101 lines
8.2 KiB
Markdown
101 lines
8.2 KiB
Markdown
<!-- file: docs/rules/RULES_RUST.md -->
|
|
<!-- version: 4 -->
|
|
|
|
# Règles Rust générales
|
|
|
|
## Portée
|
|
|
|
Les règles `RUST-*` s'appliquent aux crates, sources, tests, exemples et outils Rust de KSP. Elles sont conçues pour rester réutilisables hors de KSP lorsque la règle ne dépend pas de son architecture.
|
|
|
|
## Édition et lints
|
|
|
|
- **RUST-BASE-001** — L'édition Rust est Rust 2024, sauf contrainte externe explicitement documentée.
|
|
- **RUST-BASE-002** — Chaque `lib.rs` et `main.rs` contient `#![warn(missing_docs)]`, `#![deny(unreachable_pub)]` et `#![forbid(unsafe_code)]`.
|
|
- **RUST-BASE-003** — Les lints communs sont déclarés au niveau workspace et hérités par les crates.
|
|
- **RUST-BASE-004** — Le code `unsafe` est interdit.
|
|
|
|
## Documentation des API
|
|
|
|
- **RUST-DOC-001** — Tout élément `pub` ou `pub(crate)` possède une rustdoc utile au point de déclaration.
|
|
- **RUST-DOC-002** — Toute réexportation `pub use` ou `pub(crate) use` dans `lib.rs` ou `main.rs` possède également une rustdoc utile.
|
|
- **RUST-DOC-003** — La façade d'une crate doit permettre de comprendre son API sans dépendre de ses chemins de modules internes.
|
|
|
|
## Imports et chemins
|
|
|
|
- **RUST-IMPORT-001** — `use` est interdit pour les constantes, fonctions, structures, énumérations, unions, alias de types, modules et macros.
|
|
- **RUST-IMPORT-002** — `use` est autorisé uniquement pour un trait lorsque la résolution de méthode, une macro de dérivation ou une contrainte du langage l'exige réellement.
|
|
- **RUST-IMPORT-003** — Un import de trait reste étroit et ne mélange pas de non-traits dans un import groupé.
|
|
- **RUST-IMPORT-004** — Les glob imports et imports groupés par accolades sont interdits.
|
|
- **RUST-IMPORT-005** — Pour un élément externe, utiliser directement le chemin public le plus court fourni par la crate propriétaire.
|
|
- **RUST-IMPORT-006** — Pour un élément `pub` d'une crate KSP, l'API est réexportée au crate-root et consommée depuis une autre crate via `owner_crate::Item`.
|
|
- **RUST-IMPORT-007** — Dans sa propre crate, un élément `pub` ou `pub(crate)` partagé est consommé via `crate::Item` après réexport approprié.
|
|
- **RUST-IMPORT-008** — Un helper strictement privé au module reste privé et est appelé localement ; dans un sous-module de tests, un élément privé du module parent est appelé via `super::Item`.
|
|
- **RUST-IMPORT-009** — Les réexports ne sont pas groupés par accolades et les alias `as` sont interdits dans les réexports.
|
|
- **RUST-IMPORT-010** — Un réexport d'un module interne commence par `self::`.
|
|
|
|
## Visibilité et façade de crate
|
|
|
|
- **RUST-API-001** — Aucun `pub mod` n'est autorisé ; les modules restent privés et l'API externe est constituée par des réexports explicites au crate-root.
|
|
- **RUST-API-002** — `pub(in ...)` et `pub(super)` sont interdits.
|
|
- **RUST-API-003** — Un élément `pub` inaccessible depuis la façade de sa crate est une erreur de conception.
|
|
- **RUST-API-004** — Un élément `pub(crate)` utilisé hors de son module est réexporté au crate-root via `pub(crate) use`.
|
|
- **RUST-API-005** — Les chemins internes de modules ne constituent pas une API stable.
|
|
|
|
## Contrôle de flux et erreurs
|
|
|
|
- **RUST-ERR-001** — `unwrap`, `expect` et `panic` sont interdits dans le code de production.
|
|
- **RUST-ERR-002** — L'opérateur `?` est interdit dans le code de production ; les chemins d'erreur utilisent un contrôle de flux explicite.
|
|
- **RUST-ERR-003** — Les retours sont explicites conformément au lint `clippy::implicit_return`.
|
|
- **RUST-ERR-004** — `anyhow` et `thiserror` ne sont pas utilisés par défaut ; leur introduction exige une justification architecturale.
|
|
- **RUST-ERR-005** — Les erreurs publiques sont typées lorsque leur contrat est stable.
|
|
- **RUST-ERR-006** — Les tests peuvent utiliser `unwrap` ou `expect` uniquement dans la limite explicitement autorisée par la configuration Clippy.
|
|
|
|
## Formatage
|
|
|
|
- **RUST-FMT-001** — `rustfmt.toml` à la racine est la configuration canonique du formatage Rust.
|
|
- **RUST-FMT-002** — `cargo fmt --all` est exécuté après chaque modification Rust avant les validations de compilation et de test.
|
|
- **RUST-FMT-003** — Les fichiers Rust ne contiennent pas de lignes vides à l'intérieur d'une fonction, structure, énumération ou implémentation courte.
|
|
- **RUST-FMT-004** — Les lignes vides séparent uniquement des fonctions, types, blocs `impl` ou sections logiques distinctes.
|
|
- **RUST-FMT-005** — Les groupes homogènes de `pub use` ou `pub(crate) use` ne contiennent pas de ligne vide interne ; `pub use` précède `pub(crate) use` lorsqu'ils coexistent.
|
|
|
|
## Helpers et duplication
|
|
|
|
- **RUST-HELP-001** — Un helper répété dans plusieurs modules d'une même crate est déplacé dans un module commun dont le nom décrit la responsabilité la plus précise possible.
|
|
- **RUST-HELP-002** — Un helper réellement général et réutilisable par plusieurs crates est déplacé dans la bibliothèque KSP appropriée.
|
|
- **RUST-HELP-003** — La mutualisation ne doit pas créer de dépendance cyclique ni déplacer une logique métier spécifique dans une bibliothèque générique.
|
|
|
|
## Dépendances
|
|
|
|
- **RUST-DEP-001** — Une dépendance n'est ajoutée que si elle est réellement utilisée dans le chemin de compilation concerné.
|
|
- **RUST-DEP-002** — Une dépendance uniquement utilisée par les tests reste dans `[dev-dependencies]`.
|
|
- **RUST-DEP-003** — Les features sont minimales et explicites.
|
|
- **RUST-DEP-004** — Les lockfiles de dépendances ne sont pas versionnés dans KSP.
|
|
- **RUST-DEP-005** — KSP privilégie les versions récentes compatibles. Toute version volontairement contrainte ou ancienne doit être documentée avec sa raison et la condition permettant de lever la contrainte.
|
|
|
|
## Assertions de collections
|
|
|
|
- **RUST-TEST-001** — Un test vérifiant uniquement l'appartenance à un ensemble peut trier les valeurs obtenues et attendues avant `assert_eq!` lorsque l'ordre n'est pas contractuel.
|
|
- **RUST-TEST-002** — Une collection n'est jamais triée artificiellement dans un test lorsque l'ordre fait partie du contrat, notamment pour comptes Solana, metas, instructions, signers, événements, étapes de pipeline, priorités ou journaux ordonnés.
|
|
|
|
## Organisation des tests
|
|
|
|
- **RUST-TEST-003** — Les sources de tests unitaires sont placées autant que possible dans un répertoire `unit_tests/` à la racine de la crate et reflètent autant que possible l'arborescence et les noms des modules sous `src/`.
|
|
- **RUST-TEST-004** — Un fichier sous `unit_tests/` reste un vrai test unitaire : il est rattaché explicitement sous `#[cfg(test)]` au module de production qu'il teste et peut donc tester ses éléments privés.
|
|
- **RUST-TEST-005** — Le répertoire Cargo standard `tests/` est réservé aux tests d'intégration. Les fichiers qui y sont découverts comme cibles d'intégration testent la crate comme un consommateur externe et n'utilisent que son API publique.
|
|
- **RUST-TEST-006** — Toute partie pertinente de l'API publique d'une bibliothèque KSP doit, lorsque cela est techniquement possible, être couverte par de vrais tests d'intégration sous `tests/`, afin de valider notamment les réexports, la visibilité et le contrat réellement consommable depuis une autre crate.
|
|
- **RUST-TEST-007** — La séparation physique sous `unit_tests/` est la convention préférée et doit être utilisée au maximum. La colocalisation d'un test unitaire dans le fichier/module de production n'est autorisée qu'en dernier recours lorsqu'un rattachement externe serait techniquement impossible, incorrect ou créerait une complexité disproportionnée clairement justifiable.
|
|
- **RUST-TEST-008** — Un test unitaire séparé suit autant que possible le même chemin relatif et le même nom que le module testé, afin que la correspondance `src/...` ↔ `unit_tests/...` soit immédiatement identifiable.
|
|
|
|
## Contrôle de clôture Rust
|
|
|
|
Lorsqu'une tranche contient du Rust, les contrôles minimaux sont :
|
|
|
|
```bash
|
|
cargo fmt --all
|
|
cargo check --workspace
|
|
cargo test --workspace
|
|
cargo clippy --workspace --all-targets
|
|
```
|
|
|
|
Les audits structurels automatisés seront ajoutés lorsqu'ils existeront dans KSP ; une règle ne doit pas prétendre qu'un script inexistant a été exécuté.
|