diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index b6af74f66..e8c67f8dd 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -52,7 +52,7 @@ jobs: strategy: matrix: rust: - - { version: "1.63.0", name: MSRV } + - { version: "1.65.0", name: MSRV } - { version: stable, name: stable } kind: - name: no_std @@ -153,7 +153,7 @@ jobs: strategy: matrix: rust: - - { version: "1.63.0", name: MSRV } + - { version: "1.65.0", name: MSRV } - { version: stable, name: stable } os: - { name: Ubuntu, value: ubuntu-20.04 } diff --git a/.github/workflows/powerset.yaml b/.github/workflows/powerset.yaml index 9341eda9b..83972c7e4 100644 --- a/.github/workflows/powerset.yaml +++ b/.github/workflows/powerset.yaml @@ -51,7 +51,7 @@ jobs: strategy: matrix: rust: - - { version: "1.63.0", name: MSRV } + - { version: "1.65.0", name: MSRV } - { version: stable, name: stable } kind: - name: no_std diff --git a/README.md b/README.md index 8cd50728d..6fb715575 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # time -[![minimum rustc: 1.63](https://img.shields.io/badge/minimum%20rustc-1.63-yellowgreen?logo=rust&style=flat-square)](https://www.whatrustisit.com) +[![minimum rustc: 1.65](https://img.shields.io/badge/minimum%20rustc-1.65-yellowgreen?logo=rust&style=flat-square)](https://www.whatrustisit.com) [![version](https://img.shields.io/crates/v/time?color=blue&logo=rust&style=flat-square)](https://crates.io/crates/time) [![build status](https://img.shields.io/github/actions/workflow/status/time-rs/time/build.yaml?branch=main&style=flat-square)](https://github.com/time-rs/time/actions) [![codecov](https://codecov.io/gh/time-rs/time/branch/main/graph/badge.svg?token=yt4XSmQNKQ)](https://codecov.io/gh/time-rs/time) diff --git a/time-core/Cargo.toml b/time-core/Cargo.toml index a59b7bbf6..57ab3b9fd 100644 --- a/time-core/Cargo.toml +++ b/time-core/Cargo.toml @@ -3,7 +3,7 @@ name = "time-core" version = "0.1.0" authors = ["Jacob Pratt ", "Time contributors"] edition = "2021" -rust-version = "1.63.0" +rust-version = "1.65.0" repository = "https://github.com/time-rs/time" keywords = ["date", "time", "calendar", "duration"] categories = ["date-and-time"] diff --git a/time-macros/Cargo.toml b/time-macros/Cargo.toml index 4236416bb..206ea3f0e 100644 --- a/time-macros/Cargo.toml +++ b/time-macros/Cargo.toml @@ -3,7 +3,7 @@ name = "time-macros" version = "0.2.8" authors = ["Jacob Pratt ", "Time contributors"] edition = "2021" -rust-version = "1.63.0" +rust-version = "1.65.0" repository = "https://github.com/time-rs/time" keywords = ["date", "time", "calendar", "duration"] categories = ["date-and-time"] diff --git a/time-macros/src/format_description/ast.rs b/time-macros/src/format_description/ast.rs index 497c8965d..f33c6d433 100644 --- a/time-macros/src/format_description/ast.rs +++ b/time-macros/src/format_description/ast.rs @@ -127,24 +127,24 @@ fn parse_component<'a, I: Iterator, Error>>, cons ) -> Result, Error> { let leading_whitespace = tokens.next_if_whitespace(); - guard!(let Some(name) = tokens.next_if_not_whitespace() else { + let Some(name) = tokens.next_if_not_whitespace() else { let span = match leading_whitespace { Some(Spanned { value: _, span }) => span, None => opening_bracket.to(opening_bracket), }; return Err(span.error("expected component name")); - }); + }; if *name == b"optional" { - guard!(let Some(whitespace) = tokens.next_if_whitespace() else { + let Some(whitespace) = tokens.next_if_whitespace() else { return Err(name.span.error("expected whitespace after `optional`")); - }); + }; let nested = parse_nested::<_, VERSION>(whitespace.span.end, tokens)?; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(opening_bracket.error("unclosed bracket")); - }); + }; return Ok(Item::Optional { opening_bracket, @@ -157,18 +157,18 @@ fn parse_component<'a, I: Iterator, Error>>, cons } if *name == b"first" { - guard!(let Some(whitespace) = tokens.next_if_whitespace() else { + let Some(whitespace) = tokens.next_if_whitespace() else { return Err(name.span.error("expected whitespace after `first`")); - }); + }; let mut nested_format_descriptions = Vec::new(); while let Ok(description) = parse_nested::<_, VERSION>(whitespace.span.end, tokens) { nested_format_descriptions.push(description); } - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(opening_bracket.error("unclosed bracket")); - }); + }; return Ok(Item::First { opening_bracket, @@ -182,7 +182,7 @@ fn parse_component<'a, I: Iterator, Error>>, cons let mut modifiers = Vec::new(); let trailing_whitespace = loop { - guard!(let Some(whitespace) = tokens.next_if_whitespace() else { break None }); + let Some(whitespace) = tokens.next_if_whitespace() else { break None }; if let Some(location) = tokens.next_if_opening_bracket() { return Err(location @@ -190,13 +190,13 @@ fn parse_component<'a, I: Iterator, Error>>, cons .error("modifier must be of the form `key:value`")); } - guard!(let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { + let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { break Some(whitespace); - }); + }; - guard!(let Some(colon_index) = value.iter().position(|&b| b == b':') else { + let Some(colon_index) = value.iter().position(|&b| b == b':') else { return Err(span.error("modifier must be of the form `key:value`")); - }); + }; let key = &value[..colon_index]; let value = &value[colon_index + 1..]; @@ -215,9 +215,9 @@ fn parse_component<'a, I: Iterator, Error>>, cons }); }; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(opening_bracket.error("unclosed bracket")); - }); + }; Ok(Item::Component { _opening_bracket: unused(opening_bracket), @@ -233,13 +233,13 @@ fn parse_nested<'a, I: Iterator, Error>>, const V last_location: Location, tokens: &mut lexer::Lexed, ) -> Result, Error> { - guard!(let Some(opening_bracket) = tokens.next_if_opening_bracket() else { + let Some(opening_bracket) = tokens.next_if_opening_bracket() else { return Err(last_location.error("expected opening bracket")); - }); + }; let items = parse_inner::<_, true, VERSION>(tokens).collect::>()?; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(opening_bracket.error("unclosed bracket")); - }); + }; let trailing_whitespace = tokens.next_if_whitespace(); Ok(NestedFormatDescription { diff --git a/time-macros/src/lib.rs b/time-macros/src/lib.rs index 68c8167e5..ce62ac5be 100644 --- a/time-macros/src/lib.rs +++ b/time-macros/src/lib.rs @@ -42,9 +42,6 @@ macro_rules! bug { #[macro_use] mod quote; -#[cfg(any(feature = "formatting", feature = "parsing"))] -#[macro_use] -mod shim; mod date; mod datetime; diff --git a/time-macros/src/shim.rs b/time-macros/src/shim.rs deleted file mode 100644 index f31e5d501..000000000 --- a/time-macros/src/shim.rs +++ /dev/null @@ -1,117 +0,0 @@ -#![allow(unused_macros)] - -// The following code is copyright 2016 Alex Burka. Available under the MIT OR Apache-2.0 license. -// Some adaptations have been made to the original code. - -pub(crate) enum LetElseBodyMustDiverge {} - -#[allow(clippy::missing_docs_in_private_items)] -macro_rules! __guard_output { - ((($($imms:ident)*) ($($muts:ident)*)), - [($($pattern:tt)*) ($rhs:expr) ($diverge:expr)]) => { - __guard_impl!(@as_stmt - let ($($imms,)* $(mut $muts,)*) = { - #[allow(unused_mut)] - match $rhs { - $($pattern)* => { - ($($imms,)* $($muts,)*) - }, - _ => { - let _: $crate::shim::LetElseBodyMustDiverge = $diverge; - }, - } - } - ) - }; -} - -macro_rules! __guard_impl { - (@as_stmt $s:stmt) => { $s }; - (@collect () -> $($rest:tt)*) => { - __guard_output!($($rest)*) - }; - (@collect (($($inside:tt)*) $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect ({$($inside:tt)*} $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect ([$($inside:tt)*] $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect (, $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (.. $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (@ $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (_ $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (& $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (:: <$($generic:tt),*> $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (:: $pathend:ident $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (| $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect () -> $idents, $thru) - }; - (@collect ($id:ident: $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect ($pathcomp:ident :: $pathend:ident $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect ($id:ident ($($inside:tt)*) $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect ($id:ident {$($inside:tt)*} $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect (ref mut $id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - (@collect (ref $id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - (@collect (mut $id:ident $($tail:tt)*) -> ($imms:tt ($($muts:ident)*)), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> ($imms ($($muts)* $id)), $thru) - }; - (@collect ($id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - (@split (else { $($diverge:tt)* } = $($tail:tt)*) -> ($pat:tt)) => { - __guard_impl!(@collect $pat -> (() ()), [$pat ($($tail)*) ({ $($diverge)* })]) - }; - (@split (= $($tail:tt)*) -> ($pat:tt)) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ())) - }; - (@split ($head:tt $($tail:tt)*) -> (($($pat:tt)*))) => { - __guard_impl!(@split ($($tail)*) -> (($($pat)* $head))) - }; - (@split expr (else { $($tail:tt)* }) -> ($pat:tt $expr:tt)) => { - __guard_impl!(@collect $pat -> (() ()), [$pat $expr ({ $($tail)* })]) - }; - (@split expr (else { $($body:tt)* } $($tail:tt)*) -> ($pat:tt ($($expr:tt)*))) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ($($expr)* else { $($body)* }))) - }; - (@split expr ($head:tt $($tail:tt)*) -> ($pat:tt ($($expr:tt)*))) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ($($expr)* $head))) - }; - (let $($tail:tt)*) => { - __guard_impl!(@split ($($tail)*) -> (())) - }; -} - -macro_rules! guard { - ($($input:tt)*) => { - __guard_impl!($($input)*) - }; -} diff --git a/time/Cargo.toml b/time/Cargo.toml index 4cd10c8ea..4d6c47dda 100644 --- a/time/Cargo.toml +++ b/time/Cargo.toml @@ -3,7 +3,7 @@ name = "time" version = "0.3.20" authors = ["Jacob Pratt ", "Time contributors"] edition = "2021" -rust-version = "1.63.0" +rust-version = "1.65.0" repository = "https://github.com/time-rs/time" homepage = "https://time-rs.github.io" keywords = ["date", "time", "calendar", "duration"] diff --git a/time/src/date_time.rs b/time/src/date_time.rs index 8ef7d5da7..6254a460e 100644 --- a/time/src/date_time.rs +++ b/time/src/date_time.rs @@ -523,10 +523,10 @@ impl DateTime { /// Equivalent to `.to_offset(UtcOffset::UTC)`, but returning the year, ordinal, and time. This /// avoids constructing an invalid [`Date`] if the new value is out of range. pub(crate) const fn to_offset_raw(self, offset: UtcOffset) -> (i32, u16, Time) { - guard!(let Some(from) = maybe_offset_as_offset_opt::(self.offset) else { + let Some(from) = maybe_offset_as_offset_opt::(self.offset) else { // No adjustment is needed because there is no offset. return (self.year(), self.ordinal(), self.time); - }); + }; let to = offset; // Fast path for when no conversion is necessary. @@ -810,7 +810,7 @@ impl DateTime { } let (year, ordinal, time) = self.to_offset_raw(UtcOffset::UTC); - guard!(let Ok(date) = Date::from_ordinal_date(year, ordinal) else { return false }); + let Ok(date) = Date::from_ordinal_date(year, ordinal) else { return false }; time.hour() == 23 && time.minute() == 59 diff --git a/time/src/format_description/parse/ast.rs b/time/src/format_description/parse/ast.rs index f7b0ab78c..12fc5d55d 100644 --- a/time/src/format_description/parse/ast.rs +++ b/time/src/format_description/parse/ast.rs @@ -184,7 +184,7 @@ fn parse_component< validate_version!(VERSION); let leading_whitespace = tokens.next_if_whitespace(); - guard!(let Some(name) = tokens.next_if_not_whitespace() else { + let Some(name) = tokens.next_if_not_whitespace() else { let span = match leading_whitespace { Some(Spanned { value: _, span }) => span, None => opening_bracket.to(opening_bracket), @@ -195,10 +195,10 @@ fn parse_component< index: span.start.byte as _, }, }); - }); + }; if *name == b"optional" { - guard!(let Some(whitespace) = tokens.next_if_whitespace() else { + let Some(whitespace) = tokens.next_if_whitespace() else { return Err(Error { _inner: unused(name.span.error("expected whitespace after `optional`")), public: crate::error::InvalidFormatDescription::Expected { @@ -206,18 +206,18 @@ fn parse_component< index: name.span.end.byte as _, }, }); - }); + }; let nested = parse_nested::<_, VERSION>(whitespace.span.end, tokens)?; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(Error { _inner: unused(opening_bracket.error("unclosed bracket")), public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { index: opening_bracket.byte as _, }, }); - }); + }; return Ok(Item::Optional { opening_bracket, @@ -230,7 +230,7 @@ fn parse_component< } if *name == b"first" { - guard!(let Some(whitespace) = tokens.next_if_whitespace() else { + let Some(whitespace) = tokens.next_if_whitespace() else { return Err(Error { _inner: unused(name.span.error("expected whitespace after `first`")), public: crate::error::InvalidFormatDescription::Expected { @@ -238,21 +238,21 @@ fn parse_component< index: name.span.end.byte as _, }, }); - }); + }; let mut nested_format_descriptions = Vec::new(); while let Ok(description) = parse_nested::<_, VERSION>(whitespace.span.end, tokens) { nested_format_descriptions.push(description); } - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(Error { _inner: unused(opening_bracket.error("unclosed bracket")), public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { index: opening_bracket.byte as _, }, }); - }); + }; return Ok(Item::First { opening_bracket, @@ -266,7 +266,7 @@ fn parse_component< let mut modifiers = Vec::new(); let trailing_whitespace = loop { - guard!(let Some(whitespace) = tokens.next_if_whitespace() else { break None }); + let Some(whitespace) = tokens.next_if_whitespace() else { break None }; // This is not necessary for proper parsing, but provides a much better error when a nested // description is used where it's not allowed. @@ -284,11 +284,11 @@ fn parse_component< }); } - guard!(let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { + let Some(Spanned { value, span }) = tokens.next_if_not_whitespace() else { break Some(whitespace); - }); + }; - guard!(let Some(colon_index) = value.iter().position(|&b| b == b':') else { + let Some(colon_index) = value.iter().position(|&b| b == b':') else { return Err(Error { _inner: unused(span.error("modifier must be of the form `key:value`")), public: crate::error::InvalidFormatDescription::InvalidModifier { @@ -296,7 +296,7 @@ fn parse_component< index: span.start.byte as _, }, }); - }); + }; let key = &value[..colon_index]; let value = &value[colon_index + 1..]; @@ -327,14 +327,14 @@ fn parse_component< }); }; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(Error { _inner: unused(opening_bracket.error("unclosed bracket")), public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { index: opening_bracket.byte as _, }, }); - }); + }; Ok(Item::Component { _opening_bracket: unused(opening_bracket), @@ -352,7 +352,7 @@ fn parse_nested<'a, I: Iterator, Error>>, const V tokens: &mut lexer::Lexed, ) -> Result, Error> { validate_version!(VERSION); - guard!(let Some(opening_bracket) = tokens.next_if_opening_bracket() else { + let Some(opening_bracket) = tokens.next_if_opening_bracket() else { return Err(Error { _inner: unused(last_location.error("expected opening bracket")), public: crate::error::InvalidFormatDescription::Expected { @@ -360,16 +360,16 @@ fn parse_nested<'a, I: Iterator, Error>>, const V index: last_location.byte as _, }, }); - }); + }; let items = parse_inner::<_, true, VERSION>(tokens).collect::>()?; - guard!(let Some(closing_bracket) = tokens.next_if_closing_bracket() else { + let Some(closing_bracket) = tokens.next_if_closing_bracket() else { return Err(Error { _inner: unused(opening_bracket.error("unclosed bracket")), public: crate::error::InvalidFormatDescription::UnclosedOpeningBracket { index: opening_bracket.byte as _, }, }); - }); + }; let trailing_whitespace = tokens.next_if_whitespace(); Ok(NestedFormatDescription { diff --git a/time/src/lib.rs b/time/src/lib.rs index a5d5d0e59..2ab59cf8e 100644 --- a/time/src/lib.rs +++ b/time/src/lib.rs @@ -312,9 +312,6 @@ macro_rules! bug { } // endregion macros -#[macro_use] -mod shim; - mod date; mod date_time; mod duration; diff --git a/time/src/serde/mod.rs b/time/src/serde/mod.rs index f7306b29b..844d7bdef 100644 --- a/time/src/serde/mod.rs +++ b/time/src/serde/mod.rs @@ -224,9 +224,9 @@ impl Serialize for Date { fn serialize(&self, serializer: S) -> Result { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&DATE_FORMAT) else { + let Ok(s) = self.format(&DATE_FORMAT) else { return Err(S::Error::custom("failed formatting `Date`")); - }); + }; return serializer.serialize_str(&s); } @@ -287,9 +287,9 @@ impl Serialize for OffsetDateTime { fn serialize(&self, serializer: S) -> Result { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&OFFSET_DATE_TIME_FORMAT) else { + let Ok(s) = self.format(&OFFSET_DATE_TIME_FORMAT) else { return Err(S::Error::custom("failed formatting `OffsetDateTime`")); - }); + }; return serializer.serialize_str(&s); } @@ -332,9 +332,9 @@ impl Serialize for PrimitiveDateTime { fn serialize(&self, serializer: S) -> Result { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else { + let Ok(s) = self.format(&PRIMITIVE_DATE_TIME_FORMAT) else { return Err(S::Error::custom("failed formatting `PrimitiveDateTime`")); - }); + }; return serializer.serialize_str(&s); } @@ -378,9 +378,9 @@ impl Serialize for Time { fn serialize(&self, serializer: S) -> Result { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&TIME_FORMAT) else { + let Ok(s) = self.format(&TIME_FORMAT) else { return Err(S::Error::custom("failed formatting `Time`")); - }); + }; return serializer.serialize_str(&s); } @@ -414,9 +414,9 @@ impl Serialize for UtcOffset { fn serialize(&self, serializer: S) -> Result { #[cfg(feature = "serde-human-readable")] if serializer.is_human_readable() { - guard!(let Ok(s) = self.format(&UTC_OFFSET_FORMAT) else { + let Ok(s) = self.format(&UTC_OFFSET_FORMAT) else { return Err(S::Error::custom("failed formatting `UtcOffset`")); - }); + }; return serializer.serialize_str(&s); } diff --git a/time/src/shim.rs b/time/src/shim.rs deleted file mode 100644 index b9ac97a16..000000000 --- a/time/src/shim.rs +++ /dev/null @@ -1,180 +0,0 @@ -//! Macro for simulating let-else on older compilers. -//! -//! This module and its macros will be removed once the MSRV is 1.65 (NET 2023-05-03). - -#![allow(unused_macros)] -#![allow(clippy::missing_docs_in_private_items)] - -// The following code is copyright 2016 Alex Burka. Available under the MIT OR Apache-2.0 license. -// Some adaptations have been made to the original code. - -pub(crate) enum LetElseBodyMustDiverge {} - -#[allow(clippy::missing_docs_in_private_items)] -macro_rules! __guard_output { - ((($($imms:ident)*) ($($muts:ident)*)), - [($($pattern:tt)*) ($rhs:expr) ($diverge:expr)]) => { - __guard_impl!(@as_stmt - let ($($imms,)* $(mut $muts,)*) = { - #[allow(unused_mut)] - match $rhs { - $($pattern)* => { - ($($imms,)* $($muts,)*) - }, - _ => { - let _: $crate::shim::LetElseBodyMustDiverge = $diverge; - }, - } - } - ) - }; -} - -macro_rules! __guard_impl { - // 0. cast a series of token trees to a statement - (@as_stmt $s:stmt) => { $s }; - - // 1. output stage - (@collect () -> $($rest:tt)*) => { - __guard_output!($($rest)*) - }; - - - // 2. identifier collection stage - // The pattern is scanned destructively. Anything that looks like a capture (including - // false positives, like un-namespaced/empty structs or enum variants) is copied into the - // appropriate identifier list. Irrelevant symbols are discarded. The scanning descends - // recursively into bracketed structures. - - // unwrap brackets and prepend their contents to the pattern remainder, in case there are captures inside - (@collect (($($inside:tt)*) $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect ({$($inside:tt)*} $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - (@collect ([$($inside:tt)*] $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - - // discard irrelevant symbols - (@collect (, $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (.. $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (@ $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (_ $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - (@collect (& $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - - // ignore generic parameters - (@collect (:: <$($generic:tt),*> $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - // a path can't be a capture, and a path can't end with ::, so the ident after :: is never a capture - (@collect (:: $pathend:ident $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - - // alternative patterns may be given with | as long as the same captures (including type) appear on each side - // due to this property, if we see a | we've already parsed all the captures and can simply stop - (@collect (| $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect () -> $idents, $thru) // discard the rest of the pattern, proceed to output stage - }; - - // throw away some identifiers that do not represent captures - - // an ident followed by a colon is the name of a structure member - (@collect ($id:ident: $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - // paths do not represent captures - (@collect ($pathcomp:ident :: $pathend:ident $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> $idents, $thru) - }; - // an ident followed by parentheses is the name of a tuple-like struct or enum variant - // (unwrap the parens to parse the contents) - (@collect ($id:ident ($($inside:tt)*) $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - // an ident followed by curly braces is the name of a struct or struct-like enum variant - // (unwrap the braces to parse the contents) - (@collect ($id:ident {$($inside:tt)*} $($tail:tt)*) -> $idents:tt, $thru:tt) => { - __guard_impl!(@collect ($($inside)* $($tail)*) -> $idents, $thru) - }; - - // actually identifier collection happens here! - - // capture by mutable reference! - (@collect (ref mut $id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - // capture by immutable reference! - (@collect (ref $id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - // capture by move into mutable binding! - (@collect (mut $id:ident $($tail:tt)*) -> ($imms:tt ($($muts:ident)*)), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> ($imms ($($muts)* $id)), $thru) - }; - // capture by move into an immutable binding! - (@collect ($id:ident $($tail:tt)*) -> (($($imms:ident)*) $muts:tt), $thru:tt) => { - __guard_impl!(@collect ($($tail)*) -> (($($imms)* $id) $muts), $thru) - }; - - // 3. splitting (for new syntax) - - // done with pattern (and it's LPED=X) - (@split (else { $($diverge:tt)* } = $($tail:tt)*) -> ($pat:tt)) => { - __guard_impl!(@collect $pat -> (() ()), [$pat ($($tail)*) ({ $($diverge)* })]) - }; - - // done with pattern (and it's LP=XED) - (@split (= $($tail:tt)*) -> ($pat:tt)) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ())) - }; - - // found a token in the pattern - (@split ($head:tt $($tail:tt)*) -> (($($pat:tt)*))) => { - __guard_impl!(@split ($($tail)*) -> (($($pat)* $head))) - }; - - // found an "else DIVERGE" in the expr - (@split expr (else { $($tail:tt)* }) -> ($pat:tt $expr:tt)) => { - __guard_impl!(@collect $pat -> (() ()), [$pat $expr ({ $($tail)* })]) - }; - - // found an else in the expr with more stuff after it - (@split expr (else { $($body:tt)* } $($tail:tt)*) -> ($pat:tt ($($expr:tt)*))) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ($($expr)* else { $($body)* }))) - }; - - // found another token in the expr - (@split expr ($head:tt $($tail:tt)*) -> ($pat:tt ($($expr:tt)*))) => { - __guard_impl!(@split expr ($($tail)*) -> ($pat ($($expr)* $head))) - }; - - // 4. entry points - - // new syntax - (let $($tail:tt)*) => { - __guard_impl!(@split ($($tail)*) -> (())) - // | | | - // | | ^ pattern - // | ^ tail to be split into "PAT = EXPR else DIVERGE" - // ^ first pass will do the parsing - }; -} - -macro_rules! guard { - ($($input:tt)*) => { - __guard_impl!($($input)*) - }; -}