From 4a348f4c8e28a91b1449548316443cda0ce8e62d Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 27 Oct 2024 16:16:55 +0000 Subject: [PATCH 1/3] Removed sync feature --- README2.md | 2 -- src/lib.rs | 88 ++++++++---------------------------------------- src/pratt.rs | 6 ++-- src/recovery.rs | 4 +-- src/recursive.rs | 41 +++++----------------- src/util.rs | 2 -- 6 files changed, 27 insertions(+), 116 deletions(-) diff --git a/README2.md b/README2.md index b8883c17..7e134d59 100644 --- a/README2.md +++ b/README2.md @@ -101,8 +101,6 @@ Chumsky contains several optional features that extend the crate's functionality - `either`: implements `Parser` for `either::Either`, allowing dynamic configuration of parsers at runtime -- `sync`: enables thread-safe features - - `extension`: enables the extension API, allowing you to write your own first-class combinators that integrate with and extend chumsky - `memoization`: enables [memoization](https://en.wikipedia.org/wiki/Memoization#Parsers) features diff --git a/src/lib.rs b/src/lib.rs index 6d8eb880..c58dd0b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,7 +111,13 @@ pub mod prelude { } use crate::input::InputOwn; -use alloc::{boxed::Box, string::String, vec, vec::Vec}; +use alloc::{ + boxed::Box, + rc::{self, Rc}, + string::String, + vec, + vec::Vec, +}; #[cfg(feature = "nightly")] use core::marker::Tuple; use core::{ @@ -176,40 +182,9 @@ impl Unpin for EmptyPhantom {} impl core::panic::UnwindSafe for EmptyPhantom {} impl core::panic::RefUnwindSafe for EmptyPhantom {} -#[cfg(feature = "sync")] -mod sync { - use super::*; - - pub(crate) type RefC = alloc::sync::Arc; - pub(crate) type RefW = alloc::sync::Weak; - pub(crate) type DynParser<'src, 'b, I, O, E> = dyn Parser<'src, I, O, E> + Send + Sync + 'b; - #[cfg(feature = "pratt")] - pub(crate) type DynOperator<'src, 'b, I, O, E> = - dyn pratt::Operator<'src, I, O, E> + Send + Sync + 'b; - - /// A trait that requires either nothing or `Send` and `Sync` bounds depending on whether the `sync` feature is - /// enabled. Used to constrain API usage succinctly and easily. - pub trait MaybeSync: Send + Sync {} - impl MaybeSync for T {} -} - -#[cfg(not(feature = "sync"))] -mod sync { - use super::*; - - pub(crate) type RefC = alloc::rc::Rc; - pub(crate) type RefW = alloc::rc::Weak; - pub(crate) type DynParser<'src, 'b, I, O, E> = dyn Parser<'src, I, O, E> + 'b; - #[cfg(feature = "pratt")] - pub(crate) type DynOperator<'src, 'b, I, O, E> = dyn pratt::Operator<'src, I, O, E> + 'b; - - /// A trait that requires either nothing or `Send` and `Sync` bounds depending on whether the `sync` feature is - /// enabled. Used to constrain API usage succinctly and easily. - pub trait MaybeSync {} - impl MaybeSync for T {} -} - -use sync::{DynParser, MaybeSync, RefC, RefW}; +pub(crate) type DynParser<'src, 'b, I, O, E> = dyn Parser<'src, I, O, E> + 'b; +#[cfg(feature = "pratt")] +pub(crate) type DynOperator<'src, 'b, I, O, E> = dyn pratt::Operator<'src, I, O, E> + 'b; /// The result of performing a parse on an input with [`Parser`]. /// @@ -2129,10 +2104,10 @@ pub trait Parser<'src, I: Input<'src>, O, E: ParserExtra<'src, I> = extra::Defau /// fn boxed<'b>(self) -> Boxed<'src, 'b, I, O, E> where - Self: MaybeSync + Sized + 'src + 'b, + Self: Sized + 'src + 'b, { Boxed { - inner: RefC::new(self), + inner: Rc::new(self), } } @@ -2668,7 +2643,7 @@ where /// it is *currently* the same size as a raw pointer. // TODO: Don't use an Rc pub struct Boxed<'src, 'b, I: Input<'src>, O, E: ParserExtra<'src, I>> { - inner: RefC>, + inner: Rc>, } impl<'src, I: Input<'src>, O, E: ParserExtra<'src, I>> Clone for Boxed<'src, '_, I, O, E> { @@ -2691,7 +2666,7 @@ where fn boxed<'c>(self) -> Boxed<'src, 'c, I, O, E> where - Self: MaybeSync + Sized + 'src + 'c, + Self: Sized + 'src + 'c, { // Never double-box parsers self @@ -3333,41 +3308,6 @@ mod tests { expr.then_ignore(end()).parse("a+b+c"); } - #[test] - fn arc_impl() { - use alloc::sync::Arc; - - fn parser<'src>() -> impl Parser<'src, &'src str, Vec> { - Arc::new( - any() - .filter(|c: &char| c.is_ascii_digit()) - .repeated() - .at_least(1) - .at_most(3) - .to_slice() - .map(|b: &str| b.parse::().unwrap()) - .padded() - .separated_by(just(',').padded()) - .allow_trailing() - .collect() - .delimited_by(just('['), just(']')), - ) - } - - assert_eq!( - parser().parse("[122 , 23,43, 4, ]").into_result(), - Ok(vec![122, 23, 43, 4]), - ); - assert_eq!( - parser().parse("[0, 3, 6, 900,120]").into_result(), - Ok(vec![0, 3, 6, 900, 120]), - ); - assert_eq!( - parser().parse("[200,400,50 ,0,0, ]").into_result(), - Ok(vec![200, 400, 50, 0, 0]), - ); - } - #[test] fn box_impl() { fn parser<'src>() -> impl Parser<'src, &'src str, Vec> { diff --git a/src/pratt.rs b/src/pratt.rs index 655b1f03..b17b9410 100644 --- a/src/pratt.rs +++ b/src/pratt.rs @@ -195,9 +195,9 @@ where /// Box this operator, allowing it to be used via dynamic dispatch. fn boxed<'a>(self) -> Boxed<'src, 'a, I, O, E> where - Self: Sized + MaybeSync + 'a, + Self: Sized + 'a, { - Boxed(RefC::new(self)) + Boxed(Rc::new(self)) } #[doc(hidden)] @@ -307,7 +307,7 @@ where } /// A boxed pratt parser operator. See [`Operator`]. -pub struct Boxed<'src, 'a, I, O, E>(RefC>); +pub struct Boxed<'src, 'a, I, O, E>(Rc>); impl Clone for Boxed<'_, '_, I, O, E> { fn clone(&self) -> Self { diff --git a/src/recovery.rs b/src/recovery.rs index 0b4614d3..994790eb 100644 --- a/src/recovery.rs +++ b/src/recovery.rs @@ -215,8 +215,8 @@ pub fn nested_delimiters<'src, I, O, E, F, const N: usize>( ) -> impl Parser<'src, I, O, E> + Clone where I: ValueInput<'src>, - I::Token: PartialEq + Clone + MaybeSync, - E: extra::ParserExtra<'src, I> + MaybeSync, + I::Token: PartialEq + Clone, + E: extra::ParserExtra<'src, I>, F: Fn(I::Span) -> O + Clone, { // TODO: Does this actually work? TESTS! diff --git a/src/recursive.rs b/src/recursive.rs index a12b8795..0e4f0fcc 100644 --- a/src/recursive.rs +++ b/src/recursive.rs @@ -10,9 +10,7 @@ use super::*; -#[cfg(not(feature = "sync"))] struct OnceCell(core::cell::Cell>); -#[cfg(not(feature = "sync"))] impl OnceCell { pub fn new() -> Self { Self(core::cell::Cell::new(None)) @@ -37,33 +35,10 @@ impl OnceCell { } } -#[cfg(feature = "sync")] -struct OnceCell(spin::once::Once); -#[cfg(feature = "sync")] -impl OnceCell { - pub fn new() -> Self { - Self(spin::once::Once::new()) - } - pub fn set(&self, x: T) -> Result<(), ()> { - // TODO: Race condition here, possibility of `Err(())` not being returned even through once is already occupied - // We don't care enough about this right now to do anything though, it's not a safety violation - if !self.0.is_completed() { - self.0.call_once(move || x); - Ok(()) - } else { - Err(()) - } - } - #[inline] - pub fn get(&self) -> Option<&T> { - self.0.get() - } -} - // TODO: Ensure that this doesn't produce leaks enum RecursiveInner { - Owned(RefC), - Unowned(RefW), + Owned(Rc), + Unowned(rc::Weak), } /// Type for recursive parsers that are defined through a call to `recursive`, and as such @@ -125,7 +100,7 @@ impl<'src, 'b, I: Input<'src>, O, E: ParserExtra<'src, I>> Recursive Self { Recursive { - inner: RecursiveInner::Owned(RefC::new(Indirect { + inner: RecursiveInner::Owned(Rc::new(Indirect { inner: OnceCell::new(), })), } @@ -134,7 +109,7 @@ impl<'src, 'b, I: Input<'src>, O, E: ParserExtra<'src, I>> Recursive + Clone + MaybeSync + 'src + 'b>(&mut self, parser: P) { + pub fn define + Clone + 'src + 'b>(&mut self, parser: P) { let location = *Location::caller(); self.parser() .inner @@ -147,7 +122,7 @@ impl<'src, 'b, I: Input<'src>, O, E: ParserExtra<'src, I>> Recursive Recursive

