Coverage Report

Created: 2025-12-20 06:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/nom-8.0.0/src/character/mod.rs
Line
Count
Source
1
//! Character specific parsers and combinators
2
//!
3
//! Functions recognizing specific characters
4
5
use core::marker::PhantomData;
6
7
use crate::error::ErrorKind;
8
use crate::FindToken;
9
use crate::IsStreaming;
10
use crate::Mode;
11
use crate::{error::ParseError, AsChar, Err, IResult, Input, Needed, Parser};
12
13
#[cfg(test)]
14
mod tests;
15
16
pub mod complete;
17
pub mod streaming;
18
19
#[inline]
20
#[doc(hidden)]
21
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_alpha`")]
22
0
pub fn is_alphabetic(chr: u8) -> bool {
23
0
  matches!(chr, 0x41..=0x5A | 0x61..=0x7A)
24
0
}
25
26
#[inline]
27
#[doc(hidden)]
28
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_dec_digit`")]
29
0
pub fn is_digit(chr: u8) -> bool {
30
0
  matches!(chr, 0x30..=0x39)
31
0
}
32
33
#[inline]
34
#[doc(hidden)]
35
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_hex_digit`")]
36
0
pub fn is_hex_digit(chr: u8) -> bool {
37
0
  matches!(chr, 0x30..=0x39 | 0x41..=0x46 | 0x61..=0x66)
38
0
}
39
40
#[inline]
41
#[doc(hidden)]
42
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_oct_digit`")]
43
0
pub fn is_oct_digit(chr: u8) -> bool {
44
0
  matches!(chr, 0x30..=0x37)
45
0
}
46
47
/// Tests if byte is ASCII binary digit: 0-1
48
///
49
/// # Example
50
///
51
/// ```
52
/// # use nom::character::is_bin_digit;
53
/// assert_eq!(is_bin_digit(b'a'), false);
54
/// assert_eq!(is_bin_digit(b'2'), false);
55
/// assert_eq!(is_bin_digit(b'0'), true);
56
/// assert_eq!(is_bin_digit(b'1'), true);
57
/// ```
58
#[inline]
59
0
pub fn is_bin_digit(chr: u8) -> bool {
60
0
  matches!(chr, 0x30..=0x31)
61
0
}
62
63
#[inline]
64
#[doc(hidden)]
65
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_alphanum`")]
66
0
pub fn is_alphanumeric(chr: u8) -> bool {
67
0
  AsChar::is_alphanum(chr)
68
0
}
69
70
#[inline]
71
#[doc(hidden)]
72
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_space`")]
73
0
pub fn is_space(chr: u8) -> bool {
74
0
  chr == b' ' || chr == b'\t'
75
0
}
76
77
#[inline]
78
#[doc(hidden)]
79
#[deprecated(since = "8.0.0", note = "Replaced with `AsChar::is_newline`")]
80
0
pub fn is_newline(chr: u8) -> bool {
81
0
  chr == b'\n'
82
0
}
83
84
/// Recognizes one character.
85
///
86
/// # Example
87
///
88
/// ```
89
/// # use nom::{Err, error::{ErrorKind, Error}, Needed, IResult};
90
/// # use nom::character::streaming::char;
91
/// fn parser(i: &str) -> IResult<&str, char> {
92
///     char('a')(i)
93
/// }
94
/// assert_eq!(parser("abc"), Ok(("bc", 'a')));
95
/// assert_eq!(parser("bc"), Err(Err::Error(Error::new("bc", ErrorKind::Char))));
96
/// assert_eq!(parser(""), Err(Err::Incomplete(Needed::new(1))));
97
/// ```
98
0
pub fn char<I, Error: ParseError<I>>(c: char) -> impl Parser<I, Output = char, Error = Error>
99
0
where
100
0
  I: Input,
101
0
  <I as Input>::Item: AsChar,
102
{
103
0
  Char { c, e: PhantomData }
104
0
}
Unexecuted instantiation: nom::character::char::<&str, nom::error::Error<&str>>
Unexecuted instantiation: nom::character::char::<_, _>
105
106
/// Parser implementation for [char()]
107
pub struct Char<E> {
108
  c: char,
109
  e: PhantomData<E>,
110
}
111
112
impl<I, Error: ParseError<I>> Parser<I> for Char<Error>
113
where
114
  I: Input,
115
  <I as Input>::Item: AsChar,
