diff options
author | Martin Fischer <martin@push-f.com> | 2023-08-17 08:04:21 +0200 |
---|---|---|
committer | Martin Fischer <martin@push-f.com> | 2023-08-19 11:41:22 +0200 |
commit | 91074b6e7e6e8463f15ca26bc39e70b80f954227 (patch) | |
tree | 7db7159df67faed9c5a7954a07a064cadcb0497e /src | |
parent | 0f2d667eb08762b744ef5a18d6c09f99c9c1b8bb (diff) |
refactor!: make Position generic over offset type
Previously Span was generic over R just
so that it could provide the method:
fn from_reader(reader: &R) -> Self;
and properly implementing that method again
relied on R implementing the Position trait:
impl<P: Position> Span<P> for Range<usize> { .. }
which was a very roundabout and awkward way of doing things.
It makes much more sense to make the Position trait generic
over the return type of its method (which previously always had
to be usize). Which lets us provide a blanket implementation:
impl<R: Reader> Position<NoopOffset> for R { .. }
Diffstat (limited to 'src')
-rw-r--r-- | src/emitter.rs | 19 | ||||
-rw-r--r-- | src/spans.rs | 57 | ||||
-rw-r--r-- | src/tokenizer.rs | 1 |
3 files changed, 48 insertions, 29 deletions
diff --git a/src/emitter.rs b/src/emitter.rs index e441eb7..18b2539 100644 --- a/src/emitter.rs +++ b/src/emitter.rs @@ -5,6 +5,7 @@ use std::collections::VecDeque; use std::marker::PhantomData; use std::mem; +use crate::spans::Position; use crate::spans::Span; use crate::Error; @@ -183,7 +184,7 @@ impl<R, S> Default for DefaultEmitter<R, S> { } } -impl<R, S: Span<R>> DefaultEmitter<R, S> { +impl<R, S: Span> DefaultEmitter<R, S> { fn emit_token(&mut self, token: Token<S>) { self.flush_current_characters(); self.emitted_tokens.push_front(token); @@ -229,7 +230,7 @@ impl<R, S: Span<R>> DefaultEmitter<R, S> { } } -impl<R, S: Span<R>> Emitter<R> for DefaultEmitter<R, S> { +impl<R: Position<S::Offset>, S: Span> Emitter<R> for DefaultEmitter<R, S> { type Token = Token<S>; fn emit_eof(&mut self) { @@ -237,7 +238,7 @@ impl<R, S: Span<R>> Emitter<R> for DefaultEmitter<R, S> { } fn emit_error(&mut self, error: Error, reader: &R) { - self.push_error(error, S::from_reader(reader)); + self.push_error(error, S::new(reader.position(), reader.position())); } fn pop_token(&mut self) -> Option<Self::Token> { @@ -250,7 +251,7 @@ impl<R, S: Span<R>> Emitter<R> for DefaultEmitter<R, S> { fn init_start_tag(&mut self, reader: &R) { self.current_token = Some(Token::StartTag(StartTag { - name_span: S::from_reader(reader), + name_span: S::new(reader.position(), reader.position()), self_closing: false, name: String::new(), attributes: Default::default(), @@ -258,7 +259,7 @@ impl<R, S: Span<R>> Emitter<R> for DefaultEmitter<R, S> { } fn init_end_tag(&mut self, reader: &R) { self.current_token = Some(Token::EndTag(EndTag { - name_span: S::from_reader(reader), + name_span: S::new(reader.position(), reader.position()), name: String::new(), })); self.seen_attributes.clear(); @@ -367,15 +368,17 @@ impl<R, S: Span<R>> Emitter<R> for DefaultEmitter<R, S> { self.current_attribute = Some(( String::new(), Attribute { - name_span: S::from_reader(reader), + name_span: S::new(reader.position(), reader.position()), value: String::new(), value_span: S::default(), }, )); } fn init_attribute_value(&mut self, reader: &R, quoted: bool) { - self.current_attribute.as_mut().unwrap().1.value_span = - S::from_reader_with_offset(reader, quoted as usize); + self.current_attribute.as_mut().unwrap().1.value_span = S::new( + reader.position() + quoted as usize, + reader.position() + quoted as usize, + ); } fn push_attribute_name(&mut self, s: &str) { diff --git a/src/spans.rs b/src/spans.rs index 89595aa..14392cd 100644 --- a/src/spans.rs +++ b/src/spans.rs @@ -6,21 +6,29 @@ //! * one for `()` which acts as the no-op implementation for when you don't want to track spans //! * one for [`Range<usize>`] for when you do want to track spans //! -//! To use the latter your reader however has to implement [`Position`]. +//! To use the latter your reader however has to implement [`Position<usize>`]. //! You can easily use any existing reader by wrapping it in the [`PosTrackingReader`] struct -//! which implements the [`Position`] trait and takes care of tracking the current position. +//! which implements the [`Position<usize>`] trait and takes care of tracking the current position. -use std::ops::Range; +use std::ops::{Add, Range}; use crate::reader::{IntoReader, Reader}; +pub struct NoopOffset; + /// A trait to be implemented by readers that track their own position. -pub trait Position { +pub trait Position<T> { /// Returns the byte index of the current position. - fn position(&self) -> usize; + fn position(&self) -> T; +} + +impl<R: Reader> Position<NoopOffset> for R { + fn position(&self) -> NoopOffset { + NoopOffset + } } -/// Wraps a [`Reader`] so that it implements [`Position`]. +/// Wraps a [`Reader`] so that it implements [`Position<usize>`]. pub struct PosTrackingReader<R> { /// The wrapped reader. reader: R, @@ -29,7 +37,7 @@ pub struct PosTrackingReader<R> { } impl<R> PosTrackingReader<R> { - /// Wraps the given [`Reader`] so that it implements [`Position`] with the position starting from 0. + /// Wraps the given [`Reader`] so that it implements [`Position<usize>`] with the position starting from 0. pub fn new<'a>(into_reader: impl IntoReader<'a, Reader = R>) -> Self { Self { reader: into_reader.into_reader(), @@ -38,39 +46,46 @@ impl<R> PosTrackingReader<R> { } } -impl<R> Position for PosTrackingReader<R> { +impl<R> Position<usize> for PosTrackingReader<R> { fn position(&self) -> usize { self.position } } /// A byte range in the source code. -pub trait Span<R>: Default + Clone { - /// Initializes a new span at the current position of the reader. - fn from_reader(reader: &R) -> Self; +pub trait Span: Default + Clone { + type Offset: Add<usize, Output = Self::Offset>; - /// Initializes a new span at the current position of the reader with the given offset. - fn from_reader_with_offset(reader: &R, offset: usize) -> Self; + /// Constructs a new span from the given byte offsets. + fn new(start: Self::Offset, end: Self::Offset) -> Self; /// Extends the span by the length of the given string. fn push_str(&mut self, str: &str); } -impl<R> Span<R> for () { - fn from_reader(_reader: &R) -> Self {} +impl Span for () { + type Offset = NoopOffset; - fn from_reader_with_offset(_reader: &R, _offset: usize) -> Self {} + fn new(_start: Self::Offset, _end: Self::Offset) -> Self { + () + } fn push_str(&mut self, _str: &str) {} } -impl<P: Position> Span<P> for Range<usize> { - fn from_reader(reader: &P) -> Self { - reader.position() - 1..reader.position() - 1 +impl Add<usize> for NoopOffset { + type Output = Self; + + fn add(self, _rhs: usize) -> NoopOffset { + self } +} + +impl Span for Range<usize> { + type Offset = usize; - fn from_reader_with_offset(reader: &P, offset: usize) -> Self { - reader.position() - 1 + offset..reader.position() - 1 + offset + fn new(start: Self::Offset, end: Self::Offset) -> Self { + start - 1..end - 1 } fn push_str(&mut self, str: &str) { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 7768ee4..7b8b1ce 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -1,5 +1,6 @@ use crate::machine; use crate::reader::{IntoReader, Reader}; +use crate::spans::Position; use crate::utils::{ control_pat, noncharacter_pat, surrogate_pat, ControlToken, State as InternalState, }; |