My rust adventure continues as I have been furiously working on Rust/WinRT for the last five months or so. I am indebted to Ryan Levick for patiently answering all of my questions and also jumping in and getting deeply involved in the project early on. I am also looking forward to opening it up to the community as soon as possible. Even then, it will be early days and much still do. I remember chatting with Martyn Lovell about this a few years ago and we basically agreed that it takes about three years to build a language projection. Naturally, you can get value out of it before then but that’s what you need to keep in mind when you consider completeness.

Still, I’m starting to be able to make API calls with Rust/WinRT and its very satisfying to see this come together. So, I’ll leave you with a sneak peek to give you sense of what calling Windows APIs looks like in Rust. Here’s the venerable Windows.Foundation.Uri class:

use windows::foundation::*; let uri = Uri::create_uri("https://kennykerr.ca")?; assert!(uri.domain()? == "kennykerr.ca"); assert!(uri.port()? == 443); assert!(uri.to_string()? == "https://kennykerr.ca/");

Immediately you’ll notice this looks far more like Rust (if you’re familiar with Rust) than it looks like C++ or C#. Notice the snake_case on module and method names and the ? operator for error propagation. The Uri class has a constructor that’s implemented by a factory method called CreateUri. Since Rust lacks constructors, we simply take that CreateUri method and project it as create_uri to conform to Rust’s naming conventions. The to_string method comes from the IStringable interface that the Uri class implements. Even though Rust doesn’t support type inheritance, Rust/WinRT ensures that you get the same classy type system that WinRT is built on. Under the hood, Rust/WinRT will naturally use QueryInterface to query for the IStringable interface so that it just works. You can also expect the same on-the-metal performance and efficiency as you do from C++/WinRT.

Here’s another example using the Windows.ApplicationModel.DataTransfer namespace to copy some value onto the clipboard:

use windows::application_model::data_transfer::*; let content = DataPackage::new()?; content.set_text("Rust/WinRT")?; Clipboard::set_content(content)?; Clipboard::flush()?;

Here we’re calling the DataPackage’s default constructor, but of course Rust doesn’t have constructors. The default constructor is thus replaced with the conventional new method.

And finally, here’s an example of using the Windows.UI.Composition API:

use windows::foundation::numerics::*; use windows::ui::composition::*; use windows::ui::*; let compositor = Compositor::new()?; let visual = compositor.create_sprite_visual()?; let red = Colors::red()?; assert!(red == Color { a: 255, r: 255, g: 0, b: 0 }); let brush = compositor.create_color_brush_with_color(red)?; visual.set_brush(brush)?; visual.set_offset(Vector3 { x: 1.0, y: 2.0, z: 3.0, })?; assert!(visual.offset()? == Vector3 { x: 1.0, y: 2.0, z: 3.0 });

Here you can see we’re creating a Compositor. We use the compositor to create a sprite visual with a red brush and then set the visual’s offset. This seems simple, but that’s a testament to the sheer amount of work that’s already gone into Rust/WinRT to make it seem so natural and native to Rust. The Composition API is one of only two type hierarchies in the Windows API and requires special attention to get right in any language projection, let alone a language that lacks traditional inheritance.

My point here is not to claim these are superb APIs. There may well be a better way to do these tasks in Rust. The point is that Rust/WinRT lets you call any Windows API past, present, and future using code generated on the fly directly from the canonical metadata describing the API and right into your Rust package where you can call them as if they were just another Rust module.

I’m looking forward to sharing more about Rust/WinRT.