116
{
117
  type Output = char;
118
  type Error = Error;
119
  #[inline(always)]
120
0
  fn process<OM: crate::OutputMode>(
121
0
    &mut self,
122
0
    i: I,
123
0
  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
124
0
    match (i).iter_elements().next().map(|t| {
125
0
      let b = t.as_char() == self.c;
126
0
      (&self.c, b)
127
0
    }) {
Unexecuted instantiation: <nom::character::Char<nom::error::Error<&str>> as nom::internal::Parser<&str>>::process::<nom::internal::OutputM<nom::internal::Emit, nom::internal::Emit, nom::internal::Complete>>::{closure#0}
Unexecuted instantiation: <nom::character::Char<_> as nom::internal::Parser<_>>::process::<_>::{closure#0}
128
      None => {
129
0
        if OM::Incomplete::is_streaming() {
130
0
          Err(Err::Incomplete(Needed::new(self.c.len() - i.input_len())))
131
        } else {
132
0
          Err(Err::Error(OM::Error::bind(|| Error::from_char(i, self.c))))
Unexecuted instantiation: <nom::character::Char<nom::error::Error<&str>> as nom::internal::Parser<&str>>::process::<nom::internal::OutputM<nom::internal::Emit, nom::internal::Emit, nom::internal::Complete>>::{closure#1}
Unexecuted instantiation: <nom::character::Char<_> as nom::internal::Parser<_>>::process::<_>::{closure#1}
133
        }
134
      }
135
0
      Some((_, false)) => Err(Err::Error(OM::Error::bind(|| Error::from_char(i, self.c)))),
Unexecuted instantiation: <nom::character::Char<nom::error::Error<&str>> as nom::internal::Parser<&str>>::process::<nom::internal::OutputM<nom::internal::Emit, nom::internal::Emit, nom::internal::Complete>>::{closure#2}
Unexecuted instantiation: <nom::character::Char<_> as nom::internal::Parser<_>>::process::<_>::{closure#2}
136
0
      Some((c, true)) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
Unexecuted instantiation: <nom::character::Char<nom::error::Error<&str>> as nom::internal::Parser<&str>>::process::<nom::internal::OutputM<nom::internal::Emit, nom::internal::Emit, nom::internal::Complete>>::{closure#3}
Unexecuted instantiation: <nom::character::Char<_> as nom::internal::Parser<_>>::process::<_>::{closure#3}
137
    }
138
0
  }
Unexecuted instantiation: <nom::character::Char<nom::error::Error<&str>> as nom::internal::Parser<&str>>::process::<nom::internal::OutputM<nom::internal::Emit, nom::internal::Emit, nom::internal::Complete>>
Unexecuted instantiation: <nom::character::Char<_> as nom::internal::Parser<_>>::process::<_>
139
}
140
141
/// Recognizes one character and checks that it satisfies a predicate
142
///
143
/// # Example
144
///
145
/// ```
146
/// # use nom::{Err, error::{ErrorKind, Error}, Needed, IResult};
147
/// # use nom::character::complete::satisfy;
148
/// fn parser(i: &str) -> IResult<&str, char> {
149
///     satisfy(|c| c == 'a' || c == 'b')(i)
150
/// }
151
/// assert_eq!(parser("abc"), Ok(("bc", 'a')));
152
/// assert_eq!(parser("cd"), Err(Err::Error(Error::new("cd", ErrorKind::Satisfy))));
153
/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Satisfy))));
154
/// ```
155
0
pub fn satisfy<F, I, Error: ParseError<I>>(
156
0
  predicate: F,
157
0
) -> impl Parser<I, Output = char, Error = Error>
158
0
where
159
0
  I: Input,
160
0
  <I as Input>::Item: AsChar,
161
0
  F: Fn(char) -> bool,
162
{
163
  Satisfy {
164
0
    predicate,
165
0
    make_error: |i: I| Error::from_error_kind(i, ErrorKind::Satisfy),
166
  }
167
0
}
168
169
/// Parser implementation for [satisfy]
170
pub struct Satisfy<F, MakeError> {
171
  predicate: F,
172
  make_error: MakeError,
173
}
174
175
impl<I, Error: ParseError<I>, F, MakeError> Parser<I> for Satisfy<F, MakeError>
176
where
177
  I: Input,
178
  <I as Input>::Item: AsChar,
179
  F: Fn(char) -> bool,
180
  MakeError: Fn(I) -> Error,
181
{
182
  type Output = char;
183
  type Error = Error;
184
185
  #[inline(always)]
186
0
  fn process<OM: crate::OutputMode>(
187
0
    &mut self,
188
0
    i: I,
189
0
  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
190
0
    match (i).iter_elements().next().map(|t| {
191
0
      let c = t.as_char();
192
0
      let b = (self.predicate)(c);
193
0
      (c, b)
194
0
    }) {
195
      None => {
196
0
        if OM::Incomplete::is_streaming() {
197
0
          Err(Err::Incomplete(Needed::Unknown))
198
        } else {
199
0
          Err(Err::Error(OM::Error::bind(|| (self.make_error)(i))))
200
        }
201
      }
202
0
      Some((_, false)) => Err(Err::Error(OM::Error::bind(|| (self.make_error)(i)))),
203
0
      Some((c, true)) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
204
    }
205
0
  }
206
}
207
208
/// Recognizes one of the provided characters.
209
///
210
/// # Example
211
///
212
/// ```
213
/// # use nom::{Err, error::ErrorKind};
214
/// # use nom::character::complete::one_of;
215
/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("abc")("b"), Ok(("", 'b')));
216
/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("a")("bc"), Err(Err::Error(("bc", ErrorKind::OneOf))));
217
/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("a")(""), Err(Err::Error(("", ErrorKind::OneOf))));
218
/// ```
219
0
pub fn one_of<I, T, Error: ParseError<I>>(list: T) -> impl Parser<I, Output = char, Error = Error>
220
0
where
221
0
  I: Input,
222
0
  <I as Input>::Item: AsChar,
223
0
  T: FindToken<char>,
224
{
225
  Satisfy {
226
0
    predicate: move |c: char| list.find_token(c),
227
0
    make_error: move |i| Error::from_error_kind(i, ErrorKind::OneOf),
228
  }
229
0
}
230
231
//. Recognizes a character that is not in the provided characters.
232
///
233
/// # Example
234
///
235
/// ```
236
/// # use nom::{Err, error::ErrorKind, Needed};
237
/// # use nom::character::streaming::none_of;
238
/// assert_eq!(none_of::<_, _, (_, ErrorKind)>("abc")("z"), Ok(("", 'z')));
239
/// assert_eq!(none_of::<_, _, (_, ErrorKind)>("ab")("a"), Err(Err::Error(("a", ErrorKind::NoneOf))));
240
/// assert_eq!(none_of::<_, _, (_, ErrorKind)>("a")(""), Err(Err::Incomplete(Needed::Unknown)));
241
/// ```
242
0
pub fn none_of<I, T, Error: ParseError<I>>(list: T) -> impl Parser<I, Output = char, Error = Error>
243
0
where
244
0
  I: Input,
245
0
  <I as Input>::Item: AsChar,
246
0
  T: FindToken<char>,
247
{
248
  Satisfy {
249
0
    predicate: move |c: char| !list.find_token(c),
250
0
    make_error: move |i| Error::from_error_kind(i, ErrorKind::NoneOf),
251
  }
252
0
}
253
254
// Matches one byte as a character. Note that the input type will
255
/// accept a `str`, but not a `&[u8]`, unlike many other nom parsers.
256
///
257
/// # Example
258
///
259
/// ```
260
/// # use nom::{character::complete::anychar, Err, error::{Error, ErrorKind}, IResult};
261
/// fn parser(input: &str) -> IResult<&str, char> {
262
///     anychar(input)
263
/// }
264
///
265
/// assert_eq!(parser("abc"), Ok(("bc",'a')));
266
/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Eof))));
267
/// ```
268
0
pub fn anychar<T, E: ParseError<T>>(input: T) -> IResult<T, char, E>
269
0
where
270
0
  T: Input,
