MolotovCherry / virtual-display-rs

A Windows virtual display driver to add multiple virtual monitors to your PC! For Win10+. Works with VR, obs, streaming software, etc
MIT License
473 stars 39 forks source link

Dart vdd #108

Open Dampfwalze opened 3 months ago

Dampfwalze commented 3 months ago

Related: #101

root
├───rust
│   └───dart_vdd                        # Rust - Dart bridge (Dart package)
│       ├───example
│       │   └───dart_vdd_example.dart
│       ├───lib
│       │   └───src
│       │       └───generated
│       │           └───api.dart        # Dart API generated from Rust
│       └───rust                        # Cargo project
│           └───src
│               └───api.rs              # Rust API
└───vdd_control                         # Flutter app
    └───lib
        └───main.dart

There are a few points of interest:

I used a Dart feature called native-assets to build and link the Rust library, which is currently not stable and behind an experimental flag. It is essentially a build.dart file, similar to Rusts build.rs. Traditionally, it was not possible to distribute binaries with just Dart. Flutter has its own mechanisms for this, but then, the package can only be used in Flutter projects. The native-assets feature is meant to replace these mechanisms in the future. But for now, it is only available in Flutter on the main channel (like nightly in Rust).

The API uses a Dart Stream as the main way of communicating the driver's state (as an immutable data structure). It would stream any changes made to the driver, regardless of who did it, so it would always reflect the correct state of the driver. This pattern is quite native to Flutter to build on top of.

github-actions[bot] commented 3 months ago

CLA Assistant Lite bot All Contributors have signed the CLA.

Dampfwalze commented 3 months ago

I have read the CLA Document and I hereby sign the CLA

MolotovCherry commented 2 months ago

@Dampfwalze Okay, bindings should be hooked up now. Let me know if this initial implementation is ok or needs reworking 😁

A note about the under the hood Result returns:

stream is just running a thread under the hood. it's meant to only be set once (which is what I assume your use-case was. let me know if this assumption was wrong). not sure how to handle a possible error for stream failure here, so an error is a no-op right now

MolotovCherry commented 2 months ago

I made breaking changes to the bindings again. I'll fix them on this branch later today

Dampfwalze commented 2 months ago

I made breaking changes to the bindings again. I'll fix them on on this branch later today

I reverted the merge for now with a force push

MolotovCherry commented 2 months ago

Should be good now. I feel like I've more or less settled on a good and robust api (though let me know if I did miss something).

Dampfwalze commented 2 months ago

Should be good now. I feel like I've more or less settled on a good and robust api (though let me know if I did miss something).

I feel like you are desperately trying to hide the tokio runtime inside your api and keeping your api synchronous. I don't think this is beneficial. It should be the responsibility of the user to provide a runtime. In fact, flutter_rust_bridge provides its own tokio based runtime.

There are many methods which can just be asynchronious, which not only reduces complexity, but also gives the control to the user.

MolotovCherry commented 2 months ago

Should be good now. I feel like I've more or less settled on a good and robust api (though let me know if I did miss something).

I feel like you are desperately trying to hide the tokio runtime inside your api and keeping your api synchronous. I don't think this is beneficial. It should be the responsibility of the user to provide a runtime. In fact, flutter_rust_bridge provides its own tokio based runtime.

There are many methods which can just be asynchronious, which not only reduces complexity, but also gives the control to the user.

Tokio is indeed an intentional implementation detail, in which the runtime was required to properly handle things for the sync api.

Later on I will re-organize the API and internal code more to better reflect both cases, and in the async case, use the users runtime. When I was talking about settling on something good, I meant with the overall internal design and style of the api (not whether parts were sync or async; that's easily solvable). For example, things like, "did you need access to the monitor state but an api method to access them isn't there?" and "I want to add a mode, but the api doesn't have that function, and I'd rather not write it myself since it's such a common thing"

I was not avoiding making more async methods that match their sync counterparts, or avoiding making a clear delineation between both async/sync apis. The design is after all still in flux, and is an iterative process as most things are.

Did you have need for async equivalents right now?