Skip to content

Latest commit

 

History

History
294 lines (224 loc) · 5.95 KB

File metadata and controls

294 lines (224 loc) · 5.95 KB

Error Types Reference

This document covers error handling in libgrammstein.

Error Enum

The main error type is libgrammstein::Error:

use libgrammstein::Error;

#[derive(Error, Debug)]
pub enum Error {
    /// I/O error during corpus reading or model loading.
    #[error("I/O error: {0}")]
    Io(#[from] std::io::Error),

    /// XML parsing error (Wikipedia dump).
    #[error("XML parsing error: {0}")]
    Xml(#[from] quick_xml::Error),

    /// Invalid n-gram order (must be >= 1).
    #[error("Invalid n-gram order: {0} (must be >= 1)")]
    InvalidOrder(usize),

    /// Empty corpus provided for training.
    #[error("Empty corpus: no sentences found")]
    EmptyCorpus,

    /// Model not trained.
    #[error("Model not trained: {0}")]
    NotTrained(String),

    /// Serialization error (requires serde-extras feature).
    #[cfg(feature = "serde-extras")]
    #[error("Serialization error: {0}")]
    Serialization(#[from] bincode::Error),
}

Result Type

The library provides a type alias for convenience:

pub type Result<T> = std::result::Result<T, Error>;

Error Variants

Io

I/O errors from file operations.

// Example: File not found
let result = PlaintextReader::from_file("nonexistent.txt");
match result {
    Err(Error::Io(e)) => println!("I/O error: {}", e),
    _ => {}
}

Common causes:

  • File not found
  • Permission denied
  • Disk full
  • Network errors (HTTP corpus)

Xml

XML parsing errors when reading Wikipedia dumps.

// Example: Malformed XML
let result = WikipediaReader::from_dump("malformed.xml");
match result {
    Err(Error::Xml(e)) => println!("XML error: {}", e),
    _ => {}
}

Common causes:

  • Corrupted XML file
  • Incomplete download
  • Wrong file format

InvalidOrder

N-gram order must be at least 1.

// Example: Invalid order
let result = TrainerBuilder::new(dictionary)
    .order(0)  // Invalid!
    .train(&reader);

match result {
    Err(Error::InvalidOrder(order)) => {
        println!("Invalid order: {}", order);
    }
    _ => {}
}

EmptyCorpus

Training requires at least one sentence.

// Example: Empty input
let reader = PlaintextReader::from_string("");
let result = TrainerBuilder::new(dictionary).train(&reader);

match result {
    Err(Error::EmptyCorpus) => println!("No sentences found!"),
    _ => {}
}

Common causes:

  • Empty file
  • All text filtered out by quality filters
  • Tokenizer producing no words

NotTrained

Attempted to use a model that hasn't been trained.

// Example: Using untrained model
match result {
    Err(Error::NotTrained(reason)) => {
        println!("Model not trained: {}", reason);
    }
    _ => {}
}

Serialization

Errors during save/load operations (requires serde-extras feature).

// Example: Corrupted model file
let result = NgramModel::<D>::load("corrupted.bin");

match result {
    Err(Error::Serialization(e)) => {
        println!("Serialization error: {}", e);
    }
    _ => {}
}

Common causes:

  • Corrupted file
  • Version mismatch
  • Incomplete save
  • Wrong model type

Error Handling Patterns

Basic Pattern

use libgrammstein::Result;

fn train_model() -> Result<NgramModel<D>> {
    let reader = PlaintextReader::from_file("corpus.txt")?;
    let model = TrainerBuilder::new(dictionary).train(&reader)?;
    Ok(model)
}

With Context

fn train_model(path: &str) -> Result<NgramModel<D>> {
    let reader = PlaintextReader::from_file(path)
        .map_err(|e| {
            eprintln!("Failed to open corpus: {}", path);
            e
        })?;

    TrainerBuilder::new(dictionary).train(&reader)
}

Matching Specific Errors

use libgrammstein::Error;

fn handle_training_error(err: Error) {
    match err {
        Error::Io(e) if e.kind() == std::io::ErrorKind::NotFound => {
            eprintln!("Corpus file not found. Please provide a valid path.");
        }
        Error::EmptyCorpus => {
            eprintln!("Corpus contains no valid sentences. Check your input.");
        }
        Error::InvalidOrder(n) => {
            eprintln!("N-gram order {} is invalid. Use 1 or higher.", n);
        }
        _ => {
            eprintln!("Training failed: {}", err);
        }
    }
}

Converting Errors

use std::io::ErrorKind;

// From std::io::Error
let io_err = std::io::Error::new(ErrorKind::NotFound, "file not found");
let err: Error = io_err.into();

// From quick_xml::Error
// (automatically converted via #[from])

Propagating with ?

fn load_and_query(path: &str) -> Result<f64> {
    let model: NgramModel<D> = NgramModel::load(path)?;
    Ok(model.log_prob("test", &["a"]))
}

CLI Error Handling

The CLI provides user-friendly error messages:

use libgrammstein::cli::error::CliError;

#[derive(Error, Debug)]
pub enum CliError {
    #[error("Corpus not found: {0}")]
    CorpusNotFound(String),

    #[error("Model not found: {0}")]
    ModelNotFound(String),

    #[error("Invalid format: {0}")]
    InvalidFormat(String),

    #[error(transparent)]
    Library(#[from] libgrammstein::Error),

    #[error(transparent)]
    Io(#[from] std::io::Error),
}

Best Practices

  1. Use ? for propagation

    let model = NgramModel::load(path)?;
  2. Provide context in errors

    let reader = PlaintextReader::from_file(path)
        .map_err(|e| format!("Failed to read {}: {}", path, e))?;
  3. Handle recoverable errors gracefully

    match model.log_prob(word, context) {
        prob if prob.is_finite() => prob,
        _ => model.oov_log_prob(),  // Fallback for OOV
    }
  4. Log errors for debugging

    if let Err(e) = model.save(path) {
        log::error!("Failed to save model: {}", e);
        return Err(e);
    }

See Also