shed/cloned/src/lib.rs (161 lines of code) (raw):
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under both the MIT license found in the
* LICENSE-MIT file in the root directory of this source tree and the Apache
* License, Version 2.0 found in the LICENSE-APACHE file in the root directory
* of this source tree.
*/
#![deny(warnings, missing_docs, clippy::all, rustdoc::broken_intra_doc_links)]
//! See examples for what code you can write with cloned macro.
//!
//! # Examples
//!
//! ```
//! # use cloned::cloned;
//! struct A {
//! x: String,
//! y: String,
//! z: String,
//! }
//! impl A {
//! fn foo(&self) {
//! cloned!(self.x, self.y, self.z);
//! (move || {
//! println!("{} {} {}", x, y, z);
//! })();
//! }
//! }
//! # fn main () {}
//! ```
//!
//! It also supports setting a local alias:
//! ```
//! # use cloned::cloned;
//! # fn main () {
//! let foo = 42;
//! cloned!(foo as bar);
//! assert!(foo == bar);
//! # }
//! ```
/// See crate's documentation
#[macro_export]
macro_rules! cloned {
($i:ident as $alias:ident) => {
let $alias = $i.clone();
};
(mut $i:ident as $alias:ident) => {
let mut $alias = $i.clone();
};
($i:ident as $alias:ident, $($tt:tt)*) => {
cloned!($i as $alias);
cloned!($($tt)*);
};
(mut $i:ident as $alias:ident, $($tt:tt)*) => {
cloned!(mut $i as $alias);
cloned!($($tt)*);
};
($this:ident . $i:ident as $alias:ident) => {
let $alias = $this.$i.clone();
};
(mut $this:ident . $i:ident as $alias:ident) => {
let mut $alias = $this.$i.clone();
};
($this:ident . $i:ident as $alias:ident, $($tt:tt)*) => {
cloned!($this . $i as $alias);
cloned!($($tt)*);
};
(mut $this:ident . $i:ident as $alias:ident, $($tt:tt)*) => {
cloned!(mut $this . $i as $alias);
cloned!($($tt)*);
};
($i:ident) => {
cloned!($i as $i)
};
(mut $i:ident) => {
cloned!(mut $i as $i)
};
($i:ident, $($tt:tt)*) => {
cloned!($i as $i);
cloned!($($tt)*);
};
(mut $i:ident, $($tt:tt)*) => {
cloned!(mut $i);
cloned!($($tt)*);
};
($this:ident . $i:ident) => {
cloned!($this.$i as $i)
};
(mut $this:ident . $i:ident) => {
let mut $i = $this.$i.clone();
};
($this:ident . $i:ident, $($tt:tt)*) => {
cloned!($this . $i as $i);
cloned!($($tt)*);
};
(mut $this:ident . $i:ident, $($tt:tt)*) => {
cloned!(mut $this . $i);
cloned!($($tt)*);
};
// Handle trailing ','
() => {};
}
#[cfg(test)]
mod tests {
struct A {
x: String,
}
impl A {
#[allow(clippy::let_and_return)]
fn foo(&self) -> String {
cloned!(self.x);
x
}
}
#[test]
fn test() {
let a = A {
x: "I am a struct".into(),
};
let y: String = "that can".into();
let z: String = "talk a lot".into();
{
cloned!(a.x, y, mut z);
let _ = a.foo();
assert_eq!(
&format!("{} {} {}", x, y, z),
"I am a struct that can talk a lot"
);
z = String::new();
assert_eq!(z, "");
}
}
#[test]
#[allow(unused_variables, unused_assignments)]
fn test_mut() {
let a = 1;
let b = 2;
let c = A {
x: "foo".to_string(),
};
cloned!(mut a);
a += 1;
cloned!(mut a, b);
a += 1;
cloned!(a, mut b);
b += 1;
cloned!(mut c.x);
x += "bar";
cloned!(c.x, mut a);
a += 1;
cloned!(a, mut c.x);
x += "bar";
}
#[test]
fn trailing_comma() {
let a = 1;
let b = 2;
cloned!(a, b,);
assert_eq!((a, b), (1, 2))
}
#[test]
fn trailing_comma_mut() {
let a = 1;
let b = 2;
cloned!(a, mut b,);
b += 2;
assert_eq!((a, b), (1, 4))
}
#[test]
#[allow(unused_variables, unused_mut)]
fn aliases() {
let a = 1;
let b = 2;
let c = A {
x: "foo".to_string(),
};
cloned!(a as a2);
cloned!(a as a2,);
cloned!(mut a as a2);
cloned!(mut a as a2,);
cloned!(c.x as x2);
cloned!(c.x as x2,);
cloned!(mut c.x as x2);
cloned!(mut c.x as x2,);
cloned!(a, a as a2);
cloned!(a, a as a2,);
cloned!(a, mut a as a2);
cloned!(a, mut a as a2,);
cloned!(a, c.x as x2);
cloned!(a, c.x as x2,);
cloned!(a, mut c.x as x2);
cloned!(a, mut c.x as x2,);
}
}