1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
//! This is a very simple utility crate that provides a wrapper over `char`
//! values, `DecodedChar`, additionally storing the original byte length of the
//! character in the encoded source file.
//!
//! It also provides wrappers around `char` iterators to produce `DecodedChar`
//! iterators from UTF-8/16 encoded sources.
use std::borrow::Borrow;
use std::ops::Deref;

/// Decoded character.
///
/// A character and its original byte length in the encoded source file.
pub struct DecodedChar {
	/// Character.
	c: char,

	/// Byte length in the encoded source file.
	len: usize,
}

impl DecodedChar {
	/// Creates a new decoded character from its value, `c`,
	/// and its original byte length `len` in the encoded source file.
	#[inline(always)]
	pub fn new(c: char, len: usize) -> Self {
		Self { c, len }
	}

	/// Creates a new decoded character,
	/// decoded from an UTF-8 encoded source file.
	#[inline(always)]
	pub fn from_utf8(c: char) -> Self {
		Self {
			c,
			len: c.len_utf8(),
		}
	}

	/// Creates a new decoded character,
	/// decoded from an UTF-16 encoded source file.
	#[inline(always)]
	pub fn from_utf16(c: char) -> Self {
		Self {
			c,
			len: c.len_utf16(),
		}
	}

	/// Returns the character.
	#[inline(always)]
	pub fn chr(&self) -> char {
		self.c
	}

	/// Returns the original byte length of the character in the encoded source
	/// file.
	#[inline(always)]
	#[allow(clippy::len_without_is_empty)]
	pub fn len(&self) -> usize {
		self.len
	}

	/// Turns this `DecodedChar` into the underlying `char`.
	#[inline(always)]
	pub fn into_char(self) -> char {
		self.c
	}

	/// Turns this `DecodedChar` into the original byte length in the encoded
	/// source file.
	#[inline(always)]
	pub fn into_len(self) -> usize {
		self.len
	}
}

impl From<DecodedChar> for char {
	#[inline(always)]
	fn from(dc: DecodedChar) -> Self {
		dc.into_char()
	}
}

impl From<DecodedChar> for u32 {
	#[inline(always)]
	fn from(dc: DecodedChar) -> Self {
		dc.into_char().into()
	}
}

impl AsRef<char> for DecodedChar {
	#[inline(always)]
	fn as_ref(&self) -> &char {
		&self.c
	}
}

impl Borrow<char> for DecodedChar {
	#[inline(always)]
	fn borrow(&self) -> &char {
		&self.c
	}
}

impl Deref for DecodedChar {
	type Target = char;

	#[inline(always)]
	fn deref(&self) -> &char {
		&self.c
	}
}

/// Iterator wrapper around UTF-8 encoded sources.
pub struct Utf8Decoded<C>(pub C);

impl<C> Utf8Decoded<C> {
	#[inline(always)]
	pub fn new(chars: C) -> Self {
		Self(chars)
	}
}

impl<C: Iterator<Item = char>> Iterator for Utf8Decoded<C> {
	type Item = DecodedChar;

	#[inline(always)]
	fn next(&mut self) -> Option<Self::Item> {
		self.0.next().map(DecodedChar::from_utf8)
	}
}

/// Iterator wrapper around fallible UTF-8 encoded sources.
pub struct FallibleUtf8Decoded<C>(pub C);

impl<C> FallibleUtf8Decoded<C> {
	#[inline(always)]
	pub fn new(chars: C) -> Self {
		Self(chars)
	}
}

impl<E, C: Iterator<Item = Result<char, E>>> Iterator for FallibleUtf8Decoded<C> {
	type Item = Result<DecodedChar, E>;

	#[inline(always)]
	fn next(&mut self) -> Option<Self::Item> {
		self.0
			.next()
			.map(|result| result.map(DecodedChar::from_utf8))
	}
}

/// Iterator wrapper around UTF-16 encoded sources.
pub struct Utf16Decoded<C>(pub C);

impl<C> Utf16Decoded<C> {
	#[inline(always)]
	pub fn new(chars: C) -> Self {
		Self(chars)
	}
}

impl<C: Iterator<Item = char>> Iterator for Utf16Decoded<C> {
	type Item = DecodedChar;

	#[inline(always)]
	fn next(&mut self) -> Option<Self::Item> {
		self.0.next().map(DecodedChar::from_utf16)
	}
}

/// Iterator wrapper around fallible UTF-16 encoded sources.
pub struct FallibleUtf16Decoded<C>(pub C);

impl<C> FallibleUtf16Decoded<C> {
	#[inline(always)]
	pub fn new(chars: C) -> Self {
		Self(chars)
	}
}

impl<E, C: Iterator<Item = Result<char, E>>> Iterator for FallibleUtf16Decoded<C> {
	type Item = Result<DecodedChar, E>;

	#[inline(always)]
	fn next(&mut self) -> Option<Self::Item> {
		self.0
			.next()
			.map(|result| result.map(DecodedChar::from_utf16))
	}
}

/// Extension for `str` providing the `decoded_char` method.
pub trait DecodedChars {
	/// Returns an iterator over the UTF-8 decoded characters of the string,
	/// wrapped inside a `DecodedChar`.
	fn decoded_chars(&self) -> Utf8Decoded<std::str::Chars>;
}

impl DecodedChars for str {
	fn decoded_chars(&self) -> Utf8Decoded<std::str::Chars> {
		Utf8Decoded(self.chars())
	}
}