From e8e03ab356cb6320739dcfe071bf0dcc7f246638 Mon Sep 17 00:00:00 2001 From: Sean Olson Date: Mon, 18 Mar 2024 11:17:24 -0700 Subject: [PATCH] Move more types into `query`. This change also uses type aliases in bound APIs for consistency in code and documentation. --- src/diagnostics/mod.rs | 4 +- src/lib.rs | 34 ++++++++-------- src/query.rs | 81 +++++++++++++++++++++++++++++++++++-- src/token/mod.rs | 5 ++- src/token/variance/bound.rs | 12 +++--- src/walk/behavior.rs | 7 +--- 6 files changed, 108 insertions(+), 35 deletions(-) diff --git a/src/diagnostics/mod.rs b/src/diagnostics/mod.rs index 5e4b17a..61c0ac5 100644 --- a/src/diagnostics/mod.rs +++ b/src/diagnostics/mod.rs @@ -73,8 +73,8 @@ impl Spanned for Span { /// /// [`BuildError::locations`]: crate::BuildError::locations /// [`Display`]: std::fmt::Display -/// [`LocatedError::span`]: crate::LocatedError::span -/// [`Span`]: crate::Span +/// [`LocatedError::span`]: crate::query::LocatedError::span +/// [`Span`]: crate::query::Span pub trait LocatedError: Display { /// Gets the span within the glob expression with which the error is associated. fn span(&self) -> Span; diff --git a/src/lib.rs b/src/lib.rs index fdd7a8f..d3c3985 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -58,9 +58,10 @@ pub mod walk; /// } /// ``` pub mod prelude { + pub use crate::query::LocatedError as _; #[cfg(feature = "walk")] pub use crate::walk::{Entry as _, FileIterator as _, PathExt as _}; - pub use crate::{LocatedError as _, Program as _}; + pub use crate::Program as _; } #[cfg(feature = "miette")] @@ -75,18 +76,17 @@ use std::path::{Path, PathBuf}; use std::str::{self, FromStr}; use thiserror::Error; +use crate::diagnostics::LocatedError; use crate::encode::CompileError; -use crate::query::{CapturingToken, When}; +use crate::query::{CapturingToken, DepthVariance, TextVariance, When}; use crate::rule::{Checked, RuleError}; use crate::token::{ - ConcatenationTree, Depth, ExpressionMetadata, ParseError, Text, Token, TokenTree, - TokenVariance, Tokenized, + ConcatenationTree, ExpressionMetadata, ParseError, Token, TokenTree, Tokenized, }; #[cfg(feature = "walk")] use crate::walk::WalkError; pub use crate::capture::MatchedText; -pub use crate::diagnostics::{LocatedError, Span}; #[cfg(windows)] const PATHS_ARE_CASE_INSENSITIVE: bool = true; @@ -174,9 +174,9 @@ pub trait Program<'t>: Pattern<'t, Error = Infallible> { /// [`MatchedText`]: crate::MatchedText fn matched<'p>(&self, path: &'p CandidatePath<'_>) -> Option>; - fn depth(&self) -> TokenVariance; + fn depth(&self) -> DepthVariance; - fn text(&self) -> TokenVariance>; + fn text(&self) -> TextVariance<'t>; /// Returns `true` if the glob has a root. /// @@ -307,8 +307,8 @@ impl BuildError { /// [`Glob`]: crate::Glob /// [`Glob::partition`]: crate::Glob::partition /// [`Iterator`]: std::iter::Iterator - /// [`LocatedError`]: crate::LocatedError - /// [`Span`]: crate::Span + /// [`LocatedError`]: crate::query::LocatedError + /// [`Span`]: crate::query::Span pub fn locations(&self) -> impl Iterator { let locations: Vec<_> = match self.kind { BuildErrorKind::Parse(ref error) => error @@ -699,12 +699,12 @@ impl<'t> Program<'t> for Glob<'t> { self.program.captures(path.as_ref()).map(From::from) } - fn depth(&self) -> TokenVariance { - self.tree.as_ref().as_token().variance() + fn depth(&self) -> DepthVariance { + self.tree.as_ref().as_token().variance().into() } - fn text(&self) -> TokenVariance> { - self.tree.as_ref().as_token().variance() + fn text(&self) -> TextVariance<'t> { + self.tree.as_ref().as_token().variance().into() } fn has_root(&self) -> When { @@ -758,12 +758,12 @@ impl<'t> Program<'t> for Any<'t> { self.program.captures(path.as_ref()).map(From::from) } - fn depth(&self) -> TokenVariance { - self.tree.as_ref().as_token().variance() + fn depth(&self) -> DepthVariance { + self.tree.as_ref().as_token().variance().into() } - fn text(&self) -> TokenVariance> { - self.tree.as_ref().as_token().variance() + fn text(&self) -> TextVariance<'t> { + self.tree.as_ref().as_token().variance().into() } fn has_root(&self) -> When { diff --git a/src/query.rs b/src/query.rs index 600f775..d8a0e66 100644 --- a/src/query.rs +++ b/src/query.rs @@ -1,10 +1,85 @@ -use crate::diagnostics::Span; +//! [`Program`] diagnostic and inspection types. +//! +//! [`Program`]: crate::Program +use std::borrow::Cow; + +use crate::token::{Depth, Text, TokenVariance}; + +pub use crate::diagnostics::{LocatedError, Span}; pub use crate::token::{ - BoundedVariantRange, Boundedness, Depth, Invariant, Text, TokenVariance, UnitBound, Variance, - VariantRange, + BoundedVariantRange, Boundedness, NonZeroBound, NonZeroLower, NonZeroUpper, VariantRange, }; +// TODO: `VariantRange` is a complex type composition that requires many re-exported types. Define +// a simpler local type if possible. +pub type DepthVariance = Variance; +pub type TextVariance<'t> = Variance, ()>; + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Variance { + Invariant(T), + Variant(B), +} + +impl Variance { + pub fn invariant(self) -> Option { + match self { + Variance::Invariant(invariance) => Some(invariance), + _ => None, + } + } + + pub fn variant(self) -> Option { + match self { + Variance::Variant(variance) => Some(variance), + _ => None, + } + } + + pub fn as_ref(&self) -> Variance<&T, &B> { + match self { + Variance::Invariant(ref invariance) => Variance::Invariant(invariance), + Variance::Variant(ref variance) => Variance::Variant(variance), + } + } + + pub fn is_invariant(&self) -> bool { + matches!(self, Variance::Invariant(_)) + } + + pub fn is_variant(&self) -> bool { + matches!(self, Variance::Variant(_)) + } +} + +impl<'t> From> for Option> { + fn from(text: TextVariance<'t>) -> Self { + match text { + TextVariance::Invariant(text) => Some(text), + _ => None, + } + } +} + +impl<'t> From>> for TextVariance<'t> { + fn from(text: TokenVariance>) -> Self { + match text { + TokenVariance::Invariant(text) => TextVariance::Invariant(text.to_string()), + TokenVariance::Variant(_) => TextVariance::Variant(()), + } + } +} + +impl From> for DepthVariance { + fn from(depth: TokenVariance) -> Self { + match depth { + TokenVariance::Invariant(depth) => DepthVariance::Invariant(depth.into()), + TokenVariance::Variant(bounds) => DepthVariance::Variant(bounds), + } + } +} + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub enum When { Always, diff --git a/src/token/mod.rs b/src/token/mod.rs index d841124..d2feef0 100644 --- a/src/token/mod.rs +++ b/src/token/mod.rs @@ -22,9 +22,10 @@ use crate::{StrExt as _, PATHS_ARE_CASE_INSENSITIVE}; pub use crate::token::parse::{parse, ParseError, ROOT_SEPARATOR_EXPRESSION}; pub use crate::token::variance::bound::{ - BoundedVariantRange, Boundedness, NaturalRange, VariantRange, + BoundedVariantRange, Boundedness, NaturalRange, NonZeroBound, NonZeroLower, NonZeroUpper, + VariantRange, }; -pub use crate::token::variance::invariant::{Breadth, Depth, Invariant, Size, Text, UnitBound}; +pub use crate::token::variance::invariant::{Breadth, Depth, Invariant, Size, Text}; pub use crate::token::variance::{TokenVariance, Variance}; // TODO: Tree representations of expressions are intrusive and only differ in their annotations. diff --git a/src/token/variance/bound.rs b/src/token/variance/bound.rs index e1ea167..e14e8e9 100644 --- a/src/token/variance/bound.rs +++ b/src/token/variance/bound.rs @@ -169,14 +169,14 @@ impl NaturalRange { Self::from_closed_and_open(lower.into_usize(), upper.into_usize()) } - pub fn lower(&self) -> Lower { + pub fn lower(&self) -> NaturalLower { match self { Variance::Invariant(ref n) => NaturalBound::from(*n).into_lower(), Variance::Variant(ref range) => range.lower().map(Variance::Variant), } } - pub fn upper(&self) -> Upper { + pub fn upper(&self) -> NaturalUpper { match self { Variance::Invariant(ref n) => NaturalBound::from(*n).into_upper(), Variance::Variant(ref range) => range.upper().map(Variance::Variant), @@ -304,13 +304,13 @@ impl From for NonZeroBound { } impl VariantRange { - pub fn lower(&self) -> Lower { + pub fn lower(&self) -> NonZeroLower { self.as_ref() .bounded() .map_or_else(|| Unbounded.into_lower(), BoundedVariantRange::lower) } - pub fn upper(&self) -> Upper { + pub fn upper(&self) -> NonZeroUpper { self.as_ref() .bounded() .map_or_else(|| Unbounded.into_upper(), BoundedVariantRange::upper) @@ -564,7 +564,7 @@ impl BoundedVariantRange { } } - pub fn lower(&self) -> Lower { + pub fn lower(&self) -> NonZeroLower { use BoundedVariantRange::{Both, Lower, Upper}; match self { @@ -574,7 +574,7 @@ impl BoundedVariantRange { .into_lower() } - pub fn upper(&self) -> Upper { + pub fn upper(&self) -> NonZeroUpper { use BoundedVariantRange::{Both, Lower, Upper}; match self { diff --git a/src/walk/behavior.rs b/src/walk/behavior.rs index b50a0de..5915e01 100644 --- a/src/walk/behavior.rs +++ b/src/walk/behavior.rs @@ -210,15 +210,12 @@ impl DepthBehavior { } } - pub fn bounded_with_depth_variance( + pub fn bounded_at_depth_variance( min: impl Into>, max: impl Into>, depth: TokenVariance, ) -> Option { - let lower = depth - .map_invariant(From::from) - .map_variant(|bound| bound.lower().into_usize()) - .into_inner(); + let lower = depth.map_invariant(usize::from).lower().into_usize(); let translation = move |depth: Option| -> Result, ()> { depth .map(|depth| depth.checked_add(lower).ok_or(()))