10 releases (4 breaking)

0.5.6 Jan 20, 2024
0.5.5 Dec 5, 2023
0.4.5 Dec 4, 2023
0.3.0 Oct 24, 2023
0.1.2 Jan 16, 2023

#199 in Procedural macros

Download history 20/week @ 2024-01-16 4/week @ 2024-02-13 44/week @ 2024-02-20 25/week @ 2024-02-27 14/week @ 2024-03-12 10/week @ 2024-03-19 12/week @ 2024-03-26 50/week @ 2024-04-02

86 downloads per month

MIT/Apache

18KB
177 lines

Automation of Destructure Pattern

crate.io docs.rs

destructure is an automation library for destructure pattern.

What is destructure pattern?

A structure with too many fields makes it hard to call constructors, but it is also hard work to prepare a Getter/Setter for each one. There are macros for this purpose, but even so, a large number of macros reduces readability. This is especially true when using From<T> Trait.

So how can this be simplified? It is the technique of "converting all fields to public".

This allows for a simplified representation, as in the following example

pub struct AuthenticateResponse {
    id: Uuid,
    user_code: String,
    verification_uri: String,
    expires_in: i32,
    message: String,
    // ... too many fields...
}

impl AuthenticateResponse {
    pub fn into_destruct(self) -> DestructAuthenticateResponse {
        DestructAuthenticateResponse {
            id: self.id,
            user_code: self.user_code,
            verification_uri: self.verification_uri,
            expires_in: self.expires_in,
            message: self.message,
            // ...
        }
    }
}

pub struct DestructAuthenticateResponse {
    pub id: Uuid,
    pub user_code: String,
    pub verification_uri: String,
    pub expires_in: i32,
    pub message: String,
    // ... too many fields (All `public`.)...
}

#[tokio::main]
async fn main() {
    let res = reqwest::get("http://example.com")
        .send().await.unwrap()
        .json::<AuthenticateResponse>().await.unwrap();
    
    let des = res.into_destruct();

    println!("{:?}", des.id);
}

There are several problems with this method, the most serious of which is the increase in boilerplate.
Using the multi-cursor feature of the editor, this can be done by copy-pasting, but it is still a hassle.

Therefore, I created a Procedural Macro that automatically generates structures and methods:

use destructure::Destructure;

#[derive(Destructure)]
pub struct AuthenticateResponse {
    id: Uuid,
    user_code: String,
    verification_uri: String,
    expires_in: i32,
    message: String,
    // ... too many fields...
}

#[tokio::main]
async fn main() {
    let res = reqwest::get("http://example.com")
        .send().await.unwrap()
        .json::<AuthenticateResponse>().await.unwrap();

    // Auto generate
    let des: DestructAuthenticateResponse = res.into_destruct();

    println!("{:?}", des.id);
}

You can also perform safe value substitution by using reconstruct() or substitute(),
which performs the same role as the following usage.

use destructure::{Destructure, Mutation};

#[derive(Destructure, Mutation)]
pub struct AuthenticateResponse {
    id: Uuid,
    user_code: String,
    verification_uri: String,
    expires_in: i32,
    message: String,
    // ... too many fields...
}

#[tokio::main]
async fn main() {
    let res = reqwest::get("http://example.com")
        .send().await.unwrap()
        .json::<AuthenticateResponse>().await.unwrap();

    let message = "After".to_string();
    
    // `reconstruct()` consumes self and provides the Destructed structure 
    // as a variable reference in a closure. 
    // Literally, it is a method that reconstructs.
    let res: AuthenticateResponse = res.reconstruct(|before| {
        before.message = message;
    });
    
    // substitute is a method that refills variable references of its own field values 
    // into another structure and provides them in a closure.
    //
    // This method is suitable for loop processing, etc., 
    // because it processes by reference as opposed to reconstruct, which consumes values.
    let mut res = res;
    res.substitute(|before| {
        *before.message = message;
    });

    println!("{:?}", des.id);
}

Problem

It is still lacking in functionality, but we will accept PullRequests and Issues if there are any problems.

Dependencies

~295–740KB
~18K SLoC