14 KiB
14 KiB
Règles Rust générales
Portée
Les règles RUST-* s'appliquent à tous les fichiers Rust de KSP : crates, sources, tests, exemples et outils. Elles reprennent les règles déjà éprouvées sur les générations précédentes du projet et les rendent explicites afin que rustfmt et Clippy ne soient jamais considérés comme des contrôles structurels suffisants.
Édition et lints
- RUST-BASE-001 — L'édition Rust est Rust 2024, sauf contrainte externe explicitement documentée.
- RUST-BASE-002 — Chaque
lib.rsetmain.rscontient#![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
unsafeest interdit. - RUST-BASE-005 — Tout fichier Rust possède les en-têtes
// file: ...et// version: N, et se termine par exactement une fin de ligne.
Documentation des API et contrats internes
- RUST-DOC-001 — Tout élément
puboupub(crate)possède une rustdoc utile au point de déclaration. Cette règle couvre aussi les méthodes associées et les champs nommés visibles à ces niveaux. - RUST-DOC-002 — Toute réexportation
pub useoupub(crate) usedanslib.rsoumain.rspossède sa propre rustdoc utile et adjacente. - RUST-DOC-003 — La façade d'une crate doit permettre de comprendre son API publique et ses contrats crate-wide sans dépendre de chemins de modules internes.
- RUST-DOC-004 — Les rustdocs et commentaires du code sont en anglais ; la documentation Markdown KSP reste en français sauf document explicitement destiné à une audience différente.
Imports et chemins
- RUST-IMPORT-001 —
useest interdit pour les constantes, fonctions, structures, énumérations, unions, alias de types, modules et macros. - RUST-IMPORT-002 —
useest autorisé uniquement pour un trait lorsqu'une résolution de méthode, une dérivation ou une contrainte du langage l'exige réellement. Le motif est explicité sur la ligne parrust-rules: trait-import. - RUST-IMPORT-003 — Les imports de traits restent étroits ; un import de trait ne mélange jamais d'éléments non-traits.
- RUST-IMPORT-004 — Les glob imports et imports groupés par accolades sont interdits.
- RUST-IMPORT-005 — Les alias
assont interdits dans tous lesuse, réexports et déclarationsextern crate. Le symbole reçoit son nom canonique dans son module propriétaire. - RUST-IMPORT-006 — Les déclarations
usesont au niveau du module, dans le bloc d'en-tête avant les déclarations métier. Aucunusen'est introduit dans une fonction, méthode, bloc, test ou branche conditionnelle. - RUST-IMPORT-007 — Pour un élément fourni par une crate externe, utiliser directement le chemin public le plus court exposé par cette crate ; ne pas créer un import non-trait pour raccourcir ce chemin.
- RUST-IMPORT-008 — Pour un élément
pubd'une crate KSP, la crate propriétaire le réexporte au crate-root. Une autre crate l'appelle viaowner_crate::Item. - RUST-IMPORT-009 — Dans sa propre crate, un élément
puboupub(crate)partagé est appelé viacrate::Item, y compris depuis son module de déclaration lorsque le contrat est crate-wide. - RUST-IMPORT-010 — Un chemin
crate::module::Itemest interdit pour un élément partagépub/pub(crate)qui peut être consommé via le crate-root. Le chemin du module interne n'est pas une façade. - RUST-IMPORT-011 — Un élément strictement privé à un module n'est pas réexporté et est appelé par son nom local dans ce module.
- RUST-IMPORT-012 — Dans un fichier
unit_tests/...rattaché au module parent, tout élément strictement privé du parent est appelé explicitement viasuper::Item. Inversement, un élémentpuboupub(crate)n'est jamais appelé viasuper::ni par un nom nu : il continue d'être appelé via le crate-rootcrate::Item, y compris lorsque le test est rattaché à son module de déclaration. - RUST-IMPORT-013 — Les réexports internes commencent par
self::. Un réexport d'une crate externe peut utiliser directement le chemin externe canonique. - RUST-IMPORT-014 — Un export correspond à une ligne de réexport distincte ; les accolades ne servent jamais à regrouper une façade.
- RUST-IMPORT-015 — Une crate externe rendue publique uniquement pour l'hygiène d'une macro exportée conserve son nom canonique, porte
#[doc(hidden)]et ne devient pas une API de consommation.ksp-logging-lib::tracingest ce bridge technique pour les macros Logging ; les autres crates KSP n'y accèdent jamais directement.
Visibilité et façade de crate
- RUST-API-001 — Aucun
pub modn'est autorisé ; les modules restent privés et l'API externe est constituée exclusivement par des réexports explicites au crate-root. - RUST-API-002 —
pub(in ...)etpub(super)sont interdits. - RUST-API-003 — Un élément
pubinaccessible depuis la façade de sa crate est une erreur de conception. - RUST-API-004 — Un élément
pub(crate)consommé hors de son module est réexporté au crate-root viapub(crate) usepuis appelé viacrate::Item. - RUST-API-005 — Les chemins internes de modules ne constituent jamais une API stable.
- RUST-API-006 — Si deux éléments crate-wide auraient le même nom au crate-root, ils sont renommés dans leurs modules propriétaires avec des noms canoniques non ambigus ; un alias de réexport n'est pas utilisé pour masquer la collision.
- RUST-API-007 — La visibilité d'un item n'est jamais élargie uniquement pour permettre son test. Un helper utilisé seulement par son module et ses
unit_tests/reste privé et les tests y accèdent viasuper::Item; il ne devientpub(crate)que lorsqu'un autre module de production le consomme réellement, auquel casRUST-API-004etRUST-IMPORT-009s'appliquent. - RUST-API-008 — Un helper strictement privé dont aucun chemin de production ne dépend encore et qui n'existe que pour un
unit_tests/de préparation est compilé sous#[cfg(test)]jusqu'à sa première consommation de production réelle. Il ne reste pas mort dans le build normal et n'est pas conservé au moyen d'un#[allow(dead_code)]compensatoire.
Formatage, blocs et ordre
- RUST-FMT-001 —
rustfmt.tomlà la racine est la configuration canonique du formatage Rust. - RUST-FMT-002 —
cargo fmt --allest exécuté après chaque modification Rust avant l'audit structurel et les validations Cargo. - RUST-FMT-003 — Aucune ligne vide n'est conservée à l'intérieur du corps d'une fonction ou méthode, ni à l'intérieur d'une définition
structouenum. - RUST-FMT-004 — Deux fonctions ou méthodes distinctes, y compris deux
const fn, sont séparées par exactement une ligne vide. La même séparation exacte s'applique entrestruct,enum,union,trait, blocimplet fonction/méthode lorsqu'ils constituent des items voisins d'un même scope. - RUST-FMT-005 — Les blocs homogènes sont ordonnés alphabétiquement par nom lorsque l'ordre n'a pas de signification sémantique. Cette règle ne redéfinit pas l'ordre interne des
use/réexports : pour ceux-ci, la sortie decargo fmt --allest canonique. - RUST-FMT-006 — Les constantes de module ou associées sont ordonnées par visibilité
pub, puispub(crate), puis privée, et alphabétiquement dans chaque niveau. Deux constantes de même visibilité appartenant au même bloc ne sont séparées par aucune ligne vide ; exactement une ligne vide sépare deux niveaux de visibilité distincts. - RUST-FMT-007 — Dans une façade, le bloc
pub useprécède le blocpub(crate) use; une seule ligne vide sépare les deux blocs et aucune ligne vide n'existe à l'intérieur d'un bloc. L'ordre intra-bloc desuse/réexports est celui produit parcargo fmt --all; l'audit Python ne lui substitue aucun tri concurrent par symbole exporté ou chemin source. - RUST-FMT-008 — Les déclarations
modd'un même bloc sont ordonnées alphabétiquement ; les modules de tests conditionnels restent après les modules de production. - RUST-FMT-009 — Lorsqu'un
structet ses blocsimplforment une unité locale sans contrainte de séparation, l'implémentation suit la structure. Les éléments visibles précèdent les helpers privés lorsqu'aucun ordre métier ou protocolaire n'impose l'inverse. - RUST-FMT-010 — L'ordre alphabétique n'écrase jamais un ordre contractuel ou sémantique : wire fields, comptes Solana, étapes de protocole, priorités, transitions d'état, tableaux de dispatch et séquences explicitement normatives conservent leur ordre défini.
- RUST-FMT-011 — Les blocs homogènes de
typeoustaticde même visibilité suivent la même règle d'espacement compact que les constantes ; un changement de catégorie ou de visibilité recrée une séparation d'exactement une ligne vide. - RUST-FMT-012 — Une déclaration d'item placée après un
returninconditionnel au niveau principal d'une fonction/méthode est interdite ; elle est traitée comme un signal probable d'accolade fermante déplacée ou de bloc mal restructuré.
Contrôle de flux et erreurs
- RUST-ERR-001 —
unwrap,expectetpanicsont 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 —
anyhowetthiserrorne 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
unwrapouexpectuniquement dans la limite explicitement autorisée par la configuration Clippy. - RUST-ERR-007 — Avant d'attacher une erreur externe comme
sourcedeksp_core_lib::Error, la crate propriétaire vérifie que sa chaîneDebug/sourcene peut pas exposer de secret. Lorsqu'une dépendance fournit une primitive de neutralisation, elle est appliquée avantwith_source.
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 est documentée avec sa raison et la condition permettant de lever la contrainte.
Assertions et organisation des tests
- 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 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.
- RUST-TEST-003 — Les tests unitaires sont placés autant que possible dans
unit_tests/et reflètent l'arborescence desrc/. - RUST-TEST-004 — Un fichier
unit_tests/...est rattaché explicitement au module de production via#[cfg(test)]et#[path = ...]; il peut tester les éléments privés de ce module. - RUST-TEST-005 —
tests/est réservé aux vrais tests d'intégration consommant uniquement l'API publique de la crate. - RUST-TEST-006 — Toute partie pertinente de l'API publique est couverte, lorsque possible, par un test d'intégration afin de valider les réexports et la visibilité réellement consommables.
- RUST-TEST-007 — La colocalisation d'un test unitaire dans le fichier de production reste une exception justifiée.
Audit structurel automatisé
- RUST-AUDIT-001 —
scripts/audit_rust_workspace_rules.pyest le point d'entrée obligatoire de l'audit Rust KSP. Il exécute les audits généraux, la complétude des réexports/chemins et les frontières KSP sans fusionner leurs responsabilités. - RUST-AUDIT-002 — L'audit est dependency-free côté Python standard et échoue avec un code non nul dès qu'une violation mécanique est détectée.
- RUST-AUDIT-003 — L'audit contrôle au minimum : headers/version/newline, lints de crate-root, visibilité interdite,
use/aliases/groupes/globs/scope, rustdocs visibles, structure des blocs de réexports, ordre des imports de traits et constantes lorsque KSP le possède, lignes vides dans fonctions/structs/enums, complétude des réexports crate-root, cheminscrate::module::Item, accèssuper::PrivateItemetcrate::VisibleItemdans les tests séparés, ainsi que les frontières KSP directement vérifiables. L'ordre intra-bloc desuse/réexports reste la responsabilité canonique decargo fmt --allet n'est pas réimplémenté par le script. - RUST-AUDIT-004 — Les règles contextuelles qui ne peuvent pas être prouvées sans interpréter la sémantique restent des critères de revue humaine ; le script ne doit pas produire de faux sentiment de complétude.
Contrôle avant livraison
Après toute modification Rust, la séquence minimale est :
cargo fmt --all
python3 scripts/audit_rust_workspace_rules.py
cargo check --workspace
cargo clippy --workspace --all-targets
Pendant le développement, des tests ciblés suivent ce gate. À la fermeture d'une prerelease technique/release, exécuter également :
cargo test --workspace
Une commande non exécutée n'est jamais déclarée réussie. rustfmt, cargo check et Clippy ne remplacent pas l'audit structurel KSP.