Structure
Core projects are devided into two cargo projects. The {project-name} and {project-name}-rt.
rt-projects
Projects with the form {name}-rt mustn't be used as dependencies, except for executables and tests. All code which is required for interfacing lives in the {name} project.
The projects without suffix should only have minimal dependencies, so it can be used in other projects as e.g. pilatus-leptos.
If no unstable feature is set on the *-rt crate, it usually only provides a register method, which registers all of its dependencies to minfac
Unstable features
Many pilatus projects have a unstable feature. Code which is available behind these feature flags is not guaranteed to stay stable. They are used to:
- Make code available for testing.
- It's ok if tests of your crate break due to breaking changes in e.g.
pilatus-rt/unstable. Ifunstableis only in[dev-dependencies]and not[dependencies], your crate remains stable for others to be used.
- It's ok if tests of your crate break due to breaking changes in e.g.
- Allow for tightly bound crates.
- The GUI will be tightly coupled to a specific backend version internally. But their interface to dependents is just a stable leptos-component.
{name}-rtprojects may depend on their{name}counterpart with activeunstablefeature. Unstable can e.g. make {name}::DeviceParams available, which is a shining example of a unstable, ever evolving structures you shouldn't depend on in external code. But the UI and thedeviceimplementation in your{name}-rtproject are allowed to rely on it.
Why do we even have -rt projects?
The biggest reason for having *-rt projects is compilation time. RT projects often have significant dependencies. pilatus-axum-rt contains heavy dependencies like tokio, async-zip, image, tower etc. If all this code lived in pilatus-axum, depending crates could only start compiling, when pilatus-axum-rt and all of its dependencies are ready, leading to long dependency chains. For crates on which noone depends on, you could also add a rt feature flag to your {name} project instead. This allows:
- fine grained visibility (e.g. Params-fields are only visible in a submodule)
- avoiding Orphan-Rule problems
In the open source pilatus project, we don't do that, because the UI is always created in a different repo, so it doesn't make sense. The UI is external, so it can easily be published as MIT without any confusions and because we really want to be able to write a new UI with the same conveniences like the official one used. Furthermore, experiments showed, that most code suddenly was behind a cfg(feature = "rt") flag, which seemed off.
Ignore executables
In projects it often makes sense, not to add your executable to your workspace default-members. If you do, each change of your code triggers a rebuild of the executable, which is very slow to link on e.g. Windows.
Maintain two Compilation modes
This all leads to pilatus having two dependency modes: default and integration
| Default | Integration | |
|---|---|---|
| Usage | Building, Unittesting | Integration tests and executables |
| Compilation speed | Faster - excludes heavy runtime dependencies | Slower - includes all runtime dependencies |
| Invocations | cargo build, cargo test | cargo test --test integration, cargo run --bin executable |
To maintain these characteristics, follow these guidelines
- Don't add rt-deps to your [dev-dependencies], as optional dev-deps are not suported by cargo. Add them optional to
[features]and enbable it with theintegrationfeature - RT-Crates are allowed to add
unstablefeature to their non-rt counterpart - Add rules for your editor, which enables your "integration" feature for rust-analyzer (see this project for zed and vscode)
- Check, that
unstableis not used in your project, bycargo checking each project separately. If you run it on the workspace, tests or the executable might enableunstablefeatures
Leptos UI
The frontend code is deliberately developed under the MIT License in a separate repository. You are free to use it as a template for your own frontend and modify it without the need to publish your changes.
The backend is licensed under the MPL-2.0. You may modify it for your own use, but any changes to the backend itself must be shared under the same license, promoting open collaboration and shared progress. The MPL-2.0 is a file-level copyleft license, which means you can combine the backend with proprietary code or extensions without affecting the license of your own proprietary components.