1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
//! This module provides macro `assign!` to allow mutating instance with declarative flavor
//!
//! The motivation of this macro is to enable programmer to document a sequence of mutations instance fields as initialization by writing it in a declarative way. `assign!` macro also allows programmer to skip defining fields that has default value. Such case are used when a dependency is exposing an non-exhaustive struct
#![no_std]

/// Mutate instance with declarative flavor
///
///
/// # Usage
/// ```
/// # #[macro_use] extern crate assign;
/// # fn main() {
/// #[non_exhaustive]
/// struct SomeStruct {
///     a: u32,
///     b: Option<f32>,
///     c: String,
/// }
/// impl SomeStruct {
///     fn new() -> SomeStruct {
///         SomeStruct {
///             a: 1u32,
///             b: None,
///             c: String::from("old"),
///         }
///     }
/// }
///
/// // In order to treat the mutation of field `a` and `c` as an initialization
/// // Use assign to mutate field in declarative flavor, thus avoiding the risk inserting code
/// // between the line that defines a field and the line that defines the other
/// // Note that field `b` is skipped
/// let instance = assign!(SomeStruct::new(), {
///     a: 2u32,
///     c: String::from("new"),
/// });
///
/// // Equivalent
/// let instance2 = {
///     let mut item = SomeStruct::new();
///     item.a = 2u32;
///     item.c = String::from("new");
///     item
/// };
///
/// assert_eq!(instance.a, instance2.a);
/// assert_eq!(instance.b, instance2.b);
/// assert_eq!(&instance.c, &instance2.c);
/// # }
/// ```
///
#[macro_export]
macro_rules! assign {
    ($initial_value:expr, {
        $($field:ident: $value:expr),+ $(,)?
    }) => ({
        let mut item = $initial_value;
        $( item.$field = $value; )+
        item
    })
}