Skip to main content

link_cli/
error.rs

1//! Error types for link operations
2//!
3//! This module defines all error types used throughout the link-cli.
4//!
5//! [`LinkError`] is the typed error exposed by the public storage and
6//! transactions API. It is deliberately **not** `anyhow::Error`, so
7//! external crates embedding this library can match on failures instead
8//! of inspecting strings. Because `LinkError` implements
9//! [`std::error::Error`], every `LinkError` still converts into
10//! `anyhow::Error` with `?` for callers that prefer `anyhow`.
11
12use doublets::data::LinkReference;
13use thiserror::Error;
14
15/// Error types for link operations
16#[derive(Error, Debug)]
17pub enum LinkError {
18    /// No link exists at the requested address.
19    ///
20    /// The address is widened to `u128` so the same error type can be
21    /// used with every `doublets` address type (`u32`, `u64`, `usize`).
22    #[error("Link not found: {0}")]
23    NotFound(u128),
24
25    #[error("Invalid link format: {0}")]
26    InvalidFormat(String),
27
28    #[error("Storage error: {0}")]
29    StorageError(String),
30
31    #[error("Query error: {0}")]
32    QueryError(String),
33
34    #[error("Parse error: {0}")]
35    ParseError(String),
36
37    /// Filesystem failure while reading or writing a links database.
38    #[error("I/O error: {0}")]
39    Io(#[from] std::io::Error),
40
41    /// Failure reported by the underlying `doublets` store.
42    #[error("Doublets store error: {0}")]
43    Doublets(String),
44
45    /// Advisory file lock could not be acquired or released.
46    #[error("Lock error: {0}")]
47    Lock(String),
48
49    /// Invalid use of the transactions layer (nested transaction, ...).
50    #[error("Transaction error: {0}")]
51    Transaction(String),
52
53    /// A recorded address does not fit into the configured address type.
54    #[error("Address {0} does not fit into the configured link address type")]
55    AddressOutOfRange(u128),
56}
57
58impl LinkError {
59    /// Builds a [`LinkError::NotFound`] from any `doublets` address type.
60    pub fn not_found<T: LinkReference>(index: T) -> Self {
61        Self::NotFound(to_u128(index))
62    }
63}
64
65impl<T: LinkReference> From<doublets::Error<T>> for LinkError {
66    fn from(error: doublets::Error<T>) -> Self {
67        match error {
68            doublets::Error::NotExists(index) => Self::NotFound(to_u128(index)),
69            other => Self::Doublets(other.to_string()),
70        }
71    }
72}
73
74/// Widens any `doublets` address into `u128` for error reporting.
75///
76/// `LinkReference: TryInto<u128, Error: Debug>` and every supported
77/// address type is unsigned and at most 128 bits wide, so this never
78/// actually fails; the fallback keeps the helper total.
79fn to_u128<T: LinkReference>(index: T) -> u128 {
80    TryInto::<u128>::try_into(index).unwrap_or(u128::MAX)
81}