| pub(crate) mod printf; | |
| pub(crate) mod shell; | |
| #[derive(Clone, Copy)] | |
| struct StrCursor<'a> { | |
| s: &'a str, | |
| pub at: usize, | |
| } | |
| impl<'a> StrCursor<'a> { | |
| fn new_at(s: &'a str, at: usize) -> StrCursor<'a> { | |
| StrCursor { s, at } | |
| } | |
| fn at_next_cp(mut self) -> Option<StrCursor<'a>> { | |
| match self.try_seek_right_cp() { | |
| true => Some(self), | |
| false => None, | |
| } | |
| } | |
| fn next_cp(mut self) -> Option<(char, StrCursor<'a>)> { | |
| let cp = self.cp_after()?; | |
| self.seek_right(cp.len_utf8()); | |
| Some((cp, self)) | |
| } | |
| fn slice_before(&self) -> &'a str { | |
| &self.s[0..self.at] | |
| } | |
| fn slice_after(&self) -> &'a str { | |
| &self.s[self.at..] | |
| } | |
| fn slice_between(&self, until: StrCursor<'a>) -> Option<&'a str> { | |
| if !str_eq_literal(self.s, until.s) { | |
| None | |
| } else { | |
| use std::cmp::{max, min}; | |
| let beg = min(self.at, until.at); | |
| let end = max(self.at, until.at); | |
| Some(&self.s[beg..end]) | |
| } | |
| } | |
| fn cp_after(&self) -> Option<char> { | |
| self.slice_after().chars().next() | |
| } | |
| fn try_seek_right_cp(&mut self) -> bool { | |
| match self.slice_after().chars().next() { | |
| Some(c) => { | |
| self.at += c.len_utf8(); | |
| true | |
| } | |
| None => false, | |
| } | |
| } | |
| fn seek_right(&mut self, bytes: usize) { | |
| self.at += bytes; | |
| } | |
| } | |
| impl std::fmt::Debug for StrCursor<'_> { | |
| fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | |
| write!(fmt, "StrCursor({:?} | {:?})", self.slice_before(), self.slice_after()) | |
| } | |
| } | |
| fn str_eq_literal(a: &str, b: &str) -> bool { | |
| a.as_bytes().as_ptr() == b.as_bytes().as_ptr() && a.len() == b.len() | |
| } |