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
use crate::error::{CoreOperation, ExpectedLength, ExpectedValid, WithContext};
use crate::input::{Bytes, PrivateExt, String};
use super::BytesReader;
impl<'i, E> BytesReader<'i, E> {
/// Read a byte.
///
/// # Errors
///
/// Returns an error if there is no more input.
#[inline]
pub fn read_u8(&mut self) -> Result<u8, E>
where
E: From<ExpectedLength<'i>>,
{
self.try_advance(|input| input.split_token(CoreOperation::ReadU8))
}
/// Read an optional byte.
///
/// Returns `Some(u8)` if there was enough input, `None` if not.
#[inline]
pub fn read_u8_opt(&mut self) -> Option<u8> {
self.advance_opt(PrivateExt::split_token_opt)
}
/// Read an array from input.
///
/// # Integers
///
/// This function can be used to read integers like so:
///
/// ```
/// use dangerous::{Input, Invalid};
///
/// let result: Result<_, Invalid> = dangerous::input(&[1, 0, 0, 0]).read_all(|r| {
/// r.read_array().map(u32::from_le_bytes)
/// });
///
/// assert_eq!(result.unwrap(), 1);
/// ```
///
/// # Errors
///
/// Returns an error if the length requirement to read could not be met.
#[inline]
pub fn read_array<const N: usize>(&mut self) -> Result<[u8; N], E>
where
E: From<ExpectedLength<'i>>,
{
self.try_advance(|input| input.split_array(CoreOperation::ReadArray))
}
/// Read an optional array.
///
/// Returns `Some([u8; N])` if there was enough input, `None` if not.
#[inline]
pub fn read_array_opt<const N: usize>(&mut self) -> Option<[u8; N]> {
self.advance_opt(Bytes::split_array_opt)
}
/// Peek the next byte in the input without mutating the `Reader`.
///
/// # Errors
///
/// Returns an error if the `Reader` has no more input.
#[inline]
pub fn peek_u8(&self) -> Result<u8, E>
where
E: From<ExpectedLength<'i>>,
{
self.input
.clone()
.split_token(CoreOperation::PeekU8)
.map(|(byte, _)| byte)
}
/// Peek the next byte in the input without mutating the `Reader`.
///
/// This is equivalent to `peek_u8` but does not return an error. Don't use
/// this function if you want an error if there isn't enough input.
#[inline]
#[must_use = "peek result must be used"]
pub fn peek_u8_opt(&self) -> Option<u8> {
self.input.clone().split_token_opt().map(|(byte, _)| byte)
}
/// Read the remaining string input.
///
/// # Errors
///
/// Returns [`ExpectedValid`] if the input could never be valid UTF-8 and
/// [`ExpectedLength`] if a UTF-8 code point was cut short.
pub fn take_remaining_str(&mut self) -> Result<String<'i>, E>
where
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
{
self.try_advance(|input| input.split_str_while(|_| true, CoreOperation::TakeRemainingStr))
}
/// Read a length of string input while a predicate check remains true.
///
/// # Errors
///
/// Returns [`ExpectedValid`] if the input could never be valid UTF-8 and
/// [`ExpectedLength`] if a UTF-8 code point was cut short.
pub fn take_str_while<F>(&mut self, pred: F) -> Result<String<'i>, E>
where
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
F: FnMut(char) -> bool,
{
self.try_advance(|input| input.split_str_while(pred, CoreOperation::TakeStrWhile))
}
/// Try read a length of string input while a predicate check remains true.
///
/// # Errors
///
/// Returns any error the provided function does, [`ExpectedValid`] if the
/// the input could never be valid UTF-8 and [`ExpectedLength`] if a UTF-8
/// code point was cut short.
pub fn try_take_str_while<F>(&mut self, pred: F) -> Result<String<'i>, E>
where
E: WithContext<'i>,
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
F: FnMut(char) -> Result<bool, E>,
{
self.try_advance(|input| input.try_split_str_while(pred, CoreOperation::TakeStrWhile))
}
/// Skip a length of string input while a predicate check remains true.
///
/// # Errors
///
/// Returns [`ExpectedValid`] if the input could never be valid UTF-8 and
/// [`ExpectedLength`] if a UTF-8 code point was cut short.
pub fn skip_str_while<F>(&mut self, pred: F) -> Result<(), E>
where
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
F: FnMut(char) -> bool,
{
self.try_advance(|input| input.split_str_while(pred, CoreOperation::SkipStrWhile))
.map(drop)
}
/// Try skip a length of string input while a predicate check remains
/// successful and true.
///
/// # Errors
///
/// Returns any error the provided function does, [`ExpectedValid`] if the
/// the input could never be valid UTF-8 and [`ExpectedLength`] if a UTF-8
/// code point was cut short.
pub fn try_skip_str_while<F>(&mut self, pred: F) -> Result<(), E>
where
E: WithContext<'i>,
E: From<ExpectedValid<'i>>,
E: From<ExpectedLength<'i>>,
F: FnMut(char) -> Result<bool, E>,
{
self.try_advance(|input| input.try_split_str_while(pred, CoreOperation::SkipStrWhile))
.map(drop)
}
}