Files
khadhroony-bot3/docs/rules/RULES_RUST.md

147 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- file: docs/rules/RULES_RUST.md -->
<!-- version: 8 -->
# Règles Rust générales
Ce fichier contient les règles normatives applicables à tous les projets Rust. Elles sont indépendantes de `khadhroony-bot3` et doivent pouvoir être réutilisées telles quelles dans un autre workspace.
## En-têtes et versions de fichiers
- Tout fichier texte qui supporte des commentaires commence par une ligne indiquant son chemin relatif dans le projet, puis une ligne `version` entière.
- Un script exécutable nécessitant un shebang conserve celui-ci en première ligne ; les lignes `file:` et `version:` suivent immédiatement le shebang.
- La version d'un fichier est incrémentée à chaque modification après validation de sa version précédente.
- Les fichiers Rust utilisent `// file: ...` et `// version: N`.
- Les fichiers Markdown utilisent `<!-- file: ... -->` et `<!-- version: N -->`.
- Tous les fichiers texte se terminent par exactement une fin de ligne.
## Langue et documentation
- Les commentaires et rustdocs du code sont rédigés en anglais.
- Les documents Markdown du projet sont rédigés dans la langue documentaire choisie par le projet.
- Tout élément `pub` ou `pub(crate)` possède une rustdoc utile au point de déclaration.
- Toute réexportation `pub use` ou `pub(crate) use` dans `lib.rs` ou `main.rs` possède également sa propre rustdoc copiée ou reformulée de manière équivalente. La documentation du point d'entrée doit permettre de comprendre l'API sans ouvrir le module interne.
## Édition et lints obligatoires
- L'édition Rust cible est Rust 2024, sauf contrainte explicitement documentée.
- Chaque `lib.rs` et `main.rs` contient :
- `#![warn(missing_docs)]` ;
- `#![deny(unreachable_pub)]` ;
- `#![forbid(unsafe_code)]`.
- Les lints Clippy obligatoires sont déclarés au niveau workspace et hérités par toutes les crates.
- Les règles minimales sont : interdiction de `unwrap`, `expect`, `?`, retours implicites, code `unsafe`, APIs publiques inaccessibles et imports globaux non justifiés.
- Les tests peuvent disposer d'exceptions limitées pour `unwrap` et `expect` uniquement lorsqu'elles sont explicitement autorisées par la configuration Clippy.
La configuration workspace doit au minimum déclarer :
```toml
[workspace.lints.rust]
missing_docs = "warn"
unreachable_pub = "deny"
unsafe_code = "forbid"
[workspace.lints.clippy]
unwrap_used = "deny"
expect_used = "deny"
implicit_return = "deny"
needless_return = "allow"
useless_vec = "deny"
question_mark = "deny"
question_mark_used = "deny"
needless_match = "allow"
manual_ok_err = "allow"
manual_unwrap_or = "allow"
manual_map = "allow"
match_like_matches_macro = "allow"
single_match = "allow"
manual_unwrap_or_default = "allow"
manual_find = "allow"
explicit_counter_loop = "allow"
get_first = "allow"
implicit_saturating_sub = "allow"
```
## Formatage
- `cargo fmt --all` est exécuté après application de chaque delta ou correctif et avant les tests.
- Les fichiers Rust ne contiennent pas de lignes vides à l'intérieur d'une fonction, d'une structure, d'une énumération ou d'une implémentation courte.
- Les lignes vides séparent uniquement les fonctions, blocs `impl`, types et sections logiques.
- Les exports de `lib.rs` ou `main.rs` ne contiennent aucune ligne vide à l'intérieur d'une série homogène de `pub use` ou `pub(crate) use`.
- Les séries `pub use` et `pub(crate) use` forment deux groupes séparés lorsqu'elles coexistent.
- Le groupe `pub use` précède le groupe `pub(crate) use` dans une même façade.
- Lordre interne suit lordre naturel produit par `rustfmt` : les segments et mots séparés sont comparés avant leurs suffixes numériques, par exemple `U8` avant `U16` et `TOKEN` avant `TOKEN2022`.
## Assertions sur les collections
- Un test qui vérifie uniquement lappartenance à un ensemble peut trier la valeur obtenue et la valeur attendue avant `assert_eq!`, afin de ne pas dépendre dun ordre denregistrement non contractuel.
- Le tri doit être explicite dans le test et appliqué aux deux collections comparées.
- Ne jamais trier une collection lorsque lordre fait partie du contrat : comptes Solana, metas, instructions, signers, événements, étapes de pipeline, priorités, journaux ou toute autre séquence ordonnée.
## Imports et chemins
- `use` est interdit pour les constantes, fonctions, structures, énumérations, unions, alias de types, modules et macros.
- `use` est autorisé uniquement pour un trait lorsque la résolution de méthode, une macro de dérivation ou une contrainte de langage l'exige réellement.
- Un import de trait doit rester étroit et ne doit jamais importer simultanément des éléments non-traits par accolades.
- Les imports globaux, glob imports et imports groupés par accolades sont interdits.
- Pour un élément fourni par une crate externe au workspace, utiliser directement le chemin public le plus court exposé par cette crate. Exemple : utiliser `external_crate::Struct`, jamais `external_crate::module::Struct` si `external_crate::Struct` existe, et jamais `use external_crate::Struct`.
- Pour un élément `pub` déclaré dans le workspace :
- il est réexporté depuis le `lib.rs` ou `main.rs` de sa crate propriétaire ;
- depuis une autre crate, il est appelé via `owner_crate::Item` ;
- depuis sa propre crate, il est appelé via `crate::Item`, même depuis son module de déclaration.
- Pour un élément `pub(crate)` :
- il est réexporté depuis le `lib.rs` ou `main.rs` via `pub(crate) use` ;
- il est appelé via `crate::Item`, même depuis son module de déclaration.
- Un élément strictement privé à un module n'est pas réexporté et est appelé par son nom local uniquement. Il est interdit d'utiliser un chemin long comme `crate::module::helper` ou `owner_crate::module::helper` pour un helper privé du module courant.
- Dans un sous-module de tests, un élément privé du module parent est appelé via `super::Item`. Un élément `pub` ou `pub(crate)` continue dêtre appelé via le point dentrée de crate le plus court, par exemple `crate::Item`.
- Les exports ne sont jamais groupés avec des accolades. Un type, une fonction, une constante ou un alias correspond à une ligne de réexport distincte.
- Un réexport dun module interne commence par `self::`, y compris dans `lib.rs` ; `use crate::...` est réservé aux références qualifiées dans le code et ne sert pas à construire une façade.
- Les alias `as` sont interdits dans les réexports : le symbole reçoit son nom canonique dans son module propriétaire avant dêtre réexporté sans transformation.
- Un bloc homogène de `pub use` ou `pub(crate) use` ne contient aucune ligne vide et reste ordonné alphabétiquement par symbole réexporté lorsque `rustfmt` ne le réordonne pas.
## Visibilité et API de crate
- Aucun `pub mod` n'est autorisé. Les modules restent privés et l'API est constituée exclusivement par des réexports explicites depuis le point dentrée de la crate.
- Un élément `pub` inaccessible depuis le point d'entrée de sa crate est une erreur de conception, pas un simple avertissement.
- Un élément `pub(crate)` utilisé hors de son module est réexporté au niveau du point d'entrée de la crate.
- Les chemins internes de modules ne font pas partie de l'API stable.
- Les méthodes inhérentes publiques restent appelées via le type réexporté ; les fonctions libres publiques sont appelées via le point d'entrée de crate.
## Helpers et réutilisation
- Un helper répété dans plusieurs modules d'une même crate est déplacé dans un module commun explicite, généralement `helper.rs` ou un module spécialisé plus précis.
- Le nom `helpers.rs` ou `helper.rs` n'est utilisé que si aucune responsabilité métier plus précise ne convient.
- Un helper général réutilisable par plusieurs crates est déplacé dans une crate commune appropriée et exposé publiquement.
- Les types d'erreur généraux, identifiants de programme, primitives de validation et fonctions de sérialisation communes ne doivent pas être dupliqués entre crates.
- La mutualisation ne doit pas créer de dépendance cyclique ni déplacer un comportement métier spécifique dans une crate générique.
## Gestion des erreurs et contrôle de flux
- `unwrap`, `expect` et `panic` sont interdits dans le code de production.
- L'opérateur `?` est interdit dans les chemins de production ; utiliser des `match` explicites avec erreurs contextualisées.
- `anyhow` et `thiserror` ne sont pas utilisés par défaut.
- Les erreurs publiques sont typées lorsque leur contrat est stable ; les diagnostics dynamiques restent bornés.
- Les retours sont explicites conformément au lint `clippy::implicit_return`.
## Sécurité et dépendances
- Le code `unsafe` est interdit.
- Une dépendance n'est ajoutée que si elle est réellement utilisée dans le chemin de compilation concerné.
- Une dépendance utilisée uniquement dans les tests reste dans `[dev-dependencies]`.
- Les features sont minimales et explicites.
## Contrôle avant livraison
Chaque livraison Rust exécute au minimum, dans cet ordre :
```bash
cargo fmt --all
python3 scripts/audit_rust_general_rules.py
python3 scripts/audit_khadhroony_workspace_rules.py
cargo test --workspace
cargo clippy --workspace --all-targets
```
Un projet peut utiliser une sélection de tests plus étroite pendant le développement, mais la fermeture d'une version exige le contrôle global.
Le wrapper `python3 scripts/audit_rust_workspace_rules.py` exécute les deux audits sans fusionner leurs responsabilités.