#![allow(clippy::module_name_repetitions)]
#[cfg(feature = "proc_macro2")]
pub use proc_macro2::Spacing;
#[cfg(not(feature = "proc_macro2"))]
pub use proc_macro::Spacing;
use crate::{Error, Parser, Punct, Result, ToTokens, TokenIter, TokenStream, TokenTree};
#[derive(Default, Clone)]
pub struct PunctAny<const C: char>;
impl<const C: char> Parser for PunctAny<C> {
#[mutants::skip]
fn parser(tokens: &mut TokenIter) -> Result<Self> {
match tokens.next() {
Some(TokenTree::Punct(punct)) if punct.as_char() == C => Ok(Self),
at => Error::unexpected_token(at, tokens),
}
}
}
impl<const C: char> ToTokens for PunctAny<C> {
fn to_tokens(&self, tokens: &mut TokenStream) {
Punct::new(C, Spacing::Alone).to_tokens(tokens);
}
}
impl<const C: char> From<PunctAny<C>> for TokenTree {
fn from(_: PunctAny<C>) -> Self {
TokenTree::Punct(Punct::new(C, Spacing::Alone))
}
}
#[mutants::skip]
impl<const C: char> std::fmt::Debug for PunctAny<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "PunctAny<{C:?}>")
}
}
#[derive(Default, Clone)]
pub struct PunctJoint<const C: char>;
impl<const C: char> PunctJoint<C> {
#[must_use]
pub const fn new() -> Self {
Self
}
#[must_use]
pub const fn as_char(&self) -> char {
C
}
}
impl<const C: char> Parser for PunctJoint<C> {
fn parser(tokens: &mut TokenIter) -> Result<Self> {
match tokens.next() {
Some(TokenTree::Punct(punct))
if punct.spacing() == Spacing::Joint && punct.as_char() == C =>
{
Ok(Self)
}
at => Error::unexpected_token(at, tokens),
}
}
}
impl<const C: char> ToTokens for PunctJoint<C> {
fn to_tokens(&self, tokens: &mut TokenStream) {
Punct::new(C, Spacing::Joint).to_tokens(tokens);
}
}
#[mutants::skip]
impl<const C: char> std::fmt::Debug for PunctJoint<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "PunctJoint<{C:?}>")
}
}
impl<const C: char> From<PunctJoint<C>> for TokenTree {
fn from(_: PunctJoint<C>) -> Self {
TokenTree::Punct(Punct::new(C, Spacing::Joint))
}
}
#[test]
fn test_joint_punct_into_tt() {
let mut token_iter = "+=".to_token_iter();
let plus = PunctJoint::<'+'>::parser(&mut token_iter).unwrap();
assert_eq!(plus.as_char(), '+');
let _: TokenTree = plus.into();
}
#[derive(Default, Clone)]
pub struct PunctAlone<const C: char>;
impl<const C: char> PunctAlone<C> {
#[must_use]
pub const fn new() -> Self {
Self
}
#[must_use]
pub const fn as_char(&self) -> char {
C
}
}
impl<const C: char> Parser for PunctAlone<C> {
fn parser(tokens: &mut TokenIter) -> Result<Self> {
match tokens.next() {
Some(TokenTree::Punct(punct))
if punct.spacing() == Spacing::Alone && punct.as_char() == C =>
{
Ok(Self)
}
at => Error::unexpected_token(at, tokens),
}
}
}
impl<const C: char> ToTokens for PunctAlone<C> {
fn to_tokens(&self, tokens: &mut TokenStream) {
Punct::new(C, Spacing::Alone).to_tokens(tokens);
}
}
#[mutants::skip]
impl<const C: char> std::fmt::Debug for PunctAlone<C> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "PunctAlone<{C:?}>")
}
}
impl<const C: char> From<PunctAlone<C>> for TokenTree {
fn from(_: PunctAlone<C>) -> Self {
TokenTree::Punct(Punct::new(C, Spacing::Alone))
}
}
#[test]
fn test_alone_punct_into_tt() {
let mut token_iter = "+ +".to_token_iter();
let plus = PunctAlone::<'+'>::parser(&mut token_iter).unwrap();
assert_eq!(plus.as_char(), '+');
let _: TokenTree = plus.into();
}