6 releases
| new 0.3.0 | Feb 22, 2026 |
|---|---|
| 0.2.3 | Oct 25, 2025 |
| 0.2.2 | Mar 30, 2023 |
| 0.1.1 | Mar 29, 2023 |
#1015 in Rust patterns
23KB
405 lines
INew – a library for generating constructors
In Rust, writing constructors is common but can be repetitive and boring. This library simplifies the process, making it more enjoyable and freeing up time for more interesting tasks.
The purpose of this library is to cover the most basic and frequent case. If you want more complex generation, you should probably take a look at rust-derive-builder
How to add the library to your project?
Just add to Cargo.toml
[dependencies]
inew = "0.3.0"
Мinimum supported Rust version
The library requires a minimum Rust version of 1.80.0.
Usage examples
Suppose you have a structure and constructor, and we want to make a constructor for it. And it looks like this
struct MyStruct {
x: u32,
y: u16,
z: String,
field: String,
another_field: String
}
impl MyStruct {
pub fn new(x: u32,
y: u16,
z: String,
field: String,
another_field: String) -> Self {
Self {
x,
y,
z,
field,
another_field
}
}
}
But everything here is very obvious, all fields and types are known to compiler. Therefore, we can hand over constructor generation to a macro
use inew::New;
#[derive(New)]
struct MyStruct {
x: u32,
y: u16,
z: String,
field: String,
another_field: String
}
That's it, just add the New annotation
Default fields and custom functions for generating fields
If you don't want to pass all the fields, you can fill in some of the fields using annotations #[new(default)] for
initialization with Default::default() or #[new(default = my_func_name())] for initialization by calling
my_func_name().
use inew::New;
#[derive(New)]
struct MyStruct {
name: String,
#[new(default)]
entries: Vec<u32>,
#[new(default)]
some_values: std::collections::HashSet<u32>,
#[new(default = custom_func())]
custom_value: u32
}
fn custom_func() -> u32 {
42u32
}
fn main() {
let s = MyStruct::new("123".to_owned());
}
The #[new(default = ...)] attribute can take any valid Rust expression, such as 1 + 1 or vec![1], as its argument.
Into arguments
It's often more convenient to make the parameters accept impl Into<T> instead of T, which makes them automatically call into() inside. This can be done with #[new(into)].
use inew::New;
#[derive(New)]
struct MyStruct {
#[new(into)]
name: String,
}
fn main() {
let s = MyStruct::new("John");
}
A field's #[new(...)] attribute cannot be marked with #[new(into)] and #[new(default)] at the same time, since they are incompatible by design.
Custom names and privacy
It is also possible to configure the privacy and rename the constructor using attributes.
Custom names
use inew::New;
#[derive(New)]
#[new(rename = "create")]
struct MyStruct {
x: u32,
}
fn main() {
let s = MyStruct::create(1);
}
Privacy
use inew::New;
#[derive(New)]
#[new(pub = false)]
struct MyStruct {
x: u32,
}
fn main() {
let s = MyStruct::new(1); // now it's a private function
}
Generics and lifetimes
Generics and lifetimes are supported and work
Generics
use inew::New;
#[derive(New)]
struct MyStruct<Y, Z> {
x: u32,
y: Y,
z: Z,
}
fn main() {
let s = MyStruct::new(1u32, 2u64, 3u16);
}
Lifetimes
use inew::New;
#[derive(New)]
struct MyStruct<'a> {
x: u32,
y: &'a u16,
}
fn main() {
let y = 1u16;
let s = MyStruct::new(1, &y);
}
Static lifetimes
use inew::New;
const NAME: &str = "John";
#[derive(New)]
struct MyStruct {
name: &'static str,
}
fn main() {
let s = MyStruct::new(NAME);
}
Tuple structs
Tuple structs are fully supported as well
use inew::New;
#[derive(New)]
struct MyStruct(u32);
fn main() {
let s = MyStruct::new(1);
}
Unit-like structs
Unit-like structs also work as expected
use inew::New;
#[derive(New)]
struct MyStruct;
fn main() {
let s = MyStruct::new();
}
Constant constructors
Derived constant constructors are also supported, but they come with some limitations, see below.
use inew::New;
#[derive(New)]
#[new(const = true)]
struct MyStruct {
x: u32,
}
fn main() {
const S: MyStruct = MyStruct::new(5);
}
Limitations of constant constructors:
- Trait defaults like
#[new(default)]attribute are not supported, sinceDefaultis not yet stable as aconsttrait. - Macro defaults like
#[new(default = my_macro!())]are supported as long as they expand to a constant expression, so any macro that does allocation is not supported. - Function defaults like
#[new(default = my_function())]are supported only if the function isconst. - Any struct with generics cannot have defaults of any kind.
- Since the
Intotrait is not aconsttrait, the#[new(into)]attribute is not supported.
Unit and PhantomData
Fields with type () and PhantomData are always initialized with default values and skipped from the derived constructor, even for constant constructors.
use inew::New;
use std::marker::PhantomData;
#[derive(New)]
#[new(const = true)]
struct MyStruct<T> {
x: (),
y: PhantomData<T>,
}
fn main() {
// Both cases below are valid
let s: MyStruct<u32> = MyStruct::new();
const S: MyStruct<u32> = MyStruct::new();
}
Special thanks to
- Chat GPT-4, which helped me write all this documentation and correct a huge number of errors in the code
- Anna, who was my inspiration
- Stable Diffusion, which helped me to create logo :-)
Licensing
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Contribution
Any contribution is welcome. Just write tests and submit merge requests
Comparison with derive-new
There is a very similar library with almost the same set of features and syntax. derive-new Below is a list of differences in the table.
| Feature | INew | derive-new |
|---|---|---|
| Default values support | Yes | Yes |
| Into arguments support | Yes | Yes |
| Into iter arguments support | No | Yes |
| Generics and lifetimes support | Yes | Yes |
| Enum support | No | Yes |
| Constructor privacy settings | Yes | No |
| Constructor renaming | Yes | No |
| Tuple structs support | Yes | Yes |
| Constant constructors support | Yes | No |
Related projects
Rust libraries
rust-derive-builder derive-new derive_more
Java libraries
Non-library projects
Functionality is also built into the Scala, Kotlin, and Java languages for entities such
as case class, data class, record
Dependencies
~130–510KB
~12K SLoC