use crate::core::Cursor;
use crate::encoding::{EncodingType, Utf16, Utf8};
use crate::ParserResult;
#[cfg(feature = "duration")]
use crate::records::DurationParseRecord;
use crate::records::{IxdtfParseRecord, TimeZoneRecord, UtcOffsetRecord};
use crate::records::Annotation;
mod annotations;
pub(crate) mod datetime;
#[cfg(feature = "duration")]
pub(crate) mod duration;
mod grammar;
mod time;
pub(crate) mod timezone;
#[cfg(test)]
mod tests;
#[macro_export]
macro_rules! assert_syntax {
($cond:expr, $err:ident $(,)?) => {
if !$cond {
return Err(ParseError::$err);
}
};
}
#[derive(Debug)]
pub struct IxdtfParser<'a, T: EncodingType> {
cursor: Cursor<'a, T>,
}
impl<'a> IxdtfParser<'a, Utf8> {
#[inline]
#[must_use]
#[expect(clippy::should_implement_trait)]
pub fn from_str(source: &'a str) -> Self {
Self::from_utf8(source.as_bytes())
}
#[inline]
#[must_use]
pub fn from_utf8(source: &'a [u8]) -> Self {
Self::new(source)
}
}
impl<'a> IxdtfParser<'a, Utf16> {
pub fn from_utf16(source: &'a [u16]) -> Self {
Self::new(source)
}
}
impl<'a, T: EncodingType> IxdtfParser<'a, T> {
#[inline]
#[must_use]
pub fn new(source: &'a [T::CodeUnit]) -> Self {
Self {
cursor: Cursor::new(source),
}
}
pub fn parse(&mut self) -> ParserResult<IxdtfParseRecord<'a, T>> {
self.parse_with_annotation_handler(Some)
}
pub fn parse_with_annotation_handler(
&mut self,
handler: impl FnMut(Annotation<'a, T>) -> Option<Annotation<'a, T>>,
) -> ParserResult<IxdtfParseRecord<'a, T>> {
datetime::parse_annotated_date_time(&mut self.cursor, handler)
}
pub fn parse_year_month(&mut self) -> ParserResult<IxdtfParseRecord<'a, T>> {
self.parse_year_month_with_annotation_handler(Some)
}
pub fn parse_year_month_with_annotation_handler(
&mut self,
handler: impl FnMut(Annotation<'a, T>) -> Option<Annotation<'a, T>>,
) -> ParserResult<IxdtfParseRecord<'a, T>> {
datetime::parse_annotated_year_month(&mut self.cursor, handler)
}
pub fn parse_month_day(&mut self) -> ParserResult<IxdtfParseRecord<'a, T>> {
self.parse_month_day_with_annotation_handler(Some)
}
pub fn parse_month_day_with_annotation_handler(
&mut self,
handler: impl FnMut(Annotation<'a, T>) -> Option<Annotation<'a, T>>,
) -> ParserResult<IxdtfParseRecord<'a, T>> {
datetime::parse_annotated_month_day(&mut self.cursor, handler)
}
pub fn parse_time(&mut self) -> ParserResult<IxdtfParseRecord<'a, T>> {
self.parse_time_with_annotation_handler(Some)
}
pub fn parse_time_with_annotation_handler(
&mut self,
handler: impl FnMut(Annotation<'a, T>) -> Option<Annotation<'a, T>>,
) -> ParserResult<IxdtfParseRecord<'a, T>> {
time::parse_annotated_time_record(&mut self.cursor, handler)
}
}
#[derive(Debug)]
pub struct TimeZoneParser<'a, T: EncodingType> {
cursor: Cursor<'a, T>,
}
impl<'a> TimeZoneParser<'a, Utf8> {
#[inline]
#[must_use]
#[expect(clippy::should_implement_trait)]
pub fn from_str(source: &'a str) -> Self {
Self::from_utf8(source.as_bytes())
}
#[inline]
#[must_use]
pub fn from_utf8(source: &'a [u8]) -> Self {
Self::new(source)
}
}
impl<'a> TimeZoneParser<'a, Utf16> {
pub fn from_utf16(source: &'a [u16]) -> Self {
Self::new(source)
}
}
impl<'a, T: EncodingType> TimeZoneParser<'a, T> {
#[inline]
#[must_use]
pub fn new(source: &'a [T::CodeUnit]) -> Self {
Self {
cursor: Cursor::new(source),
}
}
pub fn parse_identifier(&mut self) -> ParserResult<TimeZoneRecord<'a, T>> {
let result = timezone::parse_time_zone(&mut self.cursor)?;
self.cursor.close()?;
Ok(result)
}
#[inline]
pub fn parse_offset(&mut self) -> ParserResult<UtcOffsetRecord> {
let result = timezone::parse_utc_offset(&mut self.cursor)?;
self.cursor.close()?;
Ok(result)
}
#[inline]
pub fn parse_iana_identifier(&mut self) -> ParserResult<&'a [T::CodeUnit]> {
let result = timezone::parse_tz_iana_name(&mut self.cursor)?;
self.cursor.close()?;
Ok(result)
}
}
#[cfg(feature = "duration")]
#[derive(Debug)]
pub struct IsoDurationParser<'a, T: EncodingType> {
cursor: Cursor<'a, T>,
}
#[cfg(feature = "duration")]
impl<'a> IsoDurationParser<'a, Utf8> {
#[inline]
#[must_use]
#[expect(clippy::should_implement_trait)]
pub fn from_str(source: &'a str) -> Self {
Self::from_utf8(source.as_bytes())
}
#[inline]
#[must_use]
pub fn from_utf8(source: &'a [u8]) -> Self {
Self::new(source)
}
}
#[cfg(feature = "duration")]
impl<'a> IsoDurationParser<'a, Utf16> {
#[inline]
#[must_use]
pub fn from_utf8(source: &'a [u16]) -> Self {
Self::new(source)
}
}
#[cfg(feature = "duration")]
impl<'a, T: EncodingType> IsoDurationParser<'a, T> {
#[inline]
#[must_use]
pub fn new(source: &'a [T::CodeUnit]) -> Self {
Self {
cursor: Cursor::new(source),
}
}
pub fn parse(&mut self) -> ParserResult<DurationParseRecord> {
duration::parse_duration(&mut self.cursor)
}
}