tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 9c8a99ad31717c852f89bc6d4597ccaa33a5f8cf
parent 36eb24d7e02783511c18ebd19d19c6d094521423
Author: Erich Gubler <erichdongubler@gmail.com>
Date:   Tue, 18 Nov 2025 19:58:36 +0000

Bug 1990905 - chore(rust): update to `windows` 0.62 r=glandium,supply-chain-reviewers

This required a coordinated upgrade of several crates at the same time:

- Backports in `third_party/rust/`, which have been merged upstream, and should pose no
  conflict when next integrated from mainline history:
	- `midir`: [Boddlnagg/midir#178](https://github.com/Boddlnagg/midir/pull/178)
	- `neqo`: [mozilla/neqo#3091](https://github.com/mozilla/neqo/pull/3091)
	- `memtest`: [mozilla/memtest#18](https://github.com/mozilla/memtest/pull/18)
		- Consumed by `toolkit/crashreporter/client/app/`.
	- `wgpu*` and `naga` crates: [wgpu#6876](https://github.com/gfx-rs/wgpu/pull/6876)
		- This is consumed by `gfx/wgpu_bindings/`.
		- Includes an upgrade to `gpu_allocator` 0.27.0 → 0.28.0. This could have been an incremental migration first, but I missed it while figuring out what supporting work to break out. Fortunately, this isn't difficult to review.
- `widget/windows/rust/` needed some migration in its direct dependencies, too.

All backports have already been merged upstream, and so should pose no conflict when next integrated.

Differential Revision: https://phabricator.services.mozilla.com/D266878

Diffstat:
M.cargo/config.toml.in | 18++++++++++++++----
MCargo.lock | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
MCargo.toml | 7++++++-
Mbuild/rust/windows/Cargo.toml | 101++++++++++++++++++++++++++++++++++++++-----------------------------------------
Mbuild/workspace-hack/Cargo.toml | 2+-
Mgfx/wgpu_bindings/Cargo.toml | 14+++++++-------
Mgfx/wgpu_bindings/moz.yaml | 4++--
Msupply-chain/audits.toml | 24+++++++++++++++---------
Msupply-chain/config.toml | 3+++
Msupply-chain/imports.lock | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtaskcluster/kinds/fetch/toolchains.yml | 6+++---
Mthird_party/rust/gpu-allocator/.cargo-checksum.json | 4++--
Mthird_party/rust/gpu-allocator/Cargo.lock | 606++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mthird_party/rust/gpu-allocator/Cargo.toml | 128+++++++++++++++++++++++++++++++++++++++++++++----------------------------------
Mthird_party/rust/gpu-allocator/README.md | 56++++++++++++++++++++++++++++++++++++++++++--------------
Mthird_party/rust/gpu-allocator/examples/d3d12-buffer-winrs.rs | 9+++------
Dthird_party/rust/gpu-allocator/examples/d3d12-buffer.rs | 283-------------------------------------------------------------------------------
Mthird_party/rust/gpu-allocator/examples/metal-buffer.rs | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Mthird_party/rust/gpu-allocator/src/allocator/dedicated_block_allocator/mod.rs | 56++++++++++++++++++++++++++++++++++++++++----------------
Mthird_party/rust/gpu-allocator/src/allocator/free_list_allocator/mod.rs | 87++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mthird_party/rust/gpu-allocator/src/allocator/mod.rs | 27+++++++++++++++++----------
Mthird_party/rust/gpu-allocator/src/d3d12/mod.rs | 288++++++++++++++++++++++++++++++-------------------------------------------------
Mthird_party/rust/gpu-allocator/src/d3d12/visualizer.rs | 4++--
Mthird_party/rust/gpu-allocator/src/lib.rs | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mthird_party/rust/gpu-allocator/src/metal/mod.rs | 368+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Athird_party/rust/gpu-allocator/src/metal/visualizer.rs | 192+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/gpu-allocator/src/result.rs | 4+++-
Mthird_party/rust/gpu-allocator/src/visualizer/allocation_reports.rs | 4++--
Mthird_party/rust/gpu-allocator/src/visualizer/memory_chunks.rs | 3+--
Mthird_party/rust/gpu-allocator/src/vulkan/mod.rs | 147++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mthird_party/rust/gpu-allocator/src/vulkan/visualizer.rs | 6+++---
Mthird_party/rust/memtest/.cargo-checksum.json | 4++--
Dthird_party/rust/memtest/Cargo.lock | 491-------------------------------------------------------------------------------
Mthird_party/rust/memtest/Cargo.toml | 26++++++++++----------------
Mthird_party/rust/midir/.cargo-checksum.json | 4++--
Mthird_party/rust/midir/Cargo.toml | 2+-
Mthird_party/rust/midir/src/backend/winmm/mod.rs | 32++++++++++++++++----------------
Mthird_party/rust/midir/src/backend/winrt/mod.rs | 22+++++++++++-----------
Mthird_party/rust/mtu/.cargo-checksum.json | 4++--
Mthird_party/rust/mtu/Cargo.toml | 3++-
Mthird_party/rust/neqo-common/.cargo-checksum.json | 4++--
Mthird_party/rust/neqo-common/Cargo.toml | 2+-
Mthird_party/rust/neqo-udp/.cargo-checksum.json | 4++--
Mthird_party/rust/neqo-udp/Cargo.toml | 2+-
Mthird_party/rust/wgpu-hal/.cargo-checksum.json | 4++--
Mthird_party/rust/wgpu-hal/Cargo.toml | 13++++++++-----
Mthird_party/rust/wgpu-hal/src/dx12/command.rs | 27+++++++++------------------
Mthird_party/rust/wgpu-hal/src/dx12/dcomp.rs | 6++++--
Mthird_party/rust/wgpu-hal/src/dx12/device.rs | 8++++----
Mthird_party/rust/wgpu-hal/src/dx12/mod.rs | 4++--
Mthird_party/rust/wgpu-hal/src/dx12/suballocation.rs | 5+++--
Mthird_party/rust/wgpu-hal/src/gles/wgl.rs | 30+++++++++++++++---------------
Mthird_party/rust/wgpu-types/.cargo-checksum.json | 4++--
Mthird_party/rust/wgpu-types/src/counters.rs | 1+
Athird_party/rust/windows-collections/.cargo-checksum.json | 2++
Athird_party/rust/windows-collections/Cargo.lock | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-collections/Cargo.toml | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-collections/license-apache-2.0 | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-collections/license-mit | 21+++++++++++++++++++++
Athird_party/rust/windows-collections/readme.md | 46++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-collections/src/bindings.rs | 1962+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-collections/src/iterable.rs | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-collections/src/lib.rs | 21+++++++++++++++++++++
Athird_party/rust/windows-collections/src/map_view.rs | 164+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-collections/src/vector_view.rs | 131+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-core/.cargo-checksum.json | 4++--
Athird_party/rust/windows-core/Cargo.lock | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-core/Cargo.toml | 46+++++++++++++++++++++++++---------------------
Mthird_party/rust/windows-core/readme.md | 87+++----------------------------------------------------------------------------
Mthird_party/rust/windows-core/src/agile_reference.rs | 2+-
Mthird_party/rust/windows-core/src/array.rs | 41++++++++++-------------------------------
Mthird_party/rust/windows-core/src/as_impl.rs | 2+-
Mthird_party/rust/windows-core/src/com_object.rs | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mthird_party/rust/windows-core/src/event.rs | 293+++++++++++++++++--------------------------------------------------------------
Mthird_party/rust/windows-core/src/guid.rs | 123++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Athird_party/rust/windows-core/src/imp/array_proxy.rs | 38++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-core/src/imp/bindings.rs | 657++-----------------------------------------------------------------------------
Mthird_party/rust/windows-core/src/imp/com_bindings.rs | 234+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mthird_party/rust/windows-core/src/imp/factory_cache.rs | 70+++++++++++++++++++++++++++++++++++++---------------------------------
Athird_party/rust/windows-core/src/imp/marshaler.rs | 268+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-core/src/imp/mod.rs | 8+++++---
Mthird_party/rust/windows-core/src/imp/ref_count.rs | 2+-
Mthird_party/rust/windows-core/src/imp/sha1.rs | 20++++++++++++--------
Dthird_party/rust/windows-core/src/imp/waiter.rs | 40----------------------------------------
Mthird_party/rust/windows-core/src/imp/weak_ref_count.rs | 326++++++++++++++++++++++++++++++++++++++++++-------------------------------------
Mthird_party/rust/windows-core/src/imp/windows.rs | 8++++----
Mthird_party/rust/windows-core/src/inspectable.rs | 56++++++++++++++++++++++++++++++++------------------------
Mthird_party/rust/windows-core/src/interface.rs | 46++++++++++++++++++++++------------------------
Mthird_party/rust/windows-core/src/lib.rs | 19++++++++++---------
Mthird_party/rust/windows-core/src/out_param.rs | 26++++++++++++++++----------
Mthird_party/rust/windows-core/src/out_ref.rs | 14+++++++++++++-
Mthird_party/rust/windows-core/src/param.rs | 35++++++++++++++++++++++++-----------
Mthird_party/rust/windows-core/src/ref.rs | 80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mthird_party/rust/windows-core/src/scoped_interface.rs | 6+++---
Mthird_party/rust/windows-core/src/type.rs | 39+++++++++++++++++++++++++++++++++------
Mthird_party/rust/windows-core/src/unknown.rs | 41+++++++++++++++++------------------------
Dthird_party/rust/windows-core/src/variant.rs | 852-------------------------------------------------------------------------------
Mthird_party/rust/windows-core/src/weak.rs | 6+++---
Mthird_party/rust/windows-core/src/windows.rs | 5+----
Athird_party/rust/windows-core/windows-core.natvis | 18++++++++++++++++++
Athird_party/rust/windows-future/.cargo-checksum.json | 2++
Athird_party/rust/windows-future/Cargo.lock | 115+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/Cargo.toml | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/license-apache-2.0 | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/license-mit | 21+++++++++++++++++++++
Athird_party/rust/windows-future/readme.md | 31+++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/async.rs | 169+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/async_ready.rs | 228+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/async_spawn.rs | 321+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/bindings.rs | 2235+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/bindings_impl.rs | 20++++++++++++++++++++
Athird_party/rust/windows-future/src/future.rs | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/join.rs | 29+++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/lib.rs | 29+++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/waiter.rs | 41+++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-future/src/when.rs | 41+++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-implement/.cargo-checksum.json | 4++--
Athird_party/rust/windows-implement/Cargo.lock | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-implement/Cargo.toml | 25+++++++++++++------------
Athird_party/rust/windows-implement/readme.md | 3+++
Athird_party/rust/windows-implement/src/gen.rs | 600+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-implement/src/lib.rs | 558+++++++++++++++++++++++++++----------------------------------------------------
Athird_party/rust/windows-implement/src/tests.rs | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-interface/.cargo-checksum.json | 4++--
Athird_party/rust/windows-interface/Cargo.lock | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-interface/Cargo.toml | 24++++++++++++------------
Athird_party/rust/windows-interface/readme.md | 3+++
Mthird_party/rust/windows-interface/src/lib.rs | 32+++++++++++++++++---------------
Athird_party/rust/windows-numerics/.cargo-checksum.json | 2++
Athird_party/rust/windows-numerics/Cargo.lock | 105+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-numerics/Cargo.toml | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-numerics/license-apache-2.0 | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-numerics/license-mit | 21+++++++++++++++++++++
Athird_party/rust/windows-numerics/readme.md | 7+++++++
Athird_party/rust/windows-numerics/src/bindings.rs | 89+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-numerics/src/lib.rs | 12++++++++++++
Athird_party/rust/windows-numerics/src/matrix3x2.rs | 184+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-numerics/src/matrix4x4.rs | 237+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-numerics/src/vector2.rs | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-numerics/src/vector3.rs | 227+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-numerics/src/vector4.rs | 246+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-result/.cargo-checksum.json | 4++--
Athird_party/rust/windows-result/Cargo.lock | 16++++++++++++++++
Mthird_party/rust/windows-result/Cargo.toml | 27++++++++++++---------------
Mthird_party/rust/windows-result/readme.md | 4++--
Mthird_party/rust/windows-result/src/bindings.rs | 28+++++++++++-----------------
Athird_party/rust/windows-result/src/bool.rs | 90+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mthird_party/rust/windows-result/src/bstr.rs | 32+++++++++++---------------------
Mthird_party/rust/windows-result/src/error.rs | 22+++++++---------------
Mthird_party/rust/windows-result/src/hresult.rs | 24++++++++++++++++++------
Mthird_party/rust/windows-result/src/lib.rs | 23+++++++++++++----------
Athird_party/rust/windows-result/windows-result.natvis | 21+++++++++++++++++++++
Mthird_party/rust/windows-strings/.cargo-checksum.json | 4++--
Athird_party/rust/windows-strings/Cargo.lock | 16++++++++++++++++
Mthird_party/rust/windows-strings/Cargo.toml | 31++++++++++++-------------------
Mthird_party/rust/windows-strings/readme.md | 12+++++-------
Mthird_party/rust/windows-strings/src/bindings.rs | 15+++++++--------
Mthird_party/rust/windows-strings/src/bstr.rs | 88+++++++++++++++++++++++++++++++++++--------------------------------------------
Mthird_party/rust/windows-strings/src/decode.rs | 2+-
Mthird_party/rust/windows-strings/src/hstring.rs | 104+++++++++++++++++++++++++++++++++++--------------------------------------------
Mthird_party/rust/windows-strings/src/hstring_builder.rs | 27++++++++++++++++++++++++---
Mthird_party/rust/windows-strings/src/hstring_header.rs | 22++++++++++++----------
Mthird_party/rust/windows-strings/src/lib.rs | 16+++-------------
Mthird_party/rust/windows-strings/src/literals.rs | 34++++++++++++++++------------------
Mthird_party/rust/windows-strings/src/pcstr.rs | 16++++++++++++----
Mthird_party/rust/windows-strings/src/pcwstr.rs | 28++++++++++++++++++++--------
Mthird_party/rust/windows-strings/src/pstr.rs | 16++++++++++++----
Mthird_party/rust/windows-strings/src/pwstr.rs | 20+++++++++++++-------
Athird_party/rust/windows-strings/windows-strings.natvis | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-threading/.cargo-checksum.json | 2++
Athird_party/rust/windows-threading/Cargo.lock | 16++++++++++++++++
Athird_party/rust/windows-threading/Cargo.toml | 47+++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-threading/license-apache-2.0 | 201+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-threading/license-mit | 21+++++++++++++++++++++
Athird_party/rust/windows-threading/readme.md | 116+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-threading/src/bindings.rs | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-threading/src/lib.rs | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Athird_party/rust/windows-threading/src/pool.rs | 139+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtoolkit/crashreporter/client/app/Cargo.toml | 2+-
Mwidget/windows/rust/Cargo.toml | 6++++--
Mwidget/windows/rust/src/lib.rs | 4++--
181 files changed, 13447 insertions(+), 4902 deletions(-)

diff --git a/.cargo/config.toml.in b/.cargo/config.toml.in @@ -35,14 +35,19 @@ git = "https://github.com/erichdongubler-contrib/hashlink" rev = "76dc47a12af5829c1e8bf4834e38b410dec2aeff" replace-with = "vendored-sources" +[source."git+https://github.com/erichdongubler-mozilla/neqo?rev=5bfb65919fb5804ec1dd68cc93e014cb9c830d94"] +git = "https://github.com/erichdongubler-mozilla/neqo" +rev = "5bfb65919fb5804ec1dd68cc93e014cb9c830d94" +replace-with = "vendored-sources" + [source."git+https://github.com/franziskuskiefer/cose-rust?rev=43c22248d136c8b38fe42ea709d08da6355cf04b"] git = "https://github.com/franziskuskiefer/cose-rust" rev = "43c22248d136c8b38fe42ea709d08da6355cf04b" replace-with = "vendored-sources" -[source."git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6"] +[source."git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4"] git = "https://github.com/gfx-rs/wgpu" -rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" replace-with = "vendored-sources" [source."git+https://github.com/glandium/allocator-api2?rev=ad5f3d56a5a4519eff52af4ff85293431466ef5c"] @@ -100,9 +105,14 @@ git = "https://github.com/mozilla/cubeb-pulse-rs" rev = "4e3ea4bbc582705a4e7d9220679525283c035a7e" replace-with = "vendored-sources" -[source."git+https://github.com/mozilla/midir.git?rev=0cc61b81b26088bb8d6e593caf96879879ab814b"] +[source."git+https://github.com/mozilla/memtest?rev=ad681ba425beb0aeba95f03e671432b4be932174"] +git = "https://github.com/mozilla/memtest" +rev = "ad681ba425beb0aeba95f03e671432b4be932174" +replace-with = "vendored-sources" + +[source."git+https://github.com/mozilla/midir.git?rev=54759f681f3b523e120d047adec2bb1a97152017"] git = "https://github.com/mozilla/midir.git" -rev = "0cc61b81b26088bb8d6e593caf96879879ab814b" +rev = "54759f681f3b523e120d047adec2bb1a97152017" replace-with = "vendored-sources" [source."git+https://github.com/mozilla/mp4parse-rust?rev=f955be5d2a04a631c0f1777d6f35370ea1a99e2d"] diff --git a/Cargo.lock b/Cargo.lock @@ -2833,13 +2833,14 @@ dependencies = [ [[package]] name = "gpu-allocator" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" +checksum = "51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795" dependencies = [ + "hashbrown 0.16.0", "log", "presser", - "thiserror 1.999.999", + "thiserror 2.0.12", "windows", ] @@ -4134,8 +4135,7 @@ dependencies = [ [[package]] name = "memtest" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ff5f1d8294a1fd0c8a32428d826ae22da3d473f0052c6e6d449a91b24e365c" +source = "git+https://github.com/mozilla/memtest?rev=ad681ba425beb0aeba95f03e671432b4be932174#ad681ba425beb0aeba95f03e671432b4be932174" dependencies = [ "anyhow", "libc", @@ -4165,7 +4165,7 @@ dependencies = [ [[package]] name = "midir" version = "0.10.3" -source = "git+https://github.com/mozilla/midir.git?rev=0cc61b81b26088bb8d6e593caf96879879ab814b#0cc61b81b26088bb8d6e593caf96879879ab814b" +source = "git+https://github.com/mozilla/midir.git?rev=54759f681f3b523e120d047adec2bb1a97152017#54759f681f3b523e120d047adec2bb1a97152017" dependencies = [ "alsa", "coremidi", @@ -4757,7 +4757,7 @@ dependencies = [ [[package]] name = "mtu" version = "0.2.9" -source = "git+https://github.com/mozilla/neqo?tag=v0.18.0#57ef3bd8f67023a168734a154e0ef273e9ddc7f1" +source = "git+https://github.com/erichdongubler-mozilla/neqo?rev=5bfb65919fb5804ec1dd68cc93e014cb9c830d94#5bfb65919fb5804ec1dd68cc93e014cb9c830d94" dependencies = [ "bindgen 0.69.999", "cfg_aliases", @@ -4776,7 +4776,7 @@ checksum = "a2983372caf4480544083767bf2d27defafe32af49ab4df3a0b7fc90793a3664" [[package]] name = "naga" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" dependencies = [ "arrayvec", "bit-set", @@ -4826,7 +4826,7 @@ dependencies = [ [[package]] name = "neqo-common" version = "0.18.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.18.0#57ef3bd8f67023a168734a154e0ef273e9ddc7f1" +source = "git+https://github.com/erichdongubler-mozilla/neqo?rev=5bfb65919fb5804ec1dd68cc93e014cb9c830d94#5bfb65919fb5804ec1dd68cc93e014cb9c830d94" dependencies = [ "enum-map", "env_logger", @@ -4911,7 +4911,7 @@ dependencies = [ [[package]] name = "neqo-udp" version = "0.18.0" -source = "git+https://github.com/mozilla/neqo?tag=v0.18.0#57ef3bd8f67023a168734a154e0ef273e9ddc7f1" +source = "git+https://github.com/erichdongubler-mozilla/neqo?rev=5bfb65919fb5804ec1dd68cc93e014cb9c830d94#5bfb65919fb5804ec1dd68cc93e014cb9c830d94" dependencies = [ "cfg_aliases", "libc", @@ -7958,7 +7958,7 @@ dependencies = [ [[package]] name = "wgpu-core" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" dependencies = [ "arrayvec", "bit-set", @@ -7989,7 +7989,7 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" dependencies = [ "wgpu-hal", ] @@ -7997,7 +7997,7 @@ dependencies = [ [[package]] name = "wgpu-core-deps-windows-linux-android" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" dependencies = [ "wgpu-hal", ] @@ -8005,7 +8005,7 @@ dependencies = [ [[package]] name = "wgpu-hal" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" dependencies = [ "android_system_properties", "arrayvec", @@ -8043,7 +8043,7 @@ dependencies = [ [[package]] name = "wgpu-types" version = "27.0.0" -source = "git+https://github.com/gfx-rs/wgpu?rev=3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6#3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +source = "git+https://github.com/gfx-rs/wgpu?rev=d65295a3ce2bb11a36c2c2454ef400652fc1c4a4#d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" dependencies = [ "bitflags 2.9.0", "bytemuck", @@ -8094,6 +8094,7 @@ dependencies = [ "nsstring", "thin-vec", "windows", + "windows-collections", "xpcom", ] @@ -8130,31 +8131,53 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" -version = "0.58.0" +version = "0.62.2" dependencies = [ "mozbuild", + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", +] + +[[package]] +name = "windows-collections" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610" +dependencies = [ "windows-core", - "windows-targets", ] [[package]] name = "windows-core" -version = "0.58.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", + "windows-link", "windows-result", "windows-strings", - "windows-targets", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.58.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -8163,9 +8186,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.58.0" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -8179,22 +8202,31 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] +name = "windows-numerics" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] name = "windows-result" -version = "0.2.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-targets", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-result", - "windows-targets", + "windows-link", ] [[package]] @@ -8215,6 +8247,15 @@ dependencies = [ ] [[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] + +[[package]] name = "winnow" version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/Cargo.toml b/Cargo.toml @@ -248,7 +248,7 @@ firefox-on-glean = { path = "toolkit/components/glean/api" } icu_capi = { path = "intl/icu_capi" } icu_segmenter_data = { path = "intl/icu_segmenter_data" } libudev-sys = { path = "dom/webauthn/libudev-sys" } -midir = { git = "https://github.com/mozilla/midir.git", rev = "0cc61b81b26088bb8d6e593caf96879879ab814b" } +midir = { git = "https://github.com/mozilla/midir.git", rev = "54759f681f3b523e120d047adec2bb1a97152017" } # Allow webrender to have a versioned dependency on the older crate on crates.io # in order to build standalone. malloc_size_of_derive = { path = "xpcom/rust/malloc_size_of_derive" } @@ -292,3 +292,8 @@ libcrux-traits = { path = "build/rust/libcrux-traits" } # Patch `hashlink` 0.10.0 to include a `hashbrown` range dependency of 0.15 <= ver <= 0.16: <https://github.com/erichdongubler-contrib/hashlink/pull/6> # This technically breaks `hashbrown::DefaultHashBuilder: Copy`, but it's not something we use. hashlink = { git = "https://github.com/erichdongubler-contrib/hashlink", rev = "76dc47a12af5829c1e8bf4834e38b410dec2aeff" } + +[patch."https://github.com/mozilla/neqo"] +neqo-common = { git = "https://github.com/erichdongubler-mozilla/neqo", rev = "5bfb65919fb5804ec1dd68cc93e014cb9c830d94" } +neqo-udp = { git = "https://github.com/erichdongubler-mozilla/neqo", rev = "5bfb65919fb5804ec1dd68cc93e014cb9c830d94" } +mtu = { git = "https://github.com/erichdongubler-mozilla/neqo", rev = "5bfb65919fb5804ec1dd68cc93e014cb9c830d94" } diff --git a/build/rust/windows/Cargo.toml b/build/rust/windows/Cargo.toml @@ -11,12 +11,12 @@ [package] edition = "2021" -rust-version = "1.70" +rust-version = "1.82" name = "windows" -version = "0.58.0" -authors = ["Microsoft"] +version = "0.62.2" build = false exclude = ["features.json"] +autolib = false autobins = false autoexamples = false autotests = false @@ -30,26 +30,19 @@ repository = "https://github.com/microsoft/windows-rs" [package.metadata.docs.rs] default-target = "x86_64-pc-windows-msvc" +targets = [] rustdoc-args = [ "--cfg", "docsrs", ] -targets = [] - -[lib] -name = "windows" -path = "src/lib.rs" -test = false -doctest = false - -[dependencies.windows-core] -version = "0.58.0" - -[dependencies.windows-targets] -version = "0.52.6" [features] AI = ["Foundation"] +AI_Actions = ["AI"] +AI_Actions_Hosting = ["AI_Actions"] +AI_Actions_Provider = ["AI_Actions"] +AI_Agents = ["AI"] +AI_Agents_Mcp = ["AI_Agents"] AI_MachineLearning = ["AI"] ApplicationModel = ["Foundation"] ApplicationModel_Activation = ["ApplicationModel"] @@ -158,8 +151,6 @@ Devices_Usb = ["Devices"] Devices_WiFi = ["Devices"] Devices_WiFiDirect = ["Devices"] Devices_WiFiDirect_Services = ["Devices_WiFiDirect"] -Embedded = ["Foundation"] -Embedded_DeviceLockdown = ["Embedded"] Foundation = [] Foundation_Collections = ["Foundation"] Foundation_Diagnostics = ["Foundation"] @@ -195,6 +186,7 @@ Graphics_Printing3D = ["Graphics"] Graphics_Printing_OptionDetails = ["Graphics_Printing"] Graphics_Printing_PrintSupport = ["Graphics_Printing"] Graphics_Printing_PrintTicket = ["Graphics_Printing"] +Graphics_Printing_ProtectedPrint = ["Graphics_Printing"] Graphics_Printing_Workflow = ["Graphics_Printing"] Management = ["Foundation"] Management_Core = ["Management"] @@ -256,30 +248,6 @@ Perception_People = ["Perception"] Perception_Spatial = ["Perception"] Perception_Spatial_Preview = ["Perception_Spatial"] Perception_Spatial_Surfaces = ["Perception_Spatial"] -Phone = ["Foundation"] -Phone_ApplicationModel = ["Phone"] -Phone_Devices = ["Phone"] -Phone_Devices_Notification = ["Phone_Devices"] -Phone_Devices_Power = ["Phone_Devices"] -Phone_Management = ["Phone"] -Phone_Management_Deployment = ["Phone_Management"] -Phone_Media = ["Phone"] -Phone_Media_Devices = ["Phone_Media"] -Phone_Notification = ["Phone"] -Phone_Notification_Management = ["Phone_Notification"] -Phone_PersonalInformation = ["Phone"] -Phone_PersonalInformation_Provisioning = ["Phone_PersonalInformation"] -Phone_Speech = ["Phone"] -Phone_Speech_Recognition = ["Phone_Speech"] -Phone_StartScreen = ["Phone"] -Phone_System = ["Phone"] -Phone_System_Power = ["Phone_System"] -Phone_System_Profile = ["Phone_System"] -Phone_System_UserProfile = ["Phone_System"] -Phone_System_UserProfile_GameServices = ["Phone_System_UserProfile"] -Phone_System_UserProfile_GameServices_Core = ["Phone_System_UserProfile_GameServices"] -Phone_UI = ["Phone"] -Phone_UI_Input = ["Phone_UI"] Security = ["Foundation"] Security_Authentication = ["Security"] Security_Authentication_Identity = ["Security_Authentication"] @@ -358,6 +326,7 @@ UI_Input_Inking_Core = ["UI_Input_Inking"] UI_Input_Inking_Preview = ["UI_Input_Inking"] UI_Input_Preview = ["UI_Input"] UI_Input_Preview_Injection = ["UI_Input_Preview"] +UI_Input_Preview_Text = ["UI_Input_Preview"] UI_Input_Spatial = ["UI_Input"] UI_Notifications = ["UI"] UI_Notifications_Management = ["UI_Notifications"] @@ -372,7 +341,6 @@ UI_UIAutomation_Core = ["UI_UIAutomation"] UI_ViewManagement = ["UI"] UI_ViewManagement_Core = ["UI_ViewManagement"] UI_WebUI = ["UI"] -UI_WebUI_Core = ["UI_WebUI"] UI_WindowManagement = ["UI"] UI_WindowManagement_Preview = ["UI_WindowManagement"] Wdk = ["Win32_Foundation"] @@ -418,13 +386,16 @@ Win32_Data_Xml_MsXml = ["Win32_Data_Xml"] Win32_Data_Xml_XmlLite = ["Win32_Data_Xml"] Win32_Devices = ["Win32"] Win32_Devices_AllJoyn = ["Win32_Devices"] +Win32_Devices_Beep = ["Win32_Devices"] Win32_Devices_BiometricFramework = ["Win32_Devices"] Win32_Devices_Bluetooth = ["Win32_Devices"] +Win32_Devices_Cdrom = ["Win32_Devices"] Win32_Devices_Communication = ["Win32_Devices"] Win32_Devices_DeviceAccess = ["Win32_Devices"] Win32_Devices_DeviceAndDriverInstallation = ["Win32_Devices"] Win32_Devices_DeviceQuery = ["Win32_Devices"] Win32_Devices_Display = ["Win32_Devices"] +Win32_Devices_Dvd = ["Win32_Devices"] Win32_Devices_Enumeration = ["Win32_Devices"] Win32_Devices_Enumeration_Pnp = ["Win32_Devices_Enumeration"] Win32_Devices_Fax = ["Win32_Devices"] @@ -432,6 +403,8 @@ Win32_Devices_FunctionDiscovery = ["Win32_Devices"] Win32_Devices_Geolocation = ["Win32_Devices"] Win32_Devices_HumanInterfaceDevice = ["Win32_Devices"] Win32_Devices_ImageAcquisition = ["Win32_Devices"] +Win32_Devices_Nfc = ["Win32_Devices"] +Win32_Devices_Nfp = ["Win32_Devices"] Win32_Devices_PortableDevices = ["Win32_Devices"] Win32_Devices_Properties = ["Win32_Devices"] Win32_Devices_Pwm = ["Win32_Devices"] @@ -736,22 +709,46 @@ Win32_UI_Wpf = ["Win32_UI"] Win32_Web = ["Win32"] Win32_Web_InternetExplorer = ["Win32_Web"] default = ["std"] -deprecated = [] docs = [] -implement = [] -std = ["windows-core/std"] +std = [ + "windows-collections/std", + "windows-core/std", + "windows-future/std", + "windows-numerics/std", +] -[lints.rust] -missing_docs = "warn" +[lib] +name = "windows" +path = "src/lib.rs" +test = false +doctest = false -[lints.rust.rust_2018_idioms] -level = "warn" -priority = -1 +[dependencies.windows-collections] +version = "0.3.2" +default-features = false + +[dependencies.windows-core] +version = "0.62.2" +default-features = false + +[dependencies.windows-future] +version = "0.3.2" +default-features = false + +[dependencies.windows-numerics] +version = "0.3.1" +default-features = false + +[lints.rust] +missing_unsafe_on_extern = "warn" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 -check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"] +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] + +[hints] +mostly-unused = true [dependencies.mozbuild] version = "0.1" diff --git a/build/workspace-hack/Cargo.toml b/build/workspace-hack/Cargo.toml @@ -195,7 +195,7 @@ features = [ ] [target."cfg(windows)".dependencies.windows] -version = "0.58" +version = "0.62" optional = true features = [ "Win32_Foundation", diff --git a/gfx/wgpu_bindings/Cargo.toml b/gfx/wgpu_bindings/Cargo.toml @@ -17,7 +17,7 @@ default = [] [dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" features = ["serde", "trace", "strict_asserts", "wgsl", "api_log_info"] # We want the wgpu-core Metal backend on macOS and iOS. @@ -25,36 +25,36 @@ features = ["serde", "trace", "strict_asserts", "wgsl", "api_log_info"] [target.'cfg(any(target_os = "macos", target_os = "ios"))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" features = ["metal"] # We want the wgpu-core Direct3D backends on Windows. [target.'cfg(windows)'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" features = ["dx12"] # We want the wgpu-core Vulkan backend on Linux and Windows. [target.'cfg(any(windows, all(unix, not(any(target_os = "macos", target_os = "ios")))))'.dependencies.wgc] package = "wgpu-core" git = "https://github.com/gfx-rs/wgpu" -rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" features = ["vulkan"] [dependencies.wgt] package = "wgpu-types" git = "https://github.com/gfx-rs/wgpu" -rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" [dependencies.wgh] package = "wgpu-hal" git = "https://github.com/gfx-rs/wgpu" -rev = "3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +rev = "d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" features = ["device_lost_panic", "internal_error_panic"] [target.'cfg(windows)'.dependencies] -windows = { version = "0.58", default-features = false, features = [ +windows = { version = "0.62", default-features = false, features = [ "Win32_Graphics_Direct3D12", ] } diff --git a/gfx/wgpu_bindings/moz.yaml b/gfx/wgpu_bindings/moz.yaml @@ -8,8 +8,8 @@ origin: name: wgpu description: A cross-platform pure-Rust graphics API, modeled on the WebGPU standard url: https://github.com/gfx-rs/wgpu - release: 3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6 (2025-11-15T22:26:27Z). - revision: 3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6 + release: d65295a3ce2bb11a36c2c2454ef400652fc1c4a4 (2025-11-18T17:48:01Z). + revision: d65295a3ce2bb11a36c2c2454ef400652fc1c4a4 license: ['MIT', 'Apache-2.0'] updatebot: diff --git a/supply-chain/audits.toml b/supply-chain/audits.toml @@ -3910,6 +3910,12 @@ criteria = "safe-to-deploy" delta = "0.3.1 -> 0.4.0" notes = "This crate is written and maintained by Mozilla employees." +[[audits.memtest]] +who = "Erich Gubler <erichdongubler@gmail.com>" +criteria = "safe-to-deploy" +delta = "0.4.0 -> 0.4.0@git:ad681ba425beb0aeba95f03e671432b4be932174" +importable = false + [[audits.metal]] who = "Jim Blandy <jimb@red-bean.com>" criteria = "safe-to-deploy" @@ -3997,7 +4003,7 @@ delta = "0.10.2 -> 0.10.3" [[audits.midir]] who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" -delta = "0.10.3 -> 0.10.3@git:0cc61b81b26088bb8d6e593caf96879879ab814b" +delta = "0.10.3 -> 0.10.3@git:54759f681f3b523e120d047adec2bb1a97152017" importable = false [[audits.minidump-common]] @@ -4260,9 +4266,9 @@ criteria = "safe-to-deploy" delta = "0.2.6 -> 0.2.9" [[audits.mtu]] -who = "Max Leonard Inden <mail@max-inden.de>" +who = "Erich Gubler <erichdongubler@gmail.com>" criteria = "safe-to-deploy" -delta = "0.2.9 -> 0.2.9@git:57ef3bd8f67023a168734a154e0ef273e9ddc7f1" +delta = "0.2.9 -> 0.2.9@git:5bfb65919fb5804ec1dd68cc93e014cb9c830d94" importable = false [[audits.naga]] @@ -4370,7 +4376,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" importable = false [[audits.net2]] @@ -6937,7 +6943,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" importable = false [[audits.wgpu-core-deps-apple]] @@ -6968,7 +6974,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" importable = false [[audits.wgpu-core-deps-windows-linux-android]] @@ -6999,7 +7005,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" importable = false [[audits.wgpu-hal]] @@ -7108,7 +7114,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" importable = false [[audits.wgpu-types]] @@ -7212,7 +7218,7 @@ who = [ "Erich Gubler <erichdongubler@gmail.com>", ] criteria = "safe-to-deploy" -delta = "27.0.0 -> 27.0.0@git:3e8a11c626df52f39bdf1097e5bd9e1bdbf648d6" +delta = "27.0.0 -> 27.0.0@git:d65295a3ce2bb11a36c2c2454ef400652fc1c4a4" importable = false [[audits.whatsys]] diff --git a/supply-chain/config.toml b/supply-chain/config.toml @@ -116,6 +116,9 @@ notes = "This was originally servo code which Bobby Holley put on crates.io some audit-as-crates-io = false notes = "This is a first-party crate which is also published to crates.io. We certify audits for this crate as part of the documented release process, but that step happens after the version bump lands on central so we don't enforce it here." +[policy.memtest] +audit-as-crates-io = true + [policy.midir] audit-as-crates-io = true notes = "This is a pinned version of the upstream code, presumably to get a fix that hadn't been released yet. We should consider switching to the latest official release." diff --git a/supply-chain/imports.lock b/supply-chain/imports.lock @@ -908,6 +908,20 @@ user-id = 64539 user-login = "kennykerr" user-name = "Kenny Kerr" +[[publisher.windows]] +version = "0.62.2" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + +[[publisher.windows-collections]] +version = "0.3.2" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + [[publisher.windows-core]] version = "0.58.0" when = "2024-07-03" @@ -915,6 +929,20 @@ user-id = 64539 user-login = "kennykerr" user-name = "Kenny Kerr" +[[publisher.windows-core]] +version = "0.62.2" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + +[[publisher.windows-future]] +version = "0.3.2" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + [[publisher.windows-implement]] version = "0.58.0" when = "2024-07-03" @@ -922,6 +950,13 @@ user-id = 64539 user-login = "kennykerr" user-name = "Kenny Kerr" +[[publisher.windows-implement]] +version = "0.60.2" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + [[publisher.windows-interface]] version = "0.58.0" when = "2024-07-03" @@ -929,6 +964,13 @@ user-id = 64539 user-login = "kennykerr" user-name = "Kenny Kerr" +[[publisher.windows-interface]] +version = "0.59.3" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + [[publisher.windows-link]] version = "0.2.1" when = "2025-10-06" @@ -936,6 +978,13 @@ user-id = 64539 user-login = "kennykerr" user-name = "Kenny Kerr" +[[publisher.windows-numerics]] +version = "0.3.1" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + [[publisher.windows-result]] version = "0.2.0" when = "2024-07-03" @@ -943,6 +992,13 @@ user-id = 64539 user-login = "kennykerr" user-name = "Kenny Kerr" +[[publisher.windows-result]] +version = "0.4.1" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + [[publisher.windows-strings]] version = "0.1.0" when = "2024-07-03" @@ -950,6 +1006,13 @@ user-id = 64539 user-login = "kennykerr" user-name = "Kenny Kerr" +[[publisher.windows-strings]] +version = "0.5.1" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + [[publisher.windows-sys]] version = "0.52.0" when = "2023-11-15" @@ -957,6 +1020,13 @@ user-id = 64539 user-login = "kennykerr" user-name = "Kenny Kerr" +[[publisher.windows-threading]] +version = "0.2.1" +when = "2025-10-06" +user-id = 64539 +user-login = "kennykerr" +user-name = "Kenny Kerr" + [[publisher.winnow]] version = "0.7.13" when = "2025-08-22" diff --git a/taskcluster/kinds/fetch/toolchains.yml b/taskcluster/kinds/fetch/toolchains.yml @@ -746,9 +746,9 @@ windows-rs: local-fetch: true fetch: type: static-url - url: https://crates.io/api/v1/crates/windows/0.58.0/download - sha256: dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6 - size: 9744521 + url: https://crates.io/api/v1/crates/windows/0.62.2/download + sha256: 527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580 + size: 9360572 artifact-name: windows-rs.tar.zst strip-components: 1 add-prefix: windows-rs/ diff --git a/third_party/rust/gpu-allocator/.cargo-checksum.json b/third_party/rust/gpu-allocator/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"3ca79349a9d9a4636c763d35a0caad53c655a13ff0612020ae8ec8fe3b42b4ff","Cargo.toml":"4d6d3bb1f8fe80fe67f31bf41d3469cc311e14daa295f42d0e7944b287b9f8d3","LICENSE-APACHE":"0178e21322b0e88aa3aeb3146f6a9611bc1f8df6d98bdfb34be28b9dd56a8107","LICENSE-MIT":"ad41be6cc6538b29b9346648f41432b5e460bad6be073b5eeaa41320ea2921dc","README.md":"d51d23364f3944098ca4b6118d46b5b353c2bfcd0cce0b3ade317537bdf69143","examples/d3d12-buffer-winrs.rs":"e7bb5565a26c1608ed57bcf5895e7e45bed5af85040f5a572049e6b74c99631c","examples/d3d12-buffer.rs":"c84cfdeae3a347fe561529b60963daaccc10880a9aeb64ae992689c30e16ea11","examples/metal-buffer.rs":"0fbd65a5a8381013199ff98f76c3830b96eb5e46591d4043f54614d582f26523","examples/vulkan-buffer.rs":"49f57f1f4542126047e217c81083b08ed798637fd90d6b7560bc9fab21732953","src/allocator/dedicated_block_allocator/mod.rs":"ec52728fb0c9d40173472640f8005ee7eca450170b7c3113adfd2e887e387f29","src/allocator/dedicated_block_allocator/visualizer.rs":"5b9019dd73ebe7bb9e9d103c48368014b73cdd4ae7f36a706ae047919f56fac6","src/allocator/free_list_allocator/mod.rs":"afe3417f40cdf71ec99c5885066d715e56d8d6c19662b17846cc8ce54222b1e2","src/allocator/free_list_allocator/visualizer.rs":"46214d07285d72a0a29c8d7e76322243853eba7d25d87ebfbb17c75e7815d07f","src/allocator/mod.rs":"86a95a58a30ec59aa7a9bc5822deca4c2a82c737e5633008400c2b291683a024","src/d3d12/mod.rs":"3cb8289c2effe1430c70cbb87b705fcaca7915d36b441f7d8a9a591bca18be25","src/d3d12/visualizer.rs":"41d1b5b897ff7b0a3fda359cee3f6b5c921617a4e1fefe7ddd2341bb1da87691","src/lib.rs":"36c8bf74f77da2113651e4e13d2bd9dbb7f6c854c089573461aaea8378c4d02c","src/metal/mod.rs":"f55592a96135da25785df21d8057fe5c1843b38f1a99d817cadba17d9d036ab7","src/result.rs":"6c7d85ee13afbd0b17c1b81ed0b6d7094247dd693444b62c28daf4d9f2248846","src/visualizer/allocation_reports.rs":"441a85fd68a8903fd9e1413756730e3e5cf9aa61803983e61f7cbca27ee39071","src/visualizer/memory_chunks.rs":"f521a4ce056d610d095c7fd65b110b8c046e84850746ec38b4d66f27b0ec70ae","src/visualizer/mod.rs":"7d56c956abba968400aa6794e399db4b7ec10135a948beef21ea13ba3bd1fd9e","src/vulkan/mod.rs":"e6dd3e67aea9f321e7c53bf87448a645bc83e3bbc92e6aef76223b18dd610fe5","src/vulkan/visualizer.rs":"6357703e89e3f5e9b78649eb16af907c107d0d121c23a4094dc0794a38fd4929"},"package":"c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd"} -\ No newline at end of file +{"files":{"Cargo.lock":"a000cc330e8479eddda74006e0e7ed42ca0db015abfc68a18196dcbc9c6a900e","Cargo.toml":"34fdab93c86a4bc928db3b4d776f6792a536f4c6fd83a51db7e923be3f4da786","LICENSE-APACHE":"0178e21322b0e88aa3aeb3146f6a9611bc1f8df6d98bdfb34be28b9dd56a8107","LICENSE-MIT":"ad41be6cc6538b29b9346648f41432b5e460bad6be073b5eeaa41320ea2921dc","README.md":"2825adc54e848dc8be155be3c481bff86b0e2a73cf91ec68eb50f9a8f3c19ce0","examples/d3d12-buffer-winrs.rs":"5c093cbf626b43f545546f60933b51ea07f35c1dea3ea16e6924e8be53b4a0e2","examples/metal-buffer.rs":"f70bd46823d3febfc126aff4578b013ec6a2842f665bc5b47c0e47ebc51112a8","examples/vulkan-buffer.rs":"49f57f1f4542126047e217c81083b08ed798637fd90d6b7560bc9fab21732953","src/allocator/dedicated_block_allocator/mod.rs":"bd79c3c7e036e85b90d5fddf9076a1b59744eff5b85f20dcdb1aa4573c2c5b70","src/allocator/dedicated_block_allocator/visualizer.rs":"5b9019dd73ebe7bb9e9d103c48368014b73cdd4ae7f36a706ae047919f56fac6","src/allocator/free_list_allocator/mod.rs":"ff337597a0cdcd6e2b0fafbe93604a7bdd3f2c31a57233b099c6b781baf0586d","src/allocator/free_list_allocator/visualizer.rs":"46214d07285d72a0a29c8d7e76322243853eba7d25d87ebfbb17c75e7815d07f","src/allocator/mod.rs":"d0a5720b79242dd708a429cdaa1e617aa56e45e837b9fe3dddc30653d0dd21c9","src/d3d12/mod.rs":"dd8e02224f35d433fad3b49430a9440c014e2b9f04e9ba9aded3bd657fcfd5c8","src/d3d12/visualizer.rs":"54a432e30ead71cfba26aeb6e52f61f5616ef36c97e9f68952d12a68f84382b7","src/lib.rs":"efd68965d62e0eb0199c6205662237939a405c84c5c0009c34cd322d6fce5aef","src/metal/mod.rs":"b8eef5d91858443bd840c2d77093e23941e8331c11dceec81b44ddd221c03f2f","src/metal/visualizer.rs":"a5ee6934a9608c085b14c0ba609477e2a0e5b8cfa14835127ea267e5a1b5c4c9","src/result.rs":"35cc54ad22ab4ef1ce82026cf6c052f53666f8ffb4106b1faa067633af4db07a","src/visualizer/allocation_reports.rs":"4ff36ff39c17d31864061b12230724536393d7bffb8f1f359019bbf22ed6553f","src/visualizer/memory_chunks.rs":"a0f31694699a2fcd0f9aaa3b8b3fda54fde6bf9ff54b1fb702cded3ac8320376","src/visualizer/mod.rs":"7d56c956abba968400aa6794e399db4b7ec10135a948beef21ea13ba3bd1fd9e","src/vulkan/mod.rs":"f354d1379ef33fe97d889940deb06cffa3977e65cb286661cee4d186dd4bd54d","src/vulkan/visualizer.rs":"672306c9a9b98e3adda03323d2868fdd0f258db61fac66374df12e9b481e228d"},"package":"51255ea7cfaadb6c5f1528d43e92a82acb2b96c43365989a28b2d44ee38f8795"} +\ No newline at end of file diff --git a/third_party/rust/gpu-allocator/Cargo.lock b/third_party/rust/gpu-allocator/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "ab_glyph" -version = "0.2.28" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb" +checksum = "e074464580a518d16a7126262fffaaa47af89d4099d4cb403f8ed938ba12ee7d" dependencies = [ "ab_glyph_rasterizer", "owned_ttf_parser", @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "ab_glyph_rasterizer" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" [[package]] name = "accesskit" @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.11" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", "once_cell", @@ -51,76 +51,93 @@ dependencies = [ ] [[package]] -name = "ash" -version = "0.38.0+1.3.281" +name = "allocator-api2" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" -dependencies = [ - "libloading", -] +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] -name = "autocfg" -version = "1.3.0" +name = "anstream" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] [[package]] -name = "bitflags" -version = "1.3.2" +name = "anstyle" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] -name = "bitflags" -version = "2.6.0" +name = "anstyle-parse" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] [[package]] -name = "block" -version = "0.1.6" +name = "anstyle-query" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" +dependencies = [ + "windows-sys", +] [[package]] -name = "cfg-if" -version = "1.0.0" +name = "anstyle-wincon" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] [[package]] -name = "core-foundation" -version = "0.9.4" +name = "ash" +version = "0.38.0+1.3.281" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" dependencies = [ - "core-foundation-sys", - "libc", + "libloading", ] [[package]] -name = "core-foundation-sys" -version = "0.8.6" +name = "autocfg" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "core-graphics-types" -version = "0.1.3" +name = "bitflags" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "libc", -] +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] -name = "dispatch" -version = "0.2.0" +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[package]] +name = "colorchoice" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "ecolor" @@ -188,9 +205,9 @@ dependencies = [ [[package]] name = "enumn" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", @@ -198,16 +215,26 @@ dependencies = [ ] [[package]] -name = "env_logger" -version = "0.10.2" +name = "env_filter" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" dependencies = [ - "humantime", - "is-terminal", "log", "regex", - "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", ] [[package]] @@ -226,92 +253,97 @@ dependencies = [ ] [[package]] -name = "foreign-types" -version = "0.5.0" +name = "equivalent" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared", -] +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "foreign-types-shared" -version = "0.3.1" +name = "foldhash" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" +checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb" [[package]] name = "gpu-allocator" -version = "0.27.0" +version = "0.28.0" dependencies = [ "ash", "egui", "egui_extras", "env_logger", + "hashbrown", "log", - "metal", + "objc2", + "objc2-foundation", + "objc2-metal", "presser", "thiserror", - "winapi", "windows", ] [[package]] -name = "hermit-abi" -version = "0.3.9" +name = "hashbrown" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" +checksum = "5419bdc4f6a9207fbeba6d11b604d481addf78ecd10c11ad51e76c2f6482748d" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] -name = "humantime" -version = "2.1.0" +name = "is_terminal_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] -name = "is-terminal" -version = "0.4.12" +name = "jiff" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" dependencies = [ - "hermit-abi", - "libc", - "windows-sys", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde", +] + +[[package]] +name = "jiff-static" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] name = "libc" -version = "0.2.155" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "libloading" -version = "0.8.4" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-targets", + "windows-link", ] [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -319,76 +351,84 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] -name = "malloc_buf" -version = "0.0.6" +name = "memchr" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] -name = "memchr" -version = "2.7.4" +name = "nohash-hasher" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" [[package]] -name = "metal" -version = "0.29.0" +name = "objc2" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21" +checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc" dependencies = [ - "bitflags 2.6.0", - "block", - "core-graphics-types", - "dispatch", - "foreign-types", - "log", - "objc", - "paste", + "objc2-encode", ] [[package]] -name = "nohash-hasher" -version = "0.2.0" +name = "objc2-encode" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" [[package]] -name = "objc" -version = "0.2.7" +name = "objc2-foundation" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c" +dependencies = [ + "bitflags", + "objc2", +] + +[[package]] +name = "objc2-metal" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +checksum = "7f246c183239540aab1782457b35ab2040d4259175bd1d0c58e46ada7b47a874" dependencies = [ - "malloc_buf", + "bitflags", + "objc2", + "objc2-foundation", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" [[package]] name = "owned_ttf_parser" -version = "0.24.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" dependencies = [ "ttf-parser", ] [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -396,22 +436,31 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets", + "windows-targets 0.52.6", ] [[package]] -name = "paste" -version = "1.0.15" +name = "portable-atomic" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] [[package]] name = "presser" @@ -421,36 +470,36 @@ checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" dependencies = [ - "bitflags 2.6.0", + "bitflags", ] [[package]] name = "regex" -version = "1.10.5" +version = "1.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "8b5288124840bee7b386bc413c487869b360b2b4ec421ea56425128692f2a82c" dependencies = [ "aho-corasick", "memchr", @@ -460,9 +509,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "833eb9ce86d40ef33cb1306d8accf7bc8ec2bfea4355cbdebb3df68b40925cad" dependencies = [ "aho-corasick", "memchr", @@ -471,9 +520,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "scopeguard" @@ -483,18 +532,28 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "80ece43fc6fbed4eb5392ab50c07334d3e577cbf40997ee896fe7af40bba4245" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.227" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a576275b607a2c86ea29e410193df32bc680303c82f31e275bbfcafe8b33be5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.227" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "51e694923b8824cf0e9b382adf0f60d4e05f348f357b38833a3fa5ed7c2ede04" dependencies = [ "proc-macro2", "quote", @@ -503,15 +562,15 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "syn" -version = "2.0.71" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b146dcf730474b4bcd16c311627b31ede9ab149045db4d6088b3becaea046462" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -519,28 +578,19 @@ dependencies = [ ] [[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - -[[package]] name = "thiserror" -version = "1.0.62" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2675633b1499176c2dff06b0856a27976a8f9d436737b4cf4f312d4d91d8bbb" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.62" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d20468752b09f49e909e55a5d338caa8bedf615594e9d80bc4c565d30faf798c" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", @@ -549,81 +599,78 @@ dependencies = [ [[package]] name = "ttf-parser" -version = "0.24.0" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8686b91785aff82828ed725225925b33b4fde44c4bb15876e5f7c832724c420a" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" [[package]] name = "unicode-ident" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" - -[[package]] -name = "version_check" -version = "0.9.4" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" [[package]] -name = "winapi" -version = "0.3.9" +name = "utf8parse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" +name = "version_check" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] -name = "winapi-util" -version = "0.1.8" +name = "windows" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "49e6c4a1f363c8210c6f77ba24f645c61c6fb941eccf013da691f7e09515b8ac" dependencies = [ - "windows-sys", + "windows-collections", + "windows-core", + "windows-future", + "windows-numerics", ] [[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.58.0" +name = "windows-collections" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +checksum = "123e712f464a8a60ce1a13f4c446d2d43ab06464cb5842ff68f5c71b6fb7852e" dependencies = [ "windows-core", - "windows-targets", ] [[package]] name = "windows-core" -version = "0.58.0" +version = "0.62.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +checksum = "6844ee5416b285084d3d3fffd743b925a6c9385455f64f6d4fa3031c4c2749a9" dependencies = [ "windows-implement", "windows-interface", + "windows-link", "windows-result", "windows-strings", - "windows-targets", +] + +[[package]] +name = "windows-future" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f3db6b24b120200d649cd4811b4947188ed3a8d2626f7075146c5d178a9a4a" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", ] [[package]] name = "windows-implement" -version = "0.58.0" +version = "0.60.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "edb307e42a74fb6de9bf3a02d9712678b22399c87e6fa869d6dfcd8c1b7754e0" dependencies = [ "proc-macro2", "quote", @@ -632,9 +679,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.58.0" +version = "0.59.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +checksum = "c0abd1ddbc6964ac14db11c7213d6532ef34bd9aa042c2e5935f59d7908b46a5" dependencies = [ "proc-macro2", "quote", @@ -642,31 +689,46 @@ dependencies = [ ] [[package]] -name = "windows-result" +name = "windows-link" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + +[[package]] +name = "windows-numerics" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ce3498fe0aba81e62e477408383196b4b0363db5e0c27646f932676283b43d8" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" dependencies = [ - "windows-targets", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.1.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" dependencies = [ - "windows-result", - "windows-targets", + "windows-link", ] [[package]] name = "windows-sys" -version = "0.52.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets", + "windows-targets 0.53.4", ] [[package]] @@ -675,14 +737,40 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d42b7b7f66d2a06854650af09cfdf8713e427a439c97ad65a6375318033ac4b" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.0", + "windows_aarch64_msvc 0.53.0", + "windows_i686_gnu 0.53.0", + "windows_i686_gnullvm 0.53.0", + "windows_i686_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + +[[package]] +name = "windows-threading" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab47f085ad6932defa48855254c758cdd0e2f2d48e62a34118a268d8f345e118" +dependencies = [ + "windows-link", ] [[package]] @@ -692,61 +780,109 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + +[[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] +name = "windows_aarch64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + +[[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] +name = "windows_i686_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" + +[[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] +name = "windows_i686_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + +[[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] +name = "windows_i686_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + +[[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] +name = "windows_x86_64_gnu" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + +[[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + +[[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] +name = "windows_x86_64_msvc" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + +[[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", diff --git a/third_party/rust/gpu-allocator/Cargo.toml b/third_party/rust/gpu-allocator/Cargo.toml @@ -11,16 +11,22 @@ [package] edition = "2021" -rust-version = "1.70" +rust-version = "1.71" name = "gpu-allocator" -version = "0.27.0" +version = "0.28.0" authors = ["Traverse Research <opensource@traverseresearch.nl>"] +build = false include = [ "/README.md", "/LICENSE-*", "/src", "/examples", ] +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false description = "Memory allocator for GPU memory in Vulkan and DirectX 12" homepage = "https://github.com/Traverse-Research/gpu-allocator" documentation = "https://docs.rs/gpu-allocator/" @@ -40,28 +46,49 @@ repository = "https://github.com/Traverse-Research/gpu-allocator" [package.metadata.docs.rs] all-features = true -[[example]] -name = "vulkan-buffer" -required-features = [ +[features] +d3d12 = ["dep:windows"] +default = [ + "std", + "d3d12", "vulkan", - "ash/loaded", + "metal", ] - -[[example]] -name = "d3d12-buffer" -required-features = [ - "d3d12", - "public-winapi", +hashbrown = ["dep:hashbrown"] +metal = [ + "dep:objc2", + "dep:objc2-metal", + "dep:objc2-foundation", +] +std = ["presser/std"] +visualizer = [ + "dep:egui", + "dep:egui_extras", ] +vulkan = ["dep:ash"] + +[lib] +name = "gpu_allocator" +path = "src/lib.rs" [[example]] name = "d3d12-buffer-winrs" +path = "examples/d3d12-buffer-winrs.rs" required-features = ["d3d12"] [[example]] name = "metal-buffer" +path = "examples/metal-buffer.rs" required-features = ["metal"] +[[example]] +name = "vulkan-buffer" +path = "examples/vulkan-buffer.rs" +required-features = [ + "vulkan", + "ash/loaded", +] + [dependencies.ash] version = "0.38" features = ["debug"] @@ -78,14 +105,21 @@ version = ">=0.24, <=0.27" optional = true default-features = false +[dependencies.hashbrown] +version = "0.16.0" +optional = true + [dependencies.log] version = "0.4" +default-features = false [dependencies.presser] version = "0.3" +default-features = false [dependencies.thiserror] -version = "1.0" +version = "2.0" +default-features = false [dev-dependencies.ash] version = "0.38" @@ -96,65 +130,49 @@ features = [ default-features = false [dev-dependencies.env_logger] -version = "0.10" +version = "0.11" -[features] -d3d12 = ["dep:windows"] -default = [ - "d3d12", - "vulkan", -] -metal = ["dep:metal"] -public-winapi = ["dep:winapi"] -visualizer = [ - "dep:egui", - "dep:egui_extras", -] -vulkan = ["dep:ash"] +[target.'cfg(target_vendor = "apple")'.dependencies.objc2] +version = "0.6" +optional = true +default-features = false -[target."cfg(any(target_os = \"macos\", target_os = \"ios\"))".dependencies.metal] -version = "0.29.0" -features = [ - "link", - "dispatch", -] +[target.'cfg(target_vendor = "apple")'.dependencies.objc2-foundation] +version = "0.3" optional = true default-features = false -[target."cfg(windows)".dependencies.winapi] -version = "0.3.9" +[target.'cfg(target_vendor = "apple")'.dependencies.objc2-metal] +version = "0.3" features = [ - "d3d12", - "winerror", - "impl-default", - "impl-debug", + "MTLAccelerationStructure", + "MTLAllocation", + "MTLBuffer", + "MTLDevice", + "MTLHeap", + "MTLResidencySet", + "MTLResource", + "MTLTexture", + "std", ] optional = true +default-features = false + +[target.'cfg(target_vendor = "apple")'.dev-dependencies.objc2-metal] +version = "0.3" +features = ["MTLPixelFormat"] +default-features = false [target."cfg(windows)".dependencies.windows] -version = ">=0.53,<=0.58" +version = ">=0.53, <=0.62" features = [ "Win32_Graphics_Direct3D12", "Win32_Graphics_Dxgi_Common", ] optional = true -[target."cfg(windows)".dev-dependencies.winapi] -version = "0.3.9" -features = [ - "d3d12", - "d3d12sdklayers", - "dxgi1_6", - "winerror", - "impl-default", - "impl-debug", - "winuser", - "windowsx", - "libloaderapi", -] - [target."cfg(windows)".dev-dependencies.windows] -version = "0.58" +version = ">=0.58, <=0.62" features = [ "Win32_Graphics_Direct3D", "Win32_Graphics_Direct3D12", diff --git a/third_party/rust/gpu-allocator/README.md b/third_party/rust/gpu-allocator/README.md @@ -6,26 +6,19 @@ [![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT) [![LICENSE](https://img.shields.io/badge/license-apache-blue.svg?logo=apache)](LICENSE-APACHE) [![Contributor Covenant](https://img.shields.io/badge/contributor%20covenant-v1.4%20adopted-ff69b4.svg)](../main/CODE_OF_CONDUCT.md) -[![MSRV](https://img.shields.io/badge/rustc-1.70.0+-ab6000.svg)](https://blog.rust-lang.org/2023/06/01/Rust-1.70.0.html) +[![MSRV](https://img.shields.io/badge/rustc-1.71.0+-ab6000.svg)](https://blog.rust-lang.org/2023/07/13/Rust-1.71.0.html) [![Banner](banner.png)](https://traverseresearch.nl) ```toml [dependencies] -gpu-allocator = "0.27.0" +gpu-allocator = "0.28.0" ``` ![Visualizer](visualizer.png) This crate provides a fully written in Rust memory allocator for Vulkan, DirectX 12 and Metal. -## [Windows-rs] and [winapi] - -`gpu-allocator` recently migrated from [winapi] to [windows-rs] but still provides convenient helpers to convert to and from [winapi] types, enabled when compiling with the `public-winapi` crate feature. - -[Windows-rs]: https://github.com/microsoft/windows-rs -[winapi]: https://github.com/retep998/winapi-rs - ## Setting up the Vulkan memory allocator ```rust @@ -134,36 +127,71 @@ allocator.free(allocation).unwrap(); ```rust use gpu_allocator::metal::*; - let mut allocator = Allocator::new(&AllocatorCreateDesc { device: device.clone(), debug_settings: Default::default(), allocation_sizes: Default::default(), + create_residency_set: false, }); ``` ## Simple Metal allocation example + ```rust use gpu_allocator::metal::*; use gpu_allocator::MemoryLocation; - let allocation_desc = AllocationCreateDesc::buffer( &device, "Example allocation", 512, // size in bytes - gpu_allocator::MemoryLocation::GpuOnly, + MemoryLocation::GpuOnly, ); let allocation = allocator.allocate(&allocation_desc).unwrap(); -let resource = allocation.make_buffer().unwrap(); +let heap = unsafe { allocation.heap() }; +let resource = unsafe { + heap.newBufferWithLength_options_offset( + allocation.size() as usize, + heap.resourceOptions(), + allocation.offset() as usize, + ) +} +.unwrap(); // Cleanup drop(resource); allocator.free(&allocation).unwrap(); ``` +## `no_std` support + +`no_std` support can be enabled by compiling with `--no-default-features` to disable `std` support and `--features hashbrown` for `Hash` collections that are only defined in `std` for internal usages in crate. For example: + +```toml +[dependencies] +gpu-allocator = { version = "0.28.0", default-features = false, features = ["hashbrown", "other features"] } +``` + +To support both `std` and `no_std` builds in your project, use the following in your `Cargo.toml`: + +```toml +[features] +default = ["std", "other features"] + +std = ["gpu-allocator/std"] +hashbrown = ["gpu-allocator/hashbrown"] +other_features = [] + +[dependencies] +gpu-allocator = { version = "0.28.0", default-features = false } +``` + ## Minimum Supported Rust Version -The MSRV for this crate and the `vulkan`, `d3d12` and `metal` features is Rust 1.70. Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI. +The MSRV for this crate and the `vulkan`, `d3d12` and `metal` features is Rust **1.71**. + +The `no_std` support requires Rust **1.81** or higher because `no_std` support of dependency `thiserror` requires `core::error::Error` which is stabilized in **1.81**. + +Any other features such as the `visualizer` (with all the `egui` dependencies) may have a higher requirement and are not tested in our CI. ## License diff --git a/third_party/rust/gpu-allocator/examples/d3d12-buffer-winrs.rs b/third_party/rust/gpu-allocator/examples/d3d12-buffer-winrs.rs @@ -33,7 +33,7 @@ fn create_d3d12_device(dxgi_factory: &IDXGIFactory6) -> Option<ID3D12Device> { let adapter1 = match unsafe { dxgi_factory.EnumAdapters1(idx) } { Ok(a) => a, Err(e) if e.code() == DXGI_ERROR_NOT_FOUND => break, - Err(e) => panic!("{:?}", e), + Err(e) => panic!("{e:?}"), }; let adapter4: IDXGIAdapter4 = adapter1.cast().unwrap(); @@ -58,7 +58,7 @@ fn create_d3d12_device(dxgi_factory: &IDXGIFactory6) -> Option<ID3D12Device> { let mut device = None; match unsafe { D3D12CreateDevice(&adapter4, feature_level, &mut device) } { Ok(()) => { - info!("Using D3D12 feature level: {}", feature_level_name); + info!("Using D3D12 feature level: {feature_level_name}"); Some(device.unwrap()) } Err(e) if e.code() == E_NOINTERFACE => { @@ -66,10 +66,7 @@ fn create_d3d12_device(dxgi_factory: &IDXGIFactory6) -> Option<ID3D12Device> { None } Err(e) => { - info!( - "D3D12 feature level {} not supported: {}", - feature_level_name, e - ); + info!("D3D12 feature level {feature_level_name} not supported: {e}"); None } } diff --git a/third_party/rust/gpu-allocator/examples/d3d12-buffer.rs b/third_party/rust/gpu-allocator/examples/d3d12-buffer.rs @@ -1,283 +0,0 @@ -//! Example showcasing [`winapi`] interop with [`gpu-allocator`] which is driven by the [`windows`] crate. -use winapi::{ - shared::{dxgiformat, winerror}, - um::{d3d12, d3dcommon}, - Interface, -}; - -mod all_dxgi { - pub use winapi::shared::{dxgi1_3::*, dxgi1_6::*, dxgitype::*}; -} - -use gpu_allocator::{ - d3d12::{ - AllocationCreateDesc, Allocator, AllocatorCreateDesc, ID3D12DeviceVersion, - ResourceCategory, ToWinapi, ToWindows, - }, - MemoryLocation, -}; -use log::*; - -fn create_d3d12_device( - dxgi_factory: *mut all_dxgi::IDXGIFactory6, -) -> Option<*mut d3d12::ID3D12Device> { - for idx in 0.. { - let mut adapter4: *mut all_dxgi::IDXGIAdapter4 = std::ptr::null_mut(); - let hr = unsafe { - dxgi_factory.as_ref().unwrap().EnumAdapters1( - idx, - <*mut *mut all_dxgi::IDXGIAdapter4>::cast(&mut adapter4), - ) - }; - - if hr == winerror::DXGI_ERROR_NOT_FOUND { - break; - } - - assert_eq!(hr, winerror::S_OK); - - let mut desc = all_dxgi::DXGI_ADAPTER_DESC3::default(); - let hr = unsafe { adapter4.as_ref().unwrap().GetDesc3(&mut desc) }; - if hr != winerror::S_OK { - error!("Failed to get adapter description for adapter"); - continue; - } - - // Skip software adapters - if (desc.Flags & all_dxgi::DXGI_ADAPTER_FLAG3_SOFTWARE) - == all_dxgi::DXGI_ADAPTER_FLAG3_SOFTWARE - { - continue; - } - - let feature_levels = [ - (d3dcommon::D3D_FEATURE_LEVEL_11_0, "D3D_FEATURE_LEVEL_11_0"), - (d3dcommon::D3D_FEATURE_LEVEL_11_1, "D3D_FEATURE_LEVEL_11_1"), - (d3dcommon::D3D_FEATURE_LEVEL_12_0, "D3D_FEATURE_LEVEL_12_0"), - ]; - - let device = - feature_levels - .iter() - .rev() - .find_map(|&(feature_level, feature_level_name)| { - let mut device: *mut d3d12::ID3D12Device = std::ptr::null_mut(); - let hr = unsafe { - d3d12::D3D12CreateDevice( - adapter4.cast(), - feature_level, - &d3d12::ID3D12Device::uuidof(), - <*mut *mut d3d12::ID3D12Device>::cast(&mut device), - ) - }; - match hr { - winerror::S_OK => { - info!("Using D3D12 feature level: {}.", feature_level_name); - Some(device) - } - winerror::E_NOINTERFACE => { - error!("ID3D12Device interface not supported."); - None - } - _ => { - info!( - "D3D12 feature level: {} not supported: {:x}", - feature_level_name, hr - ); - None - } - } - }); - if device.is_some() { - return device; - } - } - - None -} - -fn main() { - env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")).init(); - - let dxgi_factory = { - let mut dxgi_factory: *mut all_dxgi::IDXGIFactory6 = std::ptr::null_mut(); - let hr = unsafe { - all_dxgi::CreateDXGIFactory2( - 0, - &all_dxgi::IID_IDXGIFactory6, - <*mut *mut all_dxgi::IDXGIFactory6>::cast(&mut dxgi_factory), - ) - }; - - assert_eq!(hr, winerror::S_OK, "Failed to create DXGI factory"); - dxgi_factory - }; - - let device = create_d3d12_device(dxgi_factory).expect("Failed to create D3D12 device."); - - // Setting up the allocator - let mut allocator = Allocator::new(&AllocatorCreateDesc { - device: ID3D12DeviceVersion::Device(device.as_windows().clone()), - debug_settings: Default::default(), - allocation_sizes: Default::default(), - }) - .unwrap(); - - let device = unsafe { device.as_ref() }.unwrap(); - - // Test allocating Gpu Only memory - { - let test_buffer_desc = d3d12::D3D12_RESOURCE_DESC { - Dimension: d3d12::D3D12_RESOURCE_DIMENSION_BUFFER, - Alignment: d3d12::D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT as u64, - Width: 512, - Height: 1, - DepthOrArraySize: 1, - MipLevels: 1, - Format: dxgiformat::DXGI_FORMAT_UNKNOWN, - SampleDesc: all_dxgi::DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - Layout: d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - Flags: d3d12::D3D12_RESOURCE_FLAG_NONE, - }; - - let allocation_desc = AllocationCreateDesc::from_winapi_d3d12_resource_desc( - device, - &test_buffer_desc, - "Test allocation (Gpu Only)", - MemoryLocation::GpuOnly, - ); - let allocation = allocator.allocate(&allocation_desc).unwrap(); - - let mut resource: *mut d3d12::ID3D12Resource = std::ptr::null_mut(); - let hr = unsafe { - device.CreatePlacedResource( - allocation.heap().as_winapi() as *mut _, - allocation.offset(), - &test_buffer_desc, - d3d12::D3D12_RESOURCE_STATE_COMMON, - std::ptr::null(), - &d3d12::IID_ID3D12Resource, - <*mut *mut d3d12::ID3D12Resource>::cast(&mut resource), - ) - }; - if hr != winerror::S_OK { - panic!("Failed to create placed resource."); - } - - unsafe { resource.as_ref().unwrap().Release() }; - - allocator.free(allocation).unwrap(); - info!("Allocation and deallocation of GpuOnly memory was successful."); - } - - // Test allocating Cpu to Gpu memory - { - let test_buffer_desc = d3d12::D3D12_RESOURCE_DESC { - Dimension: d3d12::D3D12_RESOURCE_DIMENSION_BUFFER, - Alignment: d3d12::D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT as u64, - Width: 512, - Height: 1, - DepthOrArraySize: 1, - MipLevels: 1, - Format: dxgiformat::DXGI_FORMAT_UNKNOWN, - SampleDesc: all_dxgi::DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - Layout: d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - Flags: d3d12::D3D12_RESOURCE_FLAG_NONE, - }; - - let alloc_info = unsafe { device.GetResourceAllocationInfo(0, 1, &test_buffer_desc) }; - - let allocation = allocator - .allocate(&AllocationCreateDesc { - name: "Test allocation (Cpu to Gpu)", - location: MemoryLocation::CpuToGpu, - size: alloc_info.SizeInBytes, - alignment: alloc_info.Alignment, - resource_category: ResourceCategory::Buffer, - }) - .unwrap(); - - let mut resource: *mut d3d12::ID3D12Resource = std::ptr::null_mut(); - let hr = unsafe { - device.CreatePlacedResource( - allocation.heap().as_winapi() as *mut _, - allocation.offset(), - &test_buffer_desc, - d3d12::D3D12_RESOURCE_STATE_COMMON, - std::ptr::null(), - &d3d12::IID_ID3D12Resource, - <*mut *mut d3d12::ID3D12Resource>::cast(&mut resource), - ) - }; - if hr != winerror::S_OK { - panic!("Failed to create placed resource."); - } - - unsafe { resource.as_ref().unwrap().Release() }; - - allocator.free(allocation).unwrap(); - info!("Allocation and deallocation of CpuToGpu memory was successful."); - } - - // Test allocating Gpu to Cpu memory - { - let test_buffer_desc = d3d12::D3D12_RESOURCE_DESC { - Dimension: d3d12::D3D12_RESOURCE_DIMENSION_BUFFER, - Alignment: d3d12::D3D12_DEFAULT_RESOURCE_PLACEMENT_ALIGNMENT as u64, - Width: 512, - Height: 1, - DepthOrArraySize: 1, - MipLevels: 1, - Format: dxgiformat::DXGI_FORMAT_UNKNOWN, - SampleDesc: all_dxgi::DXGI_SAMPLE_DESC { - Count: 1, - Quality: 0, - }, - Layout: d3d12::D3D12_TEXTURE_LAYOUT_ROW_MAJOR, - Flags: d3d12::D3D12_RESOURCE_FLAG_NONE, - }; - - let alloc_info = unsafe { device.GetResourceAllocationInfo(0, 1, &test_buffer_desc) }; - - let allocation = allocator - .allocate(&AllocationCreateDesc { - name: "Test allocation (Gpu to Cpu)", - location: MemoryLocation::GpuToCpu, - size: alloc_info.SizeInBytes, - alignment: alloc_info.Alignment, - resource_category: ResourceCategory::Buffer, - }) - .unwrap(); - - let mut resource: *mut d3d12::ID3D12Resource = std::ptr::null_mut(); - let hr = unsafe { - device.CreatePlacedResource( - allocation.heap().as_winapi() as *mut _, - allocation.offset(), - &test_buffer_desc, - d3d12::D3D12_RESOURCE_STATE_COMMON, - std::ptr::null(), - &d3d12::IID_ID3D12Resource, - <*mut *mut d3d12::ID3D12Resource>::cast(&mut resource), - ) - }; - if hr != winerror::S_OK { - panic!("Failed to create placed resource."); - } - - unsafe { resource.as_ref().unwrap().Release() }; - - allocator.free(allocation).unwrap(); - info!("Allocation and deallocation of CpuToGpu memory was successful."); - } - - drop(allocator); // Explicitly drop before destruction of device. - unsafe { device.Release() }; - unsafe { dxgi_factory.as_ref().unwrap().Release() }; -} diff --git a/third_party/rust/gpu-allocator/examples/metal-buffer.rs b/third_party/rust/gpu-allocator/examples/metal-buffer.rs @@ -1,18 +1,27 @@ -use std::sync::Arc; - use gpu_allocator::metal::{AllocationCreateDesc, Allocator, AllocatorCreateDesc}; use log::info; +use objc2_foundation::NSArray; +use objc2_metal::{ + MTLCreateSystemDefaultDevice, MTLDevice as _, MTLHeap, MTLPixelFormat, + MTLPrimitiveAccelerationStructureDescriptor, MTLStorageMode, MTLTextureDescriptor, +}; fn main() { env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("trace")).init(); - let device = Arc::new(metal::Device::system_default().unwrap()); + // Allow the innards of objc2-metal to link the static function below: + // https://docs.rs/objc2-metal/0.2.2/objc2_metal/index.html + #[link(name = "CoreGraphics", kind = "framework")] + extern "C" {} + + let device = MTLCreateSystemDefaultDevice().expect("No MTLDevice found"); // Setting up the allocator let mut allocator = Allocator::new(&AllocatorCreateDesc { device: device.clone(), debug_settings: Default::default(), allocation_sizes: Default::default(), + create_residency_set: false, }) .unwrap(); @@ -25,7 +34,17 @@ fn main() { gpu_allocator::MemoryLocation::GpuOnly, ); let allocation = allocator.allocate(&allocation_desc).unwrap(); - let _buffer = allocation.make_buffer().unwrap(); + // SAFETY: We will only allocate objects on this heap within the returned offset and size + let heap = unsafe { allocation.heap() }; + let buffer = unsafe { + heap.newBufferWithLength_options_offset( + allocation.size() as usize, + heap.resourceOptions(), + allocation.offset() as usize, + ) + } + .unwrap(); + drop(buffer); allocator.free(&allocation).unwrap(); info!("Allocation and deallocation of GpuOnly memory was successful."); } @@ -39,7 +58,17 @@ fn main() { gpu_allocator::MemoryLocation::CpuToGpu, ); let allocation = allocator.allocate(&allocation_desc).unwrap(); - let _buffer = allocation.make_buffer().unwrap(); + // SAFETY: We will only allocate objects on this heap within the returned offset and size + let heap = unsafe { allocation.heap() }; + let buffer = unsafe { + heap.newBufferWithLength_options_offset( + allocation.size() as usize, + heap.resourceOptions(), + allocation.offset() as usize, + ) + } + .unwrap(); + drop(buffer); allocator.free(&allocation).unwrap(); info!("Allocation and deallocation of CpuToGpu memory was successful."); } @@ -53,40 +82,65 @@ fn main() { gpu_allocator::MemoryLocation::GpuToCpu, ); let allocation = allocator.allocate(&allocation_desc).unwrap(); - let _buffer = allocation.make_buffer().unwrap(); + // SAFETY: We will only allocate objects on this heap within the returned offset and size + let heap = unsafe { allocation.heap() }; + let buffer = unsafe { + heap.newBufferWithLength_options_offset( + allocation.size() as usize, + heap.resourceOptions(), + allocation.offset() as usize, + ) + } + .unwrap(); + drop(buffer); allocator.free(&allocation).unwrap(); info!("Allocation and deallocation of GpuToCpu memory was successful."); } // Test allocating texture { - let texture_desc = metal::TextureDescriptor::new(); - texture_desc.set_pixel_format(metal::MTLPixelFormat::RGBA8Unorm); - texture_desc.set_width(64); - texture_desc.set_height(64); - texture_desc.set_storage_mode(metal::MTLStorageMode::Private); + let texture_desc = unsafe { MTLTextureDescriptor::new() }; + texture_desc.setPixelFormat(MTLPixelFormat::RGBA8Unorm); + unsafe { texture_desc.setWidth(64) }; + unsafe { texture_desc.setHeight(64) }; + texture_desc.setStorageMode(MTLStorageMode::Private); let allocation_desc = AllocationCreateDesc::texture(&device, "Test allocation (Texture)", &texture_desc); let allocation = allocator.allocate(&allocation_desc).unwrap(); - let _texture = allocation.make_texture(&texture_desc).unwrap(); + // SAFETY: We will only allocate objects on this heap within the returned offset and size + let heap = unsafe { allocation.heap() }; + let buffer = unsafe { + heap.newTextureWithDescriptor_offset(&texture_desc, allocation.offset() as usize) + } + .unwrap(); + drop(buffer); allocator.free(&allocation).unwrap(); info!("Allocation and deallocation of Texture was successful."); } // Test allocating acceleration structure { - let empty_array = metal::Array::from_slice(&[]); - let acc_desc = metal::PrimitiveAccelerationStructureDescriptor::descriptor(); - acc_desc.set_geometry_descriptors(empty_array); - let sizes = device.acceleration_structure_sizes_with_descriptor(&acc_desc); + let empty_array = NSArray::from_slice(&[]); + let acc_desc = MTLPrimitiveAccelerationStructureDescriptor::descriptor(); + acc_desc.setGeometryDescriptors(Some(&empty_array)); + let sizes = device.accelerationStructureSizesWithDescriptor(&acc_desc); let allocation_desc = AllocationCreateDesc::acceleration_structure_with_size( &device, "Test allocation (Acceleration structure)", - sizes.acceleration_structure_size, + sizes.accelerationStructureSize as u64, gpu_allocator::MemoryLocation::GpuOnly, ); let allocation = allocator.allocate(&allocation_desc).unwrap(); - let _acc_structure = allocation.make_acceleration_structure(); + // SAFETY: We will only allocate objects on this heap within the returned offset and size + let heap = unsafe { allocation.heap() }; + let buffer = unsafe { + heap.newAccelerationStructureWithSize_offset( + allocation.size() as usize, + allocation.offset() as usize, + ) + } + .unwrap(); + drop(buffer); allocator.free(&allocation).unwrap(); info!("Allocation and deallocation of Acceleration structure was successful."); } diff --git a/third_party/rust/gpu-allocator/src/allocator/dedicated_block_allocator/mod.rs b/third_party/rust/gpu-allocator/src/allocator/dedicated_block_allocator/mod.rs @@ -1,12 +1,19 @@ #![deny(unsafe_code, clippy::unwrap_used)] +#[cfg(feature = "std")] +use alloc::sync::Arc; +use alloc::{ + borrow::ToOwned, + string::{String, ToString}, + vec::Vec, +}; +#[cfg(feature = "std")] +use std::backtrace::Backtrace; + +use log::{log, Level}; #[cfg(feature = "visualizer")] pub(crate) mod visualizer; -use std::{backtrace::Backtrace, sync::Arc}; - -use log::{log, Level}; - use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase}; use crate::{AllocationError, Result}; @@ -16,6 +23,7 @@ pub(crate) struct DedicatedBlockAllocator { allocated: u64, /// Only used if [`crate::AllocatorDebugSettings::store_stack_traces`] is [`true`] name: Option<String>, + #[cfg(feature = "std")] backtrace: Arc<Backtrace>, } @@ -25,6 +33,7 @@ impl DedicatedBlockAllocator { size, allocated: 0, name: None, + #[cfg(feature = "std")] backtrace: Arc::new(Backtrace::disabled()), } } @@ -39,8 +48,8 @@ impl SubAllocator for DedicatedBlockAllocator { _allocation_type: AllocationType, _granularity: u64, name: &str, - backtrace: Arc<Backtrace>, - ) -> Result<(u64, std::num::NonZeroU64)> { + #[cfg(feature = "std")] backtrace: Arc<Backtrace>, + ) -> Result<(u64, core::num::NonZeroU64)> { if self.allocated != 0 { return Err(AllocationError::OutOfMemory); } @@ -53,15 +62,18 @@ impl SubAllocator for DedicatedBlockAllocator { self.allocated = size; self.name = Some(name.to_string()); - self.backtrace = backtrace; + #[cfg(feature = "std")] + { + self.backtrace = backtrace; + } #[allow(clippy::unwrap_used)] - let dummy_id = std::num::NonZeroU64::new(1).unwrap(); + let dummy_id = core::num::NonZeroU64::new(1).unwrap(); Ok((0, dummy_id)) } - fn free(&mut self, chunk_id: Option<std::num::NonZeroU64>) -> Result<()> { - if chunk_id != std::num::NonZeroU64::new(1) { + fn free(&mut self, chunk_id: Option<core::num::NonZeroU64>) -> Result<()> { + if chunk_id != core::num::NonZeroU64::new(1) { Err(AllocationError::Internal("Chunk ID must be 1.".into())) } else { self.allocated = 0; @@ -71,10 +83,10 @@ impl SubAllocator for DedicatedBlockAllocator { fn rename_allocation( &mut self, - chunk_id: Option<std::num::NonZeroU64>, + chunk_id: Option<core::num::NonZeroU64>, name: &str, ) -> Result<()> { - if chunk_id != std::num::NonZeroU64::new(1) { + if chunk_id != core::num::NonZeroU64::new(1) { Err(AllocationError::Internal("Chunk ID must be 1.".into())) } else { self.name = Some(name.into()); @@ -90,6 +102,20 @@ impl SubAllocator for DedicatedBlockAllocator { ) { let empty = "".to_string(); let name = self.name.as_ref().unwrap_or(&empty); + let backtrace_info; + #[cfg(feature = "std")] + { + // TODO: Allocation could be avoided here if https://github.com/rust-lang/rust/pull/139135 is merged and stabilized. + backtrace_info = format!( + ", + backtrace: {}", + self.backtrace + ) + } + #[cfg(not(feature = "std"))] + { + backtrace_info = "" + } log!( log_level, @@ -98,16 +124,14 @@ impl SubAllocator for DedicatedBlockAllocator { memory block: {} dedicated allocation: {{ size: 0x{:x}, - name: {}, - backtrace: {} + name: {}{backtrace_info} }} }}"#, memory_type_index, memory_block_index, self.size, name, - self.backtrace - ) + ); } fn report_allocations(&self) -> Vec<AllocationReport> { diff --git a/third_party/rust/gpu-allocator/src/allocator/free_list_allocator/mod.rs b/third_party/rust/gpu-allocator/src/allocator/free_list_allocator/mod.rs @@ -1,16 +1,23 @@ #![deny(unsafe_code, clippy::unwrap_used)] - -#[cfg(feature = "visualizer")] -pub(crate) mod visualizer; - -use std::{ - backtrace::Backtrace, - collections::{HashMap, HashSet}, - sync::Arc, +#[cfg(feature = "std")] +use alloc::sync::Arc; +use alloc::{ + borrow::ToOwned, + string::{String, ToString}, + vec::Vec, }; +#[cfg(feature = "std")] +use std::backtrace::Backtrace; +#[cfg(all(feature = "std", not(feature = "hashbrown")))] +use std::collections::{HashMap, HashSet}; +#[cfg(feature = "hashbrown")] +use hashbrown::{HashMap, HashSet}; use log::{log, Level}; +#[cfg(feature = "visualizer")] +pub(crate) mod visualizer; + use super::{AllocationReport, AllocationType, SubAllocator, SubAllocatorBase}; use crate::{AllocationError, Result}; @@ -26,15 +33,16 @@ fn align_up(val: u64, alignment: u64) -> u64 { #[derive(Debug)] pub(crate) struct MemoryChunk { - pub(crate) chunk_id: std::num::NonZeroU64, + pub(crate) chunk_id: core::num::NonZeroU64, pub(crate) size: u64, pub(crate) offset: u64, pub(crate) allocation_type: AllocationType, pub(crate) name: Option<String>, /// Only used if [`crate::AllocatorDebugSettings::store_stack_traces`] is [`true`] + #[cfg(feature = "std")] pub(crate) backtrace: Arc<Backtrace>, - next: Option<std::num::NonZeroU64>, - prev: Option<std::num::NonZeroU64>, + next: Option<core::num::NonZeroU64>, + prev: Option<core::num::NonZeroU64>, } #[derive(Debug)] @@ -42,8 +50,8 @@ pub(crate) struct FreeListAllocator { size: u64, allocated: u64, pub(crate) chunk_id_counter: u64, - pub(crate) chunks: HashMap<std::num::NonZeroU64, MemoryChunk>, - free_chunks: HashSet<std::num::NonZeroU64>, + pub(crate) chunks: HashMap<core::num::NonZeroU64, MemoryChunk>, + free_chunks: HashSet<core::num::NonZeroU64>, } /// Test if two suballocations will overlap the same page. @@ -68,7 +76,7 @@ fn has_granularity_conflict(type0: AllocationType, type1: AllocationType) -> boo impl FreeListAllocator { pub(crate) fn new(size: u64) -> Self { #[allow(clippy::unwrap_used)] - let initial_chunk_id = std::num::NonZeroU64::new(1).unwrap(); + let initial_chunk_id = core::num::NonZeroU64::new(1).unwrap(); let mut chunks = HashMap::default(); chunks.insert( @@ -79,6 +87,7 @@ impl FreeListAllocator { offset: 0, allocation_type: AllocationType::Free, name: None, + #[cfg(feature = "std")] backtrace: Arc::new(Backtrace::disabled()), prev: None, next: None, @@ -100,7 +109,7 @@ impl FreeListAllocator { } /// Generates a new unique chunk ID - fn get_new_chunk_id(&mut self) -> Result<std::num::NonZeroU64> { + fn get_new_chunk_id(&mut self) -> Result<core::num::NonZeroU64> { if self.chunk_id_counter == u64::MAX { // End of chunk id counter reached, no more allocations are possible. return Err(AllocationError::OutOfMemory); @@ -108,19 +117,19 @@ impl FreeListAllocator { let id = self.chunk_id_counter; self.chunk_id_counter += 1; - std::num::NonZeroU64::new(id).ok_or_else(|| { + core::num::NonZeroU64::new(id).ok_or_else(|| { AllocationError::Internal("New chunk id was 0, which is not allowed.".into()) }) } /// Finds the specified `chunk_id` in the list of free chunks and removes if from the list - fn remove_id_from_free_list(&mut self, chunk_id: std::num::NonZeroU64) { + fn remove_id_from_free_list(&mut self, chunk_id: core::num::NonZeroU64) { self.free_chunks.remove(&chunk_id); } /// Merges two adjacent chunks. Right chunk will be merged into the left chunk fn merge_free_chunks( &mut self, - chunk_left: std::num::NonZeroU64, - chunk_right: std::num::NonZeroU64, + chunk_left: core::num::NonZeroU64, + chunk_right: core::num::NonZeroU64, ) -> Result<()> { // Gather data from right chunk and remove it let (right_size, right_next) = { @@ -162,14 +171,14 @@ impl SubAllocator for FreeListAllocator { allocation_type: AllocationType, granularity: u64, name: &str, - backtrace: Arc<Backtrace>, - ) -> Result<(u64, std::num::NonZeroU64)> { + #[cfg(feature = "std")] backtrace: Arc<Backtrace>, + ) -> Result<(u64, core::num::NonZeroU64)> { let free_size = self.size - self.allocated; if size > free_size { return Err(AllocationError::OutOfMemory); } - let mut best_fit_id: Option<std::num::NonZeroU64> = None; + let mut best_fit_id: Option<core::num::NonZeroU64> = None; let mut best_offset = 0u64; let mut best_aligned_size = 0u64; let mut best_chunk_size = 0u64; @@ -249,6 +258,7 @@ impl SubAllocator for FreeListAllocator { offset: free_chunk.offset, allocation_type, name: Some(name.to_string()), + #[cfg(feature = "std")] backtrace, prev: free_chunk.prev, next: Some(first_fit_id), @@ -278,7 +288,10 @@ impl SubAllocator for FreeListAllocator { chunk.allocation_type = allocation_type; chunk.name = Some(name.to_string()); - chunk.backtrace = backtrace; + #[cfg(feature = "std")] + { + chunk.backtrace = backtrace; + } self.remove_id_from_free_list(first_fit_id); @@ -290,7 +303,7 @@ impl SubAllocator for FreeListAllocator { Ok((best_offset, chunk_id)) } - fn free(&mut self, chunk_id: Option<std::num::NonZeroU64>) -> Result<()> { + fn free(&mut self, chunk_id: Option<core::num::NonZeroU64>) -> Result<()> { let chunk_id = chunk_id .ok_or_else(|| AllocationError::Internal("Chunk ID must be a valid value.".into()))?; @@ -302,7 +315,10 @@ impl SubAllocator for FreeListAllocator { })?; chunk.allocation_type = AllocationType::Free; chunk.name = None; - chunk.backtrace = Arc::new(Backtrace::disabled()); + #[cfg(feature = "std")] + { + chunk.backtrace = Arc::new(Backtrace::disabled()); + } self.allocated -= chunk.size; @@ -327,7 +343,7 @@ impl SubAllocator for FreeListAllocator { fn rename_allocation( &mut self, - chunk_id: Option<std::num::NonZeroU64>, + chunk_id: Option<core::num::NonZeroU64>, name: &str, ) -> Result<()> { let chunk_id = chunk_id @@ -362,7 +378,20 @@ impl SubAllocator for FreeListAllocator { } let empty = "".to_string(); let name = chunk.name.as_ref().unwrap_or(&empty); - + let backtrace_info; + #[cfg(feature = "std")] + { + // TODO: Allocation could be avoided here if https://github.com/rust-lang/rust/pull/139135 is merged and stabilized. + backtrace_info = format!( + ", + backtrace: {}", + chunk.backtrace + ) + } + #[cfg(not(feature = "std"))] + { + backtrace_info = "" + } log!( log_level, r#"leak detected: {{ @@ -373,8 +402,7 @@ impl SubAllocator for FreeListAllocator { size: 0x{:x}, offset: 0x{:x}, allocation_type: {:?}, - name: {}, - backtrace: {} + name: {}{backtrace_info} }} }}"#, memory_type_index, @@ -384,7 +412,6 @@ impl SubAllocator for FreeListAllocator { chunk.offset, chunk.allocation_type, name, - chunk.backtrace ); } } diff --git a/third_party/rust/gpu-allocator/src/allocator/mod.rs b/third_party/rust/gpu-allocator/src/allocator/mod.rs @@ -1,4 +1,9 @@ -use std::{backtrace::Backtrace, fmt, ops::Range, sync::Arc}; +#[cfg(feature = "std")] +use alloc::sync::Arc; +use alloc::{fmt, string::String, vec::Vec}; +use core::ops::Range; +#[cfg(feature = "std")] +use std::backtrace::Backtrace; use log::*; @@ -61,8 +66,8 @@ pub struct AllocatorReport { pub blocks: Vec<MemoryBlockReport>, /// Sum of the memory used by all allocations, in bytes. pub total_allocated_bytes: u64, - /// Sum of the memory reserved by all memory blocks including unallocated regions, in bytes. - pub total_reserved_bytes: u64, + /// Sum of the memory capacity of all memory blocks including unallocated regions, in bytes. + pub total_capacity_bytes: u64, } impl fmt::Debug for AllocationReport { @@ -79,7 +84,7 @@ impl fmt::Debug for AllocationReport { impl fmt::Debug for AllocatorReport { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let mut allocations = self.allocations.clone(); - allocations.sort_by_key(|alloc| std::cmp::Reverse(alloc.size)); + allocations.sort_by_key(|alloc| core::cmp::Reverse(alloc.size)); let max_num_allocations_to_print = f.precision().unwrap_or(usize::MAX); allocations.truncate(max_num_allocations_to_print); @@ -87,10 +92,10 @@ impl fmt::Debug for AllocatorReport { f.debug_struct("AllocatorReport") .field( "summary", - &std::format_args!( + &core::format_args!( "{} / {}", fmt_bytes(self.total_allocated_bytes), - fmt_bytes(self.total_reserved_bytes) + fmt_bytes(self.total_capacity_bytes) ), ) .field("blocks", &self.blocks.len()) @@ -113,14 +118,14 @@ pub(crate) trait SubAllocator: SubAllocatorBase + fmt::Debug + Sync + Send { allocation_type: AllocationType, granularity: u64, name: &str, - backtrace: Arc<Backtrace>, - ) -> Result<(u64, std::num::NonZeroU64)>; + #[cfg(feature = "std")] backtrace: Arc<Backtrace>, + ) -> Result<(u64, core::num::NonZeroU64)>; - fn free(&mut self, chunk_id: Option<std::num::NonZeroU64>) -> Result<()>; + fn free(&mut self, chunk_id: Option<core::num::NonZeroU64>) -> Result<()>; fn rename_allocation( &mut self, - chunk_id: Option<std::num::NonZeroU64>, + chunk_id: Option<core::num::NonZeroU64>, name: &str, ) -> Result<()>; @@ -133,6 +138,8 @@ pub(crate) trait SubAllocator: SubAllocatorBase + fmt::Debug + Sync + Send { fn report_allocations(&self) -> Vec<AllocationReport>; + /// Returns [`true`] if this allocator allows sub-allocating multiple allocations, [`false`] if + /// it is designed to only represent dedicated allocations. #[must_use] fn supports_general_allocations(&self) -> bool; #[must_use] diff --git a/third_party/rust/gpu-allocator/src/d3d12/mod.rs b/third_party/rust/gpu-allocator/src/d3d12/mod.rs @@ -1,90 +1,33 @@ -use std::{backtrace::Backtrace, fmt, sync::Arc}; +#[cfg(feature = "std")] +use alloc::sync::Arc; +use alloc::{boxed::Box, string::String, vec::Vec}; +use core::{ + fmt, + // TODO: Remove when bumping MSRV to 1.80 + mem::size_of_val, +}; +#[cfg(feature = "std")] +use std::backtrace::Backtrace; use log::{debug, warn, Level}; use windows::Win32::{ Foundation::E_OUTOFMEMORY, - Graphics::{Direct3D12::*, Dxgi::Common::DXGI_FORMAT}, + Graphics::{ + Direct3D12::*, + Dxgi::{Common::DXGI_FORMAT, DXGI_ERROR_DEVICE_REMOVED}, + }, }; -#[cfg(feature = "public-winapi")] -mod public_winapi { - pub use winapi::um::d3d12 as winapi_d3d12; - - use super::*; - - /// Trait similar to [`AsRef`]/[`AsMut`], - pub trait ToWinapi<T> { - fn as_winapi(&self) -> *const T; - fn as_winapi_mut(&mut self) -> *mut T; - } - - /// [`windows`] types hold their pointer internally and provide drop semantics. As such this trait - /// is usually implemented on the _pointer type_ (`*const`, `*mut`) of the [`winapi`] object so that - /// a **borrow of** that pointer becomes a borrow of the [`windows`] type. - pub trait ToWindows<T> { - fn as_windows(&self) -> &T; - } - - impl ToWinapi<winapi_d3d12::ID3D12Resource> for ID3D12Resource { - fn as_winapi(&self) -> *const winapi_d3d12::ID3D12Resource { - unsafe { std::mem::transmute_copy(self) } - } - - fn as_winapi_mut(&mut self) -> *mut winapi_d3d12::ID3D12Resource { - unsafe { std::mem::transmute_copy(self) } - } - } - - impl ToWinapi<winapi_d3d12::ID3D12Device> for ID3D12Device { - fn as_winapi(&self) -> *const winapi_d3d12::ID3D12Device { - unsafe { std::mem::transmute_copy(self) } - } - - fn as_winapi_mut(&mut self) -> *mut winapi_d3d12::ID3D12Device { - unsafe { std::mem::transmute_copy(self) } - } - } - - impl ToWindows<ID3D12Device> for *const winapi_d3d12::ID3D12Device { - fn as_windows(&self) -> &ID3D12Device { - unsafe { std::mem::transmute(self) } - } - } - - impl ToWindows<ID3D12Device> for *mut winapi_d3d12::ID3D12Device { - fn as_windows(&self) -> &ID3D12Device { - unsafe { std::mem::transmute(self) } - } - } - - impl ToWindows<ID3D12Device> for &mut winapi_d3d12::ID3D12Device { - fn as_windows(&self) -> &ID3D12Device { - unsafe { std::mem::transmute(self) } - } - } - - impl ToWinapi<winapi_d3d12::ID3D12Heap> for ID3D12Heap { - fn as_winapi(&self) -> *const winapi_d3d12::ID3D12Heap { - unsafe { std::mem::transmute_copy(self) } - } - - fn as_winapi_mut(&mut self) -> *mut winapi_d3d12::ID3D12Heap { - unsafe { std::mem::transmute_copy(self) } - } - } -} - -#[cfg(feature = "public-winapi")] -pub use public_winapi::*; - #[cfg(feature = "visualizer")] mod visualizer; #[cfg(feature = "visualizer")] pub use visualizer::AllocatorVisualizer; -use super::{allocator, allocator::AllocationType}; use crate::{ - allocator::{AllocatorReport, MemoryBlockReport}, + allocator::{ + AllocationType, AllocatorReport, DedicatedBlockAllocator, FreeListAllocator, + MemoryBlockReport, SubAllocator, + }, AllocationError, AllocationSizes, AllocatorDebugSettings, MemoryLocation, Result, }; @@ -148,23 +91,6 @@ impl From<&D3D12_RESOURCE_DESC> for ResourceCategory { } } -#[cfg(feature = "public-winapi")] -impl From<&winapi_d3d12::D3D12_RESOURCE_DESC> for ResourceCategory { - fn from(desc: &winapi_d3d12::D3D12_RESOURCE_DESC) -> Self { - if desc.Dimension == winapi_d3d12::D3D12_RESOURCE_DIMENSION_BUFFER { - Self::Buffer - } else if (desc.Flags - & (winapi_d3d12::D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET - | winapi_d3d12::D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)) - != 0 - { - Self::RtvDsvTexture - } else { - Self::OtherTexture - } - } -} - #[derive(Clone, Debug)] pub struct AllocationCreateDesc<'a> { /// Name of the allocation, for tracking and debugging purposes @@ -177,53 +103,26 @@ pub struct AllocationCreateDesc<'a> { /// Alignment of allocation, should be queried using [`ID3D12Device::GetResourceAllocationInfo()`] pub alignment: u64, /// Resource category based on resource dimension and flags. Can be created from a [`D3D12_RESOURCE_DESC`] - /// using the helper into function. The resource category is ignored when Resource Heap Tier 2 or higher + /// using the [helper `into()` function]. The resource category is ignored when Resource Heap Tier 2 or higher /// is supported. + /// + /// [helper `into()` function]: ResourceCategory::from() pub resource_category: ResourceCategory, } impl<'a> AllocationCreateDesc<'a> { - /// Helper conversion function utilizing [`winapi`] types. - /// - /// This function is also available for [`windows::Win32::Graphics::Direct3D12`] - /// types as [`from_d3d12_resource_desc()`][Self::from_d3d12_resource_desc()]. - #[cfg(feature = "public-winapi")] - pub fn from_winapi_d3d12_resource_desc( - device: *const winapi_d3d12::ID3D12Device, - desc: &winapi_d3d12::D3D12_RESOURCE_DESC, - name: &'a str, - location: MemoryLocation, - ) -> Self { - let device = device.as_windows(); - // Raw structs are binary-compatible - let desc = unsafe { - std::mem::transmute::<&winapi_d3d12::D3D12_RESOURCE_DESC, &D3D12_RESOURCE_DESC>(desc) - }; - let allocation_info = - unsafe { device.GetResourceAllocationInfo(0, std::slice::from_ref(desc)) }; - let resource_category: ResourceCategory = desc.into(); - - AllocationCreateDesc { - name, - location, - size: allocation_info.SizeInBytes, - alignment: allocation_info.Alignment, - resource_category, - } - } - - /// Helper conversion function utilizing [`windows::Win32::Graphics::Direct3D12`] types. - /// - /// This function is also available for `winapi` types as `from_winapi_d3d12_resource_desc()` - /// when the `public-winapi` feature is enabled. + /// Helper function to construct an [`AllocationCreateDesc`] from an existing + /// [`D3D12_RESOURCE_DESC`] utilizing [`ID3D12Device::GetResourceAllocationInfo()`]. pub fn from_d3d12_resource_desc( device: &ID3D12Device, desc: &D3D12_RESOURCE_DESC, name: &'a str, location: MemoryLocation, ) -> Self { + // SAFETY: `device` is a valid device handle, and no arguments (like pointers) are passed + // that could induce UB. let allocation_info = - unsafe { device.GetResourceAllocationInfo(0, std::slice::from_ref(desc)) }; + unsafe { device.GetResourceAllocationInfo(0, core::slice::from_ref(desc)) }; let resource_category: ResourceCategory = desc.into(); AllocationCreateDesc { @@ -248,7 +147,7 @@ pub enum ID3D12DeviceVersion { Device12(ID3D12Device12), } -impl std::ops::Deref for ID3D12DeviceVersion { +impl core::ops::Deref for ID3D12DeviceVersion { type Target = ID3D12Device; fn deref(&self) -> &Self::Target { @@ -313,7 +212,7 @@ pub struct CommittedAllocationStatistics { #[derive(Debug)] pub struct Allocation { - chunk_id: Option<std::num::NonZeroU64>, + chunk_id: Option<core::num::NonZeroU64>, offset: u64, size: u64, memory_block_index: usize, @@ -324,23 +223,27 @@ pub struct Allocation { } impl Allocation { - pub fn chunk_id(&self) -> Option<std::num::NonZeroU64> { + pub fn chunk_id(&self) -> Option<core::num::NonZeroU64> { self.chunk_id } /// Returns the [`ID3D12Heap`] object that is backing this allocation. - /// This heap object can be shared with multiple other allocations and shouldn't be freed (or allocated from) + /// + /// This heap object can be shared with multiple other allocations and shouldn't be allocated from /// without this library, because that will lead to undefined behavior. /// /// # Safety - /// The result of this function be safely passed into [`ID3D12Device::CreatePlacedResource()`]. - /// It is exposed for this reason. Keep in mind to also pass [`Self::offset()`] along to it. + /// The result of this function can safely be passed into [`ID3D12Device::CreatePlacedResource()`]. + /// It is exposed for this reason. Keep in mind to also pass [`Self::offset()`] along to it. + /// + /// Also, this [`Allocation`] must not be [`Allocator::free()`]d while such a created resource + /// on this [`ID3D12Heap`] is still live. pub unsafe fn heap(&self) -> &ID3D12Heap { &self.heap } /// Returns the offset of the allocation on the [`ID3D12Heap`]. - /// When creating a placed resources, this offset needs to be supplied as well. + /// When creating a placed resource, this offset needs to be supplied as well. pub fn offset(&self) -> u64 { self.offset } @@ -359,7 +262,7 @@ impl Allocation { struct MemoryBlock { heap: ID3D12Heap, size: u64, - sub_allocator: Box<dyn allocator::SubAllocator>, + sub_allocator: Box<dyn SubAllocator>, } impl MemoryBlock { fn new( @@ -388,8 +291,7 @@ impl MemoryBlock { match hr { Err(e) if e.code() == E_OUTOFMEMORY => Err(AllocationError::OutOfMemory), Err(e) => Err(AllocationError::Internal(format!( - "ID3D12Device::CreateHeap failed: {}", - e + "ID3D12Device::CreateHeap failed: {e}" ))), Ok(()) => heap.ok_or_else(|| { AllocationError::Internal( @@ -399,10 +301,10 @@ impl MemoryBlock { }? }; - let sub_allocator: Box<dyn allocator::SubAllocator> = if dedicated { - Box::new(allocator::DedicatedBlockAllocator::new(size)) + let sub_allocator: Box<dyn SubAllocator> = if dedicated { + Box::new(DedicatedBlockAllocator::new(size)) } else { - Box::new(allocator::FreeListAllocator::new(size)) + Box::new(FreeListAllocator::new(size)) }; Ok(Self { @@ -429,16 +331,13 @@ impl MemoryType { &mut self, device: &ID3D12DeviceVersion, desc: &AllocationCreateDesc<'_>, - backtrace: Arc<Backtrace>, + #[cfg(feature = "std")] backtrace: Arc<Backtrace>, allocation_sizes: &AllocationSizes, ) -> Result<Allocation> { let allocation_type = AllocationType::Linear; - let memblock_size = if self.heap_properties.Type == D3D12_HEAP_TYPE_DEFAULT { - allocation_sizes.device_memblock_size - } else { - allocation_sizes.host_memblock_size - }; + let is_host = self.heap_properties.Type != D3D12_HEAP_TYPE_DEFAULT; + let memblock_size = allocation_sizes.get_memblock_size(is_host, self.active_general_blocks); let size = desc.size; let alignment = desc.alignment; @@ -475,6 +374,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace, )?; @@ -498,6 +398,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace.clone(), ); @@ -548,6 +449,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace, ); let (offset, chunk_id) = match allocation { @@ -578,28 +480,22 @@ impl MemoryType { mem_block.sub_allocator.free(allocation.chunk_id)?; - if mem_block.sub_allocator.is_empty() { - if mem_block.sub_allocator.supports_general_allocations() { - if self.active_general_blocks > 1 { - let block = self.memory_blocks[block_idx].take(); - if block.is_none() { - return Err(AllocationError::Internal( - "Memory block must be Some.".into(), - )); - } - // Note that `block` will be destroyed on `drop` here - - self.active_general_blocks -= 1; - } - } else { - let block = self.memory_blocks[block_idx].take(); - if block.is_none() { - return Err(AllocationError::Internal( - "Memory block must be Some.".into(), - )); - } - // Note that `block` will be destroyed on `drop` here + // We only want to destroy this now-empty block if it is either a dedicated/personal + // allocation, or a block supporting sub-allocations that is not the last one (ensuring + // there's always at least one block/allocator readily available). + let is_dedicated_or_not_last_general_block = + !mem_block.sub_allocator.supports_general_allocations() + || self.active_general_blocks > 1; + if mem_block.sub_allocator.is_empty() && is_dedicated_or_not_last_general_block { + let block = self.memory_blocks[block_idx] + .take() + .ok_or_else(|| AllocationError::Internal("Memory block must be Some.".into()))?; + + if block.sub_allocator.supports_general_allocations() { + self.active_general_blocks -= 1; } + + // Note that `block` will be destroyed on `drop` here } Ok(()) @@ -628,11 +524,11 @@ impl Allocator { device.CheckFeatureSupport( D3D12_FEATURE_D3D12_OPTIONS, <*mut D3D12_FEATURE_DATA_D3D12_OPTIONS>::cast(&mut options), - std::mem::size_of_val(&options) as u32, + size_of_val(&options) as u32, ) } .map_err(|e| { - AllocationError::Internal(format!("ID3D12Device::CheckFeatureSupport failed: {}", e)) + AllocationError::Internal(format!("ID3D12Device::CheckFeatureSupport failed: {e}")) })?; let is_heap_tier1 = options.ResourceHeapTier == D3D12_RESOURCE_HEAP_TIER_1; @@ -725,6 +621,7 @@ impl Allocator { let size = desc.size; let alignment = desc.alignment; + #[cfg(feature = "std")] let backtrace = Arc::new(if self.debug_settings.store_stack_traces { Backtrace::force_capture() } else { @@ -736,9 +633,10 @@ impl Allocator { "Allocating `{}` of {} bytes with an alignment of {}.", &desc.name, size, alignment ); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); - debug!("Allocation stack trace: {}", backtrace); + debug!("Allocation stack trace: {backtrace}"); } } @@ -761,16 +659,23 @@ impl Allocator { }) .ok_or(AllocationError::NoCompatibleMemoryTypeFound)?; - memory_type.allocate(&self.device, desc, backtrace, &self.allocation_sizes) + memory_type.allocate( + &self.device, + desc, + #[cfg(feature = "std")] + backtrace, + &self.allocation_sizes, + ) } pub fn free(&mut self, allocation: Allocation) -> Result<()> { if self.debug_settings.log_frees { let name = allocation.name.as_deref().unwrap_or("<null>"); - debug!("Freeing `{}`.", name); + debug!("Freeing `{name}`."); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); - debug!("Free stack trace: {}", backtrace); + debug!("Free stack trace: {backtrace}"); } } @@ -947,9 +852,14 @@ impl Allocator { } } } { + if e.code() == DXGI_ERROR_DEVICE_REMOVED { + return Err(AllocationError::Internal(format!( + "ID3D12Device::CreateCommittedResource DEVICE_REMOVED: {:?}", + unsafe { self.device.GetDeviceRemovedReason() } + ))); + } return Err(AllocationError::Internal(format!( - "ID3D12Device::CreateCommittedResource failed: {}", - e + "ID3D12Device::CreateCommittedResource failed: {e}" ))); } @@ -1057,9 +967,14 @@ impl Allocator { } } } { + if e.code() == DXGI_ERROR_DEVICE_REMOVED { + return Err(AllocationError::Internal(format!( + "ID3D12Device::CreatePlacedResource DEVICE_REMOVED: {:?}", + unsafe { self.device.GetDeviceRemovedReason() } + ))); + } return Err(AllocationError::Internal(format!( - "ID3D12Device::CreatePlacedResource failed: {}", - e + "ID3D12Device::CreatePlacedResource failed: {e}" ))); } @@ -1104,11 +1019,11 @@ impl Allocator { pub fn generate_report(&self) -> AllocatorReport { let mut allocations = vec![]; let mut blocks = vec![]; - let mut total_reserved_bytes = 0; + let mut total_capacity_bytes = 0; for memory_type in &self.memory_types { for block in memory_type.memory_blocks.iter().flatten() { - total_reserved_bytes += block.size; + total_capacity_bytes += block.size; let first_allocation = allocations.len(); allocations.extend(block.sub_allocator.report_allocations()); blocks.push(MemoryBlockReport { @@ -1124,8 +1039,21 @@ impl Allocator { allocations, blocks, total_allocated_bytes, - total_reserved_bytes, + total_capacity_bytes, + } + } + + /// Current total capacity of memory blocks allocated on the device, in bytes + pub fn capacity(&self) -> u64 { + let mut total_capacity_bytes = 0; + + for memory_type in &self.memory_types { + for block in memory_type.memory_blocks.iter().flatten() { + total_capacity_bytes += block.size; + } } + + total_capacity_bytes } } diff --git a/third_party/rust/gpu-allocator/src/d3d12/visualizer.rs b/third_party/rust/gpu-allocator/src/d3d12/visualizer.rs @@ -128,12 +128,12 @@ impl AllocatorVisualizer { "total committed resource allocations: {} KiB", mem_type.committed_allocations.total_size )); - ui.label(format!("block count: {}", active_block_count)); + ui.label(format!("block count: {active_block_count}")); for (block_idx, block) in mem_type.memory_blocks.iter().enumerate() { let Some(block) = block else { continue }; - ui.collapsing(format!("Block: {}", block_idx), |ui| { + ui.collapsing(format!("Block: {block_idx}"), |ui| { ui.label(format!("size: {} KiB", block.size / 1024)); ui.label(format!( "allocated: {} KiB", diff --git a/third_party/rust/gpu-allocator/src/lib.rs b/third_party/rust/gpu-allocator/src/lib.rs @@ -1,12 +1,5 @@ //! This crate provides a fully written in Rust memory allocator for Vulkan, DirectX 12 and Metal. //! -//! # [Windows-rs] and [winapi] -//! -//! `gpu-allocator` recently migrated from [winapi] to [windows-rs] but still provides convenient helpers to convert to and from [winapi] types, enabled when compiling with the `public-winapi` crate feature. -//! -//! [Windows-rs]: https://github.com/microsoft/windows-rs -//! [winapi]: https://github.com/retep998/winapi-rs -//! //! # Setting up the Vulkan memory allocator //! //! ```no_run @@ -161,14 +154,13 @@ //! ```no_run //! # #[cfg(feature = "metal")] //! # fn main() { -//! # use std::sync::Arc; //! use gpu_allocator::metal::*; -//! -//! # let device = Arc::new(metal::Device::system_default().unwrap()); +//! # let device = objc2_metal::MTLCreateSystemDefaultDevice().expect("No MTLDevice found"); //! let mut allocator = Allocator::new(&AllocatorCreateDesc { //! device: device.clone(), //! debug_settings: Default::default(), //! allocation_sizes: Default::default(), +//! create_residency_set: false, //! }); //! # } //! # #[cfg(not(feature = "metal"))] @@ -176,28 +168,37 @@ //! ``` //! //! # Simple Metal allocation example +//! //! ```no_run //! # #[cfg(feature = "metal")] //! # fn main() { -//! # use std::sync::Arc; //! use gpu_allocator::metal::*; //! use gpu_allocator::MemoryLocation; -//! # let device = Arc::new(metal::Device::system_default().unwrap()); +//! # let device = objc2_metal::MTLCreateSystemDefaultDevice().expect("No MTLDevice found"); //! # let mut allocator = Allocator::new(&AllocatorCreateDesc { //! # device: device.clone(), //! # debug_settings: Default::default(), //! # allocation_sizes: Default::default(), +//! # create_residency_set: false, //! # }) //! # .unwrap(); -//! //! let allocation_desc = AllocationCreateDesc::buffer( //! &device, //! "Example allocation", //! 512, // size in bytes -//! gpu_allocator::MemoryLocation::GpuOnly, +//! MemoryLocation::GpuOnly, //! ); //! let allocation = allocator.allocate(&allocation_desc).unwrap(); -//! let resource = allocation.make_buffer().unwrap(); +//! # use objc2_metal::MTLHeap; +//! let heap = unsafe { allocation.heap() }; +//! let resource = unsafe { +//! heap.newBufferWithLength_options_offset( +//! allocation.size() as usize, +//! heap.resourceOptions(), +//! allocation.offset() as usize, +//! ) +//! } +//! .unwrap(); //! //! // Cleanup //! drop(resource); @@ -206,6 +207,22 @@ //! # #[cfg(not(feature = "metal"))] //! # fn main() {} //! ``` +#![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)] +#![warn( + clippy::alloc_instead_of_core, + clippy::std_instead_of_alloc, + clippy::std_instead_of_core +)] +#![cfg_attr(not(feature = "std"), no_std)] + +#[macro_use] +extern crate alloc; + +#[cfg(all(not(feature = "std"), feature = "visualizer"))] +compile_error!("Cannot enable `visualizer` feature in `no_std` environment."); + +#[cfg(not(any(feature = "std", feature = "hashbrown")))] +compile_error!("Either `std` or `hashbrown` feature must be enabled"); mod result; pub use result::*; @@ -223,7 +240,7 @@ pub mod vulkan; #[cfg(all(windows, feature = "d3d12"))] pub mod d3d12; -#[cfg(all(any(target_os = "macos", target_os = "ios"), feature = "metal"))] +#[cfg(all(target_vendor = "apple", feature = "metal"))] pub mod metal; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -239,6 +256,7 @@ pub enum MemoryLocation { GpuToCpu, } +#[non_exhaustive] #[derive(Copy, Clone, Debug)] pub struct AllocatorDebugSettings { /// Logs out debugging information about the various heaps the current device has on startup @@ -248,12 +266,14 @@ pub struct AllocatorDebugSettings { /// Stores a copy of the full backtrace for every allocation made, this makes it easier to debug leaks /// or other memory allocations, but storing stack traces has a RAM overhead so should be disabled /// in shipping applications. + #[cfg(feature = "std")] pub store_stack_traces: bool, /// Log out every allocation as it's being made with log level Debug, rather spammy so off by default pub log_allocations: bool, /// Log out every free that is being called with log level Debug, rather spammy so off by default pub log_frees: bool, /// Log out stack traces when either `log_allocations` or `log_frees` is enabled. + #[cfg(feature = "std")] pub log_stack_traces: bool, } @@ -262,9 +282,11 @@ impl Default for AllocatorDebugSettings { Self { log_memory_information: false, log_leaks_on_shutdown: true, + #[cfg(feature = "std")] store_stack_traces: false, log_allocations: false, log_frees: false, + #[cfg(feature = "std")] log_stack_traces: false, } } @@ -276,58 +298,152 @@ impl Default for AllocatorDebugSettings { /// values, but eg. an app might want to use smaller block sizes to reduce the amount of memory used. /// /// Clamped between 4MB and 256MB, and rounds up to the nearest multiple of 4MB for alignment reasons. +/// +/// Note that these limits only apply to shared memory blocks that can hold multiple allocations. +/// If an allocation does not fit within the corresponding maximum block size, it will be placed +/// in a dedicated memory block holding only this allocation, without limitations other than what +/// the underlying hardware and driver are able to provide. +/// +/// # Fixed or growable block size +/// +/// This structure represents ranges of allowed sizes for shared memory blocks. +/// By default, if the upper bounds are not extended using `with_max_*_memblock_size`, +/// the allocator will be configured to use a fixed memory block size for shared +/// allocations. +/// +/// Otherwise, the allocator will pick a memory block size within the specifed +/// range, depending on the number of existing allocations for the memory +/// type. +/// +/// As a rule of thumb, the allocator will start with the minimum block size +/// and double the size with each new allocation, up to the specified maximum +/// block size. This growth is tracked independently for each memory type. +/// The block size also decreases when blocks are deallocated. +/// +/// # Example +/// +/// ``` +/// use gpu_allocator::AllocationSizes; +/// const MB: u64 = 1024 * 1024; +/// // This configuration uses fixed memory block sizes. +/// let fixed = AllocationSizes::new(256 * MB, 64 * MB); +/// +/// // This configuration starts with 8MB memory blocks +/// // and grows the block size of a given memory type each +/// // time a new allocation is needed, up to a limit of +/// // 256MB for device memory and 64MB for host memory. +/// let growing = AllocationSizes::new(8 * MB, 8 * MB) +/// .with_max_device_memblock_size(256 * MB) +/// .with_max_host_memblock_size(64 * MB); +/// ``` #[derive(Clone, Copy, Debug)] pub struct AllocationSizes { - /// The size of the memory blocks that will be created for the GPU only memory type. + /// The initial size for device memory blocks. + /// + /// The size of new device memory blocks doubles each time a new block is needed, up to + /// [`AllocationSizes::max_device_memblock_size`]. /// /// Defaults to 256MB. - device_memblock_size: u64, - /// The size of the memory blocks that will be created for the CPU visible memory types. + min_device_memblock_size: u64, + /// The maximum size for device memory blocks. + /// + /// Defaults to the value of [`AllocationSizes::min_device_memblock_size`]. + max_device_memblock_size: u64, + /// The initial size for host memory blocks. + /// + /// The size of new host memory blocks doubles each time a new block is needed, up to + /// [`AllocationSizes::max_host_memblock_size`]. /// /// Defaults to 64MB. - host_memblock_size: u64, + min_host_memblock_size: u64, + /// The maximum size for host memory blocks. + /// + /// Defaults to the value of [`AllocationSizes::min_host_memblock_size`]. + max_host_memblock_size: u64, } impl AllocationSizes { + /// Sets the minimum device and host memory block sizes. + /// + /// The maximum block sizes are initialized to the minimum sizes and + /// can be increased using [`AllocationSizes::with_max_device_memblock_size`] and + /// [`AllocationSizes::with_max_host_memblock_size`]. pub fn new(device_memblock_size: u64, host_memblock_size: u64) -> Self { - const FOUR_MB: u64 = 4 * 1024 * 1024; - const TWO_HUNDRED_AND_FIFTY_SIX_MB: u64 = 256 * 1024 * 1024; + let device_memblock_size = Self::adjust_memblock_size(device_memblock_size, "Device"); + let host_memblock_size = Self::adjust_memblock_size(host_memblock_size, "Host"); - let mut device_memblock_size = - device_memblock_size.clamp(FOUR_MB, TWO_HUNDRED_AND_FIFTY_SIX_MB); - let mut host_memblock_size = - host_memblock_size.clamp(FOUR_MB, TWO_HUNDRED_AND_FIFTY_SIX_MB); - - if device_memblock_size % FOUR_MB != 0 { - let val = device_memblock_size / FOUR_MB + 1; - device_memblock_size = val * FOUR_MB; - log::warn!( - "Device memory block size must be a multiple of 4MB, clamping to {}MB", - device_memblock_size / 1024 / 1024 - ) + Self { + min_device_memblock_size: device_memblock_size, + max_device_memblock_size: device_memblock_size, + min_host_memblock_size: host_memblock_size, + max_host_memblock_size: host_memblock_size, } + } - if host_memblock_size % FOUR_MB != 0 { - let val = host_memblock_size / FOUR_MB + 1; - host_memblock_size = val * FOUR_MB; - log::warn!( - "Host memory block size must be a multiple of 4MB, clamping to {}MB", - host_memblock_size / 1024 / 1024 - ) - } + /// Sets the maximum device memblock size, in bytes. + pub fn with_max_device_memblock_size(mut self, size: u64) -> Self { + self.max_device_memblock_size = + Self::adjust_memblock_size(size, "Device").max(self.min_device_memblock_size); - Self { - device_memblock_size, - host_memblock_size, + self + } + + /// Sets the maximum host memblock size, in bytes. + pub fn with_max_host_memblock_size(mut self, size: u64) -> Self { + self.max_host_memblock_size = + Self::adjust_memblock_size(size, "Host").max(self.min_host_memblock_size); + + self + } + + fn adjust_memblock_size(size: u64, kind: &str) -> u64 { + const MB: u64 = 1024 * 1024; + + let size = size.clamp(4 * MB, 256 * MB); + + if size % (4 * MB) == 0 { + return size; } + + let val = size / (4 * MB) + 1; + let new_size = val * 4 * MB; + log::warn!( + "{kind} memory block size must be a multiple of 4MB, clamping to {}MB", + new_size / MB + ); + + new_size + } + + /// Used internally to decide the size of a shared memory block + /// based within the allowed range, based on the number of + /// existing allocations. The more blocks there already are + /// (where the requested allocation didn't fit), the larger + /// the returned memory block size is going to be (up to + /// `max_*_memblock_size`). + pub(crate) fn get_memblock_size(&self, is_host: bool, count: usize) -> u64 { + let (min_size, max_size) = if is_host { + (self.min_host_memblock_size, self.max_host_memblock_size) + } else { + (self.min_device_memblock_size, self.max_device_memblock_size) + }; + + // The ranges are clamped to 4MB..256MB so we never need to + // shift by more than 7 bits. Clamping here to avoid having + // to worry about overflows. + let shift = count.min(7) as u64; + (min_size << shift).min(max_size) } } impl Default for AllocationSizes { fn default() -> Self { + const MB: u64 = 1024 * 1024; Self { - device_memblock_size: 256 * 1024 * 1024, - host_memblock_size: 64 * 1024 * 1024, + min_device_memblock_size: 256 * MB, + max_device_memblock_size: 256 * MB, + min_host_memblock_size: 64 * MB, + max_host_memblock_size: 64 * MB, } } } diff --git a/third_party/rust/gpu-allocator/src/metal/mod.rs b/third_party/rust/gpu-allocator/src/metal/mod.rs @@ -1,70 +1,84 @@ -#![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)] -use std::{backtrace::Backtrace, sync::Arc}; +#[cfg(feature = "std")] +use alloc::sync::Arc; +use alloc::{boxed::Box, string::ToString, vec::Vec}; +#[cfg(feature = "std")] +use std::backtrace::Backtrace; use log::debug; +use objc2::{rc::Retained, runtime::ProtocolObject}; +use objc2_foundation::{ns_string, NSString}; +#[cfg(doc)] +use objc2_metal::{MTLAllocation, MTLResource}; +use objc2_metal::{ + MTLCPUCacheMode, MTLDevice, MTLHeap, MTLHeapDescriptor, MTLHeapType, MTLResidencySet, + MTLResourceOptions, MTLStorageMode, MTLTextureDescriptor, +}; + +#[cfg(feature = "visualizer")] +mod visualizer; +#[cfg(feature = "visualizer")] +pub use visualizer::AllocatorVisualizer; use crate::{ - allocator::{self, AllocatorReport, MemoryBlockReport}, + allocator::{ + AllocationType, AllocatorReport, DedicatedBlockAllocator, FreeListAllocator, + MemoryBlockReport, SubAllocator, + }, AllocationError, AllocationSizes, AllocatorDebugSettings, MemoryLocation, Result, }; -fn memory_location_to_metal(location: MemoryLocation) -> metal::MTLResourceOptions { +fn memory_location_to_metal(location: MemoryLocation) -> MTLResourceOptions { match location { - MemoryLocation::GpuOnly => metal::MTLResourceOptions::StorageModePrivate, + MemoryLocation::GpuOnly => MTLResourceOptions::StorageModePrivate, MemoryLocation::CpuToGpu | MemoryLocation::GpuToCpu | MemoryLocation::Unknown => { - metal::MTLResourceOptions::StorageModeShared + MTLResourceOptions::StorageModeShared } } } #[derive(Debug)] pub struct Allocation { - chunk_id: Option<std::num::NonZeroU64>, + chunk_id: Option<core::num::NonZeroU64>, offset: u64, size: u64, memory_block_index: usize, memory_type_index: usize, - heap: Arc<metal::Heap>, + heap: Retained<ProtocolObject<dyn MTLHeap>>, name: Option<Box<str>>, } impl Allocation { - pub fn heap(&self) -> &metal::Heap { - self.heap.as_ref() + /// Returns the [`MTLHeap`] object that is backing this allocation. + /// + /// This heap object can be shared with multiple other allocations and shouldn't be allocated from + /// without this library, because that will lead to undefined behavior. + /// + /// # Safety + /// When allocating new buffers, textures, or other resources on this [`MTLHeap`], be sure to + /// pass [`Self::offset()`] and not exceed [`Self::size()`] to not allocate new resources on top + /// of existing [`Allocation`]s. + /// + /// Also, this [`Allocation`] must not be [`Allocator::free()`]d while such a created resource + /// on this [`MTLHeap`] is still live. + pub unsafe fn heap(&self) -> &ProtocolObject<dyn MTLHeap> { + &self.heap } - pub fn make_buffer(&self) -> Option<metal::Buffer> { - let resource = - self.heap - .new_buffer_with_offset(self.size, self.heap.resource_options(), self.offset); - if let Some(resource) = &resource { - if let Some(name) = &self.name { - resource.set_label(name); - } - } - resource + /// Returns the size of the allocation + pub fn size(&self) -> u64 { + self.size } - pub fn make_texture(&self, desc: &metal::TextureDescriptor) -> Option<metal::Texture> { - let resource = self.heap.new_texture_with_offset(desc, self.offset); - if let Some(resource) = &resource { - if let Some(name) = &self.name { - resource.set_label(name); - } - } - resource + /// Returns the offset of the allocation on the [`MTLHeap`]. + /// + /// Since all [`Allocation`]s are suballocated within a [`MTLHeap`], this offset always needs to + /// be supplied. See the safety documentation on [`Self::heap()`]. + pub fn offset(&self) -> u64 { + self.offset } - pub fn make_acceleration_structure(&self) -> Option<metal::AccelerationStructure> { - let resource = self - .heap - .new_acceleration_structure_with_size_offset(self.size, self.offset); - if let Some(resource) = &resource { - if let Some(name) = &self.name { - resource.set_label(name); - } - } - resource + pub fn name(&self) -> Option<&str> { + self.name.as_deref() } fn is_null(&self) -> bool { @@ -84,64 +98,84 @@ pub struct AllocationCreateDesc<'a> { impl<'a> AllocationCreateDesc<'a> { pub fn buffer( - device: &metal::Device, + device: &ProtocolObject<dyn MTLDevice>, name: &'a str, length: u64, location: MemoryLocation, ) -> Self { - let size_and_align = - device.heap_buffer_size_and_align(length, memory_location_to_metal(location)); + let size_and_align = device.heapBufferSizeAndAlignWithLength_options( + length as usize, + memory_location_to_metal(location), + ); Self { name, location, - size: size_and_align.size, - alignment: size_and_align.align, + size: size_and_align.size as u64, + alignment: size_and_align.align as u64, } } - pub fn texture(device: &metal::Device, name: &'a str, desc: &metal::TextureDescriptor) -> Self { - let size_and_align = device.heap_texture_size_and_align(desc); + pub fn texture( + device: &ProtocolObject<dyn MTLDevice>, + name: &'a str, + desc: &MTLTextureDescriptor, + ) -> Self { + let size_and_align = device.heapTextureSizeAndAlignWithDescriptor(desc); Self { name, - location: match desc.storage_mode() { - metal::MTLStorageMode::Shared - | metal::MTLStorageMode::Managed - | metal::MTLStorageMode::Memoryless => MemoryLocation::Unknown, - metal::MTLStorageMode::Private => MemoryLocation::GpuOnly, + location: match desc.storageMode() { + MTLStorageMode::Shared | MTLStorageMode::Managed | MTLStorageMode::Memoryless => { + MemoryLocation::Unknown + } + MTLStorageMode::Private => MemoryLocation::GpuOnly, + MTLStorageMode(mode /* @ 4.. */) => todo!("Unknown storage mode {mode}"), }, - size: size_and_align.size, - alignment: size_and_align.align, + size: size_and_align.size as u64, + alignment: size_and_align.align as u64, } } pub fn acceleration_structure_with_size( - device: &metal::Device, + device: &ProtocolObject<dyn MTLDevice>, name: &'a str, - size: u64, + size: u64, // TODO: usize location: MemoryLocation, ) -> Self { - let size_and_align = device.heap_acceleration_structure_size_and_align_with_size(size); + // TODO: See if we can mark this function as safe, after checking what happens if size is too large? + // What other preconditions need to be upheld? + let size_and_align = + unsafe { device.heapAccelerationStructureSizeAndAlignWithSize(size as usize) }; Self { name, location, - size: size_and_align.size, - alignment: size_and_align.align, + size: size_and_align.size as u64, + alignment: size_and_align.align as u64, } } } pub struct Allocator { - device: Arc<metal::Device>, + device: Retained<ProtocolObject<dyn MTLDevice>>, + global_residency_set: Option<Retained<ProtocolObject<dyn MTLResidencySet>>>, debug_settings: AllocatorDebugSettings, memory_types: Vec<MemoryType>, allocation_sizes: AllocationSizes, } +impl core::fmt::Debug for Allocator { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + self.generate_report().fmt(f) + } +} + #[derive(Debug)] pub struct AllocatorCreateDesc { - pub device: Arc<metal::Device>, + pub device: Retained<ProtocolObject<dyn MTLDevice>>, pub debug_settings: AllocatorDebugSettings, pub allocation_sizes: AllocationSizes, + /// Whether to create a [`MTLResidencySet`] containing all live heaps, that can be retrieved via + /// [`Allocator::residency_set()`]. Only supported on `MacOS 15.0+` / `iOS 18.0+`. + pub create_residency_set: bool, } #[derive(Debug)] @@ -152,28 +186,33 @@ pub struct CommittedAllocationStatistics { #[derive(Debug)] struct MemoryBlock { - heap: Arc<metal::Heap>, + heap: Retained<ProtocolObject<dyn MTLHeap>>, size: u64, - sub_allocator: Box<dyn allocator::SubAllocator>, + sub_allocator: Box<dyn SubAllocator>, } impl MemoryBlock { fn new( - device: &Arc<metal::Device>, + device: &ProtocolObject<dyn MTLDevice>, size: u64, - heap_descriptor: &metal::HeapDescriptor, + heap_descriptor: &MTLHeapDescriptor, dedicated: bool, memory_location: MemoryLocation, ) -> Result<Self> { - heap_descriptor.set_size(size); + heap_descriptor.setSize(size as usize); + + let heap = device + .newHeapWithDescriptor(heap_descriptor) + .ok_or_else(|| AllocationError::Internal("No MTLHeap was returned".to_string()))?; - let heap = Arc::new(device.new_heap(heap_descriptor)); - heap.set_label(&format!("MemoryBlock {memory_location:?}")); + heap.setLabel(Some(&NSString::from_str(&format!( + "MemoryBlock {memory_location:?}" + )))); - let sub_allocator: Box<dyn allocator::SubAllocator> = if dedicated { - Box::new(allocator::DedicatedBlockAllocator::new(size)) + let sub_allocator: Box<dyn SubAllocator> = if dedicated { + Box::new(DedicatedBlockAllocator::new(size)) } else { - Box::new(allocator::FreeListAllocator::new(size)) + Box::new(FreeListAllocator::new(size)) }; Ok(Self { @@ -186,10 +225,11 @@ impl MemoryBlock { #[derive(Debug)] struct MemoryType { + global_residency_set: Option<Retained<ProtocolObject<dyn MTLResidencySet>>>, memory_blocks: Vec<Option<MemoryBlock>>, _committed_allocations: CommittedAllocationStatistics, memory_location: MemoryLocation, - heap_properties: metal::HeapDescriptor, + heap_properties: Retained<MTLHeapDescriptor>, memory_type_index: usize, active_general_blocks: usize, } @@ -197,19 +237,15 @@ struct MemoryType { impl MemoryType { fn allocate( &mut self, - device: &Arc<metal::Device>, + device: &ProtocolObject<dyn MTLDevice>, desc: &AllocationCreateDesc<'_>, - backtrace: Arc<Backtrace>, + #[cfg(feature = "std")] backtrace: Arc<Backtrace>, allocation_sizes: &AllocationSizes, ) -> Result<Allocation> { - let allocation_type = allocator::AllocationType::Linear; + let allocation_type = AllocationType::Linear; - let memblock_size = if self.heap_properties.storage_mode() == metal::MTLStorageMode::Private - { - allocation_sizes.device_memblock_size - } else { - allocation_sizes.host_memblock_size - }; + let is_host = self.heap_properties.storageMode() != MTLStorageMode::Private; + let memblock_size = allocation_sizes.get_memblock_size(is_host, self.active_general_blocks); let size = desc.size; let alignment = desc.alignment; @@ -224,6 +260,10 @@ impl MemoryType { self.memory_location, )?; + if let Some(rs) = &self.global_residency_set { + unsafe { rs.addAllocation(mem_block.heap.as_ref()) } + } + let block_index = self.memory_blocks.iter().position(|block| block.is_none()); let block_index = match block_index { Some(i) => { @@ -246,6 +286,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace, )?; @@ -269,6 +310,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace.clone(), ); @@ -292,7 +334,7 @@ impl MemoryType { } } - let new_memory_block = MemoryBlock::new( + let mem_block = MemoryBlock::new( device, memblock_size, &self.heap_properties, @@ -300,11 +342,15 @@ impl MemoryType { self.memory_location, )?; + if let Some(rs) = &self.global_residency_set { + unsafe { rs.addAllocation(mem_block.heap.as_ref()) } + } + let new_block_index = if let Some(block_index) = empty_block_index { - self.memory_blocks[block_index] = Some(new_memory_block); + self.memory_blocks[block_index] = Some(mem_block); block_index } else { - self.memory_blocks.push(Some(new_memory_block)); + self.memory_blocks.push(Some(mem_block)); self.memory_blocks.len() - 1 }; @@ -319,6 +365,7 @@ impl MemoryType { allocation_type, 1, desc.name, + #[cfg(feature = "std")] backtrace, ); let (offset, chunk_id) = match allocation { @@ -348,28 +395,26 @@ impl MemoryType { mem_block.sub_allocator.free(allocation.chunk_id)?; - if mem_block.sub_allocator.is_empty() { - if mem_block.sub_allocator.supports_general_allocations() { - if self.active_general_blocks > 1 { - let block = self.memory_blocks[block_idx].take(); - if block.is_none() { - return Err(AllocationError::Internal( - "Memory block must be Some.".into(), - )); - } - // Note that `block` will be destroyed on `drop` here + // We only want to destroy this now-empty block if it is either a dedicated/personal + // allocation, or a block supporting sub-allocations that is not the last one (ensuring + // there's always at least one block/allocator readily available). + let is_dedicated_or_not_last_general_block = + !mem_block.sub_allocator.supports_general_allocations() + || self.active_general_blocks > 1; + if mem_block.sub_allocator.is_empty() && is_dedicated_or_not_last_general_block { + let block = self.memory_blocks[block_idx] + .take() + .ok_or_else(|| AllocationError::Internal("Memory block must be Some.".into()))?; + + if block.sub_allocator.supports_general_allocations() { + self.active_general_blocks -= 1; + } - self.active_general_blocks -= 1; - } - } else { - let block = self.memory_blocks[block_idx].take(); - if block.is_none() { - return Err(AllocationError::Internal( - "Memory block must be Some.".into(), - )); - } - // Note that `block` will be destroyed on `drop` here + if let Some(rs) = &self.global_residency_set { + unsafe { rs.removeAllocation(block.heap.as_ref()) } } + + // Note that `block` will be destroyed on `drop` here } Ok(()) @@ -380,32 +425,45 @@ impl Allocator { pub fn new(desc: &AllocatorCreateDesc) -> Result<Self> { let heap_types = [ (MemoryLocation::GpuOnly, { - let heap_desc = metal::HeapDescriptor::new(); - heap_desc.set_cpu_cache_mode(metal::MTLCPUCacheMode::DefaultCache); - heap_desc.set_storage_mode(metal::MTLStorageMode::Private); - heap_desc.set_heap_type(metal::MTLHeapType::Placement); + let heap_desc = unsafe { MTLHeapDescriptor::new() }; + heap_desc.setCpuCacheMode(MTLCPUCacheMode::DefaultCache); + heap_desc.setStorageMode(MTLStorageMode::Private); + heap_desc.setType(MTLHeapType::Placement); heap_desc }), (MemoryLocation::CpuToGpu, { - let heap_desc = metal::HeapDescriptor::new(); - heap_desc.set_cpu_cache_mode(metal::MTLCPUCacheMode::WriteCombined); - heap_desc.set_storage_mode(metal::MTLStorageMode::Shared); - heap_desc.set_heap_type(metal::MTLHeapType::Placement); + let heap_desc = unsafe { MTLHeapDescriptor::new() }; + heap_desc.setCpuCacheMode(MTLCPUCacheMode::WriteCombined); + heap_desc.setStorageMode(MTLStorageMode::Shared); + heap_desc.setType(MTLHeapType::Placement); heap_desc }), (MemoryLocation::GpuToCpu, { - let heap_desc = metal::HeapDescriptor::new(); - heap_desc.set_cpu_cache_mode(metal::MTLCPUCacheMode::DefaultCache); - heap_desc.set_storage_mode(metal::MTLStorageMode::Shared); - heap_desc.set_heap_type(metal::MTLHeapType::Placement); + let heap_desc = unsafe { MTLHeapDescriptor::new() }; + heap_desc.setCpuCacheMode(MTLCPUCacheMode::DefaultCache); + heap_desc.setStorageMode(MTLStorageMode::Shared); + heap_desc.setType(MTLHeapType::Placement); heap_desc }), ]; + let global_residency_set = if desc.create_residency_set { + Some(unsafe { + let rs_desc = objc2_metal::MTLResidencySetDescriptor::new(); + rs_desc.setLabel(Some(ns_string!("gpu-allocator global residency set"))); + desc.device + .newResidencySetWithDescriptor_error(&rs_desc) + .expect("Failed to create MTLResidencySet. Unsupported MacOS/iOS version?") + }) + } else { + None + }; + let memory_types = heap_types .into_iter() .enumerate() .map(|(i, (memory_location, heap_descriptor))| MemoryType { + global_residency_set: global_residency_set.clone(), memory_blocks: vec![], _committed_allocations: CommittedAllocationStatistics { num_allocations: 0, @@ -423,6 +481,7 @@ impl Allocator { debug_settings: desc.debug_settings, memory_types, allocation_sizes: desc.allocation_sizes, + global_residency_set, }) } @@ -430,6 +489,7 @@ impl Allocator { let size = desc.size; let alignment = desc.alignment; + #[cfg(feature = "std")] let backtrace = Arc::new(if self.debug_settings.store_stack_traces { Backtrace::force_capture() } else { @@ -441,9 +501,10 @@ impl Allocator { "Allocating `{}` of {} bytes with an alignment of {}.", &desc.name, size, alignment ); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); - debug!("Allocation stack trace: {}", backtrace); + debug!("Allocation stack trace: {backtrace}"); } } @@ -462,16 +523,23 @@ impl Allocator { }) .ok_or(AllocationError::NoCompatibleMemoryTypeFound)?; - memory_type.allocate(&self.device, desc, backtrace, &self.allocation_sizes) + memory_type.allocate( + &self.device, + desc, + #[cfg(feature = "std")] + backtrace, + &self.allocation_sizes, + ) } pub fn free(&mut self, allocation: &Allocation) -> Result<()> { if self.debug_settings.log_frees { let name = allocation.name.as_deref().unwrap_or("<null>"); - debug!("Freeing `{}`.", name); + debug!("Freeing `{name}`."); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); - debug!("Free stack trace: {}", backtrace); + debug!("Free stack trace: {backtrace}"); } } @@ -482,25 +550,25 @@ impl Allocator { Ok(()) } - pub fn get_heaps(&self) -> Vec<&metal::HeapRef> { - // Get all memory blocks - let mut heaps: Vec<&metal::HeapRef> = Vec::new(); - for memory_type in &self.memory_types { - for block in memory_type.memory_blocks.iter().flatten() { - heaps.push(block.heap.as_ref()); - } - } - heaps + /// Returns heaps for all memory blocks + pub fn heaps(&self) -> impl Iterator<Item = &ProtocolObject<dyn MTLHeap>> { + self.memory_types.iter().flat_map(|memory_type| { + memory_type + .memory_blocks + .iter() + .flatten() + .map(|block| block.heap.as_ref()) + }) } pub fn generate_report(&self) -> AllocatorReport { let mut allocations = vec![]; let mut blocks = vec![]; - let mut total_reserved_bytes = 0; + let mut total_capacity_bytes = 0; for memory_type in &self.memory_types { for block in memory_type.memory_blocks.iter().flatten() { - total_reserved_bytes += block.size; + total_capacity_bytes += block.size; let first_allocation = allocations.len(); allocations.extend(block.sub_allocator.report_allocations()); blocks.push(MemoryBlockReport { @@ -516,7 +584,47 @@ impl Allocator { allocations, blocks, total_allocated_bytes, - total_reserved_bytes, + total_capacity_bytes, + } + } + + /// Current total capacity of memory blocks allocated on the device, in bytes + pub fn capacity(&self) -> u64 { + let mut total_capacity_bytes = 0; + + for memory_type in &self.memory_types { + for block in memory_type.memory_blocks.iter().flatten() { + total_capacity_bytes += block.size; + } } + + total_capacity_bytes + } + + /// Optional residency set containing all heap allocations created/owned by this allocator to + /// be made resident at once when its allocations are used on the GPU. The caller _must_ invoke + /// [`MTLResidencySet::commit()`] whenever these resources are used to make sure the latest + /// changes are visible to Metal, e.g. before committing a command buffer. + /// + /// This residency set can be attached to individual command buffers or to a queue directly + /// since usage of allocated resources is expected to be global. + /// + /// Alternatively callers can build up their own residency set(s) based on individual + /// [`MTLAllocation`]s [^heap-allocation] rather than making all heaps allocated via + /// `gpu-allocator` resident at once. + /// + /// [^heap-allocation]: Note that [`MTLHeap`]s returned by [`Allocator::heaps()`] are also + /// allocations. If individual placed [`MTLResource`]s on a heap are made resident, the entire + /// heap will be made resident. + /// + /// Callers still need to be careful to make resources created outside of `gpu-allocator` + /// resident on the GPU, such as indirect command buffers. + /// + /// This residency set is only available when requested via + /// [`AllocatorCreateDesc::create_residency_set`], otherwise this function returns [`None`]. + pub fn residency_set(&self) -> Option<&Retained<ProtocolObject<dyn MTLResidencySet>>> { + // Return the retained object so that the caller also has a way to store it, since we will + // keep using and updating the same object going forward. + self.global_residency_set.as_ref() } } diff --git a/third_party/rust/gpu-allocator/src/metal/visualizer.rs b/third_party/rust/gpu-allocator/src/metal/visualizer.rs @@ -0,0 +1,192 @@ +#![allow(clippy::new_without_default)] + +use super::Allocator; +use crate::visualizer::{ + render_allocation_reports_ui, AllocationReportVisualizeSettings, ColorScheme, + MemoryChunksVisualizationSettings, +}; + +struct AllocatorVisualizerBlockWindow { + memory_type_index: usize, + block_index: usize, + settings: MemoryChunksVisualizationSettings, +} +impl AllocatorVisualizerBlockWindow { + fn new(memory_type_index: usize, block_index: usize) -> Self { + Self { + memory_type_index, + block_index, + settings: Default::default(), + } + } +} + +pub struct AllocatorVisualizer { + selected_blocks: Vec<AllocatorVisualizerBlockWindow>, + color_scheme: ColorScheme, + breakdown_settings: AllocationReportVisualizeSettings, +} + +impl AllocatorVisualizer { + pub fn new() -> Self { + Self { + selected_blocks: Vec::default(), + color_scheme: ColorScheme::default(), + breakdown_settings: Default::default(), + } + } + + pub fn set_color_scheme(&mut self, color_scheme: ColorScheme) { + self.color_scheme = color_scheme; + } + + pub fn render_memory_block_ui(&mut self, ui: &mut egui::Ui, alloc: &Allocator) { + ui.collapsing( + format!("Memory Types: ({} types)", alloc.memory_types.len()), + |ui| { + for (mem_type_idx, mem_type) in alloc.memory_types.iter().enumerate() { + ui.collapsing( + format!( + "Type: {} ({} blocks)", + mem_type_idx, + mem_type.memory_blocks.len(), + ), + |ui| { + let mut total_block_size = 0; + let mut total_allocated = 0; + + for block in mem_type.memory_blocks.iter().flatten() { + total_block_size += block.size; + total_allocated += block.sub_allocator.allocated(); + } + + let active_block_count = mem_type + .memory_blocks + .iter() + .filter(|block| block.is_some()) + .count(); + + ui.label(format!("properties: {:?}", mem_type.heap_properties)); + ui.label(format!("memory type index: {}", mem_type.memory_type_index)); + ui.label(format!("total block size: {} KiB", total_block_size / 1024)); + ui.label(format!("total allocated: {} KiB", total_allocated / 1024)); + ui.label(format!("block count: {active_block_count}")); + + for (block_idx, block) in mem_type.memory_blocks.iter().enumerate() { + let Some(block) = block else { continue }; + + ui.collapsing(format!("Block: {block_idx}"), |ui| { + ui.label(format!("size: {} KiB", block.size / 1024)); + ui.label(format!( + "allocated: {} KiB", + block.sub_allocator.allocated() / 1024 + )); + ui.label(format!("Heap: {:?}", &block.heap)); + + block.sub_allocator.draw_base_info(ui); + + if block.sub_allocator.supports_visualization() + && ui.button("visualize").clicked() + && !self.selected_blocks.iter().any(|x| { + x.memory_type_index == mem_type_idx + && x.block_index == block_idx + }) + { + self.selected_blocks.push( + AllocatorVisualizerBlockWindow::new( + mem_type_idx, + block_idx, + ), + ); + } + }); + } + }, + ); + } + }, + ); + } + + pub fn render_memory_block_window( + &mut self, + ctx: &egui::Context, + allocator: &Allocator, + open: &mut bool, + ) { + egui::Window::new("Allocator Memory Blocks") + .open(open) + .show(ctx, |ui| self.render_breakdown_ui(ui, allocator)); + } + + pub fn render_memory_block_visualization_windows( + &mut self, + ctx: &egui::Context, + allocator: &Allocator, + ) { + // Draw each window. + let color_scheme = &self.color_scheme; + + self.selected_blocks.retain_mut(|window| { + let mut open = true; + + egui::Window::new(format!( + "Block Visualizer {}:{}", + window.memory_type_index, window.block_index + )) + .default_size([1920.0 * 0.5, 1080.0 * 0.5]) + .open(&mut open) + .show(ctx, |ui| { + let memblock = &allocator.memory_types[window.memory_type_index].memory_blocks + [window.block_index] + .as_ref(); + if let Some(memblock) = memblock { + ui.label(format!( + "Memory type {}, Memory block {}, Block size: {} KiB", + window.memory_type_index, + window.block_index, + memblock.size / 1024 + )); + + window + .settings + .ui(ui, allocator.debug_settings.store_stack_traces); + + ui.separator(); + + memblock + .sub_allocator + .draw_visualization(color_scheme, ui, &window.settings); + } else { + ui.label("Deallocated memory block"); + } + }); + + open + }); + } + + pub fn render_breakdown_ui(&mut self, ui: &mut egui::Ui, allocator: &Allocator) { + render_allocation_reports_ui( + ui, + &mut self.breakdown_settings, + allocator + .memory_types + .iter() + .flat_map(|memory_type| memory_type.memory_blocks.iter()) + .flatten() + .flat_map(|memory_block| memory_block.sub_allocator.report_allocations()), + ); + } + + pub fn render_breakdown_window( + &mut self, + ctx: &egui::Context, + allocator: &Allocator, + open: &mut bool, + ) { + egui::Window::new("Allocator Breakdown") + .open(open) + .show(ctx, |ui| self.render_breakdown_ui(ui, allocator)); + } +} diff --git a/third_party/rust/gpu-allocator/src/result.rs b/third_party/rust/gpu-allocator/src/result.rs @@ -1,3 +1,5 @@ +use alloc::string::String; + use thiserror::Error; #[derive(Error, Debug)] @@ -22,4 +24,4 @@ pub enum AllocationError { CastableFormatsRequiresAtLeastDevice12, } -pub type Result<V, E = AllocationError> = ::std::result::Result<V, E>; +pub type Result<V, E = AllocationError> = ::core::result::Result<V, E>; diff --git a/third_party/rust/gpu-allocator/src/visualizer/allocation_reports.rs b/third_party/rust/gpu-allocator/src/visualizer/allocation_reports.rs @@ -92,7 +92,7 @@ pub(crate) fn render_allocation_reports_ui( (AllocationReportVisualizeSorting::None, _) => {} (AllocationReportVisualizeSorting::Idx, true) => allocations.sort_by_key(|(idx, _)| *idx), (AllocationReportVisualizeSorting::Idx, false) => { - allocations.sort_by_key(|(idx, _)| std::cmp::Reverse(*idx)) + allocations.sort_by_key(|(idx, _)| core::cmp::Reverse(*idx)) } (AllocationReportVisualizeSorting::Name, true) => { allocations.sort_by(|(_, alloc1), (_, alloc2)| alloc1.name.cmp(&alloc2.name)) @@ -104,7 +104,7 @@ pub(crate) fn render_allocation_reports_ui( allocations.sort_by_key(|(_, alloc)| alloc.size) } (AllocationReportVisualizeSorting::Size, false) => { - allocations.sort_by_key(|(_, alloc)| std::cmp::Reverse(alloc.size)) + allocations.sort_by_key(|(_, alloc)| core::cmp::Reverse(alloc.size)) } } diff --git a/third_party/rust/gpu-allocator/src/visualizer/memory_chunks.rs b/third_party/rust/gpu-allocator/src/visualizer/memory_chunks.rs @@ -80,7 +80,6 @@ pub(crate) fn render_memory_chunks_ui<'a>( if cursor_idx < data.len() { bytes_required = data[cursor_idx].size; } - continue; } let bytes_used = bytes_required.min(bytes_left); @@ -112,7 +111,7 @@ pub(crate) fn render_memory_chunks_ui<'a>( chunk.allocation_type.as_str() )); if let Some(name) = &chunk.name { - ui.label(format!("name: {}", name)); + ui.label(format!("name: {name}")); } if settings.show_backtraces && chunk.backtrace.status() == BacktraceStatus::Captured diff --git a/third_party/rust/gpu-allocator/src/vulkan/mod.rs b/third_party/rust/gpu-allocator/src/vulkan/mod.rs @@ -1,17 +1,23 @@ -#![deny(clippy::unimplemented, clippy::unwrap_used, clippy::ok_expect)] - -#[cfg(feature = "visualizer")] -mod visualizer; -use std::{backtrace::Backtrace, fmt, marker::PhantomData, sync::Arc}; +#[cfg(feature = "std")] +use alloc::sync::Arc; +use alloc::{borrow::ToOwned, boxed::Box, string::ToString, vec::Vec}; +use core::{fmt, marker::PhantomData}; +#[cfg(feature = "std")] +use std::backtrace::Backtrace; use ash::vk; use log::{debug, Level}; + +#[cfg(feature = "visualizer")] +mod visualizer; #[cfg(feature = "visualizer")] pub use visualizer::AllocatorVisualizer; -use super::allocator; use crate::{ - allocator::{AllocatorReport, MemoryBlockReport}, + allocator::{ + AllocationType, AllocatorReport, DedicatedBlockAllocator, FreeListAllocator, + MemoryBlockReport, SubAllocator, + }, AllocationError, AllocationSizes, AllocatorDebugSettings, MemoryLocation, Result, }; @@ -45,7 +51,7 @@ pub struct AllocationCreateDesc<'a> { /// mark the entire [`Allocation`] as such, instead relying on the compiler to /// auto-implement this or fail if fields are added that violate this constraint #[derive(Clone, Copy, Debug)] -pub(crate) struct SendSyncPtr(std::ptr::NonNull<std::ffi::c_void>); +pub(crate) struct SendSyncPtr(core::ptr::NonNull<core::ffi::c_void>); // Sending is fine because mapped_ptr does not change based on the thread we are in unsafe impl Send for SendSyncPtr {} // Sync is also okay because Sending &Allocation is safe: a mutable reference @@ -149,7 +155,7 @@ pub struct AllocatorCreateDesc { /// [\[1\]]: presser#motivation #[derive(Debug)] pub struct Allocation { - chunk_id: Option<std::num::NonZeroU64>, + chunk_id: Option<core::num::NonZeroU64>, offset: u64, size: u64, memory_block_index: usize, @@ -198,7 +204,7 @@ impl Allocation { }) } - pub fn chunk_id(&self) -> Option<std::num::NonZeroU64> { + pub fn chunk_id(&self) -> Option<core::num::NonZeroU64> { self.chunk_id } @@ -208,13 +214,17 @@ impl Allocation { } /// Returns the [`vk::DeviceMemory`] object that is backing this allocation. - /// This memory object can be shared with multiple other allocations and shouldn't be freed (or allocated from) + /// + /// This memory object can be shared with multiple other allocations and shouldn't be freed or allocated from /// without this library, because that will lead to undefined behavior. /// /// # Safety - /// The result of this function can safely be used to pass into [`ash::Device::bind_buffer_memory()`], - /// [`ash::Device::bind_image_memory()`] etc. It is exposed for this reason. Keep in mind to also - /// pass [`Self::offset()`] along to those. + /// The result of this function can safely be passed into [`ash::Device::bind_buffer_memory()`], + /// [`ash::Device::bind_image_memory()`] etc. It is exposed for this reason. Keep in mind to + /// also pass [`Self::offset()`] along to those. + /// + /// Also, this [`Allocation`] must not be [`Allocator::free()`]d while such a created resource + /// on this [`vk::DeviceMemory`] is still live. pub unsafe fn memory(&self) -> vk::DeviceMemory { self.device_memory } @@ -237,7 +247,7 @@ impl Allocation { /// Returns a valid mapped pointer if the memory is host visible, otherwise it will return None. /// The pointer already points to the exact memory region of the suballocation, so no offset needs to be applied. - pub fn mapped_ptr(&self) -> Option<std::ptr::NonNull<std::ffi::c_void>> { + pub fn mapped_ptr(&self) -> Option<core::ptr::NonNull<core::ffi::c_void>> { self.mapped_ptr.map(|SendSyncPtr(p)| p) } @@ -245,7 +255,7 @@ impl Allocation { /// The slice already references the exact memory region of the allocation, so no offset needs to be applied. pub fn mapped_slice(&self) -> Option<&[u8]> { self.mapped_ptr().map(|ptr| unsafe { - std::slice::from_raw_parts(ptr.cast().as_ptr(), self.size as usize) + core::slice::from_raw_parts(ptr.cast().as_ptr(), self.size as usize) }) } @@ -253,7 +263,7 @@ impl Allocation { /// The slice already references the exact memory region of the allocation, so no offset needs to be applied. pub fn mapped_slice_mut(&mut self) -> Option<&mut [u8]> { self.mapped_ptr().map(|ptr| unsafe { - std::slice::from_raw_parts_mut(ptr.cast().as_ptr(), self.size as usize) + core::slice::from_raw_parts_mut(ptr.cast().as_ptr(), self.size as usize) }) } @@ -289,7 +299,7 @@ pub struct MappedAllocationSlab<'a> { } // SAFETY: See the safety comment of Allocation::as_mapped_slab above. -unsafe impl<'a> presser::Slab for MappedAllocationSlab<'a> { +unsafe impl presser::Slab for MappedAllocationSlab<'_> { fn base_ptr(&self) -> *const u8 { self.mapped_ptr } @@ -335,7 +345,7 @@ pub(crate) struct MemoryBlock { pub(crate) device_memory: vk::DeviceMemory, pub(crate) size: u64, pub(crate) mapped_ptr: Option<SendSyncPtr>, - pub(crate) sub_allocator: Box<dyn allocator::SubAllocator>, + pub(crate) sub_allocator: Box<dyn SubAllocator>, #[cfg(feature = "visualizer")] pub(crate) dedicated_allocation: bool, } @@ -381,8 +391,7 @@ impl MemoryBlock { unsafe { device.allocate_memory(&alloc_info, None) }.map_err(|e| match e { vk::Result::ERROR_OUT_OF_DEVICE_MEMORY => AllocationError::OutOfMemory, e => AllocationError::Internal(format!( - "Unexpected error in vkAllocateMemory: {:?}", - e + "Unexpected error in vkAllocateMemory: {e:?}" )), })? }; @@ -402,20 +411,20 @@ impl MemoryBlock { AllocationError::FailedToMap(e.to_string()) }) .and_then(|p| { - std::ptr::NonNull::new(p).map(SendSyncPtr).ok_or_else(|| { + core::ptr::NonNull::new(p).map(SendSyncPtr).ok_or_else(|| { AllocationError::FailedToMap("Returned mapped pointer is null".to_owned()) }) }) }) .transpose()?; - let sub_allocator: Box<dyn allocator::SubAllocator> = if allocation_scheme + let sub_allocator: Box<dyn SubAllocator> = if allocation_scheme != AllocationScheme::GpuAllocatorManaged || requires_personal_block { - Box::new(allocator::DedicatedBlockAllocator::new(size)) + Box::new(DedicatedBlockAllocator::new(size)) } else { - Box::new(allocator::FreeListAllocator::new(size)) + Box::new(FreeListAllocator::new(size)) }; Ok(Self { @@ -454,23 +463,20 @@ impl MemoryType { device: &ash::Device, desc: &AllocationCreateDesc<'_>, granularity: u64, - backtrace: Arc<Backtrace>, + #[cfg(feature = "std")] backtrace: Arc<Backtrace>, allocation_sizes: &AllocationSizes, ) -> Result<Allocation> { let allocation_type = if desc.linear { - allocator::AllocationType::Linear + AllocationType::Linear } else { - allocator::AllocationType::NonLinear + AllocationType::NonLinear }; - let memblock_size = if self + let is_host = self .memory_properties - .contains(vk::MemoryPropertyFlags::HOST_VISIBLE) - { - allocation_sizes.host_memblock_size - } else { - allocation_sizes.device_memblock_size - }; + .contains(vk::MemoryPropertyFlags::HOST_VISIBLE); + + let memblock_size = allocation_sizes.get_memblock_size(is_host, self.active_general_blocks); let size = desc.requirements.size; let alignment = desc.requirements.alignment; @@ -519,6 +525,7 @@ impl MemoryType { allocation_type, granularity, desc.name, + #[cfg(feature = "std")] backtrace, )?; @@ -545,6 +552,7 @@ impl MemoryType { allocation_type, granularity, desc.name, + #[cfg(feature = "std")] backtrace.clone(), ); @@ -553,7 +561,7 @@ impl MemoryType { let mapped_ptr = if let Some(SendSyncPtr(mapped_ptr)) = mem_block.mapped_ptr { let offset_ptr = unsafe { mapped_ptr.as_ptr().add(offset as usize) }; - std::ptr::NonNull::new(offset_ptr).map(SendSyncPtr) + core::ptr::NonNull::new(offset_ptr).map(SendSyncPtr) } else { None }; @@ -609,6 +617,7 @@ impl MemoryType { allocation_type, granularity, desc.name, + #[cfg(feature = "std")] backtrace, ); let (offset, chunk_id) = match allocation { @@ -626,7 +635,7 @@ impl MemoryType { let mapped_ptr = if let Some(SendSyncPtr(mapped_ptr)) = mem_block.mapped_ptr { let offset_ptr = unsafe { mapped_ptr.as_ptr().add(offset as usize) }; - std::ptr::NonNull::new(offset_ptr).map(SendSyncPtr) + core::ptr::NonNull::new(offset_ptr).map(SendSyncPtr) } else { None }; @@ -655,24 +664,22 @@ impl MemoryType { mem_block.sub_allocator.free(allocation.chunk_id)?; - if mem_block.sub_allocator.is_empty() { - if mem_block.sub_allocator.supports_general_allocations() { - if self.active_general_blocks > 1 { - let block = self.memory_blocks[block_idx].take(); - let block = block.ok_or_else(|| { - AllocationError::Internal("Memory block must be Some.".into()) - })?; - block.destroy(device); - - self.active_general_blocks -= 1; - } - } else { - let block = self.memory_blocks[block_idx].take(); - let block = block.ok_or_else(|| { - AllocationError::Internal("Memory block must be Some.".into()) - })?; - block.destroy(device); + // We only want to destroy this now-empty block if it is either a dedicated/personal + // allocation, or a block supporting sub-allocations that is not the last one (ensuring + // there's always at least one block/allocator readily available). + let is_dedicated_or_not_last_general_block = + !mem_block.sub_allocator.supports_general_allocations() + || self.active_general_blocks > 1; + if mem_block.sub_allocator.is_empty() && is_dedicated_or_not_last_general_block { + let block = self.memory_blocks[block_idx] + .take() + .ok_or_else(|| AllocationError::Internal("Memory block must be Some.".into()))?; + + if block.sub_allocator.supports_general_allocations() { + self.active_general_blocks -= 1; } + + block.destroy(device); } Ok(()) @@ -762,7 +769,7 @@ impl Allocator { device: desc.device.clone(), buffer_image_granularity: granularity, debug_settings: desc.debug_settings, - allocation_sizes: AllocationSizes::default(), + allocation_sizes: desc.allocation_sizes, }) } @@ -770,6 +777,7 @@ impl Allocator { let size = desc.requirements.size; let alignment = desc.requirements.alignment; + #[cfg(feature = "std")] let backtrace = Arc::new(if self.debug_settings.store_stack_traces { Backtrace::force_capture() } else { @@ -781,9 +789,10 @@ impl Allocator { "Allocating `{}` of {} bytes with an alignment of {}.", &desc.name, size, alignment ); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); - debug!("Allocation stack trace: {}", backtrace); + debug!("Allocation stack trace: {backtrace}"); } } @@ -835,6 +844,7 @@ impl Allocator { &self.device, desc, self.buffer_image_granularity, + #[cfg(feature = "std")] backtrace.clone(), &self.allocation_sizes, ) @@ -857,6 +867,7 @@ impl Allocator { &self.device, desc, self.buffer_image_granularity, + #[cfg(feature = "std")] backtrace, &self.allocation_sizes, ) @@ -871,10 +882,11 @@ impl Allocator { pub fn free(&mut self, allocation: Allocation) -> Result<()> { if self.debug_settings.log_frees { let name = allocation.name.as_deref().unwrap_or("<null>"); - debug!("Freeing `{}`.", name); + debug!("Freeing `{name}`."); + #[cfg(feature = "std")] if self.debug_settings.log_stack_traces { let backtrace = Backtrace::force_capture(); - debug!("Free stack trace: {}", backtrace); + debug!("Free stack trace: {backtrace}"); } } @@ -935,11 +947,11 @@ impl Allocator { pub fn generate_report(&self) -> AllocatorReport { let mut allocations = vec![]; let mut blocks = vec![]; - let mut total_reserved_bytes = 0; + let mut total_capacity_bytes = 0; for memory_type in &self.memory_types { for block in memory_type.memory_blocks.iter().flatten() { - total_reserved_bytes += block.size; + total_capacity_bytes += block.size; let first_allocation = allocations.len(); allocations.extend(block.sub_allocator.report_allocations()); blocks.push(MemoryBlockReport { @@ -955,8 +967,21 @@ impl Allocator { allocations, blocks, total_allocated_bytes, - total_reserved_bytes, + total_capacity_bytes, + } + } + + /// Current total capacity of memory blocks allocated on the device, in bytes + pub fn capacity(&self) -> u64 { + let mut total_capacity_bytes = 0; + + for memory_type in &self.memory_types { + for block in memory_type.memory_blocks.iter().flatten() { + total_capacity_bytes += block.size; + } } + + total_capacity_bytes } } diff --git a/third_party/rust/gpu-allocator/src/vulkan/visualizer.rs b/third_party/rust/gpu-allocator/src/vulkan/visualizer.rs @@ -50,7 +50,7 @@ impl AllocatorVisualizer { format!("Memory Heaps ({} heaps)", alloc.memory_heaps.len()), |ui| { for (i, heap) in alloc.memory_heaps.iter().enumerate() { - ui.collapsing(format!("Heap: {}", i), |ui| { + ui.collapsing(format!("Heap: {i}"), |ui| { ui.label(format!("flags: {:?}", heap.flags)); ui.label(format!( "size: {} MiB", @@ -90,12 +90,12 @@ impl AllocatorVisualizer { ui.label(format!("heap index: {}", mem_type.heap_index)); ui.label(format!("total block size: {} KiB", total_block_size / 1024)); ui.label(format!("total allocated: {} KiB", total_allocated / 1024)); - ui.label(format!("block count: {}", active_block_count)); + ui.label(format!("block count: {active_block_count}")); for (block_idx, block) in mem_type.memory_blocks.iter().enumerate() { let Some(block) = block else { continue }; - ui.collapsing(format!("Block: {}", block_idx), |ui| { + ui.collapsing(format!("Block: {block_idx}"), |ui| { use ash::vk::Handle; ui.label(format!("size: {} KiB", block.size / 1024)); diff --git a/third_party/rust/memtest/.cargo-checksum.json b/third_party/rust/memtest/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"b5e44890473b110841f7612656ac9ee8ba1992481ebc52f9fa2e749e8b2bc945","Cargo.toml":"bfb11483b2babbef10625c54601df9180cf132686f59989c92af8838ce946669","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"9317903e5896852844bd769652ac9818c9fec6d5b57424f230e30ff7f82e2e49","examples/usage.rs":"1c4c9ed3c421043b52fbe47e04f214a2a2fc0acd3be7d1469b8f991bce6eda8e","src/lib.rs":"277ce7a2cc92b0896a02b01807417d149472fbfbb9a7c31a9184b9151fdf458a","src/memtest.rs":"292f1ab00a83294b61eeb6083058c467dd2cfa642458044e47ed9161829e3541","src/prelude.rs":"73581af5d71192875b4c9b525c5f2e150b505e3f6df8ec1c837632a5f08b50fd"},"package":"f8ff5f1d8294a1fd0c8a32428d826ae22da3d473f0052c6e6d449a91b24e365c"} -\ No newline at end of file +{"files":{"Cargo.toml":"714504088313bc89f9bf84a6b1c136e0e44456bd4871eff22c50e15b49b960ee","LICENSE":"1f256ecad192880510e84ad60474eab7589218784b9a50bc7ceee34c2b91f1d5","README.md":"9317903e5896852844bd769652ac9818c9fec6d5b57424f230e30ff7f82e2e49","examples/usage.rs":"1c4c9ed3c421043b52fbe47e04f214a2a2fc0acd3be7d1469b8f991bce6eda8e","src/lib.rs":"277ce7a2cc92b0896a02b01807417d149472fbfbb9a7c31a9184b9151fdf458a","src/memtest.rs":"292f1ab00a83294b61eeb6083058c467dd2cfa642458044e47ed9161829e3541","src/prelude.rs":"73581af5d71192875b4c9b525c5f2e150b505e3f6df8ec1c837632a5f08b50fd"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/memtest/Cargo.lock b/third_party/rust/memtest/Cargo.lock @@ -1,491 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 4 - -[[package]] -name = "anyhow" -version = "1.0.98" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "getrandom" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "hermit-abi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" - -[[package]] -name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "lazy_static" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" - -[[package]] -name = "libc" -version = "0.2.172" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" - -[[package]] -name = "log" -version = "0.4.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" - -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - -[[package]] -name = "memtest" -version = "0.4.0" -dependencies = [ - "anyhow", - "libc", - "num_cpus", - "rand", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", - "windows", -] - -[[package]] -name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.21.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" - -[[package]] -name = "pin-project-lite" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" - -[[package]] -name = "ppv-lite86" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" -dependencies = [ - "zerocopy", -] - -[[package]] -name = "proc-macro2" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "serde" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.219" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.140" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" -dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "smallvec" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" - -[[package]] -name = "syn" -version = "2.0.101" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thread_local" -version = "1.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" -dependencies = [ - "cfg-if", - "once_cell", -] - -[[package]] -name = "tracing" -version = "0.1.41" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" -dependencies = [ - "log", - "once_cell", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" -dependencies = [ - "nu-ansi-term", - "sharded-slab", - "smallvec", - "thread_local", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "unicode-ident" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" - -[[package]] -name = "valuable" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core", - "windows-targets", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement", - "windows-interface", - "windows-result", - "windows-strings", - "windows-targets", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result", - "windows-targets", -] - -[[package]] -name = "windows-targets" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_gnullvm", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" - -[[package]] -name = "windows_i686_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" - -[[package]] -name = "windows_i686_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" - -[[package]] -name = "windows_i686_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.52.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "zerocopy" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1702d9583232ddb9174e01bb7c15a2ab8fb1bc6f227aa1233858c351a3ba0cb" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.8.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a6e20d751156648aa063f3800b706ee209a32c0b4d9f24be3d980b01be55ef" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] diff --git a/third_party/rust/memtest/Cargo.toml b/third_party/rust/memtest/Cargo.toml @@ -38,11 +38,11 @@ path = "src/lib.rs" name = "usage" path = "examples/usage.rs" -[dependencies.anyhow] -version = "1.0.69" - -[dependencies.num_cpus] -version = "1.16.0" +[dependencies] +anyhow = "1.0.69" +num_cpus = "1.16.0" +serde_json = "1.0.116" +tracing = "0.1.37" [dependencies.rand] version = "0.8.5" @@ -52,20 +52,14 @@ features = ["small_rng"] version = "1.0.214" features = ["derive"] -[dependencies.serde_json] -version = "1.0.116" - -[dependencies.tracing] -version = "0.1.37" - -[dev-dependencies.tracing-subscriber] -version = "0.3.18" +[dev-dependencies] +tracing-subscriber = "0.3.18" -[target."cfg(unix)".dependencies.libc] -version = "0.2.158" +[target."cfg(unix)".dependencies] +libc = "0.2.158" [target."cfg(windows)".dependencies.windows] -version = "0.58.0" +version = ">=0.58.0,<0.63" features = [ "Win32_Foundation", "Win32_System_Memory", diff --git a/third_party/rust/midir/.cargo-checksum.json b/third_party/rust/midir/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"7a7cdac7475e588c4f13ac7eaa019ec87cee3046895dd71024ba3556a99e9e95","Cargo.toml":"1029e787d240f805940964c1beed988c40a23c490f92e30a438bc231d2228439","LICENSE":"6fe6f623b1fa80e90679aee2f917d8978a184988ebb995ebc254cc9633903cac","README.md":"bdcbd5633c687c6fbaed22ee158776ecd56718813a36558c0ee0868bc2a6609e","azure-pipelines-template.yml":"a14f85524c2a89be59f9297b70bff5e2fb5aff4a2658edcaf5d4454cc7257764","azure-pipelines.yml":"702b4833da4052d9ddca1a162eb5ea99495d94b26c47b6d4e598acb370785452","examples/test_forward.rs":"fbc58f0b9a4c902c55d9e48ae02107ef8ffebef7c52c0f7ae55d9803460fd011","examples/test_list_ports.rs":"d535790cf2e3c35797acf1dad25f9327a9dabb242284068993588b719e65005f","examples/test_play.rs":"89722e004b9e8202cb2215f8f9b90478afbd29fe6f7bc9e9685ef9db444d654d","examples/test_read_input.rs":"d0bb090bf31ee2381940a00ebffc276b29cd3f0e8bd5d38baa27b3a23dd38d8c","examples/test_reuse.rs":"8cf3c46373f15cb10b7837912974d2bc14a4623510e06388d966ac39c140f794","examples/test_sysex.rs":"88e8cba16a6f5c6deea6c1021c4698114a0ed1003a66d0bb3a1359c378834229","src/backend/alsa/mod.rs":"62b601cb8a7c231cedaf3c0c9819190d4fbe9609fae0dd7b925167cf1f3ce9b7","src/backend/coremidi/mod.rs":"66f075da1511c1580c809d076400551799e463b026e6b2df3dafeb911e1e22af","src/backend/dummy/mod.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/backend/jack/mod.rs":"c7e5b78caa1eb614f0e89c5b481339a72a6c72f6ef7b4ada1296b7326c8105fc","src/backend/jack/wrappers.rs":"fee48deb0070e4c63b1dbc3739449c67cdfb93daced4d7003bc1cc08e0e3bef5","src/backend/mod.rs":"6794c7abe8c79a1c00ad6d87887bcdd644e697501f435c9c0bfa7f43aa586306","src/backend/webmidi/mod.rs":"0528d69c3ca9e33379b1c92b6ed72a63367281ffa0e325fb843229dd5bac0e10","src/backend/winmm/handler.rs":"828a3ea6e890b0d13b200022c4c0a9e11c318dd2b6bf93e262b39e3ab4efbfad","src/backend/winmm/mod.rs":"c4a29df2f5ba3312b54e3434c3327096a07c7808beae52a0e421a2d8deae2ab3","src/backend/winrt/mod.rs":"8366f044d1a7a9ba790c96b6d0acaa0d4a579cc9129b10a95cd4277a2e7dca2f","src/common.rs":"0bd4500ea9fffe59cb6260964ff0765f92cbcb44a515bb16490c7d8ecdc4e1b8","src/errors.rs":"85823c6b2c8a8b7d3545cf9724ac72af29c44dc884176553b4f91a20b58eb4ab","src/lib.rs":"506d579534d30d80543f6386458ebaf8bb8e860888f889305184e64fc37cb907","src/os/mod.rs":"4b2bd865bbfae91272c7582792a19d55b450623688d271b2f866598813f4bcde","src/os/unix.rs":"04375f23353fa38de08150af3b25342f9b8dd7fefb14652053998977b1c1d114","tests/virtual.rs":"559ed012016e1020077b3784cff3a7f694f950e97cd4fa49dc42a52afcfeabff"},"package":null} -\ No newline at end of file +{"files":{"CHANGELOG.md":"7a7cdac7475e588c4f13ac7eaa019ec87cee3046895dd71024ba3556a99e9e95","Cargo.toml":"847386bbd418a1a7e734f6f9d4e7fea5d78a52dbbe3e4359edbc31910a09f37b","LICENSE":"6fe6f623b1fa80e90679aee2f917d8978a184988ebb995ebc254cc9633903cac","README.md":"bdcbd5633c687c6fbaed22ee158776ecd56718813a36558c0ee0868bc2a6609e","azure-pipelines-template.yml":"a14f85524c2a89be59f9297b70bff5e2fb5aff4a2658edcaf5d4454cc7257764","azure-pipelines.yml":"702b4833da4052d9ddca1a162eb5ea99495d94b26c47b6d4e598acb370785452","examples/test_forward.rs":"fbc58f0b9a4c902c55d9e48ae02107ef8ffebef7c52c0f7ae55d9803460fd011","examples/test_list_ports.rs":"d535790cf2e3c35797acf1dad25f9327a9dabb242284068993588b719e65005f","examples/test_play.rs":"89722e004b9e8202cb2215f8f9b90478afbd29fe6f7bc9e9685ef9db444d654d","examples/test_read_input.rs":"d0bb090bf31ee2381940a00ebffc276b29cd3f0e8bd5d38baa27b3a23dd38d8c","examples/test_reuse.rs":"8cf3c46373f15cb10b7837912974d2bc14a4623510e06388d966ac39c140f794","examples/test_sysex.rs":"88e8cba16a6f5c6deea6c1021c4698114a0ed1003a66d0bb3a1359c378834229","src/backend/alsa/mod.rs":"62b601cb8a7c231cedaf3c0c9819190d4fbe9609fae0dd7b925167cf1f3ce9b7","src/backend/coremidi/mod.rs":"66f075da1511c1580c809d076400551799e463b026e6b2df3dafeb911e1e22af","src/backend/dummy/mod.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/backend/jack/mod.rs":"c7e5b78caa1eb614f0e89c5b481339a72a6c72f6ef7b4ada1296b7326c8105fc","src/backend/jack/wrappers.rs":"fee48deb0070e4c63b1dbc3739449c67cdfb93daced4d7003bc1cc08e0e3bef5","src/backend/mod.rs":"6794c7abe8c79a1c00ad6d87887bcdd644e697501f435c9c0bfa7f43aa586306","src/backend/webmidi/mod.rs":"0528d69c3ca9e33379b1c92b6ed72a63367281ffa0e325fb843229dd5bac0e10","src/backend/winmm/handler.rs":"828a3ea6e890b0d13b200022c4c0a9e11c318dd2b6bf93e262b39e3ab4efbfad","src/backend/winmm/mod.rs":"74da041f89acfd8a9cd31bcbab6d80a678fc6d578a79664f8cb1c10a65cf4693","src/backend/winrt/mod.rs":"81d201d6691ef3a1e94a63a65fba0294d731742a056295807fd91e8595ea7ef9","src/common.rs":"0bd4500ea9fffe59cb6260964ff0765f92cbcb44a515bb16490c7d8ecdc4e1b8","src/errors.rs":"85823c6b2c8a8b7d3545cf9724ac72af29c44dc884176553b4f91a20b58eb4ab","src/lib.rs":"506d579534d30d80543f6386458ebaf8bb8e860888f889305184e64fc37cb907","src/os/mod.rs":"4b2bd865bbfae91272c7582792a19d55b450623688d271b2f866598813f4bcde","src/os/unix.rs":"04375f23353fa38de08150af3b25342f9b8dd7fefb14652053998977b1c1d114","tests/virtual.rs":"559ed012016e1020077b3784cff3a7f694f950e97cd4fa49dc42a52afcfeabff"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/midir/Cargo.toml b/third_party/rust/midir/Cargo.toml @@ -135,7 +135,7 @@ coremidi = "0.8.0" version = "0.12.1" [target.'cfg(target_os = "windows")'.dependencies.windows] -version = "0.58" +version = ">=0.59.0,<=0.62" features = [ "Win32_Foundation", "Win32_Media", diff --git a/third_party/rust/midir/src/backend/winmm/mod.rs b/third_party/rust/midir/src/backend/winmm/mod.rs @@ -90,10 +90,10 @@ impl MidiInputPort { let mut buffer_size: ULONG = 0; let result = unsafe { midiInMessage( - HMIDIIN(port_number as *mut c_void), + Some(HMIDIIN(port_number as *mut c_void)), DRV_QUERYDEVICEINTERFACESIZE, - &mut buffer_size as *mut _ as DWORD_PTR, - 0, + Some(&mut buffer_size as *mut _ as DWORD_PTR), + None, ) }; if result == MMSYSERR_BADDEVICEID { @@ -104,10 +104,10 @@ impl MidiInputPort { let mut buffer = Vec::<u16>::with_capacity(buffer_size as usize / 2); unsafe { let result = midiInMessage( - HMIDIIN(port_number as *mut c_void), + Some(HMIDIIN(port_number as *mut c_void)), DRV_QUERYDEVICEINTERFACE, - buffer.as_mut_ptr() as usize, - buffer_size as DWORD_PTR, + Some(buffer.as_mut_ptr() as usize), + Some(buffer_size as DWORD_PTR), ); if result == MMSYSERR_BADDEVICEID { return Err(PortInfoError::PortNumberOutOfRange); @@ -248,8 +248,8 @@ impl MidiInput { midiInOpen( in_handle.as_mut_ptr(), port_number as UINT, - handler::handle_input::<T> as DWORD_PTR, - handler_data_ptr as DWORD_PTR, + Some(handler::handle_input::<T> as DWORD_PTR), + Some(handler_data_ptr as DWORD_PTR), CALLBACK_FUNCTION, ) }; @@ -429,10 +429,10 @@ impl MidiOutputPort { let mut buffer_size: ULONG = 0; let result = unsafe { midiOutMessage( - HMIDIOUT(port_number as *mut c_void), + Some(HMIDIOUT(port_number as *mut c_void)), DRV_QUERYDEVICEINTERFACESIZE, - &mut buffer_size as *mut _ as DWORD_PTR, - 0, + Some(&mut buffer_size as *mut _ as DWORD_PTR), + None, ) }; if result == MMSYSERR_BADDEVICEID { @@ -443,10 +443,10 @@ impl MidiOutputPort { let mut buffer = Vec::<u16>::with_capacity(buffer_size as usize / 2); unsafe { let result = midiOutMessage( - HMIDIOUT(port_number as *mut c_void), + Some(HMIDIOUT(port_number as *mut c_void)), DRV_QUERYDEVICEINTERFACE, - buffer.as_mut_ptr() as DWORD_PTR, - buffer_size as DWORD_PTR, + Some(buffer.as_mut_ptr() as DWORD_PTR), + Some(buffer_size as DWORD_PTR), ); if result == MMSYSERR_BADDEVICEID { return Err(PortInfoError::PortNumberOutOfRange); @@ -545,8 +545,8 @@ impl MidiOutput { midiOutOpen( out_handle.as_mut_ptr(), port_number as UINT, - 0, - 0, + None, + None, CALLBACK_NULL, ) }; diff --git a/third_party/rust/midir/src/backend/winrt/mod.rs b/third_party/rust/midir/src/backend/winrt/mod.rs @@ -8,7 +8,7 @@ use windows::core::HSTRING; use windows::{ Devices::Enumeration::DeviceInformation, Devices::Midi::*, - Foundation::{EventRegistrationToken, TypedEventHandler}, + Foundation::TypedEventHandler, Storage::Streams::{DataReader, DataWriter}, }; @@ -44,7 +44,7 @@ impl MidiInput { pub(crate) fn ports_internal(&self) -> Vec<crate::common::MidiInputPort> { let device_collection = DeviceInformation::FindAllAsyncAqsFilter(&self.selector) .unwrap() - .get() + .join() .expect("FindAllAsyncAqsFilter failed"); let count = device_collection.Size().expect("Size failed") as usize; let mut result = Vec::with_capacity(count); @@ -60,7 +60,7 @@ impl MidiInput { pub fn port_count(&self) -> usize { let device_collection = DeviceInformation::FindAllAsyncAqsFilter(&self.selector) .unwrap() - .get() + .join() .expect("FindAllAsyncAqsFilter failed"); device_collection.Size().expect("Size failed") as usize } @@ -69,7 +69,7 @@ impl MidiInput { let device_info_async = DeviceInformation::CreateFromIdAsync(&port.id) .map_err(|_| PortInfoError::InvalidPort)?; let device_info = device_info_async - .get() + .join() .map_err(|_| PortInfoError::InvalidPort)?; let device_name = device_info .Name() @@ -113,7 +113,7 @@ impl MidiInput { F: FnMut(u64, &[u8], &mut T) + Send + 'static, { let in_port = match MidiInPort::FromIdAsync(&port.id) { - Ok(port_async) => match port_async.get() { + Ok(port_async) => match port_async.join() { Ok(port) => port, _ => return Err(ConnectError::new(ConnectErrorKind::InvalidPort, self)), }, @@ -129,7 +129,7 @@ impl MidiInput { type Handler = TypedEventHandler<MidiInPort, MidiMessageReceivedEventArgs>; let handler = Handler::new( - move |_sender, args: &Option<MidiMessageReceivedEventArgs>| { + move |_sender, args: windows::core::Ref<'_, MidiMessageReceivedEventArgs>| { MidiInput::handle_input( args.as_ref() .expect("MidiMessageReceivedEventArgs were null"), @@ -155,7 +155,7 @@ unsafe impl Send for RtMidiInPort {} pub struct MidiInputConnection<T> { port: RtMidiInPort, - event_token: EventRegistrationToken, + event_token: i64, // TODO: get rid of Arc & Mutex? // synchronization is required because the borrow checker does not // know that the callback we're in here is never called concurrently @@ -216,7 +216,7 @@ impl MidiOutput { pub(crate) fn ports_internal(&self) -> Vec<crate::common::MidiOutputPort> { let device_collection = DeviceInformation::FindAllAsyncAqsFilter(&self.selector) .unwrap() - .get() + .join() .expect("FindAllAsyncAqsFilter failed"); let count = device_collection.Size().expect("Size failed") as usize; let mut result = Vec::with_capacity(count); @@ -232,7 +232,7 @@ impl MidiOutput { pub fn port_count(&self) -> usize { let device_collection = DeviceInformation::FindAllAsyncAqsFilter(&self.selector) .unwrap() - .get() + .join() .expect("FindAllAsyncAqsFilter failed"); device_collection.Size().expect("Size failed") as usize } @@ -241,7 +241,7 @@ impl MidiOutput { let device_info_async = DeviceInformation::CreateFromIdAsync(&port.id) .map_err(|_| PortInfoError::InvalidPort)?; let device_info = device_info_async - .get() + .join() .map_err(|_| PortInfoError::InvalidPort)?; let device_name = device_info .Name() @@ -255,7 +255,7 @@ impl MidiOutput { _port_name: &str, ) -> Result<MidiOutputConnection, ConnectError<MidiOutput>> { let out_port = match MidiOutPort::FromIdAsync(&port.id) { - Ok(port_async) => match port_async.get() { + Ok(port_async) => match port_async.join() { Ok(port) => port, _ => return Err(ConnectError::new(ConnectErrorKind::InvalidPort, self)), }, diff --git a/third_party/rust/mtu/.cargo-checksum.json b/third_party/rust/mtu/.cargo-checksum.json @@ -1 +1 @@ -{"files":{".clippy.toml":"6ab1a673bd5c7ba29bd77e62f42183db3ace327c23d446d5b4b0618f6c39d639","Cargo.toml":"b4c4826e5e748da588a67852184dac53e76fe3f31f1b1eb7bb390808688103a5","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"4ad721b5b6a3d39ca3e2202f403d897c4a1d42896486dd58963a81f8e64ef61d","README.md":"24df0e24154b7f0096570ad221aea02bd53a0f1124a2adafff5730af5443a65c","SECURITY.md":"75455814b6cf997e22a927eb979b4356d788583aa1eb96e90853aaab0f82ad1b","build.rs":"a4bcd0562c80914a8e909e8b10507605bfd6f0f268fad9ef4d79f4c48bdaed6c","src/bsd.rs":"7641b2a905a5e05505507fdf2e3af37e9c901a997d48759258f9f853cd2ab0e5","src/lib.rs":"6e8702d77e0f211d05862820eec77f2aa8cd8db6ec4de2c5278d223fbd96b31d","src/linux.rs":"aecc6acbea2419dd6cc31e916148e438d8cec20cf001758042299ff2ccc81d39","src/routesocket.rs":"be837947e2c3f9301a174499217fe8920ff492918bf85ca5eb281eb7ad2240e1","src/windows.rs":"d7e18d55b3be5462d2041fc22fb22cf1fc163ec30b107a3274f2bd22ad618411"},"package":null} -\ No newline at end of file +{"files":{".clippy.toml":"6ab1a673bd5c7ba29bd77e62f42183db3ace327c23d446d5b4b0618f6c39d639","Cargo.toml":"8f555c7d677524f948513c56a81ff6d3d984decc66c586557ff9313e92448a66","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"4ad721b5b6a3d39ca3e2202f403d897c4a1d42896486dd58963a81f8e64ef61d","README.md":"24df0e24154b7f0096570ad221aea02bd53a0f1124a2adafff5730af5443a65c","SECURITY.md":"75455814b6cf997e22a927eb979b4356d788583aa1eb96e90853aaab0f82ad1b","build.rs":"a4bcd0562c80914a8e909e8b10507605bfd6f0f268fad9ef4d79f4c48bdaed6c","src/bsd.rs":"7641b2a905a5e05505507fdf2e3af37e9c901a997d48759258f9f853cd2ab0e5","src/lib.rs":"6e8702d77e0f211d05862820eec77f2aa8cd8db6ec4de2c5278d223fbd96b31d","src/linux.rs":"aecc6acbea2419dd6cc31e916148e438d8cec20cf001758042299ff2ccc81d39","src/routesocket.rs":"be837947e2c3f9301a174499217fe8920ff492918bf85ca5eb281eb7ad2240e1","src/windows.rs":"d7e18d55b3be5462d2041fc22fb22cf1fc163ec30b107a3274f2bd22ad618411"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/mtu/Cargo.toml b/third_party/rust/mtu/Cargo.toml @@ -77,13 +77,14 @@ optional = true default-features = false [target."cfg(windows)".dependencies.windows] -version = ">=0.58,<0.60" +version = ">=0.60,<0.63" features = [ "Win32_Foundation", "Win32_NetworkManagement_IpHelper", "Win32_NetworkManagement_Ndis", "Win32_Networking_WinSock", ] +default-features = false [lints.clippy] allow_attributes = "warn" diff --git a/third_party/rust/neqo-common/.cargo-checksum.json b/third_party/rust/neqo-common/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"040088e3a044f56f5e39fb30a6e499743ed6a298f143a61c29e4502fa3273105","benches/decoder.rs":"9a5e780ff68f180d7597e9d56b6d0ae609594a4558e4010babb2f33660ddddbe","build.rs":"d9accad1f92a1d82aff73a588269342db882918173e8d9b2b914c514e42e2839","src/bytes.rs":"b9ce44977af8d0731b51798fa9bd752fa4be437603a08446eb55889c2348281c","src/codec.rs":"1d5a036147a0bd4789eb4caa545f82ee0d18eca25ad1b6bdfd2fad58d99ae29e","src/datagram.rs":"2ad1a6e1f8a157a0361b7b4e7c161d62c7bf742c4247190507b9d050d113a923","src/event.rs":"289cf8e265c33e7cded58820ac81e5b575e3f84dd52fa18b0761f4094fb361c0","src/fuzz.rs":"9e0f2dca1832ef49b93b214e8d5f1ca2f5f8cb84a856fead344f62a722c370db","src/header.rs":"7f5d82577a5e1020ff237143e3aaa7e671403466a5a87f633b4c75f9d4e90aa9","src/hrtime.rs":"fd1fbf9ddd38c77e92abe25d7ab9e62872c1cd62ffae8743835bf94f76b6ddc8","src/incrdecoder.rs":"62f61d2600dafb1eec7d6cc85b3c7b07aba0ccd1149892b1dfa1a441f30927a3","src/lib.rs":"2bb6289a73dc07edfd2bc5bccda9542d403066656f41042116ed31f4fc4725ca","src/log.rs":"61a9b24bf6bf1493da67082bcf7fef8fe55f0a23d7f2a9ad13748982c54c85e2","src/qlog.rs":"2c072bb9ad31aad99c1f41421f162fbc48fbd4a17f4e554187b41267afef144b","src/tos.rs":"e09a69a20d54178a4c74b63596c607dbe8ace4ae0758a65f9878ea63d40e3c80","tests/log.rs":"c73187e390ee1a7c4a72266cb7ce5c326e862803dbcf86c2b9a892462fa22356"},"package":null} -\ No newline at end of file +{"files":{"Cargo.toml":"c77f1227eb1b4e5057779146ec66124d73fd5395858d541a2ccecd145c1e8db3","benches/decoder.rs":"9a5e780ff68f180d7597e9d56b6d0ae609594a4558e4010babb2f33660ddddbe","build.rs":"d9accad1f92a1d82aff73a588269342db882918173e8d9b2b914c514e42e2839","src/bytes.rs":"b9ce44977af8d0731b51798fa9bd752fa4be437603a08446eb55889c2348281c","src/codec.rs":"1d5a036147a0bd4789eb4caa545f82ee0d18eca25ad1b6bdfd2fad58d99ae29e","src/datagram.rs":"2ad1a6e1f8a157a0361b7b4e7c161d62c7bf742c4247190507b9d050d113a923","src/event.rs":"289cf8e265c33e7cded58820ac81e5b575e3f84dd52fa18b0761f4094fb361c0","src/fuzz.rs":"9e0f2dca1832ef49b93b214e8d5f1ca2f5f8cb84a856fead344f62a722c370db","src/header.rs":"7f5d82577a5e1020ff237143e3aaa7e671403466a5a87f633b4c75f9d4e90aa9","src/hrtime.rs":"fd1fbf9ddd38c77e92abe25d7ab9e62872c1cd62ffae8743835bf94f76b6ddc8","src/incrdecoder.rs":"62f61d2600dafb1eec7d6cc85b3c7b07aba0ccd1149892b1dfa1a441f30927a3","src/lib.rs":"2bb6289a73dc07edfd2bc5bccda9542d403066656f41042116ed31f4fc4725ca","src/log.rs":"61a9b24bf6bf1493da67082bcf7fef8fe55f0a23d7f2a9ad13748982c54c85e2","src/qlog.rs":"2c072bb9ad31aad99c1f41421f162fbc48fbd4a17f4e554187b41267afef144b","src/tos.rs":"e09a69a20d54178a4c74b63596c607dbe8ace4ae0758a65f9878ea63d40e3c80","tests/log.rs":"c73187e390ee1a7c4a72266cb7ce5c326e862803dbcf86c2b9a892462fa22356"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/neqo-common/Cargo.toml b/third_party/rust/neqo-common/Cargo.toml @@ -110,7 +110,7 @@ default-features = false path = "../test-fixture" [target."cfg(windows)".dependencies.windows] -version = "0.58" +version = ">=0.60,<0.63" features = ["Win32_Media"] default-features = false diff --git a/third_party/rust/neqo-udp/.cargo-checksum.json b/third_party/rust/neqo-udp/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"3c1085e0f4bfd691ce7e3af2361b79a88602f742b0f84b4d33b4d33e4aef259c","build.rs":"bf57cd35a78f636c14c442c1926abc2deca3d137e9d207e4f2f960f5b8363b07","src/lib.rs":"bb87c16ab8587eb2e3a68b948de6cc0d36a469194f243bfd6b33fcf31c9e6a2d"},"package":null} -\ No newline at end of file +{"files":{"Cargo.toml":"61de4d7309d0bd40ca4793cd8b4a93a120dee8c697f9ed36591c476dbd08e929","build.rs":"bf57cd35a78f636c14c442c1926abc2deca3d137e9d207e4f2f960f5b8363b07","src/lib.rs":"bb87c16ab8587eb2e3a68b948de6cc0d36a469194f243bfd6b33fcf31c9e6a2d"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/neqo-udp/Cargo.toml b/third_party/rust/neqo-udp/Cargo.toml @@ -74,7 +74,7 @@ version = "0.2" default-features = false [target."cfg(windows)".dependencies.windows] -version = "0.58" +version = ">=0.60,<0.63" features = ["Win32_Networking_WinSock"] default-features = false diff --git a/third_party/rust/wgpu-hal/.cargo-checksum.json b/third_party/rust/wgpu-hal/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"1dfc62b0ffc591efa3f1830df8ac2b7ed566a98667c3a49b2d2c535d3afb6dac","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"642f00cedd20c87d357e48fbc194af41731e75c12f626d3ecf9fdb5e3ae5ee0c","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"a8fa13b191e1596f6895fa44fb7503638d818b8c373e4383247e82c23e5974da","examples/ray-traced-triangle/main.rs":"8cbfdf3e4cd29d23e2c9fd543a36976d849a7161670e094baeda390db9306b57","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"3ca856c93916c0be714924ff077aa1f366be5557cc164210154d252e7e49fb77","src/auxil/dxgi/exception.rs":"7138831914a59dc7cbb71512068e9134144b9bc8f43312682edccb0b3ee24a48","src/auxil/dxgi/factory.rs":"81e479e550a09127384d8080e43d5f5bae8e8dda6082fe41a87bea8f872eb0f1","src/auxil/dxgi/mod.rs":"e6c5cc3b73bb97742135d6f35308c42f0822304764978fb8dabb0e848863352a","src/auxil/dxgi/name.rs":"ff942da0da1a497ee4d2be21604f7ba9fae963588105b3d1f63aae1a0c536e82","src/auxil/dxgi/result.rs":"e7a9dfb48d8ef8cbe58b28b1ace5caf7818ee50505ba3220bb0509e66ae469b7","src/auxil/dxgi/time.rs":"b6911800be3873cbe277b2534b3839c6f005f3d9a09341aace4752e207d584a2","src/auxil/mod.rs":"540b9250d9f0e0af709245ce1e284eaca15b27d47550b0ebba2a512da1666c48","src/auxil/renderdoc.rs":"94898f747476e269b2910d42e769f2bbb6be0cb466ad92f9d381f55799d2756e","src/dx12/adapter.rs":"1db86dceaedb7abf3259e63a6e6f56bd9a985a7dc68c0404177c1f3394cb0648","src/dx12/command.rs":"9cb0220f8280070dc8e4e4ab0918ec1dd2c4b7779afee8aaa68638ccda631ea2","src/dx12/conv.rs":"a320fca45fd1990762ff10dad1d8bbb29833d9b693b0887bf2898021a737612c","src/dx12/dcomp.rs":"53bde57557d80e571257f76933d66475a765e063d8b635675f9dd2563039a4c5","src/dx12/descriptor.rs":"ccd4feb6bd3e0a0ffc26142f8a81fca26180d0f50146b6eb2f670cbc89ea7064","src/dx12/device.rs":"592d9336e807e5bbafe204923e6546547160eb660ade038f5707cbd3cb9306fe","src/dx12/instance.rs":"75bddc3807756c691ede3ff944915e443a8bb2b5ac6d0d99babd4ed50d1e3fb9","src/dx12/mod.rs":"592a110924259e8754a919bfbc3efda1292f7416a447d585fe56fe910e6225d0","src/dx12/sampler.rs":"d18d243efe4fa667dbab5b75b5b91d47de94d441976d9f44a46a2b49ba38473d","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"014e9ec4a94519b877ad3adc2ea5d182aa6cdf502248009d28dc5833a9edb93c","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"f1615cc3cae357e0608adfd97106240fc7c77195e97d8dba44c71adfabf6229b","src/dynamic/device.rs":"d5f3c1374c7eb8c8c3737de2b22691c08385cb768d4aac34182feb4d314d7ec9","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"2577d3aef6441f5b42b427d80ba3cf7fee2a97b2fc12335a1fba383e8a79a9b2","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"335dc7fbfeb781cd61148b5f8dd653b1d0b0ba79ef552beddcaf772d28b14dda","src/gles/command.rs":"c13d50eeb1a4aaab367a3b4a7fe6c25c8c73377e68d0d8cc43791d1a7202d23b","src/gles/conv.rs":"6ffb8688de38c2fdd956571dd549535259e2811225adc1df02509e8e642ee775","src/gles/device.rs":"ebe95bea12b3e04792611d66deaa6b5e52ac73e39489a247f88a58fbcb30e0b5","src/gles/egl.rs":"2509e5a5c422e213a3050d852d70a13dfc06737c829a8fc169f45791d8e27fed","src/gles/emscripten.rs":"316d2bb6f2a4bb126dbe68a223f7393399080d116b61c39504454acdf4f9cfaf","src/gles/fence.rs":"a2e7b6abd2fd4a438de90b9f58452c64cd8bba83999c90fd6390e3db128b9c6c","src/gles/mod.rs":"b6d80623eaf58719bafac26875fd0f75f8546b02c58b96a75d703e3a350e31df","src/gles/queue.rs":"5152f5698a2998a55125d13f04788b960726fd4b49ae4d2ec8f9642c8825c7fd","src/gles/shaders/clear.frag":"9133ed8ed97d3641fbb6b5f5ea894a3554c629ccc1b80a5fc9221d7293aa1954","src/gles/shaders/clear.vert":"a543768725f4121ff2e9e1fb5b00644931e9d6f2f946c0ef01968afb5a135abd","src/gles/shaders/srgb_present.frag":"dd9a43c339a2fa4ccf7f6a1854c6f400cabf271a7d5e9230768e9f39d47f3ff5","src/gles/shaders/srgb_present.vert":"6e85d489403d80b81cc94790730bb53b309dfc5eeede8f1ea3412a660f31d357","src/gles/web.rs":"cb5940bf7b2381811675011b640040274f407a7d1908d0f82c813d6a9d3b00f7","src/gles/wgl.rs":"ed0cee8844447b461ed5340f81eb55bb051ceaac67a5768985318ceac133cbe4","src/lib.rs":"acd981799345a8332dda471d5d17367c9d595dfb71946666c59ae5f141347061","src/metal/adapter.rs":"22be51defa39453de32ae4684450b551d64d154ea5cdd991fa0e2edc7d44efde","src/metal/command.rs":"60f5ed647a2b74303f031ce5f0854ecfdc0aaba6e8054d3028a24fbd8b721d16","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"332a1164ebdb5e701b07c0cd4efc54f261306d8d96e4b7787a2eebbc67b2f338","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"36fc4b1a1427d54024128832cbbcfd9d0ca1eaaf0437d24a02eb1116a0f0f37a","src/metal/surface.rs":"22dc6da86ac74b044b6498764920f0467bb5060f4dffb156b6c1e260db0c48b7","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"6e1d15602da06f63b790b938dff2c32cefa2a314e56ab116c9e80d54f8de753f","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"c5d3c0bd74d7790dab73d4a6c45777ff52f3f912d0371a2db031d9c4fa8ea876","src/vulkan/command.rs":"42a4d8e463d9a74f8000e691d36361f5c9adb792d18019deebefcd57ee9488ed","src/vulkan/conv.rs":"03eb28b81d3e41ccfcb2b3f7f029cd671ccdf9556594c6d8b6cc2b22144ec4f2","src/vulkan/device.rs":"5e13d496225f70311704439d0aa256b8feed7a6ab38e8b467f469acb26eacf7c","src/vulkan/drm.rs":"45f7bf1dd854688a65261e4674d80f90c997b193a162fd2ae658acf4e2003552","src/vulkan/instance.rs":"435fb4f22c3c39463f1a33f1a946180656cc7177eeb97035c0458f5d97a1591f","src/vulkan/mod.rs":"15771b5d598a2c675e9140c199bfcf3eacf2077918e6cee3d3db51805fb1df95","src/vulkan/sampler.rs":"f65729d6df5cce681b7756b3e48074017f0c7f42da69ca55e26cc723cd14ad59","src/vulkan/semaphore_list.rs":"6e548d810d75daf5ed31b6e520ece32c8ef97e4b66926c17f0d4317f355802e5","src/vulkan/swapchain/mod.rs":"1baef6ef36d005fe03b27ea15a91d1c5c7114eb7f777a50e67ca5f448a53291b","src/vulkan/swapchain/native.rs":"6d9aadeeb1d6774afe070e0f5d995576c1d5c1097dfc471d914b2e16782a4d69"},"package":null} -\ No newline at end of file +{"files":{"Cargo.toml":"4848d8ea1e40adb0bb6378bd2bf7fe0726dcf7f39b966003b4bef5a428a152a6","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","README.md":"cf9e84804a635e4a8a9fefc596be9da6bf7354dde0d105e27d56a12cb20dd8e3","build.rs":"e720cf033fecfdc7e4f34010af2a86340c99b8aaabf69559d32391521e25de6c","examples/halmark/main.rs":"642f00cedd20c87d357e48fbc194af41731e75c12f626d3ecf9fdb5e3ae5ee0c","examples/halmark/shader.wgsl":"26c256ec36d6f0e9a1647431ca772766bee4382d64eaa718ba7b488dcfb6bcca","examples/raw-gles.em.html":"70fbe68394a1a4522192de1dcfaf7d399f60d7bdf5de70b708f9bb0417427546","examples/raw-gles.rs":"a8fa13b191e1596f6895fa44fb7503638d818b8c373e4383247e82c23e5974da","examples/ray-traced-triangle/main.rs":"8cbfdf3e4cd29d23e2c9fd543a36976d849a7161670e094baeda390db9306b57","examples/ray-traced-triangle/shader.wgsl":"cc10caf92746724a71f6dd0dbc3a71e57b37c7d1d83278556805a535c0728a9d","src/auxil/dxgi/conv.rs":"3ca856c93916c0be714924ff077aa1f366be5557cc164210154d252e7e49fb77","src/auxil/dxgi/exception.rs":"7138831914a59dc7cbb71512068e9134144b9bc8f43312682edccb0b3ee24a48","src/auxil/dxgi/factory.rs":"81e479e550a09127384d8080e43d5f5bae8e8dda6082fe41a87bea8f872eb0f1","src/auxil/dxgi/mod.rs":"e6c5cc3b73bb97742135d6f35308c42f0822304764978fb8dabb0e848863352a","src/auxil/dxgi/name.rs":"ff942da0da1a497ee4d2be21604f7ba9fae963588105b3d1f63aae1a0c536e82","src/auxil/dxgi/result.rs":"e7a9dfb48d8ef8cbe58b28b1ace5caf7818ee50505ba3220bb0509e66ae469b7","src/auxil/dxgi/time.rs":"b6911800be3873cbe277b2534b3839c6f005f3d9a09341aace4752e207d584a2","src/auxil/mod.rs":"540b9250d9f0e0af709245ce1e284eaca15b27d47550b0ebba2a512da1666c48","src/auxil/renderdoc.rs":"94898f747476e269b2910d42e769f2bbb6be0cb466ad92f9d381f55799d2756e","src/dx12/adapter.rs":"1db86dceaedb7abf3259e63a6e6f56bd9a985a7dc68c0404177c1f3394cb0648","src/dx12/command.rs":"d0fa8baa2954f26521643caaee6e93801b58da7000b2527348361b6f25ec137a","src/dx12/conv.rs":"a320fca45fd1990762ff10dad1d8bbb29833d9b693b0887bf2898021a737612c","src/dx12/dcomp.rs":"053068fbd393a4b8610c7070a72e5887f0fe09b61d35d2be806083d800b48b08","src/dx12/descriptor.rs":"ccd4feb6bd3e0a0ffc26142f8a81fca26180d0f50146b6eb2f670cbc89ea7064","src/dx12/device.rs":"8218a384d5cf904ddada7d99e8285e06e1604406af4ed6c11a3369ee054e3338","src/dx12/instance.rs":"75bddc3807756c691ede3ff944915e443a8bb2b5ac6d0d99babd4ed50d1e3fb9","src/dx12/mod.rs":"a8059953a6f371ac3caf11c712427204eaf458fd613b567f1a3b4fd241720000","src/dx12/sampler.rs":"d18d243efe4fa667dbab5b75b5b91d47de94d441976d9f44a46a2b49ba38473d","src/dx12/shader_compilation.rs":"c901a797c69e08c8c0ec93ea37c5f31084eb21c26c7d703d7031f987f2243509","src/dx12/suballocation.rs":"6e0323277749a8bd9fb8a3cb458366d79a4c2f27f8210067026048eb65c4247e","src/dx12/types.rs":"3fc7619fc09303eb3c936d4ded6889f94ce9e8b9aa62742ce900baa1b1e1cca7","src/dx12/view.rs":"79b3f7331d9795e60f9b53023cbf0df46c3a05b1e8bd5c7bcca8acdd235b124f","src/dynamic/adapter.rs":"e93f7d082a3950c9e8ccff8a631d251c7598b4b25dda9fe6347dadfa3ba07829","src/dynamic/command.rs":"f1615cc3cae357e0608adfd97106240fc7c77195e97d8dba44c71adfabf6229b","src/dynamic/device.rs":"d5f3c1374c7eb8c8c3737de2b22691c08385cb768d4aac34182feb4d314d7ec9","src/dynamic/instance.rs":"7b515c201e1ca24f24439544dbfa1d19ea1412a4f89bd803e009aed13b021e55","src/dynamic/mod.rs":"2577d3aef6441f5b42b427d80ba3cf7fee2a97b2fc12335a1fba383e8a79a9b2","src/dynamic/queue.rs":"d76abb4797e90253386d24584f186dbe1909e772560156b2e891fa043cfefbdc","src/dynamic/surface.rs":"4328c2fe86931f50aa00ac3d6982d0879b774eebf7a507903d1b1898c891fb4d","src/gles/adapter.rs":"335dc7fbfeb781cd61148b5f8dd653b1d0b0ba79ef552beddcaf772d28b14dda","src/gles/command.rs":"c13d50eeb1a4aaab367a3b4a7fe6c25c8c73377e68d0d8cc43791d1a7202d23b","src/gles/conv.rs":"6ffb8688de38c2fdd956571dd549535259e2811225adc1df02509e8e642ee775","src/gles/device.rs":"ebe95bea12b3e04792611d66deaa6b5e52ac73e39489a247f88a58fbcb30e0b5","src/gles/egl.rs":"2509e5a5c422e213a3050d852d70a13dfc06737c829a8fc169f45791d8e27fed","src/gles/emscripten.rs":"316d2bb6f2a4bb126dbe68a223f7393399080d116b61c39504454acdf4f9cfaf","src/gles/fence.rs":"a2e7b6abd2fd4a438de90b9f58452c64cd8bba83999c90fd6390e3db128b9c6c","src/gles/mod.rs":"b6d80623eaf58719bafac26875fd0f75f8546b02c58b96a75d703e3a350e31df","src/gles/queue.rs":"5152f5698a2998a55125d13f04788b960726fd4b49ae4d2ec8f9642c8825c7fd","src/gles/shaders/clear.frag":"9133ed8ed97d3641fbb6b5f5ea894a3554c629ccc1b80a5fc9221d7293aa1954","src/gles/shaders/clear.vert":"a543768725f4121ff2e9e1fb5b00644931e9d6f2f946c0ef01968afb5a135abd","src/gles/shaders/srgb_present.frag":"dd9a43c339a2fa4ccf7f6a1854c6f400cabf271a7d5e9230768e9f39d47f3ff5","src/gles/shaders/srgb_present.vert":"6e85d489403d80b81cc94790730bb53b309dfc5eeede8f1ea3412a660f31d357","src/gles/web.rs":"cb5940bf7b2381811675011b640040274f407a7d1908d0f82c813d6a9d3b00f7","src/gles/wgl.rs":"81b2a961fb92e22613224539f85fe982599bfdb6364457578c6b0d9778295d89","src/lib.rs":"acd981799345a8332dda471d5d17367c9d595dfb71946666c59ae5f141347061","src/metal/adapter.rs":"22be51defa39453de32ae4684450b551d64d154ea5cdd991fa0e2edc7d44efde","src/metal/command.rs":"60f5ed647a2b74303f031ce5f0854ecfdc0aaba6e8054d3028a24fbd8b721d16","src/metal/conv.rs":"85e8168be334ba24d109575a0a7e91b2ad3459403173e99e5cdd5d977cc5c18f","src/metal/device.rs":"332a1164ebdb5e701b07c0cd4efc54f261306d8d96e4b7787a2eebbc67b2f338","src/metal/layer_observer.rs":"8370a6e443d01739b951b8538ee719a03b69fc0cbac92c748db418fbcc8837b5","src/metal/mod.rs":"36fc4b1a1427d54024128832cbbcfd9d0ca1eaaf0437d24a02eb1116a0f0f37a","src/metal/surface.rs":"22dc6da86ac74b044b6498764920f0467bb5060f4dffb156b6c1e260db0c48b7","src/metal/time.rs":"c32d69f30e846dfcc0e39e01097fb80df63b2bebb6586143bb62494999850246","src/noop/buffer.rs":"b5edc5e2c52287dfbd4f619e36097ac233041eb9ab287b889b6ee477d740fa09","src/noop/command.rs":"3de99a1a260cfea2e6ca2e76797c1923cc26b069b08362c38798ce27cdc75543","src/noop/mod.rs":"6e1d15602da06f63b790b938dff2c32cefa2a314e56ab116c9e80d54f8de753f","src/validation_canary.rs":"2e8f84e5f85671b3e55ddd410476171c762e34cbea315b37921cbb6ff18bfb4f","src/vulkan/adapter.rs":"c5d3c0bd74d7790dab73d4a6c45777ff52f3f912d0371a2db031d9c4fa8ea876","src/vulkan/command.rs":"42a4d8e463d9a74f8000e691d36361f5c9adb792d18019deebefcd57ee9488ed","src/vulkan/conv.rs":"03eb28b81d3e41ccfcb2b3f7f029cd671ccdf9556594c6d8b6cc2b22144ec4f2","src/vulkan/device.rs":"5e13d496225f70311704439d0aa256b8feed7a6ab38e8b467f469acb26eacf7c","src/vulkan/drm.rs":"45f7bf1dd854688a65261e4674d80f90c997b193a162fd2ae658acf4e2003552","src/vulkan/instance.rs":"435fb4f22c3c39463f1a33f1a946180656cc7177eeb97035c0458f5d97a1591f","src/vulkan/mod.rs":"15771b5d598a2c675e9140c199bfcf3eacf2077918e6cee3d3db51805fb1df95","src/vulkan/sampler.rs":"f65729d6df5cce681b7756b3e48074017f0c7f42da69ca55e26cc723cd14ad59","src/vulkan/semaphore_list.rs":"6e548d810d75daf5ed31b6e520ece32c8ef97e4b66926c17f0d4317f355802e5","src/vulkan/swapchain/mod.rs":"1baef6ef36d005fe03b27ea15a91d1c5c7114eb7f777a50e67ca5f448a53291b","src/vulkan/swapchain/native.rs":"6d9aadeeb1d6774afe070e0f5d995576c1d5c1097dfc471d914b2e16782a4d69"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/wgpu-hal/Cargo.toml b/third_party/rust/wgpu-hal/Cargo.toml @@ -390,7 +390,7 @@ version = "0.2.5" optional = true [target."cfg(unix)".dependencies.libc] -version = "0.2.171" +version = "0.2.172" optional = true default-features = false @@ -404,8 +404,11 @@ version = "0.6" optional = true [target."cfg(windows)".dependencies.gpu-allocator] -version = "0.27" -features = ["d3d12"] +version = "0.28" +features = [ + "hashbrown", + "d3d12", +] optional = true default-features = false @@ -419,12 +422,12 @@ version = "0.1" optional = true [target."cfg(windows)".dependencies.windows] -version = "0.58" +version = "0.62" optional = true default-features = false [target."cfg(windows)".dependencies.windows-core] -version = "0.58" +version = "0.62" optional = true default-features = false diff --git a/third_party/rust/wgpu-hal/src/dx12/command.rs b/third_party/rust/wgpu-hal/src/dx12/command.rs @@ -1,17 +1,19 @@ use alloc::vec::Vec; use core::{mem, ops::Range}; -use windows::Win32::{ - Foundation, - Graphics::{Direct3D12, Dxgi}, +use windows::{ + core::Interface as _, + Win32::{ + Foundation, + Graphics::{Direct3D12, Dxgi}, + }, }; -use windows_core::Interface; use super::conv; use crate::{ auxil::{ self, - dxgi::{name::ObjectExt, result::HResult as _}, + dxgi::{name::ObjectExt as _, result::HResult as _}, }, dx12::borrow_interface_temporarily, AccelerationStructureEntries, CommandEncoder as _, @@ -1001,23 +1003,12 @@ impl crate::CommandEncoder for super::CommandEncoder { if let Some(ds_view) = ds_view { if flags != Direct3D12::D3D12_CLEAR_FLAGS::default() { unsafe { - // list.ClearDepthStencilView( - // ds_view, - // flags, - // ds.clear_value.0, - // ds.clear_value.1 as u8, - // None, - // ) - // TODO: Replace with the above in the next breaking windows-rs release, - // when https://github.com/microsoft/win32metadata/pull/1971 is in. - (Interface::vtable(list).ClearDepthStencilView)( - Interface::as_raw(list), + list.ClearDepthStencilView( ds_view, flags, ds.clear_value.0, ds.clear_value.1 as u8, - 0, - core::ptr::null(), + None, ) } } diff --git a/third_party/rust/wgpu-hal/src/dx12/dcomp.rs b/third_party/rust/wgpu-hal/src/dx12/dcomp.rs @@ -2,8 +2,10 @@ use alloc::sync::Arc; use core::{ffi, ptr}; use once_cell::sync::Lazy; -use windows::Win32::{Foundation::HWND, Graphics::DirectComposition}; -use windows_core::Interface; +use windows::{ + core::Interface as _, + Win32::{Foundation::HWND, Graphics::DirectComposition}, +}; use super::DynLib; diff --git a/third_party/rust/wgpu-hal/src/dx12/device.rs b/third_party/rust/wgpu-hal/src/dx12/device.rs @@ -23,7 +23,7 @@ use super::{conv, descriptor, D3D12Lib}; use crate::{ auxil::{ self, - dxgi::{name::ObjectExt, result::HResult}, + dxgi::{name::ObjectExt as _, result::HResult as _}, }, dx12::{ borrow_optional_interface_temporarily, shader_compilation, suballocation, DCompLib, @@ -1896,8 +1896,8 @@ impl crate::Device for super::Device { DepthBias: bias.constant, DepthBiasClamp: bias.clamp, SlopeScaledDepthBias: bias.slope_scale, - DepthClipEnable: Foundation::BOOL::from(!desc.primitive.unclipped_depth), - MultisampleEnable: Foundation::BOOL::from(desc.multisample.count > 1), + DepthClipEnable: windows_core::BOOL::from(!desc.primitive.unclipped_depth), + MultisampleEnable: windows_core::BOOL::from(desc.multisample.count > 1), ForcedSampleCount: 0, AntialiasedLineEnable: false.into(), ConservativeRaster: if desc.primitive.conservative { @@ -1926,7 +1926,7 @@ impl crate::Device for super::Device { RasterizedStream: 0, }; let blend_state = Direct3D12::D3D12_BLEND_DESC { - AlphaToCoverageEnable: Foundation::BOOL::from( + AlphaToCoverageEnable: windows_core::BOOL::from( desc.multisample.alpha_to_coverage_enabled, ), IndependentBlendEnable: true.into(), diff --git a/third_party/rust/wgpu-hal/src/dx12/mod.rs b/third_party/rust/wgpu-hal/src/dx12/mod.rs @@ -93,7 +93,7 @@ use hashbrown::HashMap; use parking_lot::{Mutex, RwLock}; use suballocation::Allocator; use windows::{ - core::{Free, Interface}, + core::{Free as _, Interface}, Win32::{ Foundation, Graphics::{ @@ -1347,7 +1347,7 @@ impl crate::Surface for Surface { .ok_or(crate::SurfaceError::Other("IDXGIFactoryMedia not found"))? .CreateSwapChainForCompositionSurfaceHandle( &device.present_queue, - handle, + Some(handle), &desc, None, ) diff --git a/third_party/rust/wgpu-hal/src/dx12/suballocation.rs b/third_party/rust/wgpu-hal/src/dx12/suballocation.rs @@ -1,10 +1,11 @@ use alloc::sync::Arc; + use gpu_allocator::{d3d12::AllocationCreateDesc, MemoryLocation}; use parking_lot::Mutex; use windows::Win32::Graphics::{Direct3D12, Dxgi}; use crate::{ - auxil::dxgi::{name::ObjectExt, result::HResult as _}, + auxil::dxgi::{name::ObjectExt as _, result::HResult as _}, dx12::conv, }; @@ -143,7 +144,7 @@ impl Allocator { allocations, blocks, total_allocated_bytes: upstream.total_allocated_bytes, - total_reserved_bytes: upstream.total_reserved_bytes, + total_reserved_bytes: upstream.total_capacity_bytes, } } } diff --git a/third_party/rust/wgpu-hal/src/gles/wgl.rs b/third_party/rust/wgpu-hal/src/gles/wgl.rs @@ -128,7 +128,7 @@ impl WglContext { if unsafe { OpenGL::wglGetCurrentContext() }.is_invalid() { return Ok(()); } - unsafe { OpenGL::wglMakeCurrent(None, None) } + unsafe { OpenGL::wglMakeCurrent(Default::default(), Default::default()) } } } @@ -226,7 +226,7 @@ unsafe fn setup_pixel_format(dc: Gdi::HDC) -> Result<(), crate::InstanceError> { if index == 0 { return Err(crate::InstanceError::with_source( String::from("unable to choose pixel format"), - Error::from_win32(), + Error::from_thread(), )); } @@ -244,7 +244,7 @@ unsafe fn setup_pixel_format(dc: Gdi::HDC) -> Result<(), crate::InstanceError> { if index == 0 { return Err(crate::InstanceError::with_source( String::from("unable to get pixel format index"), - Error::from_win32(), + Error::from_thread(), )); } let mut format = Default::default(); @@ -254,7 +254,7 @@ unsafe fn setup_pixel_format(dc: Gdi::HDC) -> Result<(), crate::InstanceError> { { return Err(crate::InstanceError::with_source( String::from("unable to read pixel format"), - Error::from_win32(), + Error::from_thread(), )); } @@ -311,7 +311,7 @@ fn create_global_window_class() -> Result<CString, crate::InstanceError> { if atom == 0 { return Err(crate::InstanceError::with_source( String::from("unable to register window class"), - Error::from_win32(), + Error::from_thread(), )); } @@ -382,7 +382,7 @@ fn create_instance_device() -> Result<InstanceDevice, crate::InstanceError> { 1, None, None, - instance, + Some(instance.into()), None, ) } @@ -394,11 +394,11 @@ fn create_instance_device() -> Result<InstanceDevice, crate::InstanceError> { })?; let window = Window { window }; - let dc = unsafe { Gdi::GetDC(window.window) }; + let dc = unsafe { Gdi::GetDC(Some(window.window)) }; if dc.is_invalid() { return Err(crate::InstanceError::with_source( String::from("unable to create memory device"), - Error::from_win32(), + Error::from_thread(), )); } let dc = DeviceContextHandle { @@ -484,7 +484,7 @@ impl crate::Instance for Instance { if context.is_null() { return Err(crate::InstanceError::with_source( String::from("unable to create OpenGL context"), - Error::from_win32(), + Error::from_thread(), )); } WglContext { @@ -636,7 +636,7 @@ struct DeviceContextHandle { impl Drop for DeviceContextHandle { fn drop(&mut self) { unsafe { - Gdi::ReleaseDC(self.window, self.device); + Gdi::ReleaseDC(Some(self.window), self.device); }; } } @@ -672,11 +672,11 @@ impl Surface { ) -> Result<(), crate::SurfaceError> { let swapchain = self.swapchain.read(); let sc = swapchain.as_ref().unwrap(); - let dc = unsafe { Gdi::GetDC(self.window) }; + let dc = unsafe { Gdi::GetDC(Some(self.window)) }; if dc.is_invalid() { log::error!( "unable to get the device context from window: {}", - Error::from_win32() + Error::from_thread() ); return Err(crate::SurfaceError::Other( "unable to get the device context from window", @@ -750,11 +750,11 @@ impl crate::Surface for Surface { // Remove the old configuration. unsafe { self.unconfigure(device) }; - let dc = unsafe { Gdi::GetDC(self.window) }; + let dc = unsafe { Gdi::GetDC(Some(self.window)) }; if dc.is_invalid() { log::error!( "unable to get the device context from window: {}", - Error::from_win32() + Error::from_thread() ); return Err(crate::SurfaceError::Other( "unable to get the device context from window", @@ -828,7 +828,7 @@ impl crate::Surface for Surface { }; if unsafe { extra.SwapIntervalEXT(if vsync { 1 } else { 0 }) } == Foundation::FALSE.0 { - log::error!("unable to set swap interval: {}", Error::from_win32()); + log::error!("unable to set swap interval: {}", Error::from_thread()); return Err(crate::SurfaceError::Other("unable to set swap interval")); } diff --git a/third_party/rust/wgpu-types/.cargo-checksum.json b/third_party/rust/wgpu-types/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"7294fed45f6bf1bfbb8a32daf982744671a76cd966a67a610c95c06ac135547e","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","src/assertions.rs":"e4d2d40bc1e870a59637f4b9574743e19565a62f6dbcc21cb18a76b666b796eb","src/cast_utils.rs":"33f03a57ccbedef2699f2305bec584c623db1fd28bfdf584d1260da4fbecd529","src/counters.rs":"e2a1c69126bdb6a35f74d5062e89e242eb955014d95c2b9e6e1b03f7b4b5bd98","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"5e2dd2e2214265f69226b302bcf9192592a79ca9682653153e01e8efadca301d","src/instance.rs":"deeb5ca694163baf46c386316a498cee011cf960d48b749d4cd01125e9fca57f","src/lib.rs":"af43db13921d181e441d4b414ca90fd20c29ca9c2e44c44f090c09fe5149e2b5","src/math.rs":"3046121800bded318b7d219aea401907e7d3bba3b998df6745a71e76f0734de2","src/tokens.rs":"cdf192e0c9b4ea4f3cd4148d07be2e895f937f8154acbf52caf67f7fb4df11dc","src/transfers.rs":"25f47e9cbc5887f849f5eb4d8952d89de6377df40f480ebbea61c58d2e0e7fc6"},"package":null} -\ No newline at end of file +{"files":{"Cargo.toml":"7294fed45f6bf1bfbb8a32daf982744671a76cd966a67a610c95c06ac135547e","LICENSE.APACHE":"a6cba85bc92e0cff7a450b1d873c0eaa2e9fc96bf472df0247a26bec77bf3ff9","LICENSE.MIT":"dc0d97139e8205818c703741c7be7cb3b96888bd5917b8d6fc6133731e403c21","src/assertions.rs":"e4d2d40bc1e870a59637f4b9574743e19565a62f6dbcc21cb18a76b666b796eb","src/cast_utils.rs":"33f03a57ccbedef2699f2305bec584c623db1fd28bfdf584d1260da4fbecd529","src/counters.rs":"1cae2f153a7e4e4e8f3d4cc8ead3635a9a7486d676729f0d7cbba3a6e91ce448","src/env.rs":"26ffc91867625784159bcf391881187aa92cf92b81b1f40959ce1b96ae6d554d","src/error.rs":"0109e6209cf152abbfd0cee85dd934fb24f2304bf6adad6fb684b77f151fb158","src/features.rs":"5e2dd2e2214265f69226b302bcf9192592a79ca9682653153e01e8efadca301d","src/instance.rs":"deeb5ca694163baf46c386316a498cee011cf960d48b749d4cd01125e9fca57f","src/lib.rs":"af43db13921d181e441d4b414ca90fd20c29ca9c2e44c44f090c09fe5149e2b5","src/math.rs":"3046121800bded318b7d219aea401907e7d3bba3b998df6745a71e76f0734de2","src/tokens.rs":"cdf192e0c9b4ea4f3cd4148d07be2e895f937f8154acbf52caf67f7fb4df11dc","src/transfers.rs":"25f47e9cbc5887f849f5eb4d8952d89de6377df40f480ebbea61c58d2e0e7fc6"},"package":null} +\ No newline at end of file diff --git a/third_party/rust/wgpu-types/src/counters.rs b/third_party/rust/wgpu-types/src/counters.rs @@ -181,6 +181,7 @@ pub struct AllocatorReport { /// Sum of the memory used by all allocations, in bytes. pub total_allocated_bytes: u64, /// Sum of the memory reserved by all memory blocks including unallocated regions, in bytes. + // XXX: Rename to total_capacity_bytes following the rename at https://github.com/Traverse-Research/gpu-allocator/pull/266? pub total_reserved_bytes: u64, } diff --git a/third_party/rust/windows-collections/.cargo-checksum.json b/third_party/rust/windows-collections/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"592a9aa074d4bd60c510db8b2c777205dc5dc54d197bfdff1aeabe6926304a86","Cargo.toml":"5f8658fdee2040e7bc5260f259b677ac6263e038ee6d26f25963d40dec5cad48","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"ae6cad365b23eae76c14d2e7266d1e8a213ae934bd8d8fcbe375161f36093930","src/bindings.rs":"a53efdb0f2c754b4adafec190b3cd13216c4f15dfa7243f34823501da6faa2f1","src/iterable.rs":"4894ecfb2eb8e13ce8311da9905c8dc5d3549b304d3240dc67f85e4b3af8dd5c","src/lib.rs":"5fb05de300eff98f8497a1b4f6ef2fc0ae74deb0acea34f677edc5c52c3383b4","src/map_view.rs":"be8572a13562595e2dc1183d75d56de412254a1a9c437c9ae006b54cfaf34e2f","src/vector_view.rs":"abb7e2d5a1e8a5137d06089b6838dcf72393f8ae4a262bb38ef447fb8213dcce"},"package":"23b2d95af1a8a14a3c7367e1ed4fc9c20e0a26e79551b1454d72583c97cc6610"} +\ No newline at end of file diff --git a/third_party/rust/windows-collections/Cargo.lock b/third_party/rust/windows-collections/Cargo.lock @@ -0,0 +1,105 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "windows-collections" +version = "0.3.2" +dependencies = [ + "windows-core", + "windows-strings", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] diff --git a/third_party/rust/windows-collections/Cargo.toml b/third_party/rust/windows-collections/Cargo.toml @@ -0,0 +1,55 @@ +# 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.82" +name = "windows-collections" +version = "0.3.2" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Windows collection types" +readme = "readme.md" +categories = ["os::windows-apis"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/microsoft/windows-rs" + +[package.metadata.docs.rs] +default-target = "x86_64-pc-windows-msvc" +targets = [] + +[features] +default = ["std"] +std = ["windows-core/std"] + +[lib] +name = "windows_collections" +path = "src/lib.rs" + +[dependencies.windows-core] +version = "0.62.2" +default-features = false + +[dev-dependencies.windows-strings] +version = "0.5.1" +default-features = false + +[lints.rust] +missing_unsafe_on_extern = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-collections/license-apache-2.0 b/third_party/rust/windows-collections/license-apache-2.0 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) Microsoft Corporation. + + 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/windows-collections/license-mit b/third_party/rust/windows-collections/license-mit @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + 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/windows-collections/readme.md b/third_party/rust/windows-collections/readme.md @@ -0,0 +1,46 @@ +## Windows collection types + +The [windows-collections](https://crates.io/crates/windows-collections) crate provides stock collection support for Windows APIs. + +* [Getting started](https://kennykerr.ca/rust-getting-started/) +* [Samples](https://github.com/microsoft/windows-rs/tree/master/crates/samples) +* [Releases](https://github.com/microsoft/windows-rs/releases) + +Start by adding the following to your Cargo.toml file: + +```toml +[dependencies.windows-collections] +version = "0.3" +``` + +Use the Windows collection types as needed: + +```rust +use windows_collections::*; + +let numbers = IIterable::<i32>::from(vec![1, 2, 3]); + +for value in numbers { + println!("{value}"); +} +``` + +Naturally, the Windows collection types work with other Windows crates: + +```rust +use windows_collections::*; +use windows_strings::*; + +let greetings = + IVectorView::<HSTRING>::from(vec![HSTRING::from("hello"), HSTRING::from("world")]); + +for value in greetings { + println!("{value}"); +} + +let map = std::collections::BTreeMap::from([("one".into(), 1), ("two".into(), 2)]); +let map = IMapView::<HSTRING, i32>::from(map); + +assert_eq!(map.Lookup(h!("one")).unwrap(), 1); +assert_eq!(map.Lookup(h!("two")).unwrap(), 2); +``` diff --git a/third_party/rust/windows-collections/src/bindings.rs b/third_party/rust/windows-collections/src/bindings.rs @@ -0,0 +1,1962 @@ +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IIterable<T>(windows_core::IUnknown, core::marker::PhantomData<T>) +where + T: windows_core::RuntimeType + 'static; +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> + for IIterable<T> +{ +} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> + for IIterable<T> +{ +} +unsafe impl<T: windows_core::RuntimeType + 'static> windows_core::Interface for IIterable<T> { + type Vtable = IIterable_Vtbl<T>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<T: windows_core::RuntimeType + 'static> windows_core::RuntimeType for IIterable<T> { + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({faa585ea-6214-4217-afda-7f46de5869b3}") + .push_slice(b";") + .push_other(T::SIGNATURE) + .push_slice(b")"); +} +impl<T: windows_core::RuntimeType + 'static> IIterable<T> { + pub fn First(&self) -> windows_core::Result<IIterator<T>> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).First)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +impl<T: windows_core::RuntimeType + 'static> windows_core::RuntimeName for IIterable<T> { + const NAME: &'static str = "Windows.Foundation.Collections.IIterable"; +} +pub trait IIterable_Impl<T>: windows_core::IUnknownImpl +where + T: windows_core::RuntimeType + 'static, +{ + fn First(&self) -> windows_core::Result<IIterator<T>>; +} +impl<T: windows_core::RuntimeType + 'static> IIterable_Vtbl<T> { + pub const fn new<Identity: IIterable_Impl<T>, const OFFSET: isize>() -> Self { + unsafe extern "system" fn First< + T: windows_core::RuntimeType + 'static, + Identity: IIterable_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IIterable_Impl::First(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IIterable<T>, OFFSET>(), + First: First::<T, Identity, OFFSET>, + T: core::marker::PhantomData::<T>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IIterable<T> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IIterable_Vtbl<T> +where + T: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub First: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + T: core::marker::PhantomData<T>, +} +impl<T: windows_core::RuntimeType> IntoIterator for IIterable<T> { + type Item = T; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + IntoIterator::into_iter(&self) + } +} +impl<T: windows_core::RuntimeType> IntoIterator for &IIterable<T> { + type Item = T; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + self.First().unwrap() + } +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IIterator<T>(windows_core::IUnknown, core::marker::PhantomData<T>) +where + T: windows_core::RuntimeType + 'static; +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> + for IIterator<T> +{ +} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> + for IIterator<T> +{ +} +unsafe impl<T: windows_core::RuntimeType + 'static> windows_core::Interface for IIterator<T> { + type Vtable = IIterator_Vtbl<T>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<T: windows_core::RuntimeType + 'static> windows_core::RuntimeType for IIterator<T> { + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({6a79e863-4300-459a-9966-cbb660963ee1}") + .push_slice(b";") + .push_other(T::SIGNATURE) + .push_slice(b")"); +} +impl<T: windows_core::RuntimeType + 'static> IIterator<T> { + pub fn Current(&self) -> windows_core::Result<T> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Current)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn HasCurrent(&self) -> windows_core::Result<bool> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).HasCurrent)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn MoveNext(&self) -> windows_core::Result<bool> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).MoveNext)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn GetMany( + &self, + items: &mut [<T as windows_core::Type<T>>::Default], + ) -> windows_core::Result<u32> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetMany)( + windows_core::Interface::as_raw(this), + items.len().try_into().unwrap(), + core::mem::transmute_copy(&items), + &mut result__, + ) + .map(|| result__) + } + } +} +impl<T: windows_core::RuntimeType + 'static> windows_core::RuntimeName for IIterator<T> { + const NAME: &'static str = "Windows.Foundation.Collections.IIterator"; +} +pub trait IIterator_Impl<T>: windows_core::IUnknownImpl +where + T: windows_core::RuntimeType + 'static, +{ + fn Current(&self) -> windows_core::Result<T>; + fn HasCurrent(&self) -> windows_core::Result<bool>; + fn MoveNext(&self) -> windows_core::Result<bool>; + fn GetMany( + &self, + items: &mut [<T as windows_core::Type<T>>::Default], + ) -> windows_core::Result<u32>; +} +impl<T: windows_core::RuntimeType + 'static> IIterator_Vtbl<T> { + pub const fn new<Identity: IIterator_Impl<T>, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Current< + T: windows_core::RuntimeType + 'static, + Identity: IIterator_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut windows_core::AbiType<T>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IIterator_Impl::Current(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn HasCurrent< + T: windows_core::RuntimeType + 'static, + Identity: IIterator_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut bool, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IIterator_Impl::HasCurrent(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn MoveNext< + T: windows_core::RuntimeType + 'static, + Identity: IIterator_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut bool, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IIterator_Impl::MoveNext(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn GetMany< + T: windows_core::RuntimeType + 'static, + Identity: IIterator_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + items_array_size: u32, + items: *mut T, + result__: *mut u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IIterator_Impl::GetMany( + this, + core::slice::from_raw_parts_mut( + core::mem::transmute_copy(&items), + items_array_size as usize, + ), + ) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IIterator<T>, OFFSET>(), + Current: Current::<T, Identity, OFFSET>, + HasCurrent: HasCurrent::<T, Identity, OFFSET>, + MoveNext: MoveNext::<T, Identity, OFFSET>, + GetMany: GetMany::<T, Identity, OFFSET>, + T: core::marker::PhantomData::<T>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IIterator<T> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IIterator_Vtbl<T> +where + T: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub Current: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut windows_core::AbiType<T>, + ) -> windows_core::HRESULT, + pub HasCurrent: + unsafe extern "system" fn(*mut core::ffi::c_void, *mut bool) -> windows_core::HRESULT, + pub MoveNext: + unsafe extern "system" fn(*mut core::ffi::c_void, *mut bool) -> windows_core::HRESULT, + pub GetMany: unsafe extern "system" fn( + *mut core::ffi::c_void, + u32, + *mut T, + *mut u32, + ) -> windows_core::HRESULT, + T: core::marker::PhantomData<T>, +} +impl<T: windows_core::RuntimeType> Iterator for IIterator<T> { + type Item = T; + fn next(&mut self) -> Option<Self::Item> { + let result = if self.HasCurrent().unwrap_or(false) { + self.Current().ok() + } else { + None + }; + if result.is_some() { + self.MoveNext().ok()?; + } + result + } +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IKeyValuePair<K, V>( + windows_core::IUnknown, + core::marker::PhantomData<K>, + core::marker::PhantomData<V>, +) +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static; +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IUnknown> for IKeyValuePair<K, V> +{ +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IInspectable> for IKeyValuePair<K, V> +{ +} +unsafe impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::Interface for IKeyValuePair<K, V> +{ + type Vtable = IKeyValuePair_Vtbl<K, V>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::RuntimeType for IKeyValuePair<K, V> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({02b51929-c1c4-4a7e-8940-0312b5c18500}") + .push_slice(b";") + .push_other(K::SIGNATURE) + .push_slice(b";") + .push_other(V::SIGNATURE) + .push_slice(b")"); +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + IKeyValuePair<K, V> +{ + pub fn Key(&self) -> windows_core::Result<K> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Key)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn Value(&self) -> windows_core::Result<V> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Value)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::RuntimeName for IKeyValuePair<K, V> +{ + const NAME: &'static str = "Windows.Foundation.Collections.IKeyValuePair"; +} +pub trait IKeyValuePair_Impl<K, V>: windows_core::IUnknownImpl +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, +{ + fn Key(&self) -> windows_core::Result<K>; + fn Value(&self) -> windows_core::Result<V>; +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + IKeyValuePair_Vtbl<K, V> +{ + pub const fn new<Identity: IKeyValuePair_Impl<K, V>, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Key< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IKeyValuePair_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut windows_core::AbiType<K>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IKeyValuePair_Impl::Key(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Value< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IKeyValuePair_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut windows_core::AbiType<V>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IKeyValuePair_Impl::Value(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IKeyValuePair<K, V>, OFFSET>(), + Key: Key::<K, V, Identity, OFFSET>, + Value: Value::<K, V, Identity, OFFSET>, + K: core::marker::PhantomData::<K>, + V: core::marker::PhantomData::<V>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IKeyValuePair<K, V> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IKeyValuePair_Vtbl<K, V> +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub Key: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut windows_core::AbiType<K>, + ) -> windows_core::HRESULT, + pub Value: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut windows_core::AbiType<V>, + ) -> windows_core::HRESULT, + K: core::marker::PhantomData<K>, + V: core::marker::PhantomData<V>, +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IMap<K, V>( + windows_core::IUnknown, + core::marker::PhantomData<K>, + core::marker::PhantomData<V>, +) +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static; +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IUnknown> for IMap<K, V> +{ +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IInspectable> for IMap<K, V> +{ +} +unsafe impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::Interface for IMap<K, V> +{ + type Vtable = IMap_Vtbl<K, V>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::RuntimeType for IMap<K, V> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({3c2925fe-8519-45c1-aa79-197b6718c1c1}") + .push_slice(b";") + .push_other(K::SIGNATURE) + .push_slice(b";") + .push_other(V::SIGNATURE) + .push_slice(b")"); +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<IIterable<IKeyValuePair<K, V>>> for IMap<K, V> +{ + const QUERY: bool = true; +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IMap<K, V> { + pub fn Lookup<P0>(&self, key: P0) -> windows_core::Result<V> + where + P0: windows_core::Param<K>, + { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Lookup)( + windows_core::Interface::as_raw(this), + key.param().abi(), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn Size(&self) -> windows_core::Result<u32> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Size)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn HasKey<P0>(&self, key: P0) -> windows_core::Result<bool> + where + P0: windows_core::Param<K>, + { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).HasKey)( + windows_core::Interface::as_raw(this), + key.param().abi(), + &mut result__, + ) + .map(|| result__) + } + } + pub fn GetView(&self) -> windows_core::Result<IMapView<K, V>> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetView)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn Insert<P0, P1>(&self, key: P0, value: P1) -> windows_core::Result<bool> + where + P0: windows_core::Param<K>, + P1: windows_core::Param<V>, + { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Insert)( + windows_core::Interface::as_raw(this), + key.param().abi(), + value.param().abi(), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Remove<P0>(&self, key: P0) -> windows_core::Result<()> + where + P0: windows_core::Param<K>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Remove)( + windows_core::Interface::as_raw(this), + key.param().abi(), + ) + .ok() + } + } + pub fn Clear(&self) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Clear)(windows_core::Interface::as_raw(this)) + .ok() + } + } + pub fn First(&self) -> windows_core::Result<IIterator<IKeyValuePair<K, V>>> { + let this = &windows_core::Interface::cast::<IIterable<IKeyValuePair<K, V>>>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).First)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IntoIterator + for IMap<K, V> +{ + type Item = IKeyValuePair<K, V>; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + IntoIterator::into_iter(&self) + } +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IntoIterator + for &IMap<K, V> +{ + type Item = IKeyValuePair<K, V>; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + self.First().unwrap() + } +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::RuntimeName for IMap<K, V> +{ + const NAME: &'static str = "Windows.Foundation.Collections.IMap"; +} +pub trait IMap_Impl<K, V>: IIterable_Impl<IKeyValuePair<K, V>> +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, +{ + fn Lookup(&self, key: windows_core::Ref<K>) -> windows_core::Result<V>; + fn Size(&self) -> windows_core::Result<u32>; + fn HasKey(&self, key: windows_core::Ref<K>) -> windows_core::Result<bool>; + fn GetView(&self) -> windows_core::Result<IMapView<K, V>>; + fn Insert( + &self, + key: windows_core::Ref<K>, + value: windows_core::Ref<V>, + ) -> windows_core::Result<bool>; + fn Remove(&self, key: windows_core::Ref<K>) -> windows_core::Result<()>; + fn Clear(&self) -> windows_core::Result<()>; +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + IMap_Vtbl<K, V> +{ + pub const fn new<Identity: IMap_Impl<K, V>, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Lookup< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMap_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + key: windows_core::AbiType<K>, + result__: *mut windows_core::AbiType<V>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IMap_Impl::Lookup(this, core::mem::transmute_copy(&key)) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Size< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMap_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IMap_Impl::Size(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn HasKey< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMap_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + key: windows_core::AbiType<K>, + result__: *mut bool, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IMap_Impl::HasKey(this, core::mem::transmute_copy(&key)) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn GetView< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMap_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IMap_Impl::GetView(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Insert< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMap_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + key: windows_core::AbiType<K>, + value: windows_core::AbiType<V>, + result__: *mut bool, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IMap_Impl::Insert( + this, + core::mem::transmute_copy(&key), + core::mem::transmute_copy(&value), + ) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Remove< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMap_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + key: windows_core::AbiType<K>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IMap_Impl::Remove(this, core::mem::transmute_copy(&key)).into() + } + } + unsafe extern "system" fn Clear< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMap_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IMap_Impl::Clear(this).into() + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IMap<K, V>, OFFSET>(), + Lookup: Lookup::<K, V, Identity, OFFSET>, + Size: Size::<K, V, Identity, OFFSET>, + HasKey: HasKey::<K, V, Identity, OFFSET>, + GetView: GetView::<K, V, Identity, OFFSET>, + Insert: Insert::<K, V, Identity, OFFSET>, + Remove: Remove::<K, V, Identity, OFFSET>, + Clear: Clear::<K, V, Identity, OFFSET>, + K: core::marker::PhantomData::<K>, + V: core::marker::PhantomData::<V>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IMap<K, V> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IMap_Vtbl<K, V> +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub Lookup: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<K>, + *mut windows_core::AbiType<V>, + ) -> windows_core::HRESULT, + pub Size: unsafe extern "system" fn(*mut core::ffi::c_void, *mut u32) -> windows_core::HRESULT, + pub HasKey: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<K>, + *mut bool, + ) -> windows_core::HRESULT, + pub GetView: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub Insert: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<K>, + windows_core::AbiType<V>, + *mut bool, + ) -> windows_core::HRESULT, + pub Remove: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<K>, + ) -> windows_core::HRESULT, + pub Clear: unsafe extern "system" fn(*mut core::ffi::c_void) -> windows_core::HRESULT, + K: core::marker::PhantomData<K>, + V: core::marker::PhantomData<V>, +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IMapView<K, V>( + windows_core::IUnknown, + core::marker::PhantomData<K>, + core::marker::PhantomData<V>, +) +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static; +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IUnknown> for IMapView<K, V> +{ +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IInspectable> for IMapView<K, V> +{ +} +unsafe impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::Interface for IMapView<K, V> +{ + type Vtable = IMapView_Vtbl<K, V>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::RuntimeType for IMapView<K, V> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({e480ce40-a338-4ada-adcf-272272e48cb9}") + .push_slice(b";") + .push_other(K::SIGNATURE) + .push_slice(b";") + .push_other(V::SIGNATURE) + .push_slice(b")"); +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<IIterable<IKeyValuePair<K, V>>> for IMapView<K, V> +{ + const QUERY: bool = true; +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + IMapView<K, V> +{ + pub fn Lookup<P0>(&self, key: P0) -> windows_core::Result<V> + where + P0: windows_core::Param<K>, + { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Lookup)( + windows_core::Interface::as_raw(this), + key.param().abi(), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn Size(&self) -> windows_core::Result<u32> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Size)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn HasKey<P0>(&self, key: P0) -> windows_core::Result<bool> + where + P0: windows_core::Param<K>, + { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).HasKey)( + windows_core::Interface::as_raw(this), + key.param().abi(), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Split( + &self, + first: &mut Option<IMapView<K, V>>, + second: &mut Option<IMapView<K, V>>, + ) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Split)( + windows_core::Interface::as_raw(this), + first as *mut _ as _, + second as *mut _ as _, + ) + .ok() + } + } + pub fn First(&self) -> windows_core::Result<IIterator<IKeyValuePair<K, V>>> { + let this = &windows_core::Interface::cast::<IIterable<IKeyValuePair<K, V>>>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).First)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IntoIterator + for IMapView<K, V> +{ + type Item = IKeyValuePair<K, V>; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + IntoIterator::into_iter(&self) + } +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> IntoIterator + for &IMapView<K, V> +{ + type Item = IKeyValuePair<K, V>; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + self.First().unwrap() + } +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + windows_core::RuntimeName for IMapView<K, V> +{ + const NAME: &'static str = "Windows.Foundation.Collections.IMapView"; +} +pub trait IMapView_Impl<K, V>: IIterable_Impl<IKeyValuePair<K, V>> +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, +{ + fn Lookup(&self, key: windows_core::Ref<K>) -> windows_core::Result<V>; + fn Size(&self) -> windows_core::Result<u32>; + fn HasKey(&self, key: windows_core::Ref<K>) -> windows_core::Result<bool>; + fn Split( + &self, + first: windows_core::OutRef<IMapView<K, V>>, + second: windows_core::OutRef<IMapView<K, V>>, + ) -> windows_core::Result<()>; +} +impl<K: windows_core::RuntimeType + 'static, V: windows_core::RuntimeType + 'static> + IMapView_Vtbl<K, V> +{ + pub const fn new<Identity: IMapView_Impl<K, V>, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Lookup< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMapView_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + key: windows_core::AbiType<K>, + result__: *mut windows_core::AbiType<V>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IMapView_Impl::Lookup(this, core::mem::transmute_copy(&key)) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Size< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMapView_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IMapView_Impl::Size(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn HasKey< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMapView_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + key: windows_core::AbiType<K>, + result__: *mut bool, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IMapView_Impl::HasKey(this, core::mem::transmute_copy(&key)) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Split< + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, + Identity: IMapView_Impl<K, V>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + first: *mut *mut core::ffi::c_void, + second: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IMapView_Impl::Split( + this, + core::mem::transmute_copy(&first), + core::mem::transmute_copy(&second), + ) + .into() + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IMapView<K, V>, OFFSET>(), + Lookup: Lookup::<K, V, Identity, OFFSET>, + Size: Size::<K, V, Identity, OFFSET>, + HasKey: HasKey::<K, V, Identity, OFFSET>, + Split: Split::<K, V, Identity, OFFSET>, + K: core::marker::PhantomData::<K>, + V: core::marker::PhantomData::<V>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IMapView<K, V> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IMapView_Vtbl<K, V> +where + K: windows_core::RuntimeType + 'static, + V: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub Lookup: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<K>, + *mut windows_core::AbiType<V>, + ) -> windows_core::HRESULT, + pub Size: unsafe extern "system" fn(*mut core::ffi::c_void, *mut u32) -> windows_core::HRESULT, + pub HasKey: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<K>, + *mut bool, + ) -> windows_core::HRESULT, + pub Split: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + K: core::marker::PhantomData<K>, + V: core::marker::PhantomData<V>, +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IVector<T>(windows_core::IUnknown, core::marker::PhantomData<T>) +where + T: windows_core::RuntimeType + 'static; +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> + for IVector<T> +{ +} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> + for IVector<T> +{ +} +unsafe impl<T: windows_core::RuntimeType + 'static> windows_core::Interface for IVector<T> { + type Vtable = IVector_Vtbl<T>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<T: windows_core::RuntimeType + 'static> windows_core::RuntimeType for IVector<T> { + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({913337e9-11a1-4345-a3a2-4e7f956e222d}") + .push_slice(b";") + .push_other(T::SIGNATURE) + .push_slice(b")"); +} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<T>> + for IVector<T> +{ + const QUERY: bool = true; +} +impl<T: windows_core::RuntimeType + 'static> IVector<T> { + pub fn GetAt(&self, index: u32) -> windows_core::Result<T> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetAt)( + windows_core::Interface::as_raw(this), + index, + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn Size(&self) -> windows_core::Result<u32> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Size)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn GetView(&self) -> windows_core::Result<IVectorView<T>> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetView)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn IndexOf<P0>(&self, value: P0, index: &mut u32) -> windows_core::Result<bool> + where + P0: windows_core::Param<T>, + { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).IndexOf)( + windows_core::Interface::as_raw(this), + value.param().abi(), + index, + &mut result__, + ) + .map(|| result__) + } + } + pub fn SetAt<P1>(&self, index: u32, value: P1) -> windows_core::Result<()> + where + P1: windows_core::Param<T>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).SetAt)( + windows_core::Interface::as_raw(this), + index, + value.param().abi(), + ) + .ok() + } + } + pub fn InsertAt<P1>(&self, index: u32, value: P1) -> windows_core::Result<()> + where + P1: windows_core::Param<T>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).InsertAt)( + windows_core::Interface::as_raw(this), + index, + value.param().abi(), + ) + .ok() + } + } + pub fn RemoveAt(&self, index: u32) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).RemoveAt)( + windows_core::Interface::as_raw(this), + index, + ) + .ok() + } + } + pub fn Append<P0>(&self, value: P0) -> windows_core::Result<()> + where + P0: windows_core::Param<T>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Append)( + windows_core::Interface::as_raw(this), + value.param().abi(), + ) + .ok() + } + } + pub fn RemoveAtEnd(&self) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).RemoveAtEnd)(windows_core::Interface::as_raw( + this, + )) + .ok() + } + } + pub fn Clear(&self) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Clear)(windows_core::Interface::as_raw(this)) + .ok() + } + } + pub fn GetMany( + &self, + startindex: u32, + items: &mut [<T as windows_core::Type<T>>::Default], + ) -> windows_core::Result<u32> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetMany)( + windows_core::Interface::as_raw(this), + startindex, + items.len().try_into().unwrap(), + core::mem::transmute_copy(&items), + &mut result__, + ) + .map(|| result__) + } + } + pub fn ReplaceAll( + &self, + items: &[<T as windows_core::Type<T>>::Default], + ) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).ReplaceAll)( + windows_core::Interface::as_raw(this), + items.len().try_into().unwrap(), + core::mem::transmute(items.as_ptr()), + ) + .ok() + } + } + pub fn First(&self) -> windows_core::Result<IIterator<T>> { + let this = &windows_core::Interface::cast::<IIterable<T>>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).First)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +impl<T: windows_core::RuntimeType + 'static> IntoIterator for IVector<T> { + type Item = T; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + IntoIterator::into_iter(&self) + } +} +impl<T: windows_core::RuntimeType + 'static> IntoIterator for &IVector<T> { + type Item = T; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + self.First().unwrap() + } +} +impl<T: windows_core::RuntimeType + 'static> windows_core::RuntimeName for IVector<T> { + const NAME: &'static str = "Windows.Foundation.Collections.IVector"; +} +pub trait IVector_Impl<T>: IIterable_Impl<T> +where + T: windows_core::RuntimeType + 'static, +{ + fn GetAt(&self, index: u32) -> windows_core::Result<T>; + fn Size(&self) -> windows_core::Result<u32>; + fn GetView(&self) -> windows_core::Result<IVectorView<T>>; + fn IndexOf(&self, value: windows_core::Ref<T>, index: &mut u32) -> windows_core::Result<bool>; + fn SetAt(&self, index: u32, value: windows_core::Ref<T>) -> windows_core::Result<()>; + fn InsertAt(&self, index: u32, value: windows_core::Ref<T>) -> windows_core::Result<()>; + fn RemoveAt(&self, index: u32) -> windows_core::Result<()>; + fn Append(&self, value: windows_core::Ref<T>) -> windows_core::Result<()>; + fn RemoveAtEnd(&self) -> windows_core::Result<()>; + fn Clear(&self) -> windows_core::Result<()>; + fn GetMany( + &self, + startIndex: u32, + items: &mut [<T as windows_core::Type<T>>::Default], + ) -> windows_core::Result<u32>; + fn ReplaceAll( + &self, + items: &[<T as windows_core::Type<T>>::Default], + ) -> windows_core::Result<()>; +} +impl<T: windows_core::RuntimeType + 'static> IVector_Vtbl<T> { + pub const fn new<Identity: IVector_Impl<T>, const OFFSET: isize>() -> Self { + unsafe extern "system" fn GetAt< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + index: u32, + result__: *mut windows_core::AbiType<T>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVector_Impl::GetAt(this, index) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Size< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVector_Impl::Size(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn GetView< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVector_Impl::GetView(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn IndexOf< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + value: windows_core::AbiType<T>, + index: *mut u32, + result__: *mut bool, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVector_Impl::IndexOf( + this, + core::mem::transmute_copy(&value), + core::mem::transmute_copy(&index), + ) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn SetAt< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + index: u32, + value: windows_core::AbiType<T>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IVector_Impl::SetAt(this, index, core::mem::transmute_copy(&value)).into() + } + } + unsafe extern "system" fn InsertAt< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + index: u32, + value: windows_core::AbiType<T>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IVector_Impl::InsertAt(this, index, core::mem::transmute_copy(&value)).into() + } + } + unsafe extern "system" fn RemoveAt< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + index: u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IVector_Impl::RemoveAt(this, index).into() + } + } + unsafe extern "system" fn Append< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + value: windows_core::AbiType<T>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IVector_Impl::Append(this, core::mem::transmute_copy(&value)).into() + } + } + unsafe extern "system" fn RemoveAtEnd< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IVector_Impl::RemoveAtEnd(this).into() + } + } + unsafe extern "system" fn Clear< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IVector_Impl::Clear(this).into() + } + } + unsafe extern "system" fn GetMany< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + startindex: u32, + items_array_size: u32, + items: *mut T, + result__: *mut u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVector_Impl::GetMany( + this, + startindex, + core::slice::from_raw_parts_mut( + core::mem::transmute_copy(&items), + items_array_size as usize, + ), + ) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn ReplaceAll< + T: windows_core::RuntimeType + 'static, + Identity: IVector_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + items_array_size: u32, + items: *const T, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IVector_Impl::ReplaceAll( + this, + core::slice::from_raw_parts( + core::mem::transmute_copy(&items), + items_array_size as usize, + ), + ) + .into() + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IVector<T>, OFFSET>(), + GetAt: GetAt::<T, Identity, OFFSET>, + Size: Size::<T, Identity, OFFSET>, + GetView: GetView::<T, Identity, OFFSET>, + IndexOf: IndexOf::<T, Identity, OFFSET>, + SetAt: SetAt::<T, Identity, OFFSET>, + InsertAt: InsertAt::<T, Identity, OFFSET>, + RemoveAt: RemoveAt::<T, Identity, OFFSET>, + Append: Append::<T, Identity, OFFSET>, + RemoveAtEnd: RemoveAtEnd::<T, Identity, OFFSET>, + Clear: Clear::<T, Identity, OFFSET>, + GetMany: GetMany::<T, Identity, OFFSET>, + ReplaceAll: ReplaceAll::<T, Identity, OFFSET>, + T: core::marker::PhantomData::<T>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IVector<T> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IVector_Vtbl<T> +where + T: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub GetAt: unsafe extern "system" fn( + *mut core::ffi::c_void, + u32, + *mut windows_core::AbiType<T>, + ) -> windows_core::HRESULT, + pub Size: unsafe extern "system" fn(*mut core::ffi::c_void, *mut u32) -> windows_core::HRESULT, + pub GetView: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub IndexOf: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<T>, + *mut u32, + *mut bool, + ) -> windows_core::HRESULT, + pub SetAt: unsafe extern "system" fn( + *mut core::ffi::c_void, + u32, + windows_core::AbiType<T>, + ) -> windows_core::HRESULT, + pub InsertAt: unsafe extern "system" fn( + *mut core::ffi::c_void, + u32, + windows_core::AbiType<T>, + ) -> windows_core::HRESULT, + pub RemoveAt: unsafe extern "system" fn(*mut core::ffi::c_void, u32) -> windows_core::HRESULT, + pub Append: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<T>, + ) -> windows_core::HRESULT, + pub RemoveAtEnd: unsafe extern "system" fn(*mut core::ffi::c_void) -> windows_core::HRESULT, + pub Clear: unsafe extern "system" fn(*mut core::ffi::c_void) -> windows_core::HRESULT, + pub GetMany: unsafe extern "system" fn( + *mut core::ffi::c_void, + u32, + u32, + *mut T, + *mut u32, + ) -> windows_core::HRESULT, + pub ReplaceAll: + unsafe extern "system" fn(*mut core::ffi::c_void, u32, *const T) -> windows_core::HRESULT, + T: core::marker::PhantomData<T>, +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IVectorView<T>(windows_core::IUnknown, core::marker::PhantomData<T>) +where + T: windows_core::RuntimeType + 'static; +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IUnknown> + for IVectorView<T> +{ +} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<windows_core::IInspectable> + for IVectorView<T> +{ +} +unsafe impl<T: windows_core::RuntimeType + 'static> windows_core::Interface for IVectorView<T> { + type Vtable = IVectorView_Vtbl<T>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<T: windows_core::RuntimeType + 'static> windows_core::RuntimeType for IVectorView<T> { + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({bbe1fa4c-b0e3-4583-baef-1f1b2e483e56}") + .push_slice(b";") + .push_other(T::SIGNATURE) + .push_slice(b")"); +} +impl<T: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IIterable<T>> + for IVectorView<T> +{ + const QUERY: bool = true; +} +impl<T: windows_core::RuntimeType + 'static> IVectorView<T> { + pub fn GetAt(&self, index: u32) -> windows_core::Result<T> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetAt)( + windows_core::Interface::as_raw(this), + index, + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn Size(&self) -> windows_core::Result<u32> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Size)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn IndexOf<P0>(&self, value: P0, index: &mut u32) -> windows_core::Result<bool> + where + P0: windows_core::Param<T>, + { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).IndexOf)( + windows_core::Interface::as_raw(this), + value.param().abi(), + index, + &mut result__, + ) + .map(|| result__) + } + } + pub fn GetMany( + &self, + startindex: u32, + items: &mut [<T as windows_core::Type<T>>::Default], + ) -> windows_core::Result<u32> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetMany)( + windows_core::Interface::as_raw(this), + startindex, + items.len().try_into().unwrap(), + core::mem::transmute_copy(&items), + &mut result__, + ) + .map(|| result__) + } + } + pub fn First(&self) -> windows_core::Result<IIterator<T>> { + let this = &windows_core::Interface::cast::<IIterable<T>>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).First)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } +} +impl<T: windows_core::RuntimeType + 'static> IntoIterator for IVectorView<T> { + type Item = T; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + IntoIterator::into_iter(&self) + } +} +impl<T: windows_core::RuntimeType + 'static> IntoIterator for &IVectorView<T> { + type Item = T; + type IntoIter = IIterator<Self::Item>; + fn into_iter(self) -> Self::IntoIter { + self.First().unwrap() + } +} +impl<T: windows_core::RuntimeType + 'static> windows_core::RuntimeName for IVectorView<T> { + const NAME: &'static str = "Windows.Foundation.Collections.IVectorView"; +} +pub trait IVectorView_Impl<T>: IIterable_Impl<T> +where + T: windows_core::RuntimeType + 'static, +{ + fn GetAt(&self, index: u32) -> windows_core::Result<T>; + fn Size(&self) -> windows_core::Result<u32>; + fn IndexOf(&self, value: windows_core::Ref<T>, index: &mut u32) -> windows_core::Result<bool>; + fn GetMany( + &self, + startIndex: u32, + items: &mut [<T as windows_core::Type<T>>::Default], + ) -> windows_core::Result<u32>; +} +impl<T: windows_core::RuntimeType + 'static> IVectorView_Vtbl<T> { + pub const fn new<Identity: IVectorView_Impl<T>, const OFFSET: isize>() -> Self { + unsafe extern "system" fn GetAt< + T: windows_core::RuntimeType + 'static, + Identity: IVectorView_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + index: u32, + result__: *mut windows_core::AbiType<T>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVectorView_Impl::GetAt(this, index) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Size< + T: windows_core::RuntimeType + 'static, + Identity: IVectorView_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVectorView_Impl::Size(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn IndexOf< + T: windows_core::RuntimeType + 'static, + Identity: IVectorView_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + value: windows_core::AbiType<T>, + index: *mut u32, + result__: *mut bool, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVectorView_Impl::IndexOf( + this, + core::mem::transmute_copy(&value), + core::mem::transmute_copy(&index), + ) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn GetMany< + T: windows_core::RuntimeType + 'static, + Identity: IVectorView_Impl<T>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + startindex: u32, + items_array_size: u32, + items: *mut T, + result__: *mut u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IVectorView_Impl::GetMany( + this, + startindex, + core::slice::from_raw_parts_mut( + core::mem::transmute_copy(&items), + items_array_size as usize, + ), + ) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IVectorView<T>, OFFSET>(), + GetAt: GetAt::<T, Identity, OFFSET>, + Size: Size::<T, Identity, OFFSET>, + IndexOf: IndexOf::<T, Identity, OFFSET>, + GetMany: GetMany::<T, Identity, OFFSET>, + T: core::marker::PhantomData::<T>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IVectorView<T> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IVectorView_Vtbl<T> +where + T: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub GetAt: unsafe extern "system" fn( + *mut core::ffi::c_void, + u32, + *mut windows_core::AbiType<T>, + ) -> windows_core::HRESULT, + pub Size: unsafe extern "system" fn(*mut core::ffi::c_void, *mut u32) -> windows_core::HRESULT, + pub IndexOf: unsafe extern "system" fn( + *mut core::ffi::c_void, + windows_core::AbiType<T>, + *mut u32, + *mut bool, + ) -> windows_core::HRESULT, + pub GetMany: unsafe extern "system" fn( + *mut core::ffi::c_void, + u32, + u32, + *mut T, + *mut u32, + ) -> windows_core::HRESULT, + T: core::marker::PhantomData<T>, +} diff --git a/third_party/rust/windows-collections/src/iterable.rs b/third_party/rust/windows-collections/src/iterable.rs @@ -0,0 +1,94 @@ +use super::*; +use windows_core::*; + +#[implement(IIterable<T>)] +struct StockIterable<T> +where + T: RuntimeType + 'static, + T::Default: Clone, +{ + values: Vec<T::Default>, +} + +impl<T> IIterable_Impl<T> for StockIterable_Impl<T> +where + T: RuntimeType, + T::Default: Clone, +{ + fn First(&self) -> Result<IIterator<T>> { + Ok(ComObject::new(StockIterator { + owner: self.to_object(), + current: 0.into(), + }) + .into_interface()) + } +} + +#[implement(IIterator<T>)] +struct StockIterator<T> +where + T: RuntimeType + 'static, + T::Default: Clone, +{ + owner: ComObject<StockIterable<T>>, + current: std::sync::atomic::AtomicUsize, +} + +impl<T> IIterator_Impl<T> for StockIterator_Impl<T> +where + T: RuntimeType, + T::Default: Clone, +{ + fn Current(&self) -> Result<T> { + let owner: &StockIterable<T> = &self.owner; + let current = self.current.load(std::sync::atomic::Ordering::Relaxed); + + if self.owner.values.len() > current { + T::from_default(&owner.values[current]) + } else { + Err(Error::from(E_BOUNDS)) + } + } + + fn HasCurrent(&self) -> Result<bool> { + let owner: &StockIterable<T> = &self.owner; + let current = self.current.load(std::sync::atomic::Ordering::Relaxed); + + Ok(owner.values.len() > current) + } + + fn MoveNext(&self) -> Result<bool> { + let owner: &StockIterable<T> = &self.owner; + let current = self.current.load(std::sync::atomic::Ordering::Relaxed); + + if current < owner.values.len() { + self.current + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + } + + Ok(owner.values.len() > current + 1) + } + + fn GetMany(&self, values: &mut [T::Default]) -> Result<u32> { + let owner: &StockIterable<T> = &self.owner; + let current = self.current.load(std::sync::atomic::Ordering::Relaxed); + let actual = std::cmp::min(owner.values.len() - current, values.len()); + let (values, _) = values.split_at_mut(actual); + values.clone_from_slice(&owner.values[current..current + actual]); + + self.current + .fetch_add(actual, std::sync::atomic::Ordering::Relaxed); + + Ok(actual as u32) + } +} + +impl<T> From<Vec<T::Default>> for IIterable<T> +where + T: RuntimeType, + T::Default: Clone, +{ + fn from(values: Vec<T::Default>) -> Self { + ComObject::new(StockIterable { values }).into_interface() + } +} diff --git a/third_party/rust/windows-collections/src/lib.rs b/third_party/rust/windows-collections/src/lib.rs @@ -0,0 +1,21 @@ +#![doc = include_str!("../readme.md")] +#![cfg_attr(all(not(feature = "std")), no_std)] +#![expect( + missing_docs, + non_snake_case, + non_camel_case_types, + clippy::missing_transmute_annotations +)] + +mod bindings; +pub use bindings::*; + +#[cfg(feature = "std")] +const E_BOUNDS: windows_core::HRESULT = windows_core::HRESULT(0x8000000B_u32 as _); + +#[cfg(feature = "std")] +mod iterable; +#[cfg(feature = "std")] +mod map_view; +#[cfg(feature = "std")] +mod vector_view; diff --git a/third_party/rust/windows-collections/src/map_view.rs b/third_party/rust/windows-collections/src/map_view.rs @@ -0,0 +1,164 @@ +use super::*; +use windows_core::*; + +#[implement(IMapView<K, V>, IIterable<IKeyValuePair<K, V>>)] +struct StockMapView<K, V> +where + K: RuntimeType + 'static, + V: RuntimeType + 'static, + K::Default: Clone + Ord, + V::Default: Clone, +{ + map: std::collections::BTreeMap<K::Default, V::Default>, +} + +impl<K, V> IIterable_Impl<IKeyValuePair<K, V>> for StockMapView_Impl<K, V> +where + K: RuntimeType, + V: RuntimeType, + K::Default: Clone + Ord, + V::Default: Clone, +{ + fn First(&self) -> Result<IIterator<IKeyValuePair<K, V>>> { + Ok(ComObject::new(StockMapViewIterator::<K, V> { + _owner: self.to_object(), + current: std::sync::RwLock::new(self.map.iter()), + }) + .into_interface()) + } +} + +impl<K, V> IMapView_Impl<K, V> for StockMapView_Impl<K, V> +where + K: RuntimeType, + V: RuntimeType, + K::Default: Clone + Ord, + V::Default: Clone, +{ + fn Lookup(&self, key: Ref<K>) -> Result<V> { + let value = self.map.get(&*key).ok_or_else(|| Error::from(E_BOUNDS))?; + + V::from_default(value) + } + + fn Size(&self) -> Result<u32> { + Ok(self.map.len().try_into()?) + } + + fn HasKey(&self, key: Ref<K>) -> Result<bool> { + Ok(self.map.contains_key(&*key)) + } + + fn Split(&self, first: OutRef<IMapView<K, V>>, second: OutRef<IMapView<K, V>>) -> Result<()> { + _ = first.write(None); + _ = second.write(None); + Ok(()) + } +} + +#[implement(IIterator<IKeyValuePair<K, V>>)] +struct StockMapViewIterator<'a, K, V> +where + K: RuntimeType + 'static, + V: RuntimeType + 'static, + K::Default: Clone + Ord, + V::Default: Clone, +{ + _owner: ComObject<StockMapView<K, V>>, + current: std::sync::RwLock<std::collections::btree_map::Iter<'a, K::Default, V::Default>>, +} + +impl<K, V> IIterator_Impl<IKeyValuePair<K, V>> for StockMapViewIterator_Impl<'_, K, V> +where + K: RuntimeType, + V: RuntimeType, + K::Default: Clone + Ord, + V::Default: Clone, +{ + fn Current(&self) -> Result<IKeyValuePair<K, V>> { + let mut current = self.current.read().unwrap().clone().peekable(); + + if let Some((key, value)) = current.peek() { + Ok(ComObject::new(StockKeyValuePair { + key: (*key).clone(), + value: (*value).clone(), + }) + .into_interface()) + } else { + Err(Error::from(E_BOUNDS)) + } + } + + fn HasCurrent(&self) -> Result<bool> { + let mut current = self.current.read().unwrap().clone().peekable(); + Ok(current.peek().is_some()) + } + + fn MoveNext(&self) -> Result<bool> { + let mut current = self.current.write().unwrap(); + current.next(); + Ok(current.clone().peekable().peek().is_some()) + } + + fn GetMany(&self, pairs: &mut [Option<IKeyValuePair<K, V>>]) -> Result<u32> { + let mut current = self.current.write().unwrap(); + let mut actual = 0; + + for pair in pairs { + if let Some((key, value)) = current.next() { + *pair = Some( + ComObject::new(StockKeyValuePair { + key: (*key).clone(), + value: (*value).clone(), + }) + .into_interface(), + ); + actual += 1; + } else { + break; + } + } + + Ok(actual) + } +} + +#[implement(IKeyValuePair<K, V>)] +struct StockKeyValuePair<K, V> +where + K: RuntimeType + 'static, + V: RuntimeType + 'static, + K::Default: Clone, + V::Default: Clone, +{ + key: K::Default, + value: V::Default, +} + +impl<K, V> IKeyValuePair_Impl<K, V> for StockKeyValuePair_Impl<K, V> +where + K: RuntimeType, + V: RuntimeType, + K::Default: Clone, + V::Default: Clone, +{ + fn Key(&self) -> Result<K> { + K::from_default(&self.key) + } + + fn Value(&self) -> Result<V> { + V::from_default(&self.value) + } +} + +impl<K, V> From<std::collections::BTreeMap<K::Default, V::Default>> for IMapView<K, V> +where + K: RuntimeType, + V: RuntimeType, + K::Default: Clone + Ord, + V::Default: Clone, +{ + fn from(map: std::collections::BTreeMap<K::Default, V::Default>) -> Self { + StockMapView { map }.into() + } +} diff --git a/third_party/rust/windows-collections/src/vector_view.rs b/third_party/rust/windows-collections/src/vector_view.rs @@ -0,0 +1,131 @@ +use super::*; +use windows_core::*; + +#[implement(IVectorView<T>, IIterable<T>)] +struct StockVectorView<T> +where + T: RuntimeType + 'static, + T::Default: Clone + PartialEq, +{ + values: Vec<T::Default>, +} + +impl<T> IIterable_Impl<T> for StockVectorView_Impl<T> +where + T: RuntimeType, + T::Default: Clone + PartialEq, +{ + fn First(&self) -> Result<IIterator<T>> { + Ok(ComObject::new(StockVectorViewIterator { + owner: self.to_object(), + current: 0.into(), + }) + .into_interface()) + } +} + +impl<T> IVectorView_Impl<T> for StockVectorView_Impl<T> +where + T: RuntimeType, + T::Default: Clone + PartialEq, +{ + fn GetAt(&self, index: u32) -> Result<T> { + let item = self + .values + .get(index as usize) + .ok_or_else(|| Error::from(E_BOUNDS))?; + + T::from_default(item) + } + + fn Size(&self) -> Result<u32> { + Ok(self.values.len().try_into()?) + } + + fn IndexOf(&self, value: Ref<T>, result: &mut u32) -> Result<bool> { + match self.values.iter().position(|element| element == &*value) { + Some(index) => { + *result = index as u32; + Ok(true) + } + None => Ok(false), + } + } + + fn GetMany(&self, current: u32, values: &mut [T::Default]) -> Result<u32> { + let current = current as usize; + + if current >= self.values.len() { + return Ok(0); + } + + let actual = std::cmp::min(self.values.len() - current, values.len()); + let (values, _) = values.split_at_mut(actual); + values.clone_from_slice(&self.values[current..current + actual]); + Ok(actual as u32) + } +} + +#[implement(IIterator<T>)] +struct StockVectorViewIterator<T> +where + T: RuntimeType + 'static, + T::Default: Clone + PartialEq, +{ + owner: ComObject<StockVectorView<T>>, + current: std::sync::atomic::AtomicUsize, +} + +impl<T> IIterator_Impl<T> for StockVectorViewIterator_Impl<T> +where + T: RuntimeType, + T::Default: Clone + PartialEq, +{ + fn Current(&self) -> Result<T> { + let current = self.current.load(std::sync::atomic::Ordering::Relaxed); + + if let Some(item) = self.owner.values.get(current) { + T::from_default(item) + } else { + Err(Error::from(E_BOUNDS)) + } + } + + fn HasCurrent(&self) -> Result<bool> { + let current = self.current.load(std::sync::atomic::Ordering::Relaxed); + Ok(self.owner.values.len() > current) + } + + fn MoveNext(&self) -> Result<bool> { + let current = self.current.load(std::sync::atomic::Ordering::Relaxed); + + if current < self.owner.values.len() { + self.current + .fetch_add(1, std::sync::atomic::Ordering::Relaxed); + } + + Ok(self.owner.values.len() > current + 1) + } + + fn GetMany(&self, values: &mut [T::Default]) -> Result<u32> { + let current = self.current.load(std::sync::atomic::Ordering::Relaxed); + let actual = std::cmp::min(self.owner.values.len() - current, values.len()); + let (values, _) = values.split_at_mut(actual); + values.clone_from_slice(&self.owner.values[current..current + actual]); + + self.current + .fetch_add(actual, std::sync::atomic::Ordering::Relaxed); + + Ok(actual as u32) + } +} + +impl<T> From<Vec<T::Default>> for IVectorView<T> +where + T: RuntimeType, + T::Default: Clone + PartialEq, +{ + fn from(values: Vec<T::Default>) -> Self { + ComObject::new(StockVectorView { values }).into_interface() + } +} diff --git a/third_party/rust/windows-core/.cargo-checksum.json b/third_party/rust/windows-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"6a0eed9b6df5e3fbdd4fb636fdf0778f0182dfe81fee1427de89088c31dfb299","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"a3280bab4a34e02f616e9c55459182ed93df0cf06ae6d69743140746366679d5","src/agile_reference.rs":"aeca8437136c09a51ef45cface5ae8e6720f67d23681faa12a84b14a79cfeed2","src/array.rs":"50afdb247feb5e0b575a9cfeda2359719fe0db7bd4b12c687d699f3821d15eee","src/as_impl.rs":"b9d36d6634de33928cc78b8e0824483c5b6561ca3872d5a9b267fb196db3d07e","src/com_object.rs":"c02e31da9d2d8efd7074bf3e44afe3279ca727c6ec3b840ae4d71a8c98bc55e6","src/event.rs":"d0e528b73744e31a3c46e2a69b441ba83970e3576cd5099c66792328f8dca34a","src/guid.rs":"27f3e764fb5787cf8dbf2e284e643e1555a3bd1ae5d0d70b76a9193cd051792f","src/handles.rs":"c5f53785605cc14059c4ad0272e310b435ed2f48405e8e4052fb1d5e40ee4d78","src/imp/bindings.rs":"949bd0444b102df0b63fcbc1451171c1e13400044303fd6aa50a00b1f191c198","src/imp/can_into.rs":"d06228653f20c07dcfd8a4004cd6be7a19a8da0a79226d42653ab2f3bf290816","src/imp/com_bindings.rs":"b0e5f877f7e2db25dd680ae5c75197e9ff4cb0efb2d14083f17866a20aa5440c","src/imp/factory_cache.rs":"64f00976c5e6392de7a2c4d161f58874c7dfdbecab2c983d20d16fd1acb26826","src/imp/generic_factory.rs":"340e2a75a5c4ec36bc7ea442c7211b3be4f8d3a537fda99316f9ce15bde02555","src/imp/mod.rs":"e16decb788da9edf33b7706c1ae21c2c610f0b96b4b1b505fd4c57a6e0a11193","src/imp/ref_count.rs":"57ed3694b12509b05a140c84eab931b69d4c93c446b2842aed708a9ee6a0c862","src/imp/sha1.rs":"bf8707becd6f32e13d23da0b5ecad906858f42af9626b130a3a88bf8b4f0975e","src/imp/waiter.rs":"eae739b667fcdf290cdeb533bd1254d423e1165fa697cba7a522caa5ca66f89b","src/imp/weak_ref_count.rs":"8a69cfce27500ccc0b511de3183c0d19ad260fbffc48a8bf05275b9fc02c7118","src/imp/windows.rs":"6bf14613157d1cb1d0a376fc20fb9ee5dc2d40a64535c528bff526c4e0a895b7","src/inspectable.rs":"d6767bb4796f4e2fd1c03a2cf9fddd97d7b395ca4d56dd6a443333ce92a7865b","src/interface.rs":"c3bcbdcef95f91742215f29d57ee9920fae7923914eb635054e81ad34bd06a12","src/lib.rs":"cb46d0844bcf4ae7a2d3477e206d1623c861e68b3ec0fa8821c87df27eba36e5","src/out_param.rs":"d91dd1a88201c2dbb395d371ba42270bc19191861758496fccba30ad5f8d52e9","src/out_ref.rs":"e12010828943df8c4aa40c9b53316a96f14c208fdb0e860b5206ddc5eedce1d2","src/param.rs":"88f2de2f038e3f8776872c8f9db456a9f012329800b75e001624cdf9671cf97c","src/param_value.rs":"b1d29ec7589cc7eebba1faf01aaae39f9d401dff13d2a6a5ec382f94b1becce0","src/ref.rs":"9cdceb34ad726190459bef5ec8d2a030b0dbf164b5cd969d215a3d09622897f6","src/runtime_name.rs":"b330db95b0ce32c963d6b43a0b152cd96e136e5b38b92c02223fb53b30f83ecf","src/runtime_type.rs":"4f504a1ee3525003d4376d259c5e195a08617bd5aff1789fd9027d51b354eb63","src/scoped_interface.rs":"57d9dcd0284659e2bf465c08d6c857c2c985e90f0316e5677ebd2a656edb6737","src/type.rs":"caf4d12aa96f3204148c33f6853b7f31699fde13b2b4ada3ba2a01faab89647a","src/unknown.rs":"9b6117025d4d18600ef682aa0bacb904c020b0b6bfe6c1ab6d236c716a3abea1","src/variant.rs":"2708f9ba47369879b222f19c8bc29705d03140b254d0c09ab7557a0f71dd006e","src/weak.rs":"0363f44452b6d363431f5b4d83c83be74d6c5eb419a3d5d9a3eb35b611d3c2a6","src/windows.rs":"6cd563c982c98c18f98753b210df17c71a728532392b88d11a1fc8cef9d01397"},"package":"6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"} -\ No newline at end of file +{"files":{"Cargo.lock":"961e7cc14fdddd77f49b7fa05c59d4df1c98e43c2e77f301c3ab6f3d7812d958","Cargo.toml":"8a1d754ca9637813f9aa3cf2faac93f7a1827bbaf575dde47e300043a2139546","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"0f426dba1cf9f879c1a47a26706c4ca86a7f20809bef92d1dd132a2f2e5e39d1","src/agile_reference.rs":"3f88c6db85e1fefac15352e8b6bf63c8075b2d3c2f5f0a55e5ac2625239f7bb2","src/array.rs":"a991330fdb48bbceedbe33eb3d438e44f77bd257081e9e2409d304e7bf805a66","src/as_impl.rs":"2d4d1239869c3333141e5ebaa1fa102fd43ce48a7a9a32fe246859c0d5d4866c","src/com_object.rs":"64e1481969fcf61cdc22a935c7f1e71a8486832a13dfea7e09afbc6f06fdeb58","src/event.rs":"abf575d7af25bd6a892139a659a1ce270fb807ad94f6c2be2701f70b63d148bf","src/guid.rs":"9b276cecdccb40481ac4c39d69b0c9195913414659e46bab71b854b5491fa262","src/handles.rs":"c5f53785605cc14059c4ad0272e310b435ed2f48405e8e4052fb1d5e40ee4d78","src/imp/array_proxy.rs":"1081f11dec6250e946ce1c9a74fe848b6c43cf1c20bf74b42ee93e95edcb2ca6","src/imp/bindings.rs":"7e54bcd14f10e690320e91caecc5cd4cbbf0eab5278c72df2913c7ca5d7323ba","src/imp/can_into.rs":"d06228653f20c07dcfd8a4004cd6be7a19a8da0a79226d42653ab2f3bf290816","src/imp/com_bindings.rs":"3d3375e213d7f54f4b6e07bbac036e04eceee02376db443da8d64c284a0464f0","src/imp/factory_cache.rs":"a681c5024722e87873c9153758a4913b9e4aa4182a6d57fa878b7c14a38943f0","src/imp/generic_factory.rs":"340e2a75a5c4ec36bc7ea442c7211b3be4f8d3a537fda99316f9ce15bde02555","src/imp/marshaler.rs":"563e4965ee8db90106174caeb8ee800eb3a11f24ca6607a53606bb98fbafa8f9","src/imp/mod.rs":"21aca5aa46b4dbb827805cb22d9439e2ea07b43761ea87f35989bf566197d7c6","src/imp/ref_count.rs":"a9f4b5a3f2cc59580321cc65151510dafa699b7b308360f7023ea0f0c9f52a55","src/imp/sha1.rs":"0d06e4256c2dcd30259a97e3a16afe7d1a38a6fa87bda992faac7f98d8ae9c63","src/imp/weak_ref_count.rs":"769fca4c53f3146d2559530ab878a33ddc1fa0f584e3cdd02354efd32bdac247","src/imp/windows.rs":"7c05c90441107563fe6aee53b26bb6a78f6ff73f3e29f41a813c8559b97de36f","src/inspectable.rs":"0aaa0cf86d8ab0252d65610e38522e75ef5512202b8243d1610f2ef4ae979cab","src/interface.rs":"c8ca6c7ea20a27495412081c0827151758e601ba9887fa75e7a222a94c36297b","src/lib.rs":"1c147a297b8bbcbbdb38a6ae1abb000a1eeb9592303ff1eb475baf2f3218932e","src/out_param.rs":"cfd82569b669ed3f094d8076442c92a86bda1445e1b286a55cf5b95ff8eb80f7","src/out_ref.rs":"f19bf8900b08510f7b2d5c16e31d7712ea8a4183db8eed2de608c6e5e5b30321","src/param.rs":"7b660a0e50deb0890c849538a967e0cd5942ce122d9cf819cc0c69feb33a5ba6","src/param_value.rs":"b1d29ec7589cc7eebba1faf01aaae39f9d401dff13d2a6a5ec382f94b1becce0","src/ref.rs":"c176d20f78cedd498e1c273abe71cf7199ba811b7985e6f2074306811801ef27","src/runtime_name.rs":"b330db95b0ce32c963d6b43a0b152cd96e136e5b38b92c02223fb53b30f83ecf","src/runtime_type.rs":"4f504a1ee3525003d4376d259c5e195a08617bd5aff1789fd9027d51b354eb63","src/scoped_interface.rs":"1fb8526939d682f957ae7baee3ff1435880d6da358ce6662c68382678ecd6616","src/type.rs":"71f5028b70182b2486a3ab5b9db2626babf455285594b940210cf9d5fdb33998","src/unknown.rs":"4103ab719eafd93a2f4c756a6eb48af7e7722e034c37d649fbaf40929c8d0dbf","src/weak.rs":"e84056d21b205cd90997fbcb10b3fd11367beb4305baf039a1efdfd5a10d2005","src/windows.rs":"29d05450d084aba755c51af37f36176a73b4702756b5bee280f87c398d476460","windows-core.natvis":"4edd10bdfc6827212e412e57e24f184182035d871c8bb859c6eaccc2ad8d258e"},"package":"b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"} +\ No newline at end of file diff --git a/third_party/rust/windows-core/Cargo.lock b/third_party/rust/windows-core/Cargo.lock @@ -0,0 +1,95 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "windows-core" +version = "0.62.2" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] diff --git a/third_party/rust/windows-core/Cargo.toml b/third_party/rust/windows-core/Cargo.toml @@ -11,16 +11,16 @@ [package] edition = "2021" -rust-version = "1.70" +rust-version = "1.82" name = "windows-core" -version = "0.58.0" -authors = ["Microsoft"] +version = "0.62.2" build = false +autolib = false autobins = false autoexamples = false autotests = false autobenches = false -description = "Rust for Windows" +description = "Core type support for COM and Windows" readme = "readme.md" categories = ["os::windows-apis"] license = "MIT OR Apache-2.0" @@ -30,37 +30,41 @@ repository = "https://github.com/microsoft/windows-rs" default-target = "x86_64-pc-windows-msvc" targets = [] +[features] +default = ["std"] +std = [ + "windows-result/std", + "windows-strings/std", +] + [lib] name = "windows_core" path = "src/lib.rs" [dependencies.windows-implement] -version = "0.58.0" +version = "0.60.2" +default-features = false [dependencies.windows-interface] -version = "0.58.0" +version = "0.59.3" +default-features = false + +[dependencies.windows-link] +version = "0.2.1" +default-features = false [dependencies.windows-result] -version = "0.2.0" +version = "0.4.1" +default-features = false [dependencies.windows-strings] -version = "0.1.0" - -[dependencies.windows-targets] -version = "0.52.6" - -[features] -default = ["std"] -std = [] +version = "0.5.1" +default-features = false [lints.rust] -missing_docs = "warn" - -[lints.rust.rust_2018_idioms] -level = "warn" -priority = -1 +missing_unsafe_on_extern = "warn" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 -check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"] +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-core/readme.md b/third_party/rust/windows-core/readme.md @@ -1,88 +1,7 @@ -## Rust for Windows +## Core type support for COM and Windows -The [windows](https://crates.io/crates/windows) and [windows-sys](https://crates.io/crates/windows-sys) crates let you call any Windows API past, present, and future using code generated on the fly directly from the [metadata describing the API](https://github.com/microsoft/windows-rs/tree/master/crates/libs/bindgen/default) and right into your Rust package where you can call them as if they were just another Rust module. The Rust language projection follows in the tradition established by [C++/WinRT](https://github.com/microsoft/cppwinrt) of building language projections for Windows using standard languages and compilers, providing a natural and idiomatic way for Rust developers to call Windows APIs. +The [windows-core](https://crates.io/crates/windows-core) crate provides core type support for the windows-* family of crates. * [Getting started](https://kennykerr.ca/rust-getting-started/) -* [Samples](https://github.com/microsoft/windows-rs/tree/0.58.0/crates/samples) +* [Samples](https://github.com/microsoft/windows-rs/tree/master/crates/samples) * [Releases](https://github.com/microsoft/windows-rs/releases) - -Start by adding the following to your Cargo.toml file: - -```toml -[dependencies.windows] -version = "0.58" -features = [ - "Data_Xml_Dom", - "Win32_Foundation", - "Win32_Security", - "Win32_System_Threading", - "Win32_UI_WindowsAndMessaging", -] -``` - -Make use of any Windows APIs as needed: - -```rust,no_run -use windows::{ - core::*, Data::Xml::Dom::*, Win32::Foundation::*, Win32::System::Threading::*, - Win32::UI::WindowsAndMessaging::*, -}; - -fn main() -> Result<()> { - let doc = XmlDocument::new()?; - doc.LoadXml(h!("<html>hello world</html>"))?; - - let root = doc.DocumentElement()?; - assert!(root.NodeName()? == "html"); - assert!(root.InnerText()? == "hello world"); - - unsafe { - let event = CreateEventW(None, true, false, None)?; - SetEvent(event)?; - WaitForSingleObject(event, 0); - CloseHandle(event)?; - - MessageBoxA(None, s!("Ansi"), s!("Caption"), MB_OK); - MessageBoxW(None, w!("Wide"), w!("Caption"), MB_OK); - } - - Ok(()) -} -``` - -## windows-sys - -The `windows-sys` crate is a zero-overhead fallback for the most demanding situations and primarily where the absolute best compile time is essential. It only includes function declarations (externs), structs, and constants. No convenience helpers, traits, or wrappers are provided. - -Start by adding the following to your Cargo.toml file: - -```toml -[dependencies.windows-sys] -version = "0.52" -features = [ - "Win32_Foundation", - "Win32_Security", - "Win32_System_Threading", - "Win32_UI_WindowsAndMessaging", -] -``` - -Make use of any Windows APIs as needed: - -```rust,no_run -use windows_sys::{ - core::*, Win32::Foundation::*, Win32::System::Threading::*, Win32::UI::WindowsAndMessaging::*, -}; - -fn main() { - unsafe { - let event = CreateEventW(std::ptr::null(), 1, 0, std::ptr::null()); - SetEvent(event); - WaitForSingleObject(event, 0); - CloseHandle(event); - - MessageBoxA(0 as _, s!("Ansi"), s!("Caption"), MB_OK); - MessageBoxW(0 as _, w!("Wide"), w!("Caption"), MB_OK); - } -} -``` diff --git a/third_party/rust/windows-core/src/agile_reference.rs b/third_party/rust/windows-core/src/agile_reference.rs @@ -33,7 +33,7 @@ unsafe impl<T: Interface> Send for AgileReference<T> {} unsafe impl<T: Interface> Sync for AgileReference<T> {} impl<T> core::fmt::Debug for AgileReference<T> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!(f, "AgileReference({:?})", &self.0) } } diff --git a/third_party/rust/windows-core/src/array.rs b/third_party/rust/windows-core/src/array.rs @@ -2,13 +2,13 @@ use super::*; /// A WinRT array stores elements contiguously in a heap-allocated buffer. pub struct Array<T: Type<T>> { - data: *mut T::Default, - len: u32, + pub(crate) data: *mut T::Default, + pub(crate) len: u32, } impl<T: Type<T>> Default for Array<T> { fn default() -> Self { - Array { + Self { data: core::ptr::null_mut(), len: 0, } @@ -97,7 +97,7 @@ impl<T: Type<T>> Array<T> { unsafe { // Call the destructors of all the elements of the old array // SAFETY: the slice cannot be used after the call to `drop_in_place` - core::ptr::drop_in_place(core::slice::from_raw_parts_mut(data, len as usize)); + core::ptr::drop_in_place(core::ptr::slice_from_raw_parts_mut(data, len as usize)); // Free the data memory where the elements were // SAFETY: we have unique access to the data pointer at this point // so freeing it is the right thing to do @@ -155,32 +155,11 @@ impl<T: Type<T>> Drop for Array<T> { } } -#[doc(hidden)] -pub struct ArrayProxy<T: Type<T>> { - data: *mut *mut T::Default, - len: *mut u32, - temp: core::mem::ManuallyDrop<Array<T>>, -} - -impl<T: Type<T>> ArrayProxy<T> { - pub fn from_raw_parts(data: *mut *mut T::Default, len: *mut u32) -> Self { - Self { - data, - len, - temp: core::mem::ManuallyDrop::new(Array::new()), - } - } - - pub fn as_array(&mut self) -> &mut Array<T> { - &mut self.temp - } -} - -impl<T: Type<T>> Drop for ArrayProxy<T> { - fn drop(&mut self) { - unsafe { - *self.data = self.temp.data; - *self.len = self.temp.len; - } +impl<T: Type<T>> core::fmt::Debug for Array<T> +where + T::Default: core::fmt::Debug, +{ + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::ops::Deref::deref(self).fmt(f) } } diff --git a/third_party/rust/windows-core/src/as_impl.rs b/third_party/rust/windows-core/src/as_impl.rs @@ -7,7 +7,7 @@ pub trait AsImpl<T> { /// The caller needs to ensure that `self` is actually implemented by the /// implementation `T`. unsafe fn as_impl(&self) -> &T { - self.as_impl_ptr().as_ref() + unsafe { self.as_impl_ptr().as_ref() } } /// Returns a pointer to the implementation object. diff --git a/third_party/rust/windows-core/src/com_object.rs b/third_party/rust/windows-core/src/com_object.rs @@ -1,5 +1,5 @@ use crate::imp::Box; -use crate::{AsImpl, IUnknown, IUnknownImpl, Interface, InterfaceRef}; +use crate::{IUnknown, IUnknownImpl, Interface, InterfaceRef}; use core::any::Any; use core::borrow::Borrow; use core::ops::Deref; @@ -245,10 +245,7 @@ impl<T: ComObjectInner> Clone for ComObject<T> { } } -impl<T: ComObjectInner> AsRef<T> for ComObject<T> -where - IUnknown: From<T> + AsImpl<T>, -{ +impl<T: ComObjectInner> AsRef<T> for ComObject<T> { #[inline(always)] fn as_ref(&self) -> &T { self.get() @@ -270,8 +267,8 @@ impl<T: ComObjectInner> Deref for ComObject<T> { // exclusive access. impl<T: ComObjectInner> From<T> for ComObject<T> { - fn from(value: T) -> ComObject<T> { - ComObject::new(value) + fn from(value: T) -> Self { + Self::new(value) } } @@ -288,7 +285,7 @@ unsafe impl<T: ComObjectInner + Send> Send for ComObject<T> {} unsafe impl<T: ComObjectInner + Sync> Sync for ComObject<T> {} impl<T: ComObjectInner + PartialEq> PartialEq for ComObject<T> { - fn eq(&self, other: &ComObject<T>) -> bool { + fn eq(&self, other: &Self) -> bool { let inner_self: &T = self.get(); let other_self: &T = other.get(); inner_self == other_self @@ -314,13 +311,13 @@ impl<T: ComObjectInner + Ord> Ord for ComObject<T> { } impl<T: ComObjectInner + core::fmt::Debug> core::fmt::Debug for ComObject<T> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { <T as core::fmt::Debug>::fmt(self.get(), f) } } impl<T: ComObjectInner + core::fmt::Display> core::fmt::Display for ComObject<T> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { <T as core::fmt::Display>::fmt(self.get(), f) } } @@ -330,3 +327,68 @@ impl<T: ComObjectInner> Borrow<T> for ComObject<T> { self.get() } } + +/// Enables applications to define COM objects using static storage. This is useful for factory +/// objects, stateless objects, or objects which use need to contain or use mutable global state. +/// +/// COM objects that are defined using `StaticComObject` have their storage placed directly in +/// static storage; they are not stored in the heap. +/// +/// COM objects defined using `StaticComObject` do have a reference count and this reference +/// count is adjusted when owned COM interface references (e.g. `IFoo` and `IUnknown`) are created +/// for the object. The reference count is initialized to 1. +/// +/// # Example +/// +/// ```rust,ignore +/// #[implement(IFoo)] +/// struct MyApp { +/// // ... +/// } +/// +/// static MY_STATIC_APP: StaticComObject<MyApp> = MyApp { ... }.into_static(); +/// +/// fn get_my_static_ifoo() -> IFoo { +/// MY_STATIC_APP.to_interface() +/// } +/// ``` +pub struct StaticComObject<T> +where + T: ComObjectInner, +{ + outer: T::Outer, +} + +// IMPORTANT: Do not expose any methods that return mutable access to the contents of StaticComObject. +// Doing so would violate our safety invariants. For example, we provide a Deref impl but it would +// be unsound to provide a DerefMut impl. +impl<T> StaticComObject<T> +where + T: ComObjectInner, +{ + /// Wraps `outer` in a `StaticComObject`. + pub const fn from_outer(outer: T::Outer) -> Self { + Self { outer } + } +} + +impl<T> StaticComObject<T> +where + T: ComObjectInner, +{ + /// Gets access to the contained value. + pub const fn get(&'static self) -> &'static T::Outer { + &self.outer + } +} + +impl<T> core::ops::Deref for StaticComObject<T> +where + T: ComObjectInner, +{ + type Target = T::Outer; + + fn deref(&self) -> &Self::Target { + &self.outer + } +} diff --git a/third_party/rust/windows-core/src/event.rs b/third_party/rust/windows-core/src/event.rs @@ -1,20 +1,18 @@ use super::*; -use core::ffi::c_void; -use core::marker::PhantomData; -use core::mem::{size_of, transmute_copy}; -use core::ptr::null_mut; -use std::sync::Mutex; +use core::{iter::once, mem::transmute_copy}; +use std::sync::{Arc, RwLock}; /// A type that you can use to declare and implement an event of a specified delegate type. /// /// The implementation is thread-safe and designed to avoid contention between events being /// raised and delegates being added or removed. pub struct Event<T: Interface> { - swap: Mutex<()>, - change: Mutex<()>, - delegates: Array<T>, + delegates: RwLock<Option<Arc<[Delegate<T>]>>>, } +unsafe impl<T: Interface> Send for Event<T> {} +unsafe impl<T: Interface> Sync for Event<T> {} + impl<T: Interface> Default for Event<T> { fn default() -> Self { Self::new() @@ -23,230 +21,88 @@ impl<T: Interface> Default for Event<T> { impl<T: Interface> Event<T> { /// Creates a new, empty `Event<T>`. - pub fn new() -> Self { + pub const fn new() -> Self { Self { - delegates: Array::new(), - swap: Mutex::default(), - change: Mutex::default(), + delegates: RwLock::new(None), } } /// Registers a delegate with the event object. - pub fn add(&mut self, delegate: &T) -> Result<i64> { - let mut _lock_free_drop = Array::new(); - Ok({ - let _change_lock = self.change.lock().unwrap(); - let mut new_delegates = Array::with_capacity(self.delegates.len() + 1)?; - for delegate in self.delegates.as_slice() { - new_delegates.push(delegate.clone()); - } - let delegate = Delegate::new(delegate)?; - let token = delegate.to_token(); - new_delegates.push(delegate); + pub fn add(&self, delegate: &T) -> Result<i64> { + let new_delegate = Delegate::new(delegate)?; + let token = new_delegate.to_token(); + let new_iter = once(new_delegate); + let mut guard = self.delegates.write().unwrap(); + + let new_list = if let Some(old_delegates) = guard.as_ref() { + Arc::from_iter(old_delegates.iter().cloned().chain(new_iter)) + } else { + Arc::from_iter(new_iter) + }; + + let old_list = guard.replace(new_list); + drop(guard); + drop(old_list); // drop the old delegates _after_ releasing lock - let _swap_lock = self.swap.lock().unwrap(); - _lock_free_drop = self.delegates.swap(new_delegates); - token - }) + Ok(token) } /// Revokes a delegate's registration from the event object. - pub fn remove(&mut self, token: i64) -> Result<()> { - let mut _lock_free_drop = Array::new(); - { - let _change_lock = self.change.lock().unwrap(); - if self.delegates.is_empty() { - return Ok(()); - } - let mut capacity = self.delegates.len() - 1; - let mut new_delegates = Array::new(); - let mut removed = false; - if capacity == 0 { - removed = self.delegates.as_slice()[0].to_token() == token; - } else { - new_delegates = Array::with_capacity(capacity)?; - for delegate in self.delegates.as_slice() { - if !removed && delegate.to_token() == token { - removed = true; - continue; - } - if capacity == 0 { - break; - } - new_delegates.push(delegate.clone()); - capacity -= 1; - } - } - if removed { - let _swap_lock = self.swap.lock().unwrap(); - _lock_free_drop = self.delegates.swap(new_delegates); + pub fn remove(&self, token: i64) { + let mut guard = self.delegates.write().unwrap(); + let mut old_list = None; + if let Some(old_delegates) = guard.as_ref() { + // `self.delegates` is only modified if the token is found. + if let Some(i) = old_delegates + .iter() + .position(|old_delegate| old_delegate.to_token() == token) + { + let new_list = Arc::from_iter( + old_delegates[..i] + .iter() + .chain(old_delegates[i + 1..].iter()) + .cloned(), + ); + + old_list = guard.replace(new_list); } } - Ok(()) + drop(guard); + drop(old_list); // drop the old delegates _after_ releasing lock } /// Clears the event, removing all delegates. - pub fn clear(&mut self) { - let mut _lock_free_drop = Array::new(); - { - let _change_lock = self.change.lock().unwrap(); - if self.delegates.is_empty() { - return; - } - let _swap_lock = self.swap.lock().unwrap(); - _lock_free_drop = self.delegates.swap(Array::new()); - } + pub fn clear(&self) { + let mut guard = self.delegates.write().unwrap(); + let old_list = guard.take(); + drop(guard); + drop(old_list); // drop the old delegates _after_ releasing lock } /// Invokes all of the event object's registered delegates with the provided callback. - pub fn call<F: FnMut(&T) -> Result<()>>(&mut self, mut callback: F) -> Result<()> { - let lock_free_calls = { - let _swap_lock = self.swap.lock().unwrap(); - self.delegates.clone() + pub fn call<F: FnMut(&T) -> Result<()>>(&self, mut callback: F) { + let delegates = { + let guard = self.delegates.read().unwrap(); + if let Some(delegates) = guard.as_ref() { + delegates.clone() + } else { + // No delegates to call. + return; + } + // <-- lock is released here }; - for delegate in lock_free_calls.as_slice() { + + for delegate in delegates.iter() { if let Err(error) = delegate.call(&mut callback) { const RPC_E_SERVER_UNAVAILABLE: HRESULT = HRESULT(-2147023174); // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) if matches!( error.code(), imp::RPC_E_DISCONNECTED | imp::JSCRIPT_E_CANTEXECUTE | RPC_E_SERVER_UNAVAILABLE ) { - self.remove(delegate.to_token())?; + self.remove(delegate.to_token()); } } } - Ok(()) - } -} - -/// A thread-safe reference-counted array of delegates. -struct Array<T: Interface> { - buffer: *mut Buffer<T>, - len: usize, - _phantom: PhantomData<T>, -} - -impl<T: Interface> Default for Array<T> { - fn default() -> Self { - Self::new() - } -} - -impl<T: Interface> Array<T> { - /// Creates a new, empty `Array<T>` with no capacity. - fn new() -> Self { - Self { - buffer: null_mut(), - len: 0, - _phantom: PhantomData, - } - } - - /// Creates a new, empty `Array<T>` with the specified capacity. - fn with_capacity(capacity: usize) -> Result<Self> { - Ok(Self { - buffer: Buffer::new(capacity)?, - len: 0, - _phantom: PhantomData, - }) - } - - /// Swaps the contents of two `Array<T>` objects. - fn swap(&mut self, mut other: Self) -> Self { - unsafe { core::ptr::swap(&mut self.buffer, &mut other.buffer) }; - core::mem::swap(&mut self.len, &mut other.len); - other - } - - /// Returns `true` if the array contains no delegates. - fn is_empty(&self) -> bool { - self.len == 0 - } - - /// Returns the number of delegates in the array. - fn len(&self) -> usize { - self.len - } - - /// Appends a delegate to the back of the array. - fn push(&mut self, delegate: Delegate<T>) { - unsafe { - (*self.buffer).as_mut_ptr().add(self.len).write(delegate); - self.len += 1; - } - } - - /// Returns a slice containing of all delegates. - fn as_slice(&self) -> &[Delegate<T>] { - if self.is_empty() { - &[] - } else { - unsafe { core::slice::from_raw_parts((*self.buffer).as_ptr(), self.len) } - } - } - - /// Returns a mutable slice of all delegates. - fn as_mut_slice(&mut self) -> &mut [Delegate<T>] { - if self.is_empty() { - &mut [] - } else { - unsafe { core::slice::from_raw_parts_mut((*self.buffer).as_mut_ptr(), self.len) } - } - } -} - -impl<T: Interface> Clone for Array<T> { - fn clone(&self) -> Self { - if !self.is_empty() { - unsafe { (*self.buffer).0.add_ref() }; - } - Self { - buffer: self.buffer, - len: self.len, - _phantom: PhantomData, - } - } -} - -impl<T: Interface> Drop for Array<T> { - fn drop(&mut self) { - unsafe { - if !self.is_empty() && (*self.buffer).0.release() == 0 { - core::ptr::drop_in_place(self.as_mut_slice()); - heap_free(self.buffer as _) - } - } - } -} - -/// A reference-counted buffer. -#[repr(C)] -#[repr(align(8))] -struct Buffer<T>(imp::RefCount, PhantomData<T>); - -impl<T: Interface> Buffer<T> { - /// Creates a new `Buffer` with the specified size in bytes. - fn new(len: usize) -> Result<*mut Self> { - if len == 0 { - Ok(null_mut()) - } else { - let alloc_size = size_of::<Self>() + len * size_of::<Delegate<T>>(); - let header = heap_alloc(alloc_size)? as *mut Self; - unsafe { - header.write(Self(imp::RefCount::new(1), PhantomData)); - } - Ok(header) - } - } - - /// Returns a raw pointer to the buffer's contents. The resulting pointer might be uninititalized. - fn as_ptr(&self) -> *const Delegate<T> { - unsafe { (self as *const Self).add(1) as *const _ } - } - - /// Returns a raw mutable pointer to the buffer's contents. The resulting pointer might be uninititalized. - fn as_mut_ptr(&mut self) -> *mut Delegate<T> { - unsafe { (self as *mut Self).add(1) as *mut _ } } } @@ -286,30 +142,3 @@ impl<T: Interface> Delegate<T> { } } } - -/// Allocate memory of size `bytes` using `malloc` - the `Event` implementation does not -/// need to use any particular allocator so `HeapAlloc` need not be used. -fn heap_alloc(bytes: usize) -> crate::Result<*mut c_void> { - let ptr: *mut c_void = unsafe { - extern "C" { - fn malloc(bytes: usize) -> *mut c_void; - } - - malloc(bytes) - }; - - if ptr.is_null() { - Err(Error::from_hresult(imp::E_OUTOFMEMORY)) - } else { - Ok(ptr) - } -} - -/// Free memory allocated by `heap_alloc`. -unsafe fn heap_free(ptr: *mut c_void) { - extern "C" { - fn free(ptr: *mut c_void); - } - - free(ptr); -} diff --git a/third_party/rust/windows-core/src/guid.rs b/third_party/rust/windows-core/src/guid.rs @@ -1,5 +1,3 @@ -#![allow(clippy::many_single_char_names)] - use super::*; /// A globally unique identifier ([GUID](https://docs.microsoft.com/en-us/windows/win32/api/guiddef/ns-guiddef-guid)) @@ -23,7 +21,14 @@ pub struct GUID { impl GUID { /// Creates a unique `GUID` value. pub fn new() -> Result<Self> { - unsafe { imp::CoCreateGuid() } + let mut guid = Self::zeroed(); + let result = unsafe { imp::UuidCreate(&mut guid as *mut _ as _) }; + + if matches!(result, 0 | imp::RPC_S_UUID_LOCAL_ONLY) { + Ok(guid) + } else { + Err(Error::from_hresult(HRESULT::from_win32(result as u32))) + } } /// Creates a `GUID` represented by the all-zero byte-pattern. @@ -50,8 +55,8 @@ impl GUID { pub const fn from_u128(uuid: u128) -> Self { Self { data1: (uuid >> 96) as u32, - data2: (uuid >> 80 & 0xffff) as u16, - data3: (uuid >> 64 & 0xffff) as u16, + data2: ((uuid >> 80) & 0xffff) as u16, + data3: ((uuid >> 64) & 0xffff) as u16, data4: (uuid as u64).to_be_bytes(), } } @@ -101,7 +106,7 @@ impl TypeKind for GUID { } impl core::fmt::Debug for GUID { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!( f, "{:08X?}-{:04X?}-{:04X?}-{:02X?}{:02X?}-{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}", @@ -120,37 +125,30 @@ impl core::fmt::Debug for GUID { } } -impl From<&str> for GUID { - fn from(value: &str) -> Self { - assert!(value.len() == 36, "Invalid GUID string"); - let mut bytes = value.bytes(); - - let a = ((bytes.next_u32() * 16 + bytes.next_u32()) << 24) - + ((bytes.next_u32() * 16 + bytes.next_u32()) << 16) - + ((bytes.next_u32() * 16 + bytes.next_u32()) << 8) - + bytes.next_u32() * 16 - + bytes.next_u32(); - assert!(bytes.next().unwrap() == b'-', "Invalid GUID string"); - let b = ((bytes.next_u16() * 16 + (bytes.next_u16())) << 8) - + bytes.next_u16() * 16 - + bytes.next_u16(); - assert!(bytes.next().unwrap() == b'-', "Invalid GUID string"); - let c = ((bytes.next_u16() * 16 + bytes.next_u16()) << 8) - + bytes.next_u16() * 16 - + bytes.next_u16(); - assert!(bytes.next().unwrap() == b'-', "Invalid GUID string"); - let d = bytes.next_u8() * 16 + bytes.next_u8(); - let e = bytes.next_u8() * 16 + bytes.next_u8(); - assert!(bytes.next().unwrap() == b'-', "Invalid GUID string"); - - let f = bytes.next_u8() * 16 + bytes.next_u8(); - let g = bytes.next_u8() * 16 + bytes.next_u8(); - let h = bytes.next_u8() * 16 + bytes.next_u8(); - let i = bytes.next_u8() * 16 + bytes.next_u8(); - let j = bytes.next_u8() * 16 + bytes.next_u8(); - let k = bytes.next_u8() * 16 + bytes.next_u8(); - - Self::from_values(a, b, c, [d, e, f, g, h, i, j, k]) +impl TryFrom<&str> for GUID { + type Error = Error; + + fn try_from(from: &str) -> Result<Self> { + if from.len() != 36 { + return Err(invalid_guid()); + } + + let bytes = &mut from.bytes(); + let mut guid = Self::zeroed(); + + guid.data1 = try_u32(bytes, true)?; + guid.data2 = try_u16(bytes, true)?; + guid.data3 = try_u16(bytes, true)?; + guid.data4[0] = try_u8(bytes, false)?; + guid.data4[1] = try_u8(bytes, true)?; + guid.data4[2] = try_u8(bytes, false)?; + guid.data4[3] = try_u8(bytes, false)?; + guid.data4[4] = try_u8(bytes, false)?; + guid.data4[5] = try_u8(bytes, false)?; + guid.data4[6] = try_u8(bytes, false)?; + guid.data4[7] = try_u8(bytes, false)?; + + Ok(guid) } } @@ -166,28 +164,43 @@ impl From<GUID> for u128 { } } -trait HexReader { - fn next_u8(&mut self) -> u8; - fn next_u16(&mut self) -> u16; - fn next_u32(&mut self) -> u32; +fn invalid_guid() -> Error { + Error::from_hresult(imp::E_INVALIDARG) } -impl HexReader for core::str::Bytes<'_> { - fn next_u8(&mut self) -> u8 { - let value = self.next().unwrap(); - match value { - b'0'..=b'9' => value - b'0', - b'A'..=b'F' => 10 + value - b'A', - b'a'..=b'f' => 10 + value - b'a', - _ => panic!(), - } - } +fn try_u32(bytes: &mut core::str::Bytes, delimiter: bool) -> Result<u32> { + next(bytes, 8, delimiter).ok_or_else(invalid_guid) +} + +fn try_u16(bytes: &mut core::str::Bytes, delimiter: bool) -> Result<u16> { + next(bytes, 4, delimiter) + .map(|value| value as u16) + .ok_or_else(invalid_guid) +} + +fn try_u8(bytes: &mut core::str::Bytes, delimiter: bool) -> Result<u8> { + next(bytes, 2, delimiter) + .map(|value| value as u8) + .ok_or_else(invalid_guid) +} + +fn next(bytes: &mut core::str::Bytes, len: usize, delimiter: bool) -> Option<u32> { + let mut value: u32 = 0; - fn next_u16(&mut self) -> u16 { - self.next_u8().into() + for _ in 0..len { + let digit = bytes.next()?; + + match digit { + b'0'..=b'9' => value = (value << 4) + (digit - b'0') as u32, + b'A'..=b'F' => value = (value << 4) + (digit - b'A' + 10) as u32, + b'a'..=b'f' => value = (value << 4) + (digit - b'a' + 10) as u32, + _ => return None, + } } - fn next_u32(&mut self) -> u32 { - self.next_u8().into() + if delimiter && bytes.next() != Some(b'-') { + None + } else { + Some(value) } } diff --git a/third_party/rust/windows-core/src/imp/array_proxy.rs b/third_party/rust/windows-core/src/imp/array_proxy.rs @@ -0,0 +1,38 @@ +use crate::{Array, Type}; + +pub struct ArrayProxy<T: Type<T>> { + data: *mut *mut T::Default, + len: *mut u32, + temp: core::mem::ManuallyDrop<Array<T>>, +} + +pub unsafe fn array_proxy<T: Type<T>>(data: *mut *mut T::Default, len: *mut u32) -> ArrayProxy<T> { + ArrayProxy { + data, + len, + temp: core::mem::ManuallyDrop::new(Array::new()), + } +} + +impl<T: Type<T>> Drop for ArrayProxy<T> { + fn drop(&mut self) { + unsafe { + *self.data = self.temp.data; + *self.len = self.temp.len; + } + } +} + +impl<T: Type<T>> core::ops::Deref for ArrayProxy<T> { + type Target = Array<T>; + + fn deref(&self) -> &Array<T> { + &self.temp + } +} + +impl<T: Type<T>> core::ops::DerefMut for ArrayProxy<T> { + fn deref_mut(&mut self) -> &mut Array<T> { + &mut self.temp + } +} diff --git a/third_party/rust/windows-core/src/imp/bindings.rs b/third_party/rust/windows-core/src/imp/bindings.rs @@ -1,322 +1,17 @@ -#![allow( - non_snake_case, - non_upper_case_globals, - non_camel_case_types, - dead_code, - clippy::all -)] -windows_targets::link!("api-ms-win-core-winrt-l1-1-0.dll" "system" fn RoGetActivationFactory(activatableclassid : * mut core::ffi::c_void, iid : *const GUID, factory : *mut *mut core::ffi::c_void) -> HRESULT); -windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL); -windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE); -windows_targets::link!("kernel32.dll" "system" fn EncodePointer(ptr : *const core::ffi::c_void) -> *mut core::ffi::c_void); -windows_targets::link!("kernel32.dll" "system" fn FreeLibrary(hlibmodule : HMODULE) -> BOOL); -windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC); -windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE); -windows_targets::link!("kernel32.dll" "system" fn SetEvent(hevent : HANDLE) -> BOOL); -windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT); -windows_targets::link!("ole32.dll" "system" fn CoIncrementMTAUsage(pcookie : *mut CO_MTA_USAGE_COOKIE) -> HRESULT); -windows_targets::link!("ole32.dll" "system" fn CoTaskMemAlloc(cb : usize) -> *mut core::ffi::c_void); -windows_targets::link!("ole32.dll" "system" fn CoTaskMemFree(pv : *const core::ffi::c_void)); -windows_targets::link!("ole32.dll" "system" fn PropVariantClear(pvar : *mut PROPVARIANT) -> HRESULT); -windows_targets::link!("ole32.dll" "system" fn PropVariantCopy(pvardest : *mut PROPVARIANT, pvarsrc : *const PROPVARIANT) -> HRESULT); -windows_targets::link!("oleaut32.dll" "system" fn VariantClear(pvarg : *mut VARIANT) -> HRESULT); -windows_targets::link!("oleaut32.dll" "system" fn VariantCopy(pvargdest : *mut VARIANT, pvargsrc : *const VARIANT) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantCompareEx(propvar1 : *const PROPVARIANT, propvar2 : *const PROPVARIANT, unit : PROPVAR_COMPARE_UNIT, flags : PROPVAR_COMPARE_FLAGS) -> i32); -windows_targets::link!("propsys.dll" "system" fn PropVariantToBSTR(propvar : *const PROPVARIANT, pbstrout : *mut BSTR) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToBoolean(propvarin : *const PROPVARIANT, pfret : *mut BOOL) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToDouble(propvarin : *const PROPVARIANT, pdblret : *mut f64) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToInt16(propvarin : *const PROPVARIANT, piret : *mut i16) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToInt32(propvarin : *const PROPVARIANT, plret : *mut i32) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToInt64(propvarin : *const PROPVARIANT, pllret : *mut i64) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToUInt16(propvarin : *const PROPVARIANT, puiret : *mut u16) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToUInt32(propvarin : *const PROPVARIANT, pulret : *mut u32) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToUInt64(propvarin : *const PROPVARIANT, pullret : *mut u64) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn PropVariantToVariant(ppropvar : *const PROPVARIANT, pvar : *mut VARIANT) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToBoolean(varin : *const VARIANT, pfret : *mut BOOL) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToDouble(varin : *const VARIANT, pdblret : *mut f64) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToInt16(varin : *const VARIANT, piret : *mut i16) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToInt32(varin : *const VARIANT, plret : *mut i32) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToInt64(varin : *const VARIANT, pllret : *mut i64) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToPropVariant(pvar : *const VARIANT, ppropvar : *mut PROPVARIANT) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToUInt16(varin : *const VARIANT, puiret : *mut u16) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToUInt32(varin : *const VARIANT, pulret : *mut u32) -> HRESULT); -windows_targets::link!("propsys.dll" "system" fn VariantToUInt64(varin : *const VARIANT, pullret : *mut u64) -> HRESULT); -pub type ADVANCED_FEATURE_FLAGS = u16; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct ARRAYDESC { - pub tdescElem: TYPEDESC, - pub cDims: u16, - pub rgbounds: [SAFEARRAYBOUND; 1], -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union BINDPTR { - pub lpfuncdesc: *mut FUNCDESC, - pub lpvardesc: *mut VARDESC, - pub lptcomp: *mut core::ffi::c_void, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct BLOB { - pub cbSize: u32, - pub pBlobData: *mut u8, -} +windows_link::link!("combase.dll" "system" fn CoIncrementMTAUsage(pcookie : *mut CO_MTA_USAGE_COOKIE) -> HRESULT); +windows_link::link!("combase.dll" "system" fn CoTaskMemAlloc(cb : usize) -> *mut core::ffi::c_void); +windows_link::link!("combase.dll" "system" fn CoTaskMemFree(pv : *const core::ffi::c_void)); +windows_link::link!("kernel32.dll" "system" fn EncodePointer(ptr : *const core::ffi::c_void) -> *mut core::ffi::c_void); +windows_link::link!("kernel32.dll" "system" fn FreeLibrary(hlibmodule : HMODULE) -> BOOL); +windows_link::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC); +windows_link::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE); +windows_link::link!("api-ms-win-core-winrt-l1-1-0.dll" "system" fn RoGetActivationFactory(activatableclassid : HSTRING, iid : *const GUID, factory : *mut *mut core::ffi::c_void) -> HRESULT); +windows_link::link!("rpcrt4.dll" "system" fn UuidCreate(uuid : *mut GUID) -> RPC_STATUS); pub type BOOL = i32; -pub type BSTR = *const u16; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct BSTRBLOB { - pub cbSize: u32, - pub pData: *mut u8, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CABOOL { - pub cElems: u32, - pub pElems: *mut VARIANT_BOOL, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CABSTR { - pub cElems: u32, - pub pElems: *mut BSTR, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CABSTRBLOB { - pub cElems: u32, - pub pElems: *mut BSTRBLOB, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAC { - pub cElems: u32, - pub pElems: PSTR, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CACLIPDATA { - pub cElems: u32, - pub pElems: *mut CLIPDATA, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CACLSID { - pub cElems: u32, - pub pElems: *mut GUID, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CACY { - pub cElems: u32, - pub pElems: *mut CY, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CADATE { - pub cElems: u32, - pub pElems: *mut f64, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CADBL { - pub cElems: u32, - pub pElems: *mut f64, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAFILETIME { - pub cElems: u32, - pub pElems: *mut FILETIME, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAFLT { - pub cElems: u32, - pub pElems: *mut f32, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAH { - pub cElems: u32, - pub pElems: *mut i64, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAI { - pub cElems: u32, - pub pElems: *mut i16, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAL { - pub cElems: u32, - pub pElems: *mut i32, -} -pub type CALLCONV = i32; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CALPSTR { - pub cElems: u32, - pub pElems: *mut PSTR, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CALPWSTR { - pub cElems: u32, - pub pElems: *mut PWSTR, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAPROPVARIANT { - pub cElems: u32, - pub pElems: *mut PROPVARIANT, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CASCODE { - pub cElems: u32, - pub pElems: *mut i32, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAUB { - pub cElems: u32, - pub pElems: *mut u8, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAUH { - pub cElems: u32, - pub pElems: *mut u64, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAUI { - pub cElems: u32, - pub pElems: *mut u16, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CAUL { - pub cElems: u32, - pub pElems: *mut u32, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CLIPDATA { - pub cbSize: u32, - pub ulClipFmt: i32, - pub pClipData: *mut u8, -} pub type CO_MTA_USAGE_COOKIE = *mut core::ffi::c_void; -#[repr(C)] -#[derive(Clone, Copy)] -pub union CY { - pub Anonymous: CY_0, - pub int64: i64, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct CY_0 { - pub Lo: u32, - pub Hi: i32, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct DECIMAL { - pub wReserved: u16, - pub Anonymous1: DECIMAL_0, - pub Hi32: u32, - pub Anonymous2: DECIMAL_1, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union DECIMAL_0 { - pub Anonymous: DECIMAL_0_0, - pub signscale: u16, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct DECIMAL_0_0 { - pub scale: u8, - pub sign: u8, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union DECIMAL_1 { - pub Anonymous: DECIMAL_1_0, - pub Lo64: u64, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct DECIMAL_1_0 { - pub Lo32: u32, - pub Mid32: u32, -} -pub type DESCKIND = i32; -pub type DISPATCH_FLAGS = u16; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct DISPPARAMS { - pub rgvarg: *mut VARIANT, - pub rgdispidNamedArgs: *mut i32, - pub cArgs: u32, - pub cNamedArgs: u32, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct ELEMDESC { - pub tdesc: TYPEDESC, - pub Anonymous: ELEMDESC_0, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union ELEMDESC_0 { - pub idldesc: IDLDESC, - pub paramdesc: PARAMDESC, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct EXCEPINFO { - pub wCode: u16, - pub wReserved: u16, - pub bstrSource: BSTR, - pub bstrDescription: BSTR, - pub bstrHelpFile: BSTR, - pub dwHelpContext: u32, - pub pvReserved: *mut core::ffi::c_void, - pub pfnDeferredFillIn: LPEXCEPFINO_DEFERRED_FILLIN, - pub scode: i32, -} pub type FARPROC = Option<unsafe extern "system" fn() -> isize>; #[repr(C)] #[derive(Clone, Copy)] -pub struct FILETIME { - pub dwLowDateTime: u32, - pub dwHighDateTime: u32, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct FUNCDESC { - pub memid: i32, - pub lprgscode: *mut i32, - pub lprgelemdescParam: *mut ELEMDESC, - pub funckind: FUNCKIND, - pub invkind: INVOKEKIND, - pub callconv: CALLCONV, - pub cParams: i16, - pub cParamsOpt: i16, - pub oVft: i16, - pub cScodes: i16, - pub elemdescFunc: ELEMDESC, - pub wFuncFlags: FUNCFLAGS, -} -pub type FUNCFLAGS = u16; -pub type FUNCKIND = i32; -#[repr(C)] -#[derive(Clone, Copy)] pub struct GUID { pub data1: u32, pub data2: u16, @@ -334,338 +29,12 @@ impl GUID { } } pub type HANDLE = *mut core::ffi::c_void; +pub type HINSTANCE = *mut core::ffi::c_void; pub type HMODULE = *mut core::ffi::c_void; pub type HRESULT = i32; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct IDLDESC { - pub dwReserved: usize, - pub wIDLFlags: IDLFLAGS, -} -pub type IDLFLAGS = u16; -pub type IMPLTYPEFLAGS = i32; -pub type INVOKEKIND = i32; pub type LOAD_LIBRARY_FLAGS = u32; pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 4096u32; -pub type LPEXCEPFINO_DEFERRED_FILLIN = - Option<unsafe extern "system" fn(pexcepinfo: *mut EXCEPINFO) -> HRESULT>; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct PARAMDESC { - pub pparamdescex: *mut PARAMDESCEX, - pub wParamFlags: PARAMFLAGS, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct PARAMDESCEX { - pub cBytes: u32, - pub varDefaultValue: VARIANT, -} -pub type PARAMFLAGS = u16; pub type PCSTR = *const u8; -pub type PCWSTR = *const u16; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct PROPVARIANT { - pub Anonymous: PROPVARIANT_0, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union PROPVARIANT_0 { - pub Anonymous: PROPVARIANT_0_0, - pub decVal: DECIMAL, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct PROPVARIANT_0_0 { - pub vt: VARENUM, - pub wReserved1: u16, - pub wReserved2: u16, - pub wReserved3: u16, - pub Anonymous: PROPVARIANT_0_0_0, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union PROPVARIANT_0_0_0 { - pub cVal: i8, - pub bVal: u8, - pub iVal: i16, - pub uiVal: u16, - pub lVal: i32, - pub ulVal: u32, - pub intVal: i32, - pub uintVal: u32, - pub hVal: i64, - pub uhVal: u64, - pub fltVal: f32, - pub dblVal: f64, - pub boolVal: VARIANT_BOOL, - pub __OBSOLETE__VARIANT_BOOL: VARIANT_BOOL, - pub scode: i32, - pub cyVal: CY, - pub date: f64, - pub filetime: FILETIME, - pub puuid: *mut GUID, - pub pclipdata: *mut CLIPDATA, - pub bstrVal: BSTR, - pub bstrblobVal: BSTRBLOB, - pub blob: BLOB, - pub pszVal: PSTR, - pub pwszVal: PWSTR, - pub punkVal: *mut core::ffi::c_void, - pub pdispVal: *mut core::ffi::c_void, - pub pStream: *mut core::ffi::c_void, - pub pStorage: *mut core::ffi::c_void, - pub pVersionedStream: *mut VERSIONEDSTREAM, - pub parray: *mut SAFEARRAY, - pub cac: CAC, - pub caub: CAUB, - pub cai: CAI, - pub caui: CAUI, - pub cal: CAL, - pub caul: CAUL, - pub cah: CAH, - pub cauh: CAUH, - pub caflt: CAFLT, - pub cadbl: CADBL, - pub cabool: CABOOL, - pub cascode: CASCODE, - pub cacy: CACY, - pub cadate: CADATE, - pub cafiletime: CAFILETIME, - pub cauuid: CACLSID, - pub caclipdata: CACLIPDATA, - pub cabstr: CABSTR, - pub cabstrblob: CABSTRBLOB, - pub calpstr: CALPSTR, - pub calpwstr: CALPWSTR, - pub capropvar: CAPROPVARIANT, - pub pcVal: PSTR, - pub pbVal: *mut u8, - pub piVal: *mut i16, - pub puiVal: *mut u16, - pub plVal: *mut i32, - pub pulVal: *mut u32, - pub pintVal: *mut i32, - pub puintVal: *mut u32, - pub pfltVal: *mut f32, - pub pdblVal: *mut f64, - pub pboolVal: *mut VARIANT_BOOL, - pub pdecVal: *mut DECIMAL, - pub pscode: *mut i32, - pub pcyVal: *mut CY, - pub pdate: *mut f64, - pub pbstrVal: *mut BSTR, - pub ppunkVal: *mut *mut core::ffi::c_void, - pub ppdispVal: *mut *mut core::ffi::c_void, - pub pparray: *mut *mut SAFEARRAY, - pub pvarVal: *mut PROPVARIANT, -} -pub type PROPVAR_COMPARE_FLAGS = i32; -pub type PROPVAR_COMPARE_UNIT = i32; -pub type PSTR = *mut u8; -pub type PWSTR = *mut u16; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct SAFEARRAY { - pub cDims: u16, - pub fFeatures: ADVANCED_FEATURE_FLAGS, - pub cbElements: u32, - pub cLocks: u32, - pub pvData: *mut core::ffi::c_void, - pub rgsabound: [SAFEARRAYBOUND; 1], -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct SAFEARRAYBOUND { - pub cElements: u32, - pub lLbound: i32, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct SECURITY_ATTRIBUTES { - pub nLength: u32, - pub lpSecurityDescriptor: *mut core::ffi::c_void, - pub bInheritHandle: BOOL, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct STATSTG { - pub pwcsName: PWSTR, - pub r#type: u32, - pub cbSize: u64, - pub mtime: FILETIME, - pub ctime: FILETIME, - pub atime: FILETIME, - pub grfMode: STGM, - pub grfLocksSupported: u32, - pub clsid: GUID, - pub grfStateBits: u32, - pub reserved: u32, -} -pub type STGM = u32; -pub type STREAM_SEEK = u32; -pub type SYSKIND = i32; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct TLIBATTR { - pub guid: GUID, - pub lcid: u32, - pub syskind: SYSKIND, - pub wMajorVerNum: u16, - pub wMinorVerNum: u16, - pub wLibFlags: u16, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct TYPEATTR { - pub guid: GUID, - pub lcid: u32, - pub dwReserved: u32, - pub memidConstructor: i32, - pub memidDestructor: i32, - pub lpstrSchema: PWSTR, - pub cbSizeInstance: u32, - pub typekind: TYPEKIND, - pub cFuncs: u16, - pub cVars: u16, - pub cImplTypes: u16, - pub cbSizeVft: u16, - pub cbAlignment: u16, - pub wTypeFlags: u16, - pub wMajorVerNum: u16, - pub wMinorVerNum: u16, - pub tdescAlias: TYPEDESC, - pub idldescType: IDLDESC, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct TYPEDESC { - pub Anonymous: TYPEDESC_0, - pub vt: VARENUM, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union TYPEDESC_0 { - pub lptdesc: *mut TYPEDESC, - pub lpadesc: *mut ARRAYDESC, - pub hreftype: u32, -} -pub type TYPEKIND = i32; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct VARDESC { - pub memid: i32, - pub lpstrSchema: PWSTR, - pub Anonymous: VARDESC_0, - pub elemdescVar: ELEMDESC, - pub wVarFlags: VARFLAGS, - pub varkind: VARKIND, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union VARDESC_0 { - pub oInst: u32, - pub lpvarValue: *mut VARIANT, -} -pub type VARENUM = u16; -pub type VARFLAGS = u16; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct VARIANT { - pub Anonymous: VARIANT_0, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union VARIANT_0 { - pub Anonymous: VARIANT_0_0, - pub decVal: DECIMAL, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct VARIANT_0_0 { - pub vt: VARENUM, - pub wReserved1: u16, - pub wReserved2: u16, - pub wReserved3: u16, - pub Anonymous: VARIANT_0_0_0, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub union VARIANT_0_0_0 { - pub llVal: i64, - pub lVal: i32, - pub bVal: u8, - pub iVal: i16, - pub fltVal: f32, - pub dblVal: f64, - pub boolVal: VARIANT_BOOL, - pub __OBSOLETE__VARIANT_BOOL: VARIANT_BOOL, - pub scode: i32, - pub cyVal: CY, - pub date: f64, - pub bstrVal: BSTR, - pub punkVal: *mut core::ffi::c_void, - pub pdispVal: *mut core::ffi::c_void, - pub parray: *mut SAFEARRAY, - pub pbVal: *mut u8, - pub piVal: *mut i16, - pub plVal: *mut i32, - pub pllVal: *mut i64, - pub pfltVal: *mut f32, - pub pdblVal: *mut f64, - pub pboolVal: *mut VARIANT_BOOL, - pub __OBSOLETE__VARIANT_PBOOL: *mut VARIANT_BOOL, - pub pscode: *mut i32, - pub pcyVal: *mut CY, - pub pdate: *mut f64, - pub pbstrVal: *mut BSTR, - pub ppunkVal: *mut *mut core::ffi::c_void, - pub ppdispVal: *mut *mut core::ffi::c_void, - pub pparray: *mut *mut SAFEARRAY, - pub pvarVal: *mut VARIANT, - pub byref: *mut core::ffi::c_void, - pub cVal: i8, - pub uiVal: u16, - pub ulVal: u32, - pub ullVal: u64, - pub intVal: i32, - pub uintVal: u32, - pub pdecVal: *mut DECIMAL, - pub pcVal: PSTR, - pub puiVal: *mut u16, - pub pulVal: *mut u32, - pub pullVal: *mut u64, - pub pintVal: *mut i32, - pub puintVal: *mut u32, - pub Anonymous: VARIANT_0_0_0_0, -} -#[repr(C)] -#[derive(Clone, Copy)] -pub struct VARIANT_0_0_0_0 { - pub pvRecord: *mut core::ffi::c_void, - pub pRecInfo: *mut core::ffi::c_void, -} -pub type VARIANT_BOOL = i16; -pub type VARKIND = i32; -#[repr(C)] -#[derive(Clone, Copy)] -pub struct VERSIONEDSTREAM { - pub guidVersion: GUID, - pub pStream: *mut core::ffi::c_void, -} -pub const VT_BOOL: VARENUM = 11u16; -pub const VT_BSTR: VARENUM = 8u16; -pub const VT_EMPTY: VARENUM = 0u16; -pub const VT_I1: VARENUM = 16u16; -pub const VT_I2: VARENUM = 2u16; -pub const VT_I4: VARENUM = 3u16; -pub const VT_I8: VARENUM = 20u16; -pub const VT_R4: VARENUM = 4u16; -pub const VT_R8: VARENUM = 5u16; -pub const VT_UI1: VARENUM = 17u16; -pub const VT_UI2: VARENUM = 18u16; -pub const VT_UI4: VARENUM = 19u16; -pub const VT_UI8: VARENUM = 21u16; -pub const VT_UNKNOWN: VARENUM = 13u16; -pub type WAIT_EVENT = u32; +pub type RPC_STATUS = i32; +pub const RPC_S_UUID_LOCAL_ONLY: RPC_STATUS = 1824i32; +pub type HSTRING = *mut core::ffi::c_void; diff --git a/third_party/rust/windows-core/src/imp/com_bindings.rs b/third_party/rust/windows-core/src/imp/com_bindings.rs @@ -1,77 +1,55 @@ -#![allow( - non_snake_case, - non_upper_case_globals, - non_camel_case_types, - dead_code, - clippy::all -)] #[inline] -pub unsafe fn CoCreateGuid() -> windows_core::Result<windows_core::GUID> { - windows_targets::link!("ole32.dll" "system" fn CoCreateGuid(pguid : *mut windows_core::GUID) -> windows_core::HRESULT); - let mut result__ = core::mem::zeroed(); - CoCreateGuid(&mut result__).map(|| result__) -} -#[inline] -pub unsafe fn RoGetAgileReference<P0>( +pub unsafe fn RoGetAgileReference<P2>( options: AgileReferenceOptions, riid: *const windows_core::GUID, - punk: P0, + punk: P2, ) -> windows_core::Result<IAgileReference> where - P0: windows_core::Param<windows_core::IUnknown>, + P2: windows_core::Param<windows_core::IUnknown>, { - windows_targets::link!("ole32.dll" "system" fn RoGetAgileReference(options : AgileReferenceOptions, riid : *const windows_core::GUID, punk : * mut core::ffi::c_void, ppagilereference : *mut * mut core::ffi::c_void) -> windows_core::HRESULT); - let mut result__ = core::mem::zeroed(); - RoGetAgileReference(options, riid, punk.param().abi(), &mut result__) - .and_then(|| windows_core::Type::from_abi(result__)) + windows_core::link!("combase.dll" "system" fn RoGetAgileReference(options : AgileReferenceOptions, riid : *const windows_core::GUID, punk : * mut core::ffi::c_void, ppagilereference : *mut * mut core::ffi::c_void) -> windows_core::HRESULT); + unsafe { + let mut result__ = core::mem::zeroed(); + RoGetAgileReference(options, riid, punk.param().abi(), &mut result__) + .and_then(|| windows_core::Type::from_abi(result__)) + } } pub const AGILEREFERENCE_DEFAULT: AgileReferenceOptions = AgileReferenceOptions(0i32); #[repr(transparent)] -#[derive(PartialEq, Eq, Copy, Clone, Default)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub struct AgileReferenceOptions(pub i32); -impl windows_core::TypeKind for AgileReferenceOptions { - type TypeKind = windows_core::CopyType; -} -impl core::fmt::Debug for AgileReferenceOptions { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.debug_tuple("AgileReferenceOptions") - .field(&self.0) - .finish() - } -} pub const CO_E_NOTINITIALIZED: windows_core::HRESULT = windows_core::HRESULT(0x800401F0_u32 as _); -pub const E_BOUNDS: windows_core::HRESULT = windows_core::HRESULT(0x8000000B_u32 as _); +pub const E_INVALIDARG: windows_core::HRESULT = windows_core::HRESULT(0x80070057_u32 as _); pub const E_NOINTERFACE: windows_core::HRESULT = windows_core::HRESULT(0x80004002_u32 as _); -pub const E_OUTOFMEMORY: windows_core::HRESULT = windows_core::HRESULT(0x8007000E_u32 as _); pub const E_POINTER: windows_core::HRESULT = windows_core::HRESULT(0x80004003_u32 as _); windows_core::imp::define_interface!( IAgileObject, IAgileObject_Vtbl, 0x94ea2b94_e9cc_49e0_c0ff_ee64ca8f5b90 ); -impl core::ops::Deref for IAgileObject { - type Target = windows_core::IUnknown; - fn deref(&self) -> &Self::Target { - unsafe { core::mem::transmute(self) } - } -} windows_core::imp::interface_hierarchy!(IAgileObject, windows_core::IUnknown); -impl IAgileObject {} #[repr(C)] +#[doc(hidden)] pub struct IAgileObject_Vtbl { pub base__: windows_core::IUnknown_Vtbl, } +pub trait IAgileObject_Impl: windows_core::IUnknownImpl {} +impl IAgileObject_Vtbl { + pub const fn new<Identity: IAgileObject_Impl, const OFFSET: isize>() -> Self { + Self { + base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAgileObject as windows_core::Interface>::IID + } +} +impl windows_core::RuntimeName for IAgileObject {} windows_core::imp::define_interface!( IAgileReference, IAgileReference_Vtbl, 0xc03f6a43_65a4_9818_987e_e0b810d2a6f2 ); -impl core::ops::Deref for IAgileReference { - type Target = windows_core::IUnknown; - fn deref(&self) -> &Self::Target { - unsafe { core::mem::transmute(self) } - } -} windows_core::imp::interface_hierarchy!(IAgileReference, windows_core::IUnknown); impl IAgileReference { pub unsafe fn Resolve<T>(&self) -> windows_core::Result<T> @@ -79,15 +57,18 @@ impl IAgileReference { T: windows_core::Interface, { let mut result__ = core::ptr::null_mut(); - (windows_core::Interface::vtable(self).Resolve)( - windows_core::Interface::as_raw(self), - &T::IID, - &mut result__, - ) - .and_then(|| windows_core::Type::from_abi(result__)) + unsafe { + (windows_core::Interface::vtable(self).Resolve)( + windows_core::Interface::as_raw(self), + &T::IID, + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } } } #[repr(C)] +#[doc(hidden)] pub struct IAgileReference_Vtbl { pub base__: windows_core::IUnknown_Vtbl, pub Resolve: unsafe extern "system" fn( @@ -96,17 +77,46 @@ pub struct IAgileReference_Vtbl { *mut *mut core::ffi::c_void, ) -> windows_core::HRESULT, } +pub trait IAgileReference_Impl: windows_core::IUnknownImpl { + fn Resolve( + &self, + riid: *const windows_core::GUID, + ppvobjectreference: *mut *mut core::ffi::c_void, + ) -> windows_core::Result<()>; +} +impl IAgileReference_Vtbl { + pub const fn new<Identity: IAgileReference_Impl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Resolve<Identity: IAgileReference_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + riid: *const windows_core::GUID, + ppvobjectreference: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAgileReference_Impl::Resolve( + this, + core::mem::transmute_copy(&riid), + core::mem::transmute_copy(&ppvobjectreference), + ) + .into() + } + } + Self { + base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), + Resolve: Resolve::<Identity, OFFSET>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAgileReference as windows_core::Interface>::IID + } +} +impl windows_core::RuntimeName for IAgileReference {} windows_core::imp::define_interface!( IWeakReference, IWeakReference_Vtbl, 0x00000037_0000_0000_c000_000000000046 ); -impl core::ops::Deref for IWeakReference { - type Target = windows_core::IUnknown; - fn deref(&self) -> &Self::Target { - unsafe { core::mem::transmute(self) } - } -} windows_core::imp::interface_hierarchy!(IWeakReference, windows_core::IUnknown); impl IWeakReference { pub unsafe fn Resolve<T>(&self) -> windows_core::Result<T> @@ -114,15 +124,18 @@ impl IWeakReference { T: windows_core::Interface, { let mut result__ = core::ptr::null_mut(); - (windows_core::Interface::vtable(self).Resolve)( - windows_core::Interface::as_raw(self), - &T::IID, - &mut result__, - ) - .and_then(|| windows_core::Type::from_abi(result__)) + unsafe { + (windows_core::Interface::vtable(self).Resolve)( + windows_core::Interface::as_raw(self), + &T::IID, + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } } } #[repr(C)] +#[doc(hidden)] pub struct IWeakReference_Vtbl { pub base__: windows_core::IUnknown_Vtbl, pub Resolve: unsafe extern "system" fn( @@ -131,29 +144,61 @@ pub struct IWeakReference_Vtbl { *mut *mut core::ffi::c_void, ) -> windows_core::HRESULT, } +pub trait IWeakReference_Impl: windows_core::IUnknownImpl { + fn Resolve( + &self, + riid: *const windows_core::GUID, + objectreference: *mut *mut core::ffi::c_void, + ) -> windows_core::Result<()>; +} +impl IWeakReference_Vtbl { + pub const fn new<Identity: IWeakReference_Impl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Resolve<Identity: IWeakReference_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + riid: *const windows_core::GUID, + objectreference: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IWeakReference_Impl::Resolve( + this, + core::mem::transmute_copy(&riid), + core::mem::transmute_copy(&objectreference), + ) + .into() + } + } + Self { + base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), + Resolve: Resolve::<Identity, OFFSET>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IWeakReference as windows_core::Interface>::IID + } +} +impl windows_core::RuntimeName for IWeakReference {} windows_core::imp::define_interface!( IWeakReferenceSource, IWeakReferenceSource_Vtbl, 0x00000038_0000_0000_c000_000000000046 ); -impl core::ops::Deref for IWeakReferenceSource { - type Target = windows_core::IUnknown; - fn deref(&self) -> &Self::Target { - unsafe { core::mem::transmute(self) } - } -} windows_core::imp::interface_hierarchy!(IWeakReferenceSource, windows_core::IUnknown); impl IWeakReferenceSource { pub unsafe fn GetWeakReference(&self) -> windows_core::Result<IWeakReference> { - let mut result__ = core::mem::zeroed(); - (windows_core::Interface::vtable(self).GetWeakReference)( - windows_core::Interface::as_raw(self), - &mut result__, - ) - .and_then(|| windows_core::Type::from_abi(result__)) + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(self).GetWeakReference)( + windows_core::Interface::as_raw(self), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } } } #[repr(C)] +#[doc(hidden)] pub struct IWeakReferenceSource_Vtbl { pub base__: windows_core::IUnknown_Vtbl, pub GetWeakReference: unsafe extern "system" fn( @@ -161,6 +206,41 @@ pub struct IWeakReferenceSource_Vtbl { *mut *mut core::ffi::c_void, ) -> windows_core::HRESULT, } +pub trait IWeakReferenceSource_Impl: windows_core::IUnknownImpl { + fn GetWeakReference(&self) -> windows_core::Result<IWeakReference>; +} +impl IWeakReferenceSource_Vtbl { + pub const fn new<Identity: IWeakReferenceSource_Impl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn GetWeakReference< + Identity: IWeakReferenceSource_Impl, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + weakreference: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IWeakReferenceSource_Impl::GetWeakReference(this) { + Ok(ok__) => { + weakreference.write(core::mem::transmute(ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), + GetWeakReference: GetWeakReference::<Identity, OFFSET>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IWeakReferenceSource as windows_core::Interface>::IID + } +} +impl windows_core::RuntimeName for IWeakReferenceSource {} pub const JSCRIPT_E_CANTEXECUTE: windows_core::HRESULT = windows_core::HRESULT(0x89020001_u32 as _); +pub const REGDB_E_CLASSNOTREG: windows_core::HRESULT = windows_core::HRESULT(0x80040154_u32 as _); pub const RPC_E_DISCONNECTED: windows_core::HRESULT = windows_core::HRESULT(0x80010108_u32 as _); -pub const TYPE_E_TYPEMISMATCH: windows_core::HRESULT = windows_core::HRESULT(0x80028CA0_u32 as _); +pub const S_OK: windows_core::HRESULT = windows_core::HRESULT(0x0_u32 as _); diff --git a/third_party/rust/windows-core/src/imp/factory_cache.rs b/third_party/rust/windows-core/src/imp/factory_cache.rs @@ -40,7 +40,7 @@ impl<C: crate::RuntimeName, I: Interface> FactoryCache<C, I> { } // Otherwise, we load the factory the usual way. - let factory = factory::<C, I>()?; + let factory = load_factory::<C, I>()?; // If the factory is agile, we can safely cache it. if factory.cast::<IAgileObject>().is_ok() { @@ -70,7 +70,7 @@ unsafe impl<C, I> Sync for FactoryCache<C, I> {} /// Attempts to load the factory object for the given WinRT class. /// This can be used to access COM interfaces implemented on a Windows Runtime class factory. -pub fn factory<C: crate::RuntimeName, I: Interface>() -> crate::Result<I> { +pub fn load_factory<C: crate::RuntimeName, I: Interface>() -> crate::Result<I> { let mut factory: Option<I> = None; let name = crate::HSTRING::from(C::NAME); @@ -102,18 +102,18 @@ pub fn factory<C: crate::RuntimeName, I: Interface>() -> crate::Result<I> { return Ok(factory); } - // If not, first capture the error information from the failure above so that we - // can ultimately return this error information if all else fails. - let original: crate::Error = code.into(); - - // Now attempt to find the factory's implementation heuristically. - if let Some(i) = search_path(C::NAME, |library| unsafe { - get_activation_factory(library, &name) - }) { - i.cast() - } else { - Err(original) + // Reg-free activation should only be attempted if the class is not registered. + // It should not be attempted if the class is registered but fails to activate. + if code == REGDB_E_CLASSNOTREG { + // Now attempt to find the factory's implementation heuristically. + if let Some(i) = search_path(C::NAME, |library| unsafe { + get_activation_factory(library, &name) + }) { + return i.cast(); + } } + + Err(crate::Error::from_hresult(code)) } // Remove the suffix until a match is found appending `.dll\0` at the end @@ -146,32 +146,36 @@ unsafe fn get_activation_factory( library: crate::PCSTR, name: &crate::HSTRING, ) -> crate::Result<IGenericFactory> { - let function = - delay_load::<DllGetActivationFactory>(library, crate::s!("DllGetActivationFactory")) - .ok_or_else(crate::Error::from_win32)?; - let mut abi = null_mut(); - function(transmute_copy(name), &mut abi).and_then(|| crate::Type::from_abi(abi)) + unsafe { + let function = + delay_load::<DllGetActivationFactory>(library, crate::s!("DllGetActivationFactory")) + .ok_or_else(crate::Error::from_thread)?; + let mut abi = null_mut(); + function(transmute_copy(name), &mut abi).and_then(|| crate::Type::from_abi(abi)) + } } unsafe fn delay_load<T>(library: crate::PCSTR, function: crate::PCSTR) -> Option<T> { - let library = LoadLibraryExA( - library.0, - core::ptr::null_mut(), - LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, - ); - - if library.is_null() { - return None; - } + unsafe { + let library = LoadLibraryExA( + library.0, + core::ptr::null_mut(), + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, + ); + + if library.is_null() { + return None; + } - let address = GetProcAddress(library, function.0); + let address = GetProcAddress(library, function.0); - if address.is_some() { - return Some(core::mem::transmute_copy(&address)); - } + if address.is_some() { + return Some(core::mem::transmute_copy(&address)); + } - FreeLibrary(library); - None + FreeLibrary(library); + None + } } type DllGetActivationFactory = diff --git a/third_party/rust/windows-core/src/imp/marshaler.rs b/third_party/rust/windows-core/src/imp/marshaler.rs @@ -0,0 +1,268 @@ +use super::*; +use crate::{IUnknown, IUnknown_Vtbl, Interface, GUID, HRESULT}; +use core::ffi::c_void; +use core::mem::{transmute, transmute_copy}; +use core::ptr::null_mut; + +windows_link::link!("combase.dll" "system" fn CoCreateFreeThreadedMarshaler(punkouter: *mut c_void, ppunkmarshal: *mut *mut c_void) -> HRESULT); + +pub unsafe fn marshaler(outer: IUnknown, result: *mut *mut c_void) -> HRESULT { + unsafe { + let mut marshaler_raw = null_mut(); + _ = CoCreateFreeThreadedMarshaler(null_mut(), &mut marshaler_raw); + assert!(!marshaler_raw.is_null(), "allocation failed"); + let marshaler: IUnknown = transmute(marshaler_raw); + + _ = (marshaler.vtable().QueryInterface)( + transmute_copy(&marshaler), + &IMarshal::IID, + &mut marshaler_raw, + ); + + debug_assert!(!marshaler_raw.is_null()); + let marshaler: IMarshal = transmute(marshaler_raw); + + let marshaler = Marshaler { + vtable: &Marshaler::VTABLE, + outer, + marshaler, + count: RefCount::new(1), + }; + + debug_assert!(!result.is_null()); + *result = transmute::<Box<_>, *mut c_void>(Box::new(marshaler)); + S_OK + } +} + +#[repr(C)] +struct Marshaler { + vtable: *const IMarshal_Vtbl, + outer: IUnknown, + marshaler: IMarshal, + count: RefCount, +} + +impl Marshaler { + const VTABLE: IMarshal_Vtbl = IMarshal_Vtbl { + base__: IUnknown_Vtbl { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + }, + GetUnmarshalClass: Self::GetUnmarshalClass, + GetMarshalSizeMax: Self::GetMarshalSizeMax, + MarshalInterface: Self::MarshalInterface, + UnmarshalInterface: Self::UnmarshalInterface, + ReleaseMarshalData: Self::ReleaseMarshalData, + DisconnectObject: Self::DisconnectObject, + }; + + unsafe extern "system" fn QueryInterface( + this: *mut c_void, + iid: *const GUID, + interface: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + if iid.is_null() || interface.is_null() { + return E_POINTER; + } + + if *iid == IMarshal::IID { + *interface = &mut (*this).vtable as *mut _ as _; + (*this).count.add_ref(); + return S_OK; + } + + ((*this).outer.vtable().QueryInterface)(transmute_copy(&(*this).outer), iid, interface) + } + } + + unsafe extern "system" fn AddRef(this: *mut c_void) -> u32 { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + (*this).count.add_ref() + } + } + + unsafe extern "system" fn Release(this: *mut c_void) -> u32 { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + let remaining = (*this).count.release(); + + if remaining == 0 { + let _ = Box::from_raw(this); + } + + remaining + } + } + + unsafe extern "system" fn GetUnmarshalClass( + this: *mut c_void, + riid: *const GUID, + pv: *const c_void, + dwdestcontext: u32, + pvdestcontext: *const c_void, + mshlflags: u32, + pcid: *mut GUID, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().GetUnmarshalClass)( + transmute_copy(&(*this).marshaler), + riid, + pv, + dwdestcontext, + pvdestcontext, + mshlflags, + pcid, + ) + } + } + + unsafe extern "system" fn GetMarshalSizeMax( + this: *mut c_void, + riid: *const GUID, + pv: *const c_void, + dwdestcontext: u32, + pvdestcontext: *const c_void, + mshlflags: u32, + psize: *mut u32, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().GetMarshalSizeMax)( + transmute_copy(&(*this).marshaler), + riid, + pv, + dwdestcontext, + pvdestcontext, + mshlflags, + psize, + ) + } + } + + unsafe extern "system" fn MarshalInterface( + this: *mut c_void, + pstm: *mut c_void, + riid: *const GUID, + pv: *const c_void, + dwdestcontext: u32, + pvdestcontext: *const c_void, + mshlflags: u32, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().MarshalInterface)( + transmute_copy(&(*this).marshaler), + pstm, + riid, + pv, + dwdestcontext, + pvdestcontext, + mshlflags, + ) + } + } + + unsafe extern "system" fn UnmarshalInterface( + this: *mut c_void, + pstm: *mut c_void, + riid: *const GUID, + ppv: *mut *mut c_void, + ) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().UnmarshalInterface)( + transmute_copy(&(*this).marshaler), + pstm, + riid, + ppv, + ) + } + } + + unsafe extern "system" fn ReleaseMarshalData(this: *mut c_void, pstm: *mut c_void) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().ReleaseMarshalData)( + transmute_copy(&(*this).marshaler), + pstm, + ) + } + } + + unsafe extern "system" fn DisconnectObject(this: *mut c_void, dwreserved: u32) -> HRESULT { + unsafe { + let this = this as *mut *mut c_void as *mut Self; + + ((*this).marshaler.vtable().DisconnectObject)( + transmute_copy(&(*this).marshaler), + dwreserved, + ) + } + } +} + +#[repr(transparent)] +#[derive(Clone)] +pub struct IMarshal(IUnknown); + +unsafe impl Interface for IMarshal { + type Vtable = IMarshal_Vtbl; + const IID: GUID = GUID::from_u128(0x00000003_0000_0000_c000_000000000046); +} + +#[repr(C)] +pub struct IMarshal_Vtbl { + base__: IUnknown_Vtbl, + + GetUnmarshalClass: unsafe extern "system" fn( + *mut c_void, + *const GUID, + *const c_void, + u32, + *const c_void, + u32, + *mut GUID, + ) -> HRESULT, + + GetMarshalSizeMax: unsafe extern "system" fn( + *mut c_void, + *const GUID, + *const c_void, + u32, + *const c_void, + u32, + *mut u32, + ) -> HRESULT, + + MarshalInterface: unsafe extern "system" fn( + *mut c_void, + *mut c_void, + *const GUID, + *const c_void, + u32, + *const c_void, + u32, + ) -> HRESULT, + + UnmarshalInterface: unsafe extern "system" fn( + *mut c_void, + *mut c_void, + *const GUID, + *mut *mut c_void, + ) -> HRESULT, + + ReleaseMarshalData: unsafe extern "system" fn(*mut c_void, *mut c_void) -> HRESULT, + DisconnectObject: unsafe extern "system" fn(*mut c_void, u32) -> HRESULT, +} diff --git a/third_party/rust/windows-core/src/imp/mod.rs b/third_party/rust/windows-core/src/imp/mod.rs @@ -1,12 +1,14 @@ #[cfg(windows)] include!("windows.rs"); +mod bindings; mod can_into; mod com_bindings; mod ref_count; mod sha1; mod weak_ref_count; +pub(crate) use bindings::*; pub use can_into::*; pub use com_bindings::*; pub use ref_count::*; @@ -65,7 +67,7 @@ macro_rules! define_interface { const IID: ::windows_core::GUID = ::windows_core::GUID::from_u128($iid); } impl ::core::fmt::Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> core::fmt::Result { f.debug_tuple(stringify!($name)) .field(&::windows_core::Interface::as_raw(self)) .finish() @@ -75,14 +77,14 @@ macro_rules! define_interface { ($name:ident, $vtbl:ident) => { #[repr(transparent)] #[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone)] - pub struct $name(::std::ptr::NonNull<::std::ffi::c_void>); + pub struct $name(::core::ptr::NonNull<::core::ffi::c_void>); unsafe impl ::windows_core::Interface for $name { type Vtable = $vtbl; const IID: ::windows_core::GUID = ::windows_core::GUID::zeroed(); const UNKNOWN: bool = false; } impl ::core::fmt::Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> core::fmt::Result { f.debug_tuple(stringify!($name)).field(&self.0).finish() } } diff --git a/third_party/rust/windows-core/src/imp/ref_count.rs b/third_party/rust/windows-core/src/imp/ref_count.rs @@ -6,7 +6,7 @@ pub struct RefCount(pub(crate) AtomicI32); impl RefCount { /// Creates a new `RefCount` with an initial value of `1`. - pub fn new(count: u32) -> Self { + pub const fn new(count: u32) -> Self { Self(AtomicI32::new(count as i32)) } diff --git a/third_party/rust/windows-core/src/imp/sha1.rs b/third_party/rust/windows-core/src/imp/sha1.rs @@ -1,5 +1,3 @@ -#![allow(clippy::many_single_char_names)] - pub const fn sha1(data: &ConstBuffer) -> Digest { let state: [u32; 5] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; let len: u64 = 0; @@ -18,6 +16,12 @@ pub struct ConstBuffer { head: usize, } +impl Default for ConstBuffer { + fn default() -> Self { + Self::new() + } +} + impl ConstBuffer { pub const fn for_class<C: crate::RuntimeName, I: crate::RuntimeType>() -> Self { Self::new() @@ -112,11 +116,11 @@ impl ConstBuffer { .push(b'-') .push_hex_u16(guid.data3) .push(b'-') - .push_hex_u16((guid.data4[0] as u16) << 8 | guid.data4[1] as u16) + .push_hex_u16(((guid.data4[0] as u16) << 8) | guid.data4[1] as u16) .push(b'-') - .push_hex_u16((guid.data4[2] as u16) << 8 | guid.data4[3] as u16) - .push_hex_u16((guid.data4[4] as u16) << 8 | guid.data4[5] as u16) - .push_hex_u16((guid.data4[6] as u16) << 8 | guid.data4[7] as u16) + .push_hex_u16(((guid.data4[2] as u16) << 8) | guid.data4[3] as u16) + .push_hex_u16(((guid.data4[4] as u16) << 8) | guid.data4[5] as u16) + .push_hex_u16(((guid.data4[6] as u16) << 8) | guid.data4[7] as u16) .push(b'}') } } @@ -474,9 +478,9 @@ impl Digest { } impl core::fmt::Display for Digest { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { for i in self.data.iter() { - write!(f, "{:08x}", i)?; + write!(f, "{i:08x}")?; } Ok(()) } diff --git a/third_party/rust/windows-core/src/imp/waiter.rs b/third_party/rust/windows-core/src/imp/waiter.rs @@ -1,40 +0,0 @@ -use super::*; - -pub struct Waiter(HANDLE); -pub struct WaiterSignaler(HANDLE); - -unsafe impl Send for WaiterSignaler {} - -impl Waiter { - pub fn new() -> crate::Result<(Waiter, WaiterSignaler)> { - unsafe { - let handle = CreateEventW(core::ptr::null(), 1, 0, core::ptr::null()); - if handle.is_null() { - Err(crate::Error::from_win32()) - } else { - Ok((Waiter(handle), WaiterSignaler(handle))) - } - } - } -} - -impl WaiterSignaler { - /// # Safety - /// Signals the `Waiter`. This is unsafe because the lifetime of `WaiterSignaler` is not tied - /// to the lifetime of the `Waiter`. This is not possible in this case because the `Waiter` - /// is used to signal a WinRT async completion and the compiler doesn't know that the lifetime - /// of the delegate is bounded by the calling function. - pub unsafe fn signal(&self) { - // https://github.com/microsoft/windows-rs/pull/374#discussion_r535313344 - SetEvent(self.0); - } -} - -impl Drop for Waiter { - fn drop(&mut self) { - unsafe { - WaitForSingleObject(self.0, 0xFFFFFFFF); - CloseHandle(self.0); - } - } -} diff --git a/third_party/rust/windows-core/src/imp/weak_ref_count.rs b/third_party/rust/windows-core/src/imp/weak_ref_count.rs @@ -1,5 +1,5 @@ use super::*; -use crate::Interface; +use crate::{IUnknown, IUnknown_Vtbl, Interface, GUID, HRESULT}; use core::ffi::c_void; use core::mem::{transmute, transmute_copy}; use core::ptr::null_mut; @@ -10,7 +10,7 @@ use core::sync::atomic::{AtomicIsize, Ordering}; pub struct WeakRefCount(AtomicIsize); impl WeakRefCount { - pub fn new() -> Self { + pub const fn new() -> Self { Self(AtomicIsize::new(1)) } @@ -49,44 +49,46 @@ impl WeakRefCount { } /// # Safety - pub unsafe fn query(&self, iid: &crate::GUID, object: *mut c_void) -> *mut c_void { - if iid != &IWeakReferenceSource::IID { - return null_mut(); - } - - let mut count_or_pointer = self.0.load(Ordering::Relaxed); - - if is_weak_ref(count_or_pointer) { - return TearOff::from_encoding(count_or_pointer); - } - - let tear_off = TearOff::new(object, count_or_pointer as u32); - let tear_off_ptr: *mut c_void = transmute_copy(&tear_off); - let encoding: usize = ((tear_off_ptr as usize) >> 1) | (1 << (usize::BITS - 1)); - - loop { - match self.0.compare_exchange_weak( - count_or_pointer, - encoding as isize, - Ordering::AcqRel, - Ordering::Relaxed, - ) { - Ok(_) => { - let result: *mut c_void = transmute(tear_off); - TearOff::from_strong_ptr(result).strong_count.add_ref(); - return result; - } - Err(pointer) => count_or_pointer = pointer, + pub unsafe fn query(&self, iid: &GUID, object: *mut c_void) -> *mut c_void { + unsafe { + if iid != &IWeakReferenceSource::IID { + return null_mut(); } + let mut count_or_pointer = self.0.load(Ordering::Relaxed); + if is_weak_ref(count_or_pointer) { return TearOff::from_encoding(count_or_pointer); } - TearOff::from_strong_ptr(tear_off_ptr) - .strong_count - .0 - .store(count_or_pointer as i32, Ordering::SeqCst); + let tear_off = TearOff::new(object, count_or_pointer as u32); + let tear_off_ptr: *mut c_void = transmute_copy(&tear_off); + let encoding: usize = ((tear_off_ptr as usize) >> 1) | (1 << (usize::BITS - 1)); + + loop { + match self.0.compare_exchange_weak( + count_or_pointer, + encoding as isize, + Ordering::AcqRel, + Ordering::Relaxed, + ) { + Ok(_) => { + let result: *mut c_void = transmute(tear_off); + TearOff::from_strong_ptr(result).strong_count.add_ref(); + return result; + } + Err(pointer) => count_or_pointer = pointer, + } + + if is_weak_ref(count_or_pointer) { + return TearOff::from_encoding(count_or_pointer); + } + + TearOff::from_strong_ptr(tear_off_ptr) + .strong_count + .0 + .store(count_or_pointer as i32, Ordering::SeqCst); + } } } } @@ -105,25 +107,29 @@ struct TearOff { } impl TearOff { - #[allow(clippy::new_ret_no_self)] + #[expect(clippy::new_ret_no_self)] unsafe fn new(object: *mut c_void, strong_count: u32) -> IWeakReferenceSource { - transmute(Box::new(TearOff { - strong_vtable: &Self::STRONG_VTABLE, - weak_vtable: &Self::WEAK_VTABLE, - object, - strong_count: RefCount::new(strong_count), - weak_count: RefCount::new(1), - })) + unsafe { + transmute(Box::new(Self { + strong_vtable: &Self::STRONG_VTABLE, + weak_vtable: &Self::WEAK_VTABLE, + object, + strong_count: RefCount::new(strong_count), + weak_count: RefCount::new(1), + })) + } } unsafe fn from_encoding(encoding: isize) -> *mut c_void { - let tear_off = TearOff::decode(encoding); - tear_off.strong_count.add_ref(); - tear_off as *mut _ as *mut _ + unsafe { + let tear_off = Self::decode(encoding); + tear_off.strong_count.add_ref(); + tear_off as *mut _ as *mut _ + } } const STRONG_VTABLE: IWeakReferenceSource_Vtbl = IWeakReferenceSource_Vtbl { - base__: crate::IUnknown_Vtbl { + base__: IUnknown_Vtbl { QueryInterface: Self::StrongQueryInterface, AddRef: Self::StrongAddRef, Release: Self::StrongRelease, @@ -132,7 +138,7 @@ impl TearOff { }; const WEAK_VTABLE: IWeakReference_Vtbl = IWeakReference_Vtbl { - base__: crate::IUnknown_Vtbl { + base__: IUnknown_Vtbl { QueryInterface: Self::WeakQueryInterface, AddRef: Self::WeakAddRef, Release: Self::WeakRelease, @@ -141,163 +147,181 @@ impl TearOff { }; unsafe fn from_strong_ptr<'a>(this: *mut c_void) -> &'a mut Self { - &mut *(this as *mut *mut c_void as *mut Self) + unsafe { &mut *(this as *mut *mut c_void as *mut Self) } } unsafe fn from_weak_ptr<'a>(this: *mut c_void) -> &'a mut Self { - &mut *((this as *mut *mut c_void).sub(1) as *mut Self) + unsafe { &mut *((this as *mut *mut c_void).sub(1) as *mut Self) } } unsafe fn decode<'a>(value: isize) -> &'a mut Self { - transmute(value << 1) + unsafe { &mut *((value << 1) as *mut Self) as &mut Self } } - unsafe fn query_interface( - &self, - iid: *const crate::GUID, - interface: *mut *mut c_void, - ) -> crate::HRESULT { - ((*(*(self.object as *mut *mut crate::IUnknown_Vtbl))).QueryInterface)( - self.object, - iid, - interface, - ) + unsafe fn query_interface(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT { + unsafe { + ((*(*(self.object as *mut *mut IUnknown_Vtbl))).QueryInterface)( + self.object, + iid, + interface, + ) + } } unsafe extern "system" fn StrongQueryInterface( ptr: *mut c_void, - iid: *const crate::GUID, + iid: *const GUID, interface: *mut *mut c_void, - ) -> crate::HRESULT { - let this = Self::from_strong_ptr(ptr); + ) -> HRESULT { + unsafe { + let this = Self::from_strong_ptr(ptr); - if iid.is_null() || interface.is_null() { - return E_POINTER; - } + if iid.is_null() || interface.is_null() { + return E_POINTER; + } - // Only directly respond to queries for the the tear-off's strong interface. This is - // effectively a self-query. - if *iid == IWeakReferenceSource::IID { - *interface = ptr; - this.strong_count.add_ref(); - return crate::HRESULT(0); - } + // Only directly respond to queries for the the tear-off's strong interface. This is + // effectively a self-query. + if *iid == IWeakReferenceSource::IID { + *interface = ptr; + this.strong_count.add_ref(); + return HRESULT(0); + } - // As the tear-off is sharing the identity of the object, simply delegate any remaining - // queries to the object. - this.query_interface(iid, interface) + // As the tear-off is sharing the identity of the object, simply delegate any remaining + // queries to the object. + this.query_interface(iid, interface) + } } unsafe extern "system" fn WeakQueryInterface( ptr: *mut c_void, - iid: *const crate::GUID, + iid: *const GUID, interface: *mut *mut c_void, - ) -> crate::HRESULT { - let this = Self::from_weak_ptr(ptr); - - if iid.is_null() || interface.is_null() { - return E_POINTER; - } + ) -> HRESULT { + unsafe { + let this = Self::from_weak_ptr(ptr); - // While the weak vtable is packed into the same allocation as the strong vtable and - // tear-off, it represents a distinct COM identity and thus does not share or delegate to - // the object. + if iid.is_null() || interface.is_null() { + return E_POINTER; + } - *interface = if *iid == IWeakReference::IID - || *iid == crate::IUnknown::IID - || *iid == IAgileObject::IID - { - ptr - } else { - null_mut() - }; + // While the weak vtable is packed into the same allocation as the strong vtable and + // tear-off, it represents a distinct COM identity and thus does not share or delegate to + // the object. + + *interface = if *iid == IWeakReference::IID + || *iid == IUnknown::IID + || *iid == IAgileObject::IID + { + ptr + } else { + #[cfg(windows)] + if *iid == IMarshal::IID { + this.weak_count.add_ref(); + return marshaler(transmute::<*mut c_void, IUnknown>(ptr), interface); + } - // TODO: implement IMarshal + null_mut() + }; - if (*interface).is_null() { - E_NOINTERFACE - } else { - this.weak_count.add_ref(); - crate::HRESULT(0) + if (*interface).is_null() { + E_NOINTERFACE + } else { + this.weak_count.add_ref(); + HRESULT(0) + } } } unsafe extern "system" fn StrongAddRef(ptr: *mut c_void) -> u32 { - let this = Self::from_strong_ptr(ptr); + unsafe { + let this = Self::from_strong_ptr(ptr); - // Implement `AddRef` directly as we own the strong reference. - this.strong_count.add_ref() + // Implement `AddRef` directly as we own the strong reference. + this.strong_count.add_ref() + } } unsafe extern "system" fn WeakAddRef(ptr: *mut c_void) -> u32 { - let this = Self::from_weak_ptr(ptr); + unsafe { + let this = Self::from_weak_ptr(ptr); - // Implement `AddRef` directly as we own the weak reference. - this.weak_count.add_ref() + // Implement `AddRef` directly as we own the weak reference. + this.weak_count.add_ref() + } } unsafe extern "system" fn StrongRelease(ptr: *mut c_void) -> u32 { - let this = Self::from_strong_ptr(ptr); + unsafe { + let this = Self::from_strong_ptr(ptr); - // Forward strong `Release` to the object so that it can destroy itself. It will then - // decrement its weak reference and allow the tear-off to be released as needed. - ((*(*(this.object as *mut *mut crate::IUnknown_Vtbl))).Release)(this.object) + // Forward strong `Release` to the object so that it can destroy itself. It will then + // decrement its weak reference and allow the tear-off to be released as needed. + ((*(*(this.object as *mut *mut IUnknown_Vtbl))).Release)(this.object) + } } unsafe extern "system" fn WeakRelease(ptr: *mut c_void) -> u32 { - let this = Self::from_weak_ptr(ptr); + unsafe { + let this = Self::from_weak_ptr(ptr); - // Implement `Release` directly as we own the weak reference. - let remaining = this.weak_count.release(); + // Implement `Release` directly as we own the weak reference. + let remaining = this.weak_count.release(); - // If there are no remaining references, it means that the object has already been - // destroyed. Go ahead and destroy the tear-off. - if remaining == 0 { - let _ = Box::from_raw(this); - } + // If there are no remaining references, it means that the object has already been + // destroyed. Go ahead and destroy the tear-off. + if remaining == 0 { + let _ = Box::from_raw(this); + } - remaining + remaining + } } unsafe extern "system" fn StrongDowngrade( ptr: *mut c_void, interface: *mut *mut c_void, - ) -> crate::HRESULT { - let this = Self::from_strong_ptr(ptr); - - // The strong vtable hands out a reference to the weak vtable. This is always safe and - // straightforward since a strong reference guarantees there is at least one weak - // reference. - *interface = &mut this.weak_vtable as *mut _ as _; - this.weak_count.add_ref(); - crate::HRESULT(0) + ) -> HRESULT { + unsafe { + let this = Self::from_strong_ptr(ptr); + + // The strong vtable hands out a reference to the weak vtable. This is always safe and + // straightforward since a strong reference guarantees there is at least one weak + // reference. + *interface = &mut this.weak_vtable as *mut _ as _; + this.weak_count.add_ref(); + HRESULT(0) + } } unsafe extern "system" fn WeakUpgrade( ptr: *mut c_void, - iid: *const crate::GUID, + iid: *const GUID, interface: *mut *mut c_void, - ) -> crate::HRESULT { - let this = Self::from_weak_ptr(ptr); - - this.strong_count - .0 - .fetch_update(Ordering::Acquire, Ordering::Relaxed, |count| { - // Attempt to acquire a strong reference count to stabilize the object for the duration - // of the `QueryInterface` call. - bool::then_some(count != 0, count + 1) - }) - .map(|_| { - // Let the object respond to the upgrade query. - let result = this.query_interface(iid, interface); - // Decrement the temporary reference account used to stabilize the object. - this.strong_count.0.fetch_sub(1, Ordering::Relaxed); - // Return the result of the query. - result - }) - .unwrap_or_else(|_| { - *interface = null_mut(); - crate::HRESULT(0) - }) + ) -> HRESULT { + unsafe { + let this = Self::from_weak_ptr(ptr); + + this.strong_count + .0 + .fetch_update(Ordering::Acquire, Ordering::Relaxed, |count| { + // Attempt to acquire a strong reference count to stabilize the object for the duration + // of the `QueryInterface` call. + bool::then_some(count != 0, count + 1) + }) + .map(|_| { + // Let the object respond to the upgrade query. + let result = this.query_interface(iid, interface); + // Decrement the temporary reference account used to stabilize the object. + this.strong_count.0.fetch_sub(1, Ordering::Relaxed); + // Return the result of the query. + result + }) + .unwrap_or_else(|_| { + *interface = null_mut(); + HRESULT(0) + }) + } } } diff --git a/third_party/rust/windows-core/src/imp/windows.rs b/third_party/rust/windows-core/src/imp/windows.rs @@ -4,8 +4,8 @@ pub use factory_cache::*; mod generic_factory; pub use generic_factory::*; -mod waiter; -pub use waiter::*; +mod marshaler; +pub use marshaler::*; -mod bindings; -pub use bindings::*; +mod array_proxy; +pub use array_proxy::*; diff --git a/third_party/rust/windows-core/src/inspectable.rs b/third_party/rust/windows-core/src/inspectable.rs @@ -2,6 +2,8 @@ use super::*; use core::ffi::c_void; use core::ptr::null_mut; +/// Parent interface for all WinRT interfaces. +/// /// A WinRT object that may be used as a polymorphic stand-in for any WinRT class, interface, or boxed value. /// [`IInspectable`] represents the /// [IInspectable](https://docs.microsoft.com/en-us/windows/win32/api/inspectable/nn-inspectable-iinspectable) @@ -65,45 +67,51 @@ impl IInspectable_Vtbl { count: *mut u32, values: *mut *mut GUID, ) -> HRESULT { - if count.is_null() || values.is_null() { - return imp::E_POINTER; + unsafe { + if count.is_null() || values.is_null() { + return imp::E_POINTER; + } + // Note: even if we end up implementing this in future, it still doesn't need a this pointer + // since the data to be returned is type- not instance-specific so can be shared for all + // interfaces. + *count = 0; + *values = null_mut(); + HRESULT(0) } - // Note: even if we end up implementing this in future, it still doesn't need a this pointer - // since the data to be returned is type- not instance-specific so can be shared for all - // interfaces. - *count = 0; - *values = null_mut(); - HRESULT(0) } unsafe extern "system" fn GetRuntimeClassName<T: RuntimeName>( _: *mut c_void, value: *mut *mut c_void, ) -> HRESULT { - if value.is_null() { - return imp::E_POINTER; - } + unsafe { + if value.is_null() { + return imp::E_POINTER; + } - #[cfg(windows)] - { - *value = core::mem::transmute::<HSTRING, *mut c_void>(T::NAME.into()); - } + #[cfg(windows)] + { + *value = core::mem::transmute::<HSTRING, *mut c_void>(T::NAME.into()); + } - #[cfg(not(windows))] - { - *value = core::ptr::null_mut(); - } + #[cfg(not(windows))] + { + *value = core::ptr::null_mut(); + } - HRESULT(0) + HRESULT(0) + } } unsafe extern "system" fn GetTrustLevel<T: IUnknownImpl, const OFFSET: isize>( this: *mut c_void, value: *mut i32, ) -> HRESULT { - if value.is_null() { - return imp::E_POINTER; + unsafe { + if value.is_null() { + return imp::E_POINTER; + } + let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; + (*this).GetTrustLevel(value) } - let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; - (*this).GetTrustLevel(value) } Self { base: IUnknown_Vtbl::new::<Identity, OFFSET>(), diff --git a/third_party/rust/windows-core/src/interface.rs b/third_party/rust/windows-core/src/interface.rs @@ -38,7 +38,7 @@ pub unsafe trait Interface: Sized + Clone { #[doc(hidden)] #[inline(always)] unsafe fn assume_vtable<T: Interface>(&self) -> &T::Vtable { - &**(self.as_raw() as *mut *mut T::Vtable) + unsafe { &**(self.as_raw() as *mut *mut T::Vtable) } } /// Returns the raw COM interface pointer. The resulting pointer continues to be owned by the `Interface` implementation. @@ -64,7 +64,7 @@ pub unsafe trait Interface: Sized + Clone { /// The `raw` pointer must be owned by the caller and represent a valid COM interface pointer. In other words, /// it must point to a vtable beginning with the `IUnknown` function pointers and match the vtable of `Interface`. unsafe fn from_raw(raw: *mut c_void) -> Self { - transmute_copy(&raw) + unsafe { transmute_copy(&raw) } } /// Creates an `Interface` that is valid so long as the `raw` COM interface pointer is valid. @@ -75,10 +75,12 @@ pub unsafe trait Interface: Sized + Clone { /// beginning with the `IUnknown` function pointers and match the vtable of `Interface`. #[inline(always)] unsafe fn from_raw_borrowed(raw: &*mut c_void) -> Option<&Self> { - if raw.is_null() { - None - } else { - Some(transmute_copy(&raw)) + unsafe { + if raw.is_null() { + None + } else { + Some(transmute_copy(&raw)) + } } } @@ -235,7 +237,7 @@ pub unsafe trait Interface: Sized + Clone { /// Attempts to create a [`Weak`] reference to this object. fn downgrade(&self) -> Result<Weak<Self>> { self.cast::<imp::IWeakReferenceSource>() - .and_then(|source| Weak::downgrade(&source)) + .map(|source| Weak::downgrade(&source)) } /// Call `QueryInterface` on this interface @@ -245,10 +247,12 @@ pub unsafe trait Interface: Sized + Clone { /// `interface` must be a non-null, valid pointer for writing an interface pointer. #[inline(always)] unsafe fn query(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT { - if Self::UNKNOWN { - (self.assume_vtable::<IUnknown>().QueryInterface)(self.as_raw(), iid, interface) - } else { - panic!("Non-COM interfaces cannot be queried.") + unsafe { + if Self::UNKNOWN { + (self.assume_vtable::<IUnknown>().QueryInterface)(self.as_raw(), iid, interface) + } else { + panic!("Non-COM interfaces cannot be queried.") + } } } @@ -259,12 +263,6 @@ pub unsafe trait Interface: Sized + Clone { } } -/// # Safety -#[doc(hidden)] -pub unsafe fn from_raw_borrowed<T: Interface>(raw: &*mut c_void) -> Option<&T> { - T::from_raw_borrowed(raw) -} - /// This has the same memory representation as `IFoo`, but represents a borrowed interface pointer. /// /// This type has no `Drop` impl; it does not AddRef/Release the given interface. However, because @@ -272,21 +270,21 @@ pub unsafe fn from_raw_borrowed<T: Interface>(raw: &*mut c_void) -> Option<&T> { #[repr(transparent)] pub struct InterfaceRef<'a, I>(NonNull<c_void>, PhantomData<&'a I>); -impl<'a, I> Copy for InterfaceRef<'a, I> {} +impl<I> Copy for InterfaceRef<'_, I> {} -impl<'a, I> Clone for InterfaceRef<'a, I> { +impl<I> Clone for InterfaceRef<'_, I> { fn clone(&self) -> Self { *self } } -impl<'a, I: core::fmt::Debug + Interface> core::fmt::Debug for InterfaceRef<'a, I> { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { +impl<I: core::fmt::Debug + Interface> core::fmt::Debug for InterfaceRef<'_, I> { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { <I as core::fmt::Debug>::fmt(&**self, f) } } -impl<'a, I: Interface> InterfaceRef<'a, I> { +impl<I: Interface> InterfaceRef<'_, I> { /// Creates an `InterfaceRef` from a raw pointer. _This is extremely dangerous, since there /// is no lifetime tracking at all!_ /// @@ -320,12 +318,12 @@ impl<'a, I: Interface> InterfaceRef<'a, I> { impl<'a, 'i: 'a, I: Interface> From<&'i I> for InterfaceRef<'a, I> { #[inline(always)] - fn from(interface: &'a I) -> InterfaceRef<'a, I> { + fn from(interface: &'a I) -> Self { InterfaceRef::from_interface(interface) } } -impl<'a, I: Interface> core::ops::Deref for InterfaceRef<'a, I> { +impl<I: Interface> core::ops::Deref for InterfaceRef<'_, I> { type Target = I; #[inline(always)] diff --git a/third_party/rust/windows-core/src/lib.rs b/third_party/rust/windows-core/src/lib.rs @@ -1,14 +1,14 @@ -/*! -Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs> -*/ - +#![doc = include_str!("../readme.md")] #![doc(html_no_source)] -#![allow(non_snake_case)] -#![cfg_attr( - windows_debugger_visualizer, - debugger_visualizer(natvis_file = "../.natvis") -)] +#![debugger_visualizer(natvis_file = "../windows-core.natvis")] #![cfg_attr(all(not(feature = "std")), no_std)] +#![expect( + non_snake_case, + non_camel_case_types, + dead_code, + clippy::missing_transmute_annotations, + clippy::upper_case_acronyms +)] #[cfg(windows)] include!("windows.rs"); @@ -57,4 +57,5 @@ pub use unknown::*; pub use weak::*; pub use windows_implement::implement; pub use windows_interface::interface; +pub use windows_link::link; pub use windows_result::*; diff --git a/third_party/rust/windows-core/src/out_param.rs b/third_party/rust/windows-core/src/out_param.rs @@ -18,9 +18,11 @@ where T: TypeKind<TypeKind = CloneType> + Clone + Default, { unsafe fn borrow_mut(&self) -> OutRef<'_, T> { - let this: &mut T = transmute_copy(self); - take(this); - transmute_copy(self) + unsafe { + let this: &mut T = transmute_copy(self); + take(this); + transmute_copy(self) + } } } @@ -29,7 +31,7 @@ where T: TypeKind<TypeKind = CopyType> + Clone + Default, { unsafe fn borrow_mut(&self) -> OutRef<'_, T> { - transmute_copy(self) + unsafe { transmute_copy(self) } } } @@ -38,9 +40,11 @@ where T: TypeKind<TypeKind = InterfaceType> + Clone, { unsafe fn borrow_mut(&self) -> OutRef<'_, T> { - let this: &mut Option<T> = transmute_copy(self); - take(this); - transmute_copy(self) + unsafe { + let this: &mut Option<T> = transmute_copy(self); + take(this); + transmute_copy(self) + } } } @@ -49,9 +53,11 @@ where T: Type<T>, { unsafe fn borrow_mut(&self) -> OutRef<'_, T> { - match self { - Some(this) => transmute_copy(this), - None => zeroed(), + unsafe { + match self { + Some(this) => transmute_copy(this), + None => zeroed(), + } } } } diff --git a/third_party/rust/windows-core/src/out_ref.rs b/third_party/rust/windows-core/src/out_ref.rs @@ -6,7 +6,7 @@ use super::*; #[repr(transparent)] pub struct OutRef<'a, T: Type<T>>(*mut T::Abi, core::marker::PhantomData<&'a T>); -impl<'a, T: Type<T>> OutRef<'a, T> { +impl<T: Type<T>> OutRef<'_, T> { /// Returns `true` if the argument is null. pub fn is_null(&self) -> bool { self.0.is_null() @@ -23,3 +23,15 @@ impl<'a, T: Type<T>> OutRef<'a, T> { } } } + +impl<'a, T: Type<T>> From<&'a mut T::Default> for OutRef<'a, T> { + fn from(from: &'a mut T::Default) -> Self { + unsafe { core::mem::transmute(from) } + } +} + +impl<T: Type<T>> Default for OutRef<'_, T> { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} diff --git a/third_party/rust/windows-core/src/param.rs b/third_party/rust/windows-core/src/param.rs @@ -18,10 +18,21 @@ where T: Type<T>, { unsafe fn param(self) -> ParamValue<T> { - ParamValue::Borrowed(match self { - Some(item) => transmute_copy(item), - None => zeroed(), - }) + unsafe { + ParamValue::Borrowed(match self { + Some(item) => transmute_copy(item), + None => zeroed(), + }) + } + } +} + +impl<T> Param<T> for InterfaceRef<'_, T> +where + T: Type<T>, +{ + unsafe fn param(self) -> ParamValue<T> { + unsafe { ParamValue::Borrowed(transmute_copy(&self)) } } } @@ -33,11 +44,13 @@ where U: imp::CanInto<T>, { unsafe fn param(self) -> ParamValue<T> { - if U::QUERY { - self.cast() - .map_or(ParamValue::Borrowed(zeroed()), |ok| ParamValue::Owned(ok)) - } else { - ParamValue::Borrowed(transmute_copy(self)) + unsafe { + if U::QUERY { + self.cast() + .map_or(ParamValue::Borrowed(zeroed()), |ok| ParamValue::Owned(ok)) + } else { + ParamValue::Borrowed(transmute_copy(self)) + } } } } @@ -47,7 +60,7 @@ where T: TypeKind<TypeKind = CloneType> + Clone, { unsafe fn param(self) -> ParamValue<T> { - ParamValue::Borrowed(transmute_copy(self)) + unsafe { ParamValue::Borrowed(transmute_copy(self)) } } } @@ -58,6 +71,6 @@ where U: imp::CanInto<T>, { unsafe fn param(self) -> ParamValue<T> { - ParamValue::Owned(transmute_copy(&self)) + unsafe { ParamValue::Owned(transmute_copy(&self)) } } } diff --git a/third_party/rust/windows-core/src/ref.rs b/third_party/rust/windows-core/src/ref.rs @@ -1,26 +1,88 @@ use super::*; -use core::ffi::c_void; -use core::marker::PhantomData; use core::mem::transmute; /// A borrowed type with the same memory layout as the type itself that can be used to construct ABI-compatible function signatures. #[repr(transparent)] -pub struct Ref<'a, T: Type<T>>(T::Abi, PhantomData<&'a T>); +pub struct Ref<'a, T: Type<T>>(T::Abi, core::marker::PhantomData<&'a T>); -impl<'a, T: Type<T, Default = Option<T>, Abi = *mut c_void>> Ref<'a, T> { - /// Converts the argument to a [Result<&T>] reference. +impl<T: Type<T>> Ref<'_, T> { + /// Returns `true` if the argument is null. + pub fn is_null(&self) -> bool { + T::is_null(&self.0) + } + + /// Converts the argument to a [`Result<&T>`] reference. pub fn ok(&self) -> Result<&T> { - if self.0.is_null() { - Err(Error::from_hresult(imp::E_POINTER)) + self.as_ref() + .ok_or_else(|| Error::from_hresult(imp::E_POINTER)) + } + + /// Converts the argument to a [`Option<&T>`] reference. + pub fn as_ref(&self) -> Option<&T> { + if self.is_null() { + None } else { - unsafe { Ok(transmute::<&*mut c_void, &T>(&self.0)) } + unsafe { Some(self.assume_init_ref()) } } } + + /// Converts the argument to a `&T` reference. + /// + /// # Panics + /// + /// Panics if the argument is null. + #[track_caller] + pub fn unwrap(&self) -> &T { + self.as_ref().expect("called `Ref::unwrap` on a null value") + } + + /// Converts the argument to an [`Option<T>`] by cloning the reference. + pub fn cloned(&self) -> Option<T> { + self.as_ref().cloned() + } + + unsafe fn assume_init_ref(&self) -> &T { + unsafe { T::assume_init_ref(&self.0) } + } +} + +impl<T: Type<T>> Default for Ref<'_, T> { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } } -impl<'a, T: Type<T>> core::ops::Deref for Ref<'a, T> { +impl<T: Type<T>> core::ops::Deref for Ref<'_, T> { type Target = T::Default; fn deref(&self) -> &Self::Target { unsafe { transmute(&self.0) } } } + +impl<'a, T: Type<T, InterfaceType>> From<&'a Option<T>> for Ref<'a, T> +where + T: TypeKind<TypeKind = InterfaceType>, +{ + fn from(from: &'a Option<T>) -> Self { + unsafe { core::mem::transmute_copy(from) } + } +} + +impl<'a, T: Type<T, InterfaceType>> From<Option<&'a T>> for Ref<'a, T> +where + T: TypeKind<TypeKind = InterfaceType>, +{ + fn from(from: Option<&'a T>) -> Self { + if let Some(from) = from { + unsafe { core::mem::transmute_copy(from) } + } else { + unsafe { core::mem::zeroed() } + } + } +} + +impl<'a, T: Type<T>> From<&'a T> for Ref<'a, T> { + fn from(from: &'a T) -> Self { + unsafe { core::mem::transmute_copy(from) } + } +} diff --git a/third_party/rust/windows-core/src/scoped_interface.rs b/third_party/rust/windows-core/src/scoped_interface.rs @@ -15,7 +15,7 @@ pub struct ScopedInterface<'a, T: Interface> { lifetime: PhantomData<&'a T>, } -impl<'a, T: Interface> ScopedInterface<'a, T> { +impl<T: Interface> ScopedInterface<'_, T> { pub fn new(interface: T) -> Self { Self { interface, @@ -24,7 +24,7 @@ impl<'a, T: Interface> ScopedInterface<'a, T> { } } -impl<'a, T: Interface> core::ops::Deref for ScopedInterface<'a, T> { +impl<T: Interface> core::ops::Deref for ScopedInterface<'_, T> { type Target = T; fn deref(&self) -> &T { @@ -32,7 +32,7 @@ impl<'a, T: Interface> core::ops::Deref for ScopedInterface<'a, T> { } } -impl<'a, T: Interface> Drop for ScopedInterface<'a, T> { +impl<T: Interface> Drop for ScopedInterface<'_, T> { fn drop(&mut self) { unsafe { let _ = Box::from_raw(self.interface.as_raw() as *const _ as *mut ScopedHeap); diff --git a/third_party/rust/windows-core/src/type.rs b/third_party/rust/windows-core/src/type.rs @@ -19,7 +19,8 @@ pub trait Type<T: TypeKind, C = <T as TypeKind>::TypeKind>: TypeKind + Sized + C type Abi; type Default; - /// # Safety + fn is_null(abi: &Self::Abi) -> bool; + unsafe fn assume_init_ref(abi: &Self::Abi) -> &Self; unsafe fn from_abi(abi: Self::Abi) -> Result<Self>; fn from_default(default: &Self::Default) -> Result<Self>; } @@ -31,11 +32,21 @@ where type Abi = *mut core::ffi::c_void; type Default = Option<Self>; + fn is_null(abi: &Self::Abi) -> bool { + abi.is_null() + } + + unsafe fn assume_init_ref(abi: &Self::Abi) -> &Self { + unsafe { core::mem::transmute::<&*mut core::ffi::c_void, &T>(abi) } + } + unsafe fn from_abi(abi: Self::Abi) -> Result<Self> { - if !abi.is_null() { - Ok(core::mem::transmute_copy(&abi)) - } else { - Err(Error::empty()) + unsafe { + if !abi.is_null() { + Ok(core::mem::transmute_copy(&abi)) + } else { + Err(Error::empty()) + } } } @@ -51,8 +62,16 @@ where type Abi = core::mem::MaybeUninit<Self>; type Default = Self; + fn is_null(_: &Self::Abi) -> bool { + false + } + + unsafe fn assume_init_ref(abi: &Self::Abi) -> &Self { + unsafe { abi.assume_init_ref() } + } + unsafe fn from_abi(abi: Self::Abi) -> Result<Self> { - Ok(abi.assume_init()) + unsafe { Ok(abi.assume_init()) } } fn from_default(default: &Self::Default) -> Result<Self> { @@ -67,6 +86,14 @@ where type Abi = Self; type Default = Self; + fn is_null(_: &Self::Abi) -> bool { + false + } + + unsafe fn assume_init_ref(abi: &Self::Abi) -> &Self { + abi + } + unsafe fn from_abi(abi: Self::Abi) -> Result<Self> { Ok(abi) } diff --git a/third_party/rust/windows-core/src/unknown.rs b/third_party/rust/windows-core/src/unknown.rs @@ -2,6 +2,8 @@ use super::*; use core::ffi::c_void; use core::ptr::NonNull; +/// Base interface for all COM interfaces. +/// /// All COM interfaces (and thus WinRT classes and interfaces) implement /// [IUnknown](https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown) /// under the hood to provide reference-counted lifetime management as well as the ability @@ -11,7 +13,6 @@ pub struct IUnknown(NonNull<c_void>); #[doc(hidden)] #[repr(C)] -#[allow(non_camel_case_types)] pub struct IUnknown_Vtbl { pub QueryInterface: unsafe extern "system" fn( this: *mut c_void, @@ -56,15 +57,15 @@ impl PartialEq for IUnknown { // be determined by querying for `IUnknown` explicitly and then comparing the // pointer values. This works since `QueryInterface` is required to return // the same pointer value for queries for `IUnknown`. - self.as_raw() == other.as_raw() - || self.cast::<IUnknown>().unwrap().0 == other.cast::<IUnknown>().unwrap().0 + core::ptr::eq(self.as_raw(), other.as_raw()) + || self.cast::<Self>().unwrap().0 == other.cast::<Self>().unwrap().0 } } impl Eq for IUnknown {} impl core::fmt::Debug for IUnknown { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.debug_tuple("IUnknown").field(&self.as_raw()).finish() } } @@ -115,16 +116,6 @@ pub trait IUnknownImpl { /// Gets the trust level of the current object. unsafe fn GetTrustLevel(&self, value: *mut i32) -> HRESULT; - /// Given a reference to an inner type, returns a reference to the outer shared type. - /// - /// # Safety - /// - /// This function should only be called from methods that implement COM interfaces, i.e. - /// implementations of methods on `IFoo_Impl` traits. - // TODO: This can be made safe, if IFoo_Impl are moved to the Object_Impl types. - // That requires some substantial redesign, though. - unsafe fn from_inner_ref(inner: &Self::Impl) -> &Self; - /// Gets a borrowed reference to an interface that is implemented by this ComObject. /// /// The returned reference does not have an additional reference count. @@ -156,10 +147,6 @@ pub trait IUnknownImpl { fn to_object(&self) -> ComObject<Self::Impl> where Self::Impl: ComObjectInner<Outer = Self>; - - /// The distance from the start of `<Foo>_Impl` to the `this` field within it, measured in - /// pointer-sized elements. The `this` field contains the `MyApp` instance. - const INNER_OFFSET_IN_POINTERS: usize; } impl IUnknown_Vtbl { @@ -169,20 +156,26 @@ impl IUnknown_Vtbl { iid: *const GUID, interface: *mut *mut c_void, ) -> HRESULT { - let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; - (*this).QueryInterface(iid, interface) + unsafe { + let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; + (*this).QueryInterface(iid, interface) + } } unsafe extern "system" fn AddRef<T: IUnknownImpl, const OFFSET: isize>( this: *mut c_void, ) -> u32 { - let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; - (*this).AddRef() + unsafe { + let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; + (*this).AddRef() + } } unsafe extern "system" fn Release<T: IUnknownImpl, const OFFSET: isize>( this: *mut c_void, ) -> u32 { - let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; - T::Release(this) + unsafe { + let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T; + T::Release(this) + } } Self { QueryInterface: QueryInterface::<T, OFFSET>, diff --git a/third_party/rust/windows-core/src/variant.rs b/third_party/rust/windows-core/src/variant.rs @@ -1,852 +0,0 @@ -use super::*; -use core::mem::transmute; - -/// A VARIANT ([VARIANT](https://learn.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant)) is a container that can store different types of values. -#[repr(transparent)] -pub struct VARIANT(imp::VARIANT); - -/// A PROPVARIANT ([PROPVARIANT](https://learn.microsoft.com/en-us/windows/win32/api/propidlbase/ns-propidlbase-propvariant)) is a container that can store different types of values. -#[repr(transparent)] -pub struct PROPVARIANT(imp::PROPVARIANT); - -impl Default for VARIANT { - fn default() -> Self { - Self::new() - } -} - -impl Default for PROPVARIANT { - fn default() -> Self { - Self::new() - } -} - -impl Clone for VARIANT { - fn clone(&self) -> Self { - unsafe { - let mut value = Self::new(); - imp::VariantCopy(&mut value.0, &self.0); - value - } - } -} - -impl Clone for PROPVARIANT { - fn clone(&self) -> Self { - unsafe { - let mut value = Self::new(); - imp::PropVariantCopy(&mut value.0, &self.0); - value - } - } -} - -impl Drop for VARIANT { - fn drop(&mut self) { - unsafe { imp::VariantClear(&mut self.0) }; - } -} - -impl Drop for PROPVARIANT { - fn drop(&mut self) { - unsafe { imp::PropVariantClear(&mut self.0) }; - } -} - -impl TypeKind for VARIANT { - type TypeKind = CloneType; -} - -impl TypeKind for PROPVARIANT { - type TypeKind = CloneType; -} - -impl core::fmt::Debug for VARIANT { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut debug = f.debug_struct("VARIANT"); - debug.field("type", &unsafe { self.0.Anonymous.Anonymous.vt }); - - if let Ok(value) = BSTR::try_from(self) { - debug.field("value", &value); - } - - debug.finish() - } -} - -impl core::fmt::Debug for PROPVARIANT { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - let mut debug = f.debug_struct("PROPVARIANT"); - debug.field("type", &unsafe { self.0.Anonymous.Anonymous.vt }); - - if let Ok(value) = BSTR::try_from(self) { - debug.field("value", &value); - } - - debug.finish() - } -} - -impl core::fmt::Display for VARIANT { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::write!(f, "{}", BSTR::try_from(self).unwrap_or_default()) - } -} - -impl core::fmt::Display for PROPVARIANT { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::write!(f, "{}", BSTR::try_from(self).unwrap_or_default()) - } -} - -impl PartialEq for VARIANT { - fn eq(&self, other: &Self) -> bool { - unsafe { - if self.0.Anonymous.Anonymous.vt != other.0.Anonymous.Anonymous.vt { - return false; - } - let this = PROPVARIANT::try_from(self); - let other = PROPVARIANT::try_from(other); - - if let (Ok(this), Ok(other)) = (this, other) { - this.eq(&other) - } else { - false - } - } - } -} - -impl PartialEq for PROPVARIANT { - fn eq(&self, other: &Self) -> bool { - unsafe { - if self.0.Anonymous.Anonymous.vt != other.0.Anonymous.Anonymous.vt { - return false; - } - - imp::PropVariantCompareEx(&self.0, &other.0, 0, 0) == 0 - } - } -} - -impl Eq for VARIANT {} -impl Eq for PROPVARIANT {} - -impl VARIANT { - /// Create an empty `VARIANT`. - /// - /// This function does not allocate memory. - pub fn new() -> Self { - unsafe { core::mem::zeroed() } - } - - /// Returns true if the `VARIANT` is empty. - pub const fn is_empty(&self) -> bool { - unsafe { self.0.Anonymous.Anonymous.vt == imp::VT_EMPTY } - } - - /// Creates a `VARIANT` by taking ownership of the raw data. - /// - /// # Safety - /// - /// The raw data must be owned by the caller and represent a valid `VARIANT` data structure. - pub unsafe fn from_raw(raw: imp::VARIANT) -> Self { - Self(raw) - } - - /// Returns the underlying raw data for the `VARIANT`. - pub fn as_raw(&self) -> &imp::VARIANT { - &self.0 - } -} - -impl PROPVARIANT { - /// Create an empty `PROPVARIANT`. - /// - /// This function does not allocate memory. - pub fn new() -> Self { - unsafe { core::mem::zeroed() } - } - - /// Returns true if the `PROPVARIANT` is empty. - pub const fn is_empty(&self) -> bool { - unsafe { self.0.Anonymous.Anonymous.vt == imp::VT_EMPTY } - } - - /// Creates a `PROPVARIANT` by taking ownership of the raw data. - /// - /// # Safety - /// - /// The raw data must be owned by the caller and represent a valid `PROPVARIANT` data structure. - pub unsafe fn from_raw(raw: imp::PROPVARIANT) -> Self { - Self(raw) - } - - /// Returns the underlying raw data for the `PROPVARIANT`. - pub fn as_raw(&self) -> &imp::PROPVARIANT { - &self.0 - } -} - -impl TryFrom<&VARIANT> for PROPVARIANT { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - unsafe { - let mut value = Self::new(); - HRESULT(imp::VariantToPropVariant(&from.0, &mut value.0)).map(|| value) - } - } -} - -impl TryFrom<&PROPVARIANT> for VARIANT { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - unsafe { - let mut value = Self::new(); - HRESULT(imp::PropVariantToVariant(&from.0, &mut value.0)).map(|| value) - } - } -} - -// VT_UNKNOWN - -impl From<IUnknown> for VARIANT { - fn from(value: IUnknown) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_UNKNOWN, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { - punkVal: value.into_raw(), - }, - }, - }, - }) - } -} - -impl From<IUnknown> for PROPVARIANT { - fn from(value: IUnknown) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_UNKNOWN, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { - punkVal: value.into_raw(), - }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for IUnknown { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - unsafe { - if from.0.Anonymous.Anonymous.vt == imp::VT_UNKNOWN - && !from.0.Anonymous.Anonymous.Anonymous.punkVal.is_null() - { - let unknown: &IUnknown = transmute(&from.0.Anonymous.Anonymous.Anonymous.punkVal); - Ok(unknown.clone()) - } else { - Err(Error::from_hresult(imp::TYPE_E_TYPEMISMATCH)) - } - } - } -} - -impl TryFrom<&PROPVARIANT> for IUnknown { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - unsafe { - if from.0.Anonymous.Anonymous.vt == imp::VT_UNKNOWN - && !from.0.Anonymous.Anonymous.Anonymous.punkVal.is_null() - { - let unknown: &IUnknown = transmute(&from.0.Anonymous.Anonymous.Anonymous.punkVal); - Ok(unknown.clone()) - } else { - Err(Error::from_hresult(imp::TYPE_E_TYPEMISMATCH)) - } - } - } -} - -// VT_BSTR - -impl From<BSTR> for VARIANT { - fn from(value: BSTR) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_BSTR, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { - bstrVal: value.into_raw(), - }, - }, - }, - }) - } -} - -impl From<BSTR> for PROPVARIANT { - fn from(value: BSTR) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_BSTR, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { - bstrVal: value.into_raw(), - }, - }, - }, - }) - } -} - -impl From<&str> for VARIANT { - fn from(value: &str) -> Self { - BSTR::from(value).into() - } -} - -impl From<&str> for PROPVARIANT { - fn from(value: &str) -> Self { - BSTR::from(value).into() - } -} - -impl TryFrom<&VARIANT> for BSTR { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let pv = PROPVARIANT::try_from(from)?; - BSTR::try_from(&pv) - } -} - -impl TryFrom<&PROPVARIANT> for BSTR { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = Self::new(); - HRESULT(unsafe { imp::PropVariantToBSTR(&from.0, &mut value as *mut _ as *mut _) }) - .map(|| value) - } -} - -// VT_BOOL - -impl From<bool> for VARIANT { - fn from(value: bool) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_BOOL, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { - boolVal: if value { -1 } else { 0 }, - }, - }, - }, - }) - } -} - -impl From<bool> for PROPVARIANT { - fn from(value: bool) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_BOOL, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { - boolVal: if value { -1 } else { 0 }, - }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for bool { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::VariantToBoolean(&from.0, &mut value) }).map(|| value != 0) - } -} - -impl TryFrom<&PROPVARIANT> for bool { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::PropVariantToBoolean(&from.0, &mut value) }).map(|| value != 0) - } -} - -// VT_UI1 - -impl From<u8> for VARIANT { - fn from(value: u8) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_UI1, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { bVal: value }, - }, - }, - }) - } -} - -impl From<u8> for PROPVARIANT { - fn from(value: u8) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_UI1, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { bVal: value }, - }, - }, - }) - } -} - -// VT_I1 - -impl From<i8> for VARIANT { - fn from(value: i8) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_I1, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { cVal: value }, - }, - }, - }) - } -} - -impl From<i8> for PROPVARIANT { - fn from(value: i8) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_I1, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { cVal: value }, - }, - }, - }) - } -} - -// VT_UI2 - -impl From<u16> for VARIANT { - fn from(value: u16) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_UI2, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { uiVal: value }, - }, - }, - }) - } -} - -impl From<u16> for PROPVARIANT { - fn from(value: u16) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_UI2, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { uiVal: value }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for u16 { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::VariantToUInt16(&from.0, &mut value) }).map(|| value) - } -} - -impl TryFrom<&PROPVARIANT> for u16 { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::PropVariantToUInt16(&from.0, &mut value) }).map(|| value) - } -} - -// VT_I2 - -impl From<i16> for VARIANT { - fn from(value: i16) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_I2, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { iVal: value }, - }, - }, - }) - } -} - -impl From<i16> for PROPVARIANT { - fn from(value: i16) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_I2, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { iVal: value }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for i16 { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::VariantToInt16(&from.0, &mut value) }).map(|| value) - } -} - -impl TryFrom<&PROPVARIANT> for i16 { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::PropVariantToInt16(&from.0, &mut value) }).map(|| value) - } -} - -// VT_UI4 - -impl From<u32> for VARIANT { - fn from(value: u32) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_UI4, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { ulVal: value }, - }, - }, - }) - } -} - -impl From<u32> for PROPVARIANT { - fn from(value: u32) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_UI4, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { ulVal: value }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for u32 { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::VariantToUInt32(&from.0, &mut value) }).map(|| value) - } -} - -impl TryFrom<&PROPVARIANT> for u32 { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::PropVariantToUInt32(&from.0, &mut value) }).map(|| value) - } -} - -// VT_I4 - -impl From<i32> for VARIANT { - fn from(value: i32) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_I4, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { lVal: value }, - }, - }, - }) - } -} - -impl From<i32> for PROPVARIANT { - fn from(value: i32) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_I4, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { lVal: value }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for i32 { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::VariantToInt32(&from.0, &mut value) }).map(|| value) - } -} - -impl TryFrom<&PROPVARIANT> for i32 { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::PropVariantToInt32(&from.0, &mut value) }).map(|| value) - } -} - -// VT_UI8 - -impl From<u64> for VARIANT { - fn from(value: u64) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_UI8, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { ullVal: value }, - }, - }, - }) - } -} - -impl From<u64> for PROPVARIANT { - fn from(value: u64) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_UI8, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { uhVal: value }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for u64 { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::VariantToUInt64(&from.0, &mut value) }).map(|| value) - } -} - -impl TryFrom<&PROPVARIANT> for u64 { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::PropVariantToUInt64(&from.0, &mut value) }).map(|| value) - } -} - -// VT_I8 - -impl From<i64> for VARIANT { - fn from(value: i64) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_I8, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { llVal: value }, - }, - }, - }) - } -} - -impl From<i64> for PROPVARIANT { - fn from(value: i64) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_I8, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { hVal: value }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for i64 { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::VariantToInt64(&from.0, &mut value) }).map(|| value) - } -} - -impl TryFrom<&PROPVARIANT> for i64 { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = 0; - HRESULT(unsafe { imp::PropVariantToInt64(&from.0, &mut value) }).map(|| value) - } -} - -// VT_R4 - -impl From<f32> for VARIANT { - fn from(value: f32) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_R4, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { fltVal: value }, - }, - }, - }) - } -} - -impl From<f32> for PROPVARIANT { - fn from(value: f32) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_R4, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { fltVal: value }, - }, - }, - }) - } -} - -// VT_R8 - -impl From<f64> for VARIANT { - fn from(value: f64) -> Self { - Self(imp::VARIANT { - Anonymous: imp::VARIANT_0 { - Anonymous: imp::VARIANT_0_0 { - vt: imp::VT_R8, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::VARIANT_0_0_0 { dblVal: value }, - }, - }, - }) - } -} - -impl From<f64> for PROPVARIANT { - fn from(value: f64) -> Self { - Self(imp::PROPVARIANT { - Anonymous: imp::PROPVARIANT_0 { - Anonymous: imp::PROPVARIANT_0_0 { - vt: imp::VT_R8, - wReserved1: 0, - wReserved2: 0, - wReserved3: 0, - Anonymous: imp::PROPVARIANT_0_0_0 { dblVal: value }, - }, - }, - }) - } -} - -impl TryFrom<&VARIANT> for f64 { - type Error = Error; - fn try_from(from: &VARIANT) -> Result<Self> { - let mut value = 0.0; - HRESULT(unsafe { imp::VariantToDouble(&from.0, &mut value) }).map(|| value) - } -} - -impl TryFrom<&PROPVARIANT> for f64 { - type Error = Error; - fn try_from(from: &PROPVARIANT) -> Result<Self> { - let mut value = 0.0; - HRESULT(unsafe { imp::PropVariantToDouble(&from.0, &mut value) }).map(|| value) - } -} diff --git a/third_party/rust/windows-core/src/weak.rs b/third_party/rust/windows-core/src/weak.rs @@ -7,7 +7,7 @@ pub struct Weak<I: Interface>(Option<imp::IWeakReference>, PhantomData<I>); impl<I: Interface> Weak<I> { /// Creates a new `Weak` object without any backing object. - pub fn new() -> Self { + pub const fn new() -> Self { Self(None, PhantomData) } @@ -18,9 +18,9 @@ impl<I: Interface> Weak<I> { .and_then(|inner| unsafe { inner.Resolve().ok() }) } - pub(crate) fn downgrade(source: &imp::IWeakReferenceSource) -> Result<Self> { + pub(crate) fn downgrade(source: &imp::IWeakReferenceSource) -> Self { let reference = unsafe { source.GetWeakReference().ok() }; - Ok(Self(reference, PhantomData)) + Self(reference, PhantomData) } } diff --git a/third_party/rust/windows-core/src/windows.rs b/third_party/rust/windows-core/src/windows.rs @@ -12,15 +12,12 @@ pub use event::*; mod handles; pub use handles::*; -mod variant; -pub use variant::*; - pub use windows_strings::*; /// Attempts to load the factory object for the given WinRT class. /// This can be used to access COM interfaces implemented on a Windows Runtime class factory. pub fn factory<C: RuntimeName, I: Interface>() -> Result<I> { - imp::factory::<C, I>() + imp::load_factory::<C, I>() } impl Param<PCWSTR> for &BSTR { diff --git a/third_party/rust/windows-core/windows-core.natvis b/third_party/rust/windows-core/windows-core.natvis @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> + <Type Name="windows_core::array::Array&lt;*&gt;"> + <DisplayString>{{ len={len} }}</DisplayString> + + <Expand> + <Item Name="[len]">len</Item> + <ArrayItems> + <Size>len</Size> + <ValuePointer>data</ValuePointer> + </ArrayItems> + </Expand> + </Type> + + <Type Name="windows_core::imp::ref_count::RefCount"> + <DisplayString>{__0}</DisplayString> + </Type> +</AutoVisualizer> diff --git a/third_party/rust/windows-future/.cargo-checksum.json b/third_party/rust/windows-future/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"f3f360a2fdf05becb156fa723a2ca60cb82909a014ae7f8aa2a54b7326d18517","Cargo.toml":"37154f2d71837fd02bec63bdb3fe417284bc5e860a8739ee9c80e5ff5ab37183","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"202125e536fd43ba3ffdb28d8590497941d44fe21950251239f73dfb889a147d","src/async.rs":"5fbd7afff0b11d687b5ea04d03b2edfedb6581aa81057e5d6fcaf85e15089817","src/async_ready.rs":"ff2941738b92cff025b2cedbe4250f2168a5e8b37ad955927b019ea72dae02ac","src/async_spawn.rs":"632b8fd0bc5157d76fa67cbc55f28084efb0d3d7634bddb9b05e4592c580eacb","src/bindings.rs":"b8f37efaf73f36ee4ad87dada1757cf790a522b7d04428d317603e8755cbba8e","src/bindings_impl.rs":"9b41306964d624dc57b631d378d8547d803c764d5ff29f8697eabed1ef53f588","src/future.rs":"738746eec764326019f07fa4eea2124c2aae32d99e43917e801b785c62793724","src/join.rs":"14139a6f0b0c9b25f0a2586190e3e0724b16dd17d300c14f6e835d0f84344767","src/lib.rs":"d986973fb214b5c652eb4ed53ff43e0b4d6e93ceaad202c720fbe148fd5ef8c4","src/waiter.rs":"bef63334d5b2ff9bfddf8a3b3d6f84cab5b703b1445d7f4f84d35311d41e7c06","src/when.rs":"295283aafb6acffe27fee8eba4700f6231bcfcd1ec742f950c8386ad275de2aa"},"package":"e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"} +\ No newline at end of file diff --git a/third_party/rust/windows-future/Cargo.lock b/third_party/rust/windows-future/Cargo.lock @@ -0,0 +1,115 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-future" +version = "0.3.2" +dependencies = [ + "windows-core", + "windows-link", + "windows-threading", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-threading" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37" +dependencies = [ + "windows-link", +] diff --git a/third_party/rust/windows-future/Cargo.toml b/third_party/rust/windows-future/Cargo.toml @@ -0,0 +1,59 @@ +# 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.82" +name = "windows-future" +version = "0.3.2" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Windows async types" +readme = "readme.md" +categories = ["os::windows-apis"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/microsoft/windows-rs" + +[package.metadata.docs.rs] +default-target = "x86_64-pc-windows-msvc" +targets = [] + +[features] +default = ["std"] +std = ["windows-core/std"] + +[lib] +name = "windows_future" +path = "src/lib.rs" + +[dependencies.windows-core] +version = "0.62.2" +default-features = false + +[dependencies.windows-link] +version = "0.2.1" +default-features = false + +[dependencies.windows-threading] +version = "0.2.1" +default-features = false + +[lints.rust] +missing_unsafe_on_extern = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-future/license-apache-2.0 b/third_party/rust/windows-future/license-apache-2.0 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) Microsoft Corporation. + + 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/windows-future/license-mit b/third_party/rust/windows-future/license-mit @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + 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/windows-future/readme.md b/third_party/rust/windows-future/readme.md @@ -0,0 +1,31 @@ +## Windows async types + +The [windows-future](https://crates.io/crates/windows-future) crate provides stock async support for Windows APIs. + +* [Getting started](https://kennykerr.ca/rust-getting-started/) +* [Samples](https://github.com/microsoft/windows-rs/tree/master/crates/samples) +* [Releases](https://github.com/microsoft/windows-rs/releases) + +Start by adding the following to your Cargo.toml file: + +```toml +[dependencies.windows-future] +version = "0.3" +``` + +Use the Windows async types as needed: + +```rust +use windows_future::*; + +// This result will be available immediately. +let ready = IAsyncOperation::ready(Ok(123)); +assert_eq!(ready.join().unwrap(), 123); + +let ready = IAsyncOperation::spawn(|| { + // Some lengthy operation goes here... + Ok(456) +}); + +assert_eq!(ready.join().unwrap(), 456); +``` diff --git a/third_party/rust/windows-future/src/async.rs b/third_party/rust/windows-future/src/async.rs @@ -0,0 +1,169 @@ +use super::*; + +// An `Async` represents a WinRT async execution object or type. There are precisely four such types: +// - IAsyncAction +// - IAsyncActionWithProgress +// - IAsyncOperation +// - IAsyncOperationWithProgress +// +// All four implementations are provided here and there is thus no need to implement this trait. +// This trait provides an abstraction over the relevant differences so that the various async +// capabilities in this crate can be reused for all implementations. +pub trait Async: Interface { + // The type of value produced on completion. + type Output: Clone; + + // The type of the delegate use for completion notification. + type CompletedHandler: Interface; + + // Sets the handler or callback to invoke when execution completes. This handler can only be set once. + fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()>; + + // Calls the given handler with the current object and status. + #[cfg(feature = "std")] + fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus); + + // Returns the value produced on completion. This should only be called when execution completes. + fn get_results(&self) -> Result<Self::Output>; + + // Gets the current status of async execution. This calls `QueryInterface` so should be used sparingly. + fn status(&self) -> Result<AsyncStatus>; + + // Waits for the async execution to finish and then returns the results. + fn join(&self) -> Result<Self::Output> { + if self.status()? == AsyncStatus::Started { + let (_waiter, signaler) = Waiter::new()?; + self.set_completed(move |_| { + // This is safe because the waiter will only be dropped after being signaled. + unsafe { + signaler.signal(); + } + })?; + } + self.get_results() + } + + // Calls `op(result)` when async execution completes. + fn when<F>(&self, op: F) -> Result<()> + where + F: FnOnce(Result<Self::Output>) + Send + 'static, + { + if self.status()? == AsyncStatus::Started { + // The `set_completed` closure is guaranteed to only be called once, like `FnOnce`, by the async pattern, + // but Rust doesn't know that so `RefCell` is used to pass `op` in to the closure. + let op = core::cell::RefCell::new(Some(op)); + self.set_completed(move |sender| { + if let Some(op) = op.take() { + op(sender.get_results()); + } + })?; + } else { + op(self.get_results()); + } + Ok(()) + } +} + +impl Async for IAsyncAction { + type Output = (); + type CompletedHandler = AsyncActionCompletedHandler; + + fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> { + self.SetCompleted(&AsyncActionCompletedHandler::new(move |sender, _| { + handler(sender.ok()?); + Ok(()) + })) + } + + #[cfg(feature = "std")] + fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) { + _ = handler.Invoke(self, status); + } + + fn get_results(&self) -> Result<Self::Output> { + self.GetResults() + } + + fn status(&self) -> Result<AsyncStatus> { + self.Status() + } +} + +impl<T: RuntimeType> Async for IAsyncOperation<T> { + type Output = T; + type CompletedHandler = AsyncOperationCompletedHandler<T>; + + fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> { + self.SetCompleted(&AsyncOperationCompletedHandler::new(move |sender, _| { + handler(sender.ok()?); + Ok(()) + })) + } + + #[cfg(feature = "std")] + fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) { + _ = handler.Invoke(self, status); + } + + fn get_results(&self) -> Result<Self::Output> { + self.GetResults() + } + + fn status(&self) -> Result<AsyncStatus> { + self.Status() + } +} + +impl<P: RuntimeType> Async for IAsyncActionWithProgress<P> { + type Output = (); + type CompletedHandler = AsyncActionWithProgressCompletedHandler<P>; + + fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> { + self.SetCompleted(&AsyncActionWithProgressCompletedHandler::new( + move |sender, _| { + handler(sender.ok()?); + Ok(()) + }, + )) + } + + #[cfg(feature = "std")] + fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) { + _ = handler.Invoke(self, status); + } + + fn get_results(&self) -> Result<Self::Output> { + self.GetResults() + } + + fn status(&self) -> Result<AsyncStatus> { + self.Status() + } +} + +impl<T: RuntimeType, P: RuntimeType> Async for IAsyncOperationWithProgress<T, P> { + type Output = T; + type CompletedHandler = AsyncOperationWithProgressCompletedHandler<T, P>; + + fn set_completed<F: Fn(&Self) + Send + 'static>(&self, handler: F) -> Result<()> { + self.SetCompleted(&AsyncOperationWithProgressCompletedHandler::new( + move |sender, _| { + handler(sender.ok()?); + Ok(()) + }, + )) + } + + #[cfg(feature = "std")] + fn invoke_completed(&self, handler: &Self::CompletedHandler, status: AsyncStatus) { + _ = handler.Invoke(self, status); + } + + fn get_results(&self) -> Result<Self::Output> { + self.GetResults() + } + + fn status(&self) -> Result<AsyncStatus> { + self.Status() + } +} diff --git a/third_party/rust/windows-future/src/async_ready.rs b/third_party/rust/windows-future/src/async_ready.rs @@ -0,0 +1,228 @@ +use super::*; +use std::sync::atomic::{AtomicBool, Ordering}; + +struct ReadyState<T: Async> { + set_completed: AtomicBool, + result: Result<T::Output>, +} + +impl<T: Async> ReadyState<T> { + fn new(result: Result<T::Output>) -> Self { + Self { + set_completed: AtomicBool::new(false), + result, + } + } + + fn status(&self) -> AsyncStatus { + if self.result.is_ok() { + AsyncStatus::Completed + } else { + AsyncStatus::Error + } + } + + // The "Ready" implementations don't need to store the handler since the handler is invoked immediately + // but still need to confirm that `SetCompleted` is called at most once. + fn invoke_completed(&self, sender: &T, handler: Ref<T::CompletedHandler>) -> Result<()> { + if !self.set_completed.swap(true, Ordering::SeqCst) { + sender.invoke_completed(handler.ok()?, self.status()); + Ok(()) + } else { + Err(Error::from_hresult(HRESULT(0x80000018u32 as i32))) // E_ILLEGAL_DELEGATE_ASSIGNMENT + } + } + + // The `From` implementation is not used here since we don't want to transfer any error object to the calling thread. + // That happens when `GetResults` is called. + fn error_code(&self) -> HRESULT { + match &self.result { + Ok(_) => HRESULT(0), + Err(error) => error.code(), + } + } +} + +#[implement(IAsyncAction, IAsyncInfo)] +struct ReadyAction(ReadyState<IAsyncAction>); + +#[implement(IAsyncOperation<T>, IAsyncInfo)] +struct ReadyOperation<T>(ReadyState<IAsyncOperation<T>>) +where + T: RuntimeType + 'static; + +#[implement(IAsyncActionWithProgress<P>, IAsyncInfo)] +struct ReadyActionWithProgress<P>(ReadyState<IAsyncActionWithProgress<P>>) +where + P: RuntimeType + 'static; + +#[implement(IAsyncOperationWithProgress<T, P>, IAsyncInfo)] +struct ReadyOperationWithProgress<T, P>(ReadyState<IAsyncOperationWithProgress<T, P>>) +where + T: RuntimeType + 'static, + P: RuntimeType + 'static; + +impl IAsyncInfo_Impl for ReadyAction_Impl { + fn Id(&self) -> Result<u32> { + Ok(1) + } + fn Status(&self) -> Result<AsyncStatus> { + Ok(self.0.status()) + } + fn ErrorCode(&self) -> Result<HRESULT> { + Ok(self.0.error_code()) + } + fn Cancel(&self) -> Result<()> { + Ok(()) + } + fn Close(&self) -> Result<()> { + Ok(()) + } +} + +impl<T: RuntimeType> IAsyncInfo_Impl for ReadyOperation_Impl<T> { + fn Id(&self) -> Result<u32> { + Ok(1) + } + fn Status(&self) -> Result<AsyncStatus> { + Ok(self.0.status()) + } + fn ErrorCode(&self) -> Result<HRESULT> { + Ok(self.0.error_code()) + } + fn Cancel(&self) -> Result<()> { + Ok(()) + } + fn Close(&self) -> Result<()> { + Ok(()) + } +} + +impl<P: RuntimeType> IAsyncInfo_Impl for ReadyActionWithProgress_Impl<P> { + fn Id(&self) -> Result<u32> { + Ok(1) + } + fn Status(&self) -> Result<AsyncStatus> { + Ok(self.0.status()) + } + fn ErrorCode(&self) -> Result<HRESULT> { + Ok(self.0.error_code()) + } + fn Cancel(&self) -> Result<()> { + Ok(()) + } + fn Close(&self) -> Result<()> { + Ok(()) + } +} + +impl<T: RuntimeType, P: RuntimeType> IAsyncInfo_Impl for ReadyOperationWithProgress_Impl<T, P> { + fn Id(&self) -> Result<u32> { + Ok(1) + } + fn Status(&self) -> Result<AsyncStatus> { + Ok(self.0.status()) + } + fn ErrorCode(&self) -> Result<HRESULT> { + Ok(self.0.error_code()) + } + fn Cancel(&self) -> Result<()> { + Ok(()) + } + fn Close(&self) -> Result<()> { + Ok(()) + } +} + +impl IAsyncAction_Impl for ReadyAction_Impl { + fn SetCompleted(&self, handler: Ref<AsyncActionCompletedHandler>) -> Result<()> { + self.0.invoke_completed(&self.as_interface(), handler) + } + fn Completed(&self) -> Result<AsyncActionCompletedHandler> { + Err(Error::empty()) + } + fn GetResults(&self) -> Result<()> { + self.0.result.clone() + } +} + +impl<T: RuntimeType> IAsyncOperation_Impl<T> for ReadyOperation_Impl<T> { + fn SetCompleted(&self, handler: Ref<AsyncOperationCompletedHandler<T>>) -> Result<()> { + self.0.invoke_completed(&self.as_interface(), handler) + } + fn Completed(&self) -> Result<AsyncOperationCompletedHandler<T>> { + Err(Error::empty()) + } + fn GetResults(&self) -> Result<T> { + self.0.result.clone() + } +} + +impl<P: RuntimeType> IAsyncActionWithProgress_Impl<P> for ReadyActionWithProgress_Impl<P> { + fn SetCompleted(&self, handler: Ref<AsyncActionWithProgressCompletedHandler<P>>) -> Result<()> { + self.0.invoke_completed(&self.as_interface(), handler) + } + fn Completed(&self) -> Result<AsyncActionWithProgressCompletedHandler<P>> { + Err(Error::empty()) + } + fn GetResults(&self) -> Result<()> { + self.0.result.clone() + } + fn SetProgress(&self, _: Ref<AsyncActionProgressHandler<P>>) -> Result<()> { + Ok(()) + } + fn Progress(&self) -> Result<AsyncActionProgressHandler<P>> { + Err(Error::empty()) + } +} + +impl<T: RuntimeType, P: RuntimeType> IAsyncOperationWithProgress_Impl<T, P> + for ReadyOperationWithProgress_Impl<T, P> +{ + fn SetCompleted( + &self, + handler: Ref<AsyncOperationWithProgressCompletedHandler<T, P>>, + ) -> Result<()> { + self.0.invoke_completed(&self.as_interface(), handler) + } + fn Completed(&self) -> Result<AsyncOperationWithProgressCompletedHandler<T, P>> { + Err(Error::empty()) + } + fn GetResults(&self) -> Result<T> { + self.0.result.clone() + } + fn SetProgress(&self, _: Ref<AsyncOperationProgressHandler<T, P>>) -> Result<()> { + Ok(()) + } + fn Progress(&self) -> Result<AsyncOperationProgressHandler<T, P>> { + Err(Error::empty()) + } +} + +impl IAsyncAction { + /// Creates an `IAsyncAction` that is immediately ready with a value. + pub fn ready(result: Result<()>) -> Self { + ReadyAction(ReadyState::new(result)).into() + } +} + +impl<T: RuntimeType> IAsyncOperation<T> { + /// Creates an `IAsyncOperation<T>` that is immediately ready with a value. + pub fn ready(result: Result<T>) -> Self { + ReadyOperation(ReadyState::new(result)).into() + } +} + +impl<P: RuntimeType> IAsyncActionWithProgress<P> { + /// Creates an `IAsyncActionWithProgress<P>` that is immediately ready with a value. + pub fn ready(result: Result<()>) -> Self { + ReadyActionWithProgress(ReadyState::new(result)).into() + } +} + +impl<T: RuntimeType, P: RuntimeType> IAsyncOperationWithProgress<T, P> { + /// Creates an `IAsyncOperationWithProgress<T, P>` that is immediately ready with a value. + pub fn ready(result: Result<T>) -> Self { + ReadyOperationWithProgress(ReadyState::new(result)).into() + } +} diff --git a/third_party/rust/windows-future/src/async_spawn.rs b/third_party/rust/windows-future/src/async_spawn.rs @@ -0,0 +1,321 @@ +use super::*; +use std::sync::Mutex; + +struct State<T: Async> { + result: Option<Result<T::Output>>, + completed: Option<T::CompletedHandler>, + completed_assigned: bool, +} + +impl<T: Async> State<T> { + fn status(&self) -> AsyncStatus { + match &self.result { + None => AsyncStatus::Started, + Some(Ok(_)) => AsyncStatus::Completed, + Some(Err(_)) => AsyncStatus::Error, + } + } + + fn error_code(&self) -> HRESULT { + match &self.result { + Some(Err(error)) => error.code(), + _ => HRESULT(0), + } + } + + fn get_results(&self) -> Result<T::Output> { + match &self.result { + Some(result) => result.clone(), + None => Err(Error::from_hresult(HRESULT(0x8000000Eu32 as i32))), // E_ILLEGAL_METHOD_CALL + } + } +} + +struct SyncState<T: Async>(Mutex<State<T>>); + +impl<T: Async> SyncState<T> { + fn new() -> Self { + Self(Mutex::new(State { + result: None, + completed: None, + completed_assigned: false, + })) + } + + fn status(&self) -> AsyncStatus { + self.0.lock().unwrap().status() + } + + fn error_code(&self) -> HRESULT { + self.0.lock().unwrap().error_code() + } + + fn get_results(&self) -> Result<T::Output> { + self.0.lock().unwrap().get_results() + } + + fn set_completed(&self, sender: &T, handler: Ref<T::CompletedHandler>) -> Result<()> { + let mut guard = self.0.lock().unwrap(); + + if guard.completed_assigned { + Err(Error::from_hresult(HRESULT(0x80000018u32 as i32))) // E_ILLEGAL_DELEGATE_ASSIGNMENT + } else { + guard.completed_assigned = true; + let status = guard.status(); + let handler = handler.ok()?; + + if status == AsyncStatus::Started { + guard.completed = Some(handler.clone()); + } else { + drop(guard); + sender.invoke_completed(handler, status); + } + + Ok(()) + } + } + + fn spawn<F>(&self, sender: &T, f: F) + where + F: FnOnce() -> Result<T::Output> + Send + 'static, + { + let result = f(); + let mut guard = self.0.lock().unwrap(); + debug_assert!(guard.result.is_none()); + guard.result = Some(result); + let status = guard.status(); + let completed = guard.completed.take(); + + drop(guard); + + if let Some(completed) = completed { + sender.invoke_completed(&completed, status); + } + } +} + +unsafe impl<T: Async> Send for SyncState<T> {} + +#[implement(IAsyncAction, IAsyncInfo)] +struct Action(SyncState<IAsyncAction>); + +#[implement(IAsyncOperation<T>, IAsyncInfo)] +struct Operation<T>(SyncState<IAsyncOperation<T>>) +where + T: RuntimeType + 'static; + +#[implement(IAsyncActionWithProgress<P>, IAsyncInfo)] +struct ActionWithProgress<P>(SyncState<IAsyncActionWithProgress<P>>) +where + P: RuntimeType + 'static; + +#[implement(IAsyncOperationWithProgress<T, P>, IAsyncInfo)] +struct OperationWithProgress<T, P>(SyncState<IAsyncOperationWithProgress<T, P>>) +where + T: RuntimeType + 'static, + P: RuntimeType + 'static; + +impl IAsyncInfo_Impl for Action_Impl { + fn Id(&self) -> Result<u32> { + Ok(1) + } + fn Status(&self) -> Result<AsyncStatus> { + Ok(self.0.status()) + } + fn ErrorCode(&self) -> Result<HRESULT> { + Ok(self.0.error_code()) + } + fn Cancel(&self) -> Result<()> { + Ok(()) + } + fn Close(&self) -> Result<()> { + Ok(()) + } +} + +impl<T: RuntimeType> IAsyncInfo_Impl for Operation_Impl<T> { + fn Id(&self) -> Result<u32> { + Ok(1) + } + fn Status(&self) -> Result<AsyncStatus> { + Ok(self.0.status()) + } + fn ErrorCode(&self) -> Result<HRESULT> { + Ok(self.0.error_code()) + } + fn Cancel(&self) -> Result<()> { + Ok(()) + } + fn Close(&self) -> Result<()> { + Ok(()) + } +} + +impl<P: RuntimeType> IAsyncInfo_Impl for ActionWithProgress_Impl<P> { + fn Id(&self) -> Result<u32> { + Ok(1) + } + fn Status(&self) -> Result<AsyncStatus> { + Ok(self.0.status()) + } + fn ErrorCode(&self) -> Result<HRESULT> { + Ok(self.0.error_code()) + } + fn Cancel(&self) -> Result<()> { + Ok(()) + } + fn Close(&self) -> Result<()> { + Ok(()) + } +} + +impl<T: RuntimeType, P: RuntimeType> IAsyncInfo_Impl for OperationWithProgress_Impl<T, P> { + fn Id(&self) -> Result<u32> { + Ok(1) + } + fn Status(&self) -> Result<AsyncStatus> { + Ok(self.0.status()) + } + fn ErrorCode(&self) -> Result<HRESULT> { + Ok(self.0.error_code()) + } + fn Cancel(&self) -> Result<()> { + Ok(()) + } + fn Close(&self) -> Result<()> { + Ok(()) + } +} + +impl IAsyncAction_Impl for Action_Impl { + fn SetCompleted(&self, handler: Ref<AsyncActionCompletedHandler>) -> Result<()> { + self.0.set_completed(&self.as_interface(), handler) + } + fn Completed(&self) -> Result<AsyncActionCompletedHandler> { + Err(Error::empty()) + } + fn GetResults(&self) -> Result<()> { + self.0.get_results() + } +} + +impl<T: RuntimeType> IAsyncOperation_Impl<T> for Operation_Impl<T> { + fn SetCompleted(&self, handler: Ref<AsyncOperationCompletedHandler<T>>) -> Result<()> { + self.0.set_completed(&self.as_interface(), handler) + } + fn Completed(&self) -> Result<AsyncOperationCompletedHandler<T>> { + Err(Error::empty()) + } + fn GetResults(&self) -> Result<T> { + self.0.get_results() + } +} + +impl<P: RuntimeType> IAsyncActionWithProgress_Impl<P> for ActionWithProgress_Impl<P> { + fn SetCompleted(&self, handler: Ref<AsyncActionWithProgressCompletedHandler<P>>) -> Result<()> { + self.0.set_completed(&self.as_interface(), handler) + } + fn Completed(&self) -> Result<AsyncActionWithProgressCompletedHandler<P>> { + Err(Error::empty()) + } + fn GetResults(&self) -> Result<()> { + self.0.get_results() + } + fn SetProgress(&self, _: Ref<AsyncActionProgressHandler<P>>) -> Result<()> { + Ok(()) + } + fn Progress(&self) -> Result<AsyncActionProgressHandler<P>> { + Err(Error::empty()) + } +} + +impl<T: RuntimeType, P: RuntimeType> IAsyncOperationWithProgress_Impl<T, P> + for OperationWithProgress_Impl<T, P> +{ + fn SetCompleted( + &self, + handler: Ref<AsyncOperationWithProgressCompletedHandler<T, P>>, + ) -> Result<()> { + self.0.set_completed(&self.as_interface(), handler) + } + fn Completed(&self) -> Result<AsyncOperationWithProgressCompletedHandler<T, P>> { + Err(Error::empty()) + } + fn GetResults(&self) -> Result<T> { + self.0.get_results() + } + fn SetProgress(&self, _: Ref<AsyncOperationProgressHandler<T, P>>) -> Result<()> { + Ok(()) + } + fn Progress(&self) -> Result<AsyncOperationProgressHandler<T, P>> { + Err(Error::empty()) + } +} + +impl IAsyncAction { + /// Creates an `IAsyncAction` that waits for the closure to execute on the Windows thread pool. + pub fn spawn<F>(f: F) -> Self + where + F: FnOnce() -> Result<()> + Send + 'static, + { + let object = ComObject::new(Action(SyncState::new())); + let interface = object.to_interface(); + + windows_threading::submit(move || { + object.0.spawn(&object.as_interface(), f); + }); + + interface + } +} + +impl<T: RuntimeType> IAsyncOperation<T> { + /// Creates an `IAsyncOperation<T>` that waits for the closure to execute on the Windows thread pool. + pub fn spawn<F>(f: F) -> Self + where + F: FnOnce() -> Result<T> + Send + 'static, + { + let object = ComObject::new(Operation(SyncState::new())); + let interface = object.to_interface(); + + windows_threading::submit(move || { + object.0.spawn(&object.as_interface(), f); + }); + + interface + } +} + +impl<P: RuntimeType> IAsyncActionWithProgress<P> { + /// Creates an `IAsyncActionWithProgress<P>` that waits for the closure to execute on the Windows thread pool. + pub fn spawn<F>(f: F) -> Self + where + F: FnOnce() -> Result<()> + Send + 'static, + { + let object = ComObject::new(ActionWithProgress(SyncState::new())); + let interface = object.to_interface(); + + windows_threading::submit(move || { + object.0.spawn(&object.as_interface(), f); + }); + + interface + } +} + +impl<T: RuntimeType, P: RuntimeType> IAsyncOperationWithProgress<T, P> { + /// Creates an `IAsyncOperationWithProgress<T, P>` that waits for the closure to execute on the Windows thread pool. + pub fn spawn<F>(f: F) -> Self + where + F: FnOnce() -> Result<T> + Send + 'static, + { + let object = ComObject::new(OperationWithProgress(SyncState::new())); + let interface = object.to_interface(); + + windows_threading::submit(move || { + object.0.spawn(&object.as_interface(), f); + }); + + interface + } +} diff --git a/third_party/rust/windows-future/src/bindings.rs b/third_party/rust/windows-future/src/bindings.rs @@ -0,0 +1,2235 @@ +windows_core::imp::define_interface!( + AsyncActionCompletedHandler, + AsyncActionCompletedHandler_Vtbl, + 0xa4ed5c81_76c9_40bd_8be6_b1d90fb20ae7 +); +impl windows_core::RuntimeType for AsyncActionCompletedHandler { + const SIGNATURE: windows_core::imp::ConstBuffer = + windows_core::imp::ConstBuffer::for_interface::<Self>(); +} +impl AsyncActionCompletedHandler { + pub fn new< + F: Fn(windows_core::Ref<IAsyncAction>, AsyncStatus) -> windows_core::Result<()> + + Send + + 'static, + >( + invoke: F, + ) -> Self { + let com = AsyncActionCompletedHandlerBox { + vtable: &AsyncActionCompletedHandlerBox::<F>::VTABLE, + count: windows_core::imp::RefCount::new(1), + invoke, + }; + unsafe { core::mem::transmute(windows_core::imp::Box::new(com)) } + } + pub fn Invoke<P0>(&self, asyncinfo: P0, asyncstatus: AsyncStatus) -> windows_core::Result<()> + where + P0: windows_core::Param<IAsyncAction>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Invoke)( + windows_core::Interface::as_raw(this), + asyncinfo.param().abi(), + asyncstatus, + ) + .ok() + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct AsyncActionCompletedHandler_Vtbl { + base__: windows_core::IUnknown_Vtbl, + Invoke: unsafe extern "system" fn( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + asyncstatus: AsyncStatus, + ) -> windows_core::HRESULT, +} +#[repr(C)] +struct AsyncActionCompletedHandlerBox< + F: Fn(windows_core::Ref<IAsyncAction>, AsyncStatus) -> windows_core::Result<()> + Send + 'static, +> { + vtable: *const AsyncActionCompletedHandler_Vtbl, + invoke: F, + count: windows_core::imp::RefCount, +} +impl< + F: Fn(windows_core::Ref<IAsyncAction>, AsyncStatus) -> windows_core::Result<()> + + Send + + 'static, + > AsyncActionCompletedHandlerBox<F> +{ + const VTABLE: AsyncActionCompletedHandler_Vtbl = AsyncActionCompletedHandler_Vtbl { + base__: windows_core::IUnknown_Vtbl { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + }, + Invoke: Self::Invoke, + }; + unsafe extern "system" fn QueryInterface( + this: *mut core::ffi::c_void, + iid: *const windows_core::GUID, + interface: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + if iid.is_null() || interface.is_null() { + return windows_core::HRESULT(-2147467261); + } + *interface = if *iid == <AsyncActionCompletedHandler as windows_core::Interface>::IID + || *iid == <windows_core::IUnknown as windows_core::Interface>::IID + || *iid == <windows_core::imp::IAgileObject as windows_core::Interface>::IID + { + &mut (*this).vtable as *mut _ as _ + } else if *iid == <windows_core::imp::IMarshal as windows_core::Interface>::IID { + (*this).count.add_ref(); + return windows_core::imp::marshaler( + core::mem::transmute(&mut (*this).vtable as *mut _ as *mut core::ffi::c_void), + interface, + ); + } else { + core::ptr::null_mut() + }; + if (*interface).is_null() { + windows_core::HRESULT(-2147467262) + } else { + (*this).count.add_ref(); + windows_core::HRESULT(0) + } + } + } + unsafe extern "system" fn AddRef(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + (*this).count.add_ref() + } + } + unsafe extern "system" fn Release(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + let remaining = (*this).count.release(); + if remaining == 0 { + let _ = windows_core::imp::Box::from_raw(this); + } + remaining + } + } + unsafe extern "system" fn Invoke( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + asyncstatus: AsyncStatus, + ) -> windows_core::HRESULT { + unsafe { + let this = &mut *(this as *mut *mut core::ffi::c_void as *mut Self); + (this.invoke)(core::mem::transmute_copy(&asyncinfo), asyncstatus).into() + } + } +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AsyncActionProgressHandler<TProgress>( + windows_core::IUnknown, + core::marker::PhantomData<TProgress>, +) +where + TProgress: windows_core::RuntimeType + 'static; +unsafe impl<TProgress: windows_core::RuntimeType + 'static> windows_core::Interface + for AsyncActionProgressHandler<TProgress> +{ + type Vtable = AsyncActionProgressHandler_Vtbl<TProgress>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<TProgress: windows_core::RuntimeType + 'static> windows_core::RuntimeType + for AsyncActionProgressHandler<TProgress> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({6d844858-0cff-4590-ae89-95a5a5c8b4b8}") + .push_slice(b";") + .push_other(TProgress::SIGNATURE) + .push_slice(b")"); +} +impl<TProgress: windows_core::RuntimeType + 'static> AsyncActionProgressHandler<TProgress> { + pub fn new< + F: Fn( + windows_core::Ref<IAsyncActionWithProgress<TProgress>>, + windows_core::Ref<TProgress>, + ) -> windows_core::Result<()> + + Send + + 'static, + >( + invoke: F, + ) -> Self { + let com = AsyncActionProgressHandlerBox { + vtable: &AsyncActionProgressHandlerBox::<TProgress, F>::VTABLE, + count: windows_core::imp::RefCount::new(1), + invoke, + }; + unsafe { core::mem::transmute(windows_core::imp::Box::new(com)) } + } + pub fn Invoke<P0, P1>(&self, asyncinfo: P0, progressinfo: P1) -> windows_core::Result<()> + where + P0: windows_core::Param<IAsyncActionWithProgress<TProgress>>, + P1: windows_core::Param<TProgress>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Invoke)( + windows_core::Interface::as_raw(this), + asyncinfo.param().abi(), + progressinfo.param().abi(), + ) + .ok() + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct AsyncActionProgressHandler_Vtbl<TProgress> +where + TProgress: windows_core::RuntimeType + 'static, +{ + base__: windows_core::IUnknown_Vtbl, + Invoke: unsafe extern "system" fn( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + progressinfo: windows_core::AbiType<TProgress>, + ) -> windows_core::HRESULT, + TProgress: core::marker::PhantomData<TProgress>, +} +#[repr(C)] +struct AsyncActionProgressHandlerBox< + TProgress, + F: Fn( + windows_core::Ref<IAsyncActionWithProgress<TProgress>>, + windows_core::Ref<TProgress>, + ) -> windows_core::Result<()> + + Send + + 'static, +> where + TProgress: windows_core::RuntimeType + 'static, +{ + vtable: *const AsyncActionProgressHandler_Vtbl<TProgress>, + invoke: F, + count: windows_core::imp::RefCount, +} +impl< + TProgress: windows_core::RuntimeType + 'static, + F: Fn( + windows_core::Ref<IAsyncActionWithProgress<TProgress>>, + windows_core::Ref<TProgress>, + ) -> windows_core::Result<()> + + Send + + 'static, + > AsyncActionProgressHandlerBox<TProgress, F> +{ + const VTABLE: AsyncActionProgressHandler_Vtbl<TProgress> = + AsyncActionProgressHandler_Vtbl::<TProgress> { + base__: windows_core::IUnknown_Vtbl { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + }, + Invoke: Self::Invoke, + TProgress: core::marker::PhantomData::<TProgress>, + }; + unsafe extern "system" fn QueryInterface( + this: *mut core::ffi::c_void, + iid: *const windows_core::GUID, + interface: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + if iid.is_null() || interface.is_null() { + return windows_core::HRESULT(-2147467261); + } + *interface = if *iid + == <AsyncActionProgressHandler<TProgress> as windows_core::Interface>::IID + || *iid == <windows_core::IUnknown as windows_core::Interface>::IID + || *iid == <windows_core::imp::IAgileObject as windows_core::Interface>::IID + { + &mut (*this).vtable as *mut _ as _ + } else if *iid == <windows_core::imp::IMarshal as windows_core::Interface>::IID { + (*this).count.add_ref(); + return windows_core::imp::marshaler( + core::mem::transmute(&mut (*this).vtable as *mut _ as *mut core::ffi::c_void), + interface, + ); + } else { + core::ptr::null_mut() + }; + if (*interface).is_null() { + windows_core::HRESULT(-2147467262) + } else { + (*this).count.add_ref(); + windows_core::HRESULT(0) + } + } + } + unsafe extern "system" fn AddRef(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + (*this).count.add_ref() + } + } + unsafe extern "system" fn Release(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + let remaining = (*this).count.release(); + if remaining == 0 { + let _ = windows_core::imp::Box::from_raw(this); + } + remaining + } + } + unsafe extern "system" fn Invoke( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + progressinfo: windows_core::AbiType<TProgress>, + ) -> windows_core::HRESULT { + unsafe { + let this = &mut *(this as *mut *mut core::ffi::c_void as *mut Self); + (this.invoke)( + core::mem::transmute_copy(&asyncinfo), + core::mem::transmute_copy(&progressinfo), + ) + .into() + } + } +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AsyncActionWithProgressCompletedHandler<TProgress>( + windows_core::IUnknown, + core::marker::PhantomData<TProgress>, +) +where + TProgress: windows_core::RuntimeType + 'static; +unsafe impl<TProgress: windows_core::RuntimeType + 'static> windows_core::Interface + for AsyncActionWithProgressCompletedHandler<TProgress> +{ + type Vtable = AsyncActionWithProgressCompletedHandler_Vtbl<TProgress>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<TProgress: windows_core::RuntimeType + 'static> windows_core::RuntimeType + for AsyncActionWithProgressCompletedHandler<TProgress> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({9c029f91-cc84-44fd-ac26-0a6c4e555281}") + .push_slice(b";") + .push_other(TProgress::SIGNATURE) + .push_slice(b")"); +} +impl<TProgress: windows_core::RuntimeType + 'static> + AsyncActionWithProgressCompletedHandler<TProgress> +{ + pub fn new< + F: Fn( + windows_core::Ref<IAsyncActionWithProgress<TProgress>>, + AsyncStatus, + ) -> windows_core::Result<()> + + Send + + 'static, + >( + invoke: F, + ) -> Self { + let com = AsyncActionWithProgressCompletedHandlerBox { + vtable: &AsyncActionWithProgressCompletedHandlerBox::<TProgress, F>::VTABLE, + count: windows_core::imp::RefCount::new(1), + invoke, + }; + unsafe { core::mem::transmute(windows_core::imp::Box::new(com)) } + } + pub fn Invoke<P0>(&self, asyncinfo: P0, asyncstatus: AsyncStatus) -> windows_core::Result<()> + where + P0: windows_core::Param<IAsyncActionWithProgress<TProgress>>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Invoke)( + windows_core::Interface::as_raw(this), + asyncinfo.param().abi(), + asyncstatus, + ) + .ok() + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct AsyncActionWithProgressCompletedHandler_Vtbl<TProgress> +where + TProgress: windows_core::RuntimeType + 'static, +{ + base__: windows_core::IUnknown_Vtbl, + Invoke: unsafe extern "system" fn( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + asyncstatus: AsyncStatus, + ) -> windows_core::HRESULT, + TProgress: core::marker::PhantomData<TProgress>, +} +#[repr(C)] +struct AsyncActionWithProgressCompletedHandlerBox< + TProgress, + F: Fn( + windows_core::Ref<IAsyncActionWithProgress<TProgress>>, + AsyncStatus, + ) -> windows_core::Result<()> + + Send + + 'static, +> where + TProgress: windows_core::RuntimeType + 'static, +{ + vtable: *const AsyncActionWithProgressCompletedHandler_Vtbl<TProgress>, + invoke: F, + count: windows_core::imp::RefCount, +} +impl< + TProgress: windows_core::RuntimeType + 'static, + F: Fn( + windows_core::Ref<IAsyncActionWithProgress<TProgress>>, + AsyncStatus, + ) -> windows_core::Result<()> + + Send + + 'static, + > AsyncActionWithProgressCompletedHandlerBox<TProgress, F> +{ + const VTABLE: AsyncActionWithProgressCompletedHandler_Vtbl<TProgress> = + AsyncActionWithProgressCompletedHandler_Vtbl::<TProgress> { + base__: windows_core::IUnknown_Vtbl { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + }, + Invoke: Self::Invoke, + TProgress: core::marker::PhantomData::<TProgress>, + }; + unsafe extern "system" fn QueryInterface( + this: *mut core::ffi::c_void, + iid: *const windows_core::GUID, + interface: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + if iid.is_null() || interface.is_null() { + return windows_core::HRESULT(-2147467261); + } + * interface = if * iid == < AsyncActionWithProgressCompletedHandler < TProgress > as windows_core::Interface >::IID || * iid == < windows_core::IUnknown as windows_core::Interface >::IID || * iid == < windows_core::imp::IAgileObject as windows_core::Interface >::IID { & mut ( * this ) . vtable as * mut _ as _ } else if * iid == < windows_core::imp::IMarshal as windows_core::Interface >::IID { ( * this ) . count . add_ref ( ) ; return windows_core::imp::marshaler ( core::mem::transmute ( & mut ( * this ) . vtable as * mut _ as * mut core::ffi::c_void ) , interface ) ; } else { core::ptr::null_mut ( ) } ; + if (*interface).is_null() { + windows_core::HRESULT(-2147467262) + } else { + (*this).count.add_ref(); + windows_core::HRESULT(0) + } + } + } + unsafe extern "system" fn AddRef(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + (*this).count.add_ref() + } + } + unsafe extern "system" fn Release(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + let remaining = (*this).count.release(); + if remaining == 0 { + let _ = windows_core::imp::Box::from_raw(this); + } + remaining + } + } + unsafe extern "system" fn Invoke( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + asyncstatus: AsyncStatus, + ) -> windows_core::HRESULT { + unsafe { + let this = &mut *(this as *mut *mut core::ffi::c_void as *mut Self); + (this.invoke)(core::mem::transmute_copy(&asyncinfo), asyncstatus).into() + } + } +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AsyncOperationCompletedHandler<TResult>( + windows_core::IUnknown, + core::marker::PhantomData<TResult>, +) +where + TResult: windows_core::RuntimeType + 'static; +unsafe impl<TResult: windows_core::RuntimeType + 'static> windows_core::Interface + for AsyncOperationCompletedHandler<TResult> +{ + type Vtable = AsyncOperationCompletedHandler_Vtbl<TResult>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<TResult: windows_core::RuntimeType + 'static> windows_core::RuntimeType + for AsyncOperationCompletedHandler<TResult> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({fcdcf02c-e5d8-4478-915a-4d90b74b83a5}") + .push_slice(b";") + .push_other(TResult::SIGNATURE) + .push_slice(b")"); +} +impl<TResult: windows_core::RuntimeType + 'static> AsyncOperationCompletedHandler<TResult> { + pub fn new< + F: Fn(windows_core::Ref<IAsyncOperation<TResult>>, AsyncStatus) -> windows_core::Result<()> + + Send + + 'static, + >( + invoke: F, + ) -> Self { + let com = AsyncOperationCompletedHandlerBox { + vtable: &AsyncOperationCompletedHandlerBox::<TResult, F>::VTABLE, + count: windows_core::imp::RefCount::new(1), + invoke, + }; + unsafe { core::mem::transmute(windows_core::imp::Box::new(com)) } + } + pub fn Invoke<P0>(&self, asyncinfo: P0, asyncstatus: AsyncStatus) -> windows_core::Result<()> + where + P0: windows_core::Param<IAsyncOperation<TResult>>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Invoke)( + windows_core::Interface::as_raw(this), + asyncinfo.param().abi(), + asyncstatus, + ) + .ok() + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct AsyncOperationCompletedHandler_Vtbl<TResult> +where + TResult: windows_core::RuntimeType + 'static, +{ + base__: windows_core::IUnknown_Vtbl, + Invoke: unsafe extern "system" fn( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + asyncstatus: AsyncStatus, + ) -> windows_core::HRESULT, + TResult: core::marker::PhantomData<TResult>, +} +#[repr(C)] +struct AsyncOperationCompletedHandlerBox< + TResult, + F: Fn(windows_core::Ref<IAsyncOperation<TResult>>, AsyncStatus) -> windows_core::Result<()> + + Send + + 'static, +> where + TResult: windows_core::RuntimeType + 'static, +{ + vtable: *const AsyncOperationCompletedHandler_Vtbl<TResult>, + invoke: F, + count: windows_core::imp::RefCount, +} +impl< + TResult: windows_core::RuntimeType + 'static, + F: Fn(windows_core::Ref<IAsyncOperation<TResult>>, AsyncStatus) -> windows_core::Result<()> + + Send + + 'static, + > AsyncOperationCompletedHandlerBox<TResult, F> +{ + const VTABLE: AsyncOperationCompletedHandler_Vtbl<TResult> = + AsyncOperationCompletedHandler_Vtbl::<TResult> { + base__: windows_core::IUnknown_Vtbl { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + }, + Invoke: Self::Invoke, + TResult: core::marker::PhantomData::<TResult>, + }; + unsafe extern "system" fn QueryInterface( + this: *mut core::ffi::c_void, + iid: *const windows_core::GUID, + interface: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + if iid.is_null() || interface.is_null() { + return windows_core::HRESULT(-2147467261); + } + *interface = if *iid + == <AsyncOperationCompletedHandler<TResult> as windows_core::Interface>::IID + || *iid == <windows_core::IUnknown as windows_core::Interface>::IID + || *iid == <windows_core::imp::IAgileObject as windows_core::Interface>::IID + { + &mut (*this).vtable as *mut _ as _ + } else if *iid == <windows_core::imp::IMarshal as windows_core::Interface>::IID { + (*this).count.add_ref(); + return windows_core::imp::marshaler( + core::mem::transmute(&mut (*this).vtable as *mut _ as *mut core::ffi::c_void), + interface, + ); + } else { + core::ptr::null_mut() + }; + if (*interface).is_null() { + windows_core::HRESULT(-2147467262) + } else { + (*this).count.add_ref(); + windows_core::HRESULT(0) + } + } + } + unsafe extern "system" fn AddRef(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + (*this).count.add_ref() + } + } + unsafe extern "system" fn Release(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + let remaining = (*this).count.release(); + if remaining == 0 { + let _ = windows_core::imp::Box::from_raw(this); + } + remaining + } + } + unsafe extern "system" fn Invoke( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + asyncstatus: AsyncStatus, + ) -> windows_core::HRESULT { + unsafe { + let this = &mut *(this as *mut *mut core::ffi::c_void as *mut Self); + (this.invoke)(core::mem::transmute_copy(&asyncinfo), asyncstatus).into() + } + } +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AsyncOperationProgressHandler<TResult, TProgress>( + windows_core::IUnknown, + core::marker::PhantomData<TResult>, + core::marker::PhantomData<TProgress>, +) +where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static; +unsafe impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::Interface for AsyncOperationProgressHandler<TResult, TProgress> +{ + type Vtable = AsyncOperationProgressHandler_Vtbl<TResult, TProgress>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::RuntimeType for AsyncOperationProgressHandler<TResult, TProgress> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({55690902-0aab-421a-8778-f8ce5026d758}") + .push_slice(b";") + .push_other(TResult::SIGNATURE) + .push_slice(b";") + .push_other(TProgress::SIGNATURE) + .push_slice(b")"); +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > AsyncOperationProgressHandler<TResult, TProgress> +{ + pub fn new< + F: Fn( + windows_core::Ref<IAsyncOperationWithProgress<TResult, TProgress>>, + windows_core::Ref<TProgress>, + ) -> windows_core::Result<()> + + Send + + 'static, + >( + invoke: F, + ) -> Self { + let com = AsyncOperationProgressHandlerBox { + vtable: &AsyncOperationProgressHandlerBox::<TResult, TProgress, F>::VTABLE, + count: windows_core::imp::RefCount::new(1), + invoke, + }; + unsafe { core::mem::transmute(windows_core::imp::Box::new(com)) } + } + pub fn Invoke<P0, P1>(&self, asyncinfo: P0, progressinfo: P1) -> windows_core::Result<()> + where + P0: windows_core::Param<IAsyncOperationWithProgress<TResult, TProgress>>, + P1: windows_core::Param<TProgress>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Invoke)( + windows_core::Interface::as_raw(this), + asyncinfo.param().abi(), + progressinfo.param().abi(), + ) + .ok() + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct AsyncOperationProgressHandler_Vtbl<TResult, TProgress> +where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, +{ + base__: windows_core::IUnknown_Vtbl, + Invoke: unsafe extern "system" fn( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + progressinfo: windows_core::AbiType<TProgress>, + ) -> windows_core::HRESULT, + TResult: core::marker::PhantomData<TResult>, + TProgress: core::marker::PhantomData<TProgress>, +} +#[repr(C)] +struct AsyncOperationProgressHandlerBox< + TResult, + TProgress, + F: Fn( + windows_core::Ref<IAsyncOperationWithProgress<TResult, TProgress>>, + windows_core::Ref<TProgress>, + ) -> windows_core::Result<()> + + Send + + 'static, +> where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, +{ + vtable: *const AsyncOperationProgressHandler_Vtbl<TResult, TProgress>, + invoke: F, + count: windows_core::imp::RefCount, +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + F: Fn( + windows_core::Ref<IAsyncOperationWithProgress<TResult, TProgress>>, + windows_core::Ref<TProgress>, + ) -> windows_core::Result<()> + + Send + + 'static, + > AsyncOperationProgressHandlerBox<TResult, TProgress, F> +{ + const VTABLE: AsyncOperationProgressHandler_Vtbl<TResult, TProgress> = + AsyncOperationProgressHandler_Vtbl::<TResult, TProgress> { + base__: windows_core::IUnknown_Vtbl { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + }, + Invoke: Self::Invoke, + TResult: core::marker::PhantomData::<TResult>, + TProgress: core::marker::PhantomData::<TProgress>, + }; + unsafe extern "system" fn QueryInterface( + this: *mut core::ffi::c_void, + iid: *const windows_core::GUID, + interface: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + if iid.is_null() || interface.is_null() { + return windows_core::HRESULT(-2147467261); + } + * interface = if * iid == < AsyncOperationProgressHandler < TResult , TProgress > as windows_core::Interface >::IID || * iid == < windows_core::IUnknown as windows_core::Interface >::IID || * iid == < windows_core::imp::IAgileObject as windows_core::Interface >::IID { & mut ( * this ) . vtable as * mut _ as _ } else if * iid == < windows_core::imp::IMarshal as windows_core::Interface >::IID { ( * this ) . count . add_ref ( ) ; return windows_core::imp::marshaler ( core::mem::transmute ( & mut ( * this ) . vtable as * mut _ as * mut core::ffi::c_void ) , interface ) ; } else { core::ptr::null_mut ( ) } ; + if (*interface).is_null() { + windows_core::HRESULT(-2147467262) + } else { + (*this).count.add_ref(); + windows_core::HRESULT(0) + } + } + } + unsafe extern "system" fn AddRef(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + (*this).count.add_ref() + } + } + unsafe extern "system" fn Release(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + let remaining = (*this).count.release(); + if remaining == 0 { + let _ = windows_core::imp::Box::from_raw(this); + } + remaining + } + } + unsafe extern "system" fn Invoke( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + progressinfo: windows_core::AbiType<TProgress>, + ) -> windows_core::HRESULT { + unsafe { + let this = &mut *(this as *mut *mut core::ffi::c_void as *mut Self); + (this.invoke)( + core::mem::transmute_copy(&asyncinfo), + core::mem::transmute_copy(&progressinfo), + ) + .into() + } + } +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AsyncOperationWithProgressCompletedHandler<TResult, TProgress>( + windows_core::IUnknown, + core::marker::PhantomData<TResult>, + core::marker::PhantomData<TProgress>, +) +where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static; +unsafe impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::Interface for AsyncOperationWithProgressCompletedHandler<TResult, TProgress> +{ + type Vtable = AsyncOperationWithProgressCompletedHandler_Vtbl<TResult, TProgress>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::RuntimeType for AsyncOperationWithProgressCompletedHandler<TResult, TProgress> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({e85df41d-6aa7-46e3-a8e2-f009d840c627}") + .push_slice(b";") + .push_other(TResult::SIGNATURE) + .push_slice(b";") + .push_other(TProgress::SIGNATURE) + .push_slice(b")"); +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > AsyncOperationWithProgressCompletedHandler<TResult, TProgress> +{ + pub fn new< + F: Fn( + windows_core::Ref<IAsyncOperationWithProgress<TResult, TProgress>>, + AsyncStatus, + ) -> windows_core::Result<()> + + Send + + 'static, + >( + invoke: F, + ) -> Self { + let com = AsyncOperationWithProgressCompletedHandlerBox { + vtable: &AsyncOperationWithProgressCompletedHandlerBox::<TResult, TProgress, F>::VTABLE, + count: windows_core::imp::RefCount::new(1), + invoke, + }; + unsafe { core::mem::transmute(windows_core::imp::Box::new(com)) } + } + pub fn Invoke<P0>(&self, asyncinfo: P0, asyncstatus: AsyncStatus) -> windows_core::Result<()> + where + P0: windows_core::Param<IAsyncOperationWithProgress<TResult, TProgress>>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Invoke)( + windows_core::Interface::as_raw(this), + asyncinfo.param().abi(), + asyncstatus, + ) + .ok() + } + } +} +#[repr(C)] +#[doc(hidden)] +pub struct AsyncOperationWithProgressCompletedHandler_Vtbl<TResult, TProgress> +where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, +{ + base__: windows_core::IUnknown_Vtbl, + Invoke: unsafe extern "system" fn( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + asyncstatus: AsyncStatus, + ) -> windows_core::HRESULT, + TResult: core::marker::PhantomData<TResult>, + TProgress: core::marker::PhantomData<TProgress>, +} +#[repr(C)] +struct AsyncOperationWithProgressCompletedHandlerBox< + TResult, + TProgress, + F: Fn( + windows_core::Ref<IAsyncOperationWithProgress<TResult, TProgress>>, + AsyncStatus, + ) -> windows_core::Result<()> + + Send + + 'static, +> where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, +{ + vtable: *const AsyncOperationWithProgressCompletedHandler_Vtbl<TResult, TProgress>, + invoke: F, + count: windows_core::imp::RefCount, +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + F: Fn( + windows_core::Ref<IAsyncOperationWithProgress<TResult, TProgress>>, + AsyncStatus, + ) -> windows_core::Result<()> + + Send + + 'static, + > AsyncOperationWithProgressCompletedHandlerBox<TResult, TProgress, F> +{ + const VTABLE: AsyncOperationWithProgressCompletedHandler_Vtbl<TResult, TProgress> = + AsyncOperationWithProgressCompletedHandler_Vtbl::<TResult, TProgress> { + base__: windows_core::IUnknown_Vtbl { + QueryInterface: Self::QueryInterface, + AddRef: Self::AddRef, + Release: Self::Release, + }, + Invoke: Self::Invoke, + TResult: core::marker::PhantomData::<TResult>, + TProgress: core::marker::PhantomData::<TProgress>, + }; + unsafe extern "system" fn QueryInterface( + this: *mut core::ffi::c_void, + iid: *const windows_core::GUID, + interface: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + if iid.is_null() || interface.is_null() { + return windows_core::HRESULT(-2147467261); + } + * interface = if * iid == < AsyncOperationWithProgressCompletedHandler < TResult , TProgress > as windows_core::Interface >::IID || * iid == < windows_core::IUnknown as windows_core::Interface >::IID || * iid == < windows_core::imp::IAgileObject as windows_core::Interface >::IID { & mut ( * this ) . vtable as * mut _ as _ } else if * iid == < windows_core::imp::IMarshal as windows_core::Interface >::IID { ( * this ) . count . add_ref ( ) ; return windows_core::imp::marshaler ( core::mem::transmute ( & mut ( * this ) . vtable as * mut _ as * mut core::ffi::c_void ) , interface ) ; } else { core::ptr::null_mut ( ) } ; + if (*interface).is_null() { + windows_core::HRESULT(-2147467262) + } else { + (*this).count.add_ref(); + windows_core::HRESULT(0) + } + } + } + unsafe extern "system" fn AddRef(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + (*this).count.add_ref() + } + } + unsafe extern "system" fn Release(this: *mut core::ffi::c_void) -> u32 { + unsafe { + let this = this as *mut *mut core::ffi::c_void as *mut Self; + let remaining = (*this).count.release(); + if remaining == 0 { + let _ = windows_core::imp::Box::from_raw(this); + } + remaining + } + } + unsafe extern "system" fn Invoke( + this: *mut core::ffi::c_void, + asyncinfo: *mut core::ffi::c_void, + asyncstatus: AsyncStatus, + ) -> windows_core::HRESULT { + unsafe { + let this = &mut *(this as *mut *mut core::ffi::c_void as *mut Self); + (this.invoke)(core::mem::transmute_copy(&asyncinfo), asyncstatus).into() + } + } +} +#[repr(transparent)] +#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +pub struct AsyncStatus(pub i32); +impl AsyncStatus { + pub const Canceled: Self = Self(2i32); + pub const Completed: Self = Self(1i32); + pub const Error: Self = Self(3i32); + pub const Started: Self = Self(0i32); +} +impl windows_core::TypeKind for AsyncStatus { + type TypeKind = windows_core::CopyType; +} +impl windows_core::RuntimeType for AsyncStatus { + const SIGNATURE: windows_core::imp::ConstBuffer = + windows_core::imp::ConstBuffer::from_slice(b"enum(Windows.Foundation.AsyncStatus;i4)"); +} +windows_core::imp::define_interface!( + IAsyncAction, + IAsyncAction_Vtbl, + 0x5a648006_843a_4da9_865b_9d26e5dfad7b +); +impl windows_core::RuntimeType for IAsyncAction { + const SIGNATURE: windows_core::imp::ConstBuffer = + windows_core::imp::ConstBuffer::for_interface::<Self>(); +} +windows_core::imp::interface_hierarchy!( + IAsyncAction, + windows_core::IUnknown, + windows_core::IInspectable +); +windows_core::imp::required_hierarchy!(IAsyncAction, IAsyncInfo); +impl IAsyncAction { + pub fn SetCompleted<P0>(&self, handler: P0) -> windows_core::Result<()> + where + P0: windows_core::Param<AsyncActionCompletedHandler>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).SetCompleted)( + windows_core::Interface::as_raw(this), + handler.param().abi(), + ) + .ok() + } + } + pub fn Completed(&self) -> windows_core::Result<AsyncActionCompletedHandler> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Completed)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn GetResults(&self) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).GetResults)(windows_core::Interface::as_raw( + this, + )) + .ok() + } + } + pub fn Id(&self) -> windows_core::Result<u32> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Id)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Status(&self) -> windows_core::Result<AsyncStatus> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Status)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn ErrorCode(&self) -> windows_core::Result<windows_core::HRESULT> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).ErrorCode)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Cancel(&self) -> windows_core::Result<()> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + (windows_core::Interface::vtable(this).Cancel)(windows_core::Interface::as_raw(this)) + .ok() + } + } + pub fn Close(&self) -> windows_core::Result<()> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + (windows_core::Interface::vtable(this).Close)(windows_core::Interface::as_raw(this)) + .ok() + } + } +} +unsafe impl Send for IAsyncAction {} +unsafe impl Sync for IAsyncAction {} +impl windows_core::RuntimeName for IAsyncAction { + const NAME: &'static str = "Windows.Foundation.IAsyncAction"; +} +pub trait IAsyncAction_Impl: IAsyncInfo_Impl { + fn SetCompleted( + &self, + handler: windows_core::Ref<AsyncActionCompletedHandler>, + ) -> windows_core::Result<()>; + fn Completed(&self) -> windows_core::Result<AsyncActionCompletedHandler>; + fn GetResults(&self) -> windows_core::Result<()>; +} +impl IAsyncAction_Vtbl { + pub const fn new<Identity: IAsyncAction_Impl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn SetCompleted<Identity: IAsyncAction_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + handler: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncAction_Impl::SetCompleted(this, core::mem::transmute_copy(&handler)).into() + } + } + unsafe extern "system" fn Completed<Identity: IAsyncAction_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncAction_Impl::Completed(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn GetResults<Identity: IAsyncAction_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncAction_Impl::GetResults(this).into() + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IAsyncAction, OFFSET>(), + SetCompleted: SetCompleted::<Identity, OFFSET>, + Completed: Completed::<Identity, OFFSET>, + GetResults: GetResults::<Identity, OFFSET>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAsyncAction as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IAsyncAction_Vtbl { + pub base__: windows_core::IInspectable_Vtbl, + pub SetCompleted: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub Completed: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub GetResults: unsafe extern "system" fn(*mut core::ffi::c_void) -> windows_core::HRESULT, +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IAsyncActionWithProgress<TProgress>( + windows_core::IUnknown, + core::marker::PhantomData<TProgress>, +) +where + TProgress: windows_core::RuntimeType + 'static; +impl<TProgress: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IUnknown> for IAsyncActionWithProgress<TProgress> +{ +} +impl<TProgress: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IInspectable> for IAsyncActionWithProgress<TProgress> +{ +} +unsafe impl<TProgress: windows_core::RuntimeType + 'static> windows_core::Interface + for IAsyncActionWithProgress<TProgress> +{ + type Vtable = IAsyncActionWithProgress_Vtbl<TProgress>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<TProgress: windows_core::RuntimeType + 'static> windows_core::RuntimeType + for IAsyncActionWithProgress<TProgress> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({1f6db258-e803-48a1-9546-eb7353398884}") + .push_slice(b";") + .push_other(TProgress::SIGNATURE) + .push_slice(b")"); +} +impl<TProgress: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IAsyncInfo> + for IAsyncActionWithProgress<TProgress> +{ + const QUERY: bool = true; +} +impl<TProgress: windows_core::RuntimeType + 'static> IAsyncActionWithProgress<TProgress> { + pub fn SetProgress<P0>(&self, handler: P0) -> windows_core::Result<()> + where + P0: windows_core::Param<AsyncActionProgressHandler<TProgress>>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).SetProgress)( + windows_core::Interface::as_raw(this), + handler.param().abi(), + ) + .ok() + } + } + pub fn Progress(&self) -> windows_core::Result<AsyncActionProgressHandler<TProgress>> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Progress)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn SetCompleted<P0>(&self, handler: P0) -> windows_core::Result<()> + where + P0: windows_core::Param<AsyncActionWithProgressCompletedHandler<TProgress>>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).SetCompleted)( + windows_core::Interface::as_raw(this), + handler.param().abi(), + ) + .ok() + } + } + pub fn Completed( + &self, + ) -> windows_core::Result<AsyncActionWithProgressCompletedHandler<TProgress>> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Completed)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn GetResults(&self) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).GetResults)(windows_core::Interface::as_raw( + this, + )) + .ok() + } + } + pub fn Id(&self) -> windows_core::Result<u32> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Id)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Status(&self) -> windows_core::Result<AsyncStatus> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Status)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn ErrorCode(&self) -> windows_core::Result<windows_core::HRESULT> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).ErrorCode)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Cancel(&self) -> windows_core::Result<()> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + (windows_core::Interface::vtable(this).Cancel)(windows_core::Interface::as_raw(this)) + .ok() + } + } + pub fn Close(&self) -> windows_core::Result<()> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + (windows_core::Interface::vtable(this).Close)(windows_core::Interface::as_raw(this)) + .ok() + } + } +} +unsafe impl<TProgress: windows_core::RuntimeType + 'static> Send + for IAsyncActionWithProgress<TProgress> +{ +} +unsafe impl<TProgress: windows_core::RuntimeType + 'static> Sync + for IAsyncActionWithProgress<TProgress> +{ +} +impl<TProgress: windows_core::RuntimeType + 'static> windows_core::RuntimeName + for IAsyncActionWithProgress<TProgress> +{ + const NAME: &'static str = "Windows.Foundation.IAsyncActionWithProgress"; +} +pub trait IAsyncActionWithProgress_Impl<TProgress>: IAsyncInfo_Impl +where + TProgress: windows_core::RuntimeType + 'static, +{ + fn SetProgress( + &self, + handler: windows_core::Ref<AsyncActionProgressHandler<TProgress>>, + ) -> windows_core::Result<()>; + fn Progress(&self) -> windows_core::Result<AsyncActionProgressHandler<TProgress>>; + fn SetCompleted( + &self, + handler: windows_core::Ref<AsyncActionWithProgressCompletedHandler<TProgress>>, + ) -> windows_core::Result<()>; + fn Completed(&self) + -> windows_core::Result<AsyncActionWithProgressCompletedHandler<TProgress>>; + fn GetResults(&self) -> windows_core::Result<()>; +} +impl<TProgress: windows_core::RuntimeType + 'static> IAsyncActionWithProgress_Vtbl<TProgress> { + pub const fn new<Identity: IAsyncActionWithProgress_Impl<TProgress>, const OFFSET: isize>( + ) -> Self { + unsafe extern "system" fn SetProgress< + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncActionWithProgress_Impl<TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + handler: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncActionWithProgress_Impl::SetProgress( + this, + core::mem::transmute_copy(&handler), + ) + .into() + } + } + unsafe extern "system" fn Progress< + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncActionWithProgress_Impl<TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncActionWithProgress_Impl::Progress(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn SetCompleted< + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncActionWithProgress_Impl<TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + handler: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncActionWithProgress_Impl::SetCompleted( + this, + core::mem::transmute_copy(&handler), + ) + .into() + } + } + unsafe extern "system" fn Completed< + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncActionWithProgress_Impl<TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncActionWithProgress_Impl::Completed(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn GetResults< + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncActionWithProgress_Impl<TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncActionWithProgress_Impl::GetResults(this).into() + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::< + Identity, + IAsyncActionWithProgress<TProgress>, + OFFSET, + >(), + SetProgress: SetProgress::<TProgress, Identity, OFFSET>, + Progress: Progress::<TProgress, Identity, OFFSET>, + SetCompleted: SetCompleted::<TProgress, Identity, OFFSET>, + Completed: Completed::<TProgress, Identity, OFFSET>, + GetResults: GetResults::<TProgress, Identity, OFFSET>, + TProgress: core::marker::PhantomData::<TProgress>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAsyncActionWithProgress<TProgress> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IAsyncActionWithProgress_Vtbl<TProgress> +where + TProgress: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub SetProgress: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub Progress: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub SetCompleted: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub Completed: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub GetResults: unsafe extern "system" fn(*mut core::ffi::c_void) -> windows_core::HRESULT, + TProgress: core::marker::PhantomData<TProgress>, +} +windows_core::imp::define_interface!( + IAsyncInfo, + IAsyncInfo_Vtbl, + 0x00000036_0000_0000_c000_000000000046 +); +impl windows_core::RuntimeType for IAsyncInfo { + const SIGNATURE: windows_core::imp::ConstBuffer = + windows_core::imp::ConstBuffer::for_interface::<Self>(); +} +windows_core::imp::interface_hierarchy!( + IAsyncInfo, + windows_core::IUnknown, + windows_core::IInspectable +); +impl IAsyncInfo { + pub fn Id(&self) -> windows_core::Result<u32> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Id)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Status(&self) -> windows_core::Result<AsyncStatus> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Status)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn ErrorCode(&self) -> windows_core::Result<windows_core::HRESULT> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).ErrorCode)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Cancel(&self) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Cancel)(windows_core::Interface::as_raw(this)) + .ok() + } + } + pub fn Close(&self) -> windows_core::Result<()> { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).Close)(windows_core::Interface::as_raw(this)) + .ok() + } + } +} +impl windows_core::RuntimeName for IAsyncInfo { + const NAME: &'static str = "Windows.Foundation.IAsyncInfo"; +} +pub trait IAsyncInfo_Impl: windows_core::IUnknownImpl { + fn Id(&self) -> windows_core::Result<u32>; + fn Status(&self) -> windows_core::Result<AsyncStatus>; + fn ErrorCode(&self) -> windows_core::Result<windows_core::HRESULT>; + fn Cancel(&self) -> windows_core::Result<()>; + fn Close(&self) -> windows_core::Result<()>; +} +impl IAsyncInfo_Vtbl { + pub const fn new<Identity: IAsyncInfo_Impl, const OFFSET: isize>() -> Self { + unsafe extern "system" fn Id<Identity: IAsyncInfo_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + result__: *mut u32, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncInfo_Impl::Id(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Status<Identity: IAsyncInfo_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + result__: *mut AsyncStatus, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncInfo_Impl::Status(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn ErrorCode<Identity: IAsyncInfo_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + result__: *mut windows_core::HRESULT, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncInfo_Impl::ErrorCode(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn Cancel<Identity: IAsyncInfo_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncInfo_Impl::Cancel(this).into() + } + } + unsafe extern "system" fn Close<Identity: IAsyncInfo_Impl, const OFFSET: isize>( + this: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncInfo_Impl::Close(this).into() + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::<Identity, IAsyncInfo, OFFSET>(), + Id: Id::<Identity, OFFSET>, + Status: Status::<Identity, OFFSET>, + ErrorCode: ErrorCode::<Identity, OFFSET>, + Cancel: Cancel::<Identity, OFFSET>, + Close: Close::<Identity, OFFSET>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAsyncInfo as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IAsyncInfo_Vtbl { + pub base__: windows_core::IInspectable_Vtbl, + pub Id: unsafe extern "system" fn(*mut core::ffi::c_void, *mut u32) -> windows_core::HRESULT, + pub Status: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut AsyncStatus, + ) -> windows_core::HRESULT, + pub ErrorCode: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut windows_core::HRESULT, + ) -> windows_core::HRESULT, + pub Cancel: unsafe extern "system" fn(*mut core::ffi::c_void) -> windows_core::HRESULT, + pub Close: unsafe extern "system" fn(*mut core::ffi::c_void) -> windows_core::HRESULT, +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IAsyncOperation<TResult>(windows_core::IUnknown, core::marker::PhantomData<TResult>) +where + TResult: windows_core::RuntimeType + 'static; +impl<TResult: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IUnknown> for IAsyncOperation<TResult> +{ +} +impl<TResult: windows_core::RuntimeType + 'static> + windows_core::imp::CanInto<windows_core::IInspectable> for IAsyncOperation<TResult> +{ +} +unsafe impl<TResult: windows_core::RuntimeType + 'static> windows_core::Interface + for IAsyncOperation<TResult> +{ + type Vtable = IAsyncOperation_Vtbl<TResult>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl<TResult: windows_core::RuntimeType + 'static> windows_core::RuntimeType + for IAsyncOperation<TResult> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({9fc2b0bb-e446-44e2-aa61-9cab8f636af2}") + .push_slice(b";") + .push_other(TResult::SIGNATURE) + .push_slice(b")"); +} +impl<TResult: windows_core::RuntimeType + 'static> windows_core::imp::CanInto<IAsyncInfo> + for IAsyncOperation<TResult> +{ + const QUERY: bool = true; +} +impl<TResult: windows_core::RuntimeType + 'static> IAsyncOperation<TResult> { + pub fn SetCompleted<P0>(&self, handler: P0) -> windows_core::Result<()> + where + P0: windows_core::Param<AsyncOperationCompletedHandler<TResult>>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).SetCompleted)( + windows_core::Interface::as_raw(this), + handler.param().abi(), + ) + .ok() + } + } + pub fn Completed(&self) -> windows_core::Result<AsyncOperationCompletedHandler<TResult>> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Completed)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn GetResults(&self) -> windows_core::Result<TResult> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetResults)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn Id(&self) -> windows_core::Result<u32> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Id)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Status(&self) -> windows_core::Result<AsyncStatus> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Status)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn ErrorCode(&self) -> windows_core::Result<windows_core::HRESULT> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).ErrorCode)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Cancel(&self) -> windows_core::Result<()> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + (windows_core::Interface::vtable(this).Cancel)(windows_core::Interface::as_raw(this)) + .ok() + } + } + pub fn Close(&self) -> windows_core::Result<()> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + (windows_core::Interface::vtable(this).Close)(windows_core::Interface::as_raw(this)) + .ok() + } + } +} +unsafe impl<TResult: windows_core::RuntimeType + 'static> Send for IAsyncOperation<TResult> {} +unsafe impl<TResult: windows_core::RuntimeType + 'static> Sync for IAsyncOperation<TResult> {} +impl<TResult: windows_core::RuntimeType + 'static> windows_core::RuntimeName + for IAsyncOperation<TResult> +{ + const NAME: &'static str = "Windows.Foundation.IAsyncOperation"; +} +pub trait IAsyncOperation_Impl<TResult>: IAsyncInfo_Impl +where + TResult: windows_core::RuntimeType + 'static, +{ + fn SetCompleted( + &self, + handler: windows_core::Ref<AsyncOperationCompletedHandler<TResult>>, + ) -> windows_core::Result<()>; + fn Completed(&self) -> windows_core::Result<AsyncOperationCompletedHandler<TResult>>; + fn GetResults(&self) -> windows_core::Result<TResult>; +} +impl<TResult: windows_core::RuntimeType + 'static> IAsyncOperation_Vtbl<TResult> { + pub const fn new<Identity: IAsyncOperation_Impl<TResult>, const OFFSET: isize>() -> Self { + unsafe extern "system" fn SetCompleted< + TResult: windows_core::RuntimeType + 'static, + Identity: IAsyncOperation_Impl<TResult>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + handler: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncOperation_Impl::SetCompleted(this, core::mem::transmute_copy(&handler)).into() + } + } + unsafe extern "system" fn Completed< + TResult: windows_core::RuntimeType + 'static, + Identity: IAsyncOperation_Impl<TResult>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncOperation_Impl::Completed(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn GetResults< + TResult: windows_core::RuntimeType + 'static, + Identity: IAsyncOperation_Impl<TResult>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut windows_core::AbiType<TResult>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncOperation_Impl::GetResults(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::< + Identity, + IAsyncOperation<TResult>, + OFFSET, + >(), + SetCompleted: SetCompleted::<TResult, Identity, OFFSET>, + Completed: Completed::<TResult, Identity, OFFSET>, + GetResults: GetResults::<TResult, Identity, OFFSET>, + TResult: core::marker::PhantomData::<TResult>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAsyncOperation<TResult> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IAsyncOperation_Vtbl<TResult> +where + TResult: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub SetCompleted: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub Completed: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub GetResults: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut windows_core::AbiType<TResult>, + ) -> windows_core::HRESULT, + TResult: core::marker::PhantomData<TResult>, +} +#[repr(transparent)] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct IAsyncOperationWithProgress<TResult, TProgress>( + windows_core::IUnknown, + core::marker::PhantomData<TResult>, + core::marker::PhantomData<TProgress>, +) +where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static; +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::imp::CanInto<windows_core::IUnknown> + for IAsyncOperationWithProgress<TResult, TProgress> +{ +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::imp::CanInto<windows_core::IInspectable> + for IAsyncOperationWithProgress<TResult, TProgress> +{ +} +unsafe impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::Interface for IAsyncOperationWithProgress<TResult, TProgress> +{ + type Vtable = IAsyncOperationWithProgress_Vtbl<TResult, TProgress>; + const IID: windows_core::GUID = + windows_core::GUID::from_signature(<Self as windows_core::RuntimeType>::SIGNATURE); +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::RuntimeType for IAsyncOperationWithProgress<TResult, TProgress> +{ + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::new() + .push_slice(b"pinterface({b5d036d7-e297-498f-ba60-0289e76e23dd}") + .push_slice(b";") + .push_other(TResult::SIGNATURE) + .push_slice(b";") + .push_other(TProgress::SIGNATURE) + .push_slice(b")"); +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::imp::CanInto<IAsyncInfo> for IAsyncOperationWithProgress<TResult, TProgress> +{ + const QUERY: bool = true; +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > IAsyncOperationWithProgress<TResult, TProgress> +{ + pub fn SetProgress<P0>(&self, handler: P0) -> windows_core::Result<()> + where + P0: windows_core::Param<AsyncOperationProgressHandler<TResult, TProgress>>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).SetProgress)( + windows_core::Interface::as_raw(this), + handler.param().abi(), + ) + .ok() + } + } + pub fn Progress( + &self, + ) -> windows_core::Result<AsyncOperationProgressHandler<TResult, TProgress>> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Progress)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn SetCompleted<P0>(&self, handler: P0) -> windows_core::Result<()> + where + P0: windows_core::Param<AsyncOperationWithProgressCompletedHandler<TResult, TProgress>>, + { + let this = self; + unsafe { + (windows_core::Interface::vtable(this).SetCompleted)( + windows_core::Interface::as_raw(this), + handler.param().abi(), + ) + .ok() + } + } + pub fn Completed( + &self, + ) -> windows_core::Result<AsyncOperationWithProgressCompletedHandler<TResult, TProgress>> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Completed)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn GetResults(&self) -> windows_core::Result<TResult> { + let this = self; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).GetResults)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .and_then(|| windows_core::Type::from_abi(result__)) + } + } + pub fn Id(&self) -> windows_core::Result<u32> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Id)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Status(&self) -> windows_core::Result<AsyncStatus> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).Status)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn ErrorCode(&self) -> windows_core::Result<windows_core::HRESULT> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + let mut result__ = core::mem::zeroed(); + (windows_core::Interface::vtable(this).ErrorCode)( + windows_core::Interface::as_raw(this), + &mut result__, + ) + .map(|| result__) + } + } + pub fn Cancel(&self) -> windows_core::Result<()> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + (windows_core::Interface::vtable(this).Cancel)(windows_core::Interface::as_raw(this)) + .ok() + } + } + pub fn Close(&self) -> windows_core::Result<()> { + let this = &windows_core::Interface::cast::<IAsyncInfo>(self)?; + unsafe { + (windows_core::Interface::vtable(this).Close)(windows_core::Interface::as_raw(this)) + .ok() + } + } +} +unsafe impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > Send for IAsyncOperationWithProgress<TResult, TProgress> +{ +} +unsafe impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > Sync for IAsyncOperationWithProgress<TResult, TProgress> +{ +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > windows_core::RuntimeName for IAsyncOperationWithProgress<TResult, TProgress> +{ + const NAME: &'static str = "Windows.Foundation.IAsyncOperationWithProgress"; +} +pub trait IAsyncOperationWithProgress_Impl<TResult, TProgress>: IAsyncInfo_Impl +where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, +{ + fn SetProgress( + &self, + handler: windows_core::Ref<AsyncOperationProgressHandler<TResult, TProgress>>, + ) -> windows_core::Result<()>; + fn Progress(&self) -> windows_core::Result<AsyncOperationProgressHandler<TResult, TProgress>>; + fn SetCompleted( + &self, + handler: windows_core::Ref<AsyncOperationWithProgressCompletedHandler<TResult, TProgress>>, + ) -> windows_core::Result<()>; + fn Completed( + &self, + ) -> windows_core::Result<AsyncOperationWithProgressCompletedHandler<TResult, TProgress>>; + fn GetResults(&self) -> windows_core::Result<TResult>; +} +impl< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + > IAsyncOperationWithProgress_Vtbl<TResult, TProgress> +{ + pub const fn new< + Identity: IAsyncOperationWithProgress_Impl<TResult, TProgress>, + const OFFSET: isize, + >() -> Self { + unsafe extern "system" fn SetProgress< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncOperationWithProgress_Impl<TResult, TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + handler: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncOperationWithProgress_Impl::SetProgress( + this, + core::mem::transmute_copy(&handler), + ) + .into() + } + } + unsafe extern "system" fn Progress< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncOperationWithProgress_Impl<TResult, TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncOperationWithProgress_Impl::Progress(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn SetCompleted< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncOperationWithProgress_Impl<TResult, TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + handler: *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + IAsyncOperationWithProgress_Impl::SetCompleted( + this, + core::mem::transmute_copy(&handler), + ) + .into() + } + } + unsafe extern "system" fn Completed< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncOperationWithProgress_Impl<TResult, TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncOperationWithProgress_Impl::Completed(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + unsafe extern "system" fn GetResults< + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, + Identity: IAsyncOperationWithProgress_Impl<TResult, TProgress>, + const OFFSET: isize, + >( + this: *mut core::ffi::c_void, + result__: *mut windows_core::AbiType<TResult>, + ) -> windows_core::HRESULT { + unsafe { + let this: &Identity = + &*((this as *const *const ()).offset(OFFSET) as *const Identity); + match IAsyncOperationWithProgress_Impl::GetResults(this) { + Ok(ok__) => { + result__.write(core::mem::transmute_copy(&ok__)); + core::mem::forget(ok__); + windows_core::HRESULT(0) + } + Err(err) => err.into(), + } + } + } + Self { + base__: windows_core::IInspectable_Vtbl::new::< + Identity, + IAsyncOperationWithProgress<TResult, TProgress>, + OFFSET, + >(), + SetProgress: SetProgress::<TResult, TProgress, Identity, OFFSET>, + Progress: Progress::<TResult, TProgress, Identity, OFFSET>, + SetCompleted: SetCompleted::<TResult, TProgress, Identity, OFFSET>, + Completed: Completed::<TResult, TProgress, Identity, OFFSET>, + GetResults: GetResults::<TResult, TProgress, Identity, OFFSET>, + TResult: core::marker::PhantomData::<TResult>, + TProgress: core::marker::PhantomData::<TProgress>, + } + } + pub fn matches(iid: &windows_core::GUID) -> bool { + iid == &<IAsyncOperationWithProgress<TResult, TProgress> as windows_core::Interface>::IID + } +} +#[repr(C)] +#[doc(hidden)] +pub struct IAsyncOperationWithProgress_Vtbl<TResult, TProgress> +where + TResult: windows_core::RuntimeType + 'static, + TProgress: windows_core::RuntimeType + 'static, +{ + pub base__: windows_core::IInspectable_Vtbl, + pub SetProgress: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub Progress: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub SetCompleted: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub Completed: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut *mut core::ffi::c_void, + ) -> windows_core::HRESULT, + pub GetResults: unsafe extern "system" fn( + *mut core::ffi::c_void, + *mut windows_core::AbiType<TResult>, + ) -> windows_core::HRESULT, + TResult: core::marker::PhantomData<TResult>, + TProgress: core::marker::PhantomData<TProgress>, +} diff --git a/third_party/rust/windows-future/src/bindings_impl.rs b/third_party/rust/windows-future/src/bindings_impl.rs @@ -0,0 +1,20 @@ +windows_link::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL); +windows_link::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE); +windows_link::link!("kernel32.dll" "system" fn SetEvent(hevent : HANDLE) -> BOOL); +windows_link::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT); +pub type BOOL = i32; +pub type HANDLE = *mut core::ffi::c_void; +pub type PCWSTR = *const u16; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct SECURITY_ATTRIBUTES { + pub nLength: u32, + pub lpSecurityDescriptor: *mut core::ffi::c_void, + pub bInheritHandle: BOOL, +} +impl Default for SECURITY_ATTRIBUTES { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} +pub type WAIT_EVENT = u32; diff --git a/third_party/rust/windows-future/src/future.rs b/third_party/rust/windows-future/src/future.rs @@ -0,0 +1,121 @@ +use super::*; +use std::future::{Future, IntoFuture}; +use std::pin::Pin; +use std::sync::{Arc, Mutex}; +use std::task::{Context, Poll, Waker}; + +// The `AsyncFuture` is needed to store some extra state needed to keep async execution up to date with possible changes +// to Rust execution context. Each async type implements `IntoFuture` rather than implementing `Future` directly so that +// this adapter may be used. +pub struct AsyncFuture<A: Async> { + // Represents the async execution and provides the virtual methods for setting up a `Completed` handler and + // calling `GetResults` when execution is completed. + inner: A, + + // Provides the `Status` virtual method and saves repeated calls to `QueryInterface` during polling. + status: IAsyncInfo, + + // A shared waker is needed to keep the `Completed` handler updated. + // - `Option` is used to avoid allocations for async objects that have already completed. + // - `Arc` is used to share the `Waker` with the `Completed` handler and potentially replace the `Waker` + // since we don't have the ability to replace the `Completed` handler itself. + // - `Mutex` is used to synchronize replacing the `Waker` across threads. + waker: Option<Arc<Mutex<Waker>>>, +} + +impl<A: Async> AsyncFuture<A> { + fn new(inner: A) -> Self { + Self { + // All four async interfaces implement `IAsyncInfo` so this `cast` will always succeed. + status: inner.cast().unwrap(), + inner, + waker: None, + } + } +} + +unsafe impl<A: Async> Send for AsyncFuture<A> {} +unsafe impl<A: Async> Sync for AsyncFuture<A> {} +impl<A: Async> Unpin for AsyncFuture<A> {} + +impl<A: Async> Future for AsyncFuture<A> { + type Output = Result<A::Output>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> { + // A status of `Started` just means async execution is still in flight. Since WinRT async is always + // "hot start", if its not `Started` then its ready for us to call `GetResults` so we can skip all of + // the remaining set up. + if self.status.Status()? != AsyncStatus::Started { + return Poll::Ready(self.inner.get_results()); + } + + if let Some(shared_waker) = &self.waker { + // We have a shared waker which means we're either getting polled again or been transferred to + // another execution context. As we can't tell the difference, we need to update the shared waker + // to make sure we've got the "current" waker. + let mut guard = shared_waker.lock().unwrap(); + guard.clone_from(cx.waker()); + + // It may be possible that the `Completed` handler acquired the lock and signaled the old waker + // before we managed to acquire the lock to update it with the current waker. We check the status + // again here just in case this happens. + if self.status.Status()? != AsyncStatus::Started { + return Poll::Ready(self.inner.get_results()); + } + } else { + // If we don't have a saved waker it means this is the first time we're getting polled and should + // create the shared waker and set up a `Completed` handler. + let shared_waker = Arc::new(Mutex::new(cx.waker().clone())); + self.waker = Some(shared_waker.clone()); + + // Note that the handler can only be set once, which is why we need a shared waker in the first + // place. On the other hand, the handler will get called even if async execution has already + // completed, so we can just return `Pending` after setting the Completed handler. + self.inner.set_completed(move |_| { + shared_waker.lock().unwrap().wake_by_ref(); + })?; + }; + + Poll::Pending + } +} + +// +// The four `IntoFuture` trait implementations. +// + +impl IntoFuture for IAsyncAction { + type Output = Result<()>; + type IntoFuture = AsyncFuture<Self>; + + fn into_future(self) -> Self::IntoFuture { + AsyncFuture::new(self) + } +} + +impl<T: RuntimeType> IntoFuture for IAsyncOperation<T> { + type Output = Result<T>; + type IntoFuture = AsyncFuture<Self>; + + fn into_future(self) -> Self::IntoFuture { + AsyncFuture::new(self) + } +} + +impl<P: RuntimeType> IntoFuture for IAsyncActionWithProgress<P> { + type Output = Result<()>; + type IntoFuture = AsyncFuture<Self>; + + fn into_future(self) -> Self::IntoFuture { + AsyncFuture::new(self) + } +} + +impl<T: RuntimeType, P: RuntimeType> IntoFuture for IAsyncOperationWithProgress<T, P> { + type Output = Result<T>; + type IntoFuture = AsyncFuture<Self>; + + fn into_future(self) -> Self::IntoFuture { + AsyncFuture::new(self) + } +} diff --git a/third_party/rust/windows-future/src/join.rs b/third_party/rust/windows-future/src/join.rs @@ -0,0 +1,29 @@ +use super::*; + +impl IAsyncAction { + /// Waits for the `IAsyncAction` to finish. + pub fn join(&self) -> Result<()> { + Async::join(self) + } +} + +impl<T: RuntimeType> IAsyncOperation<T> { + /// Waits for the `IAsyncOperation<T>` to finish. + pub fn join(&self) -> Result<T> { + Async::join(self) + } +} + +impl<P: RuntimeType> IAsyncActionWithProgress<P> { + /// Waits for the `IAsyncActionWithProgress<P>` to finish. + pub fn join(&self) -> Result<()> { + Async::join(self) + } +} + +impl<T: RuntimeType, P: RuntimeType> IAsyncOperationWithProgress<T, P> { + /// Waits for the `IAsyncOperationWithProgress<T, P>` to finish. + pub fn join(&self) -> Result<T> { + Async::join(self) + } +} diff --git a/third_party/rust/windows-future/src/lib.rs b/third_party/rust/windows-future/src/lib.rs @@ -0,0 +1,29 @@ +#![expect( + missing_docs, + non_snake_case, + non_camel_case_types, + non_upper_case_globals, + clippy::all +)] +#![doc = include_str!("../readme.md")] +#![cfg_attr(all(not(feature = "std")), no_std)] + +mod r#async; +mod bindings; +mod bindings_impl; +mod join; +mod waiter; +mod when; + +pub use bindings::*; +use bindings_impl::*; +use r#async::*; +use waiter::*; +use windows_core::*; + +#[cfg(feature = "std")] +mod async_ready; +#[cfg(feature = "std")] +mod async_spawn; +#[cfg(feature = "std")] +mod future; diff --git a/third_party/rust/windows-future/src/waiter.rs b/third_party/rust/windows-future/src/waiter.rs @@ -0,0 +1,41 @@ +use super::*; + +pub struct Waiter(HANDLE); +pub struct WaiterSignaler(HANDLE); +unsafe impl Send for WaiterSignaler {} + +impl Waiter { + pub fn new() -> crate::Result<(Self, WaiterSignaler)> { + unsafe { + let handle = CreateEventW(core::ptr::null(), 1, 0, core::ptr::null()); + if handle.is_null() { + Err(crate::Error::from_thread()) + } else { + Ok((Self(handle), WaiterSignaler(handle))) + } + } + } +} + +impl WaiterSignaler { + /// # Safety + /// Signals the `Waiter`. This is unsafe because the lifetime of `WaiterSignaler` is not tied + /// to the lifetime of the `Waiter`. This is not possible in this case because the `Waiter` + /// is used to signal a WinRT async completion and the compiler doesn't know that the lifetime + /// of the delegate is bounded by the calling function. + pub unsafe fn signal(&self) { + // https://github.com/microsoft/windows-rs/pull/374#discussion_r535313344 + unsafe { + SetEvent(self.0); + } + } +} + +impl Drop for Waiter { + fn drop(&mut self) { + unsafe { + WaitForSingleObject(self.0, 0xFFFFFFFF); + CloseHandle(self.0); + } + } +} diff --git a/third_party/rust/windows-future/src/when.rs b/third_party/rust/windows-future/src/when.rs @@ -0,0 +1,41 @@ +use super::*; + +impl IAsyncAction { + /// Calls `op(result)` when the `IAsyncAction` completes. + pub fn when<F>(&self, op: F) -> Result<()> + where + F: FnOnce(Result<()>) + Send + 'static, + { + Async::when(self, op) + } +} + +impl<T: RuntimeType> IAsyncOperation<T> { + /// Calls `op(result)` when the `IAsyncOperation<T>` completes. + pub fn when<F>(&self, op: F) -> Result<()> + where + F: FnOnce(Result<T>) + Send + 'static, + { + Async::when(self, op) + } +} + +impl<P: RuntimeType> IAsyncActionWithProgress<P> { + /// Calls `op(result)` when the `IAsyncActionWithProgress<P>` completes. + pub fn when<F>(&self, op: F) -> Result<()> + where + F: FnOnce(Result<()>) + Send + 'static, + { + Async::when(self, op) + } +} + +impl<T: RuntimeType, P: RuntimeType> IAsyncOperationWithProgress<T, P> { + /// Calls `op(result)` when the `IAsyncOperationWithProgress<T, P>` completes. + pub fn when<F>(&self, op: F) -> Result<()> + where + F: FnOnce(Result<T>) + Send + 'static, + { + Async::when(self, op) + } +} diff --git a/third_party/rust/windows-implement/.cargo-checksum.json b/third_party/rust/windows-implement/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"e2760c01e9e1b707bbe2ba1af6ddbc7555e3f6111eb4981fed6a1077afce1695","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","src/lib.rs":"d372c5fa2db9fe014e71ba3cd2c81a1b566571fbca2d6a6330f4e0d224bfa880"},"package":"2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"} -\ No newline at end of file +{"files":{"Cargo.lock":"f63019c61533e35927df3ee3d13c722cf0ab937a45df6097682e65842bc266f6","Cargo.toml":"46380b1aaaf5ea3b850f30ceefa9894cd29412feaf41dc7266a9d1577e7b26b0","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"f48fcb36893ad1bbe8c8c6e2cdb16da6e4f1447498555c1078cbdac92e762b3b","src/gen.rs":"ce704067089cf587556326a2502f9b050aaa7f83eb53d3707379236830429a20","src/lib.rs":"21655fb31ddb7e1489530b7625c3860222b8d8a0aaceb6a71b5964adbe36d81a","src/tests.rs":"ea34a27316c2c7440bdc41d03fa7a3426be344a238588d3728b490a44bfecc2e"},"package":"053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"} +\ No newline at end of file diff --git a/third_party/rust/windows-implement/Cargo.lock b/third_party/rust/windows-implement/Cargo.lock @@ -0,0 +1,47 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "windows-implement" +version = "0.60.2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/third_party/rust/windows-implement/Cargo.toml b/third_party/rust/windows-implement/Cargo.toml @@ -11,17 +11,18 @@ [package] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" name = "windows-implement" -version = "0.58.0" -authors = ["Microsoft"] +version = "0.60.2" build = false +autolib = false autobins = false autoexamples = false autotests = false autobenches = false -description = "The implement macro for the windows crate" -readme = false +description = "The implement macro for the Windows crates" +readme = "readme.md" +categories = ["os::windows-apis"] license = "MIT OR Apache-2.0" repository = "https://github.com/microsoft/windows-rs" @@ -36,9 +37,11 @@ proc-macro = true [dependencies.proc-macro2] version = "1.0" +default-features = false [dependencies.quote] version = "1.0" +default-features = false [dependencies.syn] version = "2.0" @@ -47,18 +50,16 @@ features = [ "proc-macro", "printing", "full", - "derive", + "clone-impls", ] default-features = false -[lints.rust] -missing_docs = "warn" +[dev-dependencies] -[lints.rust.rust_2018_idioms] -level = "warn" -priority = -1 +[lints.rust] +missing_unsafe_on_extern = "warn" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 -check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"] +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-implement/readme.md b/third_party/rust/windows-implement/readme.md @@ -0,0 +1,3 @@ +## The implement macro for the Windows crates + +See [windows-core](https://crates.io/crates/windows-core) for more information. diff --git a/third_party/rust/windows-implement/src/gen.rs b/third_party/rust/windows-implement/src/gen.rs @@ -0,0 +1,600 @@ +//! Generates output for the `implement` proc macro. +//! +//! Each function in this module focuses on generating one thing, or one kind of thing. +//! Each takes `ImplementInputs` as its input. `gen_all` calls all of the `gen_*` functions +//! and merges them into the final list of output items. +//! +//! We use `parse_quote` so that we can verify that a given function generates a well-formed AST +//! item, within the narrowest possible scope. This allows us to detect errors more quickly during +//! development. If the input to `parse_quote` cannot be parsed, then the macro will panic and +//! the panic will point to the specific `parse_quote` call, rather than the entire output of the +//! `implement` proc macro being unparsable. This greatly aids in development. + +use super::*; +use quote::{quote, quote_spanned}; +use syn::{parse_quote, parse_quote_spanned}; + +/// Generates code for the `#[implements]` macro. +pub(crate) fn gen_all(inputs: &ImplementInputs) -> Vec<syn::Item> { + let mut items: Vec<syn::Item> = Vec::with_capacity(64); + + items.push(gen_original_impl(inputs)); + items.push(gen_impl_struct(inputs)); + items.push(gen_impl_deref(inputs)); + items.push(gen_impl_impl(inputs)); + items.push(gen_iunknown_impl(inputs)); + items.push(gen_impl_com_object_inner(inputs)); + items.extend(gen_impl_from(inputs)); + items.extend(gen_impl_com_object_interfaces(inputs)); + + for (i, interface_chain) in inputs.interface_chains.iter().enumerate() { + items.push(gen_impl_as_impl(inputs, interface_chain, i)); + } + + items +} + +/// Generates an `impl` block for the original `Foo` type. +/// +/// This `impl` block will contain `into_outer` and `into_static` (if applicable). +fn gen_original_impl(inputs: &ImplementInputs) -> syn::Item { + let original_ident = &inputs.original_ident; + let generics = &inputs.generics; + let constraints = &inputs.constraints; + + let mut output: syn::ItemImpl = parse_quote! { + impl #generics #original_ident::#generics where #constraints {} + }; + + output.items.push(gen_into_outer(inputs)); + + // Static COM objects have a lot of constraints. They can't be generic (open parameters), + // because that would be meaningless (an open generic type cannot have a known representation). + // + // Right now, we can't generate static COM objects that have base classes because we rely on + // boxing and then unboxing during construction of aggregated types. + if !inputs.is_generic { + output.items.push(gen_into_static(inputs)); + } + + syn::Item::Impl(output) +} + +/// Generates the structure definition for the `Foo_Impl` type. +fn gen_impl_struct(inputs: &ImplementInputs) -> syn::Item { + let impl_ident = &inputs.impl_ident; + let generics = &inputs.generics; + let constraints = &inputs.constraints; + let original_ident = &inputs.original_ident; + let vis = &inputs.original_type.vis; + + let mut impl_fields = quote! { + identity: &'static ::windows_core::IInspectable_Vtbl, + }; + + for interface_chain in inputs.interface_chains.iter() { + let vtbl_ty = interface_chain.implement.to_vtbl_ident(); + let chain_field_ident = &interface_chain.field_ident; + impl_fields.extend(quote! { + #chain_field_ident: &'static #vtbl_ty, + }); + } + + impl_fields.extend(quote! { + this: #original_ident::#generics, + count: ::windows_core::imp::WeakRefCount, + }); + + parse_quote! { + #[repr(C)] + #[allow(non_camel_case_types)] + #vis struct #impl_ident #generics where #constraints { + #impl_fields + } + } +} + +/// Generates the implementation of `core::ops::Deref` for the generated `Foo_Impl` type. +fn gen_impl_deref(inputs: &ImplementInputs) -> syn::Item { + let generics = &inputs.generics; + let constraints = &inputs.constraints; + let original_ident = &inputs.original_type.ident; + let impl_ident = &inputs.impl_ident; + + parse_quote! { + impl #generics ::core::ops::Deref for #impl_ident::#generics where #constraints { + type Target = #original_ident::#generics; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.this + } + } + } +} + +/// Generates an `impl` block for the generated `Foo_Impl` block. +/// +/// This generates: +/// +/// ```rust,ignore +/// const VTABLE_IDENTITY = IInspectable_Vtbl = ...; +/// const VTABLE_INTERFACE1_IFOO: IFoo_Vtbl = ...; +/// const VTABLE_INTERFACE2_IBAR: IBar_Vtbl = ...; +/// ``` +/// +/// These constants are used when constructing vtables. The benefit of using constants instead +/// of directly generating these expressions is that it allows us to overcome limitations in +/// using generics in constant contexts. Right now, Rust has a lot of limitations around using +/// constants in constant contexts. Fortunately, associated constants (constants defined within +/// `impl` blocks) work in stable Rust, even for generic types. +fn gen_impl_impl(inputs: &ImplementInputs) -> syn::Item { + let impl_ident = &inputs.impl_ident; + let generics = &inputs.generics; + let constraints = &inputs.constraints; + + let mut output: syn::ItemImpl = parse_quote! { + impl #generics #impl_ident::#generics where #constraints {} + }; + + // This is here so that IInspectable::GetRuntimeClassName can work properly. + // For a test case for this, see crates/tests/misc/component_client. + let identity_type = if let Some(first) = inputs.interface_chains.first() { + first.implement.to_ident() + } else { + quote! { ::windows_core::IInspectable } + }; + + output.items.push(parse_quote! { + const VTABLE_IDENTITY: ::windows_core::IInspectable_Vtbl = + ::windows_core::IInspectable_Vtbl::new::< + #impl_ident::#generics, + #identity_type, + 0, + >(); + }); + + for (interface_index, interface_chain) in inputs.interface_chains.iter().enumerate() { + let vtbl_ty = interface_chain.implement.to_vtbl_ident(); + let vtable_const_ident = &interface_chain.vtable_const_ident; + + let chain_offset_in_pointers: isize = -1 - interface_index as isize; + output.items.push(parse_quote! { + const #vtable_const_ident: #vtbl_ty = #vtbl_ty::new::< + #impl_ident::#generics, + #chain_offset_in_pointers, + >(); + }); + } + + syn::Item::Impl(output) +} + +/// Generates the `IUnknownImpl` implementation for the `Foo_Impl` type. +fn gen_iunknown_impl(inputs: &ImplementInputs) -> syn::Item { + let generics = &inputs.generics; + let constraints = &inputs.constraints; + let impl_ident = &inputs.impl_ident; + let original_ident = &inputs.original_type.ident; + + let trust_level = proc_macro2::Literal::usize_unsuffixed(inputs.trust_level); + + let mut output: syn::ItemImpl = parse_quote! { + impl #generics ::windows_core::IUnknownImpl for #impl_ident::#generics where #constraints { + type Impl = #original_ident::#generics; + + #[inline(always)] + fn get_impl(&self) -> &Self::Impl { + &self.this + } + + #[inline(always)] + fn get_impl_mut(&mut self) -> &mut Self::Impl { + &mut self.this + } + + #[inline(always)] + fn into_inner(self) -> Self::Impl { + self.this + } + + #[inline(always)] + fn AddRef(&self) -> u32 { + self.count.add_ref() + } + + #[inline(always)] + unsafe fn Release(self_: *mut Self) -> u32 { + let remaining = (*self_).count.release(); + if remaining == 0 { + _ = ::windows_core::imp::Box::from_raw(self_); + } + remaining + } + + #[inline(always)] + fn is_reference_count_one(&self) -> bool { + self.count.is_one() + } + + unsafe fn GetTrustLevel(&self, value: *mut i32) -> ::windows_core::HRESULT { + if value.is_null() { + return ::windows_core::imp::E_POINTER; + } + *value = #trust_level; + ::windows_core::HRESULT(0) + } + + fn to_object(&self) -> ::windows_core::ComObject<Self::Impl> { + self.count.add_ref(); + unsafe { + ::windows_core::ComObject::from_raw( + ::core::ptr::NonNull::new_unchecked(self as *const Self as *mut Self) + ) + } + } + } + }; + + let query_interface_fn = gen_query_interface(inputs); + output.items.push(syn::ImplItem::Fn(query_interface_fn)); + + syn::Item::Impl(output) +} + +/// Generates the implementation of `ComObjectInner`. +fn gen_impl_com_object_inner(inputs: &ImplementInputs) -> syn::Item { + let original_ident = &inputs.original_type.ident; + let generics = &inputs.generics; + let constraints = &inputs.constraints; + let impl_ident = &inputs.impl_ident; + + parse_quote! { + impl #generics ::windows_core::ComObjectInner for #original_ident::#generics where #constraints { + type Outer = #impl_ident::#generics; + + // IMPORTANT! This function handles assembling the "boxed" type of a COM object. + // It immediately moves the box into a heap allocation (box) and returns only a ComObject + // reference that points to it. We intentionally _do not_ expose any owned instances of + // Foo_Impl to safe Rust code, because doing so would allow unsound behavior in safe Rust + // code, due to the adjustments of the reference count that Foo_Impl permits. + // + // This is why this function returns ComObject<Self> instead of returning #impl_ident. + + fn into_object(self) -> ::windows_core::ComObject<Self> { + let boxed = ::windows_core::imp::Box::<#impl_ident::#generics>::new(self.into_outer()); + unsafe { + let ptr = ::windows_core::imp::Box::into_raw(boxed); + ::windows_core::ComObject::from_raw( + ::core::ptr::NonNull::new_unchecked(ptr) + ) + } + } + } + } +} + +/// Generates the `query_interface` method. +fn gen_query_interface(inputs: &ImplementInputs) -> syn::ImplItemFn { + let queries = inputs.interface_chains.iter().map(|interface_chain| { + let chain_ty = interface_chain.implement.to_vtbl_ident(); + let chain_field = &interface_chain.field_ident; + quote_spanned! { + interface_chain.implement.span => + if #chain_ty::matches(&iid) { + break 'found &self.#chain_field as *const _ as *const ::core::ffi::c_void; + } + } + }); + + // Dynamic casting requires that the object not contain non-static lifetimes. + let enable_dyn_casting = inputs.original_type.generics.lifetimes().count() == 0; + let dynamic_cast_query = if enable_dyn_casting { + quote! { + if iid == ::windows_core::DYNAMIC_CAST_IID { + // DYNAMIC_CAST_IID is special. We _do not_ increase the reference count for this pseudo-interface. + // Also, instead of returning an interface pointer, we simply write the `&dyn Any` directly to the + // 'interface' pointer. Since the size of `&dyn Any` is 2 pointers, not one, the caller must be + // prepared for this. This is not a normal QueryInterface call. + // + // See the `Interface::cast_to_any` method, which is the only caller that should use DYNAMIC_CAST_ID. + (interface as *mut *const dyn core::any::Any).write(self as &dyn ::core::any::Any as *const dyn ::core::any::Any); + return ::windows_core::HRESULT(0); + } + } + } else { + quote!() + }; + + let identity_query = if inputs.agile { + quote! { + if iid == <::windows_core::IUnknown as ::windows_core::Interface>::IID + || iid == <::windows_core::IInspectable as ::windows_core::Interface>::IID + || iid == <::windows_core::imp::IAgileObject as ::windows_core::Interface>::IID { + break 'found &self.identity as *const _ as *const ::core::ffi::c_void; + } + } + } else { + quote! { + if iid == <::windows_core::IUnknown as ::windows_core::Interface>::IID + || iid == <::windows_core::IInspectable as ::windows_core::Interface>::IID { + break 'found &self.identity as *const _ as *const ::core::ffi::c_void; + } + } + }; + + let marshal_query = if inputs.agile { + quote! { + #[cfg(windows)] + if iid == <::windows_core::imp::IMarshal as ::windows_core::Interface>::IID { + return ::windows_core::imp::marshaler(self.to_interface(), interface); + } + } + } else { + quote! {} + }; + + let tear_off_query = quote! { + let tear_off_ptr = self.count.query(&iid, &self.identity as *const _ as *mut _); + if !tear_off_ptr.is_null() { + *interface = tear_off_ptr; + return ::windows_core::HRESULT(0); + } + }; + + parse_quote! { + unsafe fn QueryInterface( + &self, + iid: *const ::windows_core::GUID, + interface: *mut *mut ::core::ffi::c_void, + ) -> ::windows_core::HRESULT { + unsafe { + if iid.is_null() || interface.is_null() { + return ::windows_core::imp::E_POINTER; + } + + let iid = *iid; + + let interface_ptr: *const ::core::ffi::c_void = 'found: { + #identity_query + #(#queries)* + #marshal_query + #dynamic_cast_query + #tear_off_query + + *interface = ::core::ptr::null_mut(); + return ::windows_core::imp::E_NOINTERFACE; + }; + + debug_assert!(!interface_ptr.is_null()); + *interface = interface_ptr as *mut ::core::ffi::c_void; + self.count.add_ref(); + return ::windows_core::HRESULT(0); + } + } + } +} + +/// Generates the `T::into_outer` function. This function is part of how we construct a +/// `ComObject<T>` from a `T`. +fn gen_into_outer(inputs: &ImplementInputs) -> syn::ImplItem { + let generics = &inputs.generics; + let impl_ident = &inputs.impl_ident; + + let mut initializers = quote! { + identity: &#impl_ident::#generics::VTABLE_IDENTITY, + }; + + for interface_chain in inputs.interface_chains.iter() { + let vtbl_field_ident = &interface_chain.field_ident; + let vtable_const_ident = &interface_chain.vtable_const_ident; + + initializers.extend(quote_spanned! { + interface_chain.implement.span => + #vtbl_field_ident: &#impl_ident::#generics::#vtable_const_ident, + }); + } + + // If the type is generic then into_outer() cannot be a const fn. + let maybe_const = if inputs.is_generic { + quote!() + } else { + quote!(const) + }; + + parse_quote! { + // This constructs an "outer" object. This should only be used by the implementation + // of the outer object, never by application code. + // + // The callers of this function (`into_static` and `into_object`) are both responsible + // for maintaining one of our invariants: Application code never has an owned instance + // of the outer (implementation) type. into_static() maintains this invariant by + // returning a wrapped StaticComObject value, which owns its contents but never gives + // application code a way to mutably access its contents. This prevents the refcount + // shearing problem. + // + // TODO: Make it impossible for app code to call this function, by placing it in a + // module and marking this as private to the module. + #[inline(always)] + #maybe_const fn into_outer(self) -> #impl_ident::#generics { + #impl_ident::#generics { + #initializers + count: ::windows_core::imp::WeakRefCount::new(), + this: self, + } + } + } +} + +/// Generates the `T::into_static` function. This function is part of how we construct a +/// `StaticComObject<T>` from a `T`. +fn gen_into_static(inputs: &ImplementInputs) -> syn::ImplItem { + assert!(!inputs.is_generic); + parse_quote! { + /// This converts a partially-constructed COM object (in the sense that it contains + /// application state but does not yet have vtable and reference count constructed) + /// into a `StaticComObject`. This allows the COM object to be stored in static + /// (global) variables. + pub const fn into_static(self) -> ::windows_core::StaticComObject<Self> { + ::windows_core::StaticComObject::from_outer(self.into_outer()) + } + } +} + +/// Generates `From`-based conversions. +/// +/// These conversions convert from the user's type `T` to `ComObject<T>` or to an interface +/// implemented by `T`. These conversions are shorthand for calling `ComObject::new(value)`. +/// +/// We can only generate conversions from `T` to the roots of each interface chain. We can't +/// generate `From` conversions from `T` to an interface that is inherited by an interface chain, +/// because this proc macro does not have access to any information about the inheritance chain +/// of interfaces that are referenced. +/// +/// For example: +/// +/// ```rust,ignore +/// #[implement(IFoo3)] +/// struct MyType; +/// ``` +/// +/// If `IFoo3` inherits from `IFoo2`, then this code will _not_ generate a conversion for `IFoo2`. +/// However, user code can still do this: +/// +/// ```rust,ignore +/// let ifoo2 = IFoo3::from(MyType).into(); +/// ``` +/// +/// This works because the `IFoo3` type has an `Into` impl for `IFoo2`. +fn gen_impl_from(inputs: &ImplementInputs) -> Vec<syn::Item> { + let mut items = Vec::new(); + + let original_ident = &inputs.original_type.ident; + let generics = &inputs.generics; + let constraints = &inputs.constraints; + + items.push(parse_quote! { + impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IUnknown where #constraints { + #[inline(always)] + fn from(this: #original_ident::#generics) -> Self { + let com_object = ::windows_core::ComObject::new(this); + com_object.into_interface() + } + } + }); + + items.push(parse_quote! { + impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IInspectable where #constraints { + #[inline(always)] + fn from(this: #original_ident::#generics) -> Self { + let com_object = ::windows_core::ComObject::new(this); + com_object.into_interface() + } + } + }); + + for interface_chain in inputs.interface_chains.iter() { + let interface_ident = interface_chain.implement.to_ident(); + + items.push(parse_quote_spanned! { + interface_chain.implement.span => + impl #generics ::core::convert::From<#original_ident::#generics> for #interface_ident where #constraints { + #[inline(always)] + fn from(this: #original_ident::#generics) -> Self { + let com_object = ::windows_core::ComObject::new(this); + com_object.into_interface() + } + } + }); + } + + items +} + +/// Generates the `ComObjectInterface` implementation for each interface chain. +/// +/// Each of these `impl` blocks says "this COM object implements this COM interface". +/// It allows the `ComObject` type to do conversions from the `ComObject` to `IFoo` instances, +/// _without_ doing a `QueryInterface` call. +fn gen_impl_com_object_interfaces(inputs: &ImplementInputs) -> Vec<syn::Item> { + let mut items = Vec::new(); + + let generics = &inputs.generics; + let constraints = &inputs.constraints; + let impl_ident = &inputs.impl_ident; + + items.push(parse_quote! { + impl #generics ::windows_core::ComObjectInterface<::windows_core::IUnknown> for #impl_ident::#generics where #constraints { + #[inline(always)] + fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IUnknown> { + unsafe { + let interface_ptr = &self.identity; + ::core::mem::transmute(interface_ptr) + } + } + } + }); + + items.push(parse_quote! { + impl #generics ::windows_core::ComObjectInterface<::windows_core::IInspectable> for #impl_ident::#generics where #constraints { + #[inline(always)] + fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IInspectable> { + unsafe { + let interface_ptr = &self.identity; + ::core::mem::transmute(interface_ptr) + } + } + } + }); + + for interface_chain in inputs.interface_chains.iter() { + let chain_field = &interface_chain.field_ident; + let interface_ident = interface_chain.implement.to_ident(); + + items.push(parse_quote_spanned! { + interface_chain.implement.span => + #[allow(clippy::needless_lifetimes)] + impl #generics ::windows_core::ComObjectInterface<#interface_ident> for #impl_ident::#generics where #constraints { + #[inline(always)] + fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, #interface_ident> { + unsafe { + ::core::mem::transmute(&self.#chain_field) + } + } + } + }); + } + + items +} + +/// Generates the implementation of the `AsImpl` trait for a given interface chain. +fn gen_impl_as_impl( + inputs: &ImplementInputs, + interface_chain: &InterfaceChain, + interface_chain_index: usize, +) -> syn::Item { + let generics = &inputs.generics; + let constraints = &inputs.constraints; + let interface_ident = interface_chain.implement.to_ident(); + let original_ident = &inputs.original_type.ident; + let impl_ident = &inputs.impl_ident; + + parse_quote_spanned! { + interface_chain.implement.span => + impl #generics ::windows_core::AsImpl<#original_ident::#generics> for #interface_ident where #constraints { + // SAFETY: the offset is guaranteed to be in bounds, and the implementation struct + // is guaranteed to live at least as long as `self`. + #[inline(always)] + unsafe fn as_impl_ptr(&self) -> ::core::ptr::NonNull<#original_ident::#generics> { + unsafe { + let this = ::windows_core::Interface::as_raw(self); + // Subtract away the vtable offset plus 1, for the `identity` field, to get + // to the impl struct which contains that original implementation type. + let this = (this as *mut *mut ::core::ffi::c_void).sub(1 + #interface_chain_index) as *mut #impl_ident::#generics; + ::core::ptr::NonNull::new_unchecked(::core::ptr::addr_of!((*this).this) as *const #original_ident::#generics as *mut #original_ident::#generics) + } + } + } + } +} diff --git a/third_party/rust/windows-implement/src/lib.rs b/third_party/rust/windows-implement/src/lib.rs @@ -1,16 +1,23 @@ -/*! -Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs> -*/ +//! Implement COM interfaces for Rust types. +//! +//! Take a look at [macro@implement] for an example. +//! +//! Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs> use quote::{quote, ToTokens}; +mod r#gen; +use r#gen::gen_all; + +#[cfg(test)] +mod tests; + /// Implements one or more COM interfaces. /// /// # Example +/// ```rust,no_run +/// use windows_core::*; /// -/// Here is a [more complete tutorial](https://kennykerr.ca/rust-getting-started/how-to-implement-com-interface.html). -/// -/// ```rust,ignore /// #[interface("094d70d6-5202-44b8-abb8-43860da5aca2")] /// unsafe trait IValue: IUnknown { /// fn GetValue(&self, value: *mut i32) -> HRESULT; @@ -19,377 +26,115 @@ use quote::{quote, ToTokens}; /// #[implement(IValue)] /// struct Value(i32); /// -/// impl IValue_Impl for Value { +/// impl IValue_Impl for Value_Impl { /// unsafe fn GetValue(&self, value: *mut i32) -> HRESULT { /// *value = self.0; /// HRESULT(0) /// } /// } /// -/// fn main() { -/// let rust_instance = Value(123); -/// let com_object: IValue = rust_instance.into(); -/// // You can now call interface methods on com_object. -/// } +/// let object: IValue = Value(123).into(); +/// // Call interface methods... /// ``` #[proc_macro_attribute] pub fn implement( attributes: proc_macro::TokenStream, - original_type: proc_macro::TokenStream, + type_tokens: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - let attributes = syn::parse_macro_input!(attributes as ImplementAttributes); - let interfaces_len = proc_macro2::Literal::usize_unsuffixed(attributes.implement.len()); - - let identity_type = if let Some(first) = attributes.implement.first() { - first.to_ident() - } else { - quote! { ::windows_core::IInspectable } - }; - - let original_type2 = original_type.clone(); - let original_type2 = syn::parse_macro_input!(original_type2 as syn::ItemStruct); - let vis = &original_type2.vis; - let original_ident = &original_type2.ident; - let mut constraints = quote! {}; - - if let Some(where_clause) = &original_type2.generics.where_clause { - where_clause.predicates.to_tokens(&mut constraints); - } - - let generics = if original_type2.generics.lt_token.is_some() { - let mut params = quote! {}; - original_type2.generics.params.to_tokens(&mut params); - quote! { <#params> } - } else { - quote! { <> } - }; - - let impl_ident = quote::format_ident!("{}_Impl", original_ident); - let vtbl_idents = attributes - .implement - .iter() - .map(|implement| implement.to_vtbl_ident()); - let vtbl_idents2 = vtbl_idents.clone(); - - let vtable_news = attributes - .implement - .iter() - .enumerate() - .map(|(enumerate, implement)| { - let vtbl_ident = implement.to_vtbl_ident(); - let offset = proc_macro2::Literal::isize_unsuffixed(-1 - enumerate as isize); - quote! { #vtbl_ident::new::<Self, #offset>() } - }); - - let offset = attributes - .implement - .iter() - .enumerate() - .map(|(offset, _)| proc_macro2::Literal::usize_unsuffixed(offset)); - - let queries = attributes - .implement - .iter() - .enumerate() - .map(|(count, implement)| { - let vtbl_ident = implement.to_vtbl_ident(); - let offset = proc_macro2::Literal::usize_unsuffixed(count); - quote! { - else if #vtbl_ident::matches(iid) { - &self.vtables.#offset as *const _ as *mut _ - } - } - }); + implement_core(attributes.into(), type_tokens.into()).into() +} - // Dynamic casting requires that the object not contain non-static lifetimes. - let enable_dyn_casting = original_type2.generics.lifetimes().count() == 0; - let dynamic_cast_query = if enable_dyn_casting { - quote! { - else if *iid == ::windows_core::DYNAMIC_CAST_IID { - // DYNAMIC_CAST_IID is special. We _do not_ increase the reference count for this pseudo-interface. - // Also, instead of returning an interface pointer, we simply write the `&dyn Any` directly to the - // 'interface' pointer. Since the size of `&dyn Any` is 2 pointers, not one, the caller must be - // prepared for this. This is not a normal QueryInterface call. - // - // See the `Interface::cast_to_any` method, which is the only caller that should use DYNAMIC_CAST_ID. - (interface as *mut *const dyn core::any::Any).write(self as &dyn ::core::any::Any as *const dyn ::core::any::Any); - return ::windows_core::HRESULT(0); +fn implement_core( + attributes: proc_macro2::TokenStream, + item_tokens: proc_macro2::TokenStream, +) -> proc_macro2::TokenStream { + let attributes = syn::parse2::<ImplementAttributes>(attributes).unwrap(); + let original_type = syn::parse2::<syn::ItemStruct>(item_tokens).unwrap(); + + // Do a little thinking and assemble ImplementInputs. We pass ImplementInputs to + // all of our gen_* function. + let inputs = ImplementInputs { + original_ident: original_type.ident.clone(), + interface_chains: convert_implements_to_interface_chains(attributes.implement), + trust_level: attributes.trust_level, + agile: attributes.agile, + impl_ident: quote::format_ident!("{}_Impl", &original_type.ident), + constraints: { + if let Some(where_clause) = &original_type.generics.where_clause { + where_clause.predicates.to_token_stream() + } else { + quote!() } - } - } else { - quote!() + }, + generics: if !original_type.generics.params.is_empty() { + let mut params = quote! {}; + original_type.generics.params.to_tokens(&mut params); + quote! { <#params> } + } else { + quote! { <> } + }, + is_generic: !original_type.generics.params.is_empty(), + original_type, }; - // The distance from the beginning of the generated type to the 'this' field, in units of pointers (not bytes). - let offset_of_this_in_pointers = 1 + attributes.implement.len(); - let offset_of_this_in_pointers_token = - proc_macro2::Literal::usize_unsuffixed(offset_of_this_in_pointers); - - let trust_level = proc_macro2::Literal::usize_unsuffixed(attributes.trust_level); - - let conversions = attributes.implement.iter().enumerate().map(|(enumerate, implement)| { - let interface_ident = implement.to_ident(); - let offset = proc_macro2::Literal::usize_unsuffixed(enumerate); - quote! { - impl #generics ::core::convert::From<#original_ident::#generics> for #interface_ident where #constraints { - #[inline(always)] - fn from(this: #original_ident::#generics) -> Self { - let com_object = ::windows_core::ComObject::new(this); - com_object.into_interface() - } - } - - impl #generics ::windows_core::ComObjectInterface<#interface_ident> for #impl_ident::#generics where #constraints { - #[inline(always)] - fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, #interface_ident> { - unsafe { - let interface_ptr = &self.vtables.#offset; - ::core::mem::transmute(interface_ptr) - } - } - } - - impl #generics ::windows_core::AsImpl<#original_ident::#generics> for #interface_ident where #constraints { - // SAFETY: the offset is guranteed to be in bounds, and the implementation struct - // is guaranteed to live at least as long as `self`. - #[inline(always)] - unsafe fn as_impl_ptr(&self) -> ::core::ptr::NonNull<#original_ident::#generics> { - let this = ::windows_core::Interface::as_raw(self); - // Subtract away the vtable offset plus 1, for the `identity` field, to get - // to the impl struct which contains that original implementation type. - let this = (this as *mut *mut ::core::ffi::c_void).sub(1 + #offset) as *mut #impl_ident::#generics; - ::core::ptr::NonNull::new_unchecked(::core::ptr::addr_of!((*this).this) as *const #original_ident::#generics as *mut #original_ident::#generics) - } - } - } - }); - - let tokens = quote! { - #[repr(C)] - #[allow(non_camel_case_types)] - #vis struct #impl_ident #generics where #constraints { - identity: &'static ::windows_core::IInspectable_Vtbl, - vtables: (#(&'static #vtbl_idents,)*), - this: #original_ident::#generics, - count: ::windows_core::imp::WeakRefCount, - } - - impl #generics #impl_ident::#generics where #constraints { - const VTABLES: (#(#vtbl_idents2,)*) = (#(#vtable_news,)*); - const IDENTITY: ::windows_core::IInspectable_Vtbl = ::windows_core::IInspectable_Vtbl::new::<Self, #identity_type, 0>(); - } - - impl #generics ::windows_core::ComObjectInner for #original_ident::#generics where #constraints { - type Outer = #impl_ident::#generics; - - // IMPORTANT! This function handles assembling the "boxed" type of a COM object. - // It immediately moves the box into a heap allocation (box) and returns only a ComObject - // reference that points to it. We intentionally _do not_ expose any owned instances of - // Foo_Impl to safe Rust code, because doing so would allow unsound behavior in safe Rust - // code, due to the adjustments of the reference count that Foo_Impl permits. - // - // This is why this function returns ComObject<Self> instead of returning #impl_ident. - - fn into_object(self) -> ::windows_core::ComObject<Self> { - let boxed = ::windows_core::imp::Box::new(#impl_ident::#generics { - identity: &#impl_ident::#generics::IDENTITY, - vtables: (#(&#impl_ident::#generics::VTABLES.#offset,)*), - this: self, - count: ::windows_core::imp::WeakRefCount::new(), - }); - unsafe { - let ptr = ::windows_core::imp::Box::into_raw(boxed); - ::windows_core::ComObject::from_raw( - ::core::ptr::NonNull::new_unchecked(ptr) - ) - } - } - } - - impl #generics ::windows_core::IUnknownImpl for #impl_ident::#generics where #constraints { - type Impl = #original_ident::#generics; - - #[inline(always)] - fn get_impl(&self) -> &Self::Impl { - &self.this - } - - #[inline(always)] - fn get_impl_mut(&mut self) -> &mut Self::Impl { - &mut self.this - } - - #[inline(always)] - fn is_reference_count_one(&self) -> bool { - self.count.is_one() - } - - #[inline(always)] - fn into_inner(self) -> Self::Impl { - self.this - } - - unsafe fn QueryInterface(&self, iid: *const ::windows_core::GUID, interface: *mut *mut ::core::ffi::c_void) -> ::windows_core::HRESULT { - if iid.is_null() || interface.is_null() { - return ::windows_core::imp::E_POINTER; - } - - let iid = &*iid; - - let interface_ptr: *mut ::core::ffi::c_void = if iid == &<::windows_core::IUnknown as ::windows_core::Interface>::IID - || iid == &<::windows_core::IInspectable as ::windows_core::Interface>::IID - || iid == &<::windows_core::imp::IAgileObject as ::windows_core::Interface>::IID { - &self.identity as *const _ as *mut _ - } - #(#queries)* - #dynamic_cast_query - else { - ::core::ptr::null_mut() - }; - - if !interface_ptr.is_null() { - *interface = interface_ptr; - self.count.add_ref(); - return ::windows_core::HRESULT(0); - } - - let interface_ptr = self.count.query(iid, &self.identity as *const _ as *mut _); - *interface = interface_ptr; - - if interface_ptr.is_null() { - ::windows_core::imp::E_NOINTERFACE - } else { - ::windows_core::HRESULT(0) - } - } + let items = gen_all(&inputs); + let mut tokens = inputs.original_type.into_token_stream(); + for item in items { + tokens.extend(item.into_token_stream()); + } - #[inline(always)] - fn AddRef(&self) -> u32 { - self.count.add_ref() - } + tokens +} - #[inline(always)] - unsafe fn Release(self_: *mut Self) -> u32 { - let remaining = (*self_).count.release(); - if remaining == 0 { - _ = ::windows_core::imp::Box::from_raw(self_); - } - remaining - } +/// This provides the inputs to the `gen_*` functions, which generate the proc macro output. +struct ImplementInputs { + /// The user's type that was marked with `#[implement]`. + original_type: syn::ItemStruct, - unsafe fn GetTrustLevel(&self, value: *mut i32) -> ::windows_core::HRESULT { - if value.is_null() { - return ::windows_core::imp::E_POINTER; - } - *value = #trust_level; - ::windows_core::HRESULT(0) - } + /// The identifier for the user's original type definition. + original_ident: syn::Ident, - unsafe fn from_inner_ref(inner: &Self::Impl) -> &Self { - &*((inner as *const Self::Impl as *const *const ::core::ffi::c_void) - .sub(#offset_of_this_in_pointers_token) as *const Self) - } + /// The list of interface chains that this type implements. + interface_chains: Vec<InterfaceChain>, - fn to_object(&self) -> ::windows_core::ComObject<Self::Impl> { - self.count.add_ref(); - unsafe { - ::windows_core::ComObject::from_raw( - ::core::ptr::NonNull::new_unchecked(self as *const Self as *mut Self) - ) - } - } + /// The "trust level", which is returned by `IInspectable::GetTrustLevel`. + trust_level: usize, - const INNER_OFFSET_IN_POINTERS: usize = #offset_of_this_in_pointers_token; - } + /// Determines whether `IAgileObject` and `IMarshal` are implemented automatically. + agile: bool, - impl #generics #original_ident::#generics where #constraints { - /// Try casting as the provided interface - /// - /// # Safety - /// - /// This function can only be safely called if `self` has been heap allocated and pinned using - /// the mechanisms provided by `implement` macro. - #[inline(always)] - unsafe fn cast<I: ::windows_core::Interface>(&self) -> ::windows_core::Result<I> { - let boxed = (self as *const _ as *const *mut ::core::ffi::c_void).sub(1 + #interfaces_len) as *mut #impl_ident::#generics; - let mut result = ::core::ptr::null_mut(); - _ = <#impl_ident::#generics as ::windows_core::IUnknownImpl>::QueryInterface(&*boxed, &I::IID, &mut result); - ::windows_core::Type::from_abi(result) - } - } + /// The identifier of the `Foo_Impl` type. + impl_ident: syn::Ident, - impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IUnknown where #constraints { - #[inline(always)] - fn from(this: #original_ident::#generics) -> Self { - let com_object = ::windows_core::ComObject::new(this); - com_object.into_interface() - } - } - - impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IInspectable where #constraints { - #[inline(always)] - fn from(this: #original_ident::#generics) -> Self { - let com_object = ::windows_core::ComObject::new(this); - com_object.into_interface() - } - } - - impl #generics ::windows_core::ComObjectInterface<::windows_core::IUnknown> for #impl_ident::#generics where #constraints { - #[inline(always)] - fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IUnknown> { - unsafe { - let interface_ptr = &self.identity; - ::core::mem::transmute(interface_ptr) - } - } - } - - impl #generics ::windows_core::ComObjectInterface<::windows_core::IInspectable> for #impl_ident::#generics where #constraints { - #[inline(always)] - fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IInspectable> { - unsafe { - let interface_ptr = &self.identity; - ::core::mem::transmute(interface_ptr) - } - } - } - - impl #generics ::windows_core::AsImpl<#original_ident::#generics> for ::windows_core::IUnknown where #constraints { - // SAFETY: the offset is guranteed to be in bounds, and the implementation struct - // is guaranteed to live at least as long as `self`. - #[inline(always)] - unsafe fn as_impl_ptr(&self) -> ::core::ptr::NonNull<#original_ident::#generics> { - let this = ::windows_core::Interface::as_raw(self); - // Subtract away the vtable offset plus 1, for the `identity` field, to get - // to the impl struct which contains that original implementation type. - let this = (this as *mut *mut ::core::ffi::c_void).sub(1) as *mut #impl_ident::#generics; - ::core::ptr::NonNull::new_unchecked(::core::ptr::addr_of!((*this).this) as *const #original_ident::#generics as *mut #original_ident::#generics) - } - } + /// The list of constraints needed for this `Foo_Impl` type. + constraints: proc_macro2::TokenStream, - impl #generics ::core::ops::Deref for #impl_ident::#generics where #constraints { - type Target = #original_ident::#generics; + /// The list of generic parameters for this `Foo_Impl` type, including `<` and `>`. + /// If there are no generics, this contains `<>`. + generics: proc_macro2::TokenStream, - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.this - } - } + /// True if the user type has any generic parameters. + is_generic: bool, +} - // We intentionally do not provide a DerefMut impl, due to paranoia around soundness. +/// Describes one COM interface chain. +struct InterfaceChain { + /// The name of the field for the vtable chain, e.g. `interface4_ifoo`. + field_ident: syn::Ident, - #(#conversions)* - }; + /// The name of the associated constant item for the vtable chain's initializer, + /// e.g. `INTERFACE4_IFOO_VTABLE`. + vtable_const_ident: syn::Ident, - let mut tokens: proc_macro::TokenStream = tokens.into(); - tokens.extend(core::iter::once(original_type)); - tokens + implement: ImplementType, } -#[derive(Default)] struct ImplementType { type_name: String, generics: Vec<ImplementType>, + + /// The best span for diagnostics. + span: proc_macro2::Span, } impl ImplementType { @@ -411,11 +156,15 @@ impl ImplementType { struct ImplementAttributes { pub implement: Vec<ImplementType>, pub trust_level: usize, + pub agile: bool, } impl syn::parse::Parse for ImplementAttributes { - fn parse(cursor: syn::parse::ParseStream<'_>) -> syn::parse::Result<Self> { - let mut input = Self::default(); + fn parse(cursor: syn::parse::ParseStream) -> syn::parse::Result<Self> { + let mut input = Self { + agile: true, + ..Default::default() + }; while !cursor.is_empty() { input.parse_implement(cursor)?; @@ -426,7 +175,7 @@ impl syn::parse::Parse for ImplementAttributes { } impl ImplementAttributes { - fn parse_implement(&mut self, cursor: syn::parse::ParseStream<'_>) -> syn::parse::Result<()> { + fn parse_implement(&mut self, cursor: syn::parse::ParseStream) -> syn::parse::Result<()> { let tree = cursor.parse::<UseTree2>()?; self.walk_implement(&tree, &mut String::new())?; @@ -460,6 +209,7 @@ impl ImplementAttributes { } } UseTree2::TrustLevel(input) => self.trust_level = *input, + UseTree2::Agile(agile) => self.agile = *agile, } Ok(()) @@ -471,12 +221,13 @@ enum UseTree2 { Name(UseName2), Group(UseGroup2), TrustLevel(usize), + Agile(bool), } impl UseTree2 { fn to_element_type(&self, namespace: &mut String) -> syn::parse::Result<ImplementType> { match self { - UseTree2::Path(input) => { + Self::Path(input) => { if !namespace.is_empty() { namespace.push_str("::"); } @@ -484,8 +235,9 @@ impl UseTree2 { namespace.push_str(&input.ident.to_string()); input.tree.to_element_type(namespace) } - UseTree2::Name(input) => { + Self::Name(input) => { let mut type_name = input.ident.to_string(); + let span = input.ident.span(); if !namespace.is_empty() { type_name = format!("{namespace}::{type_name}"); @@ -500,9 +252,10 @@ impl UseTree2 { Ok(ImplementType { type_name, generics, + span, }) } - UseTree2::Group(input) => Err(syn::parse::Error::new( + Self::Group(input) => Err(syn::parse::Error::new( input.brace_token.span.join(), "Syntax not supported", )), @@ -527,41 +280,54 @@ struct UseGroup2 { } impl syn::parse::Parse for UseTree2 { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result<UseTree2> { + fn parse(input: syn::parse::ParseStream) -> syn::parse::Result<Self> { let lookahead = input.lookahead1(); if lookahead.peek(syn::Ident) { use syn::ext::IdentExt; let ident = input.call(syn::Ident::parse_any)?; if input.peek(syn::Token![::]) { input.parse::<syn::Token![::]>()?; - Ok(UseTree2::Path(UsePath2 { + Ok(Self::Path(UsePath2 { ident, tree: Box::new(input.parse()?), })) } else if input.peek(syn::Token![=]) { - if ident != "TrustLevel" { - return Err(syn::parse::Error::new( + if ident == "TrustLevel" { + input.parse::<syn::Token![=]>()?; + let span = input.span(); + let value = input.call(syn::Ident::parse_any)?; + match value.to_string().as_str() { + "Partial" => Ok(Self::TrustLevel(1)), + "Full" => Ok(Self::TrustLevel(2)), + _ => Err(syn::parse::Error::new( + span, + "`TrustLevel` must be `Partial` or `Full`", + )), + } + } else if ident == "Agile" { + input.parse::<syn::Token![=]>()?; + let span = input.span(); + let value = input.call(syn::Ident::parse_any)?; + match value.to_string().as_str() { + "true" => Ok(Self::Agile(true)), + "false" => Ok(Self::Agile(false)), + _ => Err(syn::parse::Error::new( + span, + "`Agile` must be `true` or `false`", + )), + } + } else { + Err(syn::parse::Error::new( ident.span(), "Unrecognized key-value pair", - )); - } - input.parse::<syn::Token![=]>()?; - let span = input.span(); - let value = input.call(syn::Ident::parse_any)?; - match value.to_string().as_str() { - "Partial" => Ok(UseTree2::TrustLevel(1)), - "Full" => Ok(UseTree2::TrustLevel(2)), - _ => Err(syn::parse::Error::new( - span, - "`TrustLevel` must be `Partial` or `Full`", - )), + )) } } else { let generics = if input.peek(syn::Token![<]) { input.parse::<syn::Token![<]>()?; let mut generics = Vec::new(); loop { - generics.push(input.parse::<UseTree2>()?); + generics.push(input.parse::<Self>()?); if input.parse::<syn::Token![,]>().is_err() { break; @@ -573,16 +339,68 @@ impl syn::parse::Parse for UseTree2 { Vec::new() }; - Ok(UseTree2::Name(UseName2 { ident, generics })) + Ok(Self::Name(UseName2 { ident, generics })) } } else if lookahead.peek(syn::token::Brace) { let content; let brace_token = syn::braced!(content in input); - let items = content.parse_terminated(UseTree2::parse, syn::Token![,])?; + let items = content.parse_terminated(Self::parse, syn::Token![,])?; - Ok(UseTree2::Group(UseGroup2 { brace_token, items })) + Ok(Self::Group(UseGroup2 { brace_token, items })) } else { Err(lookahead.error()) } } } + +fn convert_implements_to_interface_chains(implements: Vec<ImplementType>) -> Vec<InterfaceChain> { + let mut chains = Vec::with_capacity(implements.len()); + + for (i, implement) in implements.into_iter().enumerate() { + // Create an identifier for this interface chain. + // We only use this for naming fields; it is never visible to the developer. + // This helps with debugging. + // + // We use i + 1 so that it matches the numbering of our interface offsets. Interface 0 + // is the "identity" interface. + + let mut ident_string = format!("interface{}", i + 1); + + let suffix = get_interface_ident_suffix(&implement.type_name); + if !suffix.is_empty() { + ident_string.push('_'); + ident_string.push_str(&suffix); + } + let field_ident = syn::Ident::new(&ident_string, implement.span); + + let mut vtable_const_string = ident_string.clone(); + vtable_const_string.make_ascii_uppercase(); + vtable_const_string.insert_str(0, "VTABLE_"); + let vtable_const_ident = syn::Ident::new(&vtable_const_string, implement.span); + + chains.push(InterfaceChain { + implement, + field_ident, + vtable_const_ident, + }); + } + + chains +} + +fn get_interface_ident_suffix(type_name: &str) -> String { + let mut suffix = String::new(); + for c in type_name.chars() { + let c = c.to_ascii_lowercase(); + + if suffix.len() >= 20 { + break; + } + + if c.is_ascii_alphanumeric() { + suffix.push(c); + } + } + + suffix +} diff --git a/third_party/rust/windows-implement/src/tests.rs b/third_party/rust/windows-implement/src/tests.rs @@ -0,0 +1,135 @@ +//! These tests are just a way to quickly run the `#[implement]` macro and see its output. +//! They don't check the output in any way. +//! +//! This exists because of some difficulties of running `cargo expand` against the `#[implement]` +//! macro. It's also just really convenient. You can see the output by using `--nocapture` and +//! you'll probably want to restrict the output to a single thread: +//! +//! ```text +//! cargo test -p windows-implement --lib -- --nocapture --test-threads=1 +//! ``` + +use std::io::{Read, Write}; +use std::process::{Command, Stdio}; + +use proc_macro2::TokenStream; +use quote::quote; + +fn implement(attributes: TokenStream, item_tokens: TokenStream) -> String { + let out_tokens = crate::implement_core(attributes, item_tokens); + let tokens_string = out_tokens.to_string(); + + let out_string = rustfmt(&tokens_string); + println!("// output of #[implement] :"); + println!(); + println!("{}", out_string); + out_string +} + +fn rustfmt(input: &str) -> String { + let mut rustfmt = Command::new("rustfmt"); + + rustfmt.stdin(Stdio::piped()); + rustfmt.stdout(Stdio::piped()); + rustfmt.stderr(Stdio::inherit()); + + let mut child = match rustfmt.spawn() { + Ok(c) => c, + Err(e) => { + eprintln!("failed to spawn rustfmt: {e:?}"); + return input.to_string(); + } + }; + + let mut stdout = child.stdout.take().unwrap(); + + // spawn thread to read stdout + let stdout_thread = std::thread::spawn(move || { + let mut buf = String::new(); + stdout.read_to_string(&mut buf).unwrap(); + buf + }); + + // write unformatted into stdin + let mut stdin = child.stdin.take().unwrap(); + stdin.write_all(input.as_bytes()).unwrap(); + drop(stdin); + + let stdout_string: String = stdout_thread.join().unwrap(); + + let exit = child.wait().unwrap(); + if !exit.success() { + eprintln!("rustfmt terminated with failure status code"); + return input.to_string(); + } + + stdout_string +} + +#[test] +fn simple_type() { + implement( + quote!(IFoo), + quote! { + struct Foo { + x: u32, + } + }, + ); +} + +#[test] +fn zero_sized_type() { + implement( + quote!(IFoo), + quote! { + struct Foo; + }, + ); +} + +#[test] +fn no_interfaces() { + implement( + quote!(), + quote! { + struct Foo {} + }, + ); +} + +#[test] +fn generic_no_lifetime() { + implement( + quote!(IAsyncOperationWithProgress<T, P>, IAsyncInfo), + quote! { + struct OperationWithProgress<T, P>(SyncState<IAsyncOperationWithProgress<T, P>>) + where + T: RuntimeType + 'static, + P: RuntimeType + 'static; + + }, + ); +} + +#[test] +fn generic_with_lifetime() { + implement( + quote!(), + quote! { + pub struct Foo<'a> { + pub x: &'a [u8], + } + }, + ); +} + +#[test] +fn tuple_type() { + implement( + quote!(IFoo), + quote! { + struct Foo(pub i32); + }, + ); +} diff --git a/third_party/rust/windows-interface/.cargo-checksum.json b/third_party/rust/windows-interface/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"06b4907a2ab2cd6418fe91777edd5b336ab8bf31c8d9420baaa1d064f4885be2","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","src/lib.rs":"a4d6dc0b000d483e77c10bb8bdf0c36f906aaec35dbe7649150bbf9648221f65"},"package":"053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"} -\ No newline at end of file +{"files":{"Cargo.lock":"f68dc783cf8a9cf11ac0033e98d3f5ec2cb804d9c8774f4fcfb8d589c52a01e8","Cargo.toml":"dd3e0b382b8b9efa4047630781b905086f821bfe14927b74bc2e0bdf25f9425f","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"f976507ff52b1ae3668ecadd9b35c933b4a2163ed1b4f8589c8f27645226f965","src/lib.rs":"823b42444789094620dc319351f86b63abb8d10aefdf37ecaef13c9797ae1f82"},"package":"3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"} +\ No newline at end of file diff --git a/third_party/rust/windows-interface/Cargo.lock b/third_party/rust/windows-interface/Cargo.lock @@ -0,0 +1,47 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "windows-interface" +version = "0.59.3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/third_party/rust/windows-interface/Cargo.toml b/third_party/rust/windows-interface/Cargo.toml @@ -11,17 +11,18 @@ [package] edition = "2021" -rust-version = "1.70" +rust-version = "1.74" name = "windows-interface" -version = "0.58.0" -authors = ["Microsoft"] +version = "0.59.3" build = false +autolib = false autobins = false autoexamples = false autotests = false autobenches = false -description = "The interface macro for the windows crate" -readme = false +description = "The interface macro for the Windows crates" +readme = "readme.md" +categories = ["os::windows-apis"] license = "MIT OR Apache-2.0" repository = "https://github.com/microsoft/windows-rs" @@ -36,9 +37,11 @@ proc-macro = true [dependencies.proc-macro2] version = "1.0" +default-features = false [dependencies.quote] version = "1.0" +default-features = false [dependencies.syn] version = "2.0" @@ -47,19 +50,16 @@ features = [ "proc-macro", "printing", "full", - "derive", "clone-impls", ] default-features = false -[lints.rust] -missing_docs = "warn" +[dev-dependencies] -[lints.rust.rust_2018_idioms] -level = "warn" -priority = -1 +[lints.rust] +missing_unsafe_on_extern = "warn" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 -check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"] +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-interface/readme.md b/third_party/rust/windows-interface/readme.md @@ -0,0 +1,3 @@ +## The interface macro for the Windows crates + +See [windows-core](https://crates.io/crates/windows-core) for more information. diff --git a/third_party/rust/windows-interface/src/lib.rs b/third_party/rust/windows-interface/src/lib.rs @@ -1,6 +1,8 @@ -/*! -Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs> -*/ +//! Define COM interfaces to call or implement. +//! +//! Take a look at [macro@interface] for an example. +//! +//! Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs> use quote::quote; use syn::spanned::Spanned; @@ -8,7 +10,9 @@ use syn::spanned::Spanned; /// Defines a COM interface to call or implement. /// /// # Example -/// ```rust,ignore +/// ```rust,no_run +/// use windows_core::*; +/// /// #[interface("094d70d6-5202-44b8-abb8-43860da5aca2")] /// unsafe trait IValue: IUnknown { /// fn GetValue(&self, value: *mut i32) -> HRESULT; @@ -17,17 +21,15 @@ use syn::spanned::Spanned; /// #[implement(IValue)] /// struct Value(i32); /// -/// impl IValue_Impl for Value { +/// impl IValue_Impl for Value_Impl { /// unsafe fn GetValue(&self, value: *mut i32) -> HRESULT { /// *value = self.0; /// HRESULT(0) /// } /// } /// -/// fn main() { -/// let object: IValue = Value(123).into(); -/// // Call interface methods... -/// } +/// let object: IValue = Value(123).into(); +/// // Call interface methods... /// ``` #[proc_macro_attribute] pub fn interface( @@ -385,7 +387,7 @@ impl Interface { } impl ::core::cmp::Eq for #name {} impl ::core::fmt::Debug for #name { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { f.debug_tuple(#name_string).field(&::windows_core::Interface::as_raw(self)).finish() } } @@ -429,7 +431,7 @@ impl Interface { } } - /// Gets the parent trait constrait which is nothing if the parent is IUnknown + /// Gets the parent trait constraint which is nothing if the parent is IUnknown fn parent_trait_constraint(&self) -> proc_macro2::TokenStream { if let Some((ident, path)) = self.parent_path().split_last() { if ident != "IUnknown" { @@ -443,7 +445,7 @@ impl Interface { } impl syn::parse::Parse for Interface { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { let attributes = input.call(syn::Attribute::parse_outer)?; let mut docs = Vec::new(); for attr in attributes.into_iter() { @@ -574,7 +576,7 @@ impl Guid { } impl syn::parse::Parse for Guid { - fn parse(cursor: syn::parse::ParseStream<'_>) -> syn::Result<Self> { + fn parse(cursor: syn::parse::ParseStream) -> syn::Result<Self> { let string: Option<syn::LitStr> = cursor.parse().ok(); Ok(Self(string)) @@ -688,7 +690,7 @@ impl InterfaceMethod { } impl syn::parse::Parse for InterfaceMethod { - fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { let docs = input.call(syn::Attribute::parse_outer)?; let visibility = input.parse::<syn::Visibility>()?; let method = input.parse::<syn::TraitItemFn>()?; @@ -720,7 +722,7 @@ impl syn::parse::Parse for InterfaceMethod { .collect::<Result<Vec<InterfaceMethodArg>, syn::Error>>()?; let ret = sig.output; - Ok(InterfaceMethod { + Ok(Self { name: sig.ident, visibility, args, diff --git a/third_party/rust/windows-numerics/.cargo-checksum.json b/third_party/rust/windows-numerics/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"b2e37e9dfe18a86ea05db9a04790c75f3a9d10f9049fab85e9939f72accb2f5f","Cargo.toml":"90f0d96aca9116c10fc101ff1db0aa7f39ed34856d11df9e74ce9734a2f2e1c8","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"d57d51d26262257684fabcca62defd7c9903f58fea8003a831f70b5923f68f6b","src/bindings.rs":"0951630583f6b24ebcefe83a56c268147726bcb4b9b5527714221a3092de50e0","src/lib.rs":"ff2134611669c2ca59e6517d46474750b2b15223aef92ae626e5267463df5d8d","src/matrix3x2.rs":"c27ac236de1832296963d8efcf399e74c7d50ae780fe83e229305975b0ccfcf5","src/matrix4x4.rs":"ed85dc4fa09c54eeafa38ac796cde52383e2d7bbda3d4b5a2e252e57e3489ee1","src/vector2.rs":"86b34099d4da48c591d9715a6b1de4d5416d0ddf9d86090b07be78d01594b299","src/vector3.rs":"82847210914a0be70e9b85fdf8e03454fac21fba4d33141249bd0bcb9ec88fa5","src/vector4.rs":"a8c1c73c6b060f337f09c52fc2c7482cc1b80007788a88674fea10e8a68244b5"},"package":"6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"} +\ No newline at end of file diff --git a/third_party/rust/windows-numerics/Cargo.lock b/third_party/rust/windows-numerics/Cargo.lock @@ -0,0 +1,105 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-numerics" +version = "0.3.1" +dependencies = [ + "windows-core", + "windows-link", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] diff --git a/third_party/rust/windows-numerics/Cargo.toml b/third_party/rust/windows-numerics/Cargo.toml @@ -0,0 +1,55 @@ +# 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.82" +name = "windows-numerics" +version = "0.3.1" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Windows numeric types" +readme = "readme.md" +categories = ["os::windows-apis"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/microsoft/windows-rs" + +[package.metadata.docs.rs] +default-target = "x86_64-pc-windows-msvc" +targets = [] + +[features] +default = ["std"] +std = ["windows-core/std"] + +[lib] +name = "windows_numerics" +path = "src/lib.rs" + +[dependencies.windows-core] +version = "0.62.2" +default-features = false + +[dependencies.windows-link] +version = "0.2.1" +default-features = false + +[lints.rust] +missing_unsafe_on_extern = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-numerics/license-apache-2.0 b/third_party/rust/windows-numerics/license-apache-2.0 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) Microsoft Corporation. + + 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/windows-numerics/license-mit b/third_party/rust/windows-numerics/license-mit @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + 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/windows-numerics/readme.md b/third_party/rust/windows-numerics/readme.md @@ -0,0 +1,7 @@ +## Windows numeric types + +The [windows-numerics](https://crates.io/crates/windows-numerics) crate provides graphics-oriented math types for Windows. + +* [Getting started](https://kennykerr.ca/rust-getting-started/) +* [Samples](https://github.com/microsoft/windows-rs/tree/master/crates/samples) +* [Releases](https://github.com/microsoft/windows-rs/releases) diff --git a/third_party/rust/windows-numerics/src/bindings.rs b/third_party/rust/windows-numerics/src/bindings.rs @@ -0,0 +1,89 @@ +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Matrix3x2 { + pub M11: f32, + pub M12: f32, + pub M21: f32, + pub M22: f32, + pub M31: f32, + pub M32: f32, +} +impl windows_core::TypeKind for Matrix3x2 { + type TypeKind = windows_core::CopyType; +} +impl windows_core::RuntimeType for Matrix3x2 { + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::from_slice( + b"struct(Windows.Foundation.Numerics.Matrix3x2;f4;f4;f4;f4;f4;f4)", + ); +} +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Matrix4x4 { + pub M11: f32, + pub M12: f32, + pub M13: f32, + pub M14: f32, + pub M21: f32, + pub M22: f32, + pub M23: f32, + pub M24: f32, + pub M31: f32, + pub M32: f32, + pub M33: f32, + pub M34: f32, + pub M41: f32, + pub M42: f32, + pub M43: f32, + pub M44: f32, +} +impl windows_core::TypeKind for Matrix4x4 { + type TypeKind = windows_core::CopyType; +} +impl windows_core::RuntimeType for Matrix4x4 { + const SIGNATURE :windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::from_slice ( b"struct(Windows.Foundation.Numerics.Matrix4x4;f4;f4;f4;f4;f4;f4;f4;f4;f4;f4;f4;f4;f4;f4;f4;f4)" ) ; +} +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Vector2 { + pub X: f32, + pub Y: f32, +} +impl windows_core::TypeKind for Vector2 { + type TypeKind = windows_core::CopyType; +} +impl windows_core::RuntimeType for Vector2 { + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::from_slice( + b"struct(Windows.Foundation.Numerics.Vector2;f4;f4)", + ); +} +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Vector3 { + pub X: f32, + pub Y: f32, + pub Z: f32, +} +impl windows_core::TypeKind for Vector3 { + type TypeKind = windows_core::CopyType; +} +impl windows_core::RuntimeType for Vector3 { + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::from_slice( + b"struct(Windows.Foundation.Numerics.Vector3;f4;f4;f4)", + ); +} +#[repr(C)] +#[derive(Clone, Copy, Debug, Default, PartialEq)] +pub struct Vector4 { + pub X: f32, + pub Y: f32, + pub Z: f32, + pub W: f32, +} +impl windows_core::TypeKind for Vector4 { + type TypeKind = windows_core::CopyType; +} +impl windows_core::RuntimeType for Vector4 { + const SIGNATURE: windows_core::imp::ConstBuffer = windows_core::imp::ConstBuffer::from_slice( + b"struct(Windows.Foundation.Numerics.Vector4;f4;f4;f4;f4)", + ); +} diff --git a/third_party/rust/windows-numerics/src/lib.rs b/third_party/rust/windows-numerics/src/lib.rs @@ -0,0 +1,12 @@ +#![expect(missing_docs, non_snake_case, clippy::all)] +#![doc = include_str!("../readme.md")] +#![cfg_attr(all(not(feature = "std")), no_std)] + +mod bindings; +pub use bindings::*; + +mod matrix3x2; +mod matrix4x4; +mod vector2; +mod vector3; +mod vector4; diff --git a/third_party/rust/windows-numerics/src/matrix3x2.rs b/third_party/rust/windows-numerics/src/matrix3x2.rs @@ -0,0 +1,184 @@ +use super::*; + +impl Matrix3x2 { + pub const fn identity() -> Self { + Self { + M11: 1.0, + M12: 0.0, + M21: 0.0, + M22: 1.0, + M31: 0.0, + M32: 0.0, + } + } + pub const fn translation(x: f32, y: f32) -> Self { + Self { + M11: 1.0, + M12: 0.0, + M21: 0.0, + M22: 1.0, + M31: x, + M32: y, + } + } + pub fn rotation(angle: f32) -> Self { + Self::rotation_around(angle, Vector2::zero()) + } + pub fn rotation_around(angle: f32, center: Vector2) -> Self { + windows_link::link!("d2d1.dll" "system" fn D2D1MakeRotateMatrix(angle: f32, center: Vector2, matrix: *mut Matrix3x2)); + let mut matrix = Self::default(); + unsafe { + D2D1MakeRotateMatrix(angle, center, &mut matrix); + } + matrix + } + pub fn scale(scale_x: f32, scale_y: f32) -> Self { + Self::scale_around(scale_x, scale_y, Vector2::zero()) + } + pub fn scale_around(scale_x: f32, scale_y: f32, center: Vector2) -> Self { + Self { + M11: scale_x, + M12: 0.0, + M21: 0.0, + M22: scale_y, + M31: center.X - scale_x * center.X, + M32: center.Y - scale_y * center.Y, + } + } + pub fn skew(angle_x: f32, angle_y: f32) -> Self { + Self::skew_around(angle_x, angle_y, Vector2::zero()) + } + pub fn skew_around(angle_x: f32, angle_y: f32, center: Vector2) -> Self { + windows_link::link!("d2d1.dll" "system" fn D2D1MakeSkewMatrix(angle_x: f32, angle_y: f32, center: Vector2, matrix: *mut Matrix3x2)); + let mut matrix = Self::default(); + unsafe { + D2D1MakeSkewMatrix(angle_x, angle_y, center, &mut matrix); + } + matrix + } + fn impl_add(&self, rhs: &Self) -> Self { + Self { + M11: self.M11 + rhs.M11, + M12: self.M12 + rhs.M12, + M21: self.M21 + rhs.M21, + M22: self.M22 + rhs.M22, + M31: self.M31 + rhs.M31, + M32: self.M32 + rhs.M32, + } + } + fn impl_sub(&self, rhs: &Self) -> Self { + Self { + M11: self.M11 - rhs.M11, + M12: self.M12 - rhs.M12, + M21: self.M21 - rhs.M21, + M22: self.M22 - rhs.M22, + M31: self.M31 - rhs.M31, + M32: self.M32 - rhs.M32, + } + } + fn impl_mul(&self, rhs: &Self) -> Self { + Self { + M11: self.M11 * rhs.M11 + self.M12 * rhs.M21, + M12: self.M11 * rhs.M12 + self.M12 * rhs.M22, + M21: self.M21 * rhs.M11 + self.M22 * rhs.M21, + M22: self.M21 * rhs.M12 + self.M22 * rhs.M22, + M31: self.M31 * rhs.M11 + self.M32 * rhs.M21 + rhs.M31, + M32: self.M31 * rhs.M12 + self.M32 * rhs.M22 + rhs.M32, + } + } + fn impl_mul_f32(&self, rhs: f32) -> Self { + Self { + M11: self.M11 * rhs, + M12: self.M12 * rhs, + M21: self.M21 * rhs, + M22: self.M22 * rhs, + M31: self.M31 * rhs, + M32: self.M32 * rhs, + } + } +} + +impl core::ops::Add<Self> for Matrix3x2 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Self> for Matrix3x2 { + type Output = Self; + fn add(self, rhs: &Self) -> Self { + self.impl_add(rhs) + } +} +impl core::ops::Add<Matrix3x2> for &Matrix3x2 { + type Output = Matrix3x2; + fn add(self, rhs: Matrix3x2) -> Matrix3x2 { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Matrix3x2> for &Matrix3x2 { + type Output = Matrix3x2; + fn add(self, rhs: &Matrix3x2) -> Matrix3x2 { + self.impl_add(rhs) + } +} +impl core::ops::Sub<Self> for Matrix3x2 { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Self> for Matrix3x2 { + type Output = Self; + fn sub(self, rhs: &Self) -> Self { + self.impl_sub(rhs) + } +} +impl core::ops::Sub<Matrix3x2> for &Matrix3x2 { + type Output = Matrix3x2; + fn sub(self, rhs: Matrix3x2) -> Matrix3x2 { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Matrix3x2> for &Matrix3x2 { + type Output = Matrix3x2; + fn sub(self, rhs: &Matrix3x2) -> Matrix3x2 { + self.impl_sub(rhs) + } +} +impl core::ops::Mul<Self> for Matrix3x2 { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Self> for Matrix3x2 { + type Output = Self; + fn mul(self, rhs: &Self) -> Self { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<Matrix3x2> for &Matrix3x2 { + type Output = Matrix3x2; + fn mul(self, rhs: Matrix3x2) -> Matrix3x2 { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Matrix3x2> for &Matrix3x2 { + type Output = Matrix3x2; + fn mul(self, rhs: &Matrix3x2) -> Matrix3x2 { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<f32> for Matrix3x2 { + type Output = Self; + fn mul(self, rhs: f32) -> Self { + self.impl_mul_f32(rhs) + } +} +impl core::ops::Mul<f32> for &Matrix3x2 { + type Output = Matrix3x2; + fn mul(self, rhs: f32) -> Matrix3x2 { + self.impl_mul_f32(rhs) + } +} diff --git a/third_party/rust/windows-numerics/src/matrix4x4.rs b/third_party/rust/windows-numerics/src/matrix4x4.rs @@ -0,0 +1,237 @@ +use super::*; + +impl Matrix4x4 { + pub const fn translation(x: f32, y: f32, z: f32) -> Self { + Self { + M11: 1.0, + M12: 0.0, + M13: 0.0, + M14: 0.0, + M21: 0.0, + M22: 1.0, + M23: 0.0, + M24: 0.0, + M31: 0.0, + M32: 0.0, + M33: 1.0, + M34: 0.0, + M41: x, + M42: y, + M43: z, + M44: 1.0, + } + } + pub fn rotation_y(degree: f32) -> Self { + windows_link::link!("d2d1.dll" "system" fn D2D1SinCos(angle: f32, sin: *mut f32, cos: *mut f32)); + let angle = degree * (3.141592654 / 180.0); + let mut sin = 0.0; + let mut cos = 0.0; + unsafe { + D2D1SinCos(angle, &mut sin, &mut cos); + } + Self { + M11: cos, + M12: 0.0, + M13: -sin, + M14: 0.0, + M21: 0.0, + M22: 1.0, + M23: 0.0, + M24: 0.0, + M31: sin, + M32: 0.0, + M33: cos, + M34: 0.0, + M41: 0.0, + M42: 0.0, + M43: 0.0, + M44: 1.0, + } + } + pub fn perspective_projection(depth: f32) -> Self { + let projection = if depth > 0.0 { -1.0 / depth } else { 0.0 }; + Self { + M11: 1.0, + M12: 0.0, + M13: 0.0, + M14: 0.0, + M21: 0.0, + M22: 1.0, + M23: 0.0, + M24: 0.0, + M31: 0.0, + M32: 0.0, + M33: 1.0, + M34: projection, + M41: 0.0, + M42: 0.0, + M43: 0.0, + M44: 1.0, + } + } + fn impl_add(&self, rhs: &Self) -> Self { + Self { + M11: self.M11 + rhs.M11, + M12: self.M12 + rhs.M12, + M13: self.M13 + rhs.M13, + M14: self.M14 + rhs.M14, + M21: self.M21 + rhs.M21, + M22: self.M22 + rhs.M22, + M23: self.M23 + rhs.M23, + M24: self.M24 + rhs.M24, + M31: self.M31 + rhs.M31, + M32: self.M32 + rhs.M32, + M33: self.M33 + rhs.M33, + M34: self.M34 + rhs.M34, + M41: self.M41 + rhs.M41, + M42: self.M42 + rhs.M42, + M43: self.M43 + rhs.M43, + M44: self.M44 + rhs.M44, + } + } + fn impl_sub(&self, rhs: &Self) -> Self { + Self { + M11: self.M11 - rhs.M11, + M12: self.M12 - rhs.M12, + M13: self.M13 - rhs.M13, + M14: self.M14 - rhs.M14, + M21: self.M21 - rhs.M21, + M22: self.M22 - rhs.M22, + M23: self.M23 - rhs.M23, + M24: self.M24 - rhs.M24, + M31: self.M31 - rhs.M31, + M32: self.M32 - rhs.M32, + M33: self.M33 - rhs.M33, + M34: self.M34 - rhs.M34, + M41: self.M41 - rhs.M41, + M42: self.M42 - rhs.M42, + M43: self.M43 - rhs.M43, + M44: self.M44 - rhs.M44, + } + } + fn impl_mul(&self, rhs: &Self) -> Self { + Self { + M11: self.M11 * rhs.M11 + self.M12 * rhs.M21 + self.M13 * rhs.M31 + self.M14 * rhs.M41, + M12: self.M11 * rhs.M12 + self.M12 * rhs.M22 + self.M13 * rhs.M32 + self.M14 * rhs.M42, + M13: self.M11 * rhs.M13 + self.M12 * rhs.M23 + self.M13 * rhs.M33 + self.M14 * rhs.M43, + M14: self.M11 * rhs.M14 + self.M12 * rhs.M24 + self.M13 * rhs.M34 + self.M14 * rhs.M44, + M21: self.M21 * rhs.M11 + self.M22 * rhs.M21 + self.M23 * rhs.M31 + self.M24 * rhs.M41, + M22: self.M21 * rhs.M12 + self.M22 * rhs.M22 + self.M23 * rhs.M32 + self.M24 * rhs.M42, + M23: self.M21 * rhs.M13 + self.M22 * rhs.M23 + self.M23 * rhs.M33 + self.M24 * rhs.M43, + M24: self.M21 * rhs.M14 + self.M22 * rhs.M24 + self.M23 * rhs.M34 + self.M24 * rhs.M44, + M31: self.M31 * rhs.M11 + self.M32 * rhs.M21 + self.M33 * rhs.M31 + self.M34 * rhs.M41, + M32: self.M31 * rhs.M12 + self.M32 * rhs.M22 + self.M33 * rhs.M32 + self.M34 * rhs.M42, + M33: self.M31 * rhs.M13 + self.M32 * rhs.M23 + self.M33 * rhs.M33 + self.M34 * rhs.M43, + M34: self.M31 * rhs.M14 + self.M32 * rhs.M24 + self.M33 * rhs.M34 + self.M34 * rhs.M44, + M41: self.M41 * rhs.M11 + self.M42 * rhs.M21 + self.M43 * rhs.M31 + self.M44 * rhs.M41, + M42: self.M41 * rhs.M12 + self.M42 * rhs.M22 + self.M43 * rhs.M32 + self.M44 * rhs.M42, + M43: self.M41 * rhs.M13 + self.M42 * rhs.M23 + self.M43 * rhs.M33 + self.M44 * rhs.M43, + M44: self.M41 * rhs.M14 + self.M42 * rhs.M24 + self.M43 * rhs.M34 + self.M44 * rhs.M44, + } + } + fn impl_mul_f32(&self, rhs: f32) -> Self { + Self { + M11: self.M11 * rhs, + M12: self.M12 * rhs, + M13: self.M13 * rhs, + M14: self.M14 * rhs, + M21: self.M21 * rhs, + M22: self.M22 * rhs, + M23: self.M23 * rhs, + M24: self.M24 * rhs, + M31: self.M31 * rhs, + M32: self.M32 * rhs, + M33: self.M33 * rhs, + M34: self.M34 * rhs, + M41: self.M41 * rhs, + M42: self.M42 * rhs, + M43: self.M43 * rhs, + M44: self.M44 * rhs, + } + } +} + +impl core::ops::Add<Self> for Matrix4x4 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Self> for Matrix4x4 { + type Output = Self; + fn add(self, rhs: &Self) -> Self { + self.impl_add(rhs) + } +} +impl core::ops::Add<Matrix4x4> for &Matrix4x4 { + type Output = Matrix4x4; + fn add(self, rhs: Matrix4x4) -> Matrix4x4 { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Matrix4x4> for &Matrix4x4 { + type Output = Matrix4x4; + fn add(self, rhs: &Matrix4x4) -> Matrix4x4 { + self.impl_add(rhs) + } +} +impl core::ops::Sub<Self> for Matrix4x4 { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Self> for Matrix4x4 { + type Output = Self; + fn sub(self, rhs: &Self) -> Self { + self.impl_sub(rhs) + } +} +impl core::ops::Sub<Matrix4x4> for &Matrix4x4 { + type Output = Matrix4x4; + fn sub(self, rhs: Matrix4x4) -> Matrix4x4 { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Matrix4x4> for &Matrix4x4 { + type Output = Matrix4x4; + fn sub(self, rhs: &Matrix4x4) -> Matrix4x4 { + self.impl_sub(rhs) + } +} +impl core::ops::Mul<Self> for Matrix4x4 { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Self> for Matrix4x4 { + type Output = Self; + fn mul(self, rhs: &Self) -> Self { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<Matrix4x4> for &Matrix4x4 { + type Output = Matrix4x4; + fn mul(self, rhs: Matrix4x4) -> Matrix4x4 { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Matrix4x4> for &Matrix4x4 { + type Output = Matrix4x4; + fn mul(self, rhs: &Matrix4x4) -> Matrix4x4 { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<f32> for Matrix4x4 { + type Output = Self; + fn mul(self, rhs: f32) -> Self { + self.impl_mul_f32(rhs) + } +} +impl core::ops::Mul<f32> for &Matrix4x4 { + type Output = Matrix4x4; + fn mul(self, rhs: f32) -> Matrix4x4 { + self.impl_mul_f32(rhs) + } +} diff --git a/third_party/rust/windows-numerics/src/vector2.rs b/third_party/rust/windows-numerics/src/vector2.rs @@ -0,0 +1,198 @@ +use super::*; + +impl Vector2 { + pub fn new(X: f32, Y: f32) -> Self { + Self { X, Y } + } + pub fn zero() -> Self { + Self { X: 0f32, Y: 0f32 } + } + pub fn one() -> Self { + Self { X: 1f32, Y: 1f32 } + } + pub fn unit_x() -> Self { + Self { X: 1.0, Y: 0.0 } + } + pub fn unit_y() -> Self { + Self { X: 0.0, Y: 1.0 } + } + pub fn dot(&self, rhs: &Self) -> f32 { + self.X * rhs.X + self.Y * rhs.Y + } + pub fn length_squared(&self) -> f32 { + self.dot(self) + } + #[cfg(feature = "std")] + pub fn length(&self) -> f32 { + self.length_squared().sqrt() + } + #[cfg(feature = "std")] + pub fn distance(&self, value: &Self) -> f32 { + (self - value).length() + } + pub fn distance_squared(&self, value: &Self) -> f32 { + (self - value).length_squared() + } + #[cfg(feature = "std")] + pub fn normalize(&self) -> Self { + self / self.length() + } + + fn impl_add(&self, rhs: &Self) -> Self { + Self { + X: self.X + rhs.X, + Y: self.Y + rhs.Y, + } + } + fn impl_sub(&self, rhs: &Self) -> Self { + Self { + X: self.X - rhs.X, + Y: self.Y - rhs.Y, + } + } + fn impl_div(&self, rhs: &Self) -> Self { + Self { + X: self.X / rhs.X, + Y: self.Y / rhs.Y, + } + } + fn impl_div_f32(&self, rhs: f32) -> Self { + Self { + X: self.X / rhs, + Y: self.Y / rhs, + } + } + fn impl_mul(&self, rhs: &Self) -> Self { + Self { + X: self.X * rhs.X, + Y: self.Y * rhs.Y, + } + } + fn impl_mul_f32(&self, rhs: f32) -> Self { + Self { + X: self.X * rhs, + Y: self.Y * rhs, + } + } +} + +impl core::ops::Add<Self> for Vector2 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Self> for Vector2 { + type Output = Self; + fn add(self, rhs: &Self) -> Self { + self.impl_add(rhs) + } +} +impl core::ops::Add<Vector2> for &Vector2 { + type Output = Vector2; + fn add(self, rhs: Vector2) -> Vector2 { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Vector2> for &Vector2 { + type Output = Vector2; + fn add(self, rhs: &Vector2) -> Vector2 { + self.impl_add(rhs) + } +} +impl core::ops::Sub<Self> for Vector2 { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Self> for Vector2 { + type Output = Self; + fn sub(self, rhs: &Self) -> Self { + self.impl_sub(rhs) + } +} +impl core::ops::Sub<Vector2> for &Vector2 { + type Output = Vector2; + fn sub(self, rhs: Vector2) -> Vector2 { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Vector2> for &Vector2 { + type Output = Vector2; + fn sub(self, rhs: &Vector2) -> Vector2 { + self.impl_sub(rhs) + } +} +impl core::ops::Div<Self> for Vector2 { + type Output = Self; + fn div(self, rhs: Self) -> Self { + self.impl_div(&rhs) + } +} +impl core::ops::Div<&Self> for Vector2 { + type Output = Self; + fn div(self, rhs: &Self) -> Self { + self.impl_div(rhs) + } +} +impl core::ops::Div<Vector2> for &Vector2 { + type Output = Vector2; + fn div(self, rhs: Vector2) -> Vector2 { + self.impl_div(&rhs) + } +} +impl core::ops::Div<&Vector2> for &Vector2 { + type Output = Vector2; + fn div(self, rhs: &Vector2) -> Vector2 { + self.impl_div(rhs) + } +} +impl core::ops::Div<f32> for Vector2 { + type Output = Self; + fn div(self, rhs: f32) -> Self { + self.impl_div_f32(rhs) + } +} +impl core::ops::Div<f32> for &Vector2 { + type Output = Vector2; + fn div(self, rhs: f32) -> Vector2 { + self.impl_div_f32(rhs) + } +} +impl core::ops::Mul<Self> for Vector2 { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Self> for Vector2 { + type Output = Self; + fn mul(self, rhs: &Self) -> Self { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<Vector2> for &Vector2 { + type Output = Vector2; + fn mul(self, rhs: Vector2) -> Vector2 { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Vector2> for &Vector2 { + type Output = Vector2; + fn mul(self, rhs: &Vector2) -> Vector2 { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<f32> for Vector2 { + type Output = Self; + fn mul(self, rhs: f32) -> Self { + self.impl_mul_f32(rhs) + } +} +impl core::ops::Mul<f32> for &Vector2 { + type Output = Vector2; + fn mul(self, rhs: f32) -> Vector2 { + self.impl_mul_f32(rhs) + } +} diff --git a/third_party/rust/windows-numerics/src/vector3.rs b/third_party/rust/windows-numerics/src/vector3.rs @@ -0,0 +1,227 @@ +use super::*; + +impl Vector3 { + pub fn new(X: f32, Y: f32, Z: f32) -> Self { + Self { X, Y, Z } + } + pub fn zero() -> Self { + Self { + X: 0f32, + Y: 0f32, + Z: 0f32, + } + } + pub fn one() -> Self { + Self { + X: 1f32, + Y: 1f32, + Z: 1f32, + } + } + pub fn unit_x() -> Self { + Self { + X: 1.0, + Y: 0.0, + Z: 0.0, + } + } + pub fn unit_y() -> Self { + Self { + X: 0.0, + Y: 1.0, + Z: 0.0, + } + } + pub fn unit_z() -> Self { + Self { + X: 0.0, + Y: 0.0, + Z: 1.0, + } + } + pub fn dot(&self, rhs: &Self) -> f32 { + self.X * rhs.X + self.Y * rhs.Y + self.Z * rhs.Z + } + pub fn length_squared(&self) -> f32 { + self.dot(self) + } + #[cfg(feature = "std")] + pub fn length(&self) -> f32 { + self.length_squared().sqrt() + } + #[cfg(feature = "std")] + pub fn distance(&self, value: &Self) -> f32 { + (self - value).length() + } + pub fn distance_squared(&self, value: &Self) -> f32 { + (self - value).length_squared() + } + #[cfg(feature = "std")] + pub fn normalize(&self) -> Self { + self / self.length() + } + + fn impl_add(&self, rhs: &Self) -> Self { + Self { + X: self.X + rhs.X, + Y: self.Y + rhs.Y, + Z: self.Z + rhs.Z, + } + } + fn impl_sub(&self, rhs: &Self) -> Self { + Self { + X: self.X - rhs.X, + Y: self.Y - rhs.Y, + Z: self.Z - rhs.Z, + } + } + fn impl_div(&self, rhs: &Self) -> Self { + Self { + X: self.X / rhs.X, + Y: self.Y / rhs.Y, + Z: self.Z / rhs.Z, + } + } + fn impl_div_f32(&self, rhs: f32) -> Self { + Self { + X: self.X / rhs, + Y: self.Y / rhs, + Z: self.Z / rhs, + } + } + fn impl_mul(&self, rhs: &Self) -> Self { + Self { + X: self.X * rhs.X, + Y: self.Y * rhs.Y, + Z: self.Z * rhs.Z, + } + } + fn impl_mul_f32(&self, rhs: f32) -> Self { + Self { + X: self.X * rhs, + Y: self.Y * rhs, + Z: self.Z * rhs, + } + } +} + +impl core::ops::Add<Self> for Vector3 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Self> for Vector3 { + type Output = Self; + fn add(self, rhs: &Self) -> Self { + self.impl_add(rhs) + } +} +impl core::ops::Add<Vector3> for &Vector3 { + type Output = Vector3; + fn add(self, rhs: Vector3) -> Vector3 { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Vector3> for &Vector3 { + type Output = Vector3; + fn add(self, rhs: &Vector3) -> Vector3 { + self.impl_add(rhs) + } +} +impl core::ops::Sub<Self> for Vector3 { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Self> for Vector3 { + type Output = Self; + fn sub(self, rhs: &Self) -> Self { + self.impl_sub(rhs) + } +} +impl core::ops::Sub<Vector3> for &Vector3 { + type Output = Vector3; + fn sub(self, rhs: Vector3) -> Vector3 { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Vector3> for &Vector3 { + type Output = Vector3; + fn sub(self, rhs: &Vector3) -> Vector3 { + self.impl_sub(rhs) + } +} +impl core::ops::Div<Self> for Vector3 { + type Output = Self; + fn div(self, rhs: Self) -> Self { + self.impl_div(&rhs) + } +} +impl core::ops::Div<&Self> for Vector3 { + type Output = Self; + fn div(self, rhs: &Self) -> Self { + self.impl_div(rhs) + } +} +impl core::ops::Div<Vector3> for &Vector3 { + type Output = Vector3; + fn div(self, rhs: Vector3) -> Vector3 { + self.impl_div(&rhs) + } +} +impl core::ops::Div<&Vector3> for &Vector3 { + type Output = Vector3; + fn div(self, rhs: &Vector3) -> Vector3 { + self.impl_div(rhs) + } +} +impl core::ops::Div<f32> for Vector3 { + type Output = Self; + fn div(self, rhs: f32) -> Self { + self.impl_div_f32(rhs) + } +} +impl core::ops::Div<f32> for &Vector3 { + type Output = Vector3; + fn div(self, rhs: f32) -> Vector3 { + self.impl_div_f32(rhs) + } +} +impl core::ops::Mul<Self> for Vector3 { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Self> for Vector3 { + type Output = Self; + fn mul(self, rhs: &Self) -> Self { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<Vector3> for &Vector3 { + type Output = Vector3; + fn mul(self, rhs: Vector3) -> Vector3 { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Vector3> for &Vector3 { + type Output = Vector3; + fn mul(self, rhs: &Vector3) -> Vector3 { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<f32> for Vector3 { + type Output = Self; + fn mul(self, rhs: f32) -> Self { + self.impl_mul_f32(rhs) + } +} +impl core::ops::Mul<f32> for &Vector3 { + type Output = Vector3; + fn mul(self, rhs: f32) -> Vector3 { + self.impl_mul_f32(rhs) + } +} diff --git a/third_party/rust/windows-numerics/src/vector4.rs b/third_party/rust/windows-numerics/src/vector4.rs @@ -0,0 +1,246 @@ +use super::*; + +impl Vector4 { + pub fn new(X: f32, Y: f32, Z: f32, W: f32) -> Self { + Self { X, Y, Z, W } + } + pub fn zero() -> Self { + Self { + X: 0f32, + Y: 0f32, + Z: 0f32, + W: 0f32, + } + } + pub fn one() -> Self { + Self { + X: 1f32, + Y: 1f32, + Z: 1f32, + W: 1f32, + } + } + pub fn unit_x() -> Self { + Self { + X: 1.0, + Y: 0.0, + Z: 0.0, + W: 0.0, + } + } + pub fn unit_y() -> Self { + Self { + X: 0.0, + Y: 1.0, + Z: 0.0, + W: 0.0, + } + } + pub fn unit_z() -> Self { + Self { + X: 0.0, + Y: 0.0, + Z: 1.0, + W: 0.0, + } + } + pub fn unit_w() -> Self { + Self { + X: 0.0, + Y: 0.0, + Z: 0.0, + W: 1.0, + } + } + pub fn dot(&self, rhs: &Self) -> f32 { + self.X * rhs.X + self.Y * rhs.Y + self.Z * rhs.Z + self.W * rhs.W + } + pub fn length_squared(&self) -> f32 { + self.dot(self) + } + #[cfg(feature = "std")] + pub fn length(&self) -> f32 { + self.length_squared().sqrt() + } + #[cfg(feature = "std")] + pub fn distance(&self, value: &Self) -> f32 { + (self - value).length() + } + pub fn distance_squared(&self, value: &Self) -> f32 { + (self - value).length_squared() + } + #[cfg(feature = "std")] + pub fn normalize(&self) -> Self { + self / self.length() + } + + fn impl_add(&self, rhs: &Self) -> Self { + Self { + X: self.X + rhs.X, + Y: self.Y + rhs.Y, + Z: self.Z + rhs.Z, + W: self.W + rhs.W, + } + } + fn impl_sub(&self, rhs: &Self) -> Self { + Self { + X: self.X - rhs.X, + Y: self.Y - rhs.Y, + Z: self.Z - rhs.Z, + W: self.W - rhs.W, + } + } + fn impl_div(&self, rhs: &Self) -> Self { + Self { + X: self.X / rhs.X, + Y: self.Y / rhs.Y, + Z: self.Z / rhs.Z, + W: self.W / rhs.W, + } + } + fn impl_div_f32(&self, rhs: f32) -> Self { + Self { + X: self.X / rhs, + Y: self.Y / rhs, + Z: self.Z / rhs, + W: self.W / rhs, + } + } + fn impl_mul(&self, rhs: &Self) -> Self { + Self { + X: self.X * rhs.X, + Y: self.Y * rhs.Y, + Z: self.Z * rhs.Z, + W: self.W * rhs.W, + } + } + fn impl_mul_f32(&self, rhs: f32) -> Self { + Self { + X: self.X * rhs, + Y: self.Y * rhs, + Z: self.Z * rhs, + W: self.W * rhs, + } + } +} + +impl core::ops::Add<Self> for Vector4 { + type Output = Self; + fn add(self, rhs: Self) -> Self { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Self> for Vector4 { + type Output = Self; + fn add(self, rhs: &Self) -> Self { + self.impl_add(rhs) + } +} +impl core::ops::Add<Vector4> for &Vector4 { + type Output = Vector4; + fn add(self, rhs: Vector4) -> Vector4 { + self.impl_add(&rhs) + } +} +impl core::ops::Add<&Vector4> for &Vector4 { + type Output = Vector4; + fn add(self, rhs: &Vector4) -> Vector4 { + self.impl_add(rhs) + } +} +impl core::ops::Sub<Self> for Vector4 { + type Output = Self; + fn sub(self, rhs: Self) -> Self { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Self> for Vector4 { + type Output = Self; + fn sub(self, rhs: &Self) -> Self { + self.impl_sub(rhs) + } +} +impl core::ops::Sub<Vector4> for &Vector4 { + type Output = Vector4; + fn sub(self, rhs: Vector4) -> Vector4 { + self.impl_sub(&rhs) + } +} +impl core::ops::Sub<&Vector4> for &Vector4 { + type Output = Vector4; + fn sub(self, rhs: &Vector4) -> Vector4 { + self.impl_sub(rhs) + } +} +impl core::ops::Div<Self> for Vector4 { + type Output = Self; + fn div(self, rhs: Self) -> Self { + self.impl_div(&rhs) + } +} +impl core::ops::Div<&Self> for Vector4 { + type Output = Self; + fn div(self, rhs: &Self) -> Self { + self.impl_div(rhs) + } +} +impl core::ops::Div<Vector4> for &Vector4 { + type Output = Vector4; + fn div(self, rhs: Vector4) -> Vector4 { + self.impl_div(&rhs) + } +} +impl core::ops::Div<&Vector4> for &Vector4 { + type Output = Vector4; + fn div(self, rhs: &Vector4) -> Vector4 { + self.impl_div(rhs) + } +} +impl core::ops::Div<f32> for Vector4 { + type Output = Self; + fn div(self, rhs: f32) -> Self { + self.impl_div_f32(rhs) + } +} +impl core::ops::Div<f32> for &Vector4 { + type Output = Vector4; + fn div(self, rhs: f32) -> Vector4 { + self.impl_div_f32(rhs) + } +} +impl core::ops::Mul<Self> for Vector4 { + type Output = Self; + fn mul(self, rhs: Self) -> Self { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Self> for Vector4 { + type Output = Self; + fn mul(self, rhs: &Self) -> Self { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<Vector4> for &Vector4 { + type Output = Vector4; + fn mul(self, rhs: Vector4) -> Vector4 { + self.impl_mul(&rhs) + } +} +impl core::ops::Mul<&Vector4> for &Vector4 { + type Output = Vector4; + fn mul(self, rhs: &Vector4) -> Vector4 { + self.impl_mul(rhs) + } +} +impl core::ops::Mul<f32> for Vector4 { + type Output = Self; + fn mul(self, rhs: f32) -> Self { + self.impl_mul_f32(rhs) + } +} +impl core::ops::Mul<f32> for &Vector4 { + type Output = Vector4; + fn mul(self, rhs: f32) -> Vector4 { + self.impl_mul_f32(rhs) + } +} diff --git a/third_party/rust/windows-result/.cargo-checksum.json b/third_party/rust/windows-result/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"5b207ca32f201bf44d5049ffdf90114c161bf103a2c79564e471c36d001565e1","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"0b5595048105c4e66cbc8ce38a551a0c7f28c0c4c69670e696a32df0e5aec9f5","src/bindings.rs":"13e2ec0239e501aae80277cbcdc666a1a671b41b8a4ef91a07f9cb56bd490ecb","src/bstr.rs":"651542aaaa71c11eb129263fe1966f592823ce5717ee937aa7ae23f6b0e45b91","src/com.rs":"3111c836c9a2cabcf01b06fc65af474a1e071d9c887db178105c2b52ec78bdd5","src/error.rs":"6c3d05bb2177791bff427eeaea204462202bb3ed2dc8727babdfefc4f1b3e84f","src/hresult.rs":"2a0f9f532e5e715d316735f626c1cf9e895ca1cc0aa65fedeeb01953028c4573","src/lib.rs":"985e3b67988b97ddd0358189a3d1ac9ea346b067787fae981ac3166ce04b2674","src/strings.rs":"fba5cda8e1d5ce430cfff8f9195a5cc4d7f880262715469583e8ec835a51ea8a"},"package":"1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"} -\ No newline at end of file +{"files":{"Cargo.lock":"524a84e7ed437359ae654e95b6ee0749f47bf23ceac932daa3002bb541f9b2bc","Cargo.toml":"fb2b11e12c9d99325bebc74d083ee6ff0e96c5fd0fc9edf5b38a5bfbdec249bb","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"92c8af8b8515e4fcc2e4c1d97432d4709a73ed98b0afa64a6cc47ddf3befb853","src/bindings.rs":"d8e7c0480c4af752d798b49b293eae4107a4e73f93922e8847c788c70a58b059","src/bool.rs":"2bd56877eda0a6761912dcbe5656a796cc481088afbdbd09f0d6f89dc35c0655","src/bstr.rs":"9f69a04cd6004d64964f8dfd268f3e872d530f50e4e35e82f1e434bb9a57c9a7","src/com.rs":"3111c836c9a2cabcf01b06fc65af474a1e071d9c887db178105c2b52ec78bdd5","src/error.rs":"1403d158ed3cb7c84dc3998a110d8fcccb842c22806e184d0619a05f775236cc","src/hresult.rs":"441ea1b7829e8d66ccf3cb4b98c66508e34f2d5d6eb85f2e4be85ffc910a10ea","src/lib.rs":"6944b7aaa6363b09665b4eaf6820dd82fcc130a0b97fd501c502f90848b6b0fc","src/strings.rs":"fba5cda8e1d5ce430cfff8f9195a5cc4d7f880262715469583e8ec835a51ea8a","windows-result.natvis":"bf9b0a697612a38d1edb2396c09ad136cd98a2e34bd0132c57adc6a486fe03fe"},"package":"7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"} +\ No newline at end of file diff --git a/third_party/rust/windows-result/Cargo.lock b/third_party/rust/windows-result/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +dependencies = [ + "windows-link", +] diff --git a/third_party/rust/windows-result/Cargo.toml b/third_party/rust/windows-result/Cargo.toml @@ -11,11 +11,11 @@ [package] edition = "2021" -rust-version = "1.60" +rust-version = "1.82" name = "windows-result" -version = "0.2.0" -authors = ["Microsoft"] +version = "0.4.1" build = false +autolib = false autobins = false autoexamples = false autotests = false @@ -30,25 +30,22 @@ repository = "https://github.com/microsoft/windows-rs" default-target = "x86_64-pc-windows-msvc" targets = [] +[features] +default = ["std"] +std = [] + [lib] name = "windows_result" path = "src/lib.rs" -[dependencies.windows-targets] -version = "0.52.6" - -[features] -default = ["std"] -std = [] +[dependencies.windows-link] +version = "0.2.1" +default-features = false [lints.rust] -missing_docs = "warn" - -[lints.rust.rust_2018_idioms] -level = "warn" -priority = -1 +missing_unsafe_on_extern = "warn" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 -check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"] +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-result/readme.md b/third_party/rust/windows-result/readme.md @@ -3,14 +3,14 @@ The [windows-result](https://crates.io/crates/windows-result) crate provides efficient Windows error handling and propagation with support for Win32, COM, and WinRT APIs. * [Getting started](https://kennykerr.ca/rust-getting-started/) -* [Samples](https://github.com/microsoft/windows-rs/tree/0.58.0/crates/samples) +* [Samples](https://github.com/microsoft/windows-rs/tree/master/crates/samples) * [Releases](https://github.com/microsoft/windows-rs/releases) Start by adding the following to your Cargo.toml file: ```toml [dependencies.windows-result] -version = "0.2" +version = "0.4" ``` Use the `HRESULT`, `Error`, and specialized `Result` types as needed: diff --git a/third_party/rust/windows-result/src/bindings.rs b/third_party/rust/windows-result/src/bindings.rs @@ -1,20 +1,13 @@ -#![allow( - non_snake_case, - non_upper_case_globals, - non_camel_case_types, - dead_code, - clippy::all -)] -windows_targets::link!("api-ms-win-core-winrt-error-l1-1-0.dll" "system" fn RoOriginateErrorW(error : HRESULT, cchmax : u32, message : PCWSTR) -> BOOL); -windows_targets::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32); -windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR); -windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE); -windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const core::ffi::c_void) -> BOOL); -windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE); -windows_targets::link!("oleaut32.dll" "system" fn GetErrorInfo(dwreserved : u32, pperrinfo : *mut * mut core::ffi::c_void) -> HRESULT); -windows_targets::link!("oleaut32.dll" "system" fn SetErrorInfo(dwreserved : u32, perrinfo : * mut core::ffi::c_void) -> HRESULT); -windows_targets::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR)); -windows_targets::link!("oleaut32.dll" "system" fn SysStringLen(pbstr : BSTR) -> u32); +windows_link::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32); +windows_link::link!("oleaut32.dll" "system" fn GetErrorInfo(dwreserved : u32, pperrinfo : *mut * mut core::ffi::c_void) -> HRESULT); +windows_link::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR); +windows_link::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE); +windows_link::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const core::ffi::c_void) -> BOOL); +windows_link::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE); +windows_link::link!("api-ms-win-core-winrt-error-l1-1-0.dll" "system" fn RoOriginateErrorW(error : HRESULT, cchmax : u32, message : PCWSTR) -> BOOL); +windows_link::link!("oleaut32.dll" "system" fn SetErrorInfo(dwreserved : u32, perrinfo : * mut core::ffi::c_void) -> HRESULT); +windows_link::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR)); +windows_link::link!("oleaut32.dll" "system" fn SysStringLen(pbstr : BSTR) -> u32); pub type BOOL = i32; pub type BSTR = *const u16; pub const ERROR_INVALID_DATA: WIN32_ERROR = 13u32; @@ -45,6 +38,7 @@ impl GUID { } pub type HANDLE = *mut core::ffi::c_void; pub type HEAP_FLAGS = u32; +pub type HINSTANCE = *mut core::ffi::c_void; pub type HMODULE = *mut core::ffi::c_void; pub type HRESULT = i32; pub const IID_IErrorInfo: GUID = GUID::from_u128(0x1cf2b120_547d_101b_8e65_08002b2bd119); diff --git a/third_party/rust/windows-result/src/bool.rs b/third_party/rust/windows-result/src/bool.rs @@ -0,0 +1,90 @@ +use super::*; + +/// A 32-bit value representing boolean values and returned by some functions to indicate success or failure. +#[must_use] +#[repr(transparent)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] +pub struct BOOL(pub i32); + +impl BOOL { + /// Converts the [`BOOL`] to a [`prim@bool`] value. + #[inline] + pub fn as_bool(self) -> bool { + self.0 != 0 + } + + /// Converts the [`BOOL`] to [`Result<()>`][Result<_>]. + #[inline] + pub fn ok(self) -> Result<()> { + if self.as_bool() { + Ok(()) + } else { + Err(Error::from_thread()) + } + } + + /// Asserts that `self` is a success code. + #[inline] + #[track_caller] + pub fn unwrap(self) { + self.ok().unwrap(); + } + + /// Asserts that `self` is a success code using the given panic message. + #[inline] + #[track_caller] + pub fn expect(self, msg: &str) { + self.ok().expect(msg); + } +} + +impl From<BOOL> for bool { + fn from(value: BOOL) -> Self { + value.as_bool() + } +} + +impl From<&BOOL> for bool { + fn from(value: &BOOL) -> Self { + value.as_bool() + } +} + +impl From<bool> for BOOL { + fn from(value: bool) -> Self { + if value { + Self(1) + } else { + Self(0) + } + } +} + +impl From<&bool> for BOOL { + fn from(value: &bool) -> Self { + (*value).into() + } +} + +impl PartialEq<bool> for BOOL { + fn eq(&self, other: &bool) -> bool { + self.as_bool() == *other + } +} + +impl PartialEq<BOOL> for bool { + fn eq(&self, other: &BOOL) -> bool { + *self == other.as_bool() + } +} + +impl core::ops::Not for BOOL { + type Output = Self; + fn not(self) -> Self::Output { + if self.as_bool() { + Self(0) + } else { + Self(1) + } + } +} diff --git a/third_party/rust/windows-result/src/bstr.rs b/third_party/rust/windows-result/src/bstr.rs @@ -1,36 +1,26 @@ use super::*; +use core::ops::Deref; #[repr(transparent)] pub struct BasicString(*const u16); -impl BasicString { - pub fn is_empty(&self) -> bool { - self.len() == 0 - } +impl Deref for BasicString { + type Target = [u16]; - pub fn len(&self) -> usize { - if self.0.is_null() { + fn deref(&self) -> &[u16] { + let len = if self.0.is_null() { 0 } else { unsafe { SysStringLen(self.0) as usize } - } - } - - pub fn as_wide(&self) -> &[u16] { - let len = self.len(); - if len != 0 { - unsafe { core::slice::from_raw_parts(self.as_ptr(), len) } - } else { - &[] - } - } + }; - pub fn as_ptr(&self) -> *const u16 { - if !self.is_empty() { - self.0 + if len > 0 { + unsafe { core::slice::from_raw_parts(self.0, len) } } else { + // This ensures that if `as_ptr` is called on the slice that the resulting pointer + // will still refer to a null-terminated string. const EMPTY: [u16; 1] = [0]; - EMPTY.as_ptr() + &EMPTY[..0] } } } diff --git a/third_party/rust/windows-result/src/error.rs b/third_party/rust/windows-result/src/error.rs @@ -1,7 +1,7 @@ use super::*; use core::num::NonZeroI32; -#[allow(unused_imports)] +#[expect(unused_imports)] use core::mem::size_of; /// An error object consists of both an error code and optional detailed error information for debugging. @@ -115,16 +115,8 @@ impl Error { } /// Creates a new `Error` from the Win32 error code returned by `GetLastError()`. - pub fn from_win32() -> Self { - #[cfg(windows)] - { - let error = unsafe { GetLastError() }; - Self::from_hresult(HRESULT::from_win32(error)) - } - #[cfg(not(windows))] - { - unimplemented!() - } + pub fn from_thread() -> Self { + Self::from_hresult(HRESULT::from_thread()) } /// The error code describing the error. @@ -209,7 +201,7 @@ impl From<core::num::TryFromIntError> for Error { } impl core::fmt::Debug for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { let mut debug = fmt.debug_struct("Error"); debug .field("code", &self.code()) @@ -219,12 +211,12 @@ impl core::fmt::Debug for Error { } impl core::fmt::Display for Error { - fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, fmt: &mut core::fmt::Formatter) -> core::fmt::Result { let message = self.message(); if message.is_empty() { core::write!(fmt, "{}", self.code()) } else { - core::write!(fmt, "{} ({})", self.message(), self.code()) + core::write!(fmt, "{} ({})", message, self.code()) } } } @@ -343,7 +335,7 @@ mod error_info { } } - Some(String::from_utf16_lossy(wide_trim_end(message.as_wide()))) + Some(String::from_utf16_lossy(wide_trim_end(&message))) } pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void { diff --git a/third_party/rust/windows-result/src/hresult.rs b/third_party/rust/windows-result/src/hresult.rs @@ -4,7 +4,6 @@ use super::*; #[repr(transparent)] #[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash)] #[must_use] -#[allow(non_camel_case_types)] pub struct HRESULT(pub i32); impl HRESULT { @@ -80,7 +79,7 @@ impl HRESULT { flags |= FORMAT_MESSAGE_FROM_HMODULE; module = LoadLibraryExA( - b"ntdll.dll\0".as_ptr(), + c"ntdll.dll".as_ptr() as _, core::ptr::null_mut(), LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, ); @@ -113,6 +112,19 @@ impl HRESULT { } } + /// Creates a new `HRESULT` from the Win32 error code returned by `GetLastError()`. + pub fn from_thread() -> Self { + #[cfg(windows)] + { + let error = unsafe { GetLastError() }; + Self::from_win32(error) + } + #[cfg(not(windows))] + { + unimplemented!() + } + } + /// Maps a Win32 error code to an HRESULT value. pub const fn from_win32(error: u32) -> Self { Self(if error as i32 <= 0 { @@ -137,18 +149,18 @@ impl<T> From<Result<T>> for HRESULT { if let Err(error) = result { return error.into(); } - HRESULT(0) + Self(0) } } impl core::fmt::Display for HRESULT { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.write_fmt(format_args!("{:#010X}", self.0)) } } impl core::fmt::Debug for HRESULT { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - f.write_fmt(format_args!("HRESULT({})", self)) + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + f.write_fmt(format_args!("HRESULT({self})")) } } diff --git a/third_party/rust/windows-result/src/lib.rs b/third_party/rust/windows-result/src/lib.rs @@ -1,17 +1,17 @@ -/*! -Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs> -*/ - -#![cfg_attr( - windows_debugger_visualizer, - debugger_visualizer(natvis_file = "../.natvis") -)] +#![doc = include_str!("../readme.md")] +#![debugger_visualizer(natvis_file = "../windows-result.natvis")] #![cfg_attr(all(not(feature = "std"), not(test)), no_std)] -#![cfg_attr(not(windows), allow(unused_imports))] +#![cfg_attr(not(windows), expect(unused_imports))] +#![expect( + dead_code, + non_upper_case_globals, + non_snake_case, + non_camel_case_types, + clippy::upper_case_acronyms +)] extern crate alloc; -#[allow(unused_imports)] use alloc::{string::String, vec::Vec}; mod bindings; @@ -34,5 +34,8 @@ pub use error::*; mod hresult; pub use hresult::HRESULT; +mod bool; +pub use bool::BOOL; + /// A specialized [`Result`] type that provides Windows error information. pub type Result<T> = core::result::Result<T, Error>; diff --git a/third_party/rust/windows-result/windows-result.natvis b/third_party/rust/windows-result/windows-result.natvis @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> + <Type Name="windows_result::error::Error"> + <Expand> + <ExpandedItem>(HRESULT)code.__0.__0,hr</ExpandedItem> + <Item Name="[code]">(HRESULT)code.__0.__0</Item> + <Item Name="[info]">info.ptr</Item> + </Expand> + </Type> + + <Type Name="windows_result::hresult::HRESULT"> + <DisplayString>{(HRESULT)__0}</DisplayString> + </Type> + + <Type Name="windows_result::error::error_info::ErrorInfo"> + <DisplayString>ErrorInfo</DisplayString> + <Expand> + <Item Name="[object]">*(void**)&amp;ptr</Item> + </Expand> + </Type> +</AutoVisualizer> diff --git a/third_party/rust/windows-strings/.cargo-checksum.json b/third_party/rust/windows-strings/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"32a1010e66211d4fb11ce57a26770d00e095287dbd181c4dfb709d0c059dbd19","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"3e1748347e92c36f13f857141779c447faa7e2cd8e8a0d1f9dfe155467f7637e","src/bindings.rs":"ff9b855659617081e57cb702b830e09e44dfcc4cc1245ef2c9096bae987d12b0","src/bstr.rs":"2fcd125475d865390635c387f0a95508fd0ea8235ed89cb8963a8c85d9a05aaf","src/decode.rs":"cecdb73a3b54fb8f3d24a245dddbe790a5e7889771e5c3301cbc5ac375abc7bd","src/hstring.rs":"563c38bbfd0309d9d1ed46982d47c307adbd4b1996edb416c3c21d758d0588f9","src/hstring_builder.rs":"baec1f7c7a7e765dc7abfbfea2aa640f1d73c0427372439bc7b7ab18de9c4d05","src/hstring_header.rs":"3752d9cdf4b9520d360068c84efc6586e3fd28d048cd554b63dba99a2db62117","src/lib.rs":"1ef152a7c2539a80fdef923285cbe1db1a196f6bb1a0b3492609fce64ba90e81","src/literals.rs":"08a5ff6547a9ce50d27ab910cb9d8f8a3b647a412bf320f49ea4a124265157d2","src/pcstr.rs":"832f18aea1b97eb12ecab7e58a4f5f16a22f118a4d9d66d4bdb84c83c2fd3d58","src/pcwstr.rs":"67f619fe360dbdfede4ddb5502fb0a7ef7bd68c787d873c6cf0634eff2bd5860","src/pstr.rs":"34b4b2035330d192e29914f68a1b9096387562e0bf2e1d4bef2937a9fcce7734","src/pwstr.rs":"d4701cd606421100b896d6b0cc09117df0f2e59f47e95d91eb178dfd431c89fe","src/ref_count.rs":"e1617f090d56948719730c81e34449c3d36f288b86a74182719a291c340f65d6"},"package":"4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"} -\ No newline at end of file +{"files":{"Cargo.lock":"88d9a5706935145cf723c8b60ec71dd54cdae595b4adbcbd816475b9b91682f2","Cargo.toml":"4d72a51e7a6f71120de32387f66118bb1aed6a6aee72aa058fa6964af7a0a5a6","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"9d88bef3ed0d04c97af51661e586e90386fc57c64314e43798d40b402762757d","src/bindings.rs":"2cf1f4aa078dfa35ab15e4f6985ccafe2815eb9e2e7d4de68ef91043bc2a2c7d","src/bstr.rs":"c15d999c75aaa7c59d3fd547b4e6a8709e6416812c6f7d92587fa1c0a055d288","src/decode.rs":"791adbab76560d6bcdaf530fa8e81d828f27102f2821b1b37b8913a8d82e7913","src/hstring.rs":"9acd40d74f197e85bfb36adc0c541ad5bb9062c63dc92709d20071d678e848f1","src/hstring_builder.rs":"30065d10c756dbb929c99f3c9d34180d9859e2aea553022a2c0c6c510ada626d","src/hstring_header.rs":"4efd8626e11a7b220898a9616396e4746d66083dd226846ac6bfe30be75c75e9","src/lib.rs":"9b4c7e1380c335d8dc8b84662dfefe960ddbc8c5bafbf5e532425451c66ce88b","src/literals.rs":"eed27b9c506f073b85cccf738e115c80b3b20d3fae35d67efe2c9e5d62642573","src/pcstr.rs":"463e7297aa16d7bb8d6df44c8e1588dbd9996a563144d9b4dafef5ebf294773d","src/pcwstr.rs":"2e213c8da0b2481620980fc438da576aa47df09813405239bd595e1f769b53d6","src/pstr.rs":"1516a072f24692a5bb27d025bd97cd338bc5a104305f7b8418acd6f943a5941b","src/pwstr.rs":"c1e9cd11d41e1875ffa15fa4e29805e6f99aca99a5126aacbe7f169e8b68d790","src/ref_count.rs":"e1617f090d56948719730c81e34449c3d36f288b86a74182719a291c340f65d6","windows-strings.natvis":"e1461f43c6789279ca04cc34e0d614f26162265c862e9c111d251efb843a3798"},"package":"7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"} +\ No newline at end of file diff --git a/third_party/rust/windows-strings/Cargo.lock b/third_party/rust/windows-strings/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-strings" +version = "0.5.1" +dependencies = [ + "windows-link", +] diff --git a/third_party/rust/windows-strings/Cargo.toml b/third_party/rust/windows-strings/Cargo.toml @@ -11,16 +11,16 @@ [package] edition = "2021" -rust-version = "1.60" +rust-version = "1.82" name = "windows-strings" -version = "0.1.0" -authors = ["Microsoft"] +version = "0.5.1" build = false +autolib = false autobins = false autoexamples = false autotests = false autobenches = false -description = "Rust for Windows" +description = "Windows string types" readme = "readme.md" categories = ["os::windows-apis"] license = "MIT OR Apache-2.0" @@ -30,29 +30,22 @@ repository = "https://github.com/microsoft/windows-rs" default-target = "x86_64-pc-windows-msvc" targets = [] +[features] +default = ["std"] +std = [] + [lib] name = "windows_strings" path = "src/lib.rs" -[dependencies.windows-result] -version = "0.2.0" +[dependencies.windows-link] +version = "0.2.1" default-features = false -[dependencies.windows-targets] -version = "0.52.6" - -[features] -default = ["std"] -std = [] - [lints.rust] -missing_docs = "warn" - -[lints.rust.rust_2018_idioms] -level = "warn" -priority = -1 +missing_unsafe_on_extern = "warn" [lints.rust.unexpected_cfgs] level = "warn" priority = 0 -check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"] +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-strings/readme.md b/third_party/rust/windows-strings/readme.md @@ -3,14 +3,14 @@ The [windows-strings](https://crates.io/crates/windows-strings) crate provides common Windows string types used by various Windows APIs. * [Getting started](https://kennykerr.ca/rust-getting-started/) -* [Samples](https://github.com/microsoft/windows-rs/tree/0.58.0/crates/samples) +* [Samples](https://github.com/microsoft/windows-rs/tree/master/crates/samples) * [Releases](https://github.com/microsoft/windows-rs/releases) Start by adding the following to your Cargo.toml file: ```toml [dependencies.windows-strings] -version = "0.1" +version = "0.5" ``` Use the Windows string types as needed: @@ -21,16 +21,14 @@ use windows_strings::*; const A: PCSTR = s!("ansi"); const W: PCWSTR = w!("wide"); -fn main() -> Result<()> { +fn main() { let b = BSTR::from("bstr"); let h = HSTRING::from("hstring"); assert_eq!(b, "bstr"); assert_eq!(h, "hstring"); - assert_eq!(unsafe { A.to_string()? }, "ansi"); - assert_eq!(unsafe { W.to_string()? }, "wide"); - - Ok(()) + assert_eq!(unsafe { A.to_string().unwrap() }, "ansi"); + assert_eq!(unsafe { W.to_string().unwrap() }, "wide"); } ``` diff --git a/third_party/rust/windows-strings/src/bindings.rs b/third_party/rust/windows-strings/src/bindings.rs @@ -5,16 +5,15 @@ dead_code, clippy::all )] -windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE); -windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap : HANDLE, dwflags : HEAP_FLAGS, dwbytes : usize) -> *mut core::ffi::c_void); -windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const core::ffi::c_void) -> BOOL); -windows_targets::link!("oleaut32.dll" "system" fn SysAllocStringLen(strin : PCWSTR, ui : u32) -> BSTR); -windows_targets::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR)); -windows_targets::link!("oleaut32.dll" "system" fn SysStringLen(pbstr : BSTR) -> u32); + +windows_link::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE); +windows_link::link!("kernel32.dll" "system" fn HeapAlloc(hheap : HANDLE, dwflags : HEAP_FLAGS, dwbytes : usize) -> *mut core::ffi::c_void); +windows_link::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const core::ffi::c_void) -> BOOL); +windows_link::link!("oleaut32.dll" "system" fn SysAllocStringLen(strin : PCWSTR, ui : u32) -> BSTR); +windows_link::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR)); +windows_link::link!("oleaut32.dll" "system" fn SysStringLen(pbstr : BSTR) -> u32); pub type BOOL = i32; pub type BSTR = *const u16; -pub const E_OUTOFMEMORY: HRESULT = 0x8007000E_u32 as _; pub type HANDLE = *mut core::ffi::c_void; pub type HEAP_FLAGS = u32; -pub type HRESULT = i32; pub type PCWSTR = *const u16; diff --git a/third_party/rust/windows-strings/src/bstr.rs b/third_party/rust/windows-strings/src/bstr.rs @@ -1,4 +1,5 @@ use super::*; +use core::ops::Deref; /// A BSTR string ([BSTR](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/automat/string-manipulation-functions)) /// is a length-prefixed wide string. @@ -13,53 +14,24 @@ impl BSTR { Self(core::ptr::null_mut()) } - /// Returns `true` if the string is empty. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the length of the string. - pub fn len(&self) -> usize { - if self.0.is_null() { - 0 - } else { - unsafe { bindings::SysStringLen(self.0) as usize } - } - } - - /// Get the string as 16-bit wide characters (wchars). - pub fn as_wide(&self) -> &[u16] { - unsafe { core::slice::from_raw_parts(self.as_ptr(), self.len()) } - } - - /// Returns a raw pointer to the `BSTR` buffer. - pub fn as_ptr(&self) -> *const u16 { - if !self.is_empty() { - self.0 - } else { - const EMPTY: [u16; 1] = [0]; - EMPTY.as_ptr() - } - } - /// Create a `BSTR` from a slice of 16 bit characters (wchars). - pub fn from_wide(value: &[u16]) -> Result<Self> { + pub fn from_wide(value: &[u16]) -> Self { if value.is_empty() { - return Ok(Self::new()); + return Self::new(); } let result = unsafe { Self(bindings::SysAllocStringLen( value.as_ptr(), - value.len().try_into()?, + value.len().try_into().unwrap(), )) }; if result.is_empty() { - Err(Error::from_hresult(HRESULT(bindings::E_OUTOFMEMORY))) - } else { - Ok(result) + panic!("allocation failed"); } + + result } /// # Safety @@ -75,16 +47,37 @@ impl BSTR { } } +impl Deref for BSTR { + type Target = [u16]; + + fn deref(&self) -> &[u16] { + let len = if self.0.is_null() { + 0 + } else { + unsafe { bindings::SysStringLen(self.0) as usize } + }; + + if len > 0 { + unsafe { core::slice::from_raw_parts(self.0, len) } + } else { + // This ensures that if `as_ptr` is called on the slice that the resulting pointer + // will still refer to a null-terminated string. + const EMPTY: [u16; 1] = [0]; + &EMPTY[..0] + } + } +} + impl Clone for BSTR { fn clone(&self) -> Self { - Self::from_wide(self.as_wide()).unwrap() + Self::from_wide(self) } } impl From<&str> for BSTR { fn from(value: &str) -> Self { let value: alloc::vec::Vec<u16> = value.encode_utf16().collect(); - Self::from_wide(&value).unwrap() + Self::from_wide(&value) } } @@ -100,11 +93,11 @@ impl From<&String> for BSTR { } } -impl<'a> TryFrom<&'a BSTR> for String { +impl TryFrom<&BSTR> for String { type Error = alloc::string::FromUtf16Error; fn try_from(value: &BSTR) -> core::result::Result<Self, Self::Error> { - String::from_utf16(value.as_wide()) + Self::from_utf16(value) } } @@ -112,7 +105,7 @@ impl TryFrom<BSTR> for String { type Error = alloc::string::FromUtf16Error; fn try_from(value: BSTR) -> core::result::Result<Self, Self::Error> { - String::try_from(&value) + Self::try_from(&value) } } @@ -123,24 +116,24 @@ impl Default for BSTR { } impl core::fmt::Display for BSTR { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { core::write!( f, "{}", - Decode(|| core::char::decode_utf16(self.as_wide().iter().cloned())) + Decode(|| core::char::decode_utf16(self.iter().cloned())) ) } } impl core::fmt::Debug for BSTR { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - core::write!(f, "{}", self) + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + core::write!(f, "{self}") } } impl PartialEq for BSTR { fn eq(&self, other: &Self) -> bool { - self.as_wide() == other.as_wide() + self.deref() == other.deref() } } @@ -160,10 +153,7 @@ impl PartialEq<BSTR> for String { impl<T: AsRef<str> + ?Sized> PartialEq<T> for BSTR { fn eq(&self, other: &T) -> bool { - self.as_wide() - .iter() - .copied() - .eq(other.as_ref().encode_utf16()) + self.iter().copied().eq(other.as_ref().encode_utf16()) } } diff --git a/third_party/rust/windows-strings/src/decode.rs b/third_party/rust/windows-strings/src/decode.rs @@ -6,7 +6,7 @@ where F: Clone + FnOnce() -> R, R: IntoIterator<Item = core::result::Result<char, E>>, { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { use core::fmt::Write; let iter = self.0.clone(); for c in iter().into_iter() { diff --git a/third_party/rust/windows-strings/src/hstring.rs b/third_party/rust/windows-strings/src/hstring.rs @@ -1,4 +1,5 @@ use super::*; +use core::ops::Deref; /// An ([HSTRING](https://docs.microsoft.com/en-us/windows/win32/winrt/hstring)) /// is a reference-counted and immutable UTF-16 string type. @@ -13,73 +14,47 @@ impl HSTRING { Self(core::ptr::null_mut()) } - /// Returns `true` if the string is empty. - pub fn is_empty(&self) -> bool { - // An empty HSTRING is represented by a null pointer. - self.0.is_null() - } - - /// Returns the length of the string. The length is measured in `u16`s (UTF-16 code units), not including the terminating null character. - pub fn len(&self) -> usize { - if let Some(header) = self.as_header() { - header.len as usize - } else { - 0 - } - } - - /// Get the string as 16-bit wide characters (wchars). - pub fn as_wide(&self) -> &[u16] { - unsafe { core::slice::from_raw_parts(self.as_ptr(), self.len()) } - } - - /// Returns a raw pointer to the `HSTRING` buffer. - pub fn as_ptr(&self) -> *const u16 { - if let Some(header) = self.as_header() { - header.data - } else { - const EMPTY: [u16; 1] = [0]; - EMPTY.as_ptr() - } - } - /// Create a `HSTRING` from a slice of 16 bit characters (wchars). - pub fn from_wide(value: &[u16]) -> Result<Self> { + pub fn from_wide(value: &[u16]) -> Self { unsafe { Self::from_wide_iter(value.iter().copied(), value.len()) } } /// Get the contents of this `HSTRING` as a String lossily. pub fn to_string_lossy(&self) -> String { - String::from_utf16_lossy(self.as_wide()) + String::from_utf16_lossy(self) } /// Get the contents of this `HSTRING` as a OsString. #[cfg(feature = "std")] pub fn to_os_string(&self) -> std::ffi::OsString { - std::os::windows::ffi::OsStringExt::from_wide(self.as_wide()) + std::os::windows::ffi::OsStringExt::from_wide(self) } /// # Safety /// len must not be less than the number of items in the iterator. - unsafe fn from_wide_iter<I: Iterator<Item = u16>>(iter: I, len: usize) -> Result<Self> { + unsafe fn from_wide_iter<I: Iterator<Item = u16>>(iter: I, len: usize) -> Self { if len == 0 { - return Ok(Self::new()); + return Self::new(); } - let ptr = HStringHeader::alloc(len.try_into()?)?; + let ptr = HStringHeader::alloc(len.try_into().unwrap()); // Place each utf-16 character into the buffer and // increase len as we go along. for (index, wide) in iter.enumerate() { debug_assert!(index < len); - (*ptr).data.add(index).write(wide); - (*ptr).len = index as u32 + 1; + unsafe { + (*ptr).data.add(index).write(wide); + (*ptr).len = index as u32 + 1; + } } - // Write a 0 byte to the end of the buffer. - (*ptr).data.offset((*ptr).len as isize).write(0); - Ok(Self(ptr)) + unsafe { + // Write a 0 byte to the end of the buffer. + (*ptr).data.offset((*ptr).len as isize).write(0); + } + Self(ptr) } fn as_header(&self) -> Option<&HStringHeader> { @@ -87,6 +62,21 @@ impl HSTRING { } } +impl Deref for HSTRING { + type Target = [u16]; + + fn deref(&self) -> &[u16] { + if let Some(header) = self.as_header() { + unsafe { core::slice::from_raw_parts(header.data, header.len as usize) } + } else { + // This ensures that if `as_ptr` is called on the slice that the resulting pointer + // will still refer to a null-terminated string. + const EMPTY: [u16; 1] = [0]; + &EMPTY[..0] + } + } +} + impl Default for HSTRING { fn default() -> Self { Self::new() @@ -96,7 +86,7 @@ impl Default for HSTRING { impl Clone for HSTRING { fn clone(&self) -> Self { if let Some(header) = self.as_header() { - Self(header.duplicate().unwrap()) + Self(header.duplicate()) } else { Self::new() } @@ -121,24 +111,24 @@ unsafe impl Send for HSTRING {} unsafe impl Sync for HSTRING {} impl core::fmt::Display for HSTRING { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { write!( f, "{}", - Decode(|| core::char::decode_utf16(self.as_wide().iter().cloned())) + Decode(|| core::char::decode_utf16(self.iter().cloned())) ) } } impl core::fmt::Debug for HSTRING { - fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { - write!(f, "\"{}\"", self) + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!(f, "\"{self}\"") } } impl From<&str> for HSTRING { fn from(value: &str) -> Self { - unsafe { Self::from_wide_iter(value.encode_utf16(), value.len()).unwrap() } + unsafe { Self::from_wide_iter(value.encode_utf16(), value.len()) } } } @@ -169,7 +159,6 @@ impl From<&std::ffi::OsStr> for HSTRING { std::os::windows::ffi::OsStrExt::encode_wide(value), value.len(), ) - .unwrap() } } } @@ -192,13 +181,13 @@ impl Eq for HSTRING {} impl Ord for HSTRING { fn cmp(&self, other: &Self) -> core::cmp::Ordering { - self.as_wide().cmp(other.as_wide()) + self.deref().cmp(other) } } impl core::hash::Hash for HSTRING { fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) { - self.as_wide().hash(hasher) + self.deref().hash(hasher) } } @@ -210,7 +199,7 @@ impl PartialOrd for HSTRING { impl PartialEq for HSTRING { fn eq(&self, other: &Self) -> bool { - *self.as_wide() == *other.as_wide() + self.deref() == other.deref() } } @@ -234,7 +223,7 @@ impl PartialEq<&String> for HSTRING { impl PartialEq<str> for HSTRING { fn eq(&self, other: &str) -> bool { - self.as_wide().iter().copied().eq(other.encode_utf16()) + self.iter().copied().eq(other.encode_utf16()) } } @@ -310,8 +299,7 @@ impl PartialEq<&std::ffi::OsString> for HSTRING { #[cfg(feature = "std")] impl PartialEq<std::ffi::OsStr> for HSTRING { fn eq(&self, other: &std::ffi::OsStr) -> bool { - self.as_wide() - .iter() + self.iter() .copied() .eq(std::os::windows::ffi::OsStrExt::encode_wide(other)) } @@ -373,11 +361,11 @@ impl PartialEq<&HSTRING> for std::ffi::OsString { } } -impl<'a> TryFrom<&'a HSTRING> for String { +impl TryFrom<&HSTRING> for String { type Error = alloc::string::FromUtf16Error; fn try_from(hstring: &HSTRING) -> core::result::Result<Self, Self::Error> { - String::from_utf16(hstring.as_wide()) + Self::from_utf16(hstring) } } @@ -385,12 +373,12 @@ impl TryFrom<HSTRING> for String { type Error = alloc::string::FromUtf16Error; fn try_from(hstring: HSTRING) -> core::result::Result<Self, Self::Error> { - String::try_from(&hstring) + Self::try_from(&hstring) } } #[cfg(feature = "std")] -impl<'a> From<&'a HSTRING> for std::ffi::OsString { +impl From<&HSTRING> for std::ffi::OsString { fn from(hstring: &HSTRING) -> Self { hstring.to_os_string() } diff --git a/third_party/rust/windows-strings/src/hstring_builder.rs b/third_party/rust/windows-strings/src/hstring_builder.rs @@ -8,14 +8,14 @@ pub struct HStringBuilder(*mut HStringHeader); impl HStringBuilder { /// Creates a preallocated `HSTRING` value. - pub fn new(len: usize) -> Result<Self> { - let header = HStringHeader::alloc(len.try_into()?)?; + pub fn new(len: usize) -> Self { + let header = HStringHeader::alloc(len.try_into().unwrap()); if len > 0 { unsafe { core::ptr::write_bytes((*header).data, 0, len) }; } - Ok(Self(header)) + Self(header) } /// Shortens the string by removing any trailing 0 characters. @@ -36,6 +36,17 @@ impl HStringBuilder { } } + /// Allows the `HSTRING` to be constructed from bytes. + pub fn as_bytes_mut(&mut self) -> &mut [u8] { + if let Some(header) = self.as_header() { + unsafe { + core::slice::from_raw_parts_mut(header.data as *mut _, header.len as usize * 2) + } + } else { + &mut [] + } + } + fn as_header(&self) -> Option<&HStringHeader> { unsafe { self.0.as_ref() } } @@ -87,3 +98,13 @@ impl Drop for HStringBuilder { } } } + +impl core::fmt::Debug for HStringBuilder { + fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { + write!( + f, + "\"{}\"", + Decode(|| core::char::decode_utf16(self.iter().cloned())) + ) + } +} diff --git a/third_party/rust/windows-strings/src/hstring_header.rs b/third_party/rust/windows-strings/src/hstring_header.rs @@ -14,9 +14,9 @@ pub struct HStringHeader { } impl HStringHeader { - pub fn alloc(len: u32) -> Result<*mut Self> { + pub fn alloc(len: u32) -> *mut Self { if len == 0 { - return Ok(core::ptr::null_mut()); + return core::ptr::null_mut(); } // Allocate enough space for header and two bytes per character. @@ -27,18 +27,18 @@ impl HStringHeader { unsafe { bindings::HeapAlloc(bindings::GetProcessHeap(), 0, bytes) } as *mut Self; if header.is_null() { - return Err(Error::from_hresult(HRESULT(bindings::E_OUTOFMEMORY))); + panic!("allocation failed"); } unsafe { - // Use `ptr::write` (since `header` is unintialized). `HStringHeader` is safe to be all zeros. + // Use `ptr::write` (since `header` is uninitialized). `HStringHeader` is safe to be all zeros. header.write(core::mem::MaybeUninit::<Self>::zeroed().assume_init()); (*header).len = len; (*header).count = RefCount::new(1); (*header).data = &mut (*header).buffer_start; } - Ok(header) + header } pub unsafe fn free(header: *mut Self) { @@ -46,23 +46,25 @@ impl HStringHeader { return; } - bindings::HeapFree(bindings::GetProcessHeap(), 0, header as *mut _); + unsafe { + bindings::HeapFree(bindings::GetProcessHeap(), 0, header as *mut _); + } } - pub fn duplicate(&self) -> Result<*mut Self> { + pub fn duplicate(&self) -> *mut Self { if self.flags & HSTRING_REFERENCE_FLAG == 0 { // If this is not a "fast pass" string then simply increment the reference count. self.count.add_ref(); - Ok(self as *const Self as *mut Self) + self as *const Self as *mut Self } else { // Otherwise, allocate a new string and copy the value into the new string. - let copy = Self::alloc(self.len)?; + let copy = Self::alloc(self.len); // SAFETY: since we are duplicating the string it is safe to copy all data from self to the initialized `copy`. // We copy `len + 1` characters since `len` does not account for the terminating null character. unsafe { core::ptr::copy_nonoverlapping(self.data, (*copy).data, self.len as usize + 1); } - Ok(copy) + copy } } } diff --git a/third_party/rust/windows-strings/src/lib.rs b/third_party/rust/windows-strings/src/lib.rs @@ -1,21 +1,11 @@ -/*! -Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs> -*/ - +#![doc = include_str!("../readme.md")] #![cfg(windows)] -#![allow(non_snake_case)] -#![cfg_attr( - windows_debugger_visualizer, - debugger_visualizer(natvis_file = "../.natvis") -)] +#![debugger_visualizer(natvis_file = "../windows-strings.natvis")] #![cfg_attr(all(not(feature = "std")), no_std)] extern crate alloc; use alloc::string::String; -pub use windows_result::Result; -use windows_result::*; - mod bstr; pub use bstr::*; @@ -51,6 +41,6 @@ pub use pstr::*; mod pwstr; pub use pwstr::*; -extern "C" { +unsafe extern "C" { fn strlen(s: PCSTR) -> usize; } diff --git a/third_party/rust/windows-strings/src/literals.rs b/third_party/rust/windows-strings/src/literals.rs @@ -41,26 +41,34 @@ macro_rules! h { ($s:literal) => {{ const INPUT: &[u8] = $s.as_bytes(); const OUTPUT_LEN: usize = $crate::utf16_len(INPUT) + 1; - #[allow(clippy::declare_interior_mutable_const)] - const RESULT: $crate::HSTRING = { + static RESULT: $crate::HSTRING = { if OUTPUT_LEN == 1 { - unsafe { ::std::mem::transmute(::std::ptr::null::<u16>()) } + unsafe { ::core::mem::transmute(::core::ptr::null::<u16>()) } } else { + #[repr(C)] + struct HSTRING_HEADER { + flags: u32, + len: u32, + padding1: u32, + padding2: u32, + ptr: *const u16, + padding3: i32, + padding4: u16, + } const OUTPUT: $crate::PCWSTR = $crate::w!($s); - const HEADER: $crate::HSTRING_HEADER = $crate::HSTRING_HEADER { + const HEADER: HSTRING_HEADER = HSTRING_HEADER { flags: 0x11, len: (OUTPUT_LEN - 1) as u32, padding1: 0, padding2: 0, ptr: OUTPUT.as_ptr(), + padding3: 0, + padding4: 0, }; // SAFETY: an `HSTRING` is exactly equivalent to a pointer to an `HSTRING_HEADER` - unsafe { - ::std::mem::transmute::<&$crate::HSTRING_HEADER, $crate::HSTRING>(&HEADER) - } + unsafe { ::core::mem::transmute::<&HSTRING_HEADER, $crate::HSTRING>(&HEADER) } } }; - #[allow(clippy::borrow_interior_mutable_const)] &RESULT }}; } @@ -131,16 +139,6 @@ pub const fn decode_utf8_char(bytes: &[u8], mut pos: usize) -> Option<(u32, usiz } #[doc(hidden)] -#[repr(C)] -pub struct HSTRING_HEADER { - pub flags: u32, - pub len: u32, - pub padding1: u32, - pub padding2: u32, - pub ptr: *const u16, -} - -#[doc(hidden)] pub const fn utf16_len(bytes: &[u8]) -> usize { let mut pos = 0; let mut len = 0; diff --git a/third_party/rust/windows-strings/src/pcstr.rs b/third_party/rust/windows-strings/src/pcstr.rs @@ -32,8 +32,10 @@ impl PCSTR { /// /// The `PCSTR`'s pointer needs to be valid for reads up until and including the next `\0`. pub unsafe fn as_bytes(&self) -> &[u8] { - let len = strlen(*self); - core::slice::from_raw_parts(self.0, len) + unsafe { + let len = strlen(*self); + core::slice::from_raw_parts(self.0, len) + } } /// Copy the `PCSTR` into a Rust `String`. @@ -42,7 +44,7 @@ impl PCSTR { /// /// See the safety information for `PCSTR::as_bytes`. pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf8Error> { - String::from_utf8(self.as_bytes().into()) + unsafe { String::from_utf8(self.as_bytes().into()) } } /// Allow this string to be displayed. @@ -51,6 +53,12 @@ impl PCSTR { /// /// See the safety information for `PCSTR::as_bytes`. pub unsafe fn display(&self) -> impl core::fmt::Display + '_ { - Decode(move || decode_utf8(self.as_bytes())) + unsafe { Decode(move || decode_utf8(self.as_bytes())) } + } +} + +impl Default for PCSTR { + fn default() -> Self { + Self::null() } } diff --git a/third_party/rust/windows-strings/src/pcwstr.rs b/third_party/rust/windows-strings/src/pcwstr.rs @@ -32,10 +32,10 @@ impl PCWSTR { /// /// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`. pub unsafe fn len(&self) -> usize { - extern "C" { + unsafe extern "C" { fn wcslen(s: *const u16) -> usize; } - wcslen(self.0) + unsafe { wcslen(self.0) } } /// Returns `true` if the string length is zero, and `false` otherwise. @@ -44,7 +44,7 @@ impl PCWSTR { /// /// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`. pub unsafe fn is_empty(&self) -> bool { - self.len() == 0 + unsafe { self.len() == 0 } } /// String data without the trailing 0 @@ -53,7 +53,7 @@ impl PCWSTR { /// /// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`. pub unsafe fn as_wide(&self) -> &[u16] { - core::slice::from_raw_parts(self.0, self.len()) + unsafe { core::slice::from_raw_parts(self.0, self.len()) } } /// Copy the `PCWSTR` into a Rust `String`. @@ -62,7 +62,7 @@ impl PCWSTR { /// /// See the safety information for `PCWSTR::as_wide`. pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf16Error> { - String::from_utf16(self.as_wide()) + unsafe { String::from_utf16(self.as_wide()) } } /// Copy the `PCWSTR` into an `HSTRING`. @@ -70,8 +70,8 @@ impl PCWSTR { /// # Safety /// /// See the safety information for `PCWSTR::as_wide`. - pub unsafe fn to_hstring(&self) -> Result<HSTRING> { - HSTRING::from_wide(self.as_wide()) + pub unsafe fn to_hstring(&self) -> HSTRING { + unsafe { HSTRING::from_wide(self.as_wide()) } } /// Allow this string to be displayed. @@ -80,6 +80,18 @@ impl PCWSTR { /// /// See the safety information for `PCWSTR::as_wide`. pub unsafe fn display(&self) -> impl core::fmt::Display + '_ { - Decode(move || core::char::decode_utf16(self.as_wide().iter().cloned())) + unsafe { Decode(move || core::char::decode_utf16(self.as_wide().iter().cloned())) } + } +} + +impl Default for PCWSTR { + fn default() -> Self { + Self::null() + } +} + +impl AsRef<Self> for PCWSTR { + fn as_ref(&self) -> &Self { + self } } diff --git a/third_party/rust/windows-strings/src/pstr.rs b/third_party/rust/windows-strings/src/pstr.rs @@ -32,8 +32,10 @@ impl PSTR { /// /// The `PSTR`'s pointer needs to be valid for reads up until and including the next `\0`. pub unsafe fn as_bytes(&self) -> &[u8] { - let len = strlen(PCSTR::from_raw(self.0)); - core::slice::from_raw_parts(self.0, len) + unsafe { + let len = strlen(PCSTR::from_raw(self.0)); + core::slice::from_raw_parts(self.0, len) + } } /// Copy the `PSTR` into a Rust `String`. @@ -42,7 +44,7 @@ impl PSTR { /// /// See the safety information for `PSTR::as_bytes`. pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf8Error> { - String::from_utf8(self.as_bytes().into()) + unsafe { String::from_utf8(self.as_bytes().into()) } } /// Allow this string to be displayed. @@ -51,6 +53,12 @@ impl PSTR { /// /// See the safety information for `PSTR::as_bytes`. pub unsafe fn display(&self) -> impl core::fmt::Display + '_ { - Decode(move || decode_utf8(self.as_bytes())) + unsafe { Decode(move || decode_utf8(self.as_bytes())) } + } +} + +impl Default for PSTR { + fn default() -> Self { + Self::null() } } diff --git a/third_party/rust/windows-strings/src/pwstr.rs b/third_party/rust/windows-strings/src/pwstr.rs @@ -32,7 +32,7 @@ impl PWSTR { /// /// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`. pub unsafe fn len(&self) -> usize { - PCWSTR(self.0).len() + unsafe { PCWSTR(self.0).len() } } /// Returns `true` if the string length is zero, and `false` otherwise. @@ -41,7 +41,7 @@ impl PWSTR { /// /// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`. pub unsafe fn is_empty(&self) -> bool { - self.len() == 0 + unsafe { self.len() == 0 } } /// String data without the trailing 0. @@ -50,7 +50,7 @@ impl PWSTR { /// /// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`. pub unsafe fn as_wide(&self) -> &[u16] { - core::slice::from_raw_parts(self.0, self.len()) + unsafe { core::slice::from_raw_parts(self.0, self.len()) } } /// Copy the `PWSTR` into a Rust `String`. @@ -59,7 +59,7 @@ impl PWSTR { /// /// See the safety information for `PWSTR::as_wide`. pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf16Error> { - String::from_utf16(self.as_wide()) + unsafe { String::from_utf16(self.as_wide()) } } /// Copy the `PWSTR` into an `HSTRING`. @@ -67,8 +67,8 @@ impl PWSTR { /// # Safety /// /// See the safety information for `PWSTR::as_wide`. - pub unsafe fn to_hstring(&self) -> Result<HSTRING> { - HSTRING::from_wide(self.as_wide()) + pub unsafe fn to_hstring(&self) -> HSTRING { + unsafe { HSTRING::from_wide(self.as_wide()) } } /// Allow this string to be displayed. @@ -77,6 +77,12 @@ impl PWSTR { /// /// See the safety information for `PWSTR::as_wide`. pub unsafe fn display(&self) -> impl core::fmt::Display + '_ { - Decode(move || core::char::decode_utf16(self.as_wide().iter().cloned())) + unsafe { Decode(move || core::char::decode_utf16(self.as_wide().iter().cloned())) } + } +} + +impl Default for PWSTR { + fn default() -> Self { + Self::null() } } diff --git a/third_party/rust/windows-strings/windows-strings.natvis b/third_party/rust/windows-strings/windows-strings.natvis @@ -0,0 +1,62 @@ +<?xml version="1.0" encoding="utf-8"?> +<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> + <Type Name="windows_strings::hstring::HSTRING"> + <Intrinsic Name="header" Expression="(windows_strings::hstring_header::HStringHeader *)__0" /> + <Intrinsic Name="is_empty" Expression="__0 == 0" /> + <DisplayString Condition="is_empty()">""</DisplayString> + <DisplayString>{header()->data,[header()->len]su}</DisplayString> + + <Expand> + <Item Name="[len]">is_empty() ? (unsigned int)0 : header()->len</Item> + <Item Name="[ref_count]" Condition="!is_empty()">header()->count</Item> + <Item Name="[flags]" Condition="!is_empty()">header()->flags</Item> + <Synthetic Name="[chars]" Condition="!is_empty()"> + <Expand> + <ArrayItems> + <Size>header()->len</Size> + <ValuePointer>(char16_t*)header()->data</ValuePointer> + </ArrayItems> + </Expand> + </Synthetic> + </Expand> + </Type> + + <Type Name="windows_strings::pstr::PSTR"> + <AlternativeType Name="windows_strings::pcstr::PCSTR" /> + <Intrinsic Name="len" Expression="strlen(((char*)__0))" /> + <DisplayString>{(char*)__0,[len()]s8}</DisplayString> + <Expand> + <Item Name="[len]">len()</Item> + <Synthetic Name="[chars]"> + <Expand> + <ArrayItems> + <Size>len()</Size> + <ValuePointer>(char*)__0</ValuePointer> + </ArrayItems> + </Expand> + </Synthetic> + </Expand> + </Type> + + <Type Name="windows_strings::pwstr::PWSTR"> + <AlternativeType Name="windows_strings::pcwstr::PCWSTR" /> + <Intrinsic Name="len" Expression="wcslen(((WCHAR*)__0))" /> + <DisplayString>{(char16_t*)__0,[len()]su}</DisplayString> + + <Expand> + <Item Name="[len]">len()</Item> + <Synthetic Name="[chars]"> + <Expand> + <ArrayItems> + <Size>len()</Size> + <ValuePointer>(char16_t*)__0</ValuePointer> + </ArrayItems> + </Expand> + </Synthetic> + </Expand> + </Type> + + <Type Name="windows_strings::ref_count::RefCount"> + <DisplayString>{__0}</DisplayString> + </Type> +</AutoVisualizer> diff --git a/third_party/rust/windows-threading/.cargo-checksum.json b/third_party/rust/windows-threading/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"3e5124277f575af06712d20ebe455301951323a5dc198983fe2120c63b0dcfdb","Cargo.toml":"2583042e5480a0d8bae8e6e450f8d22c17e3fdc785bb1060593c62fc93d94190","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"90752a98bfec41aa1441490117caacb3228a699948970d3d7d2e38b076783b79","src/bindings.rs":"1f24c1f5fa4d01cc1b0928e54a330bcad5b08b058fd07701f3311e168ea2cc9d","src/lib.rs":"a75bb9584007172feedec4624c1fc1a9386342d25a0e7105af6f52f913b1d852","src/pool.rs":"0ca536e02376f5e0849bcec159abe40965b8d88182c42e875bff60e880dc6dbb"},"package":"3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"} +\ No newline at end of file diff --git a/third_party/rust/windows-threading/Cargo.lock b/third_party/rust/windows-threading/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-threading" +version = "0.2.1" +dependencies = [ + "windows-link", +] diff --git a/third_party/rust/windows-threading/Cargo.toml b/third_party/rust/windows-threading/Cargo.toml @@ -0,0 +1,47 @@ +# 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.82" +name = "windows-threading" +version = "0.2.1" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Windows threading" +readme = "readme.md" +categories = ["os::windows-apis"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/microsoft/windows-rs" + +[package.metadata.docs.rs] +default-target = "x86_64-pc-windows-msvc" +targets = [] + +[lib] +name = "windows_threading" +path = "src/lib.rs" + +[dependencies.windows-link] +version = "0.2.1" +default-features = false + +[lints.rust] +missing_unsafe_on_extern = "warn" + +[lints.rust.unexpected_cfgs] +level = "warn" +priority = 0 +check-cfg = ["cfg(windows_raw_dylib, windows_slim_errors)"] diff --git a/third_party/rust/windows-threading/license-apache-2.0 b/third_party/rust/windows-threading/license-apache-2.0 @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright (c) Microsoft Corporation. + + 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/windows-threading/license-mit b/third_party/rust/windows-threading/license-mit @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + 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/windows-threading/readme.md b/third_party/rust/windows-threading/readme.md @@ -0,0 +1,116 @@ +## Windows threading + +The [windows-threading](https://crates.io/crates/windows-threading) crate provides simple, safe, and efficient access to the Windows threading support. + +* [Getting started](https://kennykerr.ca/rust-getting-started/) +* [Samples](https://github.com/microsoft/windows-rs/tree/master/crates/samples) +* [Releases](https://github.com/microsoft/windows-rs/releases) + +Start by adding the following to your Cargo.toml file: + +```toml +[dependencies.windows-threading] +version = "0.2" +``` + +Use the Windows threading support as needed. Here is how you might submit a closure to run on the default thread pool: + +```rust,no_run +windows_threading::submit(|| { + println!("thread: {}", windows_threading::thread_id()); + + loop { + println!("."); + windows_threading::sleep(1000); + } +}); +``` + +As you would expect, the closure will print the thread identifier of the pool thread it is occupying indefinitely and then print "." on one second intervals. + +```text +thread: 27292 +. +. +. +. +. +. +``` + +Here is how you might call a closure on each element of the iterator in parallel, waiting for all closures to finish: + +```rust,no_run +let counter = std::sync::RwLock::<usize>::new(0); + +windows_threading::for_each(0..10, |value| { + println!("thread: {}, value: {value}", windows_threading::thread_id()); + let mut counter = counter.write().unwrap(); + *counter += value; +}); + +println!("\nshould be 45 = {}", counter.read().unwrap()); +``` + +The resulting thread identifiers will be unpredictable and so will be the order of the values: + +```text +thread: 44088, value: 0 +thread: 36152, value: 1 +thread: 36152, value: 3 +thread: 36152, value: 4 +thread: 36152, value: 5 +thread: 36152, value: 7 +thread: 36152, value: 8 +thread: 44088, value: 2 +thread: 41592, value: 6 +thread: 34688, value: 9 + +should be 45 = 45 +``` + +The `for_each` function uses a `Pool` object internally, which you can also use directly if you prefer: + +```rust,no_run +let set = std::sync::RwLock::<std::collections::HashMap<u32, usize>>::default(); +let pool = windows_threading::Pool::new(); +pool.set_thread_limits(2, 10); +pool.scope(|pool| { + for _ in 0..10 { + pool.submit(|| { + windows_threading::sleep(10); + let mut writer = set.write().unwrap(); + *writer.entry(windows_threading::thread_id()).or_default() += 1; + }) + } +}); + +println!("{:#?}", set.read().unwrap()); +``` + +The `set_thread_limits(2, 10)` method is used to ensure that the pool includes at least two threads at all times and up to a maximum of 10. There is no reason to call `set_thread_limits` if you prefer the operating system to manage this dynamically. Calling `set_thread_limits(1, 1)` will for example ensure that all closures run on the same dedicated thread. + +The `submit` method takes the closure and runs it on one of those threads. + +The `join` method waits for all previously submitted closures to finish. + +As you might expect, the resulting distribution of closures spans a number of threads. + +```text +{ + 25064: 3, + 13692: 2, + 40784: 2, + 29608: 3, +} +``` + +Removing the `sleep` call will likely produce very different results: + +```text +{ + 22720: 10, +} +``` + +This is because the thread pool is careful not to overschedule and will happily reuse a small number of threads when the closures finish quickly. diff --git a/third_party/rust/windows-threading/src/bindings.rs b/third_party/rust/windows-threading/src/bindings.rs @@ -0,0 +1,60 @@ +windows_link::link!("kernel32.dll" "system" fn CloseThreadpool(ptpp : PTP_POOL)); +windows_link::link!("kernel32.dll" "system" fn CloseThreadpoolCleanupGroup(ptpcg : PTP_CLEANUP_GROUP)); +windows_link::link!("kernel32.dll" "system" fn CloseThreadpoolCleanupGroupMembers(ptpcg : PTP_CLEANUP_GROUP, fcancelpendingcallbacks : BOOL, pvcleanupcontext : *mut core::ffi::c_void)); +windows_link::link!("kernel32.dll" "system" fn CreateThreadpool(reserved : *const core::ffi::c_void) -> PTP_POOL); +windows_link::link!("kernel32.dll" "system" fn CreateThreadpoolCleanupGroup() -> PTP_CLEANUP_GROUP); +windows_link::link!("kernel32.dll" "system" fn GetCurrentThreadId() -> u32); +windows_link::link!("kernel32.dll" "system" fn SetThreadpoolThreadMaximum(ptpp : PTP_POOL, cthrdmost : u32)); +windows_link::link!("kernel32.dll" "system" fn SetThreadpoolThreadMinimum(ptpp : PTP_POOL, cthrdmic : u32) -> BOOL); +windows_link::link!("kernel32.dll" "system" fn Sleep(dwmilliseconds : u32)); +windows_link::link!("kernel32.dll" "system" fn TrySubmitThreadpoolCallback(pfns : PTP_SIMPLE_CALLBACK, pv : *mut core::ffi::c_void, pcbe : *const TP_CALLBACK_ENVIRON_V3) -> BOOL); +pub type BOOL = i32; +pub type PTP_CALLBACK_INSTANCE = isize; +pub type PTP_CLEANUP_GROUP = isize; +pub type PTP_CLEANUP_GROUP_CANCEL_CALLBACK = Option< + unsafe extern "system" fn( + objectcontext: *mut core::ffi::c_void, + cleanupcontext: *mut core::ffi::c_void, + ), +>; +pub type PTP_POOL = isize; +pub type PTP_SIMPLE_CALLBACK = Option< + unsafe extern "system" fn(instance: PTP_CALLBACK_INSTANCE, context: *mut core::ffi::c_void), +>; +#[repr(C)] +#[derive(Clone, Copy)] +pub struct TP_CALLBACK_ENVIRON_V3 { + pub Version: u32, + pub Pool: PTP_POOL, + pub CleanupGroup: PTP_CLEANUP_GROUP, + pub CleanupGroupCancelCallback: PTP_CLEANUP_GROUP_CANCEL_CALLBACK, + pub RaceDll: *mut core::ffi::c_void, + pub ActivationContext: isize, + pub FinalizationCallback: PTP_SIMPLE_CALLBACK, + pub u: TP_CALLBACK_ENVIRON_V3_0, + pub CallbackPriority: TP_CALLBACK_PRIORITY, + pub Size: u32, +} +impl Default for TP_CALLBACK_ENVIRON_V3 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Clone, Copy)] +pub union TP_CALLBACK_ENVIRON_V3_0 { + pub Flags: u32, + pub s: TP_CALLBACK_ENVIRON_V3_0_0, +} +impl Default for TP_CALLBACK_ENVIRON_V3_0 { + fn default() -> Self { + unsafe { core::mem::zeroed() } + } +} +#[repr(C)] +#[derive(Clone, Copy, Default)] +pub struct TP_CALLBACK_ENVIRON_V3_0_0 { + pub _bitfield: u32, +} +pub type TP_CALLBACK_PRIORITY = i32; +pub const TP_CALLBACK_PRIORITY_NORMAL: TP_CALLBACK_PRIORITY = 1i32; diff --git a/third_party/rust/windows-threading/src/lib.rs b/third_party/rust/windows-threading/src/lib.rs @@ -0,0 +1,85 @@ +#![doc = include_str!("../readme.md")] +#![cfg(windows)] +#![no_std] +#![expect(non_snake_case, non_camel_case_types, clippy::upper_case_acronyms)] + +mod bindings; +use bindings::*; + +mod pool; +pub use pool::*; + +extern crate alloc; +use alloc::boxed::Box; +use core::ffi::c_void; + +/// Submit the closure to the default thread pool. +/// +/// * The closure must have `'static` lifetime as the thread may outlive the lifetime in which `submit` is called. +/// * The closure must be `Send` as it will be sent to another thread for execution. +pub fn submit<F: FnOnce() + Send + 'static>(f: F) { + // This is safe because the closure has `'static` lifetime. + unsafe { + try_submit(core::ptr::null(), f); + } +} + +/// Calls the closure on each element of the iterator in parallel, waiting for all closures to finish. +/// +/// * The closure does not require `'static` lifetime since the `for_each` function bounds the lifetime of all submitted closures. +/// * The closure must be `Sync` as multiple threads will refer to it. +/// * The iterator items must be `Send` as they will be sent from one thread to another. +pub fn for_each<I, F, T>(i: I, f: F) +where + I: Iterator<Item = T>, + F: Fn(T) + Sync, + T: Send, +{ + Pool::with_scope(|pool| { + for item in i { + pool.submit(|| f(item)); + } + }); +} + +/// The thread identifier of the calling thread. +pub fn thread_id() -> u32 { + unsafe { GetCurrentThreadId() } +} + +/// Suspends the execution of the current thread until the time-out interval elapses. +pub fn sleep(milliseconds: u32) { + unsafe { + Sleep(milliseconds); + } +} + +// When used correctly, the Windows thread pool APIs only fail when memory is exhausted. This function will cause such failures to `panic`. +fn check<D: Default + PartialEq>(result: D) -> D { + if result == D::default() { + panic!("allocation failed"); + } + + result +} + +// This function is `unsafe` as it cannot ensure that the lifetime of the closure is sufficient or +// whether the `environment` pointer is valid. +unsafe fn try_submit<F: FnOnce() + Send>(environment: *const TP_CALLBACK_ENVIRON_V3, f: F) { + unsafe extern "system" fn callback<F: FnOnce() + Send>( + _: PTP_CALLBACK_INSTANCE, + callback: *mut c_void, + ) { + unsafe { + Box::from_raw(callback as *mut F)(); + } + } + + unsafe { + check(TrySubmitThreadpoolCallback( + Some(callback::<F>), + Box::into_raw(Box::new(f)) as _, + environment, + )); + } +} diff --git a/third_party/rust/windows-threading/src/pool.rs b/third_party/rust/windows-threading/src/pool.rs @@ -0,0 +1,139 @@ +use super::*; +use core::{marker::PhantomData, ops::Deref}; + +/// A `Pool` object represents a private thread pool with its own thread limits. +/// +/// This is in contrast to the default, or shared, thread pool used by the crate's `submit` function +/// as well as other code within the same process. +pub struct Pool(Box<TP_CALLBACK_ENVIRON_V3>); + +impl Pool { + /// Creates a new `Pool` object. + pub fn new() -> Self { + let mut e = TP_CALLBACK_ENVIRON_V3 { + Version: 3, + CallbackPriority: TP_CALLBACK_PRIORITY_NORMAL, + Size: core::mem::size_of::<TP_CALLBACK_ENVIRON_V3>() as u32, + ..Default::default() + }; + + unsafe { + e.Pool = check(CreateThreadpool(core::ptr::null())); + e.CleanupGroup = check(CreateThreadpoolCleanupGroup()); + } + + // The `TP_CALLBACK_ENVIRON_V3` is boxed to ensure its memory address remains stable for the life of the `Pool` object. + Self(Box::new(e)) + } + + /// Convenience function for creating a new pool and calling [`scope`][Self::scope]. + pub fn with_scope<'env, F>(f: F) + where + F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>), + { + let pool = Pool::new(); + pool.scope(f); + } + + /// Sets the thread limits for the `Pool` object. + pub fn set_thread_limits(&self, min: u32, max: u32) { + unsafe { + check(SetThreadpoolThreadMinimum(self.0.Pool, min)); + SetThreadpoolThreadMaximum(self.0.Pool, max); + } + } + + /// Submit the closure to the thread pool. + /// + /// * The closure must have `'static` lifetime as the thread may outlive the lifetime in which `submit` is called. + /// * The closure must be `Send` as it will be sent to another thread for execution. + pub fn submit<F: FnOnce() + Send + 'static>(&self, f: F) { + // This is safe because the closure has a `'static` lifetime. + unsafe { + try_submit(&*self.0, f); + } + } + + /// Create a scope for submitting closures. + /// + /// Within this scope local variables can be sent to the pool thread for execution. + /// This is possible because `scope` will wait for all submitted closures to finish before returning, + /// Note however that it will also wait for closures that were submitted from other threads. + pub fn scope<'env, F>(&self, f: F) + where + F: for<'scope> FnOnce(&'scope Scope<'scope, 'env>), + { + struct DropGuard<'a>(&'a Pool); + impl Drop for DropGuard<'_> { + fn drop(&mut self) { + self.0.join(); + } + } + // Ensure that we always join the pool before returning. + let _guard = DropGuard(self); + let scope = Scope { + pool: self, + env: PhantomData, + scope: PhantomData, + }; + f(&scope); + } + + /// Waits for all submissions to finish. + /// + /// Dropping the `Pool` will also wait for all submissions to finish. + pub fn join(&self) { + unsafe { + CloseThreadpoolCleanupGroupMembers(self.0.CleanupGroup, 0, core::ptr::null_mut()); + } + } +} + +impl Default for Pool { + fn default() -> Self { + Self::new() + } +} + +unsafe impl Sync for Pool {} +unsafe impl Send for Pool {} + +impl Drop for Pool { + fn drop(&mut self) { + // The `Pool` object cannot be dropped without waiting for all closures to complete, as their + // lifetimes are only guaranteed to be as long as the `Pool` object. + self.join(); + + unsafe { + CloseThreadpoolCleanupGroup(self.0.CleanupGroup); + CloseThreadpool(self.0.Pool); + } + } +} + +/// A scope to submit closures in. +/// +/// See [`scope`][Pool::scope] for details. +pub struct Scope<'scope, 'env: 'scope> { + pool: &'scope Pool, + scope: PhantomData<&'scope mut &'scope ()>, + env: PhantomData<&'env mut &'env ()>, +} + +impl<'scope, 'env> Scope<'scope, 'env> { + /// Submits the closure to run on the `Pool`. + /// + /// The closure cannot outlive the `Scope` it's run in. + pub fn submit<F: FnOnce() + Send + 'scope>(&'scope self, f: F) { + unsafe { + try_submit(&*self.pool.0, f); + } + } +} + +impl Deref for Scope<'_, '_> { + type Target = Pool; + fn deref(&self) -> &Self::Target { + self.pool + } +} diff --git a/toolkit/crashreporter/client/app/Cargo.toml b/toolkit/crashreporter/client/app/Cargo.toml @@ -17,7 +17,7 @@ glean = { workspace = true } intl-memoizer = "0.5" libloading = "0.8" log = "0.4.17" -memtest = "0.4.0" +memtest = { version = "0.4.0", git = "https://github.com/mozilla/memtest", rev = "ad681ba425beb0aeba95f03e671432b4be932174" } minidump-analyzer = { path = "../../minidump-analyzer" } mozbuild = "0.1" mozilla-central-workspace-hack = { version = "0.1", features = ["crashreporter"], optional = true } diff --git a/widget/windows/rust/Cargo.toml b/widget/windows/rust/Cargo.toml @@ -13,8 +13,10 @@ thin-vec = { version = "0.2.1", features = ["gecko-ffi"] } xpcom = { path = "../../../xpcom/rust/xpcom" } [dependencies.windows] -version = "0.58.0" +version = "0.62.0" features = [ - "Foundation_Collections", "UI_Notifications", ] + +[dependencies.windows-collections] +version = "0.3.0" diff --git a/widget/windows/rust/src/lib.rs b/widget/windows/rust/src/lib.rs @@ -7,8 +7,8 @@ use nserror::{nsresult, NS_OK}; use nsstring::{nsAString, nsString}; use thin_vec::ThinVec; use windows::core::HSTRING; -use windows::Foundation::Collections::IVectorView; use windows::UI::Notifications::{ToastNotification, ToastNotificationManager}; +use windows_collections::IVectorView; use xpcom::{xpcom, xpcom_method}; #[xpcom(implement(nsIAlertsServiceRust), nonatomic)] @@ -30,7 +30,7 @@ impl AlertsServiceRust { || -> windows::core::Result<()> { let history = ToastNotificationManager::History()?; let notifications: IVectorView<ToastNotification> = - history.GetHistoryWithId(&HSTRING::from_wide(&aumid[..])?)?; + history.GetHistoryWithId(&HSTRING::from_wide(&aumid[..]))?; for n in notifications { let tag = n.Tag()?;