# `subdef`
[](https://crates.io/crates/subdef)
[](https://docs.rs/subdef)


[](https://github.com/nik-rev/subdef)
This crate provides an attribute macro [`#[subdef]`](https://docs.rs/subdef/latest/subdef/attr.subdef.html) - it simplifies the creation of nested
structures, reduces boilerplate and helps keep logic in a single place.
```toml
[dependencies]
subdef = "0.1"
```
It is a successor to [`nestify`](https://crates.io/crates/nestify).
The biggest distinguishing feature is that items marked with `#[subdef]` can be
entirely formatted by `rustfmt`.
## Usage
Apply `#[subdef]` to your type to be able to define inline types in individual fields
```rust
#[subdef]
struct UserProfile {
name: String,
address: [_; {
struct Address {
street: String,
city: String
}
}],
friends: [Vec<_>; {
struct Friend {
name: String
}
}],
status: [_; {
enum Status {
Online,
Offline,
Idle
}
}]
}
```
Expansion:
```rust
struct UserProfile {
name: String,
address: Address,
friends: Vec<Friend>,
status: Status,
}
struct Address {
street: String,
city: String,
}
struct Friend {
name: String,
}
enum Status {
Online,
Offline,
Idle,
}
```
### How it works
Fields on types marked with `#[subdef]` can have the type `[Type; { Item }]` where `Type` is the actual
type of the field, and `Item` is the `struct` or `enum`.
The `Type` can contain `_`, which infers to the name of the `Item`. In the above example:
- The `address` field contains `_`, which infers to be `Address`.
- The `friends` field contains `_`, which infers to be `Friend`,
so `Vec<_>` is inferred to `Vec<Friend>`
You can apply `#[subdef]` to enums:
```rust
#[subdef]
pub enum One {
Two([_; { pub struct Two; }])
}
```
Inline types can contain fields that have inline types themselves:
```rust
#[subdef]
struct One {
two: [_; {
struct Two {
three: [_; {
struct Three;
}]
}
}]
}
```
Admittedly, the syntax is a little strange, but that's a small price to pay for the
convenience of automatic formatting by `rustfmt`!
## Propagate attributes
Give attributes to `subdef(...)`, and they will be propagated recursively to all inline types
```rust
#[subdef(derive(Serialize, Deserialize))]
struct SystemReport {
report_id: Uuid,
kind: [_; {
pub enum ReportKind {
Initial,
Heartbeat,
Shutdown,
}
}],
application_config: [_; {
struct ApplicationConfig {
version: String,
container_runtime: String,
flags: [_; {
struct Flags {
is_admin: bool,
is_preview_mode: bool,
telemetry_enabled: bool,
}
}],
components: [Vec<_>; {
struct Component {
name: String,
version: String,
maintainer: Option<String>,
target_platform: String,
}
}],
}
}],
}
```
Expands to this, with fields omitted:
```rust
#[derive(Serialize, Deserialize)]
struct SystemReport { /* ... */ }
#[derive(Serialize, Deserialize)]
pub enum ReportKind { /* ... */ }
#[derive(Serialize, Deserialize)]
struct Flags { /* ... */ }
#[derive(Serialize, Deserialize)]
struct Component { /* ... */ }
#[derive(Serialize, Deserialize)]
struct ApplicationConfig { /* ... */ }
```
### Fine-tune propagation
You can attach labels to each attribute:
```rust
#[subdef(
label1 = cfg(not(windows)),
label2 = derive(Serialize, Deserialize)
)]
struct SystemReport { /* ... */ }
```
These are the fine-tuning attributes that you can use:
- `#[subdef(skip(label1, label2))]` to skip applying the attribute to the type
- `#[subdef(skip_recursively(label1, label2))]` to recursively skip applying the attribute to the type
- `#[subdef(apply(label1, label2))]` to apply the attribute, overriding any previous `#[subdef(skip_recursively)]`
- `#[subdef(apply_recursively(label1, label2))]` to recursively apply the attribute, overriding any previous `#[subdef(skip_recursively)]`
Example usage of these fine-tuning attributes:
```rust
#[subdef(
debug = derive(Debug),
eq = derive(PartialEq, Eq)
)]
#[subdef(skip(debug), skip(eq))]
struct Order {
billing_info: [_; {
#[subdef(skip_recursively(eq))]
struct BillingInfo {
payment_transaction: [_; {
struct TransactionData {
amount_paid_cents: u32,
}
}],
}
}],
shipping_details: [_; {
#[subdef(apply_recursively(eq))]
struct ShippingDetails {
confirmation_status: [_; {
#[subdef(apply(debug))]
struct DetailsConfirmed;
}],
}
}],
}
```
Expansion:
```rust
struct Order {
billing_info: BillingInfo,
shipping_details: ShippingDetails,
}
#[derive(Debug)]
struct TransactionData {
amount_paid_cents: u32,
}
#[derive(Debug)]
struct BillingInfo {
payment_transaction: TransactionData,
}
#[derive(PartialEq, Eq, Debug)]
struct DetailsConfirmed;
#[derive(PartialEq, Eq, Debug)]
struct ShippingDetails {
confirmation_status: DetailsConfirmed,
}
```