1use crate::errors::ParserError;
2use crate::parsed::Parsed;
3use crate::prefix::Prefix;
4use std::collections::{HashMap, HashSet};
5use std::fmt::Debug;
6use std::marker::PhantomData;
7
8#[derive(Eq, PartialEq, Debug, Copy, Clone)]
20pub struct Tokenizer<'a, T: State> {
21 raw: &'a str,
22 state: PhantomData<T>,
23}
24
25pub trait State: PartialEq + Eq + Debug {}
26
27impl<'a, S: State> Tokenizer<'a, S> {
28 fn skip_until_char(&mut self, ch: char, skip_char: bool) {
29 if self.raw.starts_with(ch) {
30 return;
31 }
32
33 let end = self
34 .raw
35 .find(ch)
36 .map(|space_pos| if skip_char { space_pos + 1 } else { space_pos })
37 .unwrap_or_else(|| self.raw.len());
38 self.raw = &self.raw[end..];
39 }
40
41 fn skip_until_str(&mut self, s: &str) {
42 if self.raw.starts_with(s) {
43 return;
44 }
45
46 let end = self.raw.find(s).unwrap_or_else(|| self.raw.len());
47 self.raw = &self.raw[end..];
48 }
49
50 fn skip_to_end(&mut self) {
51 self.raw = &self.raw[self.raw.len()..];
52 }
53
54 fn skip_tags(&mut self) {
55 if self.raw.starts_with(&['@', ';'][..]) {
57 self.skip_until_char(' ', true);
58 }
59 }
60
61 fn skip_prefix(&mut self) {
62 self.skip_tags();
63 if self.raw.starts_with(&[':', '!', '@'][..]) {
64 self.skip_until_char(' ', true);
65 }
66 }
67
68 fn skip_command(&mut self) {
69 self.skip_prefix();
70 self.skip_until_char(' ', false);
71 }
72
73 fn skip_params(&mut self) {
74 self.skip_command();
75 self.skip_until_str(" :");
76 }
77}
78
79#[derive(Eq, PartialEq, Debug, Copy, Clone)]
80pub struct Start;
81
82impl State for Start {}
83
84impl<'a> Tokenizer<'a, Start> {
85 pub fn new(raw: &'a str) -> Result<Self, ParserError> {
86 if raw.is_empty() {
87 Err(ParserError::NoCommand)
88 } else {
89 Ok(Tokenizer {
90 raw,
91 state: PhantomData::default(),
92 })
93 }
94 }
95
96 pub fn parse_partial(self, mut cfg: PartialCfg<'a>) -> Result<Parsed<'a>, ParserError> {
97 let mut result_tags = HashMap::new();
98 let mut result_prefix = None;
99 let mut result_command = None;
100 let mut result_params = Vec::new();
101 let mut result_trailing = None;
102
103 let mut tokenizer = self.tags();
105 if !cfg.tags.is_empty() {
106 let mut tags = HashMap::with_capacity(cfg.tags.len());
107 let mut iter = tokenizer.as_iter();
108 while !cfg.tags.is_empty() {
109 match iter.next() {
110 Some(Ok((key, val))) => {
111 if cfg.tags.remove(&key) {
112 tags.insert(key, val);
113 }
114 }
115 Some(Err(why)) => return Err(why),
116 None => break,
117 }
118 }
119 result_tags = tags;
120 }
121
122 let mut tokenizer = tokenizer.prefix();
124 if let Some((user, host)) = cfg.prefix {
125 result_prefix = Some((
126 tokenizer.name()?.ok_or(ParserError::PrefixWithoutName)?,
127 if user { tokenizer.user()? } else { None },
128 if host { tokenizer.name()? } else { None },
129 ));
130 }
131
132 let mut tokenizer = tokenizer.command();
134 if cfg.command {
135 result_command = Some(tokenizer.command()?);
136 }
137
138 let mut tokenizer = tokenizer.params();
140 if !cfg.params.is_empty() {
141 let mut params = Vec::with_capacity(cfg.params.len());
142 let mut iter = tokenizer.as_iter();
143 cfg.params.dedup();
144 cfg.params.sort_unstable();
145 let mut position = 0;
146 for index in cfg.params {
147 let delta = index - position;
148 params.extend(vec![None; delta]);
150 position = index;
151 params.push(iter.nth(delta));
152 }
153 result_params = params;
154 }
155
156 let tokenizer = tokenizer.trailing();
158 if cfg.trailing {
159 result_trailing = tokenizer.trailing();
160 }
161
162 Ok(Parsed::new(
163 result_tags,
164 result_prefix,
165 result_command,
166 result_params,
167 result_trailing,
168 ))
169 }
170
171 pub fn tags(self) -> Tokenizer<'a, TagsState> {
172 Tokenizer {
173 raw: self.raw,
174 state: PhantomData::default(),
175 }
176 }
177
178 pub fn prefix(mut self) -> Tokenizer<'a, PrefixState> {
179 self.skip_tags();
180 Tokenizer {
181 raw: self.raw,
182 state: PhantomData::default(),
183 }
184 }
185
186 pub fn command(mut self) -> Tokenizer<'a, CommandState> {
187 self.skip_prefix();
188 Tokenizer {
189 raw: self.raw,
190 state: PhantomData::default(),
191 }
192 }
193
194 pub fn params(mut self) -> Tokenizer<'a, ParamsState> {
195 self.skip_command();
196 Tokenizer {
197 raw: self.raw,
198 state: PhantomData::default(),
199 }
200 }
201
202 pub fn trailing(mut self) -> Tokenizer<'a, TrailingState> {
203 self.skip_params();
204 Tokenizer {
205 raw: self.raw,
206 state: PhantomData::default(),
207 }
208 }
209}
210
211#[derive(Eq, PartialEq, Debug, Copy, Clone)]
212pub struct TagsState;
213
214impl State for TagsState {}
215
216impl<'a> Tokenizer<'a, TagsState> {
217 pub fn as_iter(&mut self) -> IntoTagsIter<'a> {
218 IntoTagsIter(*self)
219 }
220
221 pub fn prefix(mut self) -> Tokenizer<'a, PrefixState> {
222 self.skip_tags();
223 Tokenizer {
224 raw: self.raw,
225 state: PhantomData::default(),
226 }
227 }
228
229 pub fn command(mut self) -> Tokenizer<'a, CommandState> {
230 self.skip_prefix();
231 Tokenizer {
232 raw: self.raw,
233 state: PhantomData::default(),
234 }
235 }
236
237 pub fn params(mut self) -> Tokenizer<'a, ParamsState> {
238 self.skip_command();
239 Tokenizer {
240 raw: self.raw,
241 state: PhantomData::default(),
242 }
243 }
244
245 pub fn trailing(mut self) -> Tokenizer<'a, TrailingState> {
246 self.skip_params();
247 Tokenizer {
248 raw: self.raw,
249 state: PhantomData::default(),
250 }
251 }
252}
253
254impl<'a> IntoIterator for Tokenizer<'a, TagsState> {
255 type Item = Result<(&'a str, &'a str), ParserError>;
256 type IntoIter = IntoTagsIter<'a>;
257
258 fn into_iter(self) -> Self::IntoIter {
259 IntoTagsIter(self)
260 }
261}
262
263pub struct IntoTagsIter<'a>(Tokenizer<'a, TagsState>);
264
265impl<'a> Iterator for IntoTagsIter<'a> {
266 type Item = Result<(&'a str, &'a str), ParserError>;
267
268 fn next(&mut self) -> Option<Self::Item> {
269 match &self.0.raw[..1] {
270 "@" | ";" => {
271 let key_start = 1;
272 let key_end = self.0.raw[key_start..]
273 .find(&['='][..])
274 .map(|key_end| (key_end + key_start, key_end + key_start + 1))
275 .or_else(|| {
276 let key_end = key_start + self.0.raw[key_start..].find(&[' ', ';'][..])?;
277 Some((key_end, key_end))
278 });
279 if key_end.is_none() {
280 self.0.skip_to_end();
282 return Some(Err(ParserError::NoTagKeyEnd));
283 }
284 let (key_end, val_start) = key_end.unwrap();
285 let val_end = self.0.raw[val_start..].find(&[';', ' '][..]);
286 if val_end.is_none() {
287 self.0.skip_to_end();
289 return Some(Err(ParserError::NoTagValueEnd));
290 }
291 let val_end = val_start + val_end.unwrap();
292 let key_val = (
293 &self.0.raw[key_start..key_end],
294 &self.0.raw[val_start..val_end],
295 );
296 self.0.raw = &self.0.raw[val_end..];
297 Some(Ok(key_val))
298 }
299 _ => None,
300 }
301 }
302}
303
304#[derive(Eq, PartialEq, Debug, Copy, Clone)]
305pub struct PrefixState;
306
307impl State for PrefixState {}
308
309impl<'a> Tokenizer<'a, PrefixState> {
310 pub fn name(&mut self) -> Result<Option<&'a str>, ParserError> {
311 if self.raw.starts_with(' ') {
312 self.raw = &self.raw[1..];
313 }
314 let mut name = None;
315 if self.raw.starts_with(':') {
316 let end = self
317 .raw
318 .find(&['!', '@', ' '][..])
319 .ok_or(ParserError::NoCommand)?;
320 let split = self.raw.split_at(end);
321 name = Some(&split.0[1..]);
322 self.raw = split.1;
323 }
324 Ok(name)
325 }
326
327 pub fn user(&mut self) -> Result<Option<&'a str>, ParserError> {
328 let mut user = None;
329 if self.raw.starts_with('!') {
330 let end = self
331 .raw
332 .find(&['@', ' '][..])
333 .ok_or(ParserError::NoCommand)?;
334 let split = self.raw.split_at(end);
335 user = Some(&split.0[1..]);
336 self.raw = split.1;
337 }
338 Ok(user)
339 }
340
341 pub fn host(&mut self) -> Result<Option<&'a str>, ParserError> {
342 let mut host = None;
343 if self.raw.starts_with('@') {
344 let end = self.raw.find(' ').ok_or(ParserError::NoCommand)?;
345 let split = self.raw.split_at(end);
346 host = Some(&split.0[1..]);
347 self.raw = split.1;
348 }
349 Ok(host)
350 }
351
352 pub fn parts(&mut self) -> Result<Option<Prefix<'a>>, ParserError> {
354 if self.raw.starts_with(' ') {
355 self.raw = &self.raw[1..];
356 }
357 if !self.raw.starts_with(':') {
358 return Ok(None);
359 }
360 let (name, user, host) = (self.name()?, self.user()?, self.host()?);
361 if name.is_none() && (user.is_some() || host.is_some()) {
362 Err(ParserError::PrefixWithoutName)
363 } else {
364 Ok(Some((name.unwrap(), user, host)))
365 }
366 }
367
368 pub fn command(mut self) -> Tokenizer<'a, CommandState> {
369 self.skip_prefix();
370 Tokenizer {
371 raw: self.raw,
372 state: PhantomData::default(),
373 }
374 }
375
376 pub fn params(mut self) -> Tokenizer<'a, ParamsState> {
377 self.skip_command();
378 Tokenizer {
379 raw: self.raw,
380 state: PhantomData::default(),
381 }
382 }
383
384 pub fn trailing(mut self) -> Tokenizer<'a, TrailingState> {
385 self.skip_params();
386 Tokenizer {
387 raw: self.raw,
388 state: PhantomData::default(),
389 }
390 }
391}
392
393#[derive(Eq, PartialEq, Debug, Copy, Clone)]
394pub struct CommandState;
395
396impl State for CommandState {}
397
398impl<'a> Tokenizer<'a, CommandState> {
399 pub fn command(&mut self) -> Result<&'a str, ParserError> {
400 if self.raw.starts_with(' ') {
401 self.raw = &self.raw[1..];
402 }
403
404 let end = self.raw.find(' ').unwrap_or_else(|| self.raw.len());
405 let (command, rest) = self.raw.split_at(end);
406 if command.is_empty() {
407 return Err(ParserError::NoCommand);
408 }
409 self.raw = rest;
410 Ok(command)
411 }
412
413 pub fn params(mut self) -> Tokenizer<'a, ParamsState> {
414 self.skip_command();
415 Tokenizer {
416 raw: self.raw,
417 state: PhantomData::default(),
418 }
419 }
420
421 pub fn trailing(mut self) -> Tokenizer<'a, TrailingState> {
422 self.skip_params();
423 Tokenizer {
424 raw: self.raw,
425 state: PhantomData::default(),
426 }
427 }
428}
429
430#[derive(Eq, PartialEq, Debug, Copy, Clone)]
431pub struct ParamsState;
432
433impl State for ParamsState {}
434
435impl<'a> Tokenizer<'a, ParamsState> {
436 pub fn trailing(mut self) -> Tokenizer<'a, TrailingState> {
437 self.skip_params();
438 Tokenizer {
439 raw: self.raw,
440 state: PhantomData::default(),
441 }
442 }
443
444 pub fn as_iter(&mut self) -> IntoParamsIter<'a> {
445 IntoParamsIter(*self)
446 }
447}
448
449impl<'a> IntoIterator for Tokenizer<'a, ParamsState> {
450 type Item = &'a str;
451 type IntoIter = IntoParamsIter<'a>;
452
453 fn into_iter(self) -> Self::IntoIter {
454 IntoParamsIter(self)
455 }
456}
457
458pub struct IntoParamsIter<'a>(Tokenizer<'a, ParamsState>);
459
460impl<'a> Iterator for IntoParamsIter<'a> {
461 type Item = &'a str;
462
463 fn next(&mut self) -> Option<Self::Item> {
464 if !self.0.raw.starts_with(' ') || self.0.raw.starts_with(" :") {
465 return None;
466 }
467 self.0.raw = &self.0.raw[1..];
468 let end = self
469 .0
470 .raw
471 .find(' ')
472 .or_else(|| self.0.raw.find(" :"))
473 .unwrap_or_else(|| self.0.raw.len());
474 let (param, rest) = self.0.raw.split_at(end);
475 self.0.raw = rest;
476 Some(param)
477 }
478}
479
480#[derive(Eq, PartialEq, Debug, Copy, Clone)]
481pub struct TrailingState;
482
483impl State for TrailingState {}
484
485impl<'a> Tokenizer<'a, TrailingState> {
486 pub fn trailing(&self) -> Option<&'a str> {
487 if self.raw.starts_with(" :") {
488 Some(&self.raw[2..])
489 } else {
490 None
491 }
492 }
493}
494
495#[derive(Clone)]
496pub struct PartialCfg<'a> {
497 pub tags: HashSet<&'a str>,
498 pub prefix: Option<(bool, bool)>,
499 pub command: bool,
500 pub params: Vec<usize>,
501 pub trailing: bool,
502}
503
504impl<'a> Default for PartialCfg<'a> {
505 fn default() -> Self {
506 Self {
507 tags: HashSet::new(),
508 prefix: None,
509 command: true,
510 params: Vec::new(),
511 trailing: false,
512 }
513 }
514}
515
516#[cfg(test)]
517mod tests {
518 use crate::tokenizer::{ParserError, Tokenizer};
519 use std::error::Error;
520
521 #[test]
522 fn test_empty() {
523 assert_eq!(Err(ParserError::NoCommand), Tokenizer::new(""));
524 }
525
526 #[test]
527 fn test_command_only() -> Result<(), Box<dyn Error>> {
528 let mut tokenizer = Tokenizer::new("CMD")?.tags();
529 assert_eq!(None, tokenizer.as_iter().next());
530 let mut tokenizer = tokenizer.prefix();
531 assert_eq!(None, tokenizer.parts()?);
532 let mut tokenizer = tokenizer.command();
533 assert_eq!("CMD", tokenizer.command()?);
534 let mut tokenizer = tokenizer.params();
535 assert_eq!(None, tokenizer.as_iter().next());
536 assert_eq!(None, tokenizer.trailing().trailing());
537
538 Ok(())
539 }
540
541 #[test]
542 fn test_tag() -> Result<(), Box<dyn Error>> {
543 let mut tokenizer = Tokenizer::new("@key1=value1 CMD")?.tags();
544 let mut iter = tokenizer.as_iter();
545 assert_eq!(Some(Ok(("key1", "value1"))), iter.next());
546 assert_eq!(None, iter.next());
547 let mut tokenizer = tokenizer.prefix();
548 assert_eq!(None, tokenizer.parts()?);
549 let mut tokenizer = tokenizer.command();
550 assert_eq!("CMD", tokenizer.command()?);
551 let mut tokenizer = tokenizer.params();
552 let mut iter = tokenizer.as_iter();
553 assert_eq!(None, iter.next());
554 assert_eq!(None, tokenizer.trailing().trailing());
555
556 Ok(())
557 }
558
559 #[test]
560 fn test_tags() -> Result<(), Box<dyn Error>> {
561 let mut tokenizer = Tokenizer::new("@key1=value1;key2=value2;key3=;key4;key5 CMD")?.tags();
562 let mut iter = tokenizer.as_iter();
563 assert_eq!(Some(Ok(("key1", "value1"))), iter.next());
564 assert_eq!(Some(Ok(("key2", "value2"))), iter.next());
565 assert_eq!(Some(Ok(("key3", ""))), iter.next());
566 assert_eq!(Some(Ok(("key4", ""))), iter.next());
567 assert_eq!(Some(Ok(("key5", ""))), iter.next());
568 assert_eq!(None, iter.next());
569 let mut tokenizer = tokenizer.prefix();
570 assert_eq!(None, tokenizer.parts()?);
571 let mut tokenizer = tokenizer.command();
572 assert_eq!("CMD", tokenizer.command()?);
573 let mut tokenizer = tokenizer.params();
574 let mut iter = tokenizer.as_iter();
575 assert_eq!(None, iter.next());
576 assert_eq!(None, tokenizer.trailing().trailing());
577
578 Ok(())
579 }
580
581 #[test]
582 fn test_prefix() -> Result<(), Box<dyn Error>> {
583 let mut tokenizer = Tokenizer::new(":name!user@host CMD")?.tags();
584 let mut iter = tokenizer.as_iter();
585 assert_eq!(None, iter.next());
586 let mut tokenizer = tokenizer.prefix();
587 assert_eq!(
588 Some(("name", Some("user"), Some("host"))),
589 tokenizer.parts()?
590 );
591 let mut tokenizer = tokenizer.command();
592 assert_eq!("CMD", tokenizer.command()?);
593 let mut tokenizer = tokenizer.params();
594 let mut iter = tokenizer.as_iter();
595 assert_eq!(None, iter.next());
596 assert_eq!(None, tokenizer.trailing().trailing());
597
598 Ok(())
599 }
600
601 #[test]
602 fn test_prefix_name() -> Result<(), Box<dyn Error>> {
603 let mut tokenizer = Tokenizer::new(":name CMD")?.tags();
604 let mut iter = tokenizer.as_iter();
605 assert_eq!(None, iter.next());
606 let mut tokenizer = tokenizer.prefix();
607 assert_eq!(Some(("name", None, None)), tokenizer.parts()?);
608 let mut tokenizer = tokenizer.command();
609 assert_eq!("CMD", tokenizer.command()?);
610 let mut tokenizer = tokenizer.params();
611 let mut iter = tokenizer.as_iter();
612 assert_eq!(None, iter.next());
613 assert_eq!(None, tokenizer.trailing().trailing());
614
615 Ok(())
616 }
617
618 #[test]
619 fn test_prefix_user() -> Result<(), Box<dyn Error>> {
620 let mut tokenizer = Tokenizer::new(":name!user CMD")?.tags();
621 let mut iter = tokenizer.as_iter();
622 assert_eq!(None, iter.next());
623 let mut tokenizer = tokenizer.prefix();
624 assert_eq!(Some(("name", Some("user"), None)), tokenizer.parts()?);
625 let mut tokenizer = tokenizer.command();
626 assert_eq!("CMD", tokenizer.command()?);
627 let mut tokenizer = tokenizer.params();
628 let mut iter = tokenizer.as_iter();
629 assert_eq!(None, iter.next());
630 assert_eq!(None, tokenizer.trailing().trailing());
631
632 Ok(())
633 }
634
635 #[test]
636 fn test_prefix_host() -> Result<(), Box<dyn Error>> {
637 let mut tokenizer = Tokenizer::new(":name@host CMD")?.tags();
638 let mut iter = tokenizer.as_iter();
639 assert_eq!(None, iter.next());
640 let mut tokenizer = tokenizer.prefix();
641 assert_eq!(Some(("name", None, Some("host"))), tokenizer.parts()?);
642 let mut tokenizer = tokenizer.command();
643 assert_eq!("CMD", tokenizer.command()?);
644 let mut tokenizer = tokenizer.params();
645 let mut iter = tokenizer.as_iter();
646 assert_eq!(None, iter.next());
647 assert_eq!(None, tokenizer.trailing().trailing());
648
649 Ok(())
650 }
651
652 #[test]
653 fn test_params() -> Result<(), Box<dyn Error>> {
654 let mut tokenizer = Tokenizer::new("CMD param0 param1")?.tags();
655 let mut iter = tokenizer.as_iter();
656 assert_eq!(None, iter.next());
657 let mut tokenizer = tokenizer.prefix();
658 assert_eq!(None, tokenizer.parts()?);
659 let mut tokenizer = tokenizer.command();
660 assert_eq!("CMD", tokenizer.command()?);
661 let mut tokenizer = tokenizer.params();
662 let mut iter = tokenizer.as_iter();
663 assert_eq!(Some("param0"), iter.next());
664 assert_eq!(Some("param1"), iter.next());
665 assert_eq!(None, iter.next());
666 assert_eq!(None, tokenizer.trailing().trailing());
667
668 Ok(())
669 }
670
671 #[test]
672 fn test_params_trailing() -> Result<(), Box<dyn Error>> {
673 let mut tokenizer = Tokenizer::new("CMD param0 param1 :Trailing parameter!")?.tags();
674 let mut iter = tokenizer.as_iter();
675 assert_eq!(None, iter.next());
676 let mut tokenizer = tokenizer.prefix();
677 assert_eq!(None, tokenizer.parts()?);
678 let mut tokenizer = tokenizer.command();
679 assert_eq!("CMD", tokenizer.command()?);
680 let mut tokenizer = tokenizer.params();
681 let mut iter = tokenizer.as_iter();
682 assert_eq!(Some("param0"), iter.next());
683 assert_eq!(Some("param1"), iter.next());
684 assert_eq!(None, iter.next());
685 assert_eq!(Some("Trailing parameter!"), tokenizer.trailing().trailing());
686
687 Ok(())
688 }
689
690 #[test]
691 fn test_trailing() -> Result<(), Box<dyn Error>> {
692 let mut tokenizer = Tokenizer::new("CMD :Trailing parameter!")?.tags();
693 let mut iter = tokenizer.as_iter();
694 assert_eq!(None, iter.next());
695 let mut tokenizer = tokenizer.prefix();
696 assert_eq!(None, tokenizer.parts()?);
697 let mut tokenizer = tokenizer.command();
698 assert_eq!("CMD", tokenizer.command()?);
699 let mut tokenizer = tokenizer.params();
700 let mut iter = tokenizer.as_iter();
701 assert_eq!(None, iter.next());
702 assert_eq!(Some("Trailing parameter!"), tokenizer.trailing().trailing());
703
704 Ok(())
705 }
706
707 #[test]
708 fn test_all() -> Result<(), Box<dyn Error>> {
709 let mut tokenizer = Tokenizer::new(
710 "@key1=value1;key2=value2 :name!user@host CMD param0 param1 :Trailing parameter!@:=;",
711 )?
712 .tags();
713 let mut iter = tokenizer.as_iter();
714 assert_eq!(Some(Ok(("key1", "value1"))), iter.next());
715 assert_eq!(Some(Ok(("key2", "value2"))), iter.next());
716 let mut tokenizer = tokenizer.prefix();
717 assert_eq!(
718 Some(("name", Some("user"), Some("host"))),
719 tokenizer.parts()?
720 );
721 let mut tokenizer = tokenizer.command();
722 assert_eq!("CMD", tokenizer.command()?);
723 let mut tokenizer = tokenizer.params();
724 let mut iter = tokenizer.as_iter();
725 assert_eq!(Some("param0"), iter.next());
726 assert_eq!(Some("param1"), iter.next());
727 assert_eq!(
728 Some("Trailing parameter!@:=;"),
729 tokenizer.trailing().trailing()
730 );
731
732 Ok(())
733 }
734
735 #[test]
736 fn test_only_trailing() -> Result<(), Box<dyn Error>> {
737 let tokenizer = Tokenizer::new(
738 "@key1=value1;key2=value2 :name!user@host CMD param0 param1 :Trailing parameter!@:=;",
739 )?;
740 assert_eq!(
741 Some("Trailing parameter!@:=;"),
742 tokenizer.trailing().trailing()
743 );
744
745 Ok(())
746 }
747}