1use std::borrow::Cow;
10#[cfg(test)]
11use std::ops::Range;
12
13use serde::{Deserialize, Serialize, Serializer};
14
15use crate::{AnalysisError, AnalysisResult};
16
17mod allocation;
18pub(crate) use allocation::{TermBoundary, TermBuffer};
19
20#[derive(Clone)]
21enum Characters<'a> {
22 Unicode(std::str::Chars<'a>),
23 UTF16(std::char::DecodeUtf16<std::iter::Copied<std::slice::Iter<'a, u16>>>),
24}
25
26impl Iterator for Characters<'_> {
27 type Item = Result<char, u16>;
28
29 fn next(&mut self) -> Option<Self::Item> {
30 match self {
31 Self::Unicode(characters) => characters.next().map(Ok),
32 Self::UTF16(characters) => characters
33 .next()
34 .map(|value| value.map_err(|error| error.unpaired_surrogate())),
35 }
36 }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40enum Representation {
41 Unicode(String),
42 UTF16(Vec<u16>),
43}
44
45#[derive(Clone)]
46enum UTF16Units<'a> {
47 Unicode(std::str::EncodeUtf16<'a>),
48 Raw(std::iter::Copied<std::slice::Iter<'a, u16>>),
49}
50
51impl Iterator for UTF16Units<'_> {
52 type Item = u16;
53 fn next(&mut self) -> Option<u16> {
54 match self {
55 Self::Unicode(units) => units.next(),
56 Self::Raw(units) => units.next(),
57 }
58 }
59 fn size_hint(&self) -> (usize, Option<usize>) {
60 match self {
61 Self::Unicode(units) => units.size_hint(),
62 Self::Raw(units) => units.size_hint(),
63 }
64 }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Hash)]
79pub struct TokenTerm(Representation);
80
81impl TokenTerm {
82 pub(crate) fn characters(&self) -> impl Iterator<Item = Result<char, u16>> + Clone + '_ {
83 match &self.0 {
84 Representation::Unicode(text) => Characters::Unicode(text.chars()),
85 Representation::UTF16(units) => {
86 Characters::UTF16(char::decode_utf16(units.iter().copied()))
87 }
88 }
89 }
90
91 pub fn from_utf16(units: Vec<u16>) -> Self {
92 match String::from_utf16(&units) {
93 Ok(text) => Self::from(text),
94 Err(_) => Self(Representation::UTF16(units)),
95 }
96 }
97
98 pub fn as_str(&self) -> Option<&str> {
99 match &self.0 {
100 Representation::Unicode(text) => Some(text),
101 Representation::UTF16(_) => None,
102 }
103 }
104
105 pub fn utf16(&self) -> Cow<'_, [u16]> {
106 match &self.0 {
107 Representation::Unicode(_) => Cow::Owned(self.utf16_units().collect()),
108 Representation::UTF16(units) => Cow::Borrowed(units),
109 }
110 }
111
112 pub(crate) fn utf16_units(&self) -> impl Iterator<Item = u16> + Clone + '_ {
113 match &self.0 {
114 Representation::Unicode(text) => UTF16Units::Unicode(text.encode_utf16()),
115 Representation::UTF16(units) => UTF16Units::Raw(units.iter().copied()),
116 }
117 }
118
119 pub fn into_utf16(self) -> Vec<u16> {
120 match self.0 {
121 Representation::Unicode(text) => text.encode_utf16().collect(),
122 Representation::UTF16(units) => units,
123 }
124 }
125
126 pub fn into_string(self) -> AnalysisResult<String> {
128 match self.0 {
129 Representation::Unicode(text) => Ok(text),
130 Representation::UTF16(units) => {
131 let unit = char::decode_utf16(units)
132 .find_map(Result::err)
133 .expect("non-scalar representation")
134 .unpaired_surrogate();
135 Err(AnalysisError::UnpairedTokenSurrogate { unit })
136 }
137 }
138 }
139
140 pub fn character_count(&self) -> usize {
142 match &self.0 {
143 Representation::Unicode(text) => text.chars().count(),
144 Representation::UTF16(units) => char::decode_utf16(units.iter().copied()).count(),
145 }
146 }
147
148 pub fn utf16_len(&self) -> usize {
149 match &self.0 {
150 Representation::Unicode(text) => text.encode_utf16().count(),
151 Representation::UTF16(units) => units.len(),
152 }
153 }
154
155 #[cfg(test)]
156 pub(crate) fn map_unicode(&self, transform: impl Fn(&str) -> String) -> Self {
157 if let Some(text) = self.as_str() {
158 return Self::from(transform(text));
159 }
160 let mut output = Vec::new();
161 let mut text = String::new();
162 for character in char::decode_utf16(self.utf16().iter().copied()) {
163 match character {
164 Ok(character) => text.push(character),
165 Err(error) => {
166 output.extend(transform(&text).encode_utf16());
167 text.clear();
168 output.push(error.unpaired_surrogate());
169 }
170 }
171 }
172 output.extend(transform(&text).encode_utf16());
173 Self::from_utf16(output)
174 }
175
176 #[cfg(test)]
177 pub(crate) fn boundaries(&self) -> Vec<usize> {
178 match &self.0 {
179 Representation::Unicode(text) => text
180 .char_indices()
181 .map(|(offset, _)| offset)
182 .chain(std::iter::once(text.len()))
183 .collect(),
184 Representation::UTF16(units) => {
185 let mut boundaries = vec![0];
186 let mut offset = 0;
187 for character in char::decode_utf16(units.iter().copied()) {
188 offset += character.map_or(1, char::len_utf16);
189 boundaries.push(offset);
190 }
191 boundaries
192 }
193 }
194 }
195
196 #[cfg(test)]
197 pub(crate) fn substring(&self, range: Range<usize>) -> Self {
198 match &self.0 {
199 Representation::Unicode(text) => Self::from(text[range].to_owned()),
200 Representation::UTF16(units) => Self::from_utf16(units[range].to_vec()),
201 }
202 }
203}
204
205impl From<String> for TokenTerm {
206 fn from(value: String) -> Self {
207 Self(Representation::Unicode(value))
208 }
209}
210
211impl From<&str> for TokenTerm {
212 fn from(value: &str) -> Self {
213 Self::from(value.to_owned())
214 }
215}
216
217impl PartialEq<str> for TokenTerm {
218 fn eq(&self, other: &str) -> bool {
219 self.as_str() == Some(other)
220 }
221}
222
223impl PartialEq<&str> for TokenTerm {
224 fn eq(&self, other: &&str) -> bool {
225 self == *other
226 }
227}
228
229#[derive(Serialize, Deserialize)]
230#[serde(deny_unknown_fields)]
231struct RawUnits {
232 utf16: Vec<u16>,
233}
234
235impl Serialize for TokenTerm {
236 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
237 match &self.0 {
238 Representation::Unicode(text) => text.serialize(serializer),
239 Representation::UTF16(units) => {
240 use serde::ser::SerializeStruct;
241 let mut value = serializer.serialize_struct("RawUnits", 1)?;
242 value.serialize_field("utf16", units)?;
243 value.end()
244 }
245 }
246 }
247}
248
249impl<'de> Deserialize<'de> for TokenTerm {
250 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
251 #[derive(Deserialize)]
252 #[serde(untagged)]
253 enum Value {
254 Unicode(String),
255 UTF16(RawUnits),
256 }
257 Ok(match Value::deserialize(deserializer)? {
258 Value::Unicode(text) => Self::from(text),
259 Value::UTF16(raw) => Self::from_utf16(raw.utf16),
260 })
261 }
262}