use alloc::boxed::Box;
use alloc::vec::Vec;
pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
use crate::{error, format_description};
macro_rules! version {
($range:expr) => {
$range.contains(&VERSION)
};
}
macro_rules! validate_version {
($version:ident) => {
const {
assert!($version >= 1 && $version <= 2);
}
};
}
mod ast;
mod format_item;
mod lexer;
mod strftime;
#[inline]
pub fn parse(
s: &str,
) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
parse_borrowed::<1>(s)
}
#[inline]
pub fn parse_borrowed<const VERSION: usize>(
s: &str,
) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, 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<_, _>>()?)
}
#[inline]
pub fn parse_owned<const VERSION: usize>(
s: &str,
) -> Result<format_description::OwnedFormatItem, 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.collect::<Result<Box<_>, _>>()?;
Ok(items.into())
}
#[inline]
fn attach_location<'item>(
iter: impl Iterator<Item = &'item u8>,
) -> impl Iterator<Item = (&'item u8, Location)> {
let mut byte_pos = 0;
iter.map(move |byte| {
let location = Location { byte: byte_pos };
byte_pos += 1;
(byte, location)
})
}
#[derive(Clone, Copy)]
struct Location {
byte: u32,
}
impl Location {
#[inline]
const fn to(self, end: Self) -> Span {
Span { start: self, end }
}
#[inline]
const fn to_self(self) -> Span {
Span {
start: self,
end: self,
}
}
#[must_use = "this does not modify the original value"]
#[inline]
const fn offset(&self, offset: u32) -> Self {
Self {
byte: self.byte + offset,
}
}
#[inline]
const fn error(self, message: &'static str) -> ErrorInner {
ErrorInner {
_message: message,
_span: Span {
start: self,
end: self,
},
}
}
}
#[derive(Clone, Copy)]
struct Span {
start: Location,
end: Location,
}
impl Span {
#[must_use = "this does not modify the original value"]
#[inline]
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"]
#[inline]
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"]
#[inline]
const fn shrink_to_after(&self, pos: u32) -> Self {
Self {
start: Location {
byte: self.start.byte + pos + 1,
},
end: self.end,
}
}
#[inline]
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;
#[inline]
fn deref(&self) -> &Self::Target {
&self.value
}
}
trait SpannedValue: Sized {
fn spanned(self, span: Span) -> Spanned<Self>;
}
impl<T> SpannedValue for T {
#[inline]
fn spanned(self, span: Span) -> Spanned<Self> {
Spanned { value: self, span }
}
}
struct ErrorInner {
_message: &'static str,
_span: Span,
}
struct Error {
_inner: Unused<ErrorInner>,
public: error::InvalidFormatDescription,
}
impl From<Error> for error::InvalidFormatDescription {
#[inline]
fn from(error: Error) -> Self {
error.public
}
}
struct Unused<T>(core::marker::PhantomData<T>);
#[inline]
fn unused<T>(_: T) -> Unused<T> {
Unused(core::marker::PhantomData)
}