tex_engine/tex/
characters.rs1use crate::tex::catcodes::{CategoryCode, CategoryCodeScheme};
3use std::fmt::{Debug, Display};
4
5pub trait Character:
8 Sized
9 + Eq
10 + Copy
11 + Display
12 + Debug
13 + From<u8>
14 + TryInto<u8>
15 + TryFrom<u64>
16 + Into<u64>
17 + Ord
18 + std::hash::Hash
19 + Default
20 + 'static
21{
22 type CharMap<A: Clone + Default>: CharacterMap<Self, A>;
24 type Iter<'a>: ExactSizeIterator<Item = Self>;
26 const MIN: Self;
28 const MAX: Self;
30 fn convert(input: Vec<u8>) -> TextLine<Self>;
32
33 fn slice_from_str<R>(s: &str, then: impl FnOnce(&[Self]) -> R) -> R;
34
35 fn display_fmt<W: std::fmt::Write>(&self, target: &mut W);
38
39 fn display(&self) -> DisplayableCharacter<Self> {
43 DisplayableCharacter(*self)
44 }
45
46 fn to_char(&self) -> char;
48
49 fn display_opt(c: Option<Self>) -> DisplayableCharacterOpt<Self> {
53 DisplayableCharacterOpt(c)
54 }
55 fn starting_catcode_scheme() -> CategoryCodeScheme<Self>;
57
58 fn string_to_iter(string: &str) -> Self::Iter<'_>;
60}
61
62pub struct DisplayableCharacter<C: Character>(C);
64impl<C: Character> Display for DisplayableCharacter<C> {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 self.0.display_fmt(f);
67 Ok(())
68 }
69}
70
71pub struct DisplayableCharacterOpt<C: Character>(Option<C>);
74impl<C: Character> Display for DisplayableCharacterOpt<C> {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 if let Some(c) = self.0 {
77 c.display_fmt(f)
78 }
79 Ok(())
80 }
81}
82
83pub trait CharacterMap<C: Character, A: Default>: Clone {
87 fn get(&self, c: C) -> &A;
88 fn get_mut(&mut self, c: C) -> &mut A;
89 fn default() -> Self;
90}
91
92impl Character for u8 {
93 type CharMap<A: Clone + Default> = [A; 256];
94 const MIN: Self = 0;
95 const MAX: Self = 255;
96
97 fn to_char(&self) -> char {
98 *self as char
99 }
100
101 type Iter<'a> = ByteIterator<'a>;
102
103 fn slice_from_str<R>(s: &str, then: impl FnOnce(&[Self]) -> R) -> R {
104 if s.contains("^^") {
105 then(&Self::string_to_iter(s).collect::<Vec<_>>())
106 } else {
107 then(s.as_bytes())
108 }
109 }
110
111 fn string_to_iter(string: &str) -> Self::Iter<'_> {
112 ByteIterator(string.as_bytes())
113 }
114
115 fn convert(input: Vec<u8>) -> TextLine<Self> {
116 input.into()
117 }
118
119 #[allow(unused_must_use)]
120 fn display_fmt<W: std::fmt::Write>(&self, target: &mut W) {
121 if self.is_ascii() {
122 target.write_char(*self as char);
123 } else if *self > 128 && (*self - 64).is_ascii() {
124 target.write_str("^^");
125 target.write_char((*self - 64) as char);
126 } else {
127 target.write_str(format!("^^{:x}", *self).as_str());
128 }
129 }
130
131 fn starting_catcode_scheme() -> [CategoryCode; 256] {
132 super::catcodes::STARTING_SCHEME_U8
133 }
134}
135
136pub struct ByteIterator<'a>(&'a [u8]);
139impl<'a> Iterator for ByteIterator<'a> {
140 type Item = u8;
141 fn next(&mut self) -> Option<Self::Item> {
142 if self.0.is_empty() {
143 None
144 } else if self.0.starts_with(b"^^") {
145 let b = self.0[2];
146 if b <= 60 || self.0.len() == 3 {
147 self.0 = &self.0[3..];
148 Some(b + 64)
149 } else {
150 let r =
151 u8::from_str_radix(std::str::from_utf8(&self.0[2..4]).unwrap(), 16).unwrap();
152 self.0 = &self.0[4..];
153 Some(r)
154 }
155 } else {
156 let b = self.0[0];
157 self.0 = &self.0[1..];
158 Some(b)
159 }
160 }
161}
162
163impl ExactSizeIterator for ByteIterator<'_> {
164 fn len(&self) -> usize {
165 let mut num = 0usize;
166 let mut iter = self.0.iter();
167 while let Some(b) = iter.next() {
168 if *b == b'^' {
169 if let Some(b'^') = iter.next() {
170 if let Some(b) = iter.next() {
171 if *b <= 60 {
172 num += 1;
173 } else {
174 iter.next();
175 num += 1;
176 }
177 } else {
178 num += 1;
179 }
180 } else {
181 num += 1;
182 }
183 } else {
184 num += 1;
185 }
186 }
187 num
188 }
189}
190
191impl<A: Clone + Default> CharacterMap<u8, A> for [A; 256] {
192 fn get(&self, c: u8) -> &A {
193 &self[c as usize]
194 }
195
196 fn get_mut(&mut self, c: u8) -> &mut A {
197 &mut self[c as usize]
198 }
199 fn default() -> Self {
200 array_init::array_init(|_| A::default())
201 }
202}
203
204pub type TextLine<C> = Box<[C]>;
206
207pub trait TextLineSource<C: Character> {
209 fn get_line(&mut self) -> Option<TextLine<C>>;
211}
212pub struct StringLineSource<C: Character> {
214 pub lines: std::vec::IntoIter<TextLine<C>>,
215}
216impl<C: Character> StringLineSource<C> {
217 pub fn make_lines<I: Iterator<Item = u8>>(iter: I) -> Vec<TextLine<C>> {
220 let mut lines = Vec::new();
221 let mut curr = Vec::new();
222 for b in iter {
223 if b == b'\n' {
224 if let Some(b'\r') = curr.last() {
225 curr.pop();
226 }
227 while let Some(b' ') = curr.last() {
228 curr.pop();
229 }
230 lines.push(C::convert(std::mem::take(&mut curr)));
231 } else {
232 curr.push(b);
233 }
234 }
235 if !curr.is_empty() {
236 lines.push(C::convert(curr));
237 }
238 lines
239 }
240}
241impl<C: Character> From<Vec<TextLine<C>>> for StringLineSource<C> {
242 fn from(lines: Vec<TextLine<C>>) -> Self {
243 Self {
244 lines: lines.into_iter(),
245 }
246 }
247}
248impl<C: Character> TextLineSource<C> for StringLineSource<C> {
249 fn get_line(&mut self) -> Option<TextLine<C>> {
250 self.lines.next()
251 }
252}
253impl<C: Character> From<&str> for StringLineSource<C> {
254 fn from(s: &str) -> Self {
255 Self::make_lines(s.as_bytes().iter().copied()).into()
256 }
257}
258impl<C: Character> From<String> for StringLineSource<C> {
259 fn from(s: String) -> Self {
260 Self::make_lines(s.into_bytes().into_iter()).into()
261 }
262}