summaryrefslogtreecommitdiffstats
path: root/vendor/time/src/format_description/parse/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/time/src/format_description/parse/mod.rs')
-rw-r--r--vendor/time/src/format_description/parse/mod.rs193
1 files changed, 193 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 000000000..c73a67449
--- /dev/null
+++ b/vendor/time/src/format_description/parse/mod.rs
@@ -0,0 +1,193 @@
+//! Parser for format descriptions.
+
+use alloc::vec::Vec;
+use core::ops::{RangeFrom, RangeTo};
+
+mod ast;
+mod format_item;
+mod lexer;
+
+/// 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).
+pub fn parse(
+ s: &str,
+) -> Result<Vec<crate::format_description::FormatItem<'_>>, crate::error::InvalidFormatDescription>
+{
+ let lexed = lexer::lex(s.as_bytes());
+ let ast = ast::parse(lexed);
+ let format_items = format_item::parse(ast);
+ Ok(format_items
+ .map(|res| res.map(Into::into))
+ .collect::<Result<Vec<_>, _>>()?)
+}
+
+/// 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).
+///
+/// Unlike [`parse`], this function returns [`OwnedFormatItem`], which owns its contents. This means
+/// that there is no lifetime that needs to be handled.
+///
+/// [`OwnedFormatItem`]: crate::format_description::OwnedFormatItem
+pub fn parse_owned(
+ s: &str,
+) -> Result<crate::format_description::OwnedFormatItem, crate::error::InvalidFormatDescription> {
+ let lexed = lexer::lex(s.as_bytes());
+ let ast = ast::parse(lexed);
+ let format_items = format_item::parse(ast);
+ let items = format_items
+ .map(|res| res.map(Into::into))
+ .collect::<Result<Vec<_>, _>>()?
+ .into_boxed_slice();
+ Ok(crate::format_description::OwnedFormatItem::Compound(items))
+}
+
+/// A location within a string.
+#[derive(Clone, Copy)]
+struct Location {
+ /// The one-indexed line of the string.
+ line: usize,
+ /// The one-indexed column of the string.
+ column: usize,
+ /// The zero-indexed byte of the string.
+ byte: usize,
+}
+
+impl Location {
+ /// 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: usize) -> Self {
+ Self {
+ line: self.line,
+ column: self.column + offset,
+ 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 {
+ #[allow(clippy::missing_docs_in_private_items)]
+ start: Location,
+ #[allow(clippy::missing_docs_in_private_items)]
+ end: Location,
+}
+
+impl Span {
+ /// Create a new `Span` from the provided start and end locations.
+ const fn start_end(start: Location, end: Location) -> Self {
+ Self { start, end }
+ }
+
+ /// Reduce this span to the provided range.
+ #[must_use = "this does not modify the original value"]
+ fn subspan(&self, range: impl Subspan) -> Self {
+ range.subspan(self)
+ }
+
+ /// 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,
+ }
+ }
+
+ /// Create an error with the provided message at this span.
+ const fn error(self, message: &'static str) -> ErrorInner {
+ ErrorInner {
+ _message: message,
+ _span: self,
+ }
+ }
+
+ /// Get the byte index that the span starts at.
+ const fn start_byte(&self) -> usize {
+ self.start.byte
+ }
+}
+
+/// A trait for types that can be used to reduce a `Span`.
+trait Subspan {
+ /// Reduce the provided `Span` to a new `Span`.
+ fn subspan(self, span: &Span) -> Span;
+}
+
+impl Subspan for RangeFrom<usize> {
+ fn subspan(self, span: &Span) -> Span {
+ assert_eq!(span.start.line, span.end.line);
+
+ Span {
+ start: Location {
+ line: span.start.line,
+ column: span.start.column + self.start,
+ byte: span.start.byte + self.start,
+ },
+ end: span.end,
+ }
+ }
+}
+
+impl Subspan for RangeTo<usize> {
+ fn subspan(self, span: &Span) -> Span {
+ assert_eq!(span.start.line, span.end.line);
+
+ Span {
+ start: span.start,
+ end: Location {
+ line: span.start.line,
+ column: span.start.column + self.end - 1,
+ byte: span.start.byte + self.end - 1,
+ },
+ }
+ }
+}
+
+/// 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: ErrorInner,
+ /// The error needed for interoperability with the rest of `time`.
+ public: crate::error::InvalidFormatDescription,
+}
+
+impl From<Error> for crate::error::InvalidFormatDescription {
+ fn from(error: Error) -> Self {
+ error.public
+ }
+}