1#![allow(clippy::module_name_repetitions)]
5
6pub use proc_macro2::Spacing;
7
8use crate::{Error, Parser, Punct, Result, ToTokens, TokenIter, TokenStream, TokenTree};
9
10#[derive(Default, Clone)]
12pub struct PunctAny<const C: char>;
13
14impl<const C: char> Parser for PunctAny<C> {
15 fn parser(tokens: &mut TokenIter) -> Result<Self> {
16 match tokens.next() {
17 Some(TokenTree::Punct(punct)) if punct.as_char() == C => Ok(Self),
18 _ => Error::unexpected_token(tokens),
19 }
20 }
21}
22
23impl<const C: char> ToTokens for PunctAny<C> {
24 fn to_tokens(&self, tokens: &mut TokenStream) {
25 Punct::new(C, Spacing::Alone).to_tokens(tokens);
26 }
27}
28
29impl<const C: char> From<PunctAny<C>> for TokenTree {
31 fn from(_: PunctAny<C>) -> Self {
32 TokenTree::Punct(Punct::new(C, Spacing::Alone))
33 }
34}
35
36#[mutants::skip]
37impl<const C: char> std::fmt::Debug for PunctAny<C> {
38 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39 write!(f, "PunctAny<{C:?}>")
40 }
41}
42
43#[derive(Default, Clone)]
65pub struct PunctJoint<const C: char>;
66
67impl<const C: char> PunctJoint<C> {
68 #[must_use]
70 pub const fn new() -> Self {
71 Self
72 }
73
74 #[must_use]
76 pub const fn as_char(&self) -> char {
77 C
78 }
79}
80
81impl<const C: char> Parser for PunctJoint<C> {
82 fn parser(tokens: &mut TokenIter) -> Result<Self> {
83 match tokens.next() {
84 Some(TokenTree::Punct(punct))
85 if punct.spacing() == Spacing::Joint && punct.as_char() == C =>
86 {
87 Ok(Self)
88 }
89 _ => Error::unexpected_token(tokens),
90 }
91 }
92}
93
94impl<const C: char> ToTokens for PunctJoint<C> {
95 fn to_tokens(&self, tokens: &mut TokenStream) {
96 Punct::new(C, Spacing::Joint).to_tokens(tokens);
97 }
98}
99
100#[mutants::skip]
101impl<const C: char> std::fmt::Debug for PunctJoint<C> {
102 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103 write!(f, "PunctJoint<{C:?}>")
104 }
105}
106
107impl<const C: char> From<PunctJoint<C>> for TokenTree {
109 fn from(_: PunctJoint<C>) -> Self {
110 TokenTree::Punct(Punct::new(C, Spacing::Joint))
111 }
112}
113
114#[test]
115fn test_joint_punct_into_tt() {
116 let mut token_iter = "+=".to_token_iter();
117 let plus = PunctJoint::<'+'>::parser(&mut token_iter).unwrap();
118 assert_eq!(plus.as_char(), '+');
119 let _: TokenTree = plus.into();
120}
121
122#[derive(Default, Clone)]
135pub struct PunctAlone<const C: char>;
136
137impl<const C: char> PunctAlone<C> {
138 #[must_use]
140 pub const fn new() -> Self {
141 Self
142 }
143
144 #[must_use]
146 pub const fn as_char(&self) -> char {
147 C
148 }
149}
150
151impl<const C: char> Parser for PunctAlone<C> {
152 fn parser(tokens: &mut TokenIter) -> Result<Self> {
153 match tokens.next() {
154 Some(TokenTree::Punct(punct))
155 if punct.spacing() == Spacing::Alone && punct.as_char() == C =>
156 {
157 Ok(Self)
158 }
159 _ => Error::unexpected_token(tokens),
160 }
161 }
162}
163
164impl<const C: char> ToTokens for PunctAlone<C> {
165 fn to_tokens(&self, tokens: &mut TokenStream) {
166 Punct::new(C, Spacing::Alone).to_tokens(tokens);
167 }
168}
169
170#[mutants::skip]
171impl<const C: char> std::fmt::Debug for PunctAlone<C> {
172 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
173 write!(f, "PunctAlone<{C:?}>")
174 }
175}
176
177impl<const C: char> From<PunctAlone<C>> for TokenTree {
179 fn from(_: PunctAlone<C>) -> Self {
180 TokenTree::Punct(Punct::new(C, Spacing::Alone))
181 }
182}
183
184#[test]
185fn test_alone_punct_into_tt() {
186 let mut token_iter = "+ +".to_token_iter();
187 let plus = PunctAlone::<'+'>::parser(&mut token_iter).unwrap();
188 assert_eq!(plus.as_char(), '+');
189 let _: TokenTree = plus.into();
190}