use alloc::vec::Vec;
use self::lexer_ast::parse_generic;
use self::sealed::{Version, VersionedParser};
pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
use crate::error;
use crate::format_description::{BorrowedFormatItem, FormatDescriptionV3, OwnedFormatItem};
macro_rules! version {
($pat:pat) => {
const { matches!(VERSION, $pat) }
};
}
macro_rules! assert_version {
() => {
const {
assert!(matches!(VERSION, 1..=3), "invalid version provided");
}
};
}
mod format_item;
mod lexer_ast;
mod strftime;
mod sealed {
use super::*;
#[expect(
missing_debug_implementations,
reason = "only used at the type level; not public API"
)]
pub struct Version<const N: usize>;
pub trait VersionedParser {
type BorrowedOutput<'input>;
type OwnedOutput;
fn parse_borrowed(
s: &str,
) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription>;
fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription>;
}
}
impl VersionedParser for Version<1> {
type BorrowedOutput<'input> = Vec<BorrowedFormatItem<'input>>;
type OwnedOutput = OwnedFormatItem;
#[inline]
fn parse_borrowed(
s: &str,
) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
Ok(parse_generic::<1, false>(s)?)
}
#[inline]
fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
Ok(parse_generic::<1, true>(s)?)
}
}
impl VersionedParser for Version<2> {
type BorrowedOutput<'input> = Vec<BorrowedFormatItem<'input>>;
type OwnedOutput = OwnedFormatItem;
#[inline]
fn parse_borrowed(
s: &str,
) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
Ok(parse_generic::<2, false>(s)?)
}
#[inline]
fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
Ok(parse_generic::<2, true>(s)?)
}
}
impl VersionedParser for Version<3> {
type BorrowedOutput<'input> = FormatDescriptionV3<'input>;
type OwnedOutput = FormatDescriptionV3<'static>;
#[inline]
fn parse_borrowed(
s: &str,
) -> Result<Self::BorrowedOutput<'_>, error::InvalidFormatDescription> {
Ok(parse_generic::<3, false>(s)?)
}
#[inline]
fn parse_owned(s: &str) -> Result<Self::OwnedOutput, error::InvalidFormatDescription> {
Ok(parse_generic::<3, true>(s)?)
}
}
#[deprecated(
since = "0.3.48",
note = "use `parse_borrowed` with the appropriate version for clarity"
)]
#[inline]
pub fn parse(s: &str) -> Result<Vec<BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
parse_borrowed::<1>(s)
}
#[inline]
pub fn parse_borrowed<const VERSION: usize>(
s: &str,
) -> Result<
<Version<VERSION> as VersionedParser>::BorrowedOutput<'_>,
error::InvalidFormatDescription,
>
where
Version<VERSION>: VersionedParser,
{
Version::<VERSION>::parse_borrowed(s)
}
#[inline]
pub fn parse_owned<const VERSION: usize>(
s: &str,
) -> Result<<Version<VERSION> as VersionedParser>::OwnedOutput, error::InvalidFormatDescription>
where
Version<VERSION>: VersionedParser,
{
Version::<VERSION>::parse_owned(s)
}
#[derive(Clone, Copy)]
struct Location {
byte: u32,
}
impl Location {
const DUMMY: Self = Self { byte: u32::MAX };
#[inline]
const fn to(self, end: Self) -> Span {
Span { start: self, end }
}
#[inline]
const fn to_self(self) -> Span {
Span {
start: self,
end: self,
}
}
#[inline]
const fn with_length(self, length: usize) -> Span {
Span {
start: self,
end: Self {
byte: self.byte + length as u32 - 1,
},
}
}
#[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 WithLocation<T> {
value: T,
location: Location,
}
impl<T> core::ops::Deref for WithLocation<T> {
type Target = T;
#[inline]
fn deref(&self) -> &Self::Target {
&self.value
}
}
trait WithLocationValue: Sized {
fn with_location(self, location: Location) -> WithLocation<Self>;
}
impl<T> WithLocationValue for T {
#[inline]
fn with_location(self, location: Location) -> WithLocation<Self> {
WithLocation {
value: self,
location,
}
}
}
#[derive(Clone, Copy)]
struct Span {
start: Location,
end: Location,
}
impl Span {
const DUMMY: Self = Self {
start: Location { byte: u32::MAX },
end: Location { byte: u32::MAX },
};
#[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,
}
}
#[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
}
}
impl<T> Spanned<T> {
#[inline]
fn map<F, U>(self, f: F) -> Spanned<U>
where
F: FnOnce(T) -> U,
{
Spanned {
value: f(self.value),
span: self.span,
}
}
}
trait OptionExt<T> {
fn transpose(self) -> Spanned<Option<T>>;
}
impl<T> OptionExt<T> for Option<Spanned<T>> {
#[inline]
fn transpose(self) -> Spanned<Option<T>> {
match self {
Some(spanned) => Spanned {
value: Some(spanned.value),
span: spanned.span,
},
None => Spanned {
value: None,
span: Span::DUMMY,
},
}
}
}
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
}
}
impl From<core::convert::Infallible> for Error {
#[inline]
fn from(v: core::convert::Infallible) -> Self {
match v {}
}
}
struct Unused<T>(core::marker::PhantomData<T>);
#[inline]
fn unused<T>(_: T) -> Unused<T> {
Unused(core::marker::PhantomData)
}