summaryrefslogtreecommitdiff
path: root/vendor/time/src/format_description/parse/mod.rs
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
committermo khan <mo@mokhan.ca>2025-07-02 18:36:06 -0600
commit8cdfa445d6629ffef4cb84967ff7017654045bc2 (patch)
tree22f0b0907c024c78d26a731e2e1f5219407d8102 /vendor/time/src/format_description/parse/mod.rs
parent4351c74c7c5f97156bc94d3a8549b9940ac80e3f (diff)
chore: add vendor directory
Diffstat (limited to 'vendor/time/src/format_description/parse/mod.rs')
-rw-r--r--vendor/time/src/format_description/parse/mod.rs262
1 files changed, 262 insertions, 0 deletions
diff --git a/vendor/time/src/format_description/parse/mod.rs b/vendor/time/src/format_description/parse/mod.rs
new file mode 100644
index 00000000..d058594d
--- /dev/null
+++ b/vendor/time/src/format_description/parse/mod.rs
@@ -0,0 +1,262 @@
+//! Parser for format descriptions.
+
+use alloc::boxed::Box;
+use alloc::vec::Vec;
+
+pub use self::strftime::{parse_strftime_borrowed, parse_strftime_owned};
+use crate::{error, format_description};
+
+/// A helper macro to make version restrictions simpler to read and write.
+macro_rules! version {
+ ($range:expr) => {
+ $range.contains(&VERSION)
+ };
+}
+
+/// A helper macro to statically validate the version (when used as a const parameter).
+macro_rules! validate_version {
+ ($version:ident) => {
+ let _ = $crate::format_description::parse::Version::<$version>::IS_VALID;
+ };
+}
+
+mod ast;
+mod format_item;
+mod lexer;
+mod strftime;
+
+/// A struct that is used to ensure that the version is valid.
+struct Version<const N: usize>;
+impl<const N: usize> Version<N> {
+ /// A constant that panics if the version is not valid. This results in a post-monomorphization
+ /// error.
+ const IS_VALID: () = assert!(N >= 1 && N <= 2);
+}
+
+/// Parse a sequence of items from the format description.
+///
+/// The syntax for the format description can be found in [the
+/// book](https://time-rs.github.io/book/api/format-description.html).
+///
+/// This function exists for backward compatibility reasons. It is equivalent to calling
+/// `parse_borrowed::<1>(s)`. In the future, this function will be deprecated in favor of
+/// `parse_borrowed`.
+pub fn parse(
+ s: &str,
+) -> Result<Vec<format_description::BorrowedFormatItem<'_>>, error::InvalidFormatDescription> {
+ parse_borrowed::<1>(s)
+}
+
+/// Parse a sequence of items from the format description.
+///
+/// The syntax for the format description can be found in [the
+/// book](https://time-rs.github.io/book/api/format-description.html). The version of the format
+/// description is provided as the const parameter. **It is recommended to use version 2.**
+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<_, _>>()?)
+}
+
+/// Parse a sequence of items from the format description.
+///
+/// The syntax for the format description can be found in [the
+/// book](https://time-rs.github.io/book/api/format-description.html). The version of the format
+/// description is provided as the const parameter.
+///
+/// Unlike [`parse`], this function returns [`OwnedFormatItem`], which owns its contents. This means
+/// that there is no lifetime that needs to be handled. **It is recommended to use version 2.**
+///
+/// [`OwnedFormatItem`]: crate::format_description::OwnedFormatItem
+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())
+}
+
+/// Attach [`Location`] information to each byte in the iterator.
+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)
+ })
+}
+
+/// A location within a string.
+#[derive(Clone, Copy)]
+struct Location {
+ /// The zero-indexed byte of the string.
+ byte: u32,
+}
+
+impl Location {
+ /// Create a new [`Span`] from `self` to `other`.
+ const fn to(self, end: Self) -> Span {
+ Span { start: self, end }
+ }
+
+ /// Create a new [`Span`] consisting entirely of `self`.
+ const fn to_self(self) -> Span {
+ Span {
+ start: self,
+ end: self,
+ }
+ }
+
+ /// Offset the location by the provided amount.
+ ///
+ /// Note that this assumes the resulting location is on the same line as the original location.
+ #[must_use = "this does not modify the original value"]
+ const fn offset(&self, offset: u32) -> Self {
+ Self {
+ byte: self.byte + offset,
+ }
+ }
+
+ /// Create an error with the provided message at this location.
+ const fn error(self, message: &'static str) -> ErrorInner {
+ ErrorInner {
+ _message: message,
+ _span: Span {
+ start: self,
+ end: self,
+ },
+ }
+ }
+}
+
+/// A start and end point within a string.
+#[derive(Clone, Copy)]
+struct Span {
+ start: Location,
+ end: Location,
+}
+
+impl Span {
+ /// Obtain a `Span` pointing at the start of the pre-existing span.
+ #[must_use = "this does not modify the original value"]
+ const fn shrink_to_start(&self) -> Self {
+ Self {
+ start: self.start,
+ end: self.start,
+ }
+ }
+
+ /// Obtain a `Span` pointing at the end of the pre-existing span.
+ #[must_use = "this does not modify the original value"]
+ const fn shrink_to_end(&self) -> Self {
+ Self {
+ start: self.end,
+ end: self.end,
+ }
+ }
+
+ /// Obtain a `Span` that ends before the provided position of the pre-existing span.
+ #[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,
+ },
+ }
+ }
+
+ /// Obtain a `Span` that starts after provided position to the end of the pre-existing span.
+ #[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,
+ }
+ }
+
+ /// Create an error with the provided message at this span.
+ const fn error(self, message: &'static str) -> ErrorInner {
+ ErrorInner {
+ _message: message,
+ _span: self,
+ }
+ }
+}
+
+/// A value with an associated [`Span`].
+#[derive(Clone, Copy)]
+struct Spanned<T> {
+ /// The value.
+ value: T,
+ /// Where the value was in the format string.
+ span: Span,
+}
+
+impl<T> core::ops::Deref for Spanned<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ &self.value
+ }
+}
+
+/// Helper trait to attach a [`Span`] to a value.
+trait SpannedValue: Sized {
+ /// Attach a [`Span`] to a value.
+ fn spanned(self, span: Span) -> Spanned<Self>;
+}
+
+impl<T> SpannedValue for T {
+ fn spanned(self, span: Span) -> Spanned<Self> {
+ Spanned { value: self, span }
+ }
+}
+
+/// The internal error type.
+struct ErrorInner {
+ /// The message displayed to the user.
+ _message: &'static str,
+ /// Where the error originated.
+ _span: Span,
+}
+
+/// A complete error description.
+struct Error {
+ /// The internal error.
+ _inner: Unused<ErrorInner>,
+ /// The error needed for interoperability with the rest of `time`.
+ public: error::InvalidFormatDescription,
+}
+
+impl From<Error> for error::InvalidFormatDescription {
+ fn from(error: Error) -> Self {
+ error.public
+ }
+}
+
+/// A value that may be used in the future, but currently is not.
+///
+/// This struct exists so that data can semantically be passed around without _actually_ passing it
+/// around. This way the data still exists if it is needed in the future.
+// `PhantomData` is not used directly because we don't want to introduce any trait implementations.
+struct Unused<T>(core::marker::PhantomData<T>);
+
+/// Indicate that a value is currently unused.
+fn unused<T>(_: T) -> Unused<T> {
+ Unused(core::marker::PhantomData)
+}