# 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é.