271
0
  <T as Input>::Item: AsChar,
272
{
273
0
  let mut it = input.iter_elements();
274
0
  match it.next() {
275
0
    None => Err(Err::Error(E::from_error_kind(input, ErrorKind::Eof))),
276
0
    Some(c) => Ok((input.take_from(c.len()), c.as_char())),
277
  }
278
0
}
279
280
/// Parser implementation for char
281
pub struct AnyChar<E> {
282
  e: PhantomData<E>,
283
}
284
285
impl<I, Error: ParseError<I>> Parser<I> for AnyChar<Error>
286
where
287
  I: Input,
288
  <I as Input>::Item: AsChar,
289
{
290
  type Output = char;
291
  type Error = Error;
292
293
0
  fn process<OM: crate::OutputMode>(
294
0
    &mut self,
295
0
    i: I,
296
0
  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
297
0
    match (i).iter_elements().next() {
298
      None => {
299
0
        if OM::Incomplete::is_streaming() {
300
0
          Err(Err::Incomplete(Needed::new(1)))
301
        } else {
302
0
          Err(Err::Error(OM::Error::bind(|| {
303
0
            Error::from_error_kind(i, ErrorKind::Eof)
304
0
          })))
305
        }
306
      }
307
0
      Some(c) => Ok((i.take_from(c.len()), OM::Output::bind(|| c.as_char()))),
308
    }
309
0
  }
310
}
311
312
/// Recognizes one or more ASCII numerical characters: 0-9
313
///
314
/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there's not enough input data,
315
/// or if no terminating token is found (a non digit character).
316
/// # Example
317
///
318
/// ```
319
/// # use nom::{Err, error::ErrorKind, IResult, Needed};
320
/// # use nom::character::streaming::digit1;
321
/// assert_eq!(digit1::<_, (_, ErrorKind)>("21c"), Ok(("c", "21")));
322
/// assert_eq!(digit1::<_, (_, ErrorKind)>("c1"), Err(Err::Error(("c1", ErrorKind::Digit))));
323
/// assert_eq!(digit1::<_, (_, ErrorKind)>(""), Err(Err::Incomplete(Needed::new(1))));
324
/// ```
325
0
pub fn digit1<T, E: ParseError<T>>() -> impl Parser<T, Output = T, Error = E>
326
0
where
327
0
  T: Input,
