auto! Macro
The auto! macro simplifies constructing instances of types generated by derive_struct! and derive_enum!. Its primary value is resolving anonymous type names automatically — you write human-readable paths while the macro expands them to the correct generated names.
Why auto!?
When you use anonymous structs or enums, yuuka generates names like _Root_0_anonymous. Constructing these manually is verbose and fragile:
#![allow(unused)]
fn main() {
derive_struct!(Root {
data: {
name: String,
score: f64,
},
});
// Without auto! — you must know the generated name
let val = Root {
data: _Root_0_anonymous {
name: "test".to_string(),
score: 99.5,
},
};
// With auto! — just use { }
let val = auto!(Root {
data: {
name: "test".to_string(),
score: 99.5,
},
});
}
Struct Construction
Basic Struct
#![allow(unused)]
fn main() {
derive_struct!(Root {
a: String,
b: i32,
});
let obj = auto!(Root {
a: "hello".to_string(),
b: 42,
});
}
Nested Anonymous Structs
#![allow(unused)]
fn main() {
derive_struct!(Root {
a: String,
b: i32,
c: f64,
d: {
e: String = "world".to_string(),
f: i32,
},
});
let obj = auto!(Root {
a: "hello".to_string(),
b: 42,
c: std::f64::consts::PI,
d: {
f: 24,
..Default::default()
},
});
assert_eq!(obj.d.e, "world"); // From default
assert_eq!(obj.d.f, 24); // Explicitly set
}
Spread Expression
Use ..Default::default() to fill remaining fields with defaults, just like standard Rust struct update syntax:
#![allow(unused)]
fn main() {
let obj = auto!(Root {
a: "hello".to_string(),
b: 42,
c: 3.14,
d: {
f: 24,
..Default::default() // e gets its default "world"
},
});
}
Enum Construction
Unit Variant
#![allow(unused)]
fn main() {
derive_enum!(
#[derive(PartialEq)]
enum Root {
A,
B(i32),
C { a: String, b: i32 },
}
);
assert_eq!(auto!(Root::A), Root::A);
}
Tuple Variant
#![allow(unused)]
fn main() {
assert_eq!(auto!(Root::B(42)), Root::B(42));
}
Struct-like Variant
#![allow(unused)]
fn main() {
assert_eq!(
auto!(Root::C {
a: "hello".to_string(),
b: 42,
}),
Root::C {
a: "hello".to_string(),
b: 42,
}
);
}
Anonymous Enum Path Resolution
This is where auto! truly shines. For anonymous enums nested inside tuple variants, auto! resolves the path through multiple levels:
Single Level
#![allow(unused)]
fn main() {
derive_enum!(
#[derive(PartialEq)]
enum Root {
D(enum {
E,
F(i32),
G { a: String, b: i32 },
}),
}
);
// Without auto! — verbose
let _ = Root::D(__Root::_Root_0_anonymous::E);
// With auto! — clean
assert_eq!(auto!(Root::D::E), Root::D(__Root::_Root_0_anonymous::E));
assert_eq!(auto!(Root::D::F(42)), Root::D(__Root::_Root_0_anonymous::F(42)));
assert_eq!(
auto!(Root::D::G {
a: "hello".to_string(),
b: 42,
}),
Root::D(__Root::_Root_0_anonymous::G {
a: "hello".to_string(),
b: 42,
})
);
}
Deeply Nested Paths
auto! can resolve paths through arbitrarily deep anonymous enum nesting:
#![allow(unused)]
fn main() {
derive_enum!(
#[derive(PartialEq)]
enum A {
B(enum {
C(enum {
D(enum {
E(enum {
F,
G(String),
}),
}),
}),
}),
}
);
// Resolves: A::B → _A_0_anonymous::C → _A_1_anonymous::D → _A_2_anonymous::E → _A_3_anonymous::F
assert_eq!(
auto!(A::B::C::D::E::F),
A::B(_A_0_anonymous::C(_A_1_anonymous::D(_A_2_anonymous::E(_A_3_anonymous::F))))
);
assert_eq!(
auto!(A::B::C::D::E::G("hello".to_string())),
A::B(_A_0_anonymous::C(_A_1_anonymous::D(_A_2_anonymous::E(
_A_3_anonymous::G("hello".to_string())
))))
);
}
Mixed Usage
You can nest auto! calls inside other auto! calls or regular struct construction:
#![allow(unused)]
fn main() {
derive_struct!(
#[derive(PartialEq)]
Root {
outer: {
a: enum B {
C {
c: i32,
d: f64,
},
},
},
}
);
let val = auto!(Root {
outer: {
a: auto!(B::C { c: 42, d: std::f64::consts::PI }),
},
});
assert_eq!(val.outer.a, B::C { c: 42, d: std::f64::consts::PI });
}
Cross-Module Usage
auto! works across module boundaries as long as the types and their helper macros are in scope:
#![allow(unused)]
fn main() {
#[macro_use]
mod definitions {
use yuuka::derive_struct;
derive_struct!(
#[derive(PartialEq)]
pub Root {
a: String,
b: i32,
}
);
}
mod usage {
use yuuka::auto;
use super::definitions::*;
#[test]
fn test() {
assert_eq!(
auto!(Root {
a: "hello".to_string(),
b: 42,
}),
Root {
a: "hello".to_string(),
b: 42,
}
);
}
}
}
When using anonymous types across modules, ensure the defining module is marked with #[macro_use]:
#![allow(unused)]
fn main() {
#[macro_use]
mod definitions {
use yuuka::derive_struct;
derive_struct!(Root {
data: {
value: String,
},
});
}
mod usage {
use yuuka::auto;
use super::definitions::*;
fn create() {
let val = auto!(Root {
data: {
value: "hello".to_string(),
},
});
}
}
}
For cross-crate usage, see Attributes & Visibility — Cross-Crate Usage.