Struct-Merge

GitHub Actions Workflow Crates.io License: MIT Downloads

!!! Deprecated !!!

This project is superseded by inter-struct.

Consider switching to that library, as this library won't get any updates.

!!! Deprecated !!!

Generate code for merging various structs.

This crate provides two proc-macros to generate two very similar traits.

``rust,ignore /// Merge another struct into Self whilst consuming it. /// /// The other trait is namedStructMergeRef` and merges other structs by reference. pub trait StructMerge { /// Merge the given struct into self. fn merge(&mut self, src: Src);

/// Nearly the same as `merge`, but any `Self::Option<T>` fields will only get merged, if the
/// value of the field is `None`.
fn merge_soft(&mut self, src: Src);

} ```

Please read the known caveats section before using this crate!

Example

This example shows a simple usage of the struct_merge macro.

structs.rs: The structs that will be used in this example. ```rust,ignore use structmerge::structmerge;

/// The target struct we'll merge into. pub struct Target { pub normal: String, pub optional: Option, /// This field won't be touched as the macro cannot find a /// respective ignored field in the Mixed struct. pub ignored: Option, }

/// A struct with both an identical and an optional field type. /// Note that the path to Target must always a fully qualifying path.

[struct_merge(crate::structs::Target)]

pub struct Mixed { pub normal: String, pub optional: Option>, } ```

lib.rs ```rust,ignore use struct_merge::prelude::*;

mod structs; use structs::{Target, Mixed};

fn main() { let mut target = Target { normal: "target".tostring(), optional: Some("target".tostring()), ignored: "target".to_string(), };

let mixed = Mixed {
    /// Has the same type as Target::normal
    normal: "mixed".to_string(),
    /// Wraps Target::optional in an Option
    optional: Some(Some("mixed".to_string())),
};

// Merge the `Mixed` struct into target.
target.merge(mixed);
// You can also call this:
// mixed.merge_into(target);
assert_eq!(target.normal, "mixed".to_string());
assert_eq!(target.optional, Some("mixed".to_string()));
assert_eq!(target.ignored, "target".to_string());

} ```

Merge Behavior

The following will explain the merge behavior of a single field on the target struct. The name of the target field is test.

merge and merge_ref

Same Type

rust struct Src { test: T } struct Target { test: T }

This will simply merge src.test into target.test: \ target.test = src.test

Target is Optional

rust struct Src { test: T } struct Target { test: Option<T> }

This will wrap src.test into an Option and merge it into target.test: \ target.test = Some(src.test);

Source is Optional

rust struct Src { test: Option<T> } struct Target { test: T }

This will only merge src.test into target.test if src.test is Some: \ rust if let Some(value) = src.test { target.test = value; }

merge_soft and merge_ref_soft

target.test is not Optional

As long as a target field is not optional it won't be touched!

Target is Optional

rust struct Src { test: T } struct Target { test: Option<T> }

This will wrap src.test into an Option and merge it into target.test but only if target.test is None: \ rust if target.test.is_none() { target.test = Some(src.test); }

Both are Optional

rust struct Src { test: Option<T> } struct Target { test: Option<T> }

This will only merge src.test into target.test if target.test is None: \ rust if target.test.is_none() { target.test = src.test; }

Known caveats

Module/Type Resolution

There is no easy way to do path or type resolution during the procedural macro stage. \ For this reason, this crate might not work with your project's structure.

However, as we're creating safe and valid Rust code the compiler will thrown an error if any problems arise.

When using the normal merge functions, the worst thing that might happen is that this crate won't compile.

However, when using obscured types such as type aliases, the merge_soft functions won't detect Options properly and might merge values even though they're already Some!

Not yet solved problems

These are problems that can probably be solved but they're non-trivial.

Unsolvable problems

These are problems that are either impossible to solve or very infeasible. For instance, something infeasible would be to parse all files and to do a full type resolution of a given crate. That would be a job for the compiler in later stages.