mod class;
mod method;
mod ty;
use std::convert::Infallible;
pub use class::*;
pub use method::*;
pub use ty::*;
pub trait Parse<'s>: Sized {
type Error;
#[allow(clippy::missing_errors_doc)]
fn parse_from(cursor: &mut Cursor<'s>) -> Result<Self, Self::Error>;
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ReprForm {
JLS,
Internal,
}
impl ReprForm {
const fn package_separator(&self) -> char {
match self {
Self::JLS => '.',
Self::Internal => '/',
}
}
}
#[derive(Debug, Clone)]
pub struct Cursor<'a>(&'a str);
impl<'a> Cursor<'a> {
#[inline]
pub const fn new(s: &'a str) -> Self {
Self(s)
}
pub fn get_char(&mut self) -> char {
let c = self.0.chars().next().expect("end of file");
self.advance_by(c.len_utf8());
c
}
#[inline]
#[allow(clippy::missing_panics_doc)] pub fn advance<F, U>(&mut self, f: F) -> U
where
F: FnOnce(&'a str) -> (U, &'a str),
{
self.try_advance(|s| Result::<_, Infallible>::Ok(f(s)))
.unwrap()
}
#[inline]
pub fn try_advance<F, U, Err>(&mut self, f: F) -> Result<U, Err>
where
F: FnOnce(&'a str) -> Result<(U, &'a str), Err>,
{
let (ret, leftover) = f(self.0)?;
self.0 = leftover;
Ok(ret)
}
#[inline]
pub const fn get(&self) -> &'a str {
self.0
}
#[inline]
pub const fn set(&mut self, s: &'a str) {
self.0 = s;
}
#[inline]
pub fn advance_by(&mut self, n: usize) {
self.advance(|s| ((), &s[n..]))
}
#[inline]
pub fn clear(&mut self) {
self.0 = "";
}
}
fn strip_digits_prefix(s: &str) -> (Option<u32>, &str) {
let mut chars = s.char_indices();
let (digits, last_index) = chars
.by_ref()
.map_while(|(index, c)| c.to_digit(10).map(|d| (index, d)))
.fold((0, None), |(n, _), (ci, d)| (n * 10 + d, Some(ci)));
let leftover = last_index.map_or(s, |i| &s[i + 1..]);
(last_index.map(|_| digits), leftover)
}
#[allow(clippy::missing_errors_doc)]
#[inline]
pub fn parse<'a, T>(value: &'a str) -> Result<T, T::Error>
where
T: Parse<'a>,
{
T::parse_from(&mut Cursor(value))
}
#[cfg(test)]
fn validate_rw<'a, T>(value: &'a str)
where
T: Parse<'a> + std::fmt::Display,
T::Error: std::fmt::Debug,
{
use std::marker::PhantomData;
struct ClearValidator<T>(String, PhantomData<T>);
impl<'a, T> Parse<'a> for ClearValidator<T>
where
T: Parse<'a> + std::fmt::Display,
{
type Error = T::Error;
fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
let val = T::parse_from(cursor)?;
assert_eq!(cursor.get(), "", "non-empty string buf left");
Ok(Self(val.to_string(), PhantomData))
}
}
assert_eq!(
parse::<'a, ClearValidator<T>>(value).map(|o| o.0).unwrap(),
value
);
}