A procedural macro to generate a new function implementation for your struct.

Overview

Impl New ๐Ÿฆ€

A procedural macro to generate a new function implementation for your struct.

License Crates.io

Docs.rs CI CD

๐Ÿš€ Add to your project

Add this to your Cargo.toml:

[dependencies]
impl_new = "0.2.0"

Or run this command in your workspace:

cargo add impl_new

โ“ What is the new function?

The new function is a function that is used to create a new instance of a struct. It is a common pattern in Rust to use a new function to create a new instance of a struct instead of using the struct directly. This is because it is easier to add new fields to the struct without breaking the code that uses it.

๐Ÿ‘จโ€๐Ÿ’ป Usage

Is simple, just derive the impl_new::New proc macro on your struct and it will generate a new function for you.

For Named Fields

#[derive(impl_new::New)]
struct Foo {
    name: String,
    age: usize,
}

// The generated code will look like this:
// impl Foo {
//     pub fn new(name: impl Into<String>, age: Into<usize>) -> Self {
//         Self { name: name.into(), age: age.into() }
//     }
// }

fn main() {
    let foo = Foo::new("Hello", 42usize); // Will use `Into::into` to convert the arguments to the fields types.
    assert_eq!(foo.name, "Hello".to_string());
    assert_eq!(foo.age, 42);
}

For Unnamed Fields

Note: The #[impl_new(name = "name")] attribute is required for unnamed fields.

