diff --git a/src/input.rs b/src/input.rs index 8fdd7908..52e92d75 100644 --- a/src/input.rs +++ b/src/input.rs @@ -13,46 +13,6 @@ use super::*; #[cfg(feature = "std")] use std::io::{BufReader, Read, Seek}; -mod sealed { - pub trait Sealed {} -} -#[doc(hidden)] -pub trait MaybeOwned<'src, T: 'src>: - sealed::Sealed + Borrow + Into> -{ - type Proj: MaybeOwned<'src, U>; - #[doc(hidden)] - fn choose( - self, - f: impl FnOnce(&'src T) -> &'src R, - g: impl FnOnce(T) -> R, - ) -> Self::Proj; -} - -impl sealed::Sealed for &T {} -impl<'src, T> MaybeOwned<'src, T> for &'src T { - type Proj = &'src U; - fn choose( - self, - f: impl FnOnce(&'src T) -> &'src R, - _g: impl FnOnce(T) -> R, - ) -> Self::Proj { - f(self) - } -} - -impl sealed::Sealed for T {} -impl<'src, T: 'src> MaybeOwned<'src, T> for T { - type Proj = U; - fn choose( - self, - _f: impl FnOnce(&'src T) -> &'src R, - g: impl FnOnce(T) -> R, - ) -> Self::Proj { - g(self) - } -} - /// A trait for types that represents a stream of input tokens. Unlike [`Iterator`], this type /// supports backtracking and a few other features required by the crate. /// @@ -73,7 +33,7 @@ pub trait Input<'src>: 'src { type Token: 'src; /// The token type returned by [`Input::next_maybe`], allows abstracting over by-value and by-reference inputs. - type TokenMaybe: MaybeOwned<'src, Self::Token>; // Must be `&'src Self::Token` or `Self::Token` + type MaybeToken: IntoMaybe<'src, Self::Token>; // Must be `&'src Self::Token` or `Self::Token` /// The type used to keep track of the current location in the stream. /// @@ -101,7 +61,7 @@ pub trait Input<'src>: 'src { unsafe fn next_maybe( cache: &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option; + ) -> Option; /// Create a span going from the start cursor to the end cursor (exclusive). /// @@ -247,7 +207,7 @@ impl<'src> Input<'src> for &'src str { type Span = SimpleSpan; type Token = char; - type TokenMaybe = char; + type MaybeToken = char; type Cache = Self; @@ -265,7 +225,7 @@ impl<'src> Input<'src> for &'src str { unsafe fn next_maybe( this: &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { if *cursor < this.len() { // SAFETY: `cursor < self.len()` above guarantees cursor is in-bounds // We only ever return cursors that are at a character boundary @@ -328,7 +288,7 @@ impl<'src, T> Input<'src> for &'src [T] { type Span = SimpleSpan; type Token = T; - type TokenMaybe = &'src T; + type MaybeToken = &'src T; type Cache = Self; @@ -346,7 +306,7 @@ impl<'src, T> Input<'src> for &'src [T] { unsafe fn next_maybe( this: &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { if let Some(tok) = this.get(*cursor) { *cursor += 1; Some(tok) @@ -412,7 +372,7 @@ impl<'src, T: 'src, const N: usize> Input<'src> for &'src [T; N] { type Span = SimpleSpan; type Token = T; - type TokenMaybe = &'src T; + type MaybeToken = &'src T; type Cache = Self; @@ -430,7 +390,7 @@ impl<'src, T: 'src, const N: usize> Input<'src> for &'src [T; N] { unsafe fn next_maybe( this: &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { if let Some(tok) = this.get(*cursor) { *cursor += 1; Some(tok) @@ -509,7 +469,7 @@ where type Span = S; type Token = T; - type TokenMaybe = >::Proj; + type MaybeToken = >::Proj; type Cache = (I::Cache, S); @@ -528,10 +488,10 @@ where unsafe fn next_maybe( (cache, _): &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { I::next_maybe(cache, &mut cursor.0).map(|tok| { cursor.1 = Some(tok.borrow().1.end()); - tok.choose(|(tok, _)| tok, |(tok, _)| tok) + tok.map_maybe(|(tok, _)| tok, |(tok, _)| tok) }) } @@ -644,7 +604,7 @@ where type Span = S; type Token = I::Token; - type TokenMaybe = I::TokenMaybe; + type MaybeToken = I::MaybeToken; type Cache = (I::Cache, S::Context); @@ -663,7 +623,7 @@ where unsafe fn next_maybe( (cache, _): &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { I::next_maybe(cache, cursor) } @@ -789,7 +749,7 @@ where type Span = S; type Token = I::Token; - type TokenMaybe = I::TokenMaybe; + type MaybeToken = I::MaybeToken; type Cache = (I::Cache, F); @@ -808,7 +768,7 @@ where unsafe fn next_maybe( (cache, _): &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { I::next_maybe(cache, cursor) } @@ -941,7 +901,7 @@ impl<'src, R: Read + Seek + 'src> Input<'src> for IoInput { type Span = SimpleSpan; type Token = u8; - type TokenMaybe = u8; + type MaybeToken = u8; type Cache = Self; @@ -958,7 +918,7 @@ impl<'src, R: Read + Seek + 'src> Input<'src> for IoInput { unsafe fn next_maybe( this: &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { Self::next(this, cursor) } @@ -1347,7 +1307,7 @@ impl<'src, 'parse, I: Input<'src>, E: ParserExtra<'src, I>> InputRef<'src, 'pars } #[inline(always)] - pub(crate) fn next_maybe_inner(&mut self) -> Option { + pub(crate) fn next_maybe_inner(&mut self) -> Option { // SAFETY: cursor was generated by previous call to `Input::next` let token = unsafe { I::next_maybe(self.cache, &mut self.cursor) }; if let Some(t) = &token { diff --git a/src/lib.rs b/src/lib.rs index 06cc5366..9132b385 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,7 +149,7 @@ use self::{ recovery::{RecoverWith, Strategy}, span::Span, text::*, - util::{MaybeMut, MaybeRef}, + util::{IntoMaybe, MaybeMut, MaybeRef}, }; #[cfg(all(feature = "extension", doc))] use self::{extension::v1::*, primitive::custom, stream::Stream}; diff --git a/src/stream.rs b/src/stream.rs index c7568058..c271caff 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -67,7 +67,7 @@ where type Span = SimpleSpan; type Token = I::Item; - type TokenMaybe = I::Item; + type MaybeToken = I::Item; type Cursor = usize; @@ -87,7 +87,7 @@ where unsafe fn next_maybe( this: &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { Self::next(this, cursor) } @@ -151,7 +151,7 @@ where type Span = S; type Token = T; - type TokenMaybe = T; + type MaybeToken = T; type Cache = S; // eoi @@ -168,7 +168,7 @@ where unsafe fn next_maybe( _eoi: &mut Self::Cache, cursor: &mut Self::Cursor, - ) -> Option { + ) -> Option { cursor.0.next().map(|(tok, span)| { cursor.1 += 1; cursor.2 = Some(span.end()); diff --git a/src/text.rs b/src/text.rs index eed6ce5d..a0e560ea 100644 --- a/src/text.rs +++ b/src/text.rs @@ -281,7 +281,7 @@ where pub fn digits<'a, C, I, E>(radix: u32) -> Repeated + Copy, C, I, E> where C: Char, - I: ValueInput<'a> + Input<'a, Token = C>, + I: ValueInput<'a, Token = C>, E: ParserExtra<'a, I>, { any() @@ -328,7 +328,7 @@ where /// ``` /// #[must_use] -pub fn int<'a, I: ValueInput<'a> + StrInput<'a, C>, C: Char, E: ParserExtra<'a, I>>( +pub fn int<'a, I: StrInput<'a, C>, C: Char, E: ParserExtra<'a, I>>( radix: u32, ) -> impl Parser<'a, I, &'a C::Str, E> + Copy { any() diff --git a/src/util.rs b/src/util.rs index e7ecf7c1..45d839d3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -173,3 +173,54 @@ impl<'de, T: Deserialize<'de>, R: Deref> Deserialize<'de> for Maybe< deserializer.deserialize_newtype_struct("Maybe", MaybeVisitor(PhantomData)) } } + +mod ref_or_val_sealed { + pub trait Sealed {} +} + +/// An trait that allows abstracting over values of or references to a `T`. +/// +/// Some [`Input`]s can only generate tokens by-reference (like `&[T]` -> `&T`), and some can only generate tokens +/// by-value (like `&str` -> `char`). This trait allows chumsky to handle both kinds of input. +/// +/// The trait is sealed: you cannot implement it yourself. +pub trait IntoMaybe<'src, T: 'src>: + ref_or_val_sealed::Sealed + Borrow + Into> +{ + /// Project the referential properties of this type on to another type. + /// + /// For example, `<&Foo>::Proj = &Bar` but `::Proj = Bar`. + #[doc(hidden)] + type Proj: IntoMaybe<'src, U>; + + #[doc(hidden)] + fn map_maybe( + self, + f: impl FnOnce(&'src T) -> &'src R, + g: impl FnOnce(T) -> R, + ) -> Self::Proj; +} + +impl ref_or_val_sealed::Sealed for &T {} +impl<'src, T> IntoMaybe<'src, T> for &'src T { + type Proj = &'src U; + fn map_maybe( + self, + f: impl FnOnce(&'src T) -> &'src R, + _g: impl FnOnce(T) -> R, + ) -> Self::Proj { + f(self) + } +} + +impl ref_or_val_sealed::Sealed for T {} +impl<'src, T: 'src> IntoMaybe<'src, T> for T { + type Proj = U; + fn map_maybe( + self, + _f: impl FnOnce(&'src T) -> &'src R, + g: impl FnOnce(T) -> R, + ) -> Self::Proj { + g(self) + } +}