typestar

api_models.rs en Rust

Un juego completo de modelos para un payload de API: parsear, validar, resumir.

use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct Payload {
    lang: String,
    #[serde(default)]
    generated: bool,
    tours: Vec<Tour>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Tour {
    slug: String,
    title: String,
    sections: Vec<Section>,
}

#[derive(Debug, Serialize, Deserialize)]
struct Section {
    title: String,
    steps: Vec<Step>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "lowercase")]
enum Step {
    Snippet { file: String, lines: u32 },
    Script { file: String, lines: u32 },
}

impl Step {
    fn file(&self) -> &str {
        match self {
            Step::Snippet { file, .. } | Step::Script { file, .. } => file,
        }
    }

    fn lines(&self) -> u32 {
        match self {
            Step::Snippet { lines, .. } | Step::Script { lines, .. } => *lines,
        }
    }
}

fn summarize(payload: &Payload) -> BTreeMap<&str, u32> {
    let mut totals = BTreeMap::new();
    for tour in &payload.tours {
        let steps: u32 =
            tour.sections.iter().map(|s| s.steps.len() as u32).sum();
        totals.insert(tour.slug.as_str(), steps);
    }
    totals
}

fn main() -> Result<(), serde_json::Error> {
    let raw = r#"{
      "lang": "rust",
      "tours": [{
        "slug": "traits",
        "title": "Traits & generics",
        "sections": [{
          "title": "Trait objects",
          "steps": [
            {"kind": "snippet", "file": "rs_trait_objects.rs", "lines": 38},
            {"kind": "script", "file": "shapes.rs", "lines": 96}
          ]
        }]
      }]
    }"#;

    let payload: Payload = serde_json::from_str(raw)?;
    println!("{} generated={}", payload.lang, payload.generated);
    println!("{:?}", summarize(&payload));

    let longest = payload
        .tours
        .iter()
        .flat_map(|t| &t.sections)
        .flat_map(|s| &s.steps)
        .max_by_key(|step| step.lines());
    if let Some(step) = longest {
        println!("longest: {} at {} lines", step.file(), step.lines());
    }

    println!("{}", serde_json::to_string(&payload)?.len());
    Ok(())
}

Cómo funciona

  1. Los modelos espejan el JSON con renombres y valores por defecto.
  2. Un enum etiquetado cubre los dos tipos de paso.
  3. El resumen recorre el árbol parseado, no el texto crudo.

Palabras clave y builtins usados aquí

El intento, en números

Líneas
89
Caracteres a escribir
1855
Tokens
465
Ritmo de tres estrellas
115 tpm

Al ritmo de tres estrellas de 115 tokens por minuto, este intento toma unos 243 segundos.

Escribe este fragmento

Paso 1 de 1 en Bis; paso 11 de 11 en Serde y JSON.

← Anterior