From 34f2f07301af59261c6401873b23f853e5d18115 Mon Sep 17 00:00:00 2001 From: Samuel Onoja Date: Thu, 22 Oct 2026 01:11:51 +0100 Subject: [PATCH] Enforce shared Rust lint policy and document review rules --- Cargo.toml | 13 +++++ compositor/Cargo.toml | 3 ++ crates/ferese-activities/Cargo.toml | 3 ++ crates/ferese-animation/Cargo.toml | 3 ++ crates/ferese-config/Cargo.toml | 3 ++ crates/ferese-core/Cargo.toml | 3 ++ crates/ferese-ipc/Cargo.toml | 3 ++ crates/ferese-layout/Cargo.toml | 3 ++ crates/ferese-panel/Cargo.toml | 3 ++ crates/ferese-protocols/Cargo.toml | 3 ++ crates/ferese-protocols/src/lib.rs | 5 ++ crates/ferese-theme-client/Cargo.toml | 3 ++ crates/ferese-theme-model/Cargo.toml | 3 ++ crates/ferese-theme/Cargo.toml | 3 ++ docs/README.md | 1 + docs/development.md | 3 ++ docs/development/rust-style.md | 71 +++++++++++++++++++++++++++ feresectl/Cargo.toml | 3 ++ portal/Cargo.toml | 3 ++ rust-toolchain.toml | 2 +- shell/ferese-lock/Cargo.toml | 3 ++ shell/ferese-polkit-agent/Cargo.toml | 3 ++ shell/ferese-settings/Cargo.toml | 3 ++ shell/ferese-shell/Cargo.toml | 3 ++ 24 files changed, 148 insertions(+), 1 deletion(-) create mode 100644 docs/development/rust-style.md diff --git a/Cargo.toml b/Cargo.toml index 4710bbf..22043d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,19 @@ edition = "2024" license = "MIT" rust-version = "1.95" +[workspace.lints.rust] +unsafe_op_in_unsafe_fn = "deny" +unused_must_use = "deny" + +[workspace.lints.clippy] +borrowed_box = "deny" +must_use_candidate = "warn" +needless_for_each = "warn" +ptr_arg = "deny" +ref_option = "deny" +undocumented_unsafe_blocks = "deny" +wildcard_imports = "deny" + [workspace.dependencies] ferese-shape = { git = "https://github.com/ferese-wm/ferese-shape", tag = "v0.1.0" } bitflags = "2.9.4" diff --git a/compositor/Cargo.toml b/compositor/Cargo.toml index 4725cef..92c838b 100644 --- a/compositor/Cargo.toml +++ b/compositor/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-activities = { path = "../crates/ferese-activities" } ferese-panel = { path = "../crates/ferese-panel" } diff --git a/crates/ferese-activities/Cargo.toml b/crates/ferese-activities/Cargo.toml index 3d180d2..f49deb4 100644 --- a/crates/ferese-activities/Cargo.toml +++ b/crates/ferese-activities/Cargo.toml @@ -5,5 +5,8 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] serde.workspace = true diff --git a/crates/ferese-animation/Cargo.toml b/crates/ferese-animation/Cargo.toml index 7454542..a276967 100644 --- a/crates/ferese-animation/Cargo.toml +++ b/crates/ferese-animation/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-layout = { path = "../ferese-layout" } serde.workspace = true diff --git a/crates/ferese-config/Cargo.toml b/crates/ferese-config/Cargo.toml index 670d33e..82c73ed 100644 --- a/crates/ferese-config/Cargo.toml +++ b/crates/ferese-config/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-activities = { path = "../ferese-activities" } regex = "1.12" diff --git a/crates/ferese-core/Cargo.toml b/crates/ferese-core/Cargo.toml index fe86c89..eb2cc37 100644 --- a/crates/ferese-core/Cargo.toml +++ b/crates/ferese-core/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-layout = { path = "../ferese-layout" } serde = { workspace = true, features = ["derive"] } diff --git a/crates/ferese-ipc/Cargo.toml b/crates/ferese-ipc/Cargo.toml index 0e973f9..89cd001 100644 --- a/crates/ferese-ipc/Cargo.toml +++ b/crates/ferese-ipc/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-activities = { path = "../ferese-activities" } serde.workspace = true diff --git a/crates/ferese-layout/Cargo.toml b/crates/ferese-layout/Cargo.toml index 352d181..09e63be 100644 --- a/crates/ferese-layout/Cargo.toml +++ b/crates/ferese-layout/Cargo.toml @@ -5,4 +5,7 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] diff --git a/crates/ferese-panel/Cargo.toml b/crates/ferese-panel/Cargo.toml index a9d79a8..a9aa035 100644 --- a/crates/ferese-panel/Cargo.toml +++ b/crates/ferese-panel/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-animation = { path = "../ferese-animation" } ferese-layout = { path = "../ferese-layout" } diff --git a/crates/ferese-protocols/Cargo.toml b/crates/ferese-protocols/Cargo.toml index dd3f6ad..c35f5fc 100644 --- a/crates/ferese-protocols/Cargo.toml +++ b/crates/ferese-protocols/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [features] default = ["client", "server"] client = ["dep:wayland-client", "wayland-protocols-wlr/client"] diff --git a/crates/ferese-protocols/src/lib.rs b/crates/ferese-protocols/src/lib.rs index c9a2e77..74afbcd 100644 --- a/crates/ferese-protocols/src/lib.rs +++ b/crates/ferese-protocols/src/lib.rs @@ -1,3 +1,8 @@ +// The scanner's generated modules resolve protocol objects through these namespaces. +#![allow( + clippy::wildcard_imports, + reason = "Wayland scanner bindings require protocol imports" +)] #![forbid(unsafe_code)] /// Semantic surface effects protocol. diff --git a/crates/ferese-theme-client/Cargo.toml b/crates/ferese-theme-client/Cargo.toml index ed6f2d6..808d178 100644 --- a/crates/ferese-theme-client/Cargo.toml +++ b/crates/ferese-theme-client/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-config = { path = "../ferese-config" } ferese-ipc = { path = "../ferese-ipc" } diff --git a/crates/ferese-theme-model/Cargo.toml b/crates/ferese-theme-model/Cargo.toml index 748b4eb..8eec3ea 100644 --- a/crates/ferese-theme-model/Cargo.toml +++ b/crates/ferese-theme-model/Cargo.toml @@ -5,5 +5,8 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] serde.workspace = true diff --git a/crates/ferese-theme/Cargo.toml b/crates/ferese-theme/Cargo.toml index 61aaa98..c403cb5 100644 --- a/crates/ferese-theme/Cargo.toml +++ b/crates/ferese-theme/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-layout = { path = "../ferese-layout" } ferese-panel = { path = "../ferese-panel" } diff --git a/docs/README.md b/docs/README.md index 94bee1a..e495c06 100644 --- a/docs/README.md +++ b/docs/README.md @@ -43,6 +43,7 @@ and [guides at that tag](https://github.com/ferese-wm/ferese/tree/v0.1.0-beta/do - [Packages and releases](packaging.md): build Fedora and Arch packages and publish a tagged release. - [Development](development.md): build Ferese, run tests and check portal contracts. - [Publishing activities](development/activities.md): IPC schema, ownership, limits and templates. +- [Rust style](development/rust-style.md): module boundaries, ownership, API contracts and enforced checks. - [Animation model](animation-model.md): geometry, spring motion, gestures and prediction. - [Rendering diagnostics](rendering-performance.md): outcome counters, capture cost and repeatable hardware baselines. - [Output management tests](output-management-testing.md): profiles, hotplug and DRM failures. diff --git a/docs/development.md b/docs/development.md index 0ccfc3d..98a4430 100644 --- a/docs/development.md +++ b/docs/development.md @@ -1,5 +1,8 @@ # Development +Follow the [Rust style rules](development/rust-style.md) when changing workspace code. +They cover module boundaries, API contracts, ownership and the checks enforced by CI. + Install the [build dependencies](installation.md#requirements), then run: ```sh diff --git a/docs/development/rust-style.md b/docs/development/rust-style.md new file mode 100644 index 0000000..be395eb --- /dev/null +++ b/docs/development/rust-style.md @@ -0,0 +1,71 @@ +# Rust style + +Ferese follows the [Rust Style Guide](https://google.github.io/styleguide/rustguide.html) +with the stable toolchain pinned in `rust-toolchain.toml`. Rules marked for Chromium +or Fuchsia belong to those projects, so they do not change Ferese's Cargo layout, +async runtimes, threading or test framework. + +Keep each change focused enough to review and test on its own. Formatting, module +moves and behavioral fixes should have separate commits, and a refactor should +retain the assertions that established the existing behavior. + +## Modules and imports + +Keep library roots focused on module declarations and re-exports, and put substantial +implementations in modules named for the types they own. Application entry points +can contain the wiring needed to start their services; splitting that wiring should +make ownership clearer rather than add forwarding layers. + +Import types by name and qualify functions through their module unless their names +already identify their purpose unambiguously. Each import should draw from one +module. Avoid glob imports, with the guide's exceptions for inline tests, local enum +matches and re-exports. The Wayland scanner's generated namespaces also need glob +imports, and GStreamer's prelude supplies its extension traits. + +## APIs and ownership + +Borrow the data a function needs: use `&str` and slices instead of references to +owned containers, and `Option<&T>` instead of `&Option`. Clone when the caller +needs independent ownership, including messages that outlive the current callback. +Shared worker state and UI resources can use `Arc` when their lifetimes require it. + +Name fallible constructors `try_new`, use standard traits when their contracts fit, +and mark pure return values with `#[must_use]`. Prefer named fields when tuple +positions would conceal meaning. Document constraints, failure conditions and +ownership that callers cannot infer from the signature, without repeating obvious +method names in comments. + +Ferese's workspace crates evolve together. Their shared enums can remain exhaustive +so adding a state makes every affected consumer visible to the compiler. Apply +`#[non_exhaustive]` when an API crosses an independently maintained boundary and its +consumers cannot be updated together. + +## Safety and errors + +Use `Result` when callers need to distinguish recoverable failures and `Option` when +absence explains the outcome. Match a checked value rather than checking and then +unwrapping it. If an invariant requires a panic, use `expect` to explain it. + +Keep unsafe operations at their system or library boundary. Every unsafe block needs +a `SAFETY:` comment explaining its actual pointer bounds, ownership, lifetime or ABI +requirements, and unsafe functions must document what their callers guarantee. +Never recover the contents of a poisoned mutex. A disposable cache may be skipped; +state needed for correctness must fail or stop being used. + +## Checks + +Stable rustfmt uses a 100-column target. Keep imports grouped by module during +review, since stable rustfmt does not yet enforce that setting. All workspace +members inherit the shared Rust and Clippy lints from the root manifest. + +```sh +cargo fmt --all --check +cargo clippy --locked --workspace --all-targets -- -D warnings +cargo clippy --locked --workspace --all-targets --all-features -- -D warnings +cargo test --locked --workspace --no-fail-fast +python3 -m unittest discover -s scripts/tests -v +``` + +Use the [native test guides](../development.md#test-guides) for changes to rendering, +input, surface lifetimes or process supervision. Headless checks complement native +and hardware testing; they do not establish frame pacing or direct-session stability. diff --git a/feresectl/Cargo.toml b/feresectl/Cargo.toml index 65443fe..8512037 100644 --- a/feresectl/Cargo.toml +++ b/feresectl/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-activities = { path = "../crates/ferese-activities" } clap = { version = "4.5", features = ["derive"] } diff --git a/portal/Cargo.toml b/portal/Cargo.toml index c9c9ded..2885ded 100644 --- a/portal/Cargo.toml +++ b/portal/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [[bin]] name = "xdg-desktop-portal-ferese" path = "src/main.rs" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5a30785..12dd525 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] channel = "1.95.0" profile = "minimal" -components = ["rustfmt"] +components = ["rustfmt", "clippy"] diff --git a/shell/ferese-lock/Cargo.toml b/shell/ferese-lock/Cargo.toml index ad0d899..6940720 100644 --- a/shell/ferese-lock/Cargo.toml +++ b/shell/ferese-lock/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-theme-client = { path = "../../crates/ferese-theme-client" } ferese-ipc = { path = "../../crates/ferese-ipc" } diff --git a/shell/ferese-polkit-agent/Cargo.toml b/shell/ferese-polkit-agent/Cargo.toml index a12efd9..a9e838e 100644 --- a/shell/ferese-polkit-agent/Cargo.toml +++ b/shell/ferese-polkit-agent/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-theme-client = { path = "../../crates/ferese-theme-client" } ferese-ipc = { path = "../../crates/ferese-ipc" } diff --git a/shell/ferese-settings/Cargo.toml b/shell/ferese-settings/Cargo.toml index e795766..974ca6e 100644 --- a/shell/ferese-settings/Cargo.toml +++ b/shell/ferese-settings/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] ferese-panel = { path = "../../crates/ferese-panel" } ferese-theme-client = { path = "../../crates/ferese-theme-client" } diff --git a/shell/ferese-shell/Cargo.toml b/shell/ferese-shell/Cargo.toml index 6296592..84171db 100644 --- a/shell/ferese-shell/Cargo.toml +++ b/shell/ferese-shell/Cargo.toml @@ -5,6 +5,9 @@ edition.workspace = true license.workspace = true rust-version.workspace = true +[lints] +workspace = true + [dependencies] fff-search = "=0.11.0" mime_guess = "2.0.5"