Skip to content

Commit

Permalink
Merge pull request #693 from zesterer/remove-sync-feature
Browse files Browse the repository at this point in the history
Removed sync feature
  • Loading branch information
zesterer authored Oct 27, 2024
2 parents 8156611 + 315ef1a commit c7acd96
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 121 deletions.
2 changes: 0 additions & 2 deletions README2.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion examples/mini_ml.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Token<'src>>]) -> I + Clone + Send + Sync + 'src,
M: Fn(SimpleSpan, &'src [Spanned<Token<'src>>]) -> I + Clone + 'src,
{
recursive(|expr| {
let ident = select_ref! { Token::Ident(x) => *x };
Expand Down
2 changes: 1 addition & 1 deletion examples/nested_spans.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand Down
94 changes: 17 additions & 77 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down Expand Up @@ -176,40 +182,9 @@ impl<T> Unpin for EmptyPhantom<T> {}
impl<T> core::panic::UnwindSafe for EmptyPhantom<T> {}
impl<T> core::panic::RefUnwindSafe for EmptyPhantom<T> {}

#[cfg(feature = "sync")]
mod sync {
use super::*;

pub(crate) type RefC<T> = alloc::sync::Arc<T>;
pub(crate) type RefW<T> = alloc::sync::Weak<T>;
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<T: Send + Sync> MaybeSync for T {}
}

#[cfg(not(feature = "sync"))]
mod sync {
use super::*;

pub(crate) type RefC<T> = alloc::rc::Rc<T>;
pub(crate) type RefW<T> = alloc::rc::Weak<T>;
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<T> 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`].
///
Expand Down Expand Up @@ -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),
}
}

Expand Down Expand Up @@ -2663,12 +2638,12 @@ 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: RefC<DynParser<'src, 'b, I, O, E>>,
inner: Rc<DynParser<'src, 'b, I, O, E>>,
}

impl<'src, I: Input<'src>, O, E: ParserExtra<'src, I>> Clone for Boxed<'src, '_, I, O, E> {
Expand All @@ -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
Expand Down Expand Up @@ -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<u64>> {
Arc::new(
any()
.filter(|c: &char| c.is_ascii_digit())
.repeated()
.at_least(1)
.at_most(3)
.to_slice()
.map(|b: &str| b.parse::<u64>().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<u64>> {
Expand Down
6 changes: 3 additions & 3 deletions src/pratt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -307,7 +307,7 @@ where
}

/// A boxed pratt parser operator. See [`Operator`].
pub struct Boxed<'src, 'a, I, O, E>(RefC<sync::DynOperator<'src, 'a, I, O, E>>);
pub struct Boxed<'src, 'a, I, O, E>(Rc<DynOperator<'src, 'a, I, O, E>>);

impl<I, O, E> Clone for Boxed<'_, '_, I, O, E> {
fn clone(&self) -> Self {
Expand Down
4 changes: 2 additions & 2 deletions src/recovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!
Expand Down
41 changes: 8 additions & 33 deletions src/recursive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
use super::*;

#[cfg(not(feature = "sync"))]
struct OnceCell<T>(core::cell::Cell<Option<T>>);
#[cfg(not(feature = "sync"))]
impl<T> OnceCell<T> {
pub fn new() -> Self {
Self(core::cell::Cell::new(None))
Expand All @@ -37,33 +35,10 @@ impl<T> OnceCell<T> {
}
}

#[cfg(feature = "sync")]
struct OnceCell<T>(spin::once::Once<T>);
#[cfg(feature = "sync")]
impl<T> OnceCell<T> {
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<T: ?Sized> {
Owned(RefC<T>),
Unowned(RefW<T>),
Owned(Rc<T>),
Unowned(rc::Weak<T>),
}

/// Type for recursive parsers that are defined through a call to `recursive`, and as such
Expand Down Expand Up @@ -125,7 +100,7 @@ impl<'src, 'b, I: Input<'src>, O, E: ParserExtra<'src, I>> Recursive<Indirect<'s
/// ```
pub fn declare() -> Self {
Recursive {
inner: RecursiveInner::Owned(RefC::new(Indirect {
inner: RecursiveInner::Owned(Rc::new(Indirect {
inner: OnceCell::new(),
})),
}
Expand All @@ -134,7 +109,7 @@ impl<'src, 'b, I: Input<'src>, O, E: ParserExtra<'src, I>> Recursive<Indirect<'s
/// Defines the parser after declaring it, allowing it to be used for parsing.
// INFO: Clone bound not actually needed, but good to be safe for future compat
#[track_caller]
pub fn define<P: Parser<'src, I, O, E> + Clone + MaybeSync + 'src + 'b>(&mut self, parser: P) {
pub fn define<P: Parser<'src, I, O, E> + Clone + 'src + 'b>(&mut self, parser: P) {
let location = *Location::caller();
self.parser()
.inner
Expand All @@ -147,7 +122,7 @@ impl<'src, 'b, I: Input<'src>, O, E: ParserExtra<'src, I>> Recursive<Indirect<'s

impl<P: ?Sized> Recursive<P> {
#[inline]
fn parser(&self) -> RefC<P> {
fn parser(&self) -> Rc<P> {
match &self.inner {
RecursiveInner::Owned(x) => x.clone(),
RecursiveInner::Unowned(x) => x
Expand Down Expand Up @@ -268,11 +243,11 @@ pub fn recursive<'src, 'b, I, O, E, A, F>(f: F) -> Recursive<Direct<'src, 'b, I,
where
I: Input<'src>,
E: ParserExtra<'src, I>,
A: Parser<'src, I, O, E> + Clone + MaybeSync + 'b,
A: Parser<'src, I, O, E> + Clone + 'b,
F: FnOnce(Recursive<Direct<'src, 'b, I, O, E>>) -> A,
{
let rc = RefC::new_cyclic(|rc| {
let rc: RefW<DynParser<'src, 'b, I, O, E>> = rc.clone() as _;
let rc = Rc::new_cyclic(|rc| {
let rc: rc::Weak<DynParser<'src, 'b, I, O, E>> = rc.clone() as _;
let parser = Recursive {
inner: RecursiveInner::Unowned(rc.clone()),
};
Expand Down
2 changes: 0 additions & 2 deletions src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<T, &'a mut T>;

Expand Down

0 comments on commit c7acd96

Please sign in to comment.