From 04ec6f5acc45ecbe3af3b8b8723639e7526e4394 Mon Sep 17 00:00:00 2001 From: Andrew Golovashevich Date: Wed, 12 Nov 2025 20:50:17 +0300 Subject: [PATCH] Fixed ambiguous iterator state when calling first .current() vs .next() and high-level pos counters fix --- default-streams/src/_sandbox.rs | 39 +++++++++------ default-streams/src/iterator.rs | 4 +- default-streams/src/iterators/array.rs | 55 ++++++-------------- default-streams/src/iterators/str.rs | 69 +++++++++++--------------- default-streams/src/pos/index.rs | 2 +- default-streams/src/pos/newline.rs | 21 +++----- default-streams/src/stream.rs | 2 +- src/lib.rs | 2 +- 8 files changed, 81 insertions(+), 113 deletions(-) diff --git a/default-streams/src/_sandbox.rs b/default-streams/src/_sandbox.rs index d2e9be2..51b098c 100644 --- a/default-streams/src/_sandbox.rs +++ b/default-streams/src/_sandbox.rs @@ -1,25 +1,32 @@ use crate::iterators::StrSourceIterator; -use crate::pos::{NewLinePosCounter, PosLineCol}; +use crate::pos::{IndexPosCounter, NewLinePosCounter, PosLineCol}; use crate::{_CollectScopeContext, SourceIterator}; #[test] fn sandbox() { - let mut z: StrSourceIterator<'_, '_, PosLineCol, NewLinePosCounter> = + let mut z: StrSourceIterator<'_, '_, usize, IndexPosCounter> = 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(); + println!("{}", z.pos()); + z.next(); + println!("{} ", z.pos()); + z.next(); + println!("{}", z.pos()); + z.next(); + println!("{} ", z.pos()); + z.next(); + println!("{} ", z.pos()); + z.next(); + println!("{} ", z.pos()); + z.next(); + println!("{} ", z.pos()); + z.next(); + println!("{} ", z.pos()); + z.next(); + println!("{} ", z.pos()); + z.next(); + println!("{} ", z.pos()); + z.next(); + return; } diff --git a/default-streams/src/iterator.rs b/default-streams/src/iterator.rs index 683933c..6578ca4 100644 --- a/default-streams/src/iterator.rs +++ b/default-streams/src/iterator.rs @@ -1,7 +1,7 @@ use source_stream_0::{CollectResult, CollectedSubstring, Pos}; pub trait PosCounter<'pos, C, P: Pos<'pos>> { - fn update(&mut self, c: Option); + fn update(&mut self, c: C); fn export(&self) -> P; @@ -9,7 +9,7 @@ pub trait PosCounter<'pos, C, P: Pos<'pos>> { } pub trait _CollectScopeContext<'source, C> { fn next(&mut self) -> Option; - fn current(&mut self) -> Option; + fn current(&self) -> Option; } pub trait SourceIterator<'source, 'pos, C, P: Pos<'pos>, CS: CollectedSubstring<'source, C>>: diff --git a/default-streams/src/iterators/array.rs b/default-streams/src/iterators/array.rs index 8d61f1c..30eea48 100644 --- a/default-streams/src/iterators/array.rs +++ b/default-streams/src/iterators/array.rs @@ -3,12 +3,6 @@ use source_stream_0::{CollectResult, CollectedSubstring, Keyword, KeywordCompara use std::marker::PhantomData; use std::slice::Iter; -enum _CurrentChar { - UNINITIALIZED, - EOF, - Got(C), -} - pub struct ArrayCollectedSubstring<'source, C> { pub slice: &'source [C], } @@ -34,7 +28,7 @@ impl<'source, C: Copy> CollectedSubstring<'source, C> for ArrayCollectedSubstrin 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>, + _current: Option<&'source C>, _posRaw: usize, _posHighlevel: PC, __phantom1: PhantomData<&'pos ()>, @@ -45,10 +39,12 @@ 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> { + let mut it = arr.iter(); + let first = it.next(); return ArraySourceIterator { _source: arr, - _iter: arr.iter(), - _current: _CurrentChar::UNINITIALIZED, + _iter: it, + _current: first, _posRaw: 0, _posHighlevel: PC::init(), __phantom1: PhantomData::default(), @@ -61,32 +57,16 @@ 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); - } + if let Some(c) = self._current { + self._posHighlevel.update(*c); + self._posRaw += 1; + self._current = self._iter.next(); } + return self._current.map(|c| *c); } - fn current(&mut self) -> Option { - match self._current { - _CurrentChar::UNINITIALIZED => return self.next(), - _CurrentChar::EOF => return None, - _CurrentChar::Got(c) => return Some(*c), - } + fn current(&self) -> Option { + return self._current.map(|c| *c); } } @@ -104,10 +84,8 @@ impl<'source, 'pos, C: Copy, P: Pos<'pos>, PC: PosCounter<'pos, C, P>> &mut self, scope: impl FnOnce(&mut Self::CollectScopeContext) -> bool, ) -> CollectResult> { - match self._current { - _CurrentChar::EOF => return CollectResult::EOF, - _CurrentChar::UNINITIALIZED => {} - _CurrentChar::Got(_) => {} + if self._current.is_none() { + return CollectResult::EOF; } let startPosRaw = self._posRaw; @@ -117,9 +95,8 @@ impl<'source, 'pos, C: Copy, P: Pos<'pos>, PC: PosCounter<'pos, C, P>> 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], + None => slice = &self._source[startPosRaw..], + Some(_) => slice = &self._source[startPosRaw..self._posRaw], } return CollectResult::Matches(ArrayCollectedSubstring { slice: slice }); } diff --git a/default-streams/src/iterators/str.rs b/default-streams/src/iterators/str.rs index 5943173..9f4316e 100644 --- a/default-streams/src/iterators/str.rs +++ b/default-streams/src/iterators/str.rs @@ -3,12 +3,6 @@ use source_stream_0::{CollectResult, CollectedSubstring, Keyword, KeywordCompara 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, @@ -35,7 +29,7 @@ impl<'source> CollectedSubstring<'source, char> for StrCollectedSubstring<'sourc pub struct StrSourceIterator<'source, 'pos, P: Pos<'pos>, PC: PosCounter<'pos, char, P>> { _source: &'source str, _iter: CharIndices<'source>, - _current: _CurrentChar, + _current: Option, _posRaw: usize, _posCodePoints: usize, _posHighlevel: PC, @@ -47,11 +41,13 @@ 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> { + let mut it = s.char_indices(); + let first = it.next(); return StrSourceIterator { _source: s, - _iter: s.char_indices(), - _current: _CurrentChar::UNINITIALIZED, - _posRaw: 0, + _iter: it, + _current: first.map(|(_, c)| c), + _posRaw: first.map_or(s.len(), |(p, _)| p), _posCodePoints: 0, _posHighlevel: PC::init(), __phantom1: PhantomData::default(), @@ -64,34 +60,30 @@ impl<'source, 'pos, P: Pos<'pos>, PC: PosCounter<'pos, char, P>> _CollectScopeCo 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(); + match self._current { + None => return None, + Some(prev) => { + self._posHighlevel.update(prev); + self._posCodePoints += 1; + + match self._iter.next() { + None => { + self._posRaw = self._source.len(); + self._current = None; + return None; + } + Some((p, c)) => { + self._posRaw = p; + self._current = Some(c); + return Some(c); + } } - 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), - } + fn current(&self) -> Option { + return self._current; } } @@ -109,10 +101,8 @@ impl<'source, 'pos, P: Pos<'pos>, PC: PosCounter<'pos, char, P>> &mut self, scope: impl FnOnce(&mut Self::CollectScopeContext) -> bool, ) -> CollectResult> { - match self._current { - _CurrentChar::EOF => return CollectResult::EOF, - _CurrentChar::UNINITIALIZED => {} - _CurrentChar::Got(_) => {} + if self._current.is_none() { + return CollectResult::EOF; } let startPosRaw = self._posRaw; @@ -123,9 +113,8 @@ impl<'source, 'pos, P: Pos<'pos>, PC: PosCounter<'pos, char, P>> 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], + None => slice = &self._source[startPosRaw..], + Some(_) => slice = &self._source[startPosRaw..self._posRaw], } return CollectResult::Matches(StrCollectedSubstring { slice: slice, diff --git a/default-streams/src/pos/index.rs b/default-streams/src/pos/index.rs index 1c8db22..691f133 100644 --- a/default-streams/src/pos/index.rs +++ b/default-streams/src/pos/index.rs @@ -5,7 +5,7 @@ pub struct IndexPosCounter { } impl PosCounter<'static, C, usize> for IndexPosCounter { - fn update(&mut self, c: Option) { + fn update(&mut self, c: C) { self.index += 1; } diff --git a/default-streams/src/pos/newline.rs b/default-streams/src/pos/newline.rs index 1285f5a..af28c4e 100644 --- a/default-streams/src/pos/newline.rs +++ b/default-streams/src/pos/newline.rs @@ -14,17 +14,12 @@ pub struct NewLinePosCounter { } 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 _update(&mut self, actual: C, expected: C) { + if actual == expected { + self.row += 1; + self.col = 0; + } else { + self.col += 1; } } @@ -41,7 +36,7 @@ impl NewLinePosCounter { } impl PosCounter<'static, char, PosLineCol> for NewLinePosCounter { - fn update(&mut self, c: Option) { + fn update(&mut self, c: char) { self._update(c, '\n') } @@ -55,7 +50,7 @@ impl PosCounter<'static, char, PosLineCol> for NewLinePosCounter { } impl PosCounter<'static, u8, PosLineCol> for NewLinePosCounter { - fn update(&mut self, c: Option) { + fn update(&mut self, c: u8) { self._update(c, b'\n') } diff --git a/default-streams/src/stream.rs b/default-streams/src/stream.rs index f67de58..aac41f8 100644 --- a/default-streams/src/stream.rs +++ b/default-streams/src/stream.rs @@ -96,7 +96,7 @@ impl< return self._iter.pos(); } - fn currentChar(&mut self) -> Option { + fn currentChar(&self) -> Option { return self._iter.current(); } diff --git a/src/lib.rs b/src/lib.rs index 6b2fc17..15fb1a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,7 @@ pub trait SourceStream<'source, 'pos, C, P: Pos<'pos>, CS: CollectedSubstring<'s fn pos(&self) -> P; - fn currentChar(&mut self) -> Option; + fn currentChar(&self) -> Option; fn nextChar(&mut self) -> Option; fn isEnded(&mut self) -> bool {