#merge #struct #no-std

no-std merge-it

Generates logic for merging structs and enums

1 unstable release

Uses new Rust 2024

0.1.0 Feb 16, 2026

#2302 in Algorithms

23 downloads per month
Used in 9 crates

Apache-2.0

17KB
395 lines

Merge-it is a crate that generates merging logic for structs and enums.

It was inspired by the merge crate and it works similarly, but with the following improvements:

  1. If no merging strategy is specified, Merge::merge is used by default.
  2. Merge is automatically implemented for all commonly used collections such as vectors, BTreeMap/BTreeSet, HashMap/HashSet (both the std and the hashbrown variants for no_std support), IndexMap/IndexSet, OrderMap/OrderSet.
  3. Collections with the same kind of iterators (i.e. single value vs key/value tuple) implement Merge with one another.
  4. Merge::merge is automatically implemented for Option, such that an option value is overwritten only if the new value is Some.
  5. Exports a variety of merging functions, like merging values in maps (rather than overwriting them) or overwriting a value only if the new value is not the default for that type.
  6. Allows usage of closures, other than paths, for defining merging strategies at the field level.
  7. Merge can be derived automatically for enums if all variants contain a single unnamed field.
  8. Merge can be implemented for different target types and not only for Self
use merge_it::Merge;

fn merge_double(left: &mut Vec<i32>, right: Vec<i32>) {
	left.extend(right.into_iter().map(|num| num * 2));
}

#[derive(Merge, Clone)]
struct Example {
	// Uses `Merge::merge` by default
	simple: Vec<i32>,
	#[merge(with = merge_double)]
	with_fn: Vec<i32>,
	#[merge(with = |left, right| left.push(right[0] * 5))]
	with_closure: Vec<i32>,
	#[merge(skip)]
	skipped: Vec<i32>,
}

#[derive(Merge, Clone)]
// Default logic for all fields
#[merge(with = merge_double)]
struct WithDefault {
	uses_default: Vec<i32>,
	// Can be overridden
	#[merge(with = |left, right| left.push(right[0] * 5))]
	with_override: Vec<i32>,
}

// We can also derive it for enums, as long as each variant
// has a single unnamed field
#[derive(Merge, Debug, PartialEq)]
enum EnumExample {
	List(Vec<i32>),
	Single(Option<i32>),
}

fn main() {
	let mut example = Example {
		simple: vec![1],
		with_fn: vec![1],
		with_closure: vec![1],
		skipped: vec![1],
	};

	example.merge(example.clone());

	assert_eq!(example.simple, [1, 1]);
	assert_eq!(example.with_fn, [1, 2]);
	assert_eq!(example.with_closure, [1, 5]);
	assert_eq!(example.skipped, [1]);

	let mut with_default_example = WithDefault {
		uses_default: vec![1],
		with_override: vec![1],
	};

	with_default_example.merge(with_default_example.clone());

	assert_eq!(with_default_example.uses_default, [1, 2]);
	assert_eq!(with_default_example.with_override, [1, 5]);

	let mut enum_example = EnumExample::Single(None);
	enum_example.merge(EnumExample::Single(Some(1)));
	assert_eq!(enum_example, EnumExample::Single(Some(1)));

	// Different variants are not merged
	enum_example.merge(EnumExample::List(vec![1]));
	assert_eq!(enum_example, EnumExample::Single(Some(1)));
}

Dependencies

~0.2–0.9MB
~19K SLoC