Skip to main content

sim_lib_pattern/
cursor.rs

1//! Type-separated subject symbols and pattern cursors.
2
3use core::fmt::Debug;
4use core::marker::PhantomData;
5
6/// Checked exact-text offset types owned by `sim-text`.
7pub use sim_text::{CodeUnitOffset, ScalarOffset};
8
9/// A symbol domain defines both the unit consumed by a pattern and its offset type.
10///
11/// Keeping the offset as an associated type prevents byte-oriented patterns from
12/// accidentally being paired with subjects indexed in code units.
13pub trait SymbolDomain {
14    /// One symbol consumed from a subject.
15    type Symbol;
16    /// A position in both the pattern source and the subject.
17    type Offset: Copy + Debug + Eq + Ord;
18}
19
20/// A byte offset.
21#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
22pub struct ByteOffset(pub usize);
23
24/// A domain whose symbols and offsets are bytes.
25#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
26pub struct ByteDomain;
27
28impl SymbolDomain for ByteDomain {
29    type Symbol = u8;
30    type Offset = ByteOffset;
31}
32
33/// A domain whose symbols and offsets are Unicode scalar values.
34#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
35pub struct ScalarDomain;
36
37impl SymbolDomain for ScalarDomain {
38    type Symbol = char;
39    type Offset = ScalarOffset;
40}
41
42/// A domain whose symbols and offsets are exact UTF-16 code units.
43#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
44pub struct CodeUnitDomain;
45
46impl SymbolDomain for CodeUnitDomain {
47    type Symbol = u16;
48    type Offset = CodeUnitOffset;
49}
50
51/// A matching cursor carrying independent source and subject positions.
52///
53/// ```compile_fail
54/// use sim_lib_pattern::{ByteDomain, ByteOffset, CodeUnitDomain, CodeUnitOffset, Cursor};
55///
56/// fn run_bytes(_: Cursor<ByteDomain>) {}
57/// let text_cursor = Cursor::<CodeUnitDomain>::new(CodeUnitOffset::new(0), CodeUnitOffset::new(0));
58/// run_bytes(text_cursor);
59/// ```
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61pub struct Cursor<D: SymbolDomain> {
62    source: D::Offset,
63    subject: D::Offset,
64    domain: PhantomData<fn() -> D>,
65}
66
67impl<D: SymbolDomain> Cursor<D> {
68    /// Creates a cursor from its pattern-source and subject positions.
69    pub const fn new(source: D::Offset, subject: D::Offset) -> Self {
70        Self {
71            source,
72            subject,
73            domain: PhantomData,
74        }
75    }
76
77    /// Returns the position in the pattern source.
78    pub const fn source_position(&self) -> D::Offset {
79        self.source
80    }
81
82    /// Returns the position in the matched subject.
83    pub const fn subject_position(&self) -> D::Offset {
84        self.subject
85    }
86
87    /// Returns a cursor advanced to new source and subject positions.
88    pub const fn advanced(self, source: D::Offset, subject: D::Offset) -> Self {
89        Self::new(source, subject)
90    }
91}