use core::fmt; use thiserror::Error; use crate::ast::Span; #[derive(Clone, Debug, Eq, PartialEq, Error)] pub enum QueryErrorKind { #[error("query is longer than {max} bytes")] TooLong { max: usize }, #[error("query has more than {max} terms")] TooManyClauses { max: usize }, #[error("`{key}:` needs a value")] MissingValue { key: String }, #[error("`{key}:{value}` is not valid, expected {expected}")] InvalidValue { key: String, value: String, expected: &'static str, }, #[error("`{key}:` takes a single value")] TooManyValues { key: String }, #[error("`{key}:` cannot be negated")] NotNegatable { key: String }, #[error("only one `sort:` is allowed")] ConflictingSort, } #[derive(Clone, Debug, Eq, PartialEq, Error)] #[error("{kind}")] pub struct QueryError { pub span: Span, pub kind: QueryErrorKind, } impl QueryError { pub const fn new(span: Span, kind: QueryErrorKind) -> Self { Self { span, kind } } } /// all the errors in a query in source order #[derive(Clone, Debug, Eq, PartialEq, Error)] pub struct QueryErrors(Vec); impl QueryErrors { pub(crate) fn new(errors: Vec) -> Self { debug_assert!(!errors.is_empty()); Self(errors) } pub fn as_slice(&self) -> &[QueryError] { &self.0 } pub fn into_vec(self) -> Vec { self.0 } pub fn first(&self) -> Option<&QueryError> { self.0.first() } } impl fmt::Display for QueryErrors { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { for (i, e) in self.0.iter().enumerate() { if i > 0 { f.write_str("; ")?; } fmt::Display::fmt(e, f)?; } Ok(()) } } impl IntoIterator for QueryErrors { type Item = QueryError; type IntoIter = std::vec::IntoIter; fn into_iter(self) -> Self::IntoIter { self.0.into_iter() } }