{ #[inline] - fn parser(&self) -> RefC

{ + fn parser(&self) -> Rc

{ match &self.inner { RecursiveInner::Owned(x) => x.clone(), RecursiveInner::Unowned(x) => x @@ -268,11 +243,11 @@ pub fn recursive<'src, 'b, I, O, E, A, F>(f: F) -> Recursive, E: ParserExtra<'src, I>, - A: Parser<'src, I, O, E> + Clone + MaybeSync + 'b, + A: Parser<'src, I, O, E> + Clone + 'b, F: FnOnce(Recursive>) -> A, { - let rc = RefC::new_cyclic(|rc| { - let rc: RefW> = rc.clone() as _; + let rc = Rc::new_cyclic(|rc| { + let rc: rc::Weak> = rc.clone() as _; let parser = Recursive { inner: RecursiveInner::Unowned(rc.clone()), }; diff --git a/src/util.rs b/src/util.rs index 45d839d3..d2bbee2d 100644 --- a/src/util.rs +++ b/src/util.rs @@ -7,8 +7,6 @@ use core::{ ops::{Deref, DerefMut}, }; -pub use sync::MaybeSync; - /// A value that may be a `T` or a mutable reference to a `T`. pub type MaybeMut<'a, T> = Maybe; From b757ad0b00f1f9207141e106ec55d2b4c2e0257c Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 27 Oct 2024 16:32:32 +0000 Subject: [PATCH 2/3] Removed unnecessary bounds from example --- examples/mini_ml.rs | 2 +- examples/nested_spans.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/mini_ml.rs b/examples/mini_ml.rs index 47829832..b7003c14 100644 --- a/examples/mini_ml.rs +++ b/examples/mini_ml.rs @@ -116,7 +116,7 @@ where I: BorrowInput<'src, Token = Token<'src>, Span = SimpleSpan>, // Because this function is generic over the input type, we need the caller to tell us how to create a new input, // `I`, from a nested token tree. This function serves that purpose. - M: Fn(SimpleSpan, &'src [Spanned>]) -> I + Clone + Send + Sync + 'src, + M: Fn(SimpleSpan, &'src [Spanned>]) -> I + Clone + 'src, { recursive(|expr| { let ident = select_ref! { Token::Ident(x) => *x }; diff --git a/examples/nested_spans.rs b/examples/nested_spans.rs index b991fe47..1b91ee49 100644 --- a/examples/nested_spans.rs +++ b/examples/nested_spans.rs @@ -13,7 +13,7 @@ enum Token { fn parser<'src, I, M>(make_input: M) -> impl Parser<'src, I, i64> where I: BorrowInput<'src, Token = Token, Span = SimpleSpan>, - M: Fn(SimpleSpan, &'src [(Token, SimpleSpan)]) -> I + Clone + Send + Sync + 'src, + M: Fn(SimpleSpan, &'src [(Token, SimpleSpan)]) -> I + Clone + 'src, { recursive(|expr| { let num = select_ref! { Token::Num(x) => *x }; From 315ef1a7011b3641997f646c038eb42854f4b47a Mon Sep 17 00:00:00 2001 From: Joshua Barretto Date: Sun, 27 Oct 2024 17:12:05 +0000 Subject: [PATCH 3/3] Fixed doc links --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c58dd0b5..b45f5bf0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2638,10 +2638,10 @@ where /// See [`Parser::boxed`]. /// -/// Due to current implementation details, the inner value is not, in fact, a [`Box`], but is an [`Rc`](std::rc::Rc) to facilitate -/// efficient cloning. This is likely to change in the future. Unlike [`Box`], [`Rc`](std::rc::Rc) has no size guarantees: although +/// Due to current implementation details, the inner value is not, in fact, a [`Box`], but is an [`Rc`] to facilitate +/// efficient cloning. This is likely to change in the future. Unlike [`Box`], [`Rc`] has no size guarantees: although /// it is *currently* the same size as a raw pointer. -// TODO: Don't use an Rc +// TODO: Don't use an Rc (why?) pub struct Boxed<'src, 'b, I: Input<'src>, O, E: ParserExtra<'src, I>> { inner: Rc>, }