1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#![warn(missing_docs)]
#![doc = include_str!("../docs.md")]

mod parser;
pub use parser::*;

pub mod combinators;
#[cfg(feature = "builtins")] 
pub mod builtins;

///Implicit [`Infallible`] conversions.
///
///[`Infallible`]: std::convert::Infallible
pub use nevermore::FromNever;

#[cfg(test)]
mod tests;

use std::{cell::Cell, fmt::{Debug, Display}};
///A shrinking-window read-only string.
///
///String slices can be taken from the front, and reset, with zero
///allocations or copies.
pub struct ParserString {
    full: Box<str>,
    ptr: Cell<usize>,
}

fn update<T: Copy, F: Fn(T) -> T>(cell: &Cell<T>, f: F) {
    let a = cell.get();
    cell.set(f(a));
}

impl ParserString {
    ///Splits the string at `n`, shrinking it. Panics if `n` is larger than the remaining slice.
    ///```rust
    ///# use parsa::ParserString;
    ///let mut input = ParserString::from("abc123");
    ///
    ///assert_eq!(input.take(3), "abc");
    ///assert_eq!(input.take(3), "123");
    ///
    /////valid utf-8
    ///let mut input = ParserString::from("🗻∈🌏");
    ///assert_eq!(input.take(2), "🗻∈");
    ///assert_eq!(input.take(1), "🌏");
    ///```
    pub fn take(&mut self, n: usize) -> &str {
        let offs = self.get().chars()
            .take(n).map(char::len_utf8).sum();

        let (front, _) = self.get().split_at(offs);

        update(&self.ptr, |ptr| ptr + offs);

        assert!(self.ptr.get() <= self.full.len());

        front
    }

    ///Splits the string at `n`, shrinking it. Returns [`None`] if `n` is larger than the remaining slice.
    ///```rust
    ///# use parsa::ParserString;
    ///let mut input = ParserString::from("abc123");
    ///assert_eq!(input.try_take(5), Some("abc12"));
    ///assert_eq!(input.try_take(5), None);
    ///
    ///```
    pub fn try_take(&mut self, n: usize) -> Option<&str> {
        if self.ptr.get() + n > self.full.len() {
            return None;
        }

        let offs = self.get().chars()
            .take(n).map(char::len_utf8).sum();

        let (front, _) = self.get().split_at(offs);
        update(&self.ptr, |ptr| ptr + offs);
        Some(front)
    }

    ///Rewinds the string slice `n` spaces. Panics if `n` is larger than the taken space.    
    ///```rust
    ///# use parsa::ParserString;
    ///let mut input = ParserString::from("abc123");
    ///
    ///assert_eq!(input.take(3), "abc");
    ///
    ///unsafe { input.give(3); }
    ///
    ///assert_eq!(input.take(3), "abc");
    ///assert_eq!(input.take(3), "123");
    ///```
    ///# Safety
    ///Caller must assure that the resulting pointer lands on a UTF-8 code point.
    ///This library assumes that a function will never add back more than its taken, and thus is
    ///considered undefined behavior. This will never cause memory-unsafety, but can cause
    ///unpredictable things to happen.
    pub unsafe fn give(&mut self, n: usize) {
        *self.ptr.get_mut() -= n;
    }

    ///Set the current start position manually.
    ///# Safety
    ///Caller must assure that the resulting pointer lands on a UTF-8 code point.
    ///```rust
    ///# use parsa::ParserString;
    ///let mut input = ParserString::from("abc123");
    ///unsafe { input.set_ptr(3); }
    ///assert_eq!(input.get(), "123");
    ///```
    pub unsafe fn set_ptr(&mut self, ptr: usize) {
        self.ptr.set(ptr);
    }

    ///Get a reference to the string slice.
    ///```rust
    ///# use parsa::ParserString;
    ///let mut input = ParserString::from("abc123");
    ///let _ = input.take(2);
    ///
    ///assert_eq!(input.get(), "c123");
    ///```
    pub fn get(&self) -> &str {
        &self.full[self.ptr.get()..]
    }

    ///Get the length of the string.
    ///```rust
    ///# use parsa::ParserString;
    ///let mut input = ParserString::from("abc123");
    ///let _ = input.take(2);
    ///assert_eq!(input.len(), 4);
    ///```
    pub fn len(&self) -> usize {
        self.full.len() - self.ptr.get()
    }

    ///Get the current start of the string, relative to the "true" start.
    ///```rust
    ///# use parsa::ParserString;
    ///let mut input = ParserString::from("abc123");
    ///let _ = input.take(2);
    ///assert_eq!(input.start(), 2);
    ///```
    pub fn start(&self) -> usize {
        self.ptr.get()
    }
}

impl From<&str> for ParserString {
    fn from(value: &str) -> Self {
        Self {
            full: Box::from(value),
            ptr: Cell::new(0),
        }
    }
}

impl From<String> for ParserString {
    fn from(value: String) -> Self {
        Self {
            full: value.into_boxed_str(),
            ptr: Cell::new(0),
        }
    }
}

impl Debug for ParserString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}", self.get())
    }
}

impl Display for ParserString {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.get())
    }
}