Skip to main content

mant_query/selectors/
error.rs

1//! Existing public selection errors; re-exported through the crate facade.
2use std::{error::Error, fmt};
3
4/// Failure to derive an addressable view from a complete query.
5#[derive(Debug, Clone, PartialEq, Eq)]
6pub enum ProjectionError {
7    /// Neither an authoritative document nor a quick reference is available.
8    MissingContent {
9        /// Requested document label.
10        document: String,
11    },
12    /// Excerpt projection received no selectors.
13    EmptySelection,
14    /// One selector was empty after trimming.
15    EmptySelector,
16    /// A selector violates the closed path/ID grammar or size limit.
17    InvalidSelector,
18    /// Reference projection policy violates its closed bounds.
19    InvalidReferenceProjection(&'static str),
20    /// The caller exceeded the bounded selection count.
21    TooManySelections {
22        /// Maximum supported selector count.
23        maximum: usize,
24    },
25    /// No addressable node matched a selector.
26    UnknownSelector {
27        /// Requested document label.
28        document: String,
29        /// Unresolved selector.
30        selector: String,
31    },
32    /// An exact ID belongs to more than one content owner.
33    AmbiguousSelector {
34        /// Requested document label.
35        document: String,
36        /// Ambiguous selector.
37        selector: String,
38        /// Stable paths and IDs that disambiguate the match.
39        candidates: Vec<SelectorCandidate>,
40    },
41}
42
43/// One exact path offered when a content ID has multiple owners.
44#[derive(Debug, Clone, PartialEq, Eq)]
45pub struct SelectorCandidate {
46    /// Canonical structural outline path.
47    pub path: String,
48    /// Stable document-local identity.
49    pub id: String,
50}
51
52impl fmt::Display for ProjectionError {
53    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
54        match self {
55            Self::MissingContent { document } => {
56                write!(formatter, "document '{document}' has no available content")
57            }
58            Self::EmptySelection => formatter.write_str("at least one outline node is required"),
59            Self::EmptySelector => formatter.write_str("outline node must not be empty"),
60            Self::InvalidSelector => mant_protocol::InvalidContentSelector.fmt(formatter),
61            Self::InvalidReferenceProjection(reason) => formatter.write_str(reason),
62            Self::TooManySelections { maximum } => {
63                write!(formatter, "at most {maximum} outline nodes may be selected")
64            }
65            Self::UnknownSelector { document, selector } => write!(
66                formatter,
67                "document '{document}' has no outline node '{selector}'; inspect its entries outline for available selectors and diagnostics"
68            ),
69            Self::AmbiguousSelector {
70                document,
71                selector,
72                candidates,
73            } => {
74                write!(
75                    formatter,
76                    "document '{document}' has multiple content owners for '{selector}': "
77                )?;
78                for (index, candidate) in candidates.iter().enumerate() {
79                    if index > 0 {
80                        formatter.write_str(", ")?;
81                    }
82                    write!(formatter, "{} ({})", candidate.path, candidate.id)?;
83                }
84                formatter.write_str("; select one by path or ID")
85            }
86        }
87    }
88}
89
90impl Error for ProjectionError {}