From 28d44f907cf817c8669c2fe2fd5fd09159dd3219 Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Wed, 12 Nov 2025 20:02:39 +0300 Subject: [PATCH] Default implementations of streams --- .gitignore | 4 +- default-streams/Cargo.toml | 8 ++ default-streams/src/_sandbox.rs | 25 +++++ default-streams/src/iterator.rs | 26 +++++ default-streams/src/iterators/array.rs | 128 +++++++++++++++++++++++ default-streams/src/iterators/mod.rs | 8 ++ default-streams/src/iterators/str.rs | 137 +++++++++++++++++++++++++ default-streams/src/lib.rs | 11 ++ default-streams/src/pos/index.rs | 19 ++++ default-streams/src/pos/mod.rs | 6 ++ default-streams/src/pos/newline.rs | 69 +++++++++++++ default-streams/src/stream.rs | 106 +++++++++++++++++++ src/_keyword_impls.rs | 20 ++-- src/lib.rs | 35 ++++--- 14 files changed, 573 insertions(+), 29 deletions(-) create mode 100644 default-streams/Cargo.toml create mode 100644 default-streams/src/_sandbox.rs create mode 100644 default-streams/src/iterator.rs create mode 100644 default-streams/src/iterators/array.rs create mode 100644 default-streams/src/iterators/mod.rs create mode 100644 default-streams/src/iterators/str.rs create mode 100644 default-streams/src/lib.rs create mode 100644 default-streams/src/pos/index.rs create mode 100644 default-streams/src/pos/mod.rs create mode 100644 default-streams/src/pos/newline.rs create mode 100644 default-streams/src/stream.rs diff --git a/.gitignore b/.gitignore index 1dc0060..3189865 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ /.idea -/target/* -/Cargo.lock \ No newline at end of file +target/ +Cargo.lock \ No newline at end of file diff --git a/default-streams/Cargo.toml b/default-streams/Cargo.toml new file mode 100644 index 0000000..4f7153e --- /dev/null +++ b/default-streams/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "source-stream-0-default-streams-0" +edition = "2024" + +[lib] + +[dependencies] +source-stream-0 = { path = ".." } \ No newline at end of file diff --git a/default-streams/src/_sandbox.rs b/default-streams/src/_sandbox.rs new file mode 100644 index 0000000..d2e9be2 --- /dev/null +++ b/default-streams/src/_sandbox.rs @@ -0,0 +1,25 @@ +use crate::iterators::StrSourceIterator; +use crate::pos::{NewLinePosCounter, PosLineCol}; +use crate::{_CollectScopeContext, SourceIterator}; + +#[test] +fn sandbox() { + let mut z: StrSourceIterator<'_, '_, PosLineCol, NewLinePosCounter> = + StrSourceIterator::start("12\n34"); + println!("{}", z.pos().col); + z.next(); + println!("{}", z.pos().col); + z.next(); + println!("{}", z.pos().col); + z.next(); + println!("{}", z.pos().col); + z.next(); + println!("{}", z.pos().col); + z.next(); + println!("{}", z.pos().col); + z.next(); + println!("{}", z.pos().col); + z.next(); + + return; +} diff --git a/default-streams/src/iterator.rs b/default-streams/src/iterator.rs new file mode 100644 index 0000000..683933c --- /dev/null +++ b/default-streams/src/iterator.rs @@ -0,0 +1,26 @@ +use source_stream_0::{CollectResult, CollectedSubstring, Pos}; + +pub trait PosCounter<'pos, C, P: Pos<'pos>> { + fn update(&mut self, c: Option); + + fn export(&self) -> P; + + fn init() -> Self; +} +pub trait _CollectScopeContext<'source, C> { + fn next(&mut self) -> Option; + fn current(&mut self) -> Option; +} + +pub trait SourceIterator<'source, 'pos, C, P: Pos<'pos>, CS: CollectedSubstring<'source, C>>: + _CollectScopeContext<'source, C> +{ + fn pos(&self) -> P; + + type CollectScopeContext: _CollectScopeContext<'source, C>; + + fn collect( + &mut self, + scope: impl FnOnce(&mut Self::CollectScopeContext) -> bool, + ) -> CollectResult; +} diff --git a/default-streams/src/iterators/array.rs b/default-streams/src/iterators/array.rs new file mode 100644 index 0000000..8d61f1c --- /dev/null +++ b/default-streams/src/iterators/array.rs @@ -0,0 +1,128 @@ +use crate::iterator::{_CollectScopeContext, PosCounter, SourceIterator}; +use source_stream_0::{CollectResult, CollectedSubstring, Keyword, KeywordComparatorIterator, Pos}; +use std::marker::PhantomData; +use std::slice::Iter; + +enum _CurrentChar { + UNINITIALIZED, + EOF, + Got(C), +} + +pub struct ArrayCollectedSubstring<'source, C> { + pub slice: &'source [C], +} + +impl<'source, C: Copy> CollectedSubstring<'source, C> for ArrayCollectedSubstring<'source, C> { + fn compareKeyword<'keyword>(&self, kw: impl Keyword<'keyword, C>) -> bool { + let mut kwi; + match kw.startComparation(self.slice.len()) { + None => return false, + Some(_kwi) => kwi = _kwi, + }; + + for c in self.slice.iter() { + if !kwi.consume(*c) { + return false; + } + } + + return true; + } +} + +pub struct ArraySourceIterator<'source, 'pos, C: Copy, P: Pos<'pos>, PC: PosCounter<'pos, C, P>> { + _source: &'source [C], + _iter: Iter<'source, C>, + _current: _CurrentChar<&'source C>, + _posRaw: usize, + _posHighlevel: PC, + __phantom1: PhantomData<&'pos ()>, + __phantom2: PhantomData

, +} + +impl<'source, 'pos, C: Copy, P: Pos<'pos>, PC: PosCounter<'pos, C, P>> + ArraySourceIterator<'source, 'pos, C, P, PC> +{ + pub fn start(arr: &'source [C]) -> ArraySourceIterator<'source, 'pos, C, P, PC> { + return ArraySourceIterator { + _source: arr, + _iter: arr.iter(), + _current: _CurrentChar::UNINITIALIZED, + _posRaw: 0, + _posHighlevel: PC::init(), + __phantom1: PhantomData::default(), + __phantom2: PhantomData::default(), + }; + } +} + +impl<'source, 'pos, C: Copy, P: Pos<'pos>, PC: PosCounter<'pos, C, P>> + _CollectScopeContext<'source, C> for ArraySourceIterator<'source, 'pos, C, P, PC> +{ + fn next(&mut self) -> Option { + match self._iter.next() { + None => { + if let _CurrentChar::Got(_) = self._current { + self._posHighlevel.update(None); + self._posRaw += 1; + } + self._current = _CurrentChar::EOF; + return None; + } + Some(c) => { + self._posHighlevel.update(Some(*c)); + if let _CurrentChar::Got(_) = self._current { + self._posRaw += 1; + } + self._current = _CurrentChar::Got(c); + return Some(*c); + } + } + } + + fn current(&mut self) -> Option { + match self._current { + _CurrentChar::UNINITIALIZED => return self.next(), + _CurrentChar::EOF => return None, + _CurrentChar::Got(c) => return Some(*c), + } + } +} + +impl<'source, 'pos, C: Copy, P: Pos<'pos>, PC: PosCounter<'pos, C, P>> + SourceIterator<'source, 'pos, C, P, ArrayCollectedSubstring<'source, C>> + for ArraySourceIterator<'source, 'pos, C, P, PC> +{ + fn pos(&self) -> P { + return self._posHighlevel.export(); + } + + type CollectScopeContext = ArraySourceIterator<'source, 'pos, C, P, PC>; + + fn collect( + &mut self, + scope: impl FnOnce(&mut Self::CollectScopeContext) -> bool, + ) -> CollectResult> { + match self._current { + _CurrentChar::EOF => return CollectResult::EOF, + _CurrentChar::UNINITIALIZED => {} + _CurrentChar::Got(_) => {} + } + + let startPosRaw = self._posRaw; + + match scope(self) { + false => return CollectResult::NotMatches, + true => { + let slice: &'source [C]; + match self._current { + _CurrentChar::EOF => slice = &self._source[startPosRaw..], + _CurrentChar::UNINITIALIZED => slice = &[], + _CurrentChar::Got(_) => slice = &self._source[startPosRaw..self._posRaw], + } + return CollectResult::Matches(ArrayCollectedSubstring { slice: slice }); + } + } + } +} diff --git a/default-streams/src/iterators/mod.rs b/default-streams/src/iterators/mod.rs new file mode 100644 index 0000000..1dda84e --- /dev/null +++ b/default-streams/src/iterators/mod.rs @@ -0,0 +1,8 @@ +mod str; +mod array; + + +pub use str::StrCollectedSubstring; +pub use str::StrSourceIterator; +pub use array::ArrayCollectedSubstring; +pub use array::ArraySourceIterator; \ No newline at end of file diff --git a/default-streams/src/iterators/str.rs b/default-streams/src/iterators/str.rs new file mode 100644 index 0000000..5943173 --- /dev/null +++ b/default-streams/src/iterators/str.rs @@ -0,0 +1,137 @@ +use crate::iterator::{_CollectScopeContext, PosCounter, SourceIterator}; +use source_stream_0::{CollectResult, CollectedSubstring, Keyword, KeywordComparatorIterator, Pos}; +use std::marker::PhantomData; +use std::str::CharIndices; + +enum _CurrentChar { + UNINITIALIZED, + EOF, + Got(char), +} + +pub struct StrCollectedSubstring<'source> { + pub slice: &'source str, + pub size: usize, +} + +impl<'source> CollectedSubstring<'source, char> for StrCollectedSubstring<'source> { + fn compareKeyword<'keyword>(&self, kw: impl Keyword<'keyword, char>) -> bool { + let mut kwi; + match kw.startComparation(self.size) { + None => return false, + Some(_kwi) => kwi = _kwi, + }; + + for c in self.slice.chars() { + if !kwi.consume(c) { + return false; + } + } + + return true; + } +} + +pub struct StrSourceIterator<'source, 'pos, P: Pos<'pos>, PC: PosCounter<'pos, char, P>> { + _source: &'source str, + _iter: CharIndices<'source>, + _current: _CurrentChar, + _posRaw: usize, + _posCodePoints: usize, + _posHighlevel: PC, + __phantom1: PhantomData<&'pos ()>, + __phantom2: PhantomData

, +} + +impl<'source, 'pos, P: Pos<'pos>, PC: PosCounter<'pos, char, P>> + StrSourceIterator<'source, 'pos, P, PC> +{ + pub fn start(s: &'source str) -> StrSourceIterator<'source, 'pos, P, PC> { + return StrSourceIterator { + _source: s, + _iter: s.char_indices(), + _current: _CurrentChar::UNINITIALIZED, + _posRaw: 0, + _posCodePoints: 0, + _posHighlevel: PC::init(), + __phantom1: PhantomData::default(), + __phantom2: PhantomData::default(), + }; + } +} + +impl<'source, 'pos, P: Pos<'pos>, PC: PosCounter<'pos, char, P>> _CollectScopeContext<'source, char> + for StrSourceIterator<'source, 'pos, P, PC> +{ + fn next(&mut self) -> Option { + match self._iter.next() { + None => { + if let _CurrentChar::Got(_) = self._current { + self._posHighlevel.update(None); + self._posCodePoints += 1; + self._posRaw = self._source.len(); + } + self._current = _CurrentChar::EOF; + return None; + } + Some((p, c)) => { + self._posRaw = p; + if let _CurrentChar::Got(_) = self._current { + self._posCodePoints += 1; + } + self._posHighlevel.update(Some(c)); + self._current = _CurrentChar::Got(c); + return Some(c); + } + } + } + + fn current(&mut self) -> Option { + match self._current { + _CurrentChar::UNINITIALIZED => return self.next(), + _CurrentChar::EOF => return None, + _CurrentChar::Got(c) => return Some(c), + } + } +} + +impl<'source, 'pos, P: Pos<'pos>, PC: PosCounter<'pos, char, P>> + SourceIterator<'source, 'pos, char, P, StrCollectedSubstring<'source>> + for StrSourceIterator<'source, 'pos, P, PC> +{ + fn pos(&self) -> P { + return self._posHighlevel.export(); + } + + type CollectScopeContext = StrSourceIterator<'source, 'pos, P, PC>; + + fn collect( + &mut self, + scope: impl FnOnce(&mut Self::CollectScopeContext) -> bool, + ) -> CollectResult> { + match self._current { + _CurrentChar::EOF => return CollectResult::EOF, + _CurrentChar::UNINITIALIZED => {} + _CurrentChar::Got(_) => {} + } + + let startPosRaw = self._posRaw; + let startPosCodePoints = self._posCodePoints; + + match scope(self) { + false => return CollectResult::NotMatches, + true => { + let slice: &'source str; + match self._current { + _CurrentChar::EOF => slice = &self._source[startPosRaw..], + _CurrentChar::UNINITIALIZED => slice = "", + _CurrentChar::Got(_) => slice = &self._source[startPosRaw..self._posRaw], + } + return CollectResult::Matches(StrCollectedSubstring { + slice: slice, + size: self._posCodePoints - startPosCodePoints, + }); + } + } + } +} diff --git a/default-streams/src/lib.rs b/default-streams/src/lib.rs new file mode 100644 index 0000000..1362dc9 --- /dev/null +++ b/default-streams/src/lib.rs @@ -0,0 +1,11 @@ +mod iterator; +mod stream; +pub use iterator::PosCounter; +pub use iterator::SourceIterator; +pub use iterator::_CollectScopeContext; +pub use stream::SourceStreamOverIterator; + +pub mod pos; +pub mod iterators; + +mod _sandbox; \ No newline at end of file diff --git a/default-streams/src/pos/index.rs b/default-streams/src/pos/index.rs new file mode 100644 index 0000000..1c8db22 --- /dev/null +++ b/default-streams/src/pos/index.rs @@ -0,0 +1,19 @@ +use crate::iterator::PosCounter; + +pub struct IndexPosCounter { + index: usize, +} + +impl PosCounter<'static, C, usize> for IndexPosCounter { + fn update(&mut self, c: Option) { + self.index += 1; + } + + fn export(&self) -> usize { + return self.index; + } + + fn init() -> Self { + return IndexPosCounter { index: 0 }; + } +} diff --git a/default-streams/src/pos/mod.rs b/default-streams/src/pos/mod.rs new file mode 100644 index 0000000..b0a7887 --- /dev/null +++ b/default-streams/src/pos/mod.rs @@ -0,0 +1,6 @@ +mod index; +mod newline; + +pub use index::IndexPosCounter; +pub use newline::PosLineCol; +pub use newline::NewLinePosCounter; \ No newline at end of file diff --git a/default-streams/src/pos/newline.rs b/default-streams/src/pos/newline.rs new file mode 100644 index 0000000..1285f5a --- /dev/null +++ b/default-streams/src/pos/newline.rs @@ -0,0 +1,69 @@ +use crate::iterator::PosCounter; +use source_stream_0::Pos; + +pub struct PosLineCol { + pub row: usize, + pub col: usize, +} + +impl Pos<'static> for PosLineCol {} + +pub struct NewLinePosCounter { + row: usize, + col: usize, +} + +impl NewLinePosCounter { + pub fn _update(&mut self, actual: Option, expected: C) { + match actual { + None => {} + Some(c) => { + if c == expected { + self.row += 1; + self.col = 0; + } else { + self.col += 1; + } + } + } + } + + pub fn _export(&self) -> PosLineCol { + return PosLineCol { + row: self.row, + col: self.col, + }; + } + + pub fn _init() -> Self { + return NewLinePosCounter { row: 0, col: 0 }; + } +} + +impl PosCounter<'static, char, PosLineCol> for NewLinePosCounter { + fn update(&mut self, c: Option) { + self._update(c, '\n') + } + + fn export(&self) -> PosLineCol { + self._export() + } + + fn init() -> Self { + return NewLinePosCounter::_init(); + } +} + +impl PosCounter<'static, u8, PosLineCol> for NewLinePosCounter { + fn update(&mut self, c: Option) { + self._update(c, b'\n') + } + + fn export(&self) -> PosLineCol { + self._export() + } + + fn init() -> Self { + return NewLinePosCounter::_init(); + } +} diff --git a/default-streams/src/stream.rs b/default-streams/src/stream.rs new file mode 100644 index 0000000..f67de58 --- /dev/null +++ b/default-streams/src/stream.rs @@ -0,0 +1,106 @@ +use crate::iterator::{_CollectScopeContext, SourceIterator}; +use source_stream_0::{CollectResult, CollectedSubstring, Pos, Predicate, SourceStream}; +use std::marker::PhantomData; + +pub struct SourceStreamOverIterator< + 'source, + 'pos, + C, + P: Pos<'pos>, + CS: CollectedSubstring<'source, C>, + I: SourceIterator<'source, 'pos, C, P, CS>, +> { + _iter: I, + __phantom1: PhantomData<&'source ()>, + __phantom2: PhantomData<&'pos ()>, + __phantom3: PhantomData, + __phantom4: PhantomData

, + __phantom5: PhantomData, +} + +impl< + 'source, + 'pos, + C, + P: Pos<'pos>, + CS: CollectedSubstring<'source, C>, + I: SourceIterator<'source, 'pos, C, P, CS>, +> SourceStreamOverIterator<'source, 'pos, C, P, CS, I> +{ + fn wrap(iter: I) -> SourceStreamOverIterator<'source, 'pos, C, P, CS, I> { + return SourceStreamOverIterator { + _iter: iter, + __phantom1: PhantomData::default(), + __phantom2: PhantomData::default(), + __phantom3: PhantomData::default(), + __phantom4: PhantomData::default(), + __phantom5: PhantomData::default(), + }; + } +} + +impl< + 'source, + 'pos, + C, + P: Pos<'pos>, + CS: CollectedSubstring<'source, C>, + I: SourceIterator<'source, 'pos, C, P, CS>, +> SourceStream<'source, 'pos, C, P, CS> for SourceStreamOverIterator<'source, 'pos, C, P, CS, I> +{ + fn skip(&mut self, predicate: &mut impl Predicate) -> bool { + match self._iter.current() { + Some(c) => match predicate.check(c) { + false => return false, + true => {} + }, + None => return true, + } + + loop { + match self._iter.next() { + None => return true, + Some(c) => match predicate.check(c) { + true => continue, + false => return false, + }, + } + } + } + + fn collect(&mut self, predicate: &mut impl Predicate) -> CollectResult { + return self._iter.collect(|iter| { + match iter.current() { + Some(c) => match predicate.check(c) { + false => return false, + true => {} + }, + None => return false, + } + + loop { + match iter.next() { + None => { + return true; + } + Some(c) => match predicate.check(c) { + true => continue, + false => return true, + }, + } + } + }); + } + + fn pos(&self) -> P { + return self._iter.pos(); + } + + fn currentChar(&mut self) -> Option { + return self._iter.current(); + } + + fn nextChar(&mut self) -> Option { + return self._iter.next(); + } +} diff --git a/src/_keyword_impls.rs b/src/_keyword_impls.rs index 1e75e9b..5945a15 100644 --- a/src/_keyword_impls.rs +++ b/src/_keyword_impls.rs @@ -1,17 +1,17 @@ use std::slice::Iter; use std::str::Chars; -impl crate::_KeywordComparatorIterator for Chars<'_> { +impl <'keyword> crate::KeywordComparatorIterator<'keyword, char> for Chars<'keyword> { fn consume(&mut self, e: char) -> bool { return self.next().is_some_and(|a| a == e); } } -impl crate::_Keyword for &str { +impl <'keyword> crate::Keyword<'keyword, char> for &'keyword str { fn startComparation( &self, expectedLen: usize, - ) -> Option> { + ) -> Option> { if (self.len() != expectedLen) { return Option::None; } @@ -20,11 +20,11 @@ impl crate::_Keyword for &str { } } -impl crate::_Keyword for &String { +impl <'keyword> crate::Keyword<'keyword, char> for &'keyword String { fn startComparation( &self, expectedLen: usize, - ) -> Option> { + ) -> Option> { if (self.len() != expectedLen) { return Option::None; } @@ -32,17 +32,17 @@ impl crate::_Keyword for &String { return Option::Some(self.chars()); } } -impl crate::_KeywordComparatorIterator for Iter<'_, T> { +impl<'keyword, T: PartialEq> crate::KeywordComparatorIterator<'keyword, T> for Iter<'keyword, T> { fn consume(&mut self, e: T) -> bool { return self.next().is_some_and(|a| a.eq(&e)); } } -impl crate::_Keyword for &[T] { +impl<'keyword, T: PartialEq> crate::Keyword<'keyword, T> for &'keyword [T] { fn startComparation( &self, expectedLen: usize, - ) -> Option> { + ) -> Option> { if (self.len() != expectedLen) { return Option::None; } @@ -51,11 +51,11 @@ impl crate::_Keyword for &[T] { } } -impl crate::_Keyword for &[T; SZ] { +impl<'keyword, T: PartialEq, const SZ: usize> crate::Keyword<'keyword, T> for &'keyword [T; SZ] { fn startComparation( &self, expectedLen: usize, - ) -> Option> { + ) -> Option> { if (self.len() != expectedLen) { return Option::None; } diff --git a/src/lib.rs b/src/lib.rs index 5af594f..6b2fc17 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,43 +4,44 @@ pub trait Predicate { fn check(&mut self, chr: C) -> bool; } -impl bool> Predicate for F { - fn check(&mut self, chr: C) -> bool { - return self(chr); - } -} +pub trait Pos<'pos> {} -pub trait Pos {} +impl Pos<'static> for usize {} -pub trait _KeywordComparatorIterator { +pub trait KeywordComparatorIterator<'keyword, C> { fn consume(&mut self, c: C) -> bool; } -pub trait _Keyword { - fn startComparation(&self, expectedLen: usize) -> Option>; +pub trait Keyword<'keyword, C> { + fn startComparation( + &self, + expectedLen: usize, + ) -> Option>; } -pub trait CollectedSubstring { - fn compareKeyword(&self, kw: impl _Keyword); +pub trait CollectedSubstring<'source, C> { + fn compareKeyword<'keyword>(&self, kw: impl Keyword<'keyword, C>) -> bool; } pub enum CollectResult { EOF, NotMatches, - Matches(T) + Matches(T), } -pub trait SourceStream> { +pub trait SourceStream<'source, 'pos, C, P: Pos<'pos>, CS: CollectedSubstring<'source, C>> { /** * Returns `true` if the end of stream reached. */ - fn skip(&mut self, predicate: impl Predicate) -> bool; - fn collect(&mut self, predicate: impl Predicate) -> CollectResult; + fn skip(&mut self, predicate: &mut impl Predicate) -> bool; + fn collect(&mut self, predicate: &mut impl Predicate) -> CollectResult; fn pos(&self) -> P; - fn currentChar(&self) -> Option; + fn currentChar(&mut self) -> Option; fn nextChar(&mut self) -> Option; - fn isEnded(&self) -> bool; + fn isEnded(&mut self) -> bool { + return self.currentChar().is_none(); + } }