RTK Code Simplifier
Examen et simplification du code Rust dans RTK tout en respectant les contraintes du projet.
Contraintes (ne jamais simplifier)
lazy_static!regex — ne peut pas être déplacée dans les fonctions même si c'est "plus simple".context()sur chaque?— verbeux mais obligatoire- Fallback vers commande brute — ne jamais supprimer même si cela semble du code mort
- Propagation du code de sortie — ne jamais simplifier vers
Ok(()) #[cfg(test)] mod tests— ne jamais supprimer les modules de test
Motifs de simplification
1. Chaînes d'itérateurs plutôt que boucles manuelles
// ❌ Verbeux
let mut result = Vec::new();
for line in input.lines() {
let trimmed = line.trim();
if !trimmed.is_empty() && trimmed.starts_with("error") {
result.push(trimmed.to_string());
}
}
// ✅ Idiomatique
let result: Vec<String> = input.lines()
.map(|l| l.trim())
.filter(|l| !l.is_empty() && l.starts_with("error"))
.map(str::to_string)
.collect();
2. Construction de chaînes
// ❌ Boucle de push verbeux
let mut out = String::new();
for (i, line) in lines.iter().enumerate() {
out.push_str(line);
if i < lines.len() - 1 {
out.push('\n');
}
}
// ✅ join
let out = lines.join("\n");
3. Chaînage Option/Result
// ❌ Match imbriqué
let result = match maybe_value {
Some(v) => match transform(v) {
Ok(r) => r,
Err(_) => default,
},
None => default,
};
// ✅ Chaîné
let result = maybe_value
.and_then(|v| transform(v).ok())
.unwrap_or(default);
4. Destructuration de struct
// ❌ Accès répété aux champs
fn process(args: &MyArgs) -> String {
format!("{} {}", args.command, args.subcommand)
}
// ✅ Destructurer
fn process(&MyArgs { ref command, ref subcommand, .. }: &MyArgs) -> String {
format!("{} {}", command, subcommand)
}
5. Retours anticipés plutôt qu'imbrication
// ❌ Profondément imbriqué
fn filter(input: &str) -> Option<String> {
if !input.is_empty() {
if let Some(line) = input.lines().next() {
if line.starts_with("error") {
return Some(line.to_string());
}
}
}
None
}
// ✅ Retour anticipé
fn filter(input: &str) -> Option<String> {
if input.is_empty() { return None; }
let line = input.lines().next()?;
if !line.starts_with("error") { return None; }
Some(line.to_string())
}
6. Éviter les clones redondants
// ❌ Clone inutile
fn filter_output(input: &str) -> String {
let s = input.to_string(); // Clone inutile
s.lines().filter(|l| !l.is_empty()).collect::<Vec<_>>().join("\n")
}
// ✅ Travailler avec &str
fn filter_output(input: &str) -> String {
input.lines().filter(|l| !l.is_empty()).collect::<Vec<_>>().join("\n")
}
7. Utiliser if let pour une correspondance mono-variante
// ❌ Match complet pour une variante
match output {
Ok(s) => process(&s),
Err(_) => {},
}
// ✅ if let (mais toujours gérer les erreurs dans RTK — ne pas les ignorer silencieusement)
if let Ok(s) = output {
process(&s);
}
// Note : dans les filtres RTK, toujours gérer Err avec eprintln! + fallback
Vérifications RTK-Spécifiques
Exécutez-les après la simplification :
# Vérifier l'absence de régressions
cargo fmt --all && cargo clippy --all-targets && cargo test
# Vérifier qu'aucune regex n'a été ajoutée dans les fonctions
grep -n "Regex::new" src/<file>.rs
# Tous doivent être à l'intérieur des blocs lazy_static!
# Vérifier qu'aucun unwrap n'a été ajouté en production
grep -n "\.unwrap()" src/<file>.rs
# Ne devrait apparaître que dans les blocs #[cfg(test)]
Ce qu'il ne faut PAS simplifier
lazy_static! { static ref RE: Regex = Regex::new(...).unwrap(); }— le.unwrap()ici est acceptable, c'est l'initialisation- Chaînes
.context("description")?— verbeux mais requis - Le bras de correspondance fallback
Err(e) => { eprintln!(...); raw_output }— semble redondant mais c'est le filet de sécurité std::process::exit(code)à la fin de run() — semble pouvoir êtreOk(())mais ce n'est pas le cas