# ron2-derive
Derive macros for RON serialization, deserialization, and schema generation.
> **Note:** These macros are re-exported from `ron2` with the default `derive` feature.
> You only need this crate directly if you want to use the macros without the rest of `ron2`.
## Usage
Add to your `Cargo.toml`:
```toml
[dependencies]
ron2 = "0.1" # Includes derive macros by default
```
Or for standalone use:
```toml
[dependencies]
ron2-derive = "0.1"
ron2 = { version = "0.1", default-features = false }
```
## Derive Macros
- `#[derive(Ron)]` - Implements ToRon, FromRon, and RonSchema (all three)
- `#[derive(ToRon)]` - Serialize to RON
- `#[derive(FromRon)]` - Deserialize from RON
- `#[derive(RonSchema)]` - Generate RON schema files
```rust
use ron2_derive::Ron;
use ron2::{FromRon, ToRon};
#[derive(Debug, PartialEq, Ron)]
struct Config {
name: String,
port: u16,
#[ron(default)]
debug: bool,
}
fn main() {
// Deserialize
let config: Config = Config::from_ron(r#"(name: "app", port: 8080)"#).unwrap();
// Serialize
let ron = config.to_ron().unwrap();
}
```
## Container Attributes
| `rename = "Name"` | Use different name in RON |
| `rename_all = "..."` | Apply rename rule to all fields |
| `deny_unknown_fields` | Error on unknown fields |
| `transparent` | Serialize as the single inner field |
Rename rules: `camelCase`, `snake_case`, `PascalCase`, `SCREAMING_SNAKE_CASE`, `lowercase`, `UPPERCASE`
## Field Attributes
| `rename = "name"` | Use different name in RON |
| `skip` | Skip field entirely |
| `skip_serializing` | Skip during serialization |
| `skip_deserializing` | Skip during deserialization |
| `default` | Use `Default::default()` if missing |
| `default = "path"` | Use custom function if missing |
| `flatten` | Flatten nested struct into parent |
| `skip_serializing_if = "fn"` | Skip if predicate returns true |
| `explicit` | Require explicit `Some(...)` or `None` |
| `opt` | Default if missing, skip if equals default |
## Variant Attributes
| `rename = "Name"` | Use different name in RON |
| `skip` | Skip this variant |
## Extension Behavior
### Implicit Some (Default)
`Option<T>` fields accept bare values:
```rust
#[derive(FromRon)]
struct Config {
name: Option<String>,
}
```
```ron
(name: "Alice") // becomes Some("Alice")
(name: Some("Alice")) // also works
(name: None) // None
```
### Explicit Option
Use `#[ron(explicit)]` to require `Some(...)` or `None`:
```rust
#[derive(FromRon)]
struct Config {
#[ron(explicit)]
value: Option<Option<bool>>,
}
```
```ron
(value: Some(Some(true))) // ok
(value: Some(None)) // ok
(value: None) // ok
(value: true) // ERROR - bare value not allowed
```
### Flattened Option Fields
Flattened `Option<T>` fields are presence-based: if none of `T`'s fields are
present in the parent struct, the value is `None`. If any inner field is
present, the value is `Some(T)` (and missing inner fields use defaults).
This means `None` and `Some(T::default())` are indistinguishable in input
when `T` has defaults. Use a non-flattened `Option<T>` or an explicit marker
field if you need to preserve that distinction.
```rust
#[derive(Ron)]
struct Inner {
#[ron(default)]
x: i32,
#[ron(default)]
y: i32,
}
#[derive(Ron)]
struct Outer {
name: String,
#[ron(flatten)]
inner: Option<Inner>,
}
```
```ron
(name: "none") // inner = None
(name: "some", x: 1) // inner = Some(Inner { x: 1, y: 0 })
```
### Transparent Newtypes
Use `#[ron(transparent)]` to serialize as the inner type:
```rust
#[derive(FromRon, ToRon)]
#[ron(transparent)]
struct UserId(u64);
#[derive(FromRon, ToRon)]
struct User {
id: UserId,
name: String,
}
```
```ron
(id: 42, name: "Alice") // UserId is just a number
```
### Optional Fields (`#[ron(opt)]`)
Use `#[ron(opt)]` for fields that have sensible defaults and should be omitted from output when equal to that default. This combines `default` with skip-if-default serialization:
```rust
#[derive(Ron, Default, PartialEq)]
struct Config {
name: String,
#[ron(opt)]
count: i32, // Omitted when 0
#[ron(opt)]
enabled: bool, // Omitted when false
}
```
```ron
// Input with defaults omitted:
(name: "app")
// Output when count=0, enabled=false:
Config(name: "app")
// Output when count=5, enabled=true:
Config(name: "app", count: 5, enabled: true)
```
Requires the field type to implement `Default + PartialEq`.
## License
MIT OR Apache-2.0