/rust/registry/src/github.com-1ecc6299db9ec823/nom-5.1.2/src/bytes/complete.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! parsers recognizing bytes streams, complete input version |
2 | | |
3 | | use crate::error::ErrorKind; |
4 | | use crate::error::ParseError; |
5 | | use crate::internal::{Err, IResult}; |
6 | | use crate::lib::std::ops::RangeFrom; |
7 | | use crate::lib::std::result::Result::*; |
8 | | use crate::traits::{Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputTake, InputTakeAtPosition, Slice, ToUsize}; |
9 | | |
10 | | /// Recognizes a pattern |
11 | | /// |
12 | | /// The input data will be compared to the tag combinator's argument and will return the part of |
13 | | /// the input that matches the argument |
14 | | /// |
15 | | /// It will return `Err(Err::Error((_, ErrorKind::Tag)))` if the input doesn't match the pattern |
16 | | /// # Example |
17 | | /// ```rust |
18 | | /// # #[macro_use] extern crate nom; |
19 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
20 | | /// use nom::bytes::complete::tag; |
21 | | /// |
22 | | /// fn parser(s: &str) -> IResult<&str, &str> { |
23 | | /// tag("Hello")(s) |
24 | | /// } |
25 | | /// |
26 | | /// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); |
27 | | /// assert_eq!(parser("Something"), Err(Err::Error(("Something", ErrorKind::Tag)))); |
28 | | /// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag)))); |
29 | | /// ``` |
30 | 19.2k | pub fn tag<'a, T: 'a, Input: 'a, Error: ParseError<Input>>(tag: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
31 | 19.2k | where |
32 | 19.2k | Input: InputTake + Compare<T>, |
33 | 19.2k | T: InputLength + Clone, |
34 | 19.2k | { |
35 | 19.2k | move |i: Input| { |
36 | 19.2k | let tag_len = tag.input_len(); |
37 | 19.2k | let t = tag.clone(); |
38 | 19.2k | let res: IResult<_, _, Error> = match i.compare(t) { |
39 | 3 | CompareResult::Ok => Ok(i.take_split(tag_len)), |
40 | | _ => { |
41 | 19.2k | let e: ErrorKind = ErrorKind::Tag; |
42 | 19.2k | Err(Err::Error(Error::from_error_kind(i, e))) |
43 | | } |
44 | | }; |
45 | 19.2k | res |
46 | 19.2k | } Unexecuted instantiation: nom::bytes::complete::tag::<&str, &[u8], (&[u8], nom::error::ErrorKind)>::{closure#0} nom::bytes::complete::tag::<&str, &str, (&str, nom::error::ErrorKind)>::{closure#0} Line | Count | Source | 35 | 19.2k | move |i: Input| { | 36 | 19.2k | let tag_len = tag.input_len(); | 37 | 19.2k | let t = tag.clone(); | 38 | 19.2k | let res: IResult<_, _, Error> = match i.compare(t) { | 39 | 3 | CompareResult::Ok => Ok(i.take_split(tag_len)), | 40 | | _ => { | 41 | 19.2k | let e: ErrorKind = ErrorKind::Tag; | 42 | 19.2k | Err(Err::Error(Error::from_error_kind(i, e))) | 43 | | } | 44 | | }; | 45 | 19.2k | res | 46 | 19.2k | } |
|
47 | 19.2k | } Unexecuted instantiation: nom::bytes::complete::tag::<&str, &[u8], (&[u8], nom::error::ErrorKind)> nom::bytes::complete::tag::<&str, &str, (&str, nom::error::ErrorKind)> Line | Count | Source | 30 | 19.2k | pub fn tag<'a, T: 'a, Input: 'a, Error: ParseError<Input>>(tag: T) -> impl Fn(Input) -> IResult<Input, Input, Error> | 31 | 19.2k | where | 32 | 19.2k | Input: InputTake + Compare<T>, | 33 | 19.2k | T: InputLength + Clone, | 34 | 19.2k | { | 35 | | move |i: Input| { | 36 | | let tag_len = tag.input_len(); | 37 | | let t = tag.clone(); | 38 | | let res: IResult<_, _, Error> = match i.compare(t) { | 39 | | CompareResult::Ok => Ok(i.take_split(tag_len)), | 40 | | _ => { | 41 | | let e: ErrorKind = ErrorKind::Tag; | 42 | | Err(Err::Error(Error::from_error_kind(i, e))) | 43 | | } | 44 | | }; | 45 | | res | 46 | | } | 47 | 19.2k | } |
|
48 | | |
49 | | /// Recognizes a case insensitive pattern |
50 | | /// |
51 | | /// The input data will be compared to the tag combinator's argument and will return the part of |
52 | | /// the input that matches the argument with no regard to case |
53 | | /// |
54 | | /// It will return `Err(Err::Error((_, ErrorKind::Tag)))` if the input doesn't match the pattern |
55 | | /// # Example |
56 | | /// ```rust |
57 | | /// # #[macro_use] extern crate nom; |
58 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
59 | | /// use nom::bytes::complete::tag_no_case; |
60 | | /// |
61 | | /// fn parser(s: &str) -> IResult<&str, &str> { |
62 | | /// tag_no_case("hello")(s) |
63 | | /// } |
64 | | /// |
65 | | /// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); |
66 | | /// assert_eq!(parser("hello, World!"), Ok((", World!", "hello"))); |
67 | | /// assert_eq!(parser("HeLlO, World!"), Ok((", World!", "HeLlO"))); |
68 | | /// assert_eq!(parser("Something"), Err(Err::Error(("Something", ErrorKind::Tag)))); |
69 | | /// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag)))); |
70 | | /// ``` |
71 | | pub fn tag_no_case<T, Input, Error: ParseError<Input>>(tag: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
72 | | where |
73 | | Input: InputTake + Compare<T>, |
74 | | T: InputLength + Clone, |
75 | | { |
76 | | move |i: Input| { |
77 | | let tag_len = tag.input_len(); |
78 | | let t = tag.clone(); |
79 | | |
80 | | let res: IResult<_, _, Error> = match (i).compare_no_case(t) { |
81 | | CompareResult::Ok => Ok(i.take_split(tag_len)), |
82 | | _ => { |
83 | | let e: ErrorKind = ErrorKind::Tag; |
84 | | Err(Err::Error(Error::from_error_kind(i, e))) |
85 | | } |
86 | | }; |
87 | | res |
88 | | } |
89 | | } |
90 | | |
91 | | /// Parse till certain characters are met |
92 | | /// |
93 | | /// The parser will return the longest slice till one of the characters of the combinator's argument are met. |
94 | | /// |
95 | | /// It doesn't consume the matched character, |
96 | | /// |
97 | | /// It will return a `Err::Error(("", ErrorKind::IsNot))` if the pattern wasn't met |
98 | | /// # Example |
99 | | /// ```rust |
100 | | /// # #[macro_use] extern crate nom; |
101 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
102 | | /// use nom::bytes::complete::is_not; |
103 | | /// |
104 | | /// fn not_space(s: &str) -> IResult<&str, &str> { |
105 | | /// is_not(" \t\r\n")(s) |
106 | | /// } |
107 | | /// |
108 | | /// assert_eq!(not_space("Hello, World!"), Ok((" World!", "Hello,"))); |
109 | | /// assert_eq!(not_space("Sometimes\t"), Ok(("\t", "Sometimes"))); |
110 | | /// assert_eq!(not_space("Nospace"), Ok(("", "Nospace"))); |
111 | | /// assert_eq!(not_space(""), Err(Err::Error(("", ErrorKind::IsNot)))); |
112 | | /// ``` |
113 | | pub fn is_not<T, Input, Error: ParseError<Input>>(arr: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
114 | | where |
115 | | Input: InputTakeAtPosition, |
116 | | T: InputLength + FindToken<<Input as InputTakeAtPosition>::Item>, |
117 | | { |
118 | | move |i: Input| { |
119 | | let e: ErrorKind = ErrorKind::IsNot; |
120 | | i.split_at_position1_complete(|c| arr.find_token(c), e) |
121 | | } |
122 | | } |
123 | | |
124 | | /// Returns the longest slice of the matches the pattern |
125 | | /// |
126 | | /// The parser will return the longest slice consisting of the characters in provided in the |
127 | | /// combinator's argument |
128 | | /// |
129 | | /// It will return a `Err(Err::Error((_, ErrorKind::IsA)))` if the pattern wasn't met |
130 | | /// |
131 | | /// # Example |
132 | | /// ```rust |
133 | | /// # #[macro_use] extern crate nom; |
134 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
135 | | /// use nom::bytes::complete::is_a; |
136 | | /// |
137 | | /// fn hex(s: &str) -> IResult<&str, &str> { |
138 | | /// is_a("1234567890ABCDEF")(s) |
139 | | /// } |
140 | | /// |
141 | | /// assert_eq!(hex("123 and voila"), Ok((" and voila", "123"))); |
142 | | /// assert_eq!(hex("DEADBEEF and others"), Ok((" and others", "DEADBEEF"))); |
143 | | /// assert_eq!(hex("BADBABEsomething"), Ok(("something", "BADBABE"))); |
144 | | /// assert_eq!(hex("D15EA5E"), Ok(("", "D15EA5E"))); |
145 | | /// assert_eq!(hex(""), Err(Err::Error(("", ErrorKind::IsA)))); |
146 | | /// ``` |
147 | | pub fn is_a<T, Input, Error: ParseError<Input>>(arr: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
148 | | where |
149 | | Input: InputTakeAtPosition, |
150 | | T: InputLength + FindToken<<Input as InputTakeAtPosition>::Item>, |
151 | | { |
152 | | move |i: Input| { |
153 | | let e: ErrorKind = ErrorKind::IsA; |
154 | | i.split_at_position1_complete(|c| !arr.find_token(c), e) |
155 | | } |
156 | | } |
157 | | |
158 | | /// Returns the longest input slice (if any) that matches the predicate |
159 | | /// |
160 | | /// The parser will return the longest slice that matches the given predicate *(a function that |
161 | | /// takes the input and returns a bool)* |
162 | | /// |
163 | | /// # Example |
164 | | /// ```rust |
165 | | /// # #[macro_use] extern crate nom; |
166 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
167 | | /// use nom::bytes::complete::take_while; |
168 | | /// use nom::character::is_alphabetic; |
169 | | /// |
170 | | /// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { |
171 | | /// take_while(is_alphabetic)(s) |
172 | | /// } |
173 | | /// |
174 | | /// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
175 | | /// assert_eq!(alpha(b"12345"), Ok((&b"12345"[..], &b""[..]))); |
176 | | /// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
177 | | /// assert_eq!(alpha(b""), Ok((&b""[..], &b""[..]))); |
178 | | /// ``` |
179 | | pub fn take_while<F, Input, Error: ParseError<Input>>(cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
180 | | where |
181 | | Input: InputTakeAtPosition, |
182 | | F: Fn(<Input as InputTakeAtPosition>::Item) -> bool, |
183 | | { |
184 | | move |i: Input| i.split_at_position_complete(|c| !cond(c)) |
185 | | } |
186 | | |
187 | | /// Returns the longest (atleast 1) input slice that matches the predicate |
188 | | /// |
189 | | /// The parser will return the longest slice that matches the given predicate *(a function that |
190 | | /// takes the input and returns a bool)* |
191 | | /// |
192 | | /// It will return an `Err(Err::Error((_, ErrorKind::TakeWhile1)))` if the pattern wasn't met |
193 | | /// |
194 | | /// # Example |
195 | | /// ```rust |
196 | | /// # #[macro_use] extern crate nom; |
197 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
198 | | /// use nom::bytes::complete::take_while1; |
199 | | /// use nom::character::is_alphabetic; |
200 | | /// |
201 | | /// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { |
202 | | /// take_while1(is_alphabetic)(s) |
203 | | /// } |
204 | | /// |
205 | | /// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
206 | | /// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
207 | | /// assert_eq!(alpha(b"12345"), Err(Err::Error((&b"12345"[..], ErrorKind::TakeWhile1)))); |
208 | | /// ``` |
209 | 0 | pub fn take_while1<F, Input, Error: ParseError<Input>>(cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
210 | 0 | where |
211 | 0 | Input: InputTakeAtPosition, |
212 | 0 | F: Fn(<Input as InputTakeAtPosition>::Item) -> bool, |
213 | 0 | { |
214 | 0 | move |i: Input| { |
215 | 0 | let e: ErrorKind = ErrorKind::TakeWhile1; |
216 | 0 | i.split_at_position1_complete(|c| !cond(c), e) |
217 | 0 | } |
218 | 0 | } |
219 | | |
220 | | /// Returns the longest (m <= len <= n) input slice that matches the predicate |
221 | | /// |
222 | | /// The parser will return the longest slice that matches the given predicate *(a function that |
223 | | /// takes the input and returns a bool)* |
224 | | /// |
225 | | /// It will return an `Err::Error((_, ErrorKind::TakeWhileMN))` if the pattern wasn't met or is out |
226 | | /// of range (m <= len <= n) |
227 | | /// |
228 | | /// # Example |
229 | | /// ```rust |
230 | | /// # #[macro_use] extern crate nom; |
231 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
232 | | /// use nom::bytes::complete::take_while_m_n; |
233 | | /// use nom::character::is_alphabetic; |
234 | | /// |
235 | | /// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { |
236 | | /// take_while_m_n(3, 6, is_alphabetic)(s) |
237 | | /// } |
238 | | /// |
239 | | /// assert_eq!(short_alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
240 | | /// assert_eq!(short_alpha(b"lengthy"), Ok((&b"y"[..], &b"length"[..]))); |
241 | | /// assert_eq!(short_alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
242 | | /// assert_eq!(short_alpha(b"ed"), Err(Err::Error((&b"ed"[..], ErrorKind::TakeWhileMN)))); |
243 | | /// assert_eq!(short_alpha(b"12345"), Err(Err::Error((&b"12345"[..], ErrorKind::TakeWhileMN)))); |
244 | | /// ``` |
245 | | pub fn take_while_m_n<F, Input, Error: ParseError<Input>>(m: usize, n: usize, cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
246 | | where |
247 | | Input: InputTake + InputIter + InputLength + Slice<RangeFrom<usize>>, |
248 | | F: Fn(<Input as InputIter>::Item) -> bool, |
249 | | { |
250 | | move |i: Input| { |
251 | | let input = i; |
252 | | |
253 | | match input.position(|c| !cond(c)) { |
254 | | Some(idx) => { |
255 | | if idx >= m { |
256 | | if idx <= n { |
257 | | let res: IResult<_, _, Error> = if let Some(index) = input.slice_index(idx) { |
258 | | Ok(input.take_split(index)) |
259 | | } else { |
260 | | Err(Err::Error(Error::from_error_kind(input, ErrorKind::TakeWhileMN))) |
261 | | }; |
262 | | res |
263 | | } else { |
264 | | let res: IResult<_, _, Error> = if let Some(index) = input.slice_index(n) { |
265 | | Ok(input.take_split(index)) |
266 | | } else { |
267 | | Err(Err::Error(Error::from_error_kind(input, ErrorKind::TakeWhileMN))) |
268 | | }; |
269 | | res |
270 | | } |
271 | | } else { |
272 | | let e = ErrorKind::TakeWhileMN; |
273 | | Err(Err::Error(Error::from_error_kind(input, e))) |
274 | | } |
275 | | } |
276 | | None => { |
277 | | let len = input.input_len(); |
278 | | if len >= n { |
279 | | match input.slice_index(n) { |
280 | | Some(index) => Ok(input.take_split(index)), |
281 | | None => Err(Err::Error(Error::from_error_kind(input, ErrorKind::TakeWhileMN))) |
282 | | } |
283 | | } else { |
284 | | if len >= m && len <= n { |
285 | | let res: IResult<_, _, Error> = Ok((input.slice(len..), input)); |
286 | | res |
287 | | } else { |
288 | | let e = ErrorKind::TakeWhileMN; |
289 | | Err(Err::Error(Error::from_error_kind(input, e))) |
290 | | } |
291 | | } |
292 | | } |
293 | | } |
294 | | } |
295 | | } |
296 | | |
297 | | /// Returns the longest input slice (if any) till a predicate is met |
298 | | /// |
299 | | /// The parser will return the longest slice till the given predicate *(a function that |
300 | | /// takes the input and returns a bool)* |
301 | | /// |
302 | | /// # Example |
303 | | /// ```rust |
304 | | /// # #[macro_use] extern crate nom; |
305 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
306 | | /// use nom::bytes::complete::take_till; |
307 | | /// |
308 | | /// fn till_colon(s: &str) -> IResult<&str, &str> { |
309 | | /// take_till(|c| c == ':')(s) |
310 | | /// } |
311 | | /// |
312 | | /// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); |
313 | | /// assert_eq!(till_colon(":empty matched"), Ok((":empty matched", ""))); //allowed |
314 | | /// assert_eq!(till_colon("12345"), Ok(("", "12345"))); |
315 | | /// assert_eq!(till_colon(""), Ok(("", ""))); |
316 | | /// ``` |
317 | | pub fn take_till<F, Input, Error: ParseError<Input>>(cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
318 | | where |
319 | | Input: InputTakeAtPosition, |
320 | | F: Fn(<Input as InputTakeAtPosition>::Item) -> bool, |
321 | | { |
322 | | move |i: Input| i.split_at_position_complete(|c| cond(c)) |
323 | | } |
324 | | |
325 | | /// Returns the longest (atleast 1) input slice till a predicate is met |
326 | | /// |
327 | | /// The parser will return the longest slice till the given predicate *(a function that |
328 | | /// takes the input and returns a bool)* |
329 | | /// |
330 | | /// It will return `Err(Err::Error((_, ErrorKind::TakeTill1)))` if the input is empty or the |
331 | | /// predicate matches the first input |
332 | | /// |
333 | | /// # Example |
334 | | /// ```rust |
335 | | /// # #[macro_use] extern crate nom; |
336 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
337 | | /// use nom::bytes::complete::take_till1; |
338 | | /// |
339 | | /// fn till_colon(s: &str) -> IResult<&str, &str> { |
340 | | /// take_till1(|c| c == ':')(s) |
341 | | /// } |
342 | | /// |
343 | | /// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); |
344 | | /// assert_eq!(till_colon(":empty matched"), Err(Err::Error((":empty matched", ErrorKind::TakeTill1)))); |
345 | | /// assert_eq!(till_colon("12345"), Ok(("", "12345"))); |
346 | | /// assert_eq!(till_colon(""), Err(Err::Error(("", ErrorKind::TakeTill1)))); |
347 | | /// ``` |
348 | | pub fn take_till1<F, Input, Error: ParseError<Input>>(cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
349 | | where |
350 | | Input: InputTakeAtPosition, |
351 | | F: Fn(<Input as InputTakeAtPosition>::Item) -> bool, |
352 | | { |
353 | | move |i: Input| { |
354 | | let e: ErrorKind = ErrorKind::TakeTill1; |
355 | | i.split_at_position1_complete(|c| cond(c), e) |
356 | | } |
357 | | } |
358 | | |
359 | | /// Returns an input slice containing the first N input elements (Input[..N]) |
360 | | /// |
361 | | /// It will return `Err(Err::Error((_, ErrorKind::Eof)))` if the input is shorter than the argument |
362 | | /// |
363 | | /// # Example |
364 | | /// ```rust |
365 | | /// # #[macro_use] extern crate nom; |
366 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
367 | | /// use nom::bytes::complete::take; |
368 | | /// |
369 | | /// fn take6(s: &str) -> IResult<&str, &str> { |
370 | | /// take(6usize)(s) |
371 | | /// } |
372 | | /// |
373 | | /// assert_eq!(take6("1234567"), Ok(("7", "123456"))); |
374 | | /// assert_eq!(take6("things"), Ok(("", "things"))); |
375 | | /// assert_eq!(take6("short"), Err(Err::Error(("short", ErrorKind::Eof)))); |
376 | | /// assert_eq!(take6(""), Err(Err::Error(("", ErrorKind::Eof)))); |
377 | | /// ``` |
378 | 0 | pub fn take<C, Input, Error: ParseError<Input>>(count: C) -> impl Fn(Input) -> IResult<Input, Input, Error> |
379 | 0 | where |
380 | 0 | Input: InputIter + InputTake, |
381 | 0 | C: ToUsize, |
382 | 0 | { |
383 | 0 | let c = count.to_usize(); |
384 | 0 | move |i: Input| match i.slice_index(c) { |
385 | 0 | None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::Eof))), |
386 | 0 | Some(index) => Ok(i.take_split(index)), |
387 | 0 | } |
388 | 0 | } |
389 | | |
390 | | /// Returns the longest input slice till it matches the pattern. |
391 | | /// |
392 | | /// It doesn't consume the pattern. It will return `Err(Err::Error((_, ErrorKind::TakeUntil)))` |
393 | | /// if the pattern wasn't met |
394 | | /// |
395 | | /// # Example |
396 | | /// ```rust |
397 | | /// # #[macro_use] extern crate nom; |
398 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
399 | | /// use nom::bytes::complete::take_until; |
400 | | /// |
401 | | /// fn until_eof(s: &str) -> IResult<&str, &str> { |
402 | | /// take_until("eof")(s) |
403 | | /// } |
404 | | /// |
405 | | /// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); |
406 | | /// assert_eq!(until_eof("hello, world"), Err(Err::Error(("hello, world", ErrorKind::TakeUntil)))); |
407 | | /// assert_eq!(until_eof(""), Err(Err::Error(("", ErrorKind::TakeUntil)))); |
408 | | /// ``` |
409 | | pub fn take_until<T, Input, Error: ParseError<Input>>(tag: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
410 | | where |
411 | | Input: InputTake + FindSubstring<T>, |
412 | | T: InputLength + Clone, |
413 | | { |
414 | | move |i: Input| { |
415 | | let t = tag.clone(); |
416 | | let res: IResult<_, _, Error> = match i.find_substring(t) { |
417 | | None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))), |
418 | | Some(index) => Ok(i.take_split(index)), |
419 | | }; |
420 | | res |
421 | | } |
422 | | } |
423 | | |
424 | | /// Matches a byte string with escaped characters. |
425 | | /// |
426 | | /// * The first argument matches the normal characters (it must not accept the control character), |
427 | | /// * the second argument is the control character (like `\` in most languages), |
428 | | /// * the third argument matches the escaped characters |
429 | | /// |
430 | | /// # Example |
431 | | /// ``` |
432 | | /// # #[macro_use] extern crate nom; |
433 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
434 | | /// # use nom::character::complete::digit1; |
435 | | /// use nom::bytes::complete::escaped; |
436 | | /// use nom::character::complete::one_of; |
437 | | /// |
438 | | /// fn esc(s: &str) -> IResult<&str, &str> { |
439 | | /// escaped(digit1, '\\', one_of(r#""n\"#))(s) |
440 | | /// } |
441 | | /// |
442 | | /// assert_eq!(esc("123;"), Ok((";", "123"))); |
443 | | /// assert_eq!(esc(r#"12\"34;"#), Ok((";", r#"12\"34"#))); |
444 | | /// ``` |
445 | | /// |
446 | | pub fn escaped<Input, Error, F, G, O1, O2>(normal: F, control_char: char, escapable: G) -> impl Fn(Input) -> IResult<Input, Input, Error> |
447 | | where |
448 | | Input: Clone + crate::traits::Offset + InputLength + InputTake + InputTakeAtPosition + Slice<RangeFrom<usize>> + InputIter, |
449 | | <Input as InputIter>::Item: crate::traits::AsChar, |
450 | | F: Fn(Input) -> IResult<Input, O1, Error>, |
451 | | G: Fn(Input) -> IResult<Input, O2, Error>, |
452 | | Error: ParseError<Input>, |
453 | | { |
454 | | use crate::traits::AsChar; |
455 | | |
456 | | move |input: Input| { |
457 | | let mut i = input.clone(); |
458 | | |
459 | | while i.input_len() > 0 { |
460 | | match normal(i.clone()) { |
461 | | Ok((i2, _)) => { |
462 | | if i2.input_len() == 0 { |
463 | | return Ok((input.slice(input.input_len()..), input)); |
464 | | } else { |
465 | | i = i2; |
466 | | } |
467 | | } |
468 | | Err(Err::Error(_)) => { |
469 | | // unwrap() should be safe here since index < $i.input_len() |
470 | | if i.iter_elements().next().unwrap().as_char() == control_char { |
471 | | let next = control_char.len_utf8(); |
472 | | if next >= i.input_len() { |
473 | | return Err(Err::Error(Error::from_error_kind(input, ErrorKind::Escaped))); |
474 | | } else { |
475 | | match escapable(i.slice(next..)) { |
476 | | Ok((i2, _)) => { |
477 | | if i2.input_len() == 0 { |
478 | | return Ok((input.slice(input.input_len()..), input)); |
479 | | } else { |
480 | | i = i2; |
481 | | } |
482 | | } |
483 | | Err(e) => return Err(e), |
484 | | } |
485 | | } |
486 | | } else { |
487 | | let index = input.offset(&i); |
488 | | if index == 0 { |
489 | | return Err(Err::Error(Error::from_error_kind(input, ErrorKind::Escaped))); |
490 | | } |
491 | | return Ok(input.take_split(index)); |
492 | | } |
493 | | } |
494 | | Err(e) => { |
495 | | return Err(e); |
496 | | } |
497 | | } |
498 | | } |
499 | | |
500 | | Ok((input.slice(input.input_len()..), input)) |
501 | | } |
502 | | } |
503 | | |
504 | | #[doc(hidden)] |
505 | | pub fn escapedc<Input, Error, F, G, O1, O2>(i: Input, normal: F, control_char: char, escapable: G) -> IResult<Input, Input, Error> |
506 | | where |
507 | | Input: Clone + crate::traits::Offset + InputLength + InputTake + InputTakeAtPosition + Slice<RangeFrom<usize>> + InputIter, |
508 | | <Input as InputIter>::Item: crate::traits::AsChar, |
509 | | F: Fn(Input) -> IResult<Input, O1, Error>, |
510 | | G: Fn(Input) -> IResult<Input, O2, Error>, |
511 | | Error: ParseError<Input>, |
512 | | { |
513 | | escaped(normal, control_char, escapable)(i) |
514 | | } |
515 | | |
516 | | /// Matches a byte string with escaped characters. |
517 | | /// |
518 | | /// * The first argument matches the normal characters (it must not match the control character), |
519 | | /// * the second argument is the control character (like `\` in most languages), |
520 | | /// * the third argument matches the escaped characters and transforms them. |
521 | | /// |
522 | | /// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character) |
523 | | /// |
524 | | /// ``` |
525 | | /// # #[macro_use] extern crate nom; |
526 | | /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
527 | | /// # use std::str::from_utf8; |
528 | | /// use nom::bytes::complete::escaped_transform; |
529 | | /// use nom::character::complete::alpha1; |
530 | | /// |
531 | | /// fn parser(input: &str) -> IResult<&str, String> { |
532 | | /// escaped_transform( |
533 | | /// alpha1, |
534 | | /// '\\', |
535 | | /// |i:&str| alt!(i, |
536 | | /// tag!("\\") => { |_| "\\" } |
537 | | /// | tag!("\"") => { |_| "\"" } |
538 | | /// | tag!("n") => { |_| "\n" } |
539 | | /// ) |
540 | | /// )(input) |
541 | | /// } |
542 | | /// |
543 | | /// assert_eq!(parser("ab\\\"cd"), Ok(("", String::from("ab\"cd")))); |
544 | | /// ``` |
545 | | #[cfg(feature = "alloc")] |
546 | | pub fn escaped_transform<Input, Error, F, G, O1, O2, ExtendItem, Output>( |
547 | | normal: F, |
548 | | control_char: char, |
549 | | transform: G, |
550 | | ) -> impl Fn(Input) -> IResult<Input, Output, Error> |
551 | | where |
552 | | Input: Clone + crate::traits::Offset + InputLength + InputTake + InputTakeAtPosition + Slice<RangeFrom<usize>> + InputIter, |
553 | | Input: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
554 | | O1: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
555 | | O2: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
556 | | Output: core::iter::Extend<<Input as crate::traits::ExtendInto>::Item>, |
557 | | Output: core::iter::Extend<<O1 as crate::traits::ExtendInto>::Item>, |
558 | | Output: core::iter::Extend<<O2 as crate::traits::ExtendInto>::Item>, |
559 | | <Input as InputIter>::Item: crate::traits::AsChar, |
560 | | F: Fn(Input) -> IResult<Input, O1, Error>, |
561 | | G: Fn(Input) -> IResult<Input, O2, Error>, |
562 | | Error: ParseError<Input>, |
563 | | { |
564 | | use crate::traits::AsChar; |
565 | | |
566 | | move |input: Input| { |
567 | | let mut index = 0; |
568 | | let mut res = input.new_builder(); |
569 | | |
570 | | let i = input.clone(); |
571 | | |
572 | | while index < i.input_len() { |
573 | | let remainder = i.slice(index..); |
574 | | match normal(remainder.clone()) { |
575 | | Ok((i2, o)) => { |
576 | | o.extend_into(&mut res); |
577 | | if i2.input_len() == 0 { |
578 | | return Ok((i.slice(i.input_len()..), res)); |
579 | | } else { |
580 | | index = input.offset(&i2); |
581 | | } |
582 | | } |
583 | | Err(Err::Error(_)) => { |
584 | | // unwrap() should be safe here since index < $i.input_len() |
585 | | if remainder.iter_elements().next().unwrap().as_char() == control_char { |
586 | | let next = index + control_char.len_utf8(); |
587 | | let input_len = input.input_len(); |
588 | | |
589 | | if next >= input_len { |
590 | | return Err(Err::Error(Error::from_error_kind(remainder, ErrorKind::EscapedTransform))); |
591 | | } else { |
592 | | match transform(i.slice(next..)) { |
593 | | Ok((i2, o)) => { |
594 | | o.extend_into(&mut res); |
595 | | if i2.input_len() == 0 { |
596 | | return Ok((i.slice(i.input_len()..), res)); |
597 | | } else { |
598 | | index = input.offset(&i2); |
599 | | } |
600 | | } |
601 | | Err(e) => return Err(e), |
602 | | } |
603 | | } |
604 | | } else { |
605 | | if index == 0 { |
606 | | return Err(Err::Error(Error::from_error_kind(remainder, ErrorKind::EscapedTransform))); |
607 | | } |
608 | | return Ok((remainder, res)); |
609 | | } |
610 | | } |
611 | | Err(e) => return Err(e), |
612 | | } |
613 | | } |
614 | | Ok((input.slice(index..), res)) |
615 | | } |
616 | | } |
617 | | |
618 | | #[doc(hidden)] |
619 | | #[cfg(feature = "alloc")] |
620 | | pub fn escaped_transformc<Input, Error, F, G, O1, O2, ExtendItem, Output>( |
621 | | i: Input, |
622 | | normal: F, |
623 | | control_char: char, |
624 | | transform: G, |
625 | | ) -> IResult<Input, Output, Error> |
626 | | where |
627 | | Input: Clone + crate::traits::Offset + InputLength + InputTake + InputTakeAtPosition + Slice<RangeFrom<usize>> + InputIter, |
628 | | Input: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
629 | | O1: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
630 | | O2: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
631 | | Output: core::iter::Extend<<Input as crate::traits::ExtendInto>::Item>, |
632 | | Output: core::iter::Extend<<O1 as crate::traits::ExtendInto>::Item>, |
633 | | Output: core::iter::Extend<<O2 as crate::traits::ExtendInto>::Item>, |
634 | | <Input as InputIter>::Item: crate::traits::AsChar, |
635 | | F: Fn(Input) -> IResult<Input, O1, Error>, |
636 | | G: Fn(Input) -> IResult<Input, O2, Error>, |
637 | | Error: ParseError<Input>, |
638 | | { |
639 | | escaped_transform(normal, control_char, transform)(i) |
640 | | |
641 | | } |
642 | | |
643 | | #[cfg(test)] |
644 | | mod tests { |
645 | | use super::*; |
646 | | |
647 | | #[test] |
648 | | fn complete_take_while_m_n_utf8_all_matching() { |
649 | | let result: IResult<&str, &str> = super::take_while_m_n(1, 4, |c: char| c.is_alphabetic())("øn"); |
650 | | assert_eq!(result, Ok(("", "øn"))); |
651 | | } |
652 | | |
653 | | #[test] |
654 | | fn complete_take_while_m_n_utf8_all_matching_substring() { |
655 | | let result: IResult<&str, &str> = super::take_while_m_n(1, 1, |c: char| c.is_alphabetic())("øn"); |
656 | | assert_eq!(result, Ok(("n", "ø"))); |
657 | | } |
658 | | } |