Merge

Trait Merge 

Source
pub trait Merge<Partial>: Sized {
    // Required method
    fn merge_in_place(&mut self, other: Partial);

    // Provided method
    fn merge(self, other: Partial) -> Self { ... }
}
Expand description

A trait for two types that can be merged into one.

The Partial type is the type being merged into Self. It is intended to represent a subset of the data in Self, though it is not a strict requirement.

§Examples

This is an example using the Merge derive macro. Please see its documentation for further details.

#[derive(Merge)]
// Name the partial version of this type `PartialPerson`. This attribute is required.
#[partial(PartialPerson)]
struct Person {
    name: String,
    age: u16,
    // Instead of overwriting the list of friends when merged, combine them together.
    #[strategy(merge)]
    friends: Vec<String>,
}

let person = Person {
    name: "Janette".to_string(),
    age: 19,
    friends: vec!["Lou".to_string()],
};

// Change Janette's age to be 25 and add a friend, but preserve her original name.
let partial = PartialPerson {
    name: None,
    age: Some(25),
    friends: Some(vec!["Kylie".to_string()]),
};

let merged = person.merge(partial);

assert_eq!(merged.name, "Janette");
assert_eq!(merged.age, 25);
assert_eq!(merged.friends, ["Lou", "Kylie"]);

This is an example implementing Merge from scratch. It is equivalent to the prior example.

struct Person {
    name: String,
    age: u16,
    friends: Vec<String>,
}

// This represents a subset of `Person` and can be merged with it. When a field is `Some`, it
// will overwrite the `Person`'s value. When a field is `None`, it will preserve the original
// value.
struct PartialPerson {
    name: Option<String>,
    age: Option<u16>,
    friends: Option<Vec<String>>,
}

impl Merge<PartialPerson> for Person {
    fn merge_in_place(&mut self, other: PartialPerson) {
        if let Some(name) = other.name {
            self.name = name;
        }

        if let Some(age) = other.age {
            self.age = age;
        }

        // Instead of overwriting the list of friends, merge the two together.
        if let Some(friends) = other.friends {
            self.friends.merge_in_place(friends);
        }
    }
}

let person = Person {
    name: "Janette".to_string(),
    age: 19,
    friends: vec!["Lou".to_string()],
};

// Change Janette's age to be 25 and add a friend, but preserve her original name.
let partial = PartialPerson {
    name: None,
    age: Some(25),
    friends: Some(vec!["Kylie".to_string()]),
};

let merged = person.merge(partial);

assert_eq!(merged.name, "Janette");
assert_eq!(merged.age, 25);
assert_eq!(merged.friends, ["Lou", "Kylie"]);

Required Methods§

Source

fn merge_in_place(&mut self, other: Partial)

Merges Self and Partial together, mutating Self in place.

§Examples
#[derive(Merge)]
#[partial(PartialCat)]
struct Cat {
    name: String,
    age: u16,
}

let mut whiskers = Cat {
    name: "Whiskers".to_string(),
    age: 4,
};

let partial = PartialCat {
    name: None,
    age: Some(5),
};

whiskers.merge_in_place(partial);

assert_eq!(whiskers.name, "Whiskers");
assert_eq!(whiskers.age, 5);

Provided Methods§

Source

fn merge(self, other: Partial) -> Self

Merges Self and Partial together, returning a new Self.

§Examples
#[derive(Merge)]
#[partial(PartialCat)]
struct Cat {
    name: String,
    age: u16,
}

let mut whiskers = Cat {
    name: "Whiskers".to_string(),
    age: 4,
};

let partial = PartialCat {
    name: Some("Toast".to_string()),
    age: None,
};

let toast = whiskers.merge(partial);

assert_eq!(toast.name, "Toast");
assert_eq!(toast.age, 4);

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl<Base, Partial, Item> Merge<Partial> for Base
where Base: Extend<Item>, Partial: IntoIterator<Item = Item>,

Implements Merge for any type that implements Extend.

This means that most standard library collection types can be merged with anything iterable over the same type. Some highlights include:

  • Vec<T> with IntoIterator<Item = T>
  • String with IntoIterator<Item = &str> or IntoIterator<Item = char>
  • HashMap<K, V> with IntoIterator<Item = (K, V)>
  • HashSet<T> with IntoIterator<Item = T>
  • BTreeMap<K, V> with IntoIterator<Item = (K, V)>
  • BTreeSet<T> with IntoIterator<Item = T>
  • PathBuf with IntoIterator<Item = Path>

§Examples

let a = vec![1, 2];
let b = &[3, 4, 5];

assert_eq!(a.merge(b), [1, 2, 3, 4, 5]);
let c = String::from("Hello, ");
let d = ['w', 'o', 'r', 'l', 'd', '!'];

assert_eq!(c.merge(d), "Hello, world!");
let mut e = HashMap::from([
    ("Hello", "Bonjour"),
    ("Goodbye", "Au revoir"),
]);

let f = [
    ("Apple", "Pomme"),
    ("Potato", "Pomme de terre"),
];

assert_eq!(
    e.merge(f),
    HashMap::from([
        ("Hello", "Bonjour"),
        ("Goodbye", "Au revoir"),
        ("Apple", "Pomme"),
        ("Potato", "Pomme de terre"),
    ]),
);
let g = vec![2, 4, 8];
let h = std::iter::successors(Some(16), |n| Some(n * 2)).take(3);

assert_eq!(g.merge(h), [2, 4, 8, 16, 32, 64]);