unsynn/
predicates.rs

1//! Parse predicates for compile-time parser control.
2//!
3//! This module provides zero-cost abstractions for controlling parser behavior at compile time.
4//! All predicate types are zero-sized and have no runtime overhead.
5//!
6//! # Base Values
7//!
8//! - [`Enable`] - Always succeeds without consuming tokens
9//! - [`Disable`] - Always fails without consuming tokens
10//! - [`TokensRemain`] - Succeeds only when tokens remain in the stream
11//!
12//! # Logical Operators
13//!
14//! - [`AllOf`] - Logical AND (all must succeed, 2-4 operands)
15//! - [`AnyOf`] - Logical OR (at least one must succeed, 2-4 operands)
16//! - [`OneOf`] - Logical XOR (exactly one must succeed, 2-4 operands)
17//! - [`Not`] - Logical NOT (succeeds if inner fails)
18//!
19//! # Example
20//!
21//! The `predicateflag` macro creates newtype wrappers that can implement custom traits for
22//! compile-time context validation:
23//!
24//! ```rust
25//! use unsynn::*;
26//! use unsynn::predicates::*;
27//!
28//!
29//! unsynn! {
30//!    // Define a custom context predicate marker-trait
31//!     trait ExpressionContext: PredicateOp;
32//!
33//!     // Creates newtype implementing ExpressionContext
34//!     predicateflag InExpression = Enable for ExpressionContext;
35//!
36//!     // Only accepts ExpressionContext predicates
37//!     struct StructLiteral<P: ExpressionContext> {
38//!         _guard: P,
39//!         name: Ident,
40//!     }
41//! }
42//! ```
43//!
44//! See the **[Parse Predicates]** chapter in the Cookbook for detailed usage examples.
45//!
46//! [Parse Predicates]: https://docs.rs/unsynn/latest/unsynn/#parse-predicates
47
48use crate::{
49    Cons, Either, Error, Except, Expect, Parse, Parser, Result, ToTokens, TokenIter, TokenStream,
50    TokenTree,
51};
52use std::any::TypeId;
53use std::marker::PhantomData;
54
55/// Marker trait for compile-time parser predicates.
56///
57/// All predicate types are zero-sized with no runtime cost.
58/// The `'static` bound is required for type identity checking with [`PredicateCmp`].
59pub trait PredicateOp: Parser + ToTokens + Clone + 'static {}
60
61// =============================================================================
62// BASE VALUES
63// =============================================================================
64
65/// Always succeeds without consuming tokens.
66///
67/// # Examples
68///
69/// ```rust
70/// use unsynn::*;
71///
72/// let mut tokens = "foo bar".to_token_iter();
73/// let result = Enable::parse(&mut tokens);
74/// assert!(result.is_ok());
75/// assert_eq!(tokens.clone().count(), 2); // No tokens consumed
76/// ```
77#[derive(Debug, Clone, Default)]
78pub struct Enable;
79
80impl Parser for Enable {
81    #[inline]
82    #[mutants::skip] // Mutant Ok(Default::default()) is equivalent since Enable: Default
83    fn parser(_tokens: &mut TokenIter) -> Result<Self> {
84        Ok(Enable)
85    }
86}
87
88impl ToTokens for Enable {
89    #[inline]
90    fn to_tokens(&self, _tokens: &mut TokenStream) {}
91}
92
93impl PredicateOp for Enable {}
94
95/// Always fails without consuming tokens.
96///
97/// Note: Does not implement [`Default`].
98///
99/// # Examples
100///
101/// ```rust
102/// use unsynn::*;
103///
104/// let mut tokens = "foo bar".to_token_iter();
105/// let result = Disable::parse(&mut tokens);
106/// assert!(result.is_err());
107/// ```
108#[derive(Debug, Clone)]
109pub struct Disable;
110
111impl Parser for Disable {
112    #[inline]
113    fn parser(tokens: &mut TokenIter) -> Result<Self> {
114        Error::unexpected_token(None, tokens)
115    }
116}
117
118impl ToTokens for Disable {
119    #[inline]
120    fn to_tokens(&self, _tokens: &mut TokenStream) {}
121}
122
123impl PredicateOp for Disable {}
124
125/// Succeeds only when tokens remain in the stream.
126///
127/// # Examples
128///
129/// ```rust
130/// use unsynn::*;
131/// use unsynn::predicates::*;
132///
133/// let mut tokens = "foo".to_token_iter();
134/// assert!(TokensRemain::parse(&mut tokens).is_ok());
135///
136/// let mut empty = "".to_token_iter();
137/// assert!(TokensRemain::parse(&mut empty).is_err());
138/// ```
139#[derive(Debug, Clone)]
140pub struct TokensRemain;
141
142impl Parser for TokensRemain {
143    #[inline]
144    fn parser(tokens: &mut TokenIter) -> Result<Self> {
145        Expect::<TokenTree>::parse(tokens)?;
146        Ok(TokensRemain)
147    }
148}
149
150impl ToTokens for TokensRemain {
151    #[inline]
152    fn to_tokens(&self, _tokens: &mut TokenStream) {}
153}
154
155impl Default for TokensRemain {
156    #[inline]
157    fn default() -> Self {
158        TokensRemain
159    }
160}
161
162impl PredicateOp for TokensRemain {}
163
164// =============================================================================
165// LOGICAL NOT
166// =============================================================================
167
168/// Logical NOT: succeeds if inner predicate fails.
169///
170/// # Examples
171///
172/// ```rust
173/// use unsynn::*;
174///
175/// let mut tokens = "".to_token_iter();
176/// assert!(Not::<Disable>::parse(&mut tokens).is_ok());
177/// assert!(Not::<Enable>::parse(&mut tokens).is_err());
178/// ```
179#[derive(Debug, Clone)]
180pub struct Not<T: PredicateOp>(Except<T>);
181
182impl<T: PredicateOp> Parser for Not<T> {
183    #[inline]
184    fn parser(tokens: &mut TokenIter) -> Result<Self> {
185        Except::<T>::parse(tokens).map(Not)
186    }
187}
188
189impl<T: PredicateOp> ToTokens for Not<T> {
190    #[inline]
191    #[mutants::skip] // Inner type produces no tokens, so mutation to () is equivalent
192    fn to_tokens(&self, tokens: &mut TokenStream) {
193        self.0.to_tokens(tokens);
194    }
195}
196
197impl<T: PredicateOp> Default for Not<T>
198where
199    Except<T>: Default,
200{
201    #[inline]
202    fn default() -> Self {
203        Not(Except::default())
204    }
205}
206
207impl<T: PredicateOp> PredicateOp for Not<T> {}
208
209// =============================================================================
210// LOGICAL AND (2-4 operands)
211// =============================================================================
212
213/// Logical AND: 2-4 predicates must all succeed.
214///
215/// C and D default to [`Enable`] (always succeeds).
216///
217/// # Examples
218///
219/// ```rust
220/// use unsynn::*;
221///
222/// let mut tokens = "".to_token_iter();
223/// // Two predicates
224/// assert!(AllOf::<Enable, Enable>::parse(&mut tokens).is_ok());
225/// assert!(AllOf::<Enable, Disable>::parse(&mut tokens).is_err());
226/// // Four predicates
227/// assert!(AllOf::<Enable, Enable, Enable, Enable>::parse(&mut tokens).is_ok());
228/// ```
229#[derive(Debug, Clone)]
230pub struct AllOf<
231    A: PredicateOp,
232    B: PredicateOp,
233    C: PredicateOp + 'static = Enable,
234    D: PredicateOp + 'static = Enable,
235>(Cons<A, B, C, D>);
236
237impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> Parser for AllOf<A, B, C, D> {
238    #[inline]
239    fn parser(tokens: &mut TokenIter) -> Result<Self> {
240        Cons::<A, B, C, D>::parse(tokens).map(AllOf)
241    }
242}
243
244impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> ToTokens
245    for AllOf<A, B, C, D>
246{
247    #[inline]
248    #[mutants::skip] // Inner type produces no tokens, so mutation to () is equivalent
249    fn to_tokens(&self, tokens: &mut TokenStream) {
250        self.0.to_tokens(tokens);
251    }
252}
253
254impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> Default for AllOf<A, B, C, D>
255where
256    Cons<A, B, C, D>: Default,
257{
258    #[inline]
259    fn default() -> Self {
260        AllOf(Cons::default())
261    }
262}
263
264impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> PredicateOp
265    for AllOf<A, B, C, D>
266{
267}
268
269// =============================================================================
270// LOGICAL OR (2-4 operands)
271// =============================================================================
272
273/// Logical OR: 2-4 predicates, at least one must succeed.
274///
275/// C and D default to [`Disable`] (always fails).
276///
277/// # Examples
278///
279/// ```rust
280/// use unsynn::*;
281///
282/// let mut tokens = "".to_token_iter();
283/// // Two predicates
284/// assert!(AnyOf::<Enable, Disable>::parse(&mut tokens).is_ok());
285/// assert!(AnyOf::<Disable, Disable>::parse(&mut tokens).is_err());
286/// // Four predicates
287/// assert!(AnyOf::<Disable, Disable, Enable, Disable>::parse(&mut tokens).is_ok());
288/// ```
289#[derive(Debug, Clone)]
290pub struct AnyOf<
291    A: PredicateOp,
292    B: PredicateOp,
293    C: PredicateOp + 'static = Disable,
294    D: PredicateOp + 'static = Disable,
295>(Either<A, B, C, D>);
296
297impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> Parser for AnyOf<A, B, C, D> {
298    #[inline]
299    fn parser(tokens: &mut TokenIter) -> Result<Self> {
300        Either::<A, B, C, D>::parse(tokens).map(AnyOf)
301    }
302}
303
304impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> ToTokens
305    for AnyOf<A, B, C, D>
306{
307    #[inline]
308    #[mutants::skip] // Inner type produces no tokens, so mutation to () is equivalent
309    fn to_tokens(&self, tokens: &mut TokenStream) {
310        self.0.to_tokens(tokens);
311    }
312}
313
314impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> Default for AnyOf<A, B, C, D>
315where
316    Either<A, B, C, D>: Default,
317{
318    #[inline]
319    fn default() -> Self {
320        AnyOf(Either::default())
321    }
322}
323
324impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> PredicateOp
325    for AnyOf<A, B, C, D>
326{
327}
328
329// =============================================================================
330// LOGICAL XOR (2-4 operands)
331// =============================================================================
332
333/// Logical XOR: exactly one of 2-4 predicates must succeed.
334///
335/// C and D default to [`Disable`].
336///
337/// # Examples
338///
339/// ```rust
340/// use unsynn::*;
341///
342/// let mut tokens = "".to_token_iter();
343/// // Two predicates
344/// assert!(OneOf::<Enable, Disable>::parse(&mut tokens).is_ok());
345/// assert!(OneOf::<Enable, Enable>::parse(&mut tokens).is_err());
346/// // Four predicates
347/// assert!(OneOf::<Enable, Disable, Disable, Disable>::parse(&mut tokens).is_ok());
348/// assert!(OneOf::<Enable, Enable, Disable, Disable>::parse(&mut tokens).is_err());
349/// ```
350#[allow(clippy::type_complexity)]
351#[derive(Debug, Clone)]
352pub struct OneOf<
353    A: PredicateOp + 'static,
354    B: PredicateOp + 'static,
355    C: PredicateOp + 'static = Disable,
356    D: PredicateOp + 'static = Disable,
357>(
358    AnyOf<
359        AllOf<A, Not<B>, Not<C>, Not<D>>,
360        AllOf<Not<A>, B, Not<C>, Not<D>>,
361        AllOf<Not<A>, Not<B>, C, Not<D>>,
362        AllOf<Not<A>, Not<B>, Not<C>, D>,
363    >,
364);
365
366impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> Parser for OneOf<A, B, C, D> {
367    #[inline]
368    fn parser(tokens: &mut TokenIter) -> Result<Self> {
369        AnyOf::<
370            AllOf<A, Not<B>, Not<C>, Not<D>>,
371            AllOf<Not<A>, B, Not<C>, Not<D>>,
372            AllOf<Not<A>, Not<B>, C, Not<D>>,
373            AllOf<Not<A>, Not<B>, Not<C>, D>,
374        >::parse(tokens)
375        .map(OneOf)
376    }
377}
378
379impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> ToTokens
380    for OneOf<A, B, C, D>
381{
382    #[inline]
383    #[mutants::skip] // Inner type produces no tokens, so mutation to () is equivalent
384    fn to_tokens(&self, tokens: &mut TokenStream) {
385        self.0.to_tokens(tokens);
386    }
387}
388
389impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> Default for OneOf<A, B, C, D>
390where
391    AnyOf<
392        AllOf<A, Not<B>, Not<C>, Not<D>>,
393        AllOf<Not<A>, B, Not<C>, Not<D>>,
394        AllOf<Not<A>, Not<B>, C, Not<D>>,
395        AllOf<Not<A>, Not<B>, Not<C>, D>,
396    >: Default,
397{
398    #[inline]
399    fn default() -> Self {
400        OneOf(AnyOf::default())
401    }
402}
403
404impl<A: PredicateOp, B: PredicateOp, C: PredicateOp, D: PredicateOp> PredicateOp
405    for OneOf<A, B, C, D>
406{
407}
408
409// =============================================================================
410// TYPE IDENTITY CHECKING
411// =============================================================================
412
413/// Predicate that compares type `A` with type `B` at runtime.
414///
415/// Acts like `Same` when `A == B` (=[`Enable`]), and `Different`when `A != B` (=[`Disable`]).
416/// This enables distinguishing between different predicate flags at compile time through
417/// runtime type checks (which are usually optimized away by the compiler).
418///
419/// # Examples
420///
421/// ```rust
422/// use unsynn::*;
423/// //use unsynn::predicates::*;
424///
425/// unsynn! {
426///     predicatetrait Context;
427///     predicateflag InExpr for Context;
428///     predicateflag InStmt for Context;
429///
430///     // Only accepts InExpr, rejects InStmt
431///     struct OnlyInExpr<C: Context> {
432///         _guard: PredicateCmp<C, InExpr>,
433///         content: Ident,
434///     }
435///
436///     // Accepts InExpr but NOT InStmt
437///     struct ExprButNotStmt<C: Context> {
438///         _guard: AllOf<PredicateCmp<C, InExpr>, Not<PredicateCmp<C, InStmt>>>,
439///         content: Ident,
440///     }
441/// }
442/// ```
443#[derive(Debug)]
444pub struct PredicateCmp<
445    A: PredicateOp,
446    B: PredicateOp,
447    Same: PredicateOp = Enable,
448    Different: PredicateOp = Disable,
449>(PhantomData<(A, B, Same, Different)>);
450
451impl<A: PredicateOp, B: PredicateOp, Same: PredicateOp, Different: PredicateOp> PredicateOp
452    for PredicateCmp<A, B, Same, Different>
453{
454}
455
456impl<A: PredicateOp, B: PredicateOp, Same: PredicateOp, Different: PredicateOp>
457    PredicateCmp<A, B, Same, Different>
458{
459    /// Create a new `PredicateCmp` instance.
460    ///
461    /// This is primarily useful for testing or when you need to manually
462    /// construct the predicate.
463    #[inline]
464    #[must_use]
465    pub const fn new() -> Self {
466        PredicateCmp(PhantomData)
467    }
468}
469
470// Manual Clone impl to avoid requiring A: Clone, B: Clone bounds on type parameters.
471// We implement Clone explicitly even though PredicateCmp is Copy because the type
472// parameters A and B don't need to be Clone - they're only used in PhantomData.
473#[mutants::skip]
474#[allow(clippy::expl_impl_clone_on_copy)]
475impl<A: PredicateOp, B: PredicateOp, Same: PredicateOp, Different: PredicateOp> Clone
476    for PredicateCmp<A, B, Same, Different>
477{
478    fn clone(&self) -> Self {
479        *self
480    }
481}
482
483impl<A: PredicateOp, B: PredicateOp, Same: PredicateOp, Different: PredicateOp> Copy
484    for PredicateCmp<A, B, Same, Different>
485{
486}
487
488impl<A: PredicateOp, B: PredicateOp, Same: PredicateOp, Different: PredicateOp> Parser
489    for PredicateCmp<A, B, Same, Different>
490{
491    #[inline]
492    fn parser(tokens: &mut TokenIter) -> Result<Self> {
493        // Check type equality at compile/runtime
494        if TypeId::of::<A>() == TypeId::of::<B>() {
495            // Types match
496            Same::parse(tokens)?;
497        } else {
498            // Types don't match
499            Different::parse(tokens)?;
500        }
501        Ok(Self(PhantomData))
502    }
503}
504
505impl<A: PredicateOp, B: PredicateOp, Same: PredicateOp, Different: PredicateOp> ToTokens
506    for PredicateCmp<A, B, Same, Different>
507{
508    #[inline]
509    fn to_tokens(&self, _tokens: &mut TokenStream) {
510        // Zero-sized, emits nothing
511    }
512}
513
514impl<A: PredicateOp, B: PredicateOp, Same: PredicateOp, Different: PredicateOp> Default
515    for PredicateCmp<A, B, Same, Different>
516{
517    #[inline]
518    fn default() -> Self {
519        // Check at const time if possible, otherwise runtime
520        if TypeId::of::<A>() == TypeId::of::<B>() {
521            PredicateCmp(PhantomData)
522        } else {
523            // This will panic if called with mismatched types
524            // But it's safe because Default should only be called when it's valid
525            panic!("PredicateCmp::default() called with mismatched types")
526        }
527    }
528}