corresponding

Crates.iocorresponding
lib.rscorresponding
version0.1.8
sourcesrc
created_at2022-06-26 23:00:03.773716
updated_at2022-06-27 09:20:18.77705
descriptionMove corresponding fields between structs
homepagehttps://github.com/markjansnl/corresponding-rs
repositoryhttps://github.com/markjansnl/corresponding-rs
max_upload_size
id613852
size14,705
Mark Jans (markjansnl)

documentation

README

Corresponding

This Rust crate can be used to copy structs within a module to each other. Only fields with the same name and type will be copied, hence the crate name corresponding.

By adding the attribute derive_corresponding to a module, the trait MoveCorresponding will be implemented for all the structs within the module. This makes it possible to call the move_corresponding function on all the structs in the attributed module with all the structs in the module as parameter. The trait From will be implemented for all structs in the module that derive Default for all other structs in the module.

Example

Put the derive_corresponding attribute on a module. This module must be declared inline.

use corresponding::derive_corresponding;

#[derive_corresponding]
mod my_mod {
    #[derive(Debug, Default)]
    pub struct A {
        pub a: u8,
        pub b: u8,
        pub c: u8,
    }

    #[derive(Debug, Clone)]
    pub struct B {
        pub a: u8,
        pub b: Option<u8>,
        pub d: u8,
    }
}

Make sure MoveCorresponding is in scope and start moving corresponding fields from B to A and vice versa:

use corresponding::MoveCorresponding;
use my_mod::*;

fn start_moving() {
    let mut a = A { a: 1, b: 1, c: 1 };
    let mut b = B { a: 2, b: Some(2), d: 2 };

    a.move_corresponding(b.clone());
    println!("{a:?}");      // Output: A { a: 2, b: 2, c: 1 }

    let a2 = A { a: 3, b: 3, c: 3 };
    b.move_corresponding(a2);
    println!("{b:?}");      // Output: B { a: 3, b: Some(3), d: 2 }
}

Because struct A derives Default, it will also implement From. So you can transform B to A:

fn start_transforming() {
    let b = B { a: 4, b: Some(4), d: 4 };
    
    let a: A = b.into();
    println!("{a:?}");      // Output: A { a: 4, b: 4, c: 0 }
}

Struct B doesn't derive Default, so you cannot transform A to B. From is not implemented for this case.

Also see a working example in the examples folder.

Options

Also fields with types T and Option<T> are considered corresponding.

  • Moving Option<T> to T will only set the target field when the source field is Some(value)
  • Moving T to Option<T> will always set the target field with Some(value)
  • Moving Option<T> to Option<T> will only set the target field when the source field is Some(value)

This means there is no way of setting an Option to None by using move_corresponding.

Deeper nested Options are not supported, so Option<Option<V>> is considered as Option<T> with T = Option<V>.

Expand

If you have cargo-expand installed, you can see the generated implementations by running:

$ cd corresponding
$ cargo expand --example corresponding
Commit count: 36

cargo fmt