config_check.rs en Rust
Un pipeline de validación: parsear texto clave-valor, juntar cada problema, reportar.
use std::collections::HashMap;
use std::error::Error;
use std::fmt;
#[derive(Debug)]
enum Invalid {
Missing(&'static str),
NotANumber { key: &'static str, got: String },
OutOfRange { key: &'static str, got: i64 },
}
impl fmt::Display for Invalid {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Invalid::Missing(key) => write!(f, "{key} is required"),
Invalid::NotANumber { key, got } => {
write!(f, "{key} should be a number, got {got:?}")
}
Invalid::OutOfRange { key, got } => {
write!(f, "{key} is out of range: {got}")
}
}
}
}
fn parse(raw: &str) -> HashMap<&str, &str> {
raw.lines()
.filter_map(|line| line.trim().split_once('='))
.map(|(k, v)| (k.trim(), v.trim()))
.collect()
}
fn number(
fields: &HashMap<&str, &str>,
key: &'static str,
range: std::ops::RangeInclusive<i64>,
) -> Result<i64, Invalid> {
let raw = fields.get(key).ok_or(Invalid::Missing(key))?;
let value: i64 = raw.parse().map_err(|_| Invalid::NotANumber {
key,
got: raw.to_string(),
})?;
if !range.contains(&value) {
return Err(Invalid::OutOfRange { key, got: value });
}
Ok(value)
}
fn check(raw: &str) -> Vec<Invalid> {
let fields = parse(raw);
let mut problems = Vec::new();
if !fields.contains_key("host") {
problems.push(Invalid::Missing("host"));
}
for (key, range) in [("port", 1..=65535), ("workers", 1..=64)] {
if let Err(e) = number(&fields, key, range) {
problems.push(e);
}
}
problems
}
fn main() -> Result<(), Box<dyn Error>> {
let raw = "host = typestar.io\nport = 99999\nworkers = many";
let problems = check(raw);
if problems.is_empty() {
println!("config looks good");
return Ok(());
}
println!("{} problem(s):", problems.len());
for p in &problems {
println!(" - {p}");
}
Ok(())
}
Cómo funciona
- Un solo enum de error cubre las tres formas en que un campo puede fallar.
- La validación reúne todas las fallas en vez de parar en la primera.
maindevuelveResult, así que un error fatal de parseo sale con código distinto de cero.
Palabras clave y builtins usados aquí
BoxErrOkResultStringVecdynenumfnfori64ifimplinletmatchmutreturnselfstaticstruse
El intento, en números
- Líneas
- 78
- Caracteres a escribir
- 1704
- Tokens
- 554
- Ritmo de tres estrellas
- 110 tpm
Al ritmo de tres estrellas de 110 tokens por minuto, este intento toma unos 302 segundos.
Paso 1 de 1 en Bis; paso 15 de 15 en Manejo de errores.