use alloc::boxed::Box;
use alloc::vec::Vec;
macro_rules! version {
($range:expr) => {
$range.contains(&VERSION)
};
}
macro_rules! validate_version {
($version:ident) => {
#[allow(clippy::let_unit_value)]
let _ = $crate::format_description::parse::Version::<$version>::IS_VALID;
};
}
mod ast;
mod format_item;
mod lexer;
struct Version<const N: usize>;
impl<const N: usize> Version<N> {
const IS_VALID: () = assert!(N >= 1 && N <= 2);
}
pub fn parse(
s: &str,
) -> Result<Vec<crate::format_description::FormatItem<'_>>, crate::error::InvalidFormatDescription>
{
parse_borrowed::<1>(s)
}
pub fn parse_borrowed<const VERSION: usize>(
s: &str,
) -> Result<Vec<crate::format_description::FormatItem<'_>>, crate::error::InvalidFormatDescription>
{
validate_version!(VERSION);
let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
let ast = ast::parse::<_, VERSION>(&mut lexed);
let format_items = format_item::parse(ast);
Ok(format_items
.map(|res| res.and_then(TryInto::try_into))
.collect::<Result<_, _>>()?)
}
pub fn parse_owned<const VERSION: usize>(
s: &str,
) -> Result<crate::format_description::OwnedFormatItem, crate::error::InvalidFormatDescription> {
validate_version!(VERSION);
let mut lexed = lexer::lex::<VERSION>(s.as_bytes());
let ast = ast::parse::<_, VERSION>(&mut lexed);
let format_items = format_item::parse(ast);
let items = format_items
.map(|res| res.map(Into::into))
.collect::<Result<Box<_>, _>>()?;
Ok(items.into())
}
#[derive(Clone, Copy)]
struct Location {
byte: u32,
}
impl Location {
const fn to(self, end: Self) -> Span {
Span { start: self, end }
}
#[must_use = "this does not modify the original value"]
const fn offset(&self, offset: u32) -> Self {
Self {
byte: self.byte + offset,
}
}
const fn error(self, message: &'static str) -> ErrorInner {
ErrorInner {
_message: message,
_span: Span {
start: self,
end: self,
},
}
}
}
#[derive(Clone, Copy)]
struct Span {
#[allow(clippy::missing_docs_in_private_items)]
start: Location,
#[allow(clippy::missing_docs_in_private_items)]
end: Location,
}
impl Span {
#[must_use = "this does not modify the original value"]
const fn shrink_to_start(&self) -> Self {
Self {
start: self.start,
end: self.start,
}
}
#[must_use = "this does not modify the original value"]
const fn shrink_to_end(&self) -> Self {
Self {
start: self.end,
end: self.end,
}
}
#[must_use = "this does not modify the original value"]
const fn shrink_to_before(&self, pos: u32) -> Self {
Self {
start: self.start,
end: Location {
byte: self.start.byte + pos - 1,
},
}
}
#[must_use = "this does not modify the original value"]
const fn shrink_to_after(&self, pos: u32) -> Self {
Self {
start: Location {
byte: self.start.byte + pos + 1,
},
end: self.end,
}
}
const fn error(self, message: &'static str) -> ErrorInner {
ErrorInner {
_message: message,
_span: self,
}
}
}
#[derive(Clone, Copy)]
struct Spanned<T> {
value: T,
span: Span,
}
impl<T> core::ops::Deref for Spanned<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.value
}
}
trait SpannedValue: Sized {
fn spanned(self, span: Span) -> Spanned<Self>;
}
impl<T> SpannedValue for T {
fn spanned(self, span: Span) -> Spanned<Self> {
Spanned { value: self, span }
}
}
struct ErrorInner {
_message: &'static str,
_span: Span,
}
struct Error {
_inner: Unused<ErrorInner>,
public: crate::error::InvalidFormatDescription,
}
impl From<Error> for crate::error::InvalidFormatDescription {
fn from(error: Error) -> Self {
error.public
}
}
struct Unused<T>(core::marker::PhantomData<T>);
#[allow(clippy::missing_const_for_fn)] fn unused<T>(_: T) -> Unused<T> {
Unused(core::marker::PhantomData)
}