summaryrefslogtreecommitdiff
path: root/src/input.rs
diff options
context:
space:
mode:
authorJohn Turner <jturner.usa@gmail.com>2025-10-21 20:48:00 -0400
committerJohn Turner <jturner.usa@gmail.com>2025-10-21 20:48:21 -0400
commit0e23b9fa82d95ca365523afac554a4fb6d461a23 (patch)
tree296fc7fc3e8208198b7e87adf4a016a9ea93aedf /src/input.rs
parent876855e826bf3c7bd47b822fb41fd91ab46ad7e5 (diff)
downloadmon-0e23b9fa82d95ca365523afac554a4fb6d461a23.tar.gz
impl some basic parsers and combinators
Diffstat (limited to 'src/input.rs')
-rw-r--r--src/input.rs127
1 files changed, 127 insertions, 0 deletions
diff --git a/src/input.rs b/src/input.rs
new file mode 100644
index 0000000..0857c8c
--- /dev/null
+++ b/src/input.rs
@@ -0,0 +1,127 @@
+use core::{fmt, iter, slice, str::CharIndices};
+
+use crate::Span;
+
+pub trait Input: Clone {
+ type Item;
+ type Items: Clone + Iterator<Item = (usize, Self::Item)>;
+
+ fn items(&self) -> Self::Items;
+
+ fn slice(&self, span: Span) -> Self;
+
+ fn len(&self) -> usize;
+}
+
+impl<'a> Input for &'a str {
+ type Item = char;
+ type Items = CharIndices<'a>;
+
+ fn items(&self) -> Self::Items {
+ self.char_indices()
+ }
+
+ fn slice(&self, span: Span) -> Self {
+ &self[span]
+ }
+
+ fn len(&self) -> usize {
+ (*self).len()
+ }
+}
+
+impl<'a> Input for &'a [u8] {
+ type Item = u8;
+ type Items = iter::Enumerate<iter::Copied<slice::Iter<'a, u8>>>;
+
+ fn items(&self) -> Self::Items {
+ self.iter().copied().enumerate()
+ }
+
+ fn slice(&self, span: Span) -> Self {
+ &self[span]
+ }
+
+ fn len(&self) -> usize {
+ (*self).len()
+ }
+}
+
+pub trait Character {
+ fn is_alphabetic(&self) -> bool;
+
+ fn is_numeric(&self) -> bool;
+
+ fn is_whitespace(&self) -> bool;
+
+ fn is_alphanumeric(&self) -> bool {
+ self.is_alphabetic() || self.is_numeric()
+ }
+}
+
+impl Character for char {
+ fn is_alphabetic(&self) -> bool {
+ (*self).is_ascii_alphabetic()
+ }
+
+ fn is_numeric(&self) -> bool {
+ (*self).is_numeric()
+ }
+
+ fn is_whitespace(&self) -> bool {
+ (*self).is_whitespace()
+ }
+}
+
+#[derive(Clone)]
+pub struct InputIter<I: Input> {
+ pub it: I::Items,
+ pub input: I,
+}
+
+impl<I> InputIter<I>
+where
+ I: Input,
+{
+ pub fn new(input: I) -> Self {
+ Self {
+ it: input.items(),
+ input,
+ }
+ }
+
+ pub fn position(&self) -> usize {
+ match self.it.clone().next() {
+ Some((i, _)) => i,
+ None => self.input.len(),
+ }
+ }
+
+ pub fn is_finished(&self) -> bool {
+ self.clone().next().is_none()
+ }
+
+ pub fn rest(&self) -> I {
+ self.input.slice(self.position()..self.input.len())
+ }
+}
+
+impl<I> Iterator for InputIter<I>
+where
+ I: Input,
+{
+ type Item = (usize, I::Item);
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.it.next()
+ }
+}
+
+impl<I> fmt::Debug for InputIter<I>
+where
+ I: Input + fmt::Debug,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{:?}", self.rest())
+ }
+}