#[derive(impl_new::New)]
struct Foo(#[impl_new(name = "name")] String, #[impl_new(name = "age")] usize);

// The generated code will look like this:
// impl Foo {
//     pub fn new(name: impl Into<String>, age: Into<usize>) -> Self {
//         Self(name.into(), age.into())
//     }
// }

fn main() {
    let foo = Foo::new("Hello", 42usize); // Will use `Into::into` to convert the arguments to the fields types.
    assert_eq!(foo.0, "Hello".to_string());
    assert_eq!(foo.1, 42);
}

๐Ÿ›น Attributes

#[impl_new(name = "name")]

The name option specifies the name of the argument in the new function.

Note: This attribute is required for unnamed fields.

Example

#[derive(impl_new::New)]
struct User(#[impl_new(name = "username")] String, #[impl_new(name = "age")] i32);

// The generated code will look like this:
// impl User {
//     pub fn new(username: impl Into<String>, age: Into<i32>) -> Self {
//         Self(username.into(), age.into())
//     }

fn main() {
    let user = User::new("Hello", 42); // Will use `Into::into` to convert the arguments to the fields types.
    assert_eq!(user.0, "Hello".to_string());
    assert_eq!(user.1, 42);
}
#[derive(impl_new::New)]
struct User {
    #[impl_new(name = "username")]
    name: String,
    #[impl_new(name = "user_age")]
    age: i32,
}

// The generated code will look like this:
// impl User {
//     pub fn new(username: impl Into<String>, user_age: Into<i32>) -> Self {
//         Self { name: username.into(), age: user_age.into() }
//     }
// }

fn main() {
    let user = User::new("Hello", 42); // Will use `Into::into` to convert the arguments to the fields types.
    assert_eq!(user.name, "Hello".to_string());
    assert_eq!(user.age, 42);
}

#[impl_new(default)]

The default option will remove the field from the new function arguments and use the default value of the field type instead.

Note: This option is conflict with the name option, because the field will be removed from the new function arguments.

Example

#[derive(impl_new::New, Default, Debug, PartialEq)]
struct User {
    name: String,
    #[impl_new(default)]
    is_admin: bool,
}

// The generated code will look like this:
// impl User {
//     pub fn new(name: impl Into<String>) -> Self {
//         Self { name: name.into(), is_admin: bool::default() }
//     }
// }

#[derive(impl_new::New)]
struct Foo(#[impl_new(name = "somthing")] String, #[impl_new(default)] User);

// The generated code will look like this:
// impl Foo {
//     pub fn new(somthing: impl Into<String>) -> Self {
//         Self(somthing.into(), User::default())
//     }
// }

fn main() {
    let user = User::new("Hello"); // Will use `Into::into` to convert the arguments to the fields types.
    let some_foo = Foo::new("Hello"); // Will use `Into::into` to convert the arguments to the fields types.
    assert_eq!(user.name, "Hello".to_string());
    assert_eq!(user.is_admin, false);
    assert_eq!(some_foo.0, "Hello".to_string());
    assert_eq!(some_foo.1, User::default());
}

#[impl_new(value = || <VALUE>)]

The value option will set the field value to the given value.

Note: This option is conflict with the name and default options, because the field will be removed from the new function arguments.

Note: The value must be a closure that returns the field type.

Example

#[derive(impl_new::New)]
struct User {
    name: String,
    #[impl_new(value = || true)]
    is_active: bool,
}

// The generated code will look like this: (Not exactly, but you get the idea)
// impl User {
//     pub fn new(name: impl Into<String>) -> Self {
//         Self { name: name.into(), is_active: true }
//     }
// }

#[derive(impl_new::New)]
struct Foo(#[impl_new(name = "name")] String, #[impl_new(value = || true)] bool);

// The generated code will look like this: (Not exactly, but you get the idea)
// impl Foo {
//     pub fn new(name: impl Into<String>) -> Self {
//         Self(name.into(), true)
//     }
// }

fn main() {
    let user = User::new("Bob"); // Will use `Into::into` to convert the arguments to the fields types.
    let some_foo = Foo::new("Bob"); // Will use `Into::into` to convert the arguments to the fields types.
    assert_eq!(user.name, "Bob".to_string());
    assert_eq!(user.is_active, true);
    assert_eq!(some_foo.0, "Bob".to_string());
    assert_eq!(some_foo.1, true);
}

๐Ÿค— Contributing

Contributions are welcome! You can contribute in many ways, for example:

  • Improve the documentation.
  • Add more tests.
  • Add more examples.
  • Report a bug by opening an issue.
  • Suggest a new feature by opening an issue.
  • Fix a bug or add a new feature. (Please open an issue first if you want to add a new feature or if you want to fix a bug that doesn't have an issue yet.)
  • Fix a typo.
  • Refactor the code.
  • Improve the error messages.

๐Ÿค Code of Conduct

We are committed to providing a friendly, safe and welcoming environment for all. Please read and respect the Code of Conduct.

๐Ÿ“ Changelog

See CHANGELOG.md.

๐Ÿ”‘ License

This project is licensed under the MIT license.

You might also like...
 A new blockchain architecture under active development, with a strong focus on scalability, privacy and safety
A new blockchain architecture under active development, with a strong focus on scalability, privacy and safety

Project Slingshot Accelerating trajectory into interstellar space. Slingshot is a new blockchain architecture under active development, with a strong

A tray application for Windows that gives you push notifications and instant downloads of new posts, messages and stories posted by models you subscribe to on Onlyfans.

OF-notifier A tray application for Windows that gives you push notifications and instant downloads of new posts, messages and stories posted by models

My create new project simply (originaly in bash), in rust !

CNPS-Rust CNPS (Create new project simply) is a powerful tool built in Rust that simplifies the process of creating projects in various programming la

Moving to the new Arbiter framework to test Portfolio.

Stable Pool Simulation The simulation in this repository is intended to demonstrate a basic simulation created with the Arbiter framework. To do so, w

A Rust macro for writing nested loop expressions

loop_chain A Rust macro for writing nested loop expressions Usage | Examples | Docs Dependencies [dependencies] loop_chain = "0.1.1" Usage For express

Macro assembler for Rust

Macro Assembler This crate implement JSC/SpiderMonkey like macro assembler. Macro assembler purpose is to generate machine code for different platform

Macro for fast implementing serialize methods in serde::Serializer trait

impl_serialize! This library provides a simple procedural macro for fast implementing serialize methods in serde::Serializer trait. [dependencies] imp

hashmap macro for creating hashmap from provided key/value pairs

HashMap Macro Creates a HashMap from provided key/value pairs. Usage use std::collections::HashMap; use hashmap_macro::hashmap; let m: HashMap&str,

Library and proc macro to analyze memory usage of data structures in rust.
Library and proc macro to analyze memory usage of data structures in rust.

Allocative: memory profiler for Rust This crate implements a lightweight memory profiler which allows object traversal and memory size introspection.

Comments
  • [Feature request]: New `impl_new` attribute option to set a default value for the field.

    [Feature request]: New `impl_new` attribute option to set a default value for the field.

    Feature description

    New impl_new attribute option to set a default value for the field. This will remove the field from the new function arguments and use the value that you set instead. This will be useful to set a specific value for a field that you don't want to be changed by the user.

    Note: This will not use Default::default to set the default value, it will use the value that you set.

    Example

    #[derive(impl_new::New)]
    struct SomeStruct {
        #[impl_new(name = "Some_name")]
        name: String,
        #[impl_new(value = String::from("This is a default text"))]
        text: String,
    }
    
    fn main() {
        let some_struct = SomeStruct::new("Alix");
        assert_eq!(some_struct.name, "Alix".to_string());
        assert_eq!(some_struct.text, "This is a default text".to_string());
    }
    
    ๐Ÿ”ฅ Feature 
    opened by TheAwiteb 0
  • [Feature request]: `default` option that set the default value of the field

    [Feature request]: `default` option that set the default value of the field

    Feature description

    default option in the impl_new attribute, which will remove the field from the new function and use the default value instead.

    Conflict

    This should conflict with the name option, because default will remove the field from the new function and use the default value instead, so there is no need to rename the field because it is not in the new function.

    Example

    
    #[derive(impl_new::New)]
    struct User {
        username: String,
        age: u8,
        #[impl_new(default)]
        is_admin: bool,
    }
    
    // Generated code:
    // impl User {
    //     pub fn new(username: impl Into<String>, age: impl Into<u8>) -> Self {
    //         Self {
    //             username,
    //             age,
    //             is_admin: bool::default(),
    //         }
    //     }
    // }
    
    fn main() {
        let user = User::new("Alice", 18);
        assert_eq!(user.username, "Alice");
        assert_eq!(user.age, 18);
        assert_eq!(user.is_admin, false);
    }
    
    ๐Ÿ”ฅ Feature 
    opened by TheAwiteb 0
  • Add CI/CD workflow and issues template

    Add CI/CD workflow and issues template

    Description

    Add a CI/CD workflow and issues template, this will help contributors to know what to do and how to do it.

    Tasks

    • [x] Bug report template
    • [x] Feature request template
    • [x] question template

    • [x] Rustfmt
    • [x] Clippy
    • [x] Tests

    • [x] Add a CI/CD badge to the README.md

    • [x] Publish to crates.io for tags
    ๐Ÿ‘ทโ€โ™‚๏ธ CI 
    opened by TheAwiteb 0
Releases(v0.2.1)
Owner
Mohammed Alotaibi
Awiteb a university student and aspiring programmer who loves the Rust language
Mohammed Alotaibi
Procedural macro to derive Serde serializer-deserializer for Prost

prost-serde-derive prost-serde-derive is a procedural macro to generate Serde serializers and deserializers for Prost-generated structs. Rationale Cur

Park Joon-Kyu 4 Dec 15, 2022
A Rust attribute macro that adds memoization to a function (rhymes with Mickey)

michie (sounds like Mickey) โ€” an attribute macro that adds memoization to a function. Table of contents Features Non-features key_expr key_type store_

Mobus Operandi 16 Dec 20, 2022
Learn to write Rust procedural macros [Rust Latam conference, Montevideo Uruguay, March 2019]

Rust Latam: procedural macros workshop This repo contains a selection of projects designed to learn to write Rust procedural macros โ€” Rust code that g

David Tolnay 2.5k Dec 29, 2022
Simple and customizable procedural noise generation library written in Rust.

libnoise A simple, performant, and customizable procedural noise generation library inspired by libnoise for C++ featuring: Easy coherent noise genera

SpoogieOogie 29 Aug 13, 2023
Proc macro implementation of #[naked]

#[naked] Documentation This crate provide a proc macro version of the #[naked] attribute which can be used on stable Rust. Example // The SYSV64 calli

Amanieu d'Antras 10 Aug 13, 2022
A Quest to Find a Highly Compressed Emoji :shortcode: Lookup Function

Highly Compressed Emoji Shortcode Mapping An experiment to try and find a highly compressed representation of the entire unicode shortcodes-to-emoji m

Daniel Prilik 13 Nov 16, 2021
a function programming language for real world applications made in rust

a function programming language for real world applications made in rust

Tanay Pingalkar 6 Jun 12, 2022
Allow function lifetime elision and explicit `for<'a>` annotations on closures.

::higher-order-closure Allow function lifetime elision and explicit for<'a> annotations on closures. Motivation / Rationale See the RFC #3216: this cr

Daniel Henry-Mantilla 18 Dec 26, 2022
Tool to convert variable and function names in C/C++ source code to snake_case

FixNameCase Tool to convert variable and function names in C/C++ source code to snake_case. Hidden files and files listed in .gitignore are untouched.

AgriConnect 4 May 25, 2023
Generate SUMMARY.md files based on your book's file structure

mdbook-autosummary Generate a SUMMARY.md for your mdBook based on your folder structure! Warning The implementation is hacky and has several limitatio

Hyper 3 Sep 30, 2023