summaryrefslogtreecommitdiffstats
path: root/vendor/if_chain/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/if_chain/src
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/if_chain/src')
-rw-r--r--vendor/if_chain/src/lib.rs314
1 files changed, 314 insertions, 0 deletions
diff --git a/vendor/if_chain/src/lib.rs b/vendor/if_chain/src/lib.rs
new file mode 100644
index 000000000..e72f7aa88
--- /dev/null
+++ b/vendor/if_chain/src/lib.rs
@@ -0,0 +1,314 @@
+//! This crate provides a single macro called `if_chain!`.
+//!
+//! `if_chain!` lets you write long chains of nested `if` and `if let`
+//! statements without the associated rightward drift. It also supports multiple
+//! patterns (e.g. `if let Foo(a) | Bar(a) = b`) in places where Rust would
+//! normally not allow them.
+//!
+//! See the associated [blog post] for the background behind this crate.
+//!
+//! [blog post]: https://lambda.xyz/blog/if-chain
+//!
+//! # Note about recursion limits
+//!
+//! If you run into "recursion limit reached" errors while using this macro, try
+//! adding
+//!
+//! ```rust,ignore
+//! #![recursion_limit = "1000"]
+//! ```
+//!
+//! to the top of your crate.
+//!
+//! # Examples
+//!
+//! ## Quick start
+//!
+//! ```rust,ignore
+//! if_chain! {
+//! if let Some(y) = x;
+//! if y.len() == 2;
+//! if let Some(z) = y;
+//! then {
+//! do_stuff_with(z);
+//! }
+//! }
+//! ```
+//!
+//! becomes
+//!
+//! ```rust,ignore
+//! if let Some(y) = x {
+//! if y.len() == 2 {
+//! if let Some(z) = y {
+//! do_stuff_with(z);
+//! }
+//! }
+//! }
+//! ```
+//!
+//! ## Fallback values with `else`
+//!
+//! ```rust,ignore
+//! if_chain! {
+//! if let Some(y) = x;
+//! if let Some(z) = y;
+//! then {
+//! do_stuff_with(z)
+//! } else {
+//! do_something_else()
+//! }
+//! }
+//! ```
+//!
+//! becomes
+//!
+//! ```rust,ignore
+//! if let Some(y) = x {
+//! if let Some(z) = y {
+//! do_stuff_with(z)
+//! } else {
+//! do_something_else()
+//! }
+//! } else {
+//! do_something_else()
+//! }
+//! ```
+//!
+//! ## Intermediate variables with `let`
+//!
+//! ```rust,ignore
+//! if_chain! {
+//! if let Some(y) = x;
+//! let z = y.some().complicated().expression();
+//! if z == 42;
+//! then {
+//! do_stuff_with(y);
+//! }
+//! }
+//! ```
+//!
+//! becomes
+//!
+//! ```rust,ignore
+//! if let Some(y) = x {
+//! let z = y.some().complicated().expression();
+//! if z == 42 {
+//! do_stuff_with(y);
+//! }
+//! }
+//! ```
+//!
+//! ## Type ascription
+//!
+//! ```rust,ignore
+//! let mut x = some_generic_computation();
+//! if_chain! {
+//! if x > 7;
+//! let y: u32 = another_generic_computation();
+//! then { x += y }
+//! else { x += 1 }
+//! }
+//! ```
+//!
+//! becomes
+//!
+//! ```rust,ignore
+//! let mut x = some_generic_computation();
+//! if x > 7 {
+//! let y: u32 = another_generic_computation();
+//! x += y
+//! } else {
+//! x += 1
+//! }
+//! ```
+//!
+//! ## Multiple patterns
+//!
+//! ```rust,ignore
+//! if_chain! {
+//! if let Foo(y) | Bar(y) | Baz(y) = x;
+//! let Bubbles(z) | Buttercup(z) | Blossom(z) = y;
+//! then { do_stuff_with(z) }
+//! }
+//! ```
+//!
+//! becomes
+//!
+//! ```rust,ignore
+//! match x {
+//! Foo(y) | Bar(y) | Baz(y) => match y {
+//! Bubbles(z) | Buttercup(z) | Blossom(z) => do_stuff_with(z)
+//! },
+//! _ => {}
+//! }
+//! ```
+//!
+//! Note that if you use a plain `let`, then `if_chain!` assumes that the
+//! pattern is *irrefutable* (always matches) and doesn't add a fallback branch.
+
+#![cfg_attr(not(test), no_std)]
+
+/// Macro for writing nested `if let` expressions.
+///
+/// See the crate documentation for information on how to use this macro.
+#[macro_export(local_inner_macros)]
+macro_rules! if_chain {
+ ($($tt:tt)*) => {
+ __if_chain! { @init () $($tt)* }
+ };
+}
+
+#[doc(hidden)]
+#[macro_export(local_inner_macros)]
+macro_rules! __if_chain {
+ // Expand with both a successful case and a fallback
+ (@init ($($tt:tt)*) then { $($then:tt)* } else { $($other:tt)* }) => {
+ __if_chain! { @expand { $($other)* } $($tt)* then { $($then)* } }
+ };
+ // Expand with no fallback
+ (@init ($($tt:tt)*) then { $($then:tt)* }) => {
+ __if_chain! { @expand {} $($tt)* then { $($then)* } }
+ };
+ // Munch everything until either of the arms above can be matched.
+ // Munched tokens are placed into `$($tt)*`
+ (@init ($($tt:tt)*) $head:tt $($tail:tt)*) => {
+ __if_chain! { @init ($($tt)* $head) $($tail)* }
+ };
+
+ // `let` with a single pattern
+ (@expand { $($other:tt)* } let $pat:pat = $expr:expr; $($tt:tt)+) => {
+ {
+ let $pat = $expr;
+ __if_chain! { @expand { $($other)* } $($tt)+ }
+ }
+ };
+ // `let` with a single identifier and a type hint
+ (@expand { $($other:tt)* } let $ident:ident: $ty:ty = $expr:expr; $($tt:tt)+) => {
+ {
+ let $ident: $ty = $expr;
+ __if_chain! { @expand { $($other)* } $($tt)+ }
+ }
+ };
+ // `let` with multiple patterns
+ (@expand { $($other:tt)* } let $pat1:pat | $($pat:pat)|+ = $expr:expr; $($tt:tt)+) => {
+ match $expr {
+ $pat1 | $($pat)|+ => __if_chain! { @expand { $($other)* } $($tt)+ }
+ }
+ };
+ // `if let` with a single pattern
+ (@expand {} if let $pat:pat = $expr:expr; $($tt:tt)+) => {
+ if let $pat = $expr {
+ __if_chain! { @expand {} $($tt)+ }
+ }
+ };
+ // `if let` with a single pattern and a fallback
+ (@expand { $($other:tt)+ } if let $pat:pat = $expr:expr; $($tt:tt)+) => {
+ if let $pat = $expr {
+ __if_chain! { @expand { $($other)+ } $($tt)+ }
+ } else {
+ $($other)+
+ }
+ };
+ // `if let` with multiple matterns and a fallback (if present)
+ (@expand { $($other:tt)* } if let $pat1:pat | $($pat:pat)|+ = $expr:expr; $($tt:tt)+) => {
+ match $expr {
+ $pat1 | $($pat)|+ => { __if_chain! { @expand { $($other)* } $($tt)+ } },
+ _ => { $($other)* }
+ }
+ };
+ // `if` with a successful case
+ (@expand {} if $expr:expr; $($tt:tt)+) => {
+ if $expr {
+ __if_chain! { @expand {} $($tt)+ }
+ }
+ };
+ // `if` with both a successful case and a fallback
+ (@expand { $($other:tt)+ } if $expr:expr; $($tt:tt)+) => {
+ if $expr {
+ __if_chain! { @expand { $($other)+ } $($tt)+ }
+ } else {
+ $($other)+
+ }
+ };
+ // Final macro call
+ (@expand { $($other:tt)* } then { $($then:tt)* }) => {
+ $($then)*
+ };
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn simple() {
+ let x: Option<Result<Option<String>, (u32, u32)>> = Some(Err((41, 42)));
+ let mut success = false;
+ if_chain! {
+ if let Some(y) = x;
+ if let Err(z) = y;
+ let (_, b) = z;
+ if b == 42;
+ then { success = true; }
+ }
+ assert!(success);
+ }
+
+ #[test]
+ fn empty() {
+ let success;
+ if_chain! {
+ then { success = true; }
+ }
+ assert!(success);
+ }
+
+ #[test]
+ fn empty_with_else() {
+ let success;
+ if_chain! {
+ then { success = true; }
+ else { unreachable!(); }
+ }
+ assert!(success);
+ }
+
+ #[test]
+ fn if_let_multiple_patterns() {
+ #[derive(Copy, Clone)]
+ enum Robot { Nano, Biscuit1, Biscuit2 }
+ for &(robot, expected) in &[
+ (Robot::Nano, false),
+ (Robot::Biscuit1, true),
+ (Robot::Biscuit2, true),
+ ] {
+ let is_biscuit = if_chain! {
+ if let Robot::Biscuit1 | Robot::Biscuit2 = robot;
+ then { true } else { false }
+ };
+ assert_eq!(is_biscuit, expected);
+ }
+ }
+
+ #[test]
+ fn let_multiple_patterns() {
+ let x: Result<u32, u32> = Ok(42);
+ if_chain! {
+ let Ok(x) | Err(x) = x;
+ then { assert_eq!(x, 42); }
+ else { panic!(); }
+ }
+ }
+
+ #[test]
+ fn let_type_annotation_patterns() {
+ let mut x = 1;
+ if_chain! {
+ if x > 0;
+ let y: u32 = 2;
+
+ then { x += y; }
+ else { x += 1; }
+ };
+ assert_eq!(x, 3);
+ }
+}