Skip to content

Commit

Permalink
Remove dependency on rustfmt installation for consumers (#221)
Browse files Browse the repository at this point in the history
  • Loading branch information
mbrobbel authored Mar 17, 2023
1 parent ea94b94 commit 33832b9
Show file tree
Hide file tree
Showing 10 changed files with 88 additions and 27 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@

== Unreleased changes (release date TBD)

Breaking change: this release removes the `ToString` implementation for
`TypeSpace` and the `rustfmt-wrapper` dependency. This allows users to use a
pretty printing method of choice. Users can use the `ToTokens` implementation of
`TypeSpace`:

Before:
[source,rust]
----
let typespace = TypeSpace::default();
typespace.to_string()
----

After:
[source,rust]
----
let typespace = TypeSpace::default();
typespace.to_stream().to_string()
----

https://github.com/oxidecomputer/typify/compare/v0.0.10\...HEAD[Full list of commits]

* Allow per-type renames and derive macro applications (#131)
Expand Down
14 changes: 14 additions & 0 deletions Cargo.lock

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

63 changes: 47 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,18 @@
Typify compiles JSON Schema documents into Rust types. It can be used in one of
three ways:

- via the macro `import_types!("types.json")` to generate Rust types directly
in your program
- via the macro `import_types!("types.json")` to generate Rust types directly in
your program

- via a builder interface to generate Rust types in `build.rs`

- or via the builder functions to generate persistent files e.g. when building
API bindings.
API bindings.

## JSON Schema → Rust types

Typify translates JSON Schema types in a few different ways depending on some basic properties of the schema:
Typify translates JSON Schema types in a few different ways depending on some
basic properties of the schema:

### Built-in types

Expand All @@ -23,17 +24,17 @@ appropriate built-in type based on type attributes. For example, a JSON Schema
might specify a maximum and/or minimum that indicates the appropriate integral
type to use.

String schemas that include a `format` are represented with the appropriate
Rust type. For example `{ "type": "string", "format": "uuid" }` is represented
as a `uuid::Uuid` (which requires the `uuid` crate be included as a dependency).
String schemas that include a `format` are represented with the appropriate Rust
type. For example `{ "type": "string", "format": "uuid" }` is represented as a
`uuid::Uuid` (which requires the `uuid` crate be included as a dependency).

### Arrays

JSON Schema arrays can turn into one of three Rust types `Vec<T>`,
`HashSet<T>`, and tuples depending on the schema properties. An array may have
a fixed length that matches a fixed list of item types; this is well
represented by a Rust tuples. The distinction between `Vec<T>` and `HashSet<T>`
is only if the schema's `uniqueItems` field is `false` or `true` respectively.
JSON Schema arrays can turn into one of three Rust types `Vec<T>`, `HashSet<T>`,
and tuples depending on the schema properties. An array may have a fixed length
that matches a fixed list of item types; this is well represented by a Rust
tuples. The distinction between `Vec<T>` and `HashSet<T>` is only if the
schema's `uniqueItems` field is `false` or `true` respectively.

### Objects

Expand All @@ -49,14 +50,43 @@ simply get the `#[serde(default)]` attribute (so you won't see e.g.

### OneOf

The `OneOf` construct maps to a Rust enum. Typify maps this to the various [serde enum types](https://serde.rs/enum-representations.html).
The `OneOf` construct maps to a Rust enum. Typify maps this to the various
[serde enum types](https://serde.rs/enum-representations.html).

### AnyOf / AllOf

The `anyOf` and `allOf` constructs are a little trickier to handle, but (in
general) Typify models these as structs where each member is decorated with the
`#[serde(flatten)]` attribute (with `Option` wrappers in the case of `anyOf`).

## Formatting

By default Typify's generated code is not formatted. If formatted code is
preferred, crates like [rustfmt-wrapper](https://docs.rs/rustfmt-wrapper) and
[prettyplease](https://docs.rs/prettyplease) can be used to format the generated
code before writing it to a file.

The examples below show different ways to convert a `TypeSpace` to a string
(`typespace` is a `typify::TypeSpace`).

### No formatting

```rust
typespace.to_stream().to_string()
```

### Rustfmt

```rust
rustfmt_wrapper::rustfmt(typespace.to_stream().to_string())?
```

### Prettyplease

```rust
prettyplease::unparse(&syn::parse2::<syn::File>(typespace.to_stream())?)
```

## WIP

Typify is a work in progress. Changes that affect output will be indicated with
Expand All @@ -73,9 +103,9 @@ Bounded numbers aren't very well handled. Consider, for example, the schema:

```json
{
"type": "integer",
"minimum": 1,
"maximum": 6
"type": "integer",
"minimum": 1,
"maximum": 6
}
```

Expand All @@ -98,4 +128,5 @@ struct A {
a: Box<A>,
}
```

.. but it does not support more complex cycles such as A -> B -> A.
2 changes: 1 addition & 1 deletion cargo-typify/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ pub fn convert(args: &CliArgs) -> Result<String> {
use serde::{Deserialize, Serialize};
";

let contents = format!("{intro}\n{}", type_space.to_string());
let contents = format!("{intro}\n{}", type_space.to_stream().to_string());

let contents = rustfmt_wrapper::rustfmt(contents).wrap_err("Failed to format Rust code")?;

Expand Down
2 changes: 2 additions & 0 deletions example-build/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ serde = "1.0"
serde_json = "1.0.94"

[build-dependencies]
prettyplease = "0.1"
schemars = "0.8"
serde_json = "1.0.94"
syn = "1.0.109"
typify = { path = "../typify" }
2 changes: 1 addition & 1 deletion example-build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn main() {
let contents = format!(
"{}\n{}",
"use serde::{Deserialize, Serialize};",
type_space.to_string()
prettyplease::unparse(&syn::parse2::<syn::File>(type_space.to_stream()).unwrap())
);

let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf();
Expand Down
2 changes: 1 addition & 1 deletion typify-impl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ log = "0.4"
proc-macro2 = "1.0"
quote = "1.0"
regress = "0.5.0"
rustfmt-wrapper = "0.2"
schemars = "0.8.12"
serde_json = "1.0"
syn = { version = "1.0", features = ["full"] }
Expand All @@ -24,6 +23,7 @@ unicode-ident = "1.0.8"
[dev-dependencies]
expectorate = "1.0"
paste = "1.0"
rustfmt-wrapper = "0.2"
schema = "0.0.1"
schemars = { version = "0.8.12", features = ["uuid1"] }
serde = "1.0"
Expand Down
7 changes: 0 additions & 7 deletions typify-impl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use log::info;
use output::OutputSpace;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use rustfmt_wrapper::rustfmt;
use schemars::schema::{Metadata, Schema};
use thiserror::Error;
use type_entry::{
Expand Down Expand Up @@ -801,12 +800,6 @@ impl TypeSpace {
}
}

impl ToString for TypeSpace {
fn to_string(&self) -> String {
rustfmt(self.to_stream().to_string()).unwrap()
}
}

impl ToTokens for TypeSpace {
fn to_tokens(&self, tokens: &mut TokenStream) {
tokens.extend(self.to_stream())
Expand Down
2 changes: 2 additions & 0 deletions typify-test/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ serde_json = "1.0.94"

[build-dependencies]
ipnetwork = { version = "0.20.0", features = ["schemars"] }
prettyplease = "0.1"
schemars = "0.8.12"
serde = "1.0.155"
syn = "1.0.109"
typify = { path = "../typify" }
2 changes: 1 addition & 1 deletion typify-test/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fn main() {
let contents = format!(
"{}\n{}",
"use serde::{Deserialize, Serialize};",
type_space.to_string()
prettyplease::unparse(&syn::parse2::<syn::File>(type_space.to_stream()).unwrap())
);

let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf();
Expand Down

0 comments on commit 33832b9

Please sign in to comment.