1use core::fmt::{self, Display, Formatter};
12
13use crate::join::Separator;
14
15#[derive(Debug, Clone, Copy, Default)]
35#[must_use]
36pub struct NoSeparator;
37
38impl Display for NoSeparator {
39 #[inline(always)]
40 fn fmt(&self, _f: &mut Formatter) -> fmt::Result {
41 Ok(())
42 }
43}
44
45impl Separator for NoSeparator {}
46
47#[cfg(feature = "token-stream")]
48impl quote::ToTokens for NoSeparator {
49 fn to_tokens(&self, _tokens: &mut proc_macro2::TokenStream) {}
50}
51
52#[cfg(test)]
53#[test]
54fn test_no_separator() {
55 use crate::join::Joinable;
56 use crate::separators::NoSeparator;
57
58 let data = [1, 2, 3, 4, 5];
59 let join = data.join_with(NoSeparator);
60 let result = join.to_string();
61
62 assert_eq!(result, "12345");
63}
64
65macro_rules! const_separator {
66 ($($Name:ident(sep: $sep:expr, repr: $repr:expr, test: $test_name:ident $(, token: $($token:tt)?)? ))+) => {$(
67 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
68 #[must_use]
69 #[doc = "Zero size type representing the "]
70 #[doc = $repr]
71 #[doc = " separator."]
72 pub struct $Name;
73
74 impl Display for $Name {
75 #[inline]
76 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
77 $sep.fmt(f)
78 }
79 }
80
81 impl Separator for $Name {}
82
83 $(
84 #[cfg(feature="token-stream")]
85 impl quote::ToTokens for $Name {
86 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
87 $(
88 tokens.extend(token!($token));
89 )?
90 let _tokens = tokens;
91 }
92 }
93 )?
94
95 #[cfg(test)]
96 mod $test_name {
97 use crate::separators::$Name;
98 use crate::join::Joinable;
99
100 #[test]
101 fn separator() {
102 let data = [1, 2, 3];
103 let join = data.join_with($Name);
104 let result = join.to_string();
105
106 assert_eq!(result, concat!(1, $sep, 2, $sep, 3));
107 }
108
109 $(
110 #[cfg(feature="token-stream")]
111 #[test]
112 fn to_tokens() {
113 use quote::{ToTokens, quote};
114
115 let data = [1, 2, 3];
116 let join = data.join_with($Name);
117 let result = join.into_token_stream();
118
119 let target = quote! {
120 1i32 $($token)? 2i32 $($token)? 3i32
121 };
122
123 assert_eq!(result.to_string(), target.to_string());
124 }
125 )?
126 }
127 )+}
128}
129
130#[cfg(feature = "token-stream")]
131macro_rules! token {
132 (.) => { token!(token '.') };
133 (,) => { token!(token ',') };
134 (/) => { token!(token '/') };
135 (-) => { token!(token '-') };
136
137 (token $token:literal) => {
138 [proc_macro2::TokenTree::Punct(proc_macro2::Punct::new(
139 $token,
140 proc_macro2::Spacing::Alone,
141 ))]
142 };
143}
144
145const_separator! {
146 Newline(sep: '\n', repr: "newline", test: test_newline, token: )
147 Space(sep: ' ', repr:"space", test: test_space, token: )
148 Comma(sep: ',', repr: "`,`", test: test_comma, token: ,)
149 CommaSpace(sep: ", ", repr: "comma followed by space", test: test_comma_space, token: ,)
150 Dot(sep: '.', repr: "`.`", test: test_dot, token: .)
151 Slash(sep: '/', repr: "`/`", test: test_slash, token: /)
152 Underscore(sep: '_', repr: "`_`", test: test_underscore)
153 Dash(sep: '-', repr: "`-`", test: test_dash, token: -)
154 Tab(sep: '\t', repr: "tab", test: test_tab, token: )
155}