pkce_std/check/
string.rs

1//! Checking PKCE code verifier strings.
2
3use const_macros::{const_map_err, const_try};
4
5#[cfg(feature = "diagnostics")]
6use miette::Diagnostic;
7
8use thiserror::Error;
9
10use crate::check::{ascii, bytes};
11
12/// Represents sources of errors that can occur when checking strings.
13#[derive(Debug, Error)]
14#[error("invalid string encountered")]
15#[cfg_attr(feature = "diagnostics", derive(Diagnostic))]
16pub enum Error {
17    /// Non-ASCII string encountered.
18    #[cfg_attr(
19        feature = "diagnostics",
20        diagnostic(
21            code(pkce_std::check::string::ascii),
22            help("ensure the string is ASCII")
23        )
24    )]
25    Ascii(#[from] ascii::Error),
26    /// Invalid byte encountered.
27    #[cfg_attr(
28        feature = "diagnostics",
29        diagnostic(code(pkce_std::check::string::byte), help("ensure the byte is valid"))
30    )]
31    Bytes(#[from] bytes::Error),
32}
33
34/// Recursively checks that the given string contains valid characters only.
35///
36/// One may need to increase the recursion limit manually to use this `const` function.
37///
38/// This is done via applying the `recursion_limit` attribute to the crate:
39///
40/// ```
41/// #![recursion_limit = "256"]
42/// ```
43///
44/// # Errors
45///
46/// Returns [`enum@Error`] on non-ASCII or otherwise invalid strings.
47pub const fn const_check_str(string: &str) -> Result<(), Error> {
48    pub const fn check_bytes(bytes: &[u8]) -> Result<(), bytes::Error> {
49        match *bytes {
50            [] => Ok(()),
51            [byte, ref rest @ ..] => {
52                const_try!(bytes::check(byte));
53
54                check_bytes(rest)
55            }
56        }
57    }
58
59    const_try!(const_map_err!(ascii::check_str(string) => Error::Ascii));
60
61    const_map_err!(check_bytes(string.as_bytes()) => Error::Bytes)
62}
63
64/// Iterarively checks that the given string contains valid characters only.
65///
66/// # Errors
67///
68/// Returns [`enum@Error`] on non-ASCII or otherwise invalid codes.
69pub fn check_str(string: &str) -> Result<(), Error> {
70    fn check_bytes(bytes: &[u8]) -> Result<(), bytes::Error> {
71        bytes.iter().copied().try_for_each(bytes::check)
72    }
73
74    ascii::check(string)?;
75
76    check_bytes(string.as_bytes())?;
77
78    Ok(())
79}
80
81/// Similar to [`check_str`], except it is generic over [`AsRef<str>`].
82///
83/// # Errors
84///
85/// Any [`enum@Error`] in [`check_str`] is propagated.
86pub fn check<S: AsRef<str>>(string: S) -> Result<(), Error> {
87    check_str(string.as_ref())
88}