#[cfg(feature = "chumsky")]
use chumsky::{
IterParser as _, Parser,
prelude::{any, just, one_of},
text::digits,
};
#[cfg(feature = "chumsky")]
#[must_use]
pub fn url_text_component_parser<'src>()
-> impl Parser<'src, &'src str, String, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
any()
.filter(|c: &char| {
c.is_alphabetic() || c.is_numeric() || *c == '%' || *c == '-' || *c == '~' || *c == '.'
})
.repeated()
.at_least(1)
.collect::<String>()
.try_map(|s, span| {
percent_encoding::percent_decode(s.as_bytes())
.decode_utf8()
.map(|s| s.into_owned())
.map_err(|e| chumsky::error::Rich::custom(span, format!("{e:?}")))
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn usize_parser<'src>()
-> impl Parser<'src, &'src str, usize, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
digits(10).collect::<String>().try_map(|c: String, span| {
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as usize: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn isize_parser<'src>()
-> impl Parser<'src, &'src str, isize, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
one_of("+-")
.or_not()
.then(digits(10).collect::<String>())
.try_map(|(sign, c): (Option<char>, String), span| {
let c = if let Some(sign) = sign {
format!("{sign}{c}")
} else {
c
};
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as isize: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn u8_parser<'src>()
-> impl Parser<'src, &'src str, u8, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
digits(10).collect::<String>().try_map(|c: String, span| {
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as u8: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn u16_parser<'src>()
-> impl Parser<'src, &'src str, u16, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
digits(10).collect::<String>().try_map(|c: String, span| {
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as u16: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn u32_parser<'src>()
-> impl Parser<'src, &'src str, u32, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
digits(10).collect::<String>().try_map(|c: String, span| {
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as u32: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn u64_parser<'src>()
-> impl Parser<'src, &'src str, u64, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
digits(10).collect::<String>().try_map(|c: String, span| {
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as u64: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn i8_parser<'src>()
-> impl Parser<'src, &'src str, i8, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
one_of("+-")
.or_not()
.then(digits(10).collect::<String>())
.try_map(|(sign, c): (Option<char>, String), span| {
let c = if let Some(sign) = sign {
format!("{sign}{c}")
} else {
c
};
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as i8: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn i16_parser<'src>()
-> impl Parser<'src, &'src str, i16, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
one_of("+-")
.or_not()
.then(digits(10).collect::<String>())
.try_map(|(sign, c): (Option<char>, String), span| {
let c = if let Some(sign) = sign {
format!("{sign}{c}")
} else {
c
};
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as i16: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn i32_parser<'src>()
-> impl Parser<'src, &'src str, i32, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
one_of("+-")
.or_not()
.then(digits(10).collect::<String>())
.try_map(|(sign, c): (Option<char>, String), span| {
let c = if let Some(sign) = sign {
format!("{sign}{c}")
} else {
c
};
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as i32: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn i64_parser<'src>()
-> impl Parser<'src, &'src str, i64, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
one_of("+-")
.or_not()
.then(digits(10).collect::<String>())
.try_map(|(sign, c): (Option<char>, String), span| {
let c = if let Some(sign) = sign {
format!("{sign}{c}")
} else {
c
};
c.parse().map_err(|err| {
chumsky::error::Rich::custom(span, format!("failed to parse {c} as i64: {err:?}"))
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn unsigned_f32_parser<'src>()
-> impl Parser<'src, &'src str, f32, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
digits(10)
.collect::<String>()
.then(
just('.')
.ignore_then(digits(10).collect::<String>())
.or_not(),
)
.try_map(|(before_point, after_point), span| {
let raw_float = format!(
"{}.{}",
before_point,
after_point.unwrap_or_else(|| "0".to_string())
);
raw_float.parse().map_err(|err| {
chumsky::error::Rich::custom(
span,
format!("Could not parse {raw_float} as f32: {err:?}"),
)
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn unsigned_f64_parser<'src>()
-> impl Parser<'src, &'src str, f64, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
digits(10)
.collect::<String>()
.then(
just('.')
.ignore_then(digits(10).collect::<String>())
.or_not(),
)
.try_map(|(before_point, after_point), span| {
let raw_float = format!(
"{}.{}",
before_point,
after_point.unwrap_or_else(|| "0".to_string())
);
raw_float.parse().map_err(|err| {
chumsky::error::Rich::custom(
span,
format!("Could not parse {raw_float} as f64: {err:?}"),
)
})
})
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn f32_parser<'src>()
-> impl Parser<'src, &'src str, f32, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
one_of("+-")
.or_not()
.then(unsigned_f32_parser())
.map(
|(sign, value)| {
if sign == Some('-') { -value } else { value }
},
)
}
#[cfg(feature = "chumsky")]
#[must_use]
pub fn f64_parser<'src>()
-> impl Parser<'src, &'src str, f64, chumsky::extra::Err<chumsky::error::Rich<'src, char>>> {
one_of("+-")
.or_not()
.then(unsigned_f64_parser())
.map(
|(sign, value)| {
if sign == Some('-') { -value } else { value }
},
)
}