1use 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#[derive(Debug, Error)]
14#[error("invalid string encountered")]
15#[cfg_attr(feature = "diagnostics", derive(Diagnostic))]
16pub enum Error {
17 #[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 #[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
34pub 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
64pub 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
81pub fn check<S: AsRef<str>>(string: S) -> Result<(), Error> {
87 check_str(string.as_ref())
88}