1#![no_std]
46#![forbid(
47 unsafe_code,
48 missing_docs,
49 missing_debug_implementations,
50 missing_copy_implementations,
51 future_incompatible,
52 rust_2018_idioms
53)]
54
55#[cfg(feature = "builder")]
56pub mod builder;
57
58#[cfg(all(feature = "builder", not(intern_str_no_alloc)))]
59extern crate alloc;
60#[cfg(all(feature = "builder", intern_str_no_alloc))]
61extern crate std as alloc;
62
63#[cfg(feature = "std")]
64extern crate std;
65
66#[cfg(feature = "builder")]
67use alloc::vec::Vec;
68
69use core::{cmp, hash, ops};
70
71#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub struct Node<'inst, Input, Output> {
74 inputs: MaybeSlice<'inst, (Input, usize)>,
79
80 output: Output,
82
83 default: usize,
85
86 amount: usize,
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
93pub struct Graph<'inst, 'nodes, Input, Output> {
94 nodes: &'nodes [Node<'inst, Input, Output>],
96
97 start: usize,
99}
100
101impl<'inst, Input, Output> Node<'inst, Input, Output> {
102 pub const fn new(
104 inputs: &'inst [(Input, usize)],
105 output: Output,
106 default: usize,
107 amount: usize,
108 ) -> Self {
109 Self {
110 inputs: MaybeSlice::Slice(inputs),
111 output,
112 default,
113 amount,
114 }
115 }
116}
117
118impl<'inst, Input: Segmentable, Output> Node<'inst, Input, Output> {
119 fn next(&self, input: &Input) -> usize {
121 match self.inputs.binary_search_by(|(i, _)| i.cmp(input)) {
123 Ok(i) => self.inputs[i].1,
124 Err(_) => self.default,
125 }
126 }
127
128 pub fn inputs(&self) -> &[(Input, usize)] {
130 match &self.inputs {
131 MaybeSlice::Slice(s) => s,
132 #[cfg(feature = "builder")]
133 MaybeSlice::Vec(v) => v,
134 }
135 }
136
137 pub fn output(&self) -> &Output {
139 &self.output
140 }
141
142 pub fn default(&self) -> usize {
144 self.default
145 }
146
147 pub fn amount(&self) -> usize {
149 self.amount
150 }
151}
152
153impl<'nodes, 'inst, Input, Output> Graph<'inst, 'nodes, Input, Output> {
154 pub const fn new(nodes: &'nodes [Node<'inst, Input, Output>], start: usize) -> Self {
156 Self { nodes, start }
157 }
158}
159
160impl<'nodes, 'inst, Input: Segmentable, Output> Graph<'inst, 'nodes, Input, Output> {
161 pub fn nodes(&self) -> &'nodes [Node<'inst, Input, Output>] {
163 self.nodes
164 }
165
166 pub fn start(&self) -> usize {
168 self.start
169 }
170
171 pub fn process(&self, mut input: Input) -> &Output {
173 let mut node = &self.nodes[self.start];
174
175 loop {
177 let (chunk, rest) = match input.split(node.amount) {
179 Some(result) => result,
180 None => {
181 return &node.output;
183 }
184 };
185
186 node = &self.nodes[node.next(&chunk)];
188 input = rest;
189 }
190 }
191}
192
193pub trait Segmentable: Ord + Sized {
195 fn split(self, at: usize) -> Option<(Self, Self)>;
197
198 fn len(&self) -> usize;
200
201 fn is_empty(&self) -> bool {
203 self.len() == 0
204 }
205}
206
207impl<'a> Segmentable for &'a str {
208 fn split(self, at: usize) -> Option<(Self, Self)> {
209 if at > self.len() {
210 return None;
211 }
212
213 let (left, right) = self.split_at(at);
214 Some((left, right))
215 }
216
217 fn len(&self) -> usize {
218 str::len(self)
219 }
220}
221
222impl<'a, T: Ord> Segmentable for &'a [T] {
223 fn split(self, at: usize) -> Option<(Self, Self)> {
224 if at > self.len() {
225 return None;
226 }
227
228 let (left, right) = self.split_at(at);
229 Some((left, right))
230 }
231
232 fn len(&self) -> usize {
233 <[T]>::len(self)
234 }
235}
236
237#[derive(Debug, Clone, Copy, Default)]
241pub struct CaseInsensitive<T>(pub T);
242
243impl<T> ops::Deref for CaseInsensitive<T> {
244 type Target = T;
245
246 fn deref(&self) -> &T {
247 &self.0
248 }
249}
250
251impl<T> ops::DerefMut for CaseInsensitive<T> {
252 fn deref_mut(&mut self) -> &mut T {
253 &mut self.0
254 }
255}
256
257impl<T> From<T> for CaseInsensitive<T> {
258 fn from(value: T) -> Self {
259 CaseInsensitive(value)
260 }
261}
262
263impl<T: AsRef<[u8]>> PartialEq for CaseInsensitive<T> {
264 fn eq(&self, other: &Self) -> bool {
265 self.0.as_ref().eq_ignore_ascii_case(other.0.as_ref())
266 }
267}
268
269impl<T: AsRef<[u8]>> Eq for CaseInsensitive<T> {}
270
271impl<T: AsRef<[u8]>> PartialOrd for CaseInsensitive<T> {
272 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
273 Some(self.cmp(other))
274 }
275}
276
277impl<T: AsRef<[u8]>> Ord for CaseInsensitive<T> {
278 fn cmp(&self, other: &Self) -> cmp::Ordering {
279 let this = self.0.as_ref();
280 let other = other.0.as_ref();
281 let common_len = cmp::min(this.len(), other.len());
282
283 let this_seg = &this[..common_len];
284 let other_seg = &other[..common_len];
285
286 for (a, b) in this_seg.iter().zip(other_seg.iter()) {
288 let a = a.to_ascii_lowercase();
289 let b = b.to_ascii_lowercase();
290
291 match a.cmp(&b) {
292 cmp::Ordering::Equal => continue,
293 other => return other,
294 }
295 }
296
297 this.len().cmp(&other.len())
299 }
300}
301
302impl<T: AsRef<[u8]>> hash::Hash for CaseInsensitive<T> {
303 fn hash<H: hash::Hasher>(&self, state: &mut H) {
304 for byte in self.0.as_ref() {
305 state.write_u8(byte.to_ascii_lowercase());
306 }
307 }
308}
309
310impl<T: Segmentable + AsRef<[u8]>> Segmentable for CaseInsensitive<T> {
311 fn split(self, at: usize) -> Option<(Self, Self)> {
312 T::split(self.0, at).map(|(left, right)| (left.into(), right.into()))
313 }
314
315 fn len(&self) -> usize {
316 T::len(&self.0)
317 }
318}
319
320#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
321enum MaybeSlice<'a, T> {
322 Slice(&'a [T]),
323 #[cfg(feature = "builder")]
324 Vec(Vec<T>),
325}
326
327impl<'a, T> core::ops::Deref for MaybeSlice<'a, T> {
328 type Target = [T];
329
330 fn deref(&self) -> &Self::Target {
331 match self {
332 MaybeSlice::Slice(slice) => slice,
333 #[cfg(feature = "builder")]
334 MaybeSlice::Vec(vec) => vec,
335 }
336 }
337}