Skip to content

ZibanPirate/nest_struct

Repository files navigation

crates.io docs.rs CI Maintenance

nest_struct

Nest struct and enum definitions with minimal syntax changes in Rust

Example

use nest_struct::nest_struct;

#[nest_struct]
struct Post {
    title: String,
    summary: String,
    author: nest! {
        name: String,
        handle: String,
    },
}
See expanded code
struct Post {
    title: String,
    summary: String,
    author: PostAuthor,
}

struct PostAuthor {
    name: String,
    handle: String,
}

You can also overwrite inner struct name, by passing the name itself as macro instead of nest!:

use nest_struct::nest_struct;

#[nest_struct]
struct Post {
    title: String,
    summary: String,
    author: Author! {
        name: String,
        handle: String,
    },
}
See expanded code
struct Post {
    title: String,
    summary: String,
    author: Author,
}

struct Author {
    name: String,
    handle: String,
}

Or, you can open a block and define struct like normal Rust code for full flexibility:

use nest_struct::nest_struct;

#[nest_struct]
struct Post {
    title: String,
    summary: String,
    author: nest! {
        /// doc comment for Author struct
        #[derive(Debug)]
        struct Author {
            name: String,
            handle: String,
        }
    },
}
See expanded code
struct Post {
    title: String,
    summary: String,
    author: Author,
}

/// doc comment for Author struct
#[derive(Debug)]
struct Author {
    name: String,
    handle: String,
}

Another example calling Pokemon API
use nest_struct::nest_struct;

// Define a struct with nested struct definitions all in one place
// with minimal syntax changes.
#[nest_struct]
#[derive(serde::Deserialize)]
struct APIResponse {
    id: u32,
    name: String,
    abilities: Vec<nest! {
            ability: nest! { name: String, url: String },
            is_hidden: bool,
            slot: u32,
        },
    >,
}

let body = reqwest::blocking::get("https://pokeapi.co/api/v2/pokemon/ditto").unwrap().text().unwrap();
let api_response: APIResponse = serde_json::from_str(&body).unwrap();

assert_eq!(api_response.name, "ditto");
// Access nested struct fields
assert_eq!(api_response.abilities.first().unwrap().ability.name, "limber");

For more examples, see the ./tests/cases directory.

Features

  • deep nesting (no theoretical limit).
  • nest struct inside another struct.
  • nest enum inside another enum.
  • nest enum inside a struct and vice-versa.
  • inherit derive and other attribute macros from root struct.
  • auto-generate inner struct names.
  • overwrite the auto-generated inner struct name.

Feature parity with native Rust code:

  • impl block on inner structs.
  • define derive and other attribute macros individually per inner struct.
  • define doc comments individually per inner struct.
  • useful compiler error messages.
  • support generic types.
  • support lifetimes.

Contributing

Contributions are welcome, please read CONTRIBUTING.md to get started.

License

Licensed under MIT (twitter: @zibanpirate).