1#![no_std]
4
5use core::{fmt, fmt::Write, hash::Hash, iter::FusedIterator};
6
7pub use symbol_ty_macro::Symbol;
8
9#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Cons<const C: char, Tail>(Tail);
12
13#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
15pub struct Nil;
16
17pub trait Symbol: fmt::Display + fmt::Debug + Default + Eq + Ord + Copy + Sized + Hash {
19 type Chars: Iterator<Item = char>;
20
21 fn new() -> Self;
23
24 fn chars() -> Self::Chars;
26}
27
28impl Symbol for Nil {
29 type Chars = core::iter::Empty<char>;
30
31 #[inline(always)]
32 fn new() -> Self {
33 Self::new()
34 }
35
36 #[inline(always)]
37 fn chars() -> Self::Chars {
38 core::iter::empty()
39 }
40}
41
42impl<const C: char, Tail: Symbol> Symbol for Cons<C, Tail> {
43 type Chars = Chars<C, <Tail as Symbol>::Chars>;
44
45 fn new() -> Self {
46 Self(Tail::new())
47 }
48
49 fn chars() -> Self::Chars {
50 Chars {
51 used_c: false,
52 tail: Tail::chars(),
53 }
54 }
55}
56
57impl<const C: char, Tail: Symbol> Cons<C, Tail> {
58 #[inline(always)]
59 pub fn new() -> Self {
60 <Self as Symbol>::new()
61 }
62}
63
64impl Nil {
65 #[inline(always)]
66 pub const fn new() -> Self {
67 Self
68 }
69}
70
71impl<const C: char, Tail: Symbol> Default for Cons<C, Tail> {
72 #[inline(always)]
73 fn default() -> Self {
74 Self::new()
75 }
76}
77
78impl fmt::Display for Nil {
79 #[inline(always)]
80 fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
81 Ok(())
82 }
83}
84
85impl<const C: char, Tail: fmt::Display> fmt::Display for Cons<C, Tail> {
86 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87 f.write_char(C)?;
88 self.0.fmt(f)
89 }
90}
91
92impl<const C: char, Tail: fmt::Debug> fmt::Debug for Cons<C, Tail> {
93 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94 f.debug_tuple("Cons").field(&C).field(&self.0).finish()
95 }
96}
97
98#[derive(Clone, Copy, PartialEq, Eq, Hash)]
100#[must_use = "iterators are lazy and do nothing unless consumed"]
101pub struct Chars<const C: char, Tail> {
102 used_c: bool,
103 tail: Tail,
104}
105
106impl<const C: char, Tail: Iterator<Item = char>> Iterator for Chars<C, Tail> {
107 type Item = char;
108
109 fn next(&mut self) -> Option<Self::Item> {
110 if self.used_c {
111 self.tail.next()
112 } else {
113 self.used_c = true;
114 Some(C)
115 }
116 }
117
118 fn size_hint(&self) -> (usize, Option<usize>) {
119 let (lower, upper) = self.tail.size_hint();
120 if self.used_c {
121 return (lower, upper);
122 }
123 (
124 lower.saturating_add(1),
125 upper.and_then(|upper| upper.checked_add(1)),
126 )
127 }
128}
129
130impl<const C: char, Tail: DoubleEndedIterator<Item = char>> DoubleEndedIterator for Chars<C, Tail> {
131 fn next_back(&mut self) -> Option<Self::Item> {
132 if let Some(c) = self.tail.next_back() {
133 return Some(c);
134 }
135 if self.used_c {
136 None
137 } else {
138 self.used_c = true;
139 Some(C)
140 }
141 }
142}
143
144impl<const C: char, Tail: ExactSizeIterator<Item = char>> ExactSizeIterator for Chars<C, Tail> {
145 fn len(&self) -> usize {
146 let len = self.tail.len();
147 if self.used_c {
148 len
149 } else {
150 len.saturating_add(1)
151 }
152 }
153}
154
155impl<const C: char, Tail: FusedIterator<Item = char>> FusedIterator for Chars<C, Tail> {}
156
157#[cfg(test)]
158mod tests {
159 extern crate std;
160
161 use std::string::{String, ToString};
162
163 use insta::{assert_debug_snapshot, with_settings};
164
165 use super::Symbol;
166
167 macro_rules! insta_assert {
168 ($e:expr) => {
169 with_settings!({prepend_module_to_snapshot => false}, {
170 assert_debug_snapshot!($e);
171 });
172 };
173 }
174
175 #[test]
176 fn test_empty_symbol() {
177 insta_assert!(<Symbol!("")>::new());
178 }
179
180 #[test]
181 fn test_display() {
182 insta_assert!(<Symbol!("hello")>::new().to_string());
183 }
184
185 #[test]
186 fn test_debug() {
187 insta_assert!(<Symbol!("hello")>::new());
188 }
189
190 #[test]
191 fn test_iter() {
192 insta_assert!(<Symbol!("hello")>::chars().collect::<String>());
193 }
194
195 #[test]
196 fn test_iter_rev() {
197 insta_assert!(<Symbol!("hello")>::chars().rev().collect::<String>());
198 }
199
200 #[test]
201 fn test_fuse() {
202 let mut chars = <Symbol!("abc")>::chars();
203 assert_eq!(chars.next(), Some('a'));
204 assert_eq!(chars.next(), Some('b'));
205 assert_eq!(chars.next(), Some('c'));
206 assert_eq!(chars.next(), None);
207 assert_eq!(chars.next(), None);
208 assert_eq!(chars.next(), None);
209 }
210
211 #[test]
212 fn test_rev_fuse() {
213 let mut chars = <Symbol!("abc")>::chars().rev();
214 assert_eq!(chars.next(), Some('c'));
215 assert_eq!(chars.next(), Some('b'));
216 assert_eq!(chars.next(), Some('a'));
217 assert_eq!(chars.next(), None);
218 assert_eq!(chars.next(), None);
219 assert_eq!(chars.next(), None);
220 }
221}