14 KiB
Profil Rust / Cargo
Scope
Ce profil s'applique aux projets qui utilisent Rust avec Cargo.
Il spécialise 500-LANGUAGES.md pour les responsabilités propres à Rust et Cargo. Il ne possède pas les contraintes particulières d'une plateforme, d'un framework, d'une FFI, d'un protocole ou d'un domaine métier.
Une règle plus spécifique, par exemple Android, WASM, Tauri ou une frontière FFI, MAY raffiner ce profil dans son scope sans modifier la politique Rust générale.
Toolchain et édition
Un nouveau projet Rust SHOULD utiliser une toolchain stable récente compatible avec ses dépendances et ses cibles. Une toolchain nightly, beta ou autre prerelease nécessite une justification explicite.
PGR MUST NOT imposer un pin exact de toolchain uniquement parce qu'un projet source historique utilisait cette version. Un fichier rust-toolchain.toml ou équivalent SHOULD être ajouté uniquement lorsqu'un besoin réel de reproductibilité, de composant ou de compatibilité l'exige.
Lorsqu'un workspace partage une politique d'édition unique, l'édition Rust SHOULD être déclarée une seule fois sous [workspace.package] et héritée par les membres. Une évolution d'édition est une décision de compatibilité/toolchain et non une modification opportuniste.
Workspace et unités de release
Un projet Rust composé de plusieurs packages SHOULD utiliser un workspace Cargo lorsque les packages partagent réellement gouvernance, validation ou dépendances.
Pour un workspace à train de release unique :
- le fichier PGR
VERSIONreste la version canonique de l'unité de release ; [workspace.package].versionMUST refléter cette version lorsque Cargo exige une version de package ;- les crates membres SHOULD hériter de la version workspace plutôt que recopier la même valeur ;
- les métadonnées réellement communes comme
edition,license,repositoryouauthorsSHOULD être centralisées puis héritées lorsqu'elles ont le même propriétaire.
Un monorepo contenant plusieurs unités de release indépendantes MUST NOT fabriquer une fausse version Cargo globale uniquement pour appliquer ce modèle. Chaque unité conserve alors son propriétaire de version conformément aux règles générales PGR.
Le répertoire crates/ est le placement PGR recommandé pour les packages Rust d'un workspace structuré, sauf layout imposé par un framework, une plateforme ou un projet existant.
Manifests et dépendances Cargo
Dans un workspace, une dépendance tierce réellement partagée par plusieurs crates SHOULD posséder sa contrainte de version canonique sous [workspace.dependencies].
Une crate membre SHOULD consommer cette dépendance avec workspace = true et activer localement uniquement les features nécessaires à son propre code. Une feature de plateforme ou de test MUST NOT être activée globalement par commodité lorsqu'un scope plus étroit suffit.
Une dépendance utilisée uniquement par les tests, benchmarks ou exemples SHOULD rester dans la section de dépendances de développement appropriée.
Les contraintes de version SHOULD exprimer l'intention de compatibilité réellement souhaitée. Un pin exact ou une version volontairement ancienne MUST avoir une raison identifiable : compatibilité, reproductibilité, sécurité, bug connu ou matrice imposée par un scope plus spécifique.
cargo update MUST NOT être exécuté opportunistement dans une tranche sans rapport avec les dépendances. Une mise à jour de résolution ou de dépendance appartient au scope courant uniquement lorsqu'elle est nécessaire et explicitement vérifiée.
Politique de Cargo.lock
PGR ne généralise pas automatiquement la politique de lockfile d'un projet source à tous les projets Rust.
La décision de versionner ou non Cargo.lock MUST être explicite et cohérente avec le type de produit, le mode de publication et le besoin de reproductibilité du projet. Un profil plus spécifique MAY imposer une politique particulière.
Dans tous les cas, un lockfile ne remplace jamais les contraintes de version et décisions de compatibilité appartenant aux manifests et à la documentation normative.
Lints communs
Un workspace structuré SHOULD déclarer les lints communs au niveau racine et les crates membres SHOULD les hériter plutôt que maintenir plusieurs copies divergentes.
Le profil strict PGR recommandé pour un nouveau workspace Rust comprend au minimum :
[workspace.lints.rust]
missing_docs = "warn"
unreachable_pub = "deny"
unsafe_code = "forbid"
[workspace.lints.clippy]
unwrap_used = "deny"
expect_used = "deny"
implicit_return = "deny"
question_mark = "deny"
question_mark_used = "deny"
Des allow nécessaires pour éviter qu'un lint de suggestion contredise intentionnellement le style retenu MAY être déclarés au workspace, mais la liste doit rester minimale et justifiée par une règle réelle.
Safety et FFI
Le code unsafe est interdit par défaut dans un projet suivant le profil strict PGR.
Lorsqu'une FFI ou une plateforme impose réellement une opération unsafe, l'exception MUST appartenir au scope le plus étroit possible : crate, module, symbole ou attribut concerné. Elle MUST être documentée et ne doit pas affaiblir silencieusement le reste du workspace.
Une exception FFI locale n'autorise donc pas à remplacer globalement unsafe_code = "forbid" par une politique permissive pour toutes les crates.
API, visibilité et rustdoc
Tout élément pub ou pub(crate) SHOULD posséder une rustdoc utile au point de déclaration lorsque son contrat dépasse une implémentation triviale locale.
Une crate réutilisable SHOULD exposer son API durable depuis son crate-root par des réexports explicites. Les modules d'implémentation SHOULD rester privés ; pub mod ne doit pas être utilisé uniquement pour éviter de concevoir une façade stable.
Un élément partagé à l'échelle de sa propre crate SHOULD être consommable via crate::Item après réexport approprié. Les autres crates consomment l'API publique du crate propriétaire plutôt que ses chemins internes.
Les glob imports SHOULD être évités. Un alias de réexport ne doit pas servir à masquer durablement une collision de noms dans l'API ; lorsqu'un nom fait partie du contrat public, le propriétaire SHOULD choisir un nom canonique non ambigu.
PGR ne généralise pas l'interdiction KSP plus stricte de tous les use non-traits : cette convention appartient à un profil ou projet plus spécifique tant qu'elle n'est pas nécessaire au contrat Rust général.
Contrôle de flux et erreurs
Dans le code de production du profil strict PGR :
unwrap()etexpect()MUST NOT servir à traiter un chemin d'erreur récupérable ;panic!MUST NOT représenter une erreur métier récupérable ;- les retours explicites sont la convention par défaut ;
- l'opérateur
?est désactivé par le profil Clippy strict afin de conserver des chemins d'erreur explicites.
Une règle plus spécifique MAY définir une politique d'erreur différente lorsqu'elle possède une justification architecturale explicite. PGR ne généralise pas l'interdiction d'une bibliothèque d'erreur particulière à partir d'un seul projet source.
Formatage
rustfmt.toml à la racine SHOULD être le propriétaire canonique du formatage Rust d'un workspace.
Le profil PGR issu des corpus actuellement éprouvés utilise notamment :
edition = "2024"
newline_style = "Unix"
hard_tabs = false
tab_spaces = 4
max_width = 160
reorder_imports = true
reorder_modules = true
use_try_shorthand = false
force_explicit_abi = true
L'édition de ce fichier MUST rester cohérente avec l'édition réellement utilisée par le workspace ; l'exemple 2024 décrit la baseline actuelle et ne constitue pas un pin éternel pour les futures éditions Rust.
Après une modification Rust, cargo fmt --all applique le formatage canonique puis cargo fmt --all -- --check vérifie l'état livré. Une modification produite uniquement par le formatter officiel ne crée pas artificiellement une nouvelle révision documentaire d'un fichier si aucun contenu réel n'a changé.
Le profil de style strict supplémentaire peut être adopté par un projet qui souhaite appliquer les conventions KSP/Games. Dans ce scope choisi, les lignes vides consécutives SHOULD être supprimées, ainsi que les lignes vides à l'intérieur des fonctions/méthodes et des définitions struct/enum. Ces propriétés ne sont pas entièrement possédées par Rustfmt. L'audit facultatif scripts/audit_rust_blank_lines.py contrôle ces deux formes d'espacement sur les seuls fichiers Rust sélectionnés.
Les constantes de module qui constituent un bloc homogène sans ordre sémantique SHOULD être regroupées dans l'ordre pub, pub(crate), privé, puis par nom dans chaque visibilité : aucune ligne vide entre constantes d'une même visibilité et exactement une entre niveaux différents. scripts/audit_rust_const_blocks.py vérifie cette convention uniquement sur les constantes au niveau racine des fichiers choisis. Son exécution requiert une sélection explicite des fichiers pour lesquels cet ordre est réellement souhaité. Une table de protocole, une séquence de migrations ou tout autre ordre contractuel conserve son ordre propre ; le lecteur ne doit pas réordonner une telle séquence pour faire passer l'audit.
L'ordre des use, réexports et déclarations mod que Rustfmt sait réordonner dans ses groupes appartient au formatteur ; les modules de test après les modules de production et l'organisation d'une façade relèvent de leur contrat local, avec revue ou audit dédié seulement si celui-ci apporte une preuve fiable. Les règles rustdoc et d'API conservent leurs propriétaires ci-dessus. Les scripts PGR ne prétendent pas parser toutes les macros ou les items Rust : une décision sémantique reste une revue.
Configuration Cargo et artefacts générés
.cargo/config.toml est le propriétaire naturel d'une configuration Cargo partagée par le projet lorsqu'une telle configuration est nécessaire.
Si un projet choisit de placer les artefacts Cargo hors de l'arborescence source, target-dir et les autres paramètres correspondants SHOULD être définis dans cette configuration plutôt que répétés dans chaque commande. Le chemin exact reste une décision de projet ou de skeleton et n'est pas figé par ce profil.
Les sorties target/, caches et artefacts de compilation MUST rester hors des livraisons source sauf contrat de packaging explicite.
Tests Rust
Les tests MUST NOT élargir artificiellement la visibilité de l'API de production.
Les tests d'intégration Cargo résident sous tests/ de la crate concernée et consomment son API publique.
Les tests unitaires restent sous la responsabilité de la crate ou du module testé. Un workspace MAY adopter une arborescence unit_tests/ séparée et miroir de src/ lorsqu'elle améliore la lisibilité ; cette convention doit alors être appliquée de manière cohérente sans transformer tests/ en tests internes.
Une dépendance ou feature exclusivement nécessaire aux tests SHOULD rester dans le scope de développement/test approprié.
Validation Rust / Cargo
Les catégories, l'autorité du gate et la proportionnalité restent possédées par 400-VALIDATION.md. Ce profil ajoute seulement les commandes propres à Rust/Cargo.
Lorsqu'un delta modifie du code Rust, un manifeste Cargo, une feature ou une dépendance Rust, la séquence normale SHOULD inclure :
cargo fmt --all
cargo fmt --all -- --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
Les audits structurels read-only réellement applicables s'insèrent après le formatage et avant ou autour des contrôles Cargo selon leur responsabilité.
Les tests ciblés constituent la stratégie normale d'une tranche :
cargo test -p <crate> --all-targets --all-features
cargo test --workspace --all-targets --all-features est une gate plus large réservée aux changements transverses ou aux phases où une validation globale apporte une preuve supplémentaire réelle.
cargo build SHOULD être exécuté lorsqu'un artefact est nécessaire ; il ne doit pas être ajouté systématiquement à cargo check sans besoin de build ou packaging.
cargo tree et ses variantes SHOULD être utilisés lors d'une modification de dépendances/features ou d'un diagnostic de graphe, pas comme cérémonie de chaque delta.
cargo clean est une opération de maintenance et MUST NOT être exécuté automatiquement à chaque tranche.
La validation Cargo finale appartient à l'environnement autoritaire du projet. Une prévalidation par générateur ou CI supplémentaire ne remplace pas le gate opérateur défini par le projet.
Audits PGR pour Rust
Les audits Rust historiques de projets sources peuvent combiner de nombreuses responsabilités. PGR ne doit pas recopier cette complexité comme point de départ.
Lorsqu'une règle Rust devient objectivement automatisable dans un projet ou skeleton concret, PGR SHOULD préférer plusieurs audits monotâches et lisibles, par exemple un contrôle de manifests/workspace distinct d'un contrôle de headers ou de façade publique.
Un éventuel wrapper d'orchestration MAY appeler plusieurs audits, mais chaque audit propriétaire doit conserver une responsabilité identifiable et rester read-only.
Les deux audits de style disponibles sont documentés dans ../validation/002-RUST_STYLE_AUDITS.md. Ils restent optionnels et prennent un corpus Rust explicitement sélectionné ; le dépôt PGR lui-même ne contient pas de workspace Rust sur lequel une telle gate fournirait une preuve réelle.