use crate::parser::err::{ParseError, ParseErrors, ToASTError, ToASTErrorKind};
use crate::parser::Loc;
use std::fmt::Display;
use std::str::FromStr;
pub trait FromNormalizedStr: FromStr<Err = ParseErrors> + Display {
fn from_normalized_str(s: &str) -> Result<Self, ParseErrors> {
default_from_normalized_str(s, Self::describe_self)
}
fn describe_self() -> &'static str;
}
pub fn default_from_normalized_str<T: FromStr<Err = ParseErrors> + Display>(
s: &str,
describe_self: impl FnOnce() -> &'static str,
) -> Result<T, ParseErrors> {
let parsed = T::from_str(s)?;
let normalized_src = parsed.to_string();
if normalized_src == s {
Ok(parsed)
} else {
let diff_byte = s
.bytes()
.zip(normalized_src.bytes())
.enumerate()
.find(|(_, (b0, b1))| b0 != b1)
.map(|(idx, _)| idx)
.unwrap_or_else(|| s.len().min(normalized_src.len()));
Err(ParseErrors::singleton(ParseError::ToAST(ToASTError::new(
ToASTErrorKind::NonNormalizedString {
kind: describe_self(),
src: s.to_string(),
normalized_src,
},
Some(Loc::new(diff_byte, s.into())),
))))
}
}