]> git.proxmox.com Git - rustc.git/blame - vendor/nom8/src/bytes/complete.rs
New upstream version 1.70.0+dfsg2
[rustc.git] / vendor / nom8 / src / bytes / complete.rs
CommitLineData
0a29b90c
FG
1//! Parsers recognizing bytes streams, complete input version
2
3#![allow(deprecated)]
4
5use crate::error::ErrorKind;
6use crate::error::ParseError;
7use crate::input::{
8 Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputTake,
9 InputTakeAtPosition, IntoOutput, Slice, ToUsize,
10};
11use crate::lib::std::ops::RangeFrom;
12use crate::lib::std::result::Result::*;
13use crate::IntoOutputIResult;
14use crate::{Err, IResult, Parser};
15
16pub(crate) fn any<I, E: ParseError<I>>(input: I) -> IResult<I, <I as InputIter>::Item, E>
17where
18 I: InputIter + InputLength + Slice<RangeFrom<usize>>,
19{
20 let mut it = input.iter_indices();
21 match it.next() {
22 None => Err(Err::Error(E::from_error_kind(input, ErrorKind::Eof))),
23 Some((_, c)) => match it.next() {
24 None => Ok((input.slice(input.input_len()..), c)),
25 Some((idx, _)) => Ok((input.slice(idx..), c)),
26 },
27 }
28}
29
30/// Recognizes a pattern
31///
32/// The input data will be compared to the tag combinator's argument and will return the part of
33/// the input that matches the argument
34///
35/// It will return `Err(Err::Error((_, ErrorKind::Tag)))` if the input doesn't match the pattern
36/// # Example
37/// ```rust
38/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
39/// use nom8::bytes::complete::tag;
40///
41/// fn parser(s: &str) -> IResult<&str, &str> {
42/// tag("Hello")(s)
43/// }
44///
45/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello")));
46/// assert_eq!(parser("Something"), Err(Err::Error(Error::new("Something", ErrorKind::Tag))));
47/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Tag))));
48/// ```
49///
50/// **WARNING:** Deprecated, replaced with [`nom8::bytes::tag`][crate::bytes::tag]
51#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::tag`")]
52pub fn tag<T, Input, Error: ParseError<Input>>(
53 tag: T,
54) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
55where
56 Input: InputTake + Compare<T>,
57 Input: IntoOutput,
58 T: InputLength + Clone,
59{
60 move |i: Input| tag_internal(i, tag.clone())
61}
62
63pub(crate) fn tag_internal<T, Input, Error: ParseError<Input>>(
64 i: Input,
65 t: T,
66) -> IResult<Input, <Input as IntoOutput>::Output, Error>
67where
68 Input: InputTake + Compare<T>,
69 Input: IntoOutput,
70 T: InputLength,
71{
72 let tag_len = t.input_len();
73 let res: IResult<_, _, Error> = match i.compare(t) {
74 CompareResult::Ok => Ok(i.take_split(tag_len)),
75 _ => {
76 let e: ErrorKind = ErrorKind::Tag;
77 Err(Err::Error(Error::from_error_kind(i, e)))
78 }
79 };
80 res.into_output()
81}
82
83/// Recognizes a case insensitive pattern.
84///
85/// The input data will be compared to the tag combinator's argument and will return the part of
86/// the input that matches the argument with no regard to case.
87///
88/// It will return `Err(Err::Error((_, ErrorKind::Tag)))` if the input doesn't match the pattern.
89/// # Example
90/// ```rust
91/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
92/// use nom8::bytes::complete::tag_no_case;
93///
94/// fn parser(s: &str) -> IResult<&str, &str> {
95/// tag_no_case("hello")(s)
96/// }
97///
98/// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello")));
99/// assert_eq!(parser("hello, World!"), Ok((", World!", "hello")));
100/// assert_eq!(parser("HeLlO, World!"), Ok((", World!", "HeLlO")));
101/// assert_eq!(parser("Something"), Err(Err::Error(Error::new("Something", ErrorKind::Tag))));
102/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Tag))));
103/// ```
104///
105/// **WARNING:** Deprecated, replaced with [`nom8::bytes::tag_no_case`][crate::bytes::tag_no_case]
106#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::tag_no_case`")]
107pub fn tag_no_case<T, Input, Error: ParseError<Input>>(
108 tag: T,
109) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
110where
111 Input: InputTake + Compare<T>,
112 Input: IntoOutput,
113 T: InputLength + Clone,
114{
115 move |i: Input| tag_no_case_internal(i, tag.clone())
116}
117
118pub(crate) fn tag_no_case_internal<T, Input, Error: ParseError<Input>>(
119 i: Input,
120 t: T,
121) -> IResult<Input, <Input as IntoOutput>::Output, Error>
122where
123 Input: InputTake + Compare<T>,
124 Input: IntoOutput,
125 T: InputLength,
126{
127 let tag_len = t.input_len();
128
129 let res: IResult<_, _, Error> = match (i).compare_no_case(t) {
130 CompareResult::Ok => Ok(i.take_split(tag_len)),
131 _ => {
132 let e: ErrorKind = ErrorKind::Tag;
133 Err(Err::Error(Error::from_error_kind(i, e)))
134 }
135 };
136 res.into_output()
137}
138
139pub(crate) fn one_of_internal<I, T, E: ParseError<I>>(
140 input: I,
141 list: &T,
142) -> IResult<I, <I as InputIter>::Item, E>
143where
144 I: Slice<RangeFrom<usize>> + InputIter + InputLength,
145 <I as InputIter>::Item: Copy,
146 T: FindToken<<I as InputIter>::Item>,
147{
148 let mut it = input.iter_indices();
149 match it.next() {
150 Some((_, c)) if list.find_token(c) => match it.next() {
151 None => Ok((input.slice(input.input_len()..), c)),
152 Some((idx, _)) => Ok((input.slice(idx..), c)),
153 },
154 Some(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::OneOf))),
155 None => Err(Err::Error(E::from_error_kind(input, ErrorKind::OneOf))),
156 }
157}
158
159pub(crate) fn none_of_internal<I, T, E: ParseError<I>>(
160 input: I,
161 list: &T,
162) -> IResult<I, <I as InputIter>::Item, E>
163where
164 I: Slice<RangeFrom<usize>> + InputIter + InputLength,
165 <I as InputIter>::Item: Copy,
166 T: FindToken<<I as InputIter>::Item>,
167{
168 let mut it = input.iter_indices();
169 match it.next() {
170 Some((_, c)) if !list.find_token(c) => match it.next() {
171 None => Ok((input.slice(input.input_len()..), c)),
172 Some((idx, _)) => Ok((input.slice(idx..), c)),
173 },
174 Some(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::NoneOf))),
175 None => Err(Err::Error(E::from_error_kind(input, ErrorKind::NoneOf))),
176 }
177}
178
179/// Parse till certain characters are met.
180///
181/// The parser will return the longest slice till one of the characters of the combinator's argument are met.
182///
183/// It doesn't consume the matched character.
184///
185/// It will return a `Err::Error(("", ErrorKind::IsNot))` if the pattern wasn't met.
186/// # Example
187/// ```rust
188/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
189/// use nom8::bytes::complete::is_not;
190///
191/// fn not_space(s: &str) -> IResult<&str, &str> {
192/// is_not(" \t\r\n")(s)
193/// }
194///
195/// assert_eq!(not_space("Hello, World!"), Ok((" World!", "Hello,")));
196/// assert_eq!(not_space("Sometimes\t"), Ok(("\t", "Sometimes")));
197/// assert_eq!(not_space("Nospace"), Ok(("", "Nospace")));
198/// assert_eq!(not_space(""), Err(Err::Error(Error::new("", ErrorKind::IsNot))));
199/// ```
200///
201/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_till1`][crate::bytes::take_till1]
202#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_till1`")]
203pub fn is_not<T, Input, Error: ParseError<Input>>(
204 arr: T,
205) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
206where
207 Input: InputTakeAtPosition,
208 Input: IntoOutput,
209 T: FindToken<<Input as InputTakeAtPosition>::Item>,
210{
211 move |i: Input| is_not_internal(i, &arr)
212}
213
214pub(crate) fn is_not_internal<T, Input, Error: ParseError<Input>>(
215 i: Input,
216 arr: &T,
217) -> IResult<Input, <Input as IntoOutput>::Output, Error>
218where
219 Input: InputTakeAtPosition,
220 Input: IntoOutput,
221 T: FindToken<<Input as InputTakeAtPosition>::Item>,
222{
223 let e: ErrorKind = ErrorKind::IsNot;
224 i.split_at_position1_complete(|c| arr.find_token(c), e)
225 .into_output()
226}
227
228/// Returns the longest slice of the matches the pattern.
229///
230/// The parser will return the longest slice consisting of the characters in provided in the
231/// combinator's argument.
232///
233/// It will return a `Err(Err::Error((_, ErrorKind::IsA)))` if the pattern wasn't met.
234/// # Example
235/// ```rust
236/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
237/// use nom8::bytes::complete::is_a;
238///
239/// fn hex(s: &str) -> IResult<&str, &str> {
240/// is_a("1234567890ABCDEF")(s)
241/// }
242///
243/// assert_eq!(hex("123 and voila"), Ok((" and voila", "123")));
244/// assert_eq!(hex("DEADBEEF and others"), Ok((" and others", "DEADBEEF")));
245/// assert_eq!(hex("BADBABEsomething"), Ok(("something", "BADBABE")));
246/// assert_eq!(hex("D15EA5E"), Ok(("", "D15EA5E")));
247/// assert_eq!(hex(""), Err(Err::Error(Error::new("", ErrorKind::IsA))));
248/// ```
249///
250/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_while1`][crate::bytes::take_while1`]
251#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_while1`")]
252pub fn is_a<T, Input, Error: ParseError<Input>>(
253 arr: T,
254) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
255where
256 Input: InputTakeAtPosition,
257 Input: IntoOutput,
258 T: FindToken<<Input as InputTakeAtPosition>::Item>,
259{
260 move |i: Input| is_a_internal(i, &arr)
261}
262
263pub(crate) fn is_a_internal<T, Input, Error: ParseError<Input>>(
264 i: Input,
265 arr: &T,
266) -> IResult<Input, <Input as IntoOutput>::Output, Error>
267where
268 Input: InputTakeAtPosition,
269 Input: IntoOutput,
270 T: FindToken<<Input as InputTakeAtPosition>::Item>,
271{
272 let e: ErrorKind = ErrorKind::IsA;
273 i.split_at_position1_complete(|c| !arr.find_token(c), e)
274 .into_output()
275}
276
277/// Returns the longest input slice (if any) that matches the predicate.
278///
279/// The parser will return the longest slice that matches the given predicate *(a function that
280/// takes the input and returns a bool)*.
281/// # Example
282/// ```rust
283/// # use nom8::{Err, error::ErrorKind, Needed, IResult};
284/// use nom8::bytes::complete::take_while;
285/// use nom8::input::AsChar;
286///
287/// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> {
288/// take_while(AsChar::is_alpha)(s)
289/// }
290///
291/// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..])));
292/// assert_eq!(alpha(b"12345"), Ok((&b"12345"[..], &b""[..])));
293/// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..])));
294/// assert_eq!(alpha(b""), Ok((&b""[..], &b""[..])));
295/// ```
296///
297/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_while`][crate::bytes::take_while]
298#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_while`")]
299pub fn take_while<T, Input, Error: ParseError<Input>>(
300 list: T,
301) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
302where
303 Input: InputTakeAtPosition,
304 Input: IntoOutput,
305 T: FindToken<<Input as InputTakeAtPosition>::Item>,
306{
307 move |i: Input| take_while_internal(i, &list)
308}
309
310pub(crate) fn take_while_internal<T, Input, Error: ParseError<Input>>(
311 i: Input,
312 list: &T,
313) -> IResult<Input, <Input as IntoOutput>::Output, Error>
314where
315 Input: InputTakeAtPosition,
316 Input: IntoOutput,
317 T: FindToken<<Input as InputTakeAtPosition>::Item>,
318{
319 i.split_at_position_complete(|c| !list.find_token(c))
320 .into_output()
321}
322
323/// Returns the longest (at least 1) input slice that matches the predicate.
324///
325/// The parser will return the longest slice that matches the given predicate *(a function that
326/// takes the input and returns a bool)*.
327///
328/// It will return an `Err(Err::Error((_, ErrorKind::TakeWhile1)))` if the pattern wasn't met.
329/// # Example
330/// ```rust
331/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
332/// use nom8::bytes::complete::take_while1;
333/// use nom8::input::AsChar;
334///
335/// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> {
336/// take_while1(AsChar::is_alpha)(s)
337/// }
338///
339/// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..])));
340/// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..])));
341/// assert_eq!(alpha(b"12345"), Err(Err::Error(Error::new(&b"12345"[..], ErrorKind::TakeWhile1))));
342/// ```
343///
344/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_while1`][crate::bytes::take_while1]
345#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_while1`")]
346pub fn take_while1<T, Input, Error: ParseError<Input>>(
347 list: T,
348) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
349where
350 Input: InputTakeAtPosition,
351 Input: IntoOutput,
352 T: FindToken<<Input as InputTakeAtPosition>::Item>,
353{
354 move |i: Input| take_while1_internal(i, &list)
355}
356
357pub(crate) fn take_while1_internal<T, Input, Error: ParseError<Input>>(
358 i: Input,
359 list: &T,
360) -> IResult<Input, <Input as IntoOutput>::Output, Error>
361where
362 Input: InputTakeAtPosition,
363 Input: IntoOutput,
364 T: FindToken<<Input as InputTakeAtPosition>::Item>,
365{
366 let e: ErrorKind = ErrorKind::TakeWhile1;
367 i.split_at_position1_complete(|c| !list.find_token(c), e)
368 .into_output()
369}
370
371/// Returns the longest (m <= len <= n) input slice that matches the predicate.
372///
373/// The parser will return the longest slice that matches the given predicate *(a function that
374/// takes the input and returns a bool)*.
375///
376/// It will return an `Err::Error((_, ErrorKind::TakeWhileMN))` if the pattern wasn't met or is out
377/// of range (m <= len <= n).
378/// # Example
379/// ```rust
380/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
381/// use nom8::bytes::complete::take_while_m_n;
382/// use nom8::input::AsChar;
383///
384/// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> {
385/// take_while_m_n(3, 6, AsChar::is_alpha)(s)
386/// }
387///
388/// assert_eq!(short_alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..])));
389/// assert_eq!(short_alpha(b"lengthy"), Ok((&b"y"[..], &b"length"[..])));
390/// assert_eq!(short_alpha(b"latin"), Ok((&b""[..], &b"latin"[..])));
391/// assert_eq!(short_alpha(b"ed"), Err(Err::Error(Error::new(&b"ed"[..], ErrorKind::TakeWhileMN))));
392/// assert_eq!(short_alpha(b"12345"), Err(Err::Error(Error::new(&b"12345"[..], ErrorKind::TakeWhileMN))));
393/// ```
394///
395/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_while_m_n`][crate::bytes::take_while_m_n]
396#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_while_m_n`")]
397pub fn take_while_m_n<T, Input, Error: ParseError<Input>>(
398 m: usize,
399 n: usize,
400 list: T,
401) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
402where
403 Input: InputTake + InputIter + InputLength + Slice<RangeFrom<usize>>,
404 Input: IntoOutput,
405 T: FindToken<<Input as InputIter>::Item>,
406{
407 move |i: Input| take_while_m_n_internal(i, m, n, &list)
408}
409
410pub(crate) fn take_while_m_n_internal<T, Input, Error: ParseError<Input>>(
411 input: Input,
412 m: usize,
413 n: usize,
414 list: &T,
415) -> IResult<Input, <Input as IntoOutput>::Output, Error>
416where
417 Input: InputTake + InputIter + InputLength + Slice<RangeFrom<usize>>,
418 Input: IntoOutput,
419 T: FindToken<<Input as InputIter>::Item>,
420{
421 match input.position(|c| !list.find_token(c)) {
422 Some(idx) => {
423 if idx >= m {
424 if idx <= n {
425 let res: IResult<_, _, Error> = if let Ok(index) = input.slice_index(idx) {
426 Ok(input.take_split(index)).into_output()
427 } else {
428 Err(Err::Error(Error::from_error_kind(
429 input,
430 ErrorKind::TakeWhileMN,
431 )))
432 };
433 res
434 } else {
435 let res: IResult<_, _, Error> = if let Ok(index) = input.slice_index(n) {
436 Ok(input.take_split(index)).into_output()
437 } else {
438 Err(Err::Error(Error::from_error_kind(
439 input,
440 ErrorKind::TakeWhileMN,
441 )))
442 };
443 res
444 }
445 } else {
446 let e = ErrorKind::TakeWhileMN;
447 Err(Err::Error(Error::from_error_kind(input, e)))
448 }
449 }
450 None => {
451 let len = input.input_len();
452 if len >= n {
453 match input.slice_index(n) {
454 Ok(index) => Ok(input.take_split(index)).into_output(),
455 Err(_needed) => Err(Err::Error(Error::from_error_kind(
456 input,
457 ErrorKind::TakeWhileMN,
458 ))),
459 }
460 } else if len >= m && len <= n {
461 let res: IResult<_, _, Error> = Ok((input.slice(len..), input));
462 res.into_output()
463 } else {
464 let e = ErrorKind::TakeWhileMN;
465 Err(Err::Error(Error::from_error_kind(input, e)))
466 }
467 }
468 }
469}
470
471/// Returns the longest input slice (if any) till a predicate is met.
472///
473/// The parser will return the longest slice till the given predicate *(a function that
474/// takes the input and returns a bool)*.
475/// # Example
476/// ```rust
477/// # use nom8::{Err, error::ErrorKind, Needed, IResult};
478/// use nom8::bytes::complete::take_till;
479///
480/// fn till_colon(s: &str) -> IResult<&str, &str> {
481/// take_till(|c| c == ':')(s)
482/// }
483///
484/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin")));
485/// assert_eq!(till_colon(":empty matched"), Ok((":empty matched", ""))); //allowed
486/// assert_eq!(till_colon("12345"), Ok(("", "12345")));
487/// assert_eq!(till_colon(""), Ok(("", "")));
488/// ```
489///
490/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_till`][crate::bytes::take_till]
491#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_till`")]
492pub fn take_till<T, Input, Error: ParseError<Input>>(
493 list: T,
494) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
495where
496 Input: InputTakeAtPosition,
497 Input: IntoOutput,
498 T: FindToken<<Input as InputTakeAtPosition>::Item>,
499{
500 move |i: Input| take_till_internal(i, &list)
501}
502
503pub(crate) fn take_till_internal<T, Input, Error: ParseError<Input>>(
504 i: Input,
505 list: &T,
506) -> IResult<Input, <Input as IntoOutput>::Output, Error>
507where
508 Input: InputTakeAtPosition,
509 Input: IntoOutput,
510 T: FindToken<<Input as InputTakeAtPosition>::Item>,
511{
512 i.split_at_position_complete(|c| list.find_token(c))
513 .into_output()
514}
515
516/// Returns the longest (at least 1) input slice till a predicate is met.
517///
518/// The parser will return the longest slice till the given predicate *(a function that
519/// takes the input and returns a bool)*.
520///
521/// It will return `Err(Err::Error((_, ErrorKind::TakeTill1)))` if the input is empty or the
522/// predicate matches the first input.
523/// # Example
524/// ```rust
525/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
526/// use nom8::bytes::complete::take_till1;
527///
528/// fn till_colon(s: &str) -> IResult<&str, &str> {
529/// take_till1(|c| c == ':')(s)
530/// }
531///
532/// assert_eq!(till_colon("latin:123"), Ok((":123", "latin")));
533/// assert_eq!(till_colon(":empty matched"), Err(Err::Error(Error::new(":empty matched", ErrorKind::TakeTill1))));
534/// assert_eq!(till_colon("12345"), Ok(("", "12345")));
535/// assert_eq!(till_colon(""), Err(Err::Error(Error::new("", ErrorKind::TakeTill1))));
536/// ```
537///
538/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_till1`][crate::bytes::take_till1]
539#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_till1`")]
540pub fn take_till1<T, Input, Error: ParseError<Input>>(
541 list: T,
542) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
543where
544 Input: InputTakeAtPosition,
545 Input: IntoOutput,
546 T: FindToken<<Input as InputTakeAtPosition>::Item>,
547{
548 move |i: Input| take_till1_internal(i, &list)
549}
550
551pub(crate) fn take_till1_internal<T, Input, Error: ParseError<Input>>(
552 i: Input,
553 list: &T,
554) -> IResult<Input, <Input as IntoOutput>::Output, Error>
555where
556 Input: InputTakeAtPosition,
557 Input: IntoOutput,
558 T: FindToken<<Input as InputTakeAtPosition>::Item>,
559{
560 let e: ErrorKind = ErrorKind::TakeTill1;
561 i.split_at_position1_complete(|c| list.find_token(c), e)
562 .into_output()
563}
564
565/// Returns an input slice containing the first N input elements (Input[..N]).
566///
567/// It will return `Err(Err::Error((_, ErrorKind::Eof)))` if the input is shorter than the argument.
568/// # Example
569/// ```rust
570/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
571/// use nom8::bytes::complete::take;
572///
573/// fn take6(s: &str) -> IResult<&str, &str> {
574/// take(6usize)(s)
575/// }
576///
577/// assert_eq!(take6("1234567"), Ok(("7", "123456")));
578/// assert_eq!(take6("things"), Ok(("", "things")));
579/// assert_eq!(take6("short"), Err(Err::Error(Error::new("short", ErrorKind::Eof))));
580/// assert_eq!(take6(""), Err(Err::Error(Error::new("", ErrorKind::Eof))));
581/// ```
582///
583/// The units that are taken will depend on the input type. For example, for a
584/// `&str` it will take a number of `char`'s, whereas for a `&[u8]` it will
585/// take that many `u8`'s:
586///
587/// ```rust
588/// use nom8::error::Error;
589/// use nom8::bytes::complete::take;
590///
591/// assert_eq!(take::<_, _, Error<_>>(1usize)("💙"), Ok(("", "💙")));
592/// assert_eq!(take::<_, _, Error<_>>(1usize)("💙".as_bytes()), Ok((b"\x9F\x92\x99".as_ref(), b"\xF0".as_ref())));
593/// ```
594///
595/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take`][crate::bytes::take]
596#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take`")]
597pub fn take<C, Input, Error: ParseError<Input>>(
598 count: C,
599) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
600where
601 Input: InputIter + InputTake,
602 Input: IntoOutput,
603 C: ToUsize,
604{
605 let c = count.to_usize();
606 move |i: Input| take_internal(i, c)
607}
608
609pub(crate) fn take_internal<Input, Error: ParseError<Input>>(
610 i: Input,
611 c: usize,
612) -> IResult<Input, <Input as IntoOutput>::Output, Error>
613where
614 Input: InputIter + InputTake,
615 Input: IntoOutput,
616{
617 match i.slice_index(c) {
618 Err(_needed) => Err(Err::Error(Error::from_error_kind(i, ErrorKind::Eof))),
619 Ok(index) => Ok(i.take_split(index)).into_output(),
620 }
621}
622
623/// Returns the input slice up to the first occurrence of the pattern.
624///
625/// It doesn't consume the pattern. It will return `Err(Err::Error((_, ErrorKind::TakeUntil)))`
626/// if the pattern wasn't met.
627/// # Example
628/// ```rust
629/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
630/// use nom8::bytes::complete::take_until;
631///
632/// fn until_eof(s: &str) -> IResult<&str, &str> {
633/// take_until("eof")(s)
634/// }
635///
636/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world")));
637/// assert_eq!(until_eof("hello, world"), Err(Err::Error(Error::new("hello, world", ErrorKind::TakeUntil))));
638/// assert_eq!(until_eof(""), Err(Err::Error(Error::new("", ErrorKind::TakeUntil))));
639/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1")));
640/// ```
641///
642/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_until`][crate::bytes::take_until]
643#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_until`")]
644pub fn take_until<T, Input, Error: ParseError<Input>>(
645 tag: T,
646) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
647where
648 Input: InputTake + FindSubstring<T>,
649 Input: IntoOutput,
650 T: InputLength + Clone,
651{
652 move |i: Input| take_until_internal(i, tag.clone())
653}
654
655pub(crate) fn take_until_internal<T, Input, Error: ParseError<Input>>(
656 i: Input,
657 t: T,
658) -> IResult<Input, <Input as IntoOutput>::Output, Error>
659where
660 Input: InputTake + FindSubstring<T>,
661 Input: IntoOutput,
662 T: InputLength,
663{
664 let res: IResult<_, _, Error> = match i.find_substring(t) {
665 None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))),
666 Some(index) => Ok(i.take_split(index)),
667 };
668 res.into_output()
669}
670
671/// Returns the non empty input slice up to the first occurrence of the pattern.
672///
673/// It doesn't consume the pattern. It will return `Err(Err::Error((_, ErrorKind::TakeUntil)))`
674/// if the pattern wasn't met.
675/// # Example
676/// ```rust
677/// # use nom8::{Err, error::{Error, ErrorKind}, Needed, IResult};
678/// use nom8::bytes::complete::take_until1;
679///
680/// fn until_eof(s: &str) -> IResult<&str, &str> {
681/// take_until1("eof")(s)
682/// }
683///
684/// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world")));
685/// assert_eq!(until_eof("hello, world"), Err(Err::Error(Error::new("hello, world", ErrorKind::TakeUntil))));
686/// assert_eq!(until_eof(""), Err(Err::Error(Error::new("", ErrorKind::TakeUntil))));
687/// assert_eq!(until_eof("1eof2eof"), Ok(("eof2eof", "1")));
688/// assert_eq!(until_eof("eof"), Err(Err::Error(Error::new("eof", ErrorKind::TakeUntil))));
689/// ```
690///
691/// **WARNING:** Deprecated, replaced with [`nom8::bytes::take_until1`][crate::bytes::take_until1]
692#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::take_until1`")]
693pub fn take_until1<T, Input, Error: ParseError<Input>>(
694 tag: T,
695) -> impl Fn(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
696where
697 Input: InputTake + FindSubstring<T>,
698 Input: IntoOutput,
699 T: InputLength + Clone,
700{
701 move |i: Input| take_until1_internal(i, tag.clone())
702}
703
704pub(crate) fn take_until1_internal<T, Input, Error: ParseError<Input>>(
705 i: Input,
706 t: T,
707) -> IResult<Input, <Input as IntoOutput>::Output, Error>
708where
709 Input: InputTake + FindSubstring<T>,
710 Input: IntoOutput,
711 T: InputLength,
712{
713 let res: IResult<_, _, Error> = match i.find_substring(t) {
714 None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))),
715 Some(0) => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))),
716 Some(index) => Ok(i.take_split(index)),
717 };
718 res.into_output()
719}
720
721/// Matches a byte string with escaped characters.
722///
723/// * The first argument matches the normal characters (it must not accept the control character)
724/// * The second argument is the control character (like `\` in most languages)
725/// * The third argument matches the escaped characters
726/// # Example
727/// ```
728/// # use nom8::{Err, error::ErrorKind, Needed, IResult};
729/// # use nom8::character::complete::digit1;
730/// use nom8::bytes::complete::escaped;
731/// use nom8::character::complete::one_of;
732///
733/// fn esc(s: &str) -> IResult<&str, &str> {
734/// escaped(digit1, '\\', one_of(r#""n\"#))(s)
735/// }
736///
737/// assert_eq!(esc("123;"), Ok((";", "123")));
738/// assert_eq!(esc(r#"12\"34;"#), Ok((";", r#"12\"34"#)));
739/// ```
740///
741///
742/// **WARNING:** Deprecated, replaced with [`nom8::bytes::escaped`][crate::bytes::escaped]
743#[deprecated(since = "8.0.0", note = "Replaced with `nom8::bytes::escaped`")]
744pub fn escaped<'a, Input: 'a, Error, F, G, O1, O2>(
745 mut normal: F,
746 control_char: char,
747 mut escapable: G,
748) -> impl FnMut(Input) -> IResult<Input, <Input as IntoOutput>::Output, Error>
749where
750 Input: Clone
751 + crate::input::Offset
752 + InputLength
753 + InputTake
754 + InputTakeAtPosition
755 + Slice<RangeFrom<usize>>
756 + InputIter,
757 Input: IntoOutput,
758 <Input as InputIter>::Item: crate::input::AsChar,
759 F: Parser<Input, O1, Error>,
760 G: Parser<Input, O2, Error>,
761 Error: ParseError<Input>,
762{
763 move |input: Input| escaped_internal(input, &mut normal, control_char, &mut escapable)
764}
765
766pub(crate) fn escaped_internal<'a, Input: 'a, Error, F, G, O1, O2>(
767 input: Input,
768 normal: &mut F,
769 control_char: char,
770 escapable: &mut G,
771) -> IResult<Input, <Input as IntoOutput>::Output, Error>
772where
773 Input: Clone
774 + crate::input::Offset
775 + InputLength
776 + InputTake
777 + InputTakeAtPosition
778 + Slice<RangeFrom<usize>>
779 + InputIter,
780 Input: IntoOutput,
781 <Input as InputIter>::Item: crate::input::AsChar,
782 F: Parser<Input, O1, Error>,
783 G: Parser<Input, O2, Error>,
784 Error: ParseError<Input>,
785{
786 use crate::input::AsChar;
787
788 let mut i = input.clone();
789
790 while i.input_len() > 0 {
791 let current_len = i.input_len();
792
793 match normal.parse(i.clone()) {
794 Ok((i2, _)) => {
795 // return if we consumed everything or if the normal parser
796 // does not consume anything
797 if i2.input_len() == 0 {
798 return Ok((input.slice(input.input_len()..), input)).into_output();
799 } else if i2.input_len() == current_len {
800 let index = input.offset(&i2);
801 return Ok(input.take_split(index)).into_output();
802 } else {
803 i = i2;
804 }
805 }
806 Err(Err::Error(_)) => {
807 // unwrap() should be safe here since index < $i.input_len()
808 if i.iter_elements().next().unwrap().as_char() == control_char {
809 let next = control_char.len_utf8();
810 if next >= i.input_len() {
811 return Err(Err::Error(Error::from_error_kind(
812 input,
813 ErrorKind::Escaped,
814 )));
815 } else {
816 match escapable.parse(i.slice(next..)) {
817 Ok((i2, _)) => {
818 if i2.input_len() == 0 {
819 return Ok((input.slice(input.input_len()..), input)).into_output();
820 } else {
821 i = i2;
822 }
823 }
824 Err(e) => return Err(e),
825 }
826 }
827 } else {
828 let index = input.offset(&i);
829 if index == 0 {
830 return Err(Err::Error(Error::from_error_kind(
831 input,
832 ErrorKind::Escaped,
833 )));
834 }
835 return Ok(input.take_split(index)).into_output();
836 }
837 }
838 Err(e) => {
839 return Err(e);
840 }
841 }
842 }
843
844 Ok((input.slice(input.input_len()..), input)).into_output()
845}
846
847/// Matches a byte string with escaped characters.
848///
849/// * The first argument matches the normal characters (it must not match the control character)
850/// * The second argument is the control character (like `\` in most languages)
851/// * The third argument matches the escaped characters and transforms them
852///
853/// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character)
854///
855/// ```
856/// # use nom8::{Err, error::ErrorKind, Needed, IResult};
857/// # use std::str::from_utf8;
858/// use nom8::bytes::complete::{escaped_transform, tag};
859/// use nom8::character::complete::alpha1;
860/// use nom8::branch::alt;
861/// use nom8::combinator::value;
862///
863/// fn parser(input: &str) -> IResult<&str, String> {
864/// escaped_transform(
865/// alpha1,
866/// '\\',
867/// alt((
868/// value("\\", tag("\\")),
869/// value("\"", tag("\"")),
870/// value("\n", tag("n")),
871/// ))
872/// )(input)
873/// }
874///
875/// assert_eq!(parser("ab\\\"cd"), Ok(("", String::from("ab\"cd"))));
876/// assert_eq!(parser("ab\\ncd"), Ok(("", String::from("ab\ncd"))));
877/// ```
878#[cfg(feature = "alloc")]
879///
880/// **WARNING:** Deprecated, replaced with [`nom8::bytes::escaped_transform`][crate::bytes::escaped_transform]
881#[deprecated(
882 since = "8.0.0",
883 note = "Replaced with `nom8::bytes::escaped_transform`"
884)]
885pub fn escaped_transform<Input, Error, F, G, O1, O2, ExtendItem, Output>(
886 mut normal: F,
887 control_char: char,
888 mut transform: G,
889) -> impl FnMut(Input) -> IResult<Input, Output, Error>
890where
891 Input: Clone
892 + crate::input::Offset
893 + InputLength
894 + InputTake
895 + InputTakeAtPosition
896 + Slice<RangeFrom<usize>>
897 + InputIter,
898 Input: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>,
899 O1: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>,
900 O2: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>,
901 <Input as InputIter>::Item: crate::input::AsChar,
902 F: Parser<Input, O1, Error>,
903 G: Parser<Input, O2, Error>,
904 Error: ParseError<Input>,
905{
906 move |input: Input| escaped_transform_internal(input, &mut normal, control_char, &mut transform)
907}
908
909#[cfg(feature = "alloc")]
910pub(crate) fn escaped_transform_internal<Input, Error, F, G, O1, O2, ExtendItem, Output>(
911 input: Input,
912 normal: &mut F,
913 control_char: char,
914 transform: &mut G,
915) -> IResult<Input, Output, Error>
916where
917 Input: Clone
918 + crate::input::Offset
919 + InputLength
920 + InputTake
921 + InputTakeAtPosition
922 + Slice<RangeFrom<usize>>
923 + InputIter,
924 Input: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>,
925 O1: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>,
926 O2: crate::input::ExtendInto<Item = ExtendItem, Extender = Output>,
927 <Input as InputIter>::Item: crate::input::AsChar,
928 F: Parser<Input, O1, Error>,
929 G: Parser<Input, O2, Error>,
930 Error: ParseError<Input>,
931{
932 use crate::input::AsChar;
933
934 let mut index = 0;
935 let mut res = input.new_builder();
936
937 let i = input.clone();
938
939 while index < i.input_len() {
940 let current_len = i.input_len();
941 let remainder = i.slice(index..);
942 match normal.parse(remainder.clone()) {
943 Ok((i2, o)) => {
944 o.extend_into(&mut res);
945 if i2.input_len() == 0 {
946 return Ok((i.slice(i.input_len()..), res));
947 } else if i2.input_len() == current_len {
948 return Ok((remainder, res));
949 } else {
950 index = input.offset(&i2);
951 }
952 }
953 Err(Err::Error(_)) => {
954 // unwrap() should be safe here since index < $i.input_len()
955 if remainder.iter_elements().next().unwrap().as_char() == control_char {
956 let next = index + control_char.len_utf8();
957 let input_len = input.input_len();
958
959 if next >= input_len {
960 return Err(Err::Error(Error::from_error_kind(
961 remainder,
962 ErrorKind::EscapedTransform,
963 )));
964 } else {
965 match transform.parse(i.slice(next..)) {
966 Ok((i2, o)) => {
967 o.extend_into(&mut res);
968 if i2.input_len() == 0 {
969 return Ok((i.slice(i.input_len()..), res));
970 } else {
971 index = input.offset(&i2);
972 }
973 }
974 Err(e) => return Err(e),
975 }
976 }
977 } else {
978 if index == 0 {
979 return Err(Err::Error(Error::from_error_kind(
980 remainder,
981 ErrorKind::EscapedTransform,
982 )));
983 }
984 return Ok((remainder, res));
985 }
986 }
987 Err(e) => return Err(e),
988 }
989 }
990 Ok((input.slice(index..), res))
991}
992
993#[cfg(test)]
994mod tests {
995 use super::*;
996 use crate::character::complete::{alpha1 as alpha, digit1 as digit};
997 #[cfg(feature = "alloc")]
998 use crate::{
999 branch::alt,
1000 combinator::{map, value},
1001 lib::std::string::String,
1002 lib::std::vec::Vec,
1003 };
1004
1005 #[test]
1006 fn complete_take_while_m_n_utf8_all_matching() {
1007 let result: IResult<&str, &str> =
1008 super::take_while_m_n(1, 4, |c: char| c.is_alphabetic())("øn");
1009 assert_eq!(result, Ok(("", "øn")));
1010 }
1011
1012 #[test]
1013 fn complete_take_while_m_n_utf8_all_matching_substring() {
1014 let result: IResult<&str, &str> =
1015 super::take_while_m_n(1, 1, |c: char| c.is_alphabetic())("øn");
1016 assert_eq!(result, Ok(("n", "ø")));
1017 }
1018
1019 // issue #1336 "escaped hangs if normal parser accepts empty"
1020 fn escaped_string(input: &str) -> IResult<&str, &str> {
1021 use crate::character::complete::{alpha0, one_of};
1022 escaped(alpha0, '\\', one_of("n"))(input)
1023 }
1024
1025 // issue #1336 "escaped hangs if normal parser accepts empty"
1026 #[test]
1027 fn escaped_hang() {
1028 escaped_string("7").unwrap();
1029 escaped_string("a7").unwrap();
1030 }
1031
1032 // issue ##1118 escaped does not work with empty string
1033 fn unquote<'a>(input: &'a str) -> IResult<&'a str, &'a str> {
1034 use crate::bytes::complete::*;
1035 use crate::character::complete::*;
1036 use crate::combinator::opt;
1037 use crate::sequence::delimited;
1038
1039 delimited(
1040 char('"'),
1041 escaped(opt(none_of(r#"\""#)), '\\', one_of(r#"\"rnt"#)),
1042 char('"'),
1043 )(input)
1044 }
1045
1046 #[test]
1047 fn escaped_hang_1118() {
1048 assert_eq!(unquote(r#""""#), Ok(("", "")));
1049 }
1050
1051 #[cfg(feature = "alloc")]
1052 #[allow(unused_variables)]
1053 #[test]
1054 fn escaping() {
1055 use crate::character::complete::one_of;
1056
1057 fn esc(i: &[u8]) -> IResult<&[u8], &[u8]> {
1058 escaped(alpha, '\\', one_of("\"n\\"))(i)
1059 }
1060 assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], &b"abcd"[..])));
1061 assert_eq!(esc(&b"ab\\\"cd;"[..]), Ok((&b";"[..], &b"ab\\\"cd"[..])));
1062 assert_eq!(esc(&b"\\\"abcd;"[..]), Ok((&b";"[..], &b"\\\"abcd"[..])));
1063 assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], &b"\\n"[..])));
1064 assert_eq!(esc(&b"ab\\\"12"[..]), Ok((&b"12"[..], &b"ab\\\""[..])));
1065 assert_eq!(
1066 esc(&b"AB\\"[..]),
1067 Err(Err::Error(error_position!(
1068 &b"AB\\"[..],
1069 ErrorKind::Escaped
1070 )))
1071 );
1072 assert_eq!(
1073 esc(&b"AB\\A"[..]),
1074 Err(Err::Error(error_node_position!(
1075 &b"AB\\A"[..],
1076 ErrorKind::Escaped,
1077 error_position!(&b"A"[..], ErrorKind::OneOf)
1078 )))
1079 );
1080
1081 fn esc2(i: &[u8]) -> IResult<&[u8], &[u8]> {
1082 escaped(digit, '\\', one_of("\"n\\"))(i)
1083 }
1084 assert_eq!(esc2(&b"12\\nnn34"[..]), Ok((&b"nn34"[..], &b"12\\n"[..])));
1085 }
1086
1087 #[cfg(feature = "alloc")]
1088 #[test]
1089 fn escaping_str() {
1090 use crate::character::complete::one_of;
1091
1092 fn esc(i: &str) -> IResult<&str, &str> {
1093 escaped(alpha, '\\', one_of("\"n\\"))(i)
1094 }
1095 assert_eq!(esc("abcd;"), Ok((";", "abcd")));
1096 assert_eq!(esc("ab\\\"cd;"), Ok((";", "ab\\\"cd")));
1097 assert_eq!(esc("\\\"abcd;"), Ok((";", "\\\"abcd")));
1098 assert_eq!(esc("\\n;"), Ok((";", "\\n")));
1099 assert_eq!(esc("ab\\\"12"), Ok(("12", "ab\\\"")));
1100 assert_eq!(
1101 esc("AB\\"),
1102 Err(Err::Error(error_position!("AB\\", ErrorKind::Escaped)))
1103 );
1104 assert_eq!(
1105 esc("AB\\A"),
1106 Err(Err::Error(error_node_position!(
1107 "AB\\A",
1108 ErrorKind::Escaped,
1109 error_position!("A", ErrorKind::OneOf)
1110 )))
1111 );
1112
1113 fn esc2(i: &str) -> IResult<&str, &str> {
1114 escaped(digit, '\\', one_of("\"n\\"))(i)
1115 }
1116 assert_eq!(esc2("12\\nnn34"), Ok(("nn34", "12\\n")));
1117
1118 fn esc3(i: &str) -> IResult<&str, &str> {
1119 escaped(alpha, '\u{241b}', one_of("\"n"))(i)
1120 }
1121 assert_eq!(esc3("ab␛ncd;"), Ok((";", "ab␛ncd")));
1122 }
1123
1124 #[cfg(feature = "alloc")]
1125 fn to_s(i: Vec<u8>) -> String {
1126 String::from_utf8_lossy(&i).into_owned()
1127 }
1128
1129 #[cfg(feature = "alloc")]
1130 #[test]
1131 fn escape_transform() {
1132 fn esc(i: &[u8]) -> IResult<&[u8], String> {
1133 map(
1134 escaped_transform(
1135 alpha,
1136 '\\',
1137 alt((
1138 value(&b"\\"[..], tag("\\")),
1139 value(&b"\""[..], tag("\"")),
1140 value(&b"\n"[..], tag("n")),
1141 )),
1142 ),
1143 to_s,
1144 )(i)
1145 }
1146
1147 assert_eq!(esc(&b"abcd;"[..]), Ok((&b";"[..], String::from("abcd"))));
1148 assert_eq!(
1149 esc(&b"ab\\\"cd;"[..]),
1150 Ok((&b";"[..], String::from("ab\"cd")))
1151 );
1152 assert_eq!(
1153 esc(&b"\\\"abcd;"[..]),
1154 Ok((&b";"[..], String::from("\"abcd")))
1155 );
1156 assert_eq!(esc(&b"\\n;"[..]), Ok((&b";"[..], String::from("\n"))));
1157 assert_eq!(
1158 esc(&b"ab\\\"12"[..]),
1159 Ok((&b"12"[..], String::from("ab\"")))
1160 );
1161 assert_eq!(
1162 esc(&b"AB\\"[..]),
1163 Err(Err::Error(error_position!(
1164 &b"\\"[..],
1165 ErrorKind::EscapedTransform
1166 )))
1167 );
1168 assert_eq!(
1169 esc(&b"AB\\A"[..]),
1170 Err(Err::Error(error_node_position!(
1171 &b"AB\\A"[..],
1172 ErrorKind::EscapedTransform,
1173 error_position!(&b"A"[..], ErrorKind::Tag)
1174 )))
1175 );
1176
1177 fn esc2(i: &[u8]) -> IResult<&[u8], String> {
1178 map(
1179 escaped_transform(
1180 alpha,
1181 '&',
1182 alt((
1183 value("è".as_bytes(), tag("egrave;")),
1184 value("à".as_bytes(), tag("agrave;")),
1185 )),
1186 ),
1187 to_s,
1188 )(i)
1189 }
1190 assert_eq!(
1191 esc2(&b"ab&egrave;DEF;"[..]),
1192 Ok((&b";"[..], String::from("abèDEF")))
1193 );
1194 assert_eq!(
1195 esc2(&b"ab&egrave;D&agrave;EF;"[..]),
1196 Ok((&b";"[..], String::from("abèDàEF")))
1197 );
1198 }
1199
1200 #[cfg(feature = "std")]
1201 #[test]
1202 fn escape_transform_str() {
1203 fn esc(i: &str) -> IResult<&str, String> {
1204 escaped_transform(
1205 alpha,
1206 '\\',
1207 alt((
1208 value("\\", tag("\\")),
1209 value("\"", tag("\"")),
1210 value("\n", tag("n")),
1211 )),
1212 )(i)
1213 }
1214
1215 assert_eq!(esc("abcd;"), Ok((";", String::from("abcd"))));
1216 assert_eq!(esc("ab\\\"cd;"), Ok((";", String::from("ab\"cd"))));
1217 assert_eq!(esc("\\\"abcd;"), Ok((";", String::from("\"abcd"))));
1218 assert_eq!(esc("\\n;"), Ok((";", String::from("\n"))));
1219 assert_eq!(esc("ab\\\"12"), Ok(("12", String::from("ab\""))));
1220 assert_eq!(
1221 esc("AB\\"),
1222 Err(Err::Error(error_position!(
1223 "\\",
1224 ErrorKind::EscapedTransform
1225 )))
1226 );
1227 assert_eq!(
1228 esc("AB\\A"),
1229 Err(Err::Error(error_node_position!(
1230 "AB\\A",
1231 ErrorKind::EscapedTransform,
1232 error_position!("A", ErrorKind::Tag)
1233 )))
1234 );
1235
1236 fn esc2(i: &str) -> IResult<&str, String> {
1237 escaped_transform(
1238 alpha,
1239 '&',
1240 alt((value("è", tag("egrave;")), value("à", tag("agrave;")))),
1241 )(i)
1242 }
1243 assert_eq!(esc2("ab&egrave;DEF;"), Ok((";", String::from("abèDEF"))));
1244 assert_eq!(
1245 esc2("ab&egrave;D&agrave;EF;"),
1246 Ok((";", String::from("abèDàEF")))
1247 );
1248
1249 fn esc3(i: &str) -> IResult<&str, String> {
1250 escaped_transform(
1251 alpha,
1252 '␛',
1253 alt((value("\0", tag("0")), value("\n", tag("n")))),
1254 )(i)
1255 }
1256 assert_eq!(esc3("a␛0bc␛n"), Ok(("", String::from("a\0bc\n"))));
1257 }
1258}