ankit_engine/error.rs
1//! Error types for ankit-engine.
2//!
3//! Errors from engine workflows fall into two categories:
4//!
5//! 1. **Client errors**: Wrapped from the underlying [`ankit::Error`] type
6//! 2. **Workflow errors**: Specific to engine operations (e.g., deck not found)
7//!
8//! # Example
9//!
10//! ```no_run
11//! use ankit_engine::{Engine, Error};
12//!
13//! # async fn example() {
14//! let engine = Engine::new();
15//!
16//! match engine.analyze().study_summary("NonexistentDeck", 7).await {
17//! Ok(stats) => println!("Reviews: {}", stats.total_reviews),
18//! Err(Error::DeckNotFound(name)) => {
19//! eprintln!("Deck '{}' not found", name);
20//! }
21//! Err(Error::Client(ankit::Error::ConnectionRefused)) => {
22//! eprintln!("Is Anki running?");
23//! }
24//! Err(e) => eprintln!("Error: {}", e),
25//! }
26//! # }
27//! ```
28
29use std::fmt;
30
31/// Result type for ankit-engine operations.
32pub type Result<T> = std::result::Result<T, Error>;
33
34/// Errors that can occur during engine operations.
35///
36/// Engine errors wrap lower-level client errors and add workflow-specific
37/// error variants for common failure cases.
38#[derive(Debug)]
39pub enum Error {
40 /// An error from the underlying ankit client.
41 Client(ankit::Error),
42
43 /// A deck was not found.
44 DeckNotFound(String),
45
46 /// A model (note type) was not found.
47 ModelNotFound(String),
48
49 /// A required field is missing from a note.
50 MissingField {
51 /// The model name.
52 model: String,
53 /// The missing field name.
54 field: String,
55 },
56
57 /// No notes matched the query.
58 NoNotesFound(String),
59
60 /// An operation was cancelled.
61 Cancelled,
62
63 /// A validation error occurred.
64 Validation(String),
65
66 /// An I/O error occurred.
67 Io(std::io::Error),
68
69 /// A backup operation failed.
70 Backup(String),
71}
72
73impl std::error::Error for Error {
74 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
75 match self {
76 Error::Client(e) => Some(e),
77 Error::Io(e) => Some(e),
78 _ => None,
79 }
80 }
81}
82
83impl fmt::Display for Error {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 match self {
86 Error::Client(e) => write!(f, "{}", e),
87 Error::DeckNotFound(name) => write!(f, "deck not found: {}", name),
88 Error::ModelNotFound(name) => write!(f, "model not found: {}", name),
89 Error::MissingField { model, field } => {
90 write!(f, "missing field '{}' for model '{}'", field, model)
91 }
92 Error::NoNotesFound(query) => write!(f, "no notes found for query: {}", query),
93 Error::Cancelled => write!(f, "operation cancelled"),
94 Error::Validation(msg) => write!(f, "validation error: {}", msg),
95 Error::Io(e) => write!(f, "I/O error: {}", e),
96 Error::Backup(msg) => write!(f, "backup error: {}", msg),
97 }
98 }
99}
100
101impl From<std::io::Error> for Error {
102 fn from(err: std::io::Error) -> Self {
103 Error::Io(err)
104 }
105}
106
107impl From<ankit::Error> for Error {
108 fn from(err: ankit::Error) -> Self {
109 Error::Client(err)
110 }
111}