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}