328
0
  <T as Input>::Item: AsChar,
329
{
330
0
  Digit1 { e: PhantomData }
331
0
}
332
333
/// Parser implementation for [digit1]
334
pub struct Digit1<E> {
335
  e: PhantomData<E>,
336
}
337
338
impl<I: Input, E: ParseError<I>> Parser<I> for Digit1<E>
339
where
340
  <I as Input>::Item: AsChar,
341
{
342
  type Output = I;
343
344
  type Error = E;
345
346
  #[inline]
347
0
  fn process<OM: crate::OutputMode>(
348
0
    &mut self,
349
0
    input: I,
350
0
  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
351
0
    input.split_at_position_mode1::<OM, _, _>(|item| !item.is_dec_digit(), ErrorKind::Digit)
352
0
  }
353
}
354
355
/// Recognizes zero or more spaces, tabs, carriage returns and line feeds.
356
///
357
/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there's not enough input data,
358
/// or if no terminating token is found (a non space character).
359
/// # Example
360
///
361
/// ```
362
/// # use nom::{Err, error::ErrorKind, IResult, Needed};
363
/// # use nom::character::streaming::multispace0;
364
/// assert_eq!(multispace0::<_, (_, ErrorKind)>(" \t\n\r21c"), Ok(("21c", " \t\n\r")));
365
/// assert_eq!(multispace0::<_, (_, ErrorKind)>("Z21c"), Ok(("Z21c", "")));
366
/// assert_eq!(multispace0::<_, (_, ErrorKind)>(""), Err(Err::Incomplete(Needed::new(1))));
367
/// ```
368
0
pub fn multispace0<T, E: ParseError<T>>() -> impl Parser<T, Output = T, Error = E>
369
0
where
370
0
  T: Input,
371
0
  <T as Input>::Item: AsChar,
372
{
373
0
  MultiSpace0 { e: PhantomData }
374
  /*input.split_at_position(|item| {
375
    let c = item.as_char();
376
    !(c == ' ' || c == '\t' || c == '\r' || c == '\n')
377
  })*/
378
0
}
379
380
/// Parser implementation for [multispace0()]
381
pub struct MultiSpace0<E> {
382
  e: PhantomData<E>,
383
}
384
385
impl<I, Error: ParseError<I>> Parser<I> for MultiSpace0<Error>
386
where
387
  I: Input,
388
  <I as Input>::Item: AsChar,
389
{
390
  type Output = I;
391
  type Error = Error;
392
393
0
  fn process<OM: crate::OutputMode>(
394
0
    &mut self,
395
0
    i: I,
396
0
  ) -> crate::PResult<OM, I, Self::Output, Self::Error> {
397
0
    i.split_at_position_mode::<OM, _, _>(|item| {
398
0
      let c = item.as_char();
399
0
      !(c == ' ' || c == '\t' || c == '\r' || c == '\n')
400
0
    })
401
0
  }
402
}