Skip to content

Commit dd2de06

Browse files
committed
consider exposing split_at_* methods for input
1 parent e9d4b61 commit dd2de06

File tree

6 files changed

+117
-65
lines changed

6 files changed

+117
-65
lines changed

src/display/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::error::{self, Context};
22
use crate::fmt::{self, Write};
3-
use crate::input::{Bytes, Input, Private};
3+
use crate::input::{Bytes, Input};
44

55
use super::{DisplayBase, InputDisplay, PreferredFormat};
66

src/error/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ pub enum CoreOperation {
229229
SkipStrWhile,
230230
SkipUntil,
231231
SkipUntilConsume,
232+
// Splitting
233+
SplitAt,
234+
SplitAtByte,
232235
// Taking
233236
Take,
234237
TakeArray,
@@ -292,6 +295,8 @@ impl CoreOperation {
292295
Self::SkipUntil => "skip input until a pattern matches",
293296
Self::SkipUntilConsume => "skip input until a pattern matches and consume it",
294297
Self::SkipStrWhile => "skip UTF-8 input while a condition remains true",
298+
Self::SplitAt => "split input at a token index",
299+
Self::SplitAtByte => "split input at a byte index",
295300
Self::Take => "take a length of input",
296301
Self::TakeArray => "take an array of bytes",
297302
Self::TakeWhile => "take input while a pattern matches",

src/input/bytes/mod.rs

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,18 @@ impl<'i> Input<'i> for Bytes<'i> {
126126
fn display(&self) -> InputDisplay<'i> {
127127
InputDisplay::new(self)
128128
}
129+
130+
#[inline(always)]
131+
fn split_at_opt(self, mid: usize) -> Option<(Self, Self)> {
132+
slice::split_at_opt(self.as_dangerous(), mid).map(|(head, tail)| {
133+
// We split at a known length making the head input bound.
134+
let head = Bytes::new(head, self.bound().close_end());
135+
// For the tail we derive the bound constraint from self.
136+
let tail = Bytes::new(tail, self.bound());
137+
// Return the split input parts.
138+
(head, tail)
139+
})
140+
}
129141
}
130142

131143
///////////////////////////////////////////////////////////////////////////////
@@ -231,7 +243,7 @@ impl<'i> Bytes<'i> {
231243
where
232244
E: From<ExpectedLength<'i>>,
233245
{
234-
match self.split_at(N, operation) {
246+
match self.split_at_for(N, operation) {
235247
Ok((head, tail)) => {
236248
// SAFETY: safe as we took only N amount.
237249
let arr = unsafe { slice::slice_to_array_unchecked(head.as_dangerous()) };
@@ -328,18 +340,6 @@ impl<'i> Private<'i, u8> for Bytes<'i> {
328340
}
329341
}
330342

331-
#[inline(always)]
332-
fn split_at_opt(self, mid: usize) -> Option<(Self, Self)> {
333-
slice::split_at_opt(self.as_dangerous(), mid).map(|(head, tail)| {
334-
// We split at a known length making the head input bound.
335-
let head = Bytes::new(head, self.bound().close_end());
336-
// For the tail we derive the bound constraint from self.
337-
let tail = Bytes::new(tail, self.bound());
338-
// Return the split input parts.
339-
(head, tail)
340-
})
341-
}
342-
343343
#[inline(always)]
344344
unsafe fn split_at_byte_unchecked(self, mid: usize) -> (Self, Self) {
345345
let (head, tail) = slice::split_at_unchecked(self.as_dangerous(), mid);

src/input/string/mod.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,22 @@ impl<'i> Input<'i> for String<'i> {
144144
fn display(&self) -> InputDisplay<'i> {
145145
InputDisplay::new(self).str_hint()
146146
}
147+
148+
#[inline(always)]
149+
fn split_at_opt(self, mid: usize) -> Option<(Self, Self)> {
150+
let string = self.as_dangerous();
151+
let iter = &mut string.chars();
152+
if iter.nth(mid.saturating_sub(1)).is_some() {
153+
let byte_mid = string.as_bytes().len() - iter.as_str().as_bytes().len();
154+
// SAFETY: we take byte_mid as the difference between the parent
155+
// string and the remaining string left over from the char iterator.
156+
// This means both the index can only ever be valid and the bytes in
157+
// between are valid UTF-8.
158+
Some(unsafe { self.split_at_byte_unchecked(byte_mid) })
159+
} else {
160+
None
161+
}
162+
}
147163
}
148164

149165
impl<'i> Private<'i, char> for String<'i> {
@@ -184,22 +200,6 @@ impl<'i> Private<'i, char> for String<'i> {
184200
}
185201
}
186202

187-
#[inline(always)]
188-
fn split_at_opt(self, mid: usize) -> Option<(Self, Self)> {
189-
let string = self.as_dangerous();
190-
let iter = &mut string.chars();
191-
if iter.nth(mid.saturating_sub(1)).is_some() {
192-
let byte_mid = string.as_bytes().len() - iter.as_str().as_bytes().len();
193-
// SAFETY: we take byte_mid as the difference between the parent
194-
// string and the remaining string left over from the char iterator.
195-
// This means both the index can only ever be valid and the bytes in
196-
// between are valid UTF-8.
197-
Some(unsafe { self.split_at_byte_unchecked(byte_mid) })
198-
} else {
199-
None
200-
}
201-
}
202-
203203
#[inline(always)]
204204
unsafe fn split_at_byte_unchecked(self, mid: usize) -> (Self, Self) {
205205
let (head, tail) = slice::split_str_at_unchecked(self.as_dangerous(), mid);

src/input/traits.rs

Lines changed: 64 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,54 @@ pub trait Input<'i>: Private<'i, Self::Token> {
7676
/// Returns an [`InputDisplay`] for formatting.
7777
fn display(&self) -> InputDisplay<'i>;
7878

79+
/// Splits the input into two at the token index `mid`.
80+
///
81+
/// # Errors
82+
///
83+
/// Returns an error if `mid > self.len()`.
84+
#[inline]
85+
fn split_at<E>(self, mid: usize) -> Result<(Self, Self), E>
86+
where
87+
E: From<ExpectedLength<'i>>,
88+
{
89+
self.split_at_for(mid, CoreOperation::SplitAt)
90+
}
91+
92+
/// Splits the input into two at the token index `mid`.
93+
///
94+
/// Returns `Some(Self)` if `mid` is a valid token index, `None` if `mid` is
95+
/// out of bounds.
96+
fn split_at_opt(self, mid: usize) -> Option<(Self, Self)>;
97+
98+
/// Splits the input into two at the byte index `mid`.
99+
///
100+
/// # Errors
101+
///
102+
/// Returns [`ExpectedLength`] if `mid > self.len()` and [`ExpectedValid`]
103+
/// if `mid` is not a valid token boundary.
104+
#[inline]
105+
fn split_at_byte<E>(self, mid: usize) -> Result<(Self, Self), E>
106+
where
107+
E: From<ExpectedValid<'i>>,
108+
E: From<ExpectedLength<'i>>,
109+
{
110+
self.split_at_byte_for(mid, CoreOperation::SplitAtByte)
111+
}
112+
113+
/// Splits the input into two at the byte index `mid`.
114+
///
115+
/// Returns `Some(Self)` if `mid` is a valid token index, `None` if `mid` is
116+
/// out of bounds or not a valid token boundary.
117+
fn split_at_byte_opt(self, mid: usize) -> Option<(Self, Self)> {
118+
if self.verify_token_boundary(mid).is_ok() {
119+
// SAFETY: we verified that the index is a token boundary so this is
120+
// safe.
121+
unsafe { Some(self.split_at_byte_unchecked(mid)) }
122+
} else {
123+
None
124+
}
125+
}
126+
79127
///////////////////////////////////////////////////////////////////////////
80128
// Provided methods
81129

@@ -271,11 +319,6 @@ pub trait Private<'i, Token>: Sized + Clone + DisplayBase + Debug + Display {
271319
/// Returns what was expected at that index.
272320
fn verify_token_boundary(&self, index: usize) -> Result<(), CoreExpected>;
273321

274-
/// Split the input at the token index `mid`.
275-
///
276-
/// Return `Some` if mid is a valid index, `None` if not.
277-
fn split_at_opt(self, mid: usize) -> Option<(Self, Self)>;
278-
279322
/// Splits the input at the byte index `mid` without any validation.
280323
///
281324
/// # Safety
@@ -300,7 +343,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
300343
///
301344
/// Returns an error if `mid > self.len()`.
302345
#[inline(always)]
303-
fn split_at<E>(self, mid: usize, operation: CoreOperation) -> Result<(Self, Self), E>
346+
fn split_at_for<E>(self, mid: usize, operation: CoreOperation) -> Result<(Self, Self), E>
304347
where
305348
E: From<ExpectedLength<'i>>,
306349
{
@@ -325,7 +368,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
325368
/// Returns [`ExpectedLength`] if `mid > self.len()` and [`ExpectedValid`]
326369
/// if `mid` is not a valid token boundary.
327370
#[inline(always)]
328-
fn split_at_byte<E>(self, mid: usize, operation: CoreOperation) -> Result<(Self, Self), E>
371+
fn split_at_byte_for<E>(self, mid: usize, operation: CoreOperation) -> Result<(Self, Self), E>
329372
where
330373
E: From<ExpectedValid<'i>>,
331374
E: From<ExpectedLength<'i>>,
@@ -379,7 +422,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
379422
///
380423
/// Returns an error if the input is empty.
381424
#[inline(always)]
382-
fn split_token<E>(self, operation: CoreOperation) -> Result<(Self::Token, Self), E>
425+
fn split_token_for<E>(self, operation: CoreOperation) -> Result<(Self::Token, Self), E>
383426
where
384427
E: From<ExpectedLength<'i>>,
385428
{
@@ -419,7 +462,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
419462
///
420463
/// Returns an error if the input does not have the prefix.
421464
#[inline(always)]
422-
fn split_prefix<P, E>(self, prefix: P, operation: CoreOperation) -> Result<(Self, Self), E>
465+
fn split_prefix_for<P, E>(self, prefix: P, operation: CoreOperation) -> Result<(Self, Self), E>
423466
where
424467
E: From<ExpectedValue<'i>>,
425468
P: Prefix<Self> + Into<Value<'i>>,
@@ -475,7 +518,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
475518

476519
/// Splits the input up to when the pattern matches.
477520
#[inline(always)]
478-
fn split_until<P, E>(self, pattern: P, operation: CoreOperation) -> Result<(Self, Self), E>
521+
fn split_until_for<P, E>(self, pattern: P, operation: CoreOperation) -> Result<(Self, Self), E>
479522
where
480523
E: From<ExpectedValue<'i>>,
481524
P: Pattern<Self> + Into<Value<'i>> + Copy,
@@ -499,7 +542,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
499542
///
500543
/// Returns an error if the input does not have the pattern.
501544
#[inline(always)]
502-
fn split_until_consume<P, E>(
545+
fn split_until_consume_for<P, E>(
503546
self,
504547
pattern: P,
505548
operation: CoreOperation,
@@ -542,7 +585,11 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
542585
///
543586
/// Returns an error from the provided function if it fails.
544587
#[inline(always)]
545-
fn try_split_while<F, E>(self, mut f: F, operation: CoreOperation) -> Result<(Self, Self), E>
588+
fn try_split_while_for<F, E>(
589+
self,
590+
mut f: F,
591+
operation: CoreOperation,
592+
) -> Result<(Self, Self), E>
546593
where
547594
E: WithContext<'i>,
548595
F: FnMut(Self::Token) -> Result<bool, E>,
@@ -602,7 +649,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
602649
///
603650
/// Returns an error from the provided function if it fails.
604651
#[inline(always)]
605-
fn try_split_consumed<F, T, E>(
652+
fn try_split_consumed_for<F, T, E>(
606653
self,
607654
f: F,
608655
operation: CoreOperation,
@@ -639,7 +686,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
639686
///
640687
/// Returns an error if the expected value was not present.
641688
#[inline(always)]
642-
fn split_expect<F, T, E>(
689+
fn split_expect_for<F, T, E>(
643690
self,
644691
f: F,
645692
expected: &'static str,
@@ -674,7 +721,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
674721
/// Returns an error from the provided function if it fails or if the
675722
/// expected value was not present.
676723
#[inline(always)]
677-
fn try_split_expect<F, T, E>(
724+
fn try_split_expect_for<F, T, E>(
678725
self,
679726
f: F,
680727
expected: &'static str,
@@ -727,7 +774,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
727774
/// - the provided function returns an amount of input read that is greater
728775
/// than the actual length
729776
#[inline(always)]
730-
fn try_split_external<F, T, E, Ex>(
777+
fn try_split_external_for<F, T, E, Ex>(
731778
self,
732779
f: F,
733780
expected: &'static str,
@@ -742,7 +789,7 @@ pub(crate) trait PrivateExt<'i>: Input<'i> {
742789
{
743790
match f(self.clone()) {
744791
Ok((read, ok)) => self
745-
.split_at_byte(read, operation)
792+
.split_at_byte_for(read, operation)
746793
.map(|(_, remaining)| (ok, remaining)),
747794
Err(external) => Err(self.map_external_error(external, expected, operation)),
748795
}

0 commit comments

Comments
 (0)