ron2-derive 0.2.0

Derive macros for RON serialization, deserialization, and schema generation
Documentation

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:

[dependencies]
ron2 = "0.1"  # Includes derive macros by default

Or for standalone use:

[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
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

Attribute Description
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

Attribute Description
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

Attribute Description
rename = "Name" Use different name in RON
skip Skip this variant

Extension Behavior

Implicit Some (Default)

Option<T> fields accept bare values:

#[derive(FromRon)]
struct Config {
    name: Option<String>,
}
(name: "Alice")         // becomes Some("Alice")
(name: Some("Alice"))   // also works
(name: None)            // None

Explicit Option

Use #[ron(explicit)] to require Some(...) or None:

#[derive(FromRon)]
struct Config {
    #[ron(explicit)]
    value: Option<Option<bool>>,
}
(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.

#[derive(Ron)]
struct Inner {
    #[ron(default)]
    x: i32,
    #[ron(default)]
    y: i32,
}

#[derive(Ron)]
struct Outer {
    name: String,
    #[ron(flatten)]
    inner: Option<Inner>,
}
(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:

#[derive(FromRon, ToRon)]
#[ron(transparent)]
struct UserId(u64);

#[derive(FromRon, ToRon)]
struct User {
    id: UserId,
    name: String,
}
(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:

#[derive(Ron, Default, PartialEq)]
struct Config {
    name: String,
    #[ron(opt)]
    count: i32,      // Omitted when 0
    #[ron(opt)]
    enabled: bool,   // Omitted when false
}
// 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