1mod class;
25mod method;
26mod ty;
27
28use std::convert::Infallible;
29
30pub use class::*;
31pub use method::*;
32pub use ty::*;
33
34pub trait Parse<'s>: Sized {
36 type Error;
38
39 #[allow(clippy::missing_errors_doc)]
41 fn parse_from(cursor: &mut Cursor<'s>) -> Result<Self, Self::Error>;
42}
43
44#[non_exhaustive]
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub enum ReprForm {
48 JLS,
50 Internal,
55}
56
57impl ReprForm {
58 const fn package_separator(&self) -> char {
59 match self {
60 Self::JLS => '.',
61 Self::Internal => '/',
62 }
63 }
64}
65
66#[derive(Debug, Clone)]
68pub struct Cursor<'a>(&'a str);
69
70impl<'a> Cursor<'a> {
71 #[inline]
73 pub const fn new(s: &'a str) -> Self {
74 Self(s)
75 }
76
77 pub fn get_char(&mut self) -> char {
83 let c = self.0.chars().next().expect("end of file");
84 self.advance_by(c.len_utf8());
85 c
86 }
87
88 #[inline]
90 #[allow(clippy::missing_panics_doc)] pub fn advance<F, U>(&mut self, f: F) -> U
92 where
93 F: FnOnce(&'a str) -> (U, &'a str),
94 {
95 self.try_advance(|s| Result::<_, Infallible>::Ok(f(s)))
96 .unwrap()
97 }
98
99 #[inline]
105 pub fn try_advance<F, U, Err>(&mut self, f: F) -> Result<U, Err>
106 where
107 F: FnOnce(&'a str) -> Result<(U, &'a str), Err>,
108 {
109 let (ret, leftover) = f(self.0)?;
110 self.0 = leftover;
111 Ok(ret)
112 }
113
114 #[inline]
116 pub const fn get(&self) -> &'a str {
117 self.0
118 }
119
120 #[inline]
122 pub const fn set(&mut self, s: &'a str) {
123 self.0 = s;
124 }
125
126 #[inline]
132 pub fn advance_by(&mut self, n: usize) {
133 self.advance(|s| ((), &s[n..]))
134 }
135
136 #[inline]
138 pub fn clear(&mut self) {
139 self.0 = "";
140 }
141}
142
143fn strip_digits_prefix(s: &str) -> (Option<u32>, &str) {
144 let mut chars = s.char_indices();
145 let (digits, last_index) = chars
146 .by_ref()
147 .map_while(|(index, c)| c.to_digit(10).map(|d| (index, d)))
148 .fold((0, None), |(n, _), (ci, d)| (n * 10 + d, Some(ci)));
149 let leftover = last_index.map_or(s, |i| &s[i + 1..]);
150 (last_index.map(|_| digits), leftover)
151}
152
153#[allow(clippy::missing_errors_doc)]
155#[inline]
156pub fn parse<'a, T>(value: &'a str) -> Result<T, T::Error>
157where
158 T: Parse<'a>,
159{
160 T::parse_from(&mut Cursor(value))
161}
162
163#[cfg(test)]
164fn validate_rw<'a, T>(value: &'a str)
165where
166 T: Parse<'a> + std::fmt::Display,
167 T::Error: std::fmt::Debug,
168{
169 use std::marker::PhantomData;
170
171 struct ClearValidator<T>(String, PhantomData<T>);
172
173 impl<'a, T> Parse<'a> for ClearValidator<T>
174 where
175 T: Parse<'a> + std::fmt::Display,
176 {
177 type Error = T::Error;
178
179 fn parse_from(cursor: &mut Cursor<'a>) -> Result<Self, Self::Error> {
180 let val = T::parse_from(cursor)?;
181 assert_eq!(cursor.get(), "", "non-empty string buf left");
182 Ok(Self(val.to_string(), PhantomData))
183 }
184 }
185
186 assert_eq!(
187 parse::<'a, ClearValidator<T>>(value).map(|o| o.0).unwrap(),
188 value
189 );
190}