1 unstable release
0.1.0 | Nov 14, 2024 |
---|
#1449 in Development tools
124 downloads per month
16KB
200 lines
Rust Dataclass Macro
A Rust procedural macro that implements Python-style dataclasses. This macro helps reduce boilerplate code by automatically implementing common traits and generating constructors for your structs.
Features
- Similar API to Python's
@dataclass
decorator - Customizable trait implementations
- Supports frozen (immutable) classes
- Memory layout optimization options
- Automatic constructor generation
- Optional serde support
Installation
Add this to your Cargo.toml
:
[dependencies]
dataclass-macro = "0.1.0" # Replace with actual version
Usage
Basic usage:
use dataclass_macro::dataclass;
#[dataclass] // Use all default options
struct Point {
x: i32,
y: i32,
}
// With custom options
#[dataclass(
init = true,
repr = true,
eq = true,
order = true,
unsafe_hash = true,
frozen = false,
slots = false
)]
struct Person {
name: String,
age: i32,
email: Option<String>,
}
fn main() {
let person = Person::new(
String::from("Alice"),
30,
Some(String::from("alice@example.com"))
);
println!("{:?}", person); // Debug output thanks to repr=true
let clone = person.clone(); // Clone is always implemented
assert_eq!(person, clone); // PartialEq is implemented when eq=true
}
Options
Option | Default | Description |
---|---|---|
init |
true |
Generate a constructor |
repr |
true |
Implement Debug trait |
eq |
true |
Implement PartialEq and Eq traits |
order |
false |
Implement Ord and PartialOrd traits |
unsafe_hash |
false |
Implement Hash trait |
frozen |
false |
Make fields immutable (pub(crate)) |
match_args |
true |
Enable pattern matching support |
kw_only |
false |
Constructor requires named arguments |
slots |
false |
Optimize memory layout |
weakref_slot |
false |
Reserved for future use |
Generated Code
For a basic struct with default options, the macro generates:
// Your code
#[dataclass]
struct Point {
x: i32,
y: i32,
}
// Generated code
#[derive(Clone)]
pub struct Point {
pub x: i32,
pub y: i32,
}
impl Point {
pub fn new(x: i32, y: i32) -> Self {
Self { x, y }
}
}
impl std::fmt::Debug for Point {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Point")
.field("x", &self.x)
.field("y", &self.y)
.finish()
}
}
impl PartialEq for Point {
fn eq(&self, other: &Self) -> bool {
self.x == other.x && self.y == other.y
}
}
impl Eq for Point {}
Feature Flags
serde
: Enable serde support for serialization/deserialization
[dependencies]
dataclass-macro = { version = "0.1.0", features = ["serde"] }
Examples
Basic Point Structure
use dataclass_macro::dataclass;
#[dataclass]
struct Point {
x: i32,
y: i32,
}
let point = Point::new(10, 20);
println!("{:?}", point); // Point { x: 10, y: 20 }
Ordered Data Structure
#[dataclass(order = true)]
struct Version {
major: u32,
minor: u32,
patch: u32,
}
let v1 = Version::new(1, 0, 0);
let v2 = Version::new(2, 0, 0);
assert!(v1 < v2); // Comparison works
Immutable Structure
#[dataclass(frozen = true)]
struct Config {
name: String,
value: i32,
}
let config = Config::new(String::from("test"), 42);
// config.value = 43; // This would cause a compilation error
With Serde Support
use dataclass_macro::dataclass;
use serde::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
#[dataclass]
struct User {
#[serde(rename = "userName")]
name: String,
age: i32,
#[serde(skip_serializing_if = "Option::is_none")]
email: Option<String>,
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let user = User::new(
String::from("Alice"),
30,
Some(String::from("alice@example.com"))
);
// Serialize to JSON
let json = serde_json::to_string_pretty(&user)?;
println!("JSON:\n{}", json);
// Deserialize from JSON
let deserialized: User = serde_json::from_str(&json)?;
assert_eq!(user, deserialized);
Ok(())
}
For more detailed serde integration examples, including custom serialization, working with complex types, and different formats, see SERDE.md.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Comparison with Python's Dataclass
This macro aims to provide similar functionality to Python's dataclass decorator while remaining true to Rust's patterns and safety guarantees. The main differences are:
- No default values in struct definition (use Default trait instead)
- No post-init processing (use custom impl blocks)
- No field order specification (follows struct definition order)
- Additional memory optimization options
- Rust-specific features like pub/pub(crate) visibility
Known Limitations
- Limited support for generic types (work in progress)
- No support for custom derive implementations
- Field attributes are not processed
Dependencies
~220–720KB
~17K SLoC