1#![allow(clippy::module_name_repetitions)]
5
6#[cfg(feature = "proc_macro2")]
7pub use proc_macro2::Spacing;
8
9#[cfg(not(feature = "proc_macro2"))]
10pub use proc_macro::Spacing;
11
12use crate::{Error, Parser, Punct, Result, ToTokens, TokenIter, TokenStream, TokenTree};
13
14#[derive(Default, Clone)]
16pub struct PunctAny<const C: char>;
17
18impl<const C: char> Parser for PunctAny<C> {
19 #[mutants::skip]
25 fn parser(tokens: &mut TokenIter) -> Result<Self> {
26 match tokens.next() {
27 Some(TokenTree::Punct(punct)) if punct.as_char() == C => Ok(Self),
28 at => Error::unexpected_token(at, tokens),
29 }
30 }
31}
32
33impl<const C: char> ToTokens for PunctAny<C> {
34 fn to_tokens(&self, tokens: &mut TokenStream) {
35 Punct::new(C, Spacing::Alone).to_tokens(tokens);
36 }
37}
38
39impl<const C: char> From<PunctAny<C>> for TokenTree {
41 fn from(_: PunctAny<C>) -> Self {
42 TokenTree::Punct(Punct::new(C, Spacing::Alone))
43 }
44}
45
46#[mutants::skip]
47impl<const C: char> std::fmt::Debug for PunctAny<C> {
48 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49 write!(f, "PunctAny<{C:?}>")
50 }
51}
52
53#[derive(Default, Clone)]
75pub struct PunctJoint<const C: char>;
76
77impl<const C: char> PunctJoint<C> {
78 #[must_use]
80 pub const fn new() -> Self {
81 Self
82 }
83
84 #[must_use]
86 pub const fn as_char(&self) -> char {
87 C
88 }
89}
90
91impl<const C: char> Parser for PunctJoint<C> {
92 fn parser(tokens: &mut TokenIter) -> Result<Self> {
93 match tokens.next() {
94 Some(TokenTree::Punct(punct))
95 if punct.spacing() == Spacing::Joint && punct.as_char() == C =>
96 {
97 Ok(Self)
98 }
99 at => Error::unexpected_token(at, tokens),
100 }
101 }
102}
103
104impl<const C: char> ToTokens for PunctJoint<C> {
105 fn to_tokens(&self, tokens: &mut TokenStream) {
106 Punct::new(C, Spacing::Joint).to_tokens(tokens);
107 }
108}
109
110#[mutants::skip]
111impl<const C: char> std::fmt::Debug for PunctJoint<C> {
112 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113 write!(f, "PunctJoint<{C:?}>")
114 }
115}
116
117impl<const C: char> From<PunctJoint<C>> for TokenTree {
119 fn from(_: PunctJoint<C>) -> Self {
120 TokenTree::Punct(Punct::new(C, Spacing::Joint))
121 }
122}
123
124#[test]
125fn test_joint_punct_into_tt() {
126 let mut token_iter = "+=".to_token_iter();
127 let plus = PunctJoint::<'+'>::parser(&mut token_iter).unwrap();
128 assert_eq!(plus.as_char(), '+');
129 let _: TokenTree = plus.into();
130}
131
132#[derive(Default, Clone)]
145pub struct PunctAlone<const C: char>;
146
147impl<const C: char> PunctAlone<C> {
148 #[must_use]
150 pub const fn new() -> Self {
151 Self
152 }
153
154 #[must_use]
156 pub const fn as_char(&self) -> char {
157 C
158 }
159}
160
161impl<const C: char> Parser for PunctAlone<C> {
162 fn parser(tokens: &mut TokenIter) -> Result<Self> {
163 match tokens.next() {
164 Some(TokenTree::Punct(punct))
165 if punct.spacing() == Spacing::Alone && punct.as_char() == C =>
166 {
167 Ok(Self)
168 }
169 at => Error::unexpected_token(at, tokens),
170 }
171 }
172}
173
174impl<const C: char> ToTokens for PunctAlone<C> {
175 fn to_tokens(&self, tokens: &mut TokenStream) {
176 Punct::new(C, Spacing::Alone).to_tokens(tokens);
177 }
178}
179
180#[mutants::skip]
181impl<const C: char> std::fmt::Debug for PunctAlone<C> {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 write!(f, "PunctAlone<{C:?}>")
184 }
185}
186
187impl<const C: char> From<PunctAlone<C>> for TokenTree {
189 fn from(_: PunctAlone<C>) -> Self {
190 TokenTree::Punct(Punct::new(C, Spacing::Alone))
191 }
192}
193
194#[test]
195fn test_alone_punct_into_tt() {
196 let mut token_iter = "+ +".to_token_iter();
197 let plus = PunctAlone::<'+'>::parser(&mut token_iter).unwrap();
198 assert_eq!(plus.as_char(), '+');
199 let _: TokenTree = plus.into();
200}