Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "model" macro to simplify model definitions #625

Merged
merged 1 commit into from
Jan 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions workspaces/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions workspaces/deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ skip = [
{ name = "laika", licenses = [] },
{ name = "migration-helpers", licenses = [] },
{ name = "migrator", licenses = [] },
{ name = "model-derive", licenses = [] },
{ name = "models", licenses = [] },
{ name = "moondog", licenses = [] },
{ name = "netdog", licenses = [] },
Expand Down
1 change: 1 addition & 0 deletions workspaces/models/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ build = "build.rs"
[dependencies]
base64 = "0.11"
lazy_static = "1.2"
model-derive = { path = "model-derive" }
regex = "1.1"
serde = { version = "1.0", features = ["derive"] }
snafu = "0.6"
Expand Down
2 changes: 2 additions & 0 deletions workspaces/models/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ This `Settings` essentially becomes the schema for the variant's data store.

At the field level, standard Rust types can be used, or ["modeled types"](src/modeled_types) that add input validation.

The `#[model]` attribute on Settings and its sub-structs reduces duplication and adds some required metadata; see [its docs](model-derive/) for details.

### aws-k8s: Kubernetes

* [Model](src/aws-k8s/mod.rs)
Expand Down
20 changes: 20 additions & 0 deletions workspaces/models/model-derive/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "model-derive"
version = "0.1.0"
authors = ["Tom Kirchner <[email protected]>"]
edition = "2018"
publish = false
build = "build.rs"

[lib]
path = "src/lib.rs"
proc-macro = true

[dependencies]
darling = "0.10"
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "1.0", default-features = false, features = ["full", "parsing", "printing", "proc-macro", "visit-mut"] }

[build-dependencies]
cargo-readme = "3.1"
44 changes: 44 additions & 0 deletions workspaces/models/model-derive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# model-derive

Current version: 0.1.0

## Overview

This module provides a attribute-style procedural macro, `model`, that makes sure a struct is
ready to be used as an API model.

The goal is to reduce cognitive overhead when reading models.
We do this by automatically specifying required attributes on structs and fields.

Several arguments are available to override default behavior; see below.

## Changes it makes

### Visibility

All types must be public, so `pub` is added.
Override this (at a per-struct or per-field level) by specifying your own visibility.

### Derives

All structs must serde-`Serializable` and -`Deserializable`, and comparable via `PartialEq`.
`Debug` is added for convenience.
`Default` can also be added by specifying the argument `impl_default = true`.

### Serde

Structs have a `#[serde(...)]` attribute added to deny unknown fields and rename fields to kebab-case.
The struct can be renamed (for ser/de purposes) by specifying the argument `rename = "bla"`.

Fields have a `#[serde(...)]` attribute added to skip `Option` fields that are `None`.
This is because we accept updates in the API that are structured the same way as the model, but we don't want to require users to specify fields they aren't changing.
This can be disabled by specifying the argument `add_option = false`.

### Option

Fields are all wrapped in `Option<...>`.
Similar to the `serde` attribute added to fields, this is because we don't want users to have to specify fields they aren't changing, and can be disabled the same way, by specifying `add_option = false`.

## Colophon

This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.
9 changes: 9 additions & 0 deletions workspaces/models/model-derive/README.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# {{crate}}

Current version: {{version}}

{{readme}}

## Colophon

This text was generated from `README.tpl` using [cargo-readme](https://crates.io/crates/cargo-readme), and includes the rustdoc from `src/lib.rs`.
32 changes: 32 additions & 0 deletions workspaces/models/model-derive/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Automatically generate README.md from rustdoc.

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
// Check for environment variable "SKIP_README". If it is set,
// skip README generation
if env::var_os("SKIP_README").is_some() {
return;
}

let mut lib = File::open("src/lib.rs").unwrap();
let mut template = File::open("README.tpl").unwrap();

let content = cargo_readme::generate_readme(
&PathBuf::from("."), // root
&mut lib, // source
Some(&mut template), // template
// The "add x" arguments don't apply when using a template.
true, // add title
false, // add badges
false, // add license
true, // indent headings
)
.unwrap();

let mut readme = File::create("README.md").unwrap();
readme.write_all(content.as_bytes()).unwrap();
}
Loading