typestar

inventory.rs en Rust

Un pequeño árbol de módulos con un builder, invariantes privados y sus propias pruebas.

mod store {
    use std::collections::HashMap;

    #[derive(Debug, Clone, PartialEq)]
    pub struct Item {
        sku: String,
        quantity: u32,
    }

    impl Item {
        pub fn new(sku: &str, quantity: u32) -> Result<Item, String> {
            if sku.is_empty() {
                return Err("sku is required".to_string());
            }
            Ok(Item { sku: sku.to_string(), quantity })
        }

        pub fn sku(&self) -> &str {
            &self.sku
        }

        pub fn quantity(&self) -> u32 {
            self.quantity
        }
    }

    #[derive(Default)]
    pub struct Inventory {
        items: HashMap<String, Item>,
    }

    impl Inventory {
        pub fn add(&mut self, item: Item) {
            self.items
                .entry(item.sku().to_string())
                .and_modify(|held| held.quantity += item.quantity())
                .or_insert(item);
        }

        pub fn total(&self) -> u32 {
            self.items.values().map(|i| i.quantity()).sum()
        }

        pub fn low_stock(&self, floor: u32) -> Vec<&str> {
            let mut low: Vec<&str> = self
                .items
                .values()
                .filter(|i| i.quantity() < floor)
                .map(|i| i.sku())
                .collect();
            low.sort();
            low
        }
    }
}

use store::{Inventory, Item};

fn main() {
    let mut inventory = Inventory::default();
    for (sku, qty) in [("TS-001", 5), ("TS-002", 1), ("TS-001", 3)] {
        match Item::new(sku, qty) {
            Ok(item) => inventory.add(item),
            Err(e) => println!("skipped: {e}"),
        }
    }

    println!("total units: {}", inventory.total());
    println!("low stock: {:?}", inventory.low_stock(4));
    println!("{:?}", Item::new("", 1));
}

#[cfg(test)]
mod tests {
    use super::store::{Inventory, Item};

    #[test]
    fn merges_quantities_for_one_sku() {
        let mut inv = Inventory::default();
        inv.add(Item::new("A", 2).unwrap());
        inv.add(Item::new("A", 3).unwrap());
        assert_eq!(inv.total(), 5);
    }

    #[test]
    fn rejects_an_empty_sku() {
        assert!(Item::new("", 1).is_err());
    }
}

Cómo funciona

  1. El módulo store posee los datos y mantiene privados sus campos.
  2. Un builder arma los ítems, validando sobre la marcha.
  3. El módulo de pruebas ejercita el camino feliz y el que falla.

Palabras clave y builtins usados aquí

El intento, en números

Líneas
89
Caracteres a escribir
1633
Tokens
556
Ritmo de tres estrellas
115 tpm

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

Escribe este fragmento

Paso 1 de 1 en Bis; paso 12 de 12 en Módulos, pruebas y macros.

← Anterior