# Regla: Estilo de Código — Rust

Aplica a todo código Rust del proyecto. El compilador de Rust ya impone muchas
restricciones; estas reglas cubren las decisiones de estilo y legibilidad que
el compilador no puede forzar. El objetivo es código que sea seguro, claro y
que cualquier miembro del equipo pueda mantener con confianza.

---

## Formateo con rustfmt (obligatorio)

- `rustfmt` es el formateador oficial y su uso es obligatorio. No se aceptan
  PRs con código sin formatear.
- El archivo `rustfmt.toml` en la raíz del proyecto define la configuración.
  Si no existe, usar los valores por defecto de rustfmt.
- Ejecutar antes de cada commit: `cargo fmt --check` para verificar sin modificar.
- NUNCA editar manualmente el indentado o el espaciado — dejar que rustfmt decida.
- CI debe fallar si `cargo fmt --check` produce diferencias.

---

## Clippy como linter (obligatorio)

- Clippy detecta errores idiomáticos que rustfmt no cubre.
- Ejecutar con: `cargo clippy -- -D warnings`
  El flag `-D warnings` convierte todo warning en error — CI falla si hay alguno.
- Cuando un lint de Clippy es incorrecto para el caso específico, suprimir
  con `#[allow(clippy::nombre_del_lint)]` en el sitio exacto, con comentario
  explicando por qué:
  ```rust
  #[allow(clippy::too_many_arguments)] // Esta función es el punto de entrada del CLI y requiere todos estos parámetros
  pub fn ejecutar(...) { ... }
  ```
- NUNCA `#![allow(clippy::all)]` a nivel de crate — suprime lints válidos.

---

## Convenciones de nombres

| Elemento | Convención | Ejemplo |
|----------|-----------|---------|
| Funciones y métodos | `snake_case` | `calcular_total()` |
| Variables y parámetros | `snake_case` | `precio_unitario` |
| Constantes y statics | `SCREAMING_SNAKE_CASE` | `MAX_REINTENTOS` |
| Tipos, traits, enums | `PascalCase` | `FacturaError`, `Pagable` |
| Variantes de enum | `PascalCase` | `EstadoPedido::Enviado` |
| Módulos y archivos | `snake_case` | `factura_service.rs` |
| Lifetimes | `'a`, `'b` o nombres cortos descriptivos | `'entrada`, `'cache` |

- NUNCA abreviar nombres de tipos. `UsrMngr` — mal. `UserManager` — bien.
- Prefijo `is_` / `has_` para métodos que retornan `bool`:
  `is_active()`, `has_items()`, `can_retry()`.

---

## Ownership y borrowing: reglas de cuándo usar qué

| Situación | Usar | Razón |
|-----------|------|-------|
| Leer datos sin modificar | `&T` | Préstamo inmutable, sin costo de copia |
| Modificar datos en el lugar | `&mut T` | Préstamo mutable |
| Tomar posesión para almacenar | `T` (move) | El caller ya no necesita el valor |
| Compartir entre hilos | `Arc<T>` | Reference counting atómico |
| Mutación compartida entre hilos | `Arc<Mutex<T>>` | Exclusión mutua |

**Parámetros de función**:
- Preferir `&str` sobre `&String` — acepta tanto `&str` como `&String`.
- Preferir `&[T]` sobre `&Vec<T>` — acepta cualquier slice.
- Preferir `&Path` sobre `&PathBuf`.
- Usar `impl Trait` para aceptar cualquier implementador del trait:

```rust
// MAL — restringe a String específicamente
fn saludar(nombre: &String) -> String { ... }

// BIEN — acepta &str, &String, Cow<str>, etc.
fn saludar(nombre: &str) -> String { ... }
```

**Retornos**:
- Retornar `String` (owned) cuando el caller necesita poseer el valor.
- Retornar `&str` solo cuando el lifetime está atado al receiver (`&self`).

---

## Organización de módulos

- Organizar módulos por **dominio**, no por tipo de artefacto.

```
// MAL — organizado por tipo
src/
  models/
  services/
  handlers/

// BIEN — organizado por dominio
src/
  facturacion/
    mod.rs
    factura.rs
    calculo.rs
  usuario/
    mod.rs
    autenticacion.rs
```

- Cada módulo tiene su `mod.rs` que re-exporta solo lo público necesario.
- Módulos de utilidades genéricas van en `src/comun/` o `src/infra/`.

---

## Visibilidad por defecto: privada

- Todo es privado por defecto en Rust. `pub` solo cuando el símbolo es
  parte de la interfaz pública intencional del módulo.
- Escala de visibilidad (usar la más restrictiva posible):
  1. Privado (sin modificador) — solo dentro del módulo
  2. `pub(super)` — visible en el módulo padre
  3. `pub(crate)` — visible en todo el crate
  4. `pub` — visible fuera del crate (API pública)
- Los campos de struct son privados por defecto. Exponer solo con métodos
  o con `pub` cuando sea realmente necesario.

---

## No unwrap() en código de producción

- `unwrap()` y `expect()` panicanean en runtime. Prohibidos en `src/` fuera de tests.
- Usar el operador `?` para propagar errores.
- Usar combinators de `Option` para manejar la ausencia de valor:

```rust
// MAL — panics si el valor es None
let config = env::var("DATABASE_URL").unwrap();

// BIEN — propaga el error con contexto
let config = env::var("DATABASE_URL")
    .map_err(|_| ConfigError::MissingEnvVar("DATABASE_URL"))?;
```

- `expect()` solo está permitido en código de inicio de la aplicación
  (main, configuración inicial) donde un panic es aceptable, y con mensaje descriptivo:
  `config.load().expect("No se pudo cargar configuración inicial")`.
- En tests: `unwrap()` y `expect()` son aceptables.

---

## Iteradores sobre loops indexados

```rust
// MAL — loop indexado, verboso y propenso a off-by-one
for i in 0..facturas.len() {
    procesar(&facturas[i]);
}

// BIEN — iterador idiomático
for factura in &facturas {
    procesar(factura);
}

// BIEN — con transformación
let totales: Vec<f64> = facturas.iter().map(|f| f.total()).collect();
```

- Prefer `iter()` sobre índices directos en la mayoría de los casos.
- `iter_mut()` para modificación in-place. `into_iter()` para consumir.
- Cadenas de iteradores (`map`, `filter`, `flat_map`, `fold`) sobre loops
  cuando la operación es una transformación de datos.

---

## Lifetimes explícitos: solo cuando el compilador no infiere

- No agregar lifetimes donde el compilador puede inferirlos (elision rules).
- Lifetimes explícitos en structs que contienen referencias:

```rust
// NECESARIO — el struct contiene una referencia
struct Analizador<'a> {
    datos: &'a [u8],
}

// INNECESARIO — el compilador infiere correctamente
fn primera_linea(texto: &str) -> &str { ... }
```

---

## Longitud máxima de función: 50 líneas

- Las funciones no deben exceder 50 líneas de código efectivo.
- Funciones largas se dividen en funciones privadas con nombres descriptivos.
- Los métodos de `impl` siguen la misma regla.

---

## Checklist de estilo antes de hacer commit

- [ ] `cargo fmt --check` pasa sin diferencias
- [ ] `cargo clippy -- -D warnings` pasa sin warnings
- [ ] Sin `unwrap()` ni `expect()` en `src/` fuera de tests y main
- [ ] Parámetros de función usan `&str` / `&[T]` en lugar de `&String` / `&Vec<T>`
- [ ] Sin loops indexados donde un iterador funciona igual
- [ ] Visibilidad mínima necesaria en todos los símbolos
- [ ] Módulos organizados por dominio, no por tipo de artefacto
- [ ] Funciones <= 50 líneas
