From 8be8037b930094ced7f7d8510369761c07c64bc6 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Wed, 15 Mar 2023 11:08:41 +0100 Subject: [PATCH 1/9] Add `rustfmt` and `prettyplease` features --- Cargo.lock | 11 + typify-impl/Cargo.toml | 10 +- typify-impl/src/lib.rs | 16 ++ typify-impl/tests/generator.out | 234 +--------------- typify-impl/tests/generator.prettyplease.out | 264 +++++++++++++++++++ typify-impl/tests/generator.rustfmt.out | 233 ++++++++++++++++ typify-impl/tests/test_generation.rs | 10 +- typify/Cargo.toml | 2 + 8 files changed, 545 insertions(+), 235 deletions(-) create mode 100644 typify-impl/tests/generator.prettyplease.out create mode 100644 typify-impl/tests/generator.rustfmt.out diff --git a/Cargo.lock b/Cargo.lock index 20fa1b83..19bc9c50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,6 +219,16 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.52" @@ -553,6 +563,7 @@ dependencies = [ "heck", "log", "paste", + "prettyplease", "proc-macro2", "quote", "regress", diff --git a/typify-impl/Cargo.toml b/typify-impl/Cargo.toml index 6faa81f1..0e2aa2c7 100644 --- a/typify-impl/Cargo.toml +++ b/typify-impl/Cargo.toml @@ -8,13 +8,19 @@ description = "typify backend implementation" repository = "https://github.com/oxidecomputer/typify" readme = "../README.md" +[features] +default = [] +rustfmt = ["dep:rustfmt-wrapper"] +prettyplease = ["dep:prettyplease"] + [dependencies] heck = "0.4.1" log = "0.4" +prettyplease = { version = "0.1", optional = true } proc-macro2 = "1.0" quote = "1.0" regress = "0.5.0" -rustfmt-wrapper = "0.2" +rustfmt-wrapper = { version = "0.2", optional = true } schemars = "0.8.12" serde_json = "1.0" syn = { version = "1.0", features = ["full"] } @@ -24,6 +30,8 @@ unicode-ident = "1.0.8" [dev-dependencies] expectorate = "1.0" paste = "1.0" +prettyplease = "0.1" +rustfmt-wrapper = "0.2" schema = "0.0.1" schemars = { version = "0.8.12", features = ["uuid1"] } serde = "1.0" diff --git a/typify-impl/src/lib.rs b/typify-impl/src/lib.rs index 5664f641..5452fb30 100644 --- a/typify-impl/src/lib.rs +++ b/typify-impl/src/lib.rs @@ -1,5 +1,8 @@ // Copyright 2023 Oxide Computer Company +#[cfg(all(feature = "rustfmt", feature = "prettyplease"))] +compile_error!("Either feature `rustfmt` or `prettyplease` can be enabled"); + use std::collections::{BTreeMap, BTreeSet}; use conversions::SchemaCache; @@ -7,6 +10,7 @@ use log::info; use output::OutputSpace; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; +#[cfg(feature = "rustfmt")] use rustfmt_wrapper::rustfmt; use schemars::schema::{Metadata, Schema}; use thiserror::Error; @@ -802,9 +806,21 @@ impl TypeSpace { } impl ToString for TypeSpace { + #[cfg(feature = "rustfmt")] fn to_string(&self) -> String { rustfmt(self.to_stream().to_string()).unwrap() } + + #[cfg(feature = "prettyplease")] + fn to_string(&self) -> String { + let file = syn::parse_file(&self.to_stream().to_string()).unwrap(); + prettyplease::unparse(&file) + } + + #[cfg(not(any(feature = "rustfmt", feature = "prettyplease")))] + fn to_string(&self) -> String { + self.to_stream().to_string() + } } impl ToTokens for TypeSpace { diff --git a/typify-impl/tests/generator.out b/typify-impl/tests/generator.out index 41f8e2b4..05113413 100644 --- a/typify-impl/tests/generator.out +++ b/typify-impl/tests/generator.out @@ -1,233 +1 @@ -mod types { - #[derive( - Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, - )] - pub struct AllTheTraits { - pub ok: String, - } - impl From<&AllTheTraits> for AllTheTraits { - fn from(value: &AllTheTraits) -> Self { - value.clone() - } - } - impl AllTheTraits { - pub fn builder() -> builder::AllTheTraits { - builder::AllTheTraits::default() - } - } - #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] - pub struct CompoundType { - pub value1: String, - pub value2: u64, - } - impl From<&CompoundType> for CompoundType { - fn from(value: &CompoundType) -> Self { - value.clone() - } - } - impl CompoundType { - pub fn builder() -> builder::CompoundType { - builder::CompoundType::default() - } - } - #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] - pub struct Pair { - #[serde(default = "defaults::pair_a")] - pub a: StringEnum, - #[serde(default = "defaults::pair_b")] - pub b: StringEnum, - } - impl From<&Pair> for Pair { - fn from(value: &Pair) -> Self { - value.clone() - } - } - impl Pair { - pub fn builder() -> builder::Pair { - builder::Pair::default() - } - } - #[derive( - Clone, Copy, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, - )] - pub enum StringEnum { - One, - Two, - BuckleMyShoe, - } - impl From<&StringEnum> for StringEnum { - fn from(value: &StringEnum) -> Self { - value.clone() - } - } - impl ToString for StringEnum { - fn to_string(&self) -> String { - match *self { - Self::One => "One".to_string(), - Self::Two => "Two".to_string(), - Self::BuckleMyShoe => "BuckleMyShoe".to_string(), - } - } - } - impl std::str::FromStr for StringEnum { - type Err = &'static str; - fn from_str(value: &str) -> Result { - match value { - "One" => Ok(Self::One), - "Two" => Ok(Self::Two), - "BuckleMyShoe" => Ok(Self::BuckleMyShoe), - _ => Err("invalid value"), - } - } - } - impl std::convert::TryFrom<&str> for StringEnum { - type Error = &'static str; - fn try_from(value: &str) -> Result { - value.parse() - } - } - impl std::convert::TryFrom<&String> for StringEnum { - type Error = &'static str; - fn try_from(value: &String) -> Result { - value.parse() - } - } - impl std::convert::TryFrom for StringEnum { - type Error = &'static str; - fn try_from(value: String) -> Result { - value.parse() - } - } - mod builder { - pub struct AllTheTraits { - ok: Result, - } - impl Default for AllTheTraits { - fn default() -> Self { - Self { - ok: Err("no value supplied for ok".to_string()), - } - } - } - impl AllTheTraits { - pub fn ok(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.ok = value - .try_into() - .map_err(|e| format!("error converting supplied value for ok: {}", e)); - self - } - } - impl std::convert::TryFrom for super::AllTheTraits { - type Error = String; - fn try_from(value: AllTheTraits) -> Result { - Ok(Self { ok: value.ok? }) - } - } - pub struct CompoundType { - value1: Result, - value2: Result, - } - impl Default for CompoundType { - fn default() -> Self { - Self { - value1: Err("no value supplied for value1".to_string()), - value2: Err("no value supplied for value2".to_string()), - } - } - } - impl CompoundType { - pub fn value1(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.value1 = value - .try_into() - .map_err(|e| format!("error converting supplied value for value1: {}", e)); - self - } - pub fn value2(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.value2 = value - .try_into() - .map_err(|e| format!("error converting supplied value for value2: {}", e)); - self - } - } - impl std::convert::TryFrom for super::CompoundType { - type Error = String; - fn try_from(value: CompoundType) -> Result { - Ok(Self { - value1: value.value1?, - value2: value.value2?, - }) - } - } - pub struct Pair { - a: Result, - b: Result, - } - impl Default for Pair { - fn default() -> Self { - Self { - a: Ok(super::defaults::pair_a()), - b: Ok(super::defaults::pair_b()), - } - } - } - impl Pair { - pub fn a(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.a = value - .try_into() - .map_err(|e| format!("error converting supplied value for a: {}", e)); - self - } - pub fn b(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.b = value - .try_into() - .map_err(|e| format!("error converting supplied value for b: {}", e)); - self - } - } - impl std::convert::TryFrom for super::Pair { - type Error = String; - fn try_from(value: Pair) -> Result { - Ok(Self { - a: value.a?, - b: value.b?, - }) - } - } - } - mod defaults { - pub(super) fn pair_a() -> super::StringEnum { - super::StringEnum::One - } - pub(super) fn pair_b() -> super::StringEnum { - super::StringEnum::Two - } - } -} -pub fn do_stuff( - body: &types::CompoundType, - string: &str, - opt_int: Option, - strenum: types::StringEnum, -) -> types::CompoundType { - todo!() -} +mod types { # [derive (Clone , Debug , Deserialize , Eq , Hash , JsonSchema , Ord , PartialEq , PartialOrd , Serialize)] pub struct AllTheTraits { pub ok : String , } impl From < & AllTheTraits > for AllTheTraits { fn from (value : & AllTheTraits) -> Self { value . clone () } } impl AllTheTraits { pub fn builder () -> builder :: AllTheTraits { builder :: AllTheTraits :: default () } } # [derive (Clone , Debug , Deserialize , JsonSchema , Serialize)] pub struct CompoundType { pub value1 : String , pub value2 : u64 , } impl From < & CompoundType > for CompoundType { fn from (value : & CompoundType) -> Self { value . clone () } } impl CompoundType { pub fn builder () -> builder :: CompoundType { builder :: CompoundType :: default () } } # [derive (Clone , Debug , Deserialize , JsonSchema , Serialize)] pub struct Pair { # [serde (default = "defaults::pair_a")] pub a : StringEnum , # [serde (default = "defaults::pair_b")] pub b : StringEnum , } impl From < & Pair > for Pair { fn from (value : & Pair) -> Self { value . clone () } } impl Pair { pub fn builder () -> builder :: Pair { builder :: Pair :: default () } } # [derive (Clone , Copy , Debug , Deserialize , Eq , Hash , JsonSchema , Ord , PartialEq , PartialOrd , Serialize)] pub enum StringEnum { One , Two , BuckleMyShoe , } impl From < & StringEnum > for StringEnum { fn from (value : & StringEnum) -> Self { value . clone () } } impl ToString for StringEnum { fn to_string (& self) -> String { match * self { Self :: One => "One" . to_string () , Self :: Two => "Two" . to_string () , Self :: BuckleMyShoe => "BuckleMyShoe" . to_string () , } } } impl std :: str :: FromStr for StringEnum { type Err = & 'static str ; fn from_str (value : & str) -> Result < Self , & 'static str > { match value { "One" => Ok (Self :: One) , "Two" => Ok (Self :: Two) , "BuckleMyShoe" => Ok (Self :: BuckleMyShoe) , _ => Err ("invalid value") , } } } impl std :: convert :: TryFrom < & str > for StringEnum { type Error = & 'static str ; fn try_from (value : & str) -> Result < Self , & 'static str > { value . parse () } } impl std :: convert :: TryFrom < & String > for StringEnum { type Error = & 'static str ; fn try_from (value : & String) -> Result < Self , & 'static str > { value . parse () } } impl std :: convert :: TryFrom < String > for StringEnum { type Error = & 'static str ; fn try_from (value : String) -> Result < Self , & 'static str > { value . parse () } } mod builder { pub struct AllTheTraits { ok : Result < String , String > , } impl Default for AllTheTraits { fn default () -> Self { Self { ok : Err ("no value supplied for ok" . to_string ()) , } } } impl AllTheTraits { pub fn ok < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < String > , T :: Error : std :: fmt :: Display , { self . ok = value . try_into () . map_err (| e | format ! ("error converting supplied value for ok: {}" , e)) ; self } } impl std :: convert :: TryFrom < AllTheTraits > for super :: AllTheTraits { type Error = String ; fn try_from (value : AllTheTraits) -> Result < Self , String > { Ok (Self { ok : value . ok ? , }) } } pub struct CompoundType { value1 : Result < String , String > , value2 : Result < u64 , String > , } impl Default for CompoundType { fn default () -> Self { Self { value1 : Err ("no value supplied for value1" . to_string ()) , value2 : Err ("no value supplied for value2" . to_string ()) , } } } impl CompoundType { pub fn value1 < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < String > , T :: Error : std :: fmt :: Display , { self . value1 = value . try_into () . map_err (| e | format ! ("error converting supplied value for value1: {}" , e)) ; self } pub fn value2 < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < u64 > , T :: Error : std :: fmt :: Display , { self . value2 = value . try_into () . map_err (| e | format ! ("error converting supplied value for value2: {}" , e)) ; self } } impl std :: convert :: TryFrom < CompoundType > for super :: CompoundType { type Error = String ; fn try_from (value : CompoundType) -> Result < Self , String > { Ok (Self { value1 : value . value1 ? , value2 : value . value2 ? , }) } } pub struct Pair { a : Result < super :: StringEnum , String > , b : Result < super :: StringEnum , String > , } impl Default for Pair { fn default () -> Self { Self { a : Ok (super :: defaults :: pair_a ()) , b : Ok (super :: defaults :: pair_b ()) , } } } impl Pair { pub fn a < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < super :: StringEnum > , T :: Error : std :: fmt :: Display , { self . a = value . try_into () . map_err (| e | format ! ("error converting supplied value for a: {}" , e)) ; self } pub fn b < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < super :: StringEnum > , T :: Error : std :: fmt :: Display , { self . b = value . try_into () . map_err (| e | format ! ("error converting supplied value for b: {}" , e)) ; self } } impl std :: convert :: TryFrom < Pair > for super :: Pair { type Error = String ; fn try_from (value : Pair) -> Result < Self , String > { Ok (Self { a : value . a ? , b : value . b ? , }) } } } mod defaults { pub (super) fn pair_a () -> super :: StringEnum { super :: StringEnum :: One } pub (super) fn pair_b () -> super :: StringEnum { super :: StringEnum :: Two } } } pub fn do_stuff (body : & types :: CompoundType , string : & str , opt_int : Option < u32 > , strenum : types :: StringEnum ,) -> types :: CompoundType { todo ! () } \ No newline at end of file diff --git a/typify-impl/tests/generator.prettyplease.out b/typify-impl/tests/generator.prettyplease.out new file mode 100644 index 00000000..2db49914 --- /dev/null +++ b/typify-impl/tests/generator.prettyplease.out @@ -0,0 +1,264 @@ +mod types { + #[derive( + Clone, + Debug, + Deserialize, + Eq, + Hash, + JsonSchema, + Ord, + PartialEq, + PartialOrd, + Serialize + )] + pub struct AllTheTraits { + pub ok: String, + } + impl From<&AllTheTraits> for AllTheTraits { + fn from(value: &AllTheTraits) -> Self { + value.clone() + } + } + impl AllTheTraits { + pub fn builder() -> builder::AllTheTraits { + builder::AllTheTraits::default() + } + } + #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] + pub struct CompoundType { + pub value1: String, + pub value2: u64, + } + impl From<&CompoundType> for CompoundType { + fn from(value: &CompoundType) -> Self { + value.clone() + } + } + impl CompoundType { + pub fn builder() -> builder::CompoundType { + builder::CompoundType::default() + } + } + #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] + pub struct Pair { + #[serde(default = "defaults::pair_a")] + pub a: StringEnum, + #[serde(default = "defaults::pair_b")] + pub b: StringEnum, + } + impl From<&Pair> for Pair { + fn from(value: &Pair) -> Self { + value.clone() + } + } + impl Pair { + pub fn builder() -> builder::Pair { + builder::Pair::default() + } + } + #[derive( + Clone, + Copy, + Debug, + Deserialize, + Eq, + Hash, + JsonSchema, + Ord, + PartialEq, + PartialOrd, + Serialize + )] + pub enum StringEnum { + One, + Two, + BuckleMyShoe, + } + impl From<&StringEnum> for StringEnum { + fn from(value: &StringEnum) -> Self { + value.clone() + } + } + impl ToString for StringEnum { + fn to_string(&self) -> String { + match *self { + Self::One => "One".to_string(), + Self::Two => "Two".to_string(), + Self::BuckleMyShoe => "BuckleMyShoe".to_string(), + } + } + } + impl std::str::FromStr for StringEnum { + type Err = &'static str; + fn from_str(value: &str) -> Result { + match value { + "One" => Ok(Self::One), + "Two" => Ok(Self::Two), + "BuckleMyShoe" => Ok(Self::BuckleMyShoe), + _ => Err("invalid value"), + } + } + } + impl std::convert::TryFrom<&str> for StringEnum { + type Error = &'static str; + fn try_from(value: &str) -> Result { + value.parse() + } + } + impl std::convert::TryFrom<&String> for StringEnum { + type Error = &'static str; + fn try_from(value: &String) -> Result { + value.parse() + } + } + impl std::convert::TryFrom for StringEnum { + type Error = &'static str; + fn try_from(value: String) -> Result { + value.parse() + } + } + mod builder { + pub struct AllTheTraits { + ok: Result, + } + impl Default for AllTheTraits { + fn default() -> Self { + Self { + ok: Err("no value supplied for ok".to_string()), + } + } + } + impl AllTheTraits { + pub fn ok(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self + .ok = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for ok: {}", e) + }); + self + } + } + impl std::convert::TryFrom for super::AllTheTraits { + type Error = String; + fn try_from(value: AllTheTraits) -> Result { + Ok(Self { ok: value.ok? }) + } + } + pub struct CompoundType { + value1: Result, + value2: Result, + } + impl Default for CompoundType { + fn default() -> Self { + Self { + value1: Err("no value supplied for value1".to_string()), + value2: Err("no value supplied for value2".to_string()), + } + } + } + impl CompoundType { + pub fn value1(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self + .value1 = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for value1: {}", e) + }); + self + } + pub fn value2(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self + .value2 = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for value2: {}", e) + }); + self + } + } + impl std::convert::TryFrom for super::CompoundType { + type Error = String; + fn try_from(value: CompoundType) -> Result { + Ok(Self { + value1: value.value1?, + value2: value.value2?, + }) + } + } + pub struct Pair { + a: Result, + b: Result, + } + impl Default for Pair { + fn default() -> Self { + Self { + a: Ok(super::defaults::pair_a()), + b: Ok(super::defaults::pair_b()), + } + } + } + impl Pair { + pub fn a(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self + .a = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for a: {}", e) + }); + self + } + pub fn b(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self + .b = value + .try_into() + .map_err(|e| { + format!("error converting supplied value for b: {}", e) + }); + self + } + } + impl std::convert::TryFrom for super::Pair { + type Error = String; + fn try_from(value: Pair) -> Result { + Ok(Self { a: value.a?, b: value.b? }) + } + } + } + mod defaults { + pub(super) fn pair_a() -> super::StringEnum { + super::StringEnum::One + } + pub(super) fn pair_b() -> super::StringEnum { + super::StringEnum::Two + } + } +} +pub fn do_stuff( + body: &types::CompoundType, + string: &str, + opt_int: Option, + strenum: types::StringEnum, +) -> types::CompoundType { + todo!() +} diff --git a/typify-impl/tests/generator.rustfmt.out b/typify-impl/tests/generator.rustfmt.out new file mode 100644 index 00000000..41f8e2b4 --- /dev/null +++ b/typify-impl/tests/generator.rustfmt.out @@ -0,0 +1,233 @@ +mod types { + #[derive( + Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, + )] + pub struct AllTheTraits { + pub ok: String, + } + impl From<&AllTheTraits> for AllTheTraits { + fn from(value: &AllTheTraits) -> Self { + value.clone() + } + } + impl AllTheTraits { + pub fn builder() -> builder::AllTheTraits { + builder::AllTheTraits::default() + } + } + #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] + pub struct CompoundType { + pub value1: String, + pub value2: u64, + } + impl From<&CompoundType> for CompoundType { + fn from(value: &CompoundType) -> Self { + value.clone() + } + } + impl CompoundType { + pub fn builder() -> builder::CompoundType { + builder::CompoundType::default() + } + } + #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] + pub struct Pair { + #[serde(default = "defaults::pair_a")] + pub a: StringEnum, + #[serde(default = "defaults::pair_b")] + pub b: StringEnum, + } + impl From<&Pair> for Pair { + fn from(value: &Pair) -> Self { + value.clone() + } + } + impl Pair { + pub fn builder() -> builder::Pair { + builder::Pair::default() + } + } + #[derive( + Clone, Copy, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, + )] + pub enum StringEnum { + One, + Two, + BuckleMyShoe, + } + impl From<&StringEnum> for StringEnum { + fn from(value: &StringEnum) -> Self { + value.clone() + } + } + impl ToString for StringEnum { + fn to_string(&self) -> String { + match *self { + Self::One => "One".to_string(), + Self::Two => "Two".to_string(), + Self::BuckleMyShoe => "BuckleMyShoe".to_string(), + } + } + } + impl std::str::FromStr for StringEnum { + type Err = &'static str; + fn from_str(value: &str) -> Result { + match value { + "One" => Ok(Self::One), + "Two" => Ok(Self::Two), + "BuckleMyShoe" => Ok(Self::BuckleMyShoe), + _ => Err("invalid value"), + } + } + } + impl std::convert::TryFrom<&str> for StringEnum { + type Error = &'static str; + fn try_from(value: &str) -> Result { + value.parse() + } + } + impl std::convert::TryFrom<&String> for StringEnum { + type Error = &'static str; + fn try_from(value: &String) -> Result { + value.parse() + } + } + impl std::convert::TryFrom for StringEnum { + type Error = &'static str; + fn try_from(value: String) -> Result { + value.parse() + } + } + mod builder { + pub struct AllTheTraits { + ok: Result, + } + impl Default for AllTheTraits { + fn default() -> Self { + Self { + ok: Err("no value supplied for ok".to_string()), + } + } + } + impl AllTheTraits { + pub fn ok(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.ok = value + .try_into() + .map_err(|e| format!("error converting supplied value for ok: {}", e)); + self + } + } + impl std::convert::TryFrom for super::AllTheTraits { + type Error = String; + fn try_from(value: AllTheTraits) -> Result { + Ok(Self { ok: value.ok? }) + } + } + pub struct CompoundType { + value1: Result, + value2: Result, + } + impl Default for CompoundType { + fn default() -> Self { + Self { + value1: Err("no value supplied for value1".to_string()), + value2: Err("no value supplied for value2".to_string()), + } + } + } + impl CompoundType { + pub fn value1(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.value1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for value1: {}", e)); + self + } + pub fn value2(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.value2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for value2: {}", e)); + self + } + } + impl std::convert::TryFrom for super::CompoundType { + type Error = String; + fn try_from(value: CompoundType) -> Result { + Ok(Self { + value1: value.value1?, + value2: value.value2?, + }) + } + } + pub struct Pair { + a: Result, + b: Result, + } + impl Default for Pair { + fn default() -> Self { + Self { + a: Ok(super::defaults::pair_a()), + b: Ok(super::defaults::pair_b()), + } + } + } + impl Pair { + pub fn a(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.a = value + .try_into() + .map_err(|e| format!("error converting supplied value for a: {}", e)); + self + } + pub fn b(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.b = value + .try_into() + .map_err(|e| format!("error converting supplied value for b: {}", e)); + self + } + } + impl std::convert::TryFrom for super::Pair { + type Error = String; + fn try_from(value: Pair) -> Result { + Ok(Self { + a: value.a?, + b: value.b?, + }) + } + } + } + mod defaults { + pub(super) fn pair_a() -> super::StringEnum { + super::StringEnum::One + } + pub(super) fn pair_b() -> super::StringEnum { + super::StringEnum::Two + } + } +} +pub fn do_stuff( + body: &types::CompoundType, + string: &str, + opt_int: Option, + strenum: types::StringEnum, +) -> types::CompoundType { + todo!() +} diff --git a/typify-impl/tests/test_generation.rs b/typify-impl/tests/test_generation.rs index 64394a63..1483c9c0 100644 --- a/typify-impl/tests/test_generation.rs +++ b/typify-impl/tests/test_generation.rs @@ -108,7 +108,15 @@ fn test_generation() { } }; - let fmt = rustfmt_wrapper::rustfmt(file.to_string()).unwrap(); + let fmt = file.to_string(); expectorate::assert_contents("tests/generator.out", fmt.as_str()); + + let fmt = rustfmt_wrapper::rustfmt(file.to_string()).unwrap(); + + expectorate::assert_contents("tests/generator.rustfmt.out", fmt.as_str()); + + let fmt = prettyplease::unparse(&syn::parse_file(&file.to_string()).unwrap()); + + expectorate::assert_contents("tests/generator.prettyplease.out", fmt.as_str()); } diff --git a/typify/Cargo.toml b/typify/Cargo.toml index 96ca2c81..9f7e51d9 100644 --- a/typify/Cargo.toml +++ b/typify/Cargo.toml @@ -13,6 +13,8 @@ categories = ["api-bindings", "compilers"] [features] default = ["macro"] macro = ["typify-macro"] +prettyplease = ["typify-impl/prettyplease"] +rustfmt = ["typify-impl/rustfmt"] [dependencies] typify-macro = { version = "0.0.11-dev", path = "../typify-macro", optional = true } From cced30119c1b4da39f5c62d0d0b9712d539affe8 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Wed, 15 Mar 2023 21:07:41 +0100 Subject: [PATCH 2/9] Remove impl `ToString` for `TypeSpace` and `rustfmt-wrapper` dependency --- Cargo.lock | 4 ++++ example-build/Cargo.toml | 2 ++ example-build/build.rs | 2 +- typify-impl/Cargo.toml | 7 ------- typify-impl/src/lib.rs | 23 ----------------------- typify-impl/tests/test_generation.rs | 2 +- typify-test/Cargo.toml | 2 ++ typify-test/build.rs | 2 +- typify/Cargo.toml | 2 -- 9 files changed, 11 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19bc9c50..e2354358 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,9 +72,11 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" name = "example-build" version = "0.0.0" dependencies = [ + "prettyplease", "schemars", "serde", "serde_json", + "syn", "typify", ] @@ -597,10 +599,12 @@ name = "typify-test" version = "0.0.0" dependencies = [ "ipnetwork", + "prettyplease", "regress", "schemars", "serde", "serde_json", + "syn", "typify", ] diff --git a/example-build/Cargo.toml b/example-build/Cargo.toml index 751c54b0..d08c92c6 100644 --- a/example-build/Cargo.toml +++ b/example-build/Cargo.toml @@ -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" typify = { path = "../typify" } diff --git a/example-build/build.rs b/example-build/build.rs index c24415b1..71af1b93 100644 --- a/example-build/build.rs +++ b/example-build/build.rs @@ -18,7 +18,7 @@ fn main() { let contents = format!( "{}\n{}", "use serde::{Deserialize, Serialize};", - type_space.to_string() + prettyplease::unparse(&syn::parse2::(type_space.to_stream()).unwrap()) ); let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf(); diff --git a/typify-impl/Cargo.toml b/typify-impl/Cargo.toml index 0e2aa2c7..12a04222 100644 --- a/typify-impl/Cargo.toml +++ b/typify-impl/Cargo.toml @@ -8,19 +8,12 @@ description = "typify backend implementation" repository = "https://github.com/oxidecomputer/typify" readme = "../README.md" -[features] -default = [] -rustfmt = ["dep:rustfmt-wrapper"] -prettyplease = ["dep:prettyplease"] - [dependencies] heck = "0.4.1" log = "0.4" -prettyplease = { version = "0.1", optional = true } proc-macro2 = "1.0" quote = "1.0" regress = "0.5.0" -rustfmt-wrapper = { version = "0.2", optional = true } schemars = "0.8.12" serde_json = "1.0" syn = { version = "1.0", features = ["full"] } diff --git a/typify-impl/src/lib.rs b/typify-impl/src/lib.rs index 5452fb30..25329df2 100644 --- a/typify-impl/src/lib.rs +++ b/typify-impl/src/lib.rs @@ -1,8 +1,5 @@ // Copyright 2023 Oxide Computer Company -#[cfg(all(feature = "rustfmt", feature = "prettyplease"))] -compile_error!("Either feature `rustfmt` or `prettyplease` can be enabled"); - use std::collections::{BTreeMap, BTreeSet}; use conversions::SchemaCache; @@ -10,8 +7,6 @@ use log::info; use output::OutputSpace; use proc_macro2::TokenStream; use quote::{quote, ToTokens}; -#[cfg(feature = "rustfmt")] -use rustfmt_wrapper::rustfmt; use schemars::schema::{Metadata, Schema}; use thiserror::Error; use type_entry::{ @@ -805,24 +800,6 @@ impl TypeSpace { } } -impl ToString for TypeSpace { - #[cfg(feature = "rustfmt")] - fn to_string(&self) -> String { - rustfmt(self.to_stream().to_string()).unwrap() - } - - #[cfg(feature = "prettyplease")] - fn to_string(&self) -> String { - let file = syn::parse_file(&self.to_stream().to_string()).unwrap(); - prettyplease::unparse(&file) - } - - #[cfg(not(any(feature = "rustfmt", feature = "prettyplease")))] - fn to_string(&self) -> String { - self.to_stream().to_string() - } -} - impl ToTokens for TypeSpace { fn to_tokens(&self, tokens: &mut TokenStream) { tokens.extend(self.to_stream()) diff --git a/typify-impl/tests/test_generation.rs b/typify-impl/tests/test_generation.rs index 1483c9c0..408d35e6 100644 --- a/typify-impl/tests/test_generation.rs +++ b/typify-impl/tests/test_generation.rs @@ -116,7 +116,7 @@ fn test_generation() { expectorate::assert_contents("tests/generator.rustfmt.out", fmt.as_str()); - let fmt = prettyplease::unparse(&syn::parse_file(&file.to_string()).unwrap()); + let fmt = prettyplease::unparse(&syn::parse2::(file).unwrap()); expectorate::assert_contents("tests/generator.prettyplease.out", fmt.as_str()); } diff --git a/typify-test/Cargo.toml b/typify-test/Cargo.toml index fda2b3c4..9b49c82b 100644 --- a/typify-test/Cargo.toml +++ b/typify-test/Cargo.toml @@ -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" typify = { path = "../typify" } diff --git a/typify-test/build.rs b/typify-test/build.rs index 20a34e89..1933770e 100644 --- a/typify-test/build.rs +++ b/typify-test/build.rs @@ -109,7 +109,7 @@ fn main() { let contents = format!( "{}\n{}", "use serde::{Deserialize, Serialize};", - type_space.to_string() + prettyplease::unparse(&syn::parse2::(type_space.to_stream()).unwrap()) ); let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf(); diff --git a/typify/Cargo.toml b/typify/Cargo.toml index 9f7e51d9..96ca2c81 100644 --- a/typify/Cargo.toml +++ b/typify/Cargo.toml @@ -13,8 +13,6 @@ categories = ["api-bindings", "compilers"] [features] default = ["macro"] macro = ["typify-macro"] -prettyplease = ["typify-impl/prettyplease"] -rustfmt = ["typify-impl/rustfmt"] [dependencies] typify-macro = { version = "0.0.11-dev", path = "../typify-macro", optional = true } From 103506e7b455cacc855d5fd728d5068c95c4363c Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 16 Mar 2023 09:17:16 +0100 Subject: [PATCH 3/9] Use `rustfmt` instead of `prettyplease` --- Cargo.lock | 15 +- example-build/Cargo.toml | 2 +- example-build/build.rs | 2 +- typify-impl/Cargo.toml | 1 - typify-impl/tests/generator.out | 234 +++++++++++++++- typify-impl/tests/generator.prettyplease.out | 264 ------------------- typify-impl/tests/generator.rustfmt.out | 233 ---------------- typify-impl/tests/test_generation.rs | 8 - typify-test/Cargo.toml | 2 +- typify-test/build.rs | 2 +- 10 files changed, 239 insertions(+), 524 deletions(-) delete mode 100644 typify-impl/tests/generator.prettyplease.out delete mode 100644 typify-impl/tests/generator.rustfmt.out diff --git a/Cargo.lock b/Cargo.lock index e2354358..20e0d117 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -72,7 +72,7 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" name = "example-build" version = "0.0.0" dependencies = [ - "prettyplease", + "rustfmt-wrapper", "schemars", "serde", "serde_json", @@ -221,16 +221,6 @@ dependencies = [ "ucd-trie", ] -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "proc-macro2" version = "1.0.52" @@ -565,7 +555,6 @@ dependencies = [ "heck", "log", "paste", - "prettyplease", "proc-macro2", "quote", "regress", @@ -599,8 +588,8 @@ name = "typify-test" version = "0.0.0" dependencies = [ "ipnetwork", - "prettyplease", "regress", + "rustfmt-wrapper", "schemars", "serde", "serde_json", diff --git a/example-build/Cargo.toml b/example-build/Cargo.toml index d08c92c6..25ec0f7c 100644 --- a/example-build/Cargo.toml +++ b/example-build/Cargo.toml @@ -9,7 +9,7 @@ serde = "1.0" serde_json = "1.0.94" [build-dependencies] -prettyplease = "0.1" +rustfmt-wrapper = "0.2" schemars = "0.8" serde_json = "1.0.94" syn = "1" diff --git a/example-build/build.rs b/example-build/build.rs index 71af1b93..1e2e4374 100644 --- a/example-build/build.rs +++ b/example-build/build.rs @@ -18,7 +18,7 @@ fn main() { let contents = format!( "{}\n{}", "use serde::{Deserialize, Serialize};", - prettyplease::unparse(&syn::parse2::(type_space.to_stream()).unwrap()) + rustfmt_wrapper::rustfmt(type_space.to_stream().to_string()).unwrap() ); let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf(); diff --git a/typify-impl/Cargo.toml b/typify-impl/Cargo.toml index 12a04222..3be01342 100644 --- a/typify-impl/Cargo.toml +++ b/typify-impl/Cargo.toml @@ -23,7 +23,6 @@ unicode-ident = "1.0.8" [dev-dependencies] expectorate = "1.0" paste = "1.0" -prettyplease = "0.1" rustfmt-wrapper = "0.2" schema = "0.0.1" schemars = { version = "0.8.12", features = ["uuid1"] } diff --git a/typify-impl/tests/generator.out b/typify-impl/tests/generator.out index 05113413..41f8e2b4 100644 --- a/typify-impl/tests/generator.out +++ b/typify-impl/tests/generator.out @@ -1 +1,233 @@ -mod types { # [derive (Clone , Debug , Deserialize , Eq , Hash , JsonSchema , Ord , PartialEq , PartialOrd , Serialize)] pub struct AllTheTraits { pub ok : String , } impl From < & AllTheTraits > for AllTheTraits { fn from (value : & AllTheTraits) -> Self { value . clone () } } impl AllTheTraits { pub fn builder () -> builder :: AllTheTraits { builder :: AllTheTraits :: default () } } # [derive (Clone , Debug , Deserialize , JsonSchema , Serialize)] pub struct CompoundType { pub value1 : String , pub value2 : u64 , } impl From < & CompoundType > for CompoundType { fn from (value : & CompoundType) -> Self { value . clone () } } impl CompoundType { pub fn builder () -> builder :: CompoundType { builder :: CompoundType :: default () } } # [derive (Clone , Debug , Deserialize , JsonSchema , Serialize)] pub struct Pair { # [serde (default = "defaults::pair_a")] pub a : StringEnum , # [serde (default = "defaults::pair_b")] pub b : StringEnum , } impl From < & Pair > for Pair { fn from (value : & Pair) -> Self { value . clone () } } impl Pair { pub fn builder () -> builder :: Pair { builder :: Pair :: default () } } # [derive (Clone , Copy , Debug , Deserialize , Eq , Hash , JsonSchema , Ord , PartialEq , PartialOrd , Serialize)] pub enum StringEnum { One , Two , BuckleMyShoe , } impl From < & StringEnum > for StringEnum { fn from (value : & StringEnum) -> Self { value . clone () } } impl ToString for StringEnum { fn to_string (& self) -> String { match * self { Self :: One => "One" . to_string () , Self :: Two => "Two" . to_string () , Self :: BuckleMyShoe => "BuckleMyShoe" . to_string () , } } } impl std :: str :: FromStr for StringEnum { type Err = & 'static str ; fn from_str (value : & str) -> Result < Self , & 'static str > { match value { "One" => Ok (Self :: One) , "Two" => Ok (Self :: Two) , "BuckleMyShoe" => Ok (Self :: BuckleMyShoe) , _ => Err ("invalid value") , } } } impl std :: convert :: TryFrom < & str > for StringEnum { type Error = & 'static str ; fn try_from (value : & str) -> Result < Self , & 'static str > { value . parse () } } impl std :: convert :: TryFrom < & String > for StringEnum { type Error = & 'static str ; fn try_from (value : & String) -> Result < Self , & 'static str > { value . parse () } } impl std :: convert :: TryFrom < String > for StringEnum { type Error = & 'static str ; fn try_from (value : String) -> Result < Self , & 'static str > { value . parse () } } mod builder { pub struct AllTheTraits { ok : Result < String , String > , } impl Default for AllTheTraits { fn default () -> Self { Self { ok : Err ("no value supplied for ok" . to_string ()) , } } } impl AllTheTraits { pub fn ok < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < String > , T :: Error : std :: fmt :: Display , { self . ok = value . try_into () . map_err (| e | format ! ("error converting supplied value for ok: {}" , e)) ; self } } impl std :: convert :: TryFrom < AllTheTraits > for super :: AllTheTraits { type Error = String ; fn try_from (value : AllTheTraits) -> Result < Self , String > { Ok (Self { ok : value . ok ? , }) } } pub struct CompoundType { value1 : Result < String , String > , value2 : Result < u64 , String > , } impl Default for CompoundType { fn default () -> Self { Self { value1 : Err ("no value supplied for value1" . to_string ()) , value2 : Err ("no value supplied for value2" . to_string ()) , } } } impl CompoundType { pub fn value1 < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < String > , T :: Error : std :: fmt :: Display , { self . value1 = value . try_into () . map_err (| e | format ! ("error converting supplied value for value1: {}" , e)) ; self } pub fn value2 < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < u64 > , T :: Error : std :: fmt :: Display , { self . value2 = value . try_into () . map_err (| e | format ! ("error converting supplied value for value2: {}" , e)) ; self } } impl std :: convert :: TryFrom < CompoundType > for super :: CompoundType { type Error = String ; fn try_from (value : CompoundType) -> Result < Self , String > { Ok (Self { value1 : value . value1 ? , value2 : value . value2 ? , }) } } pub struct Pair { a : Result < super :: StringEnum , String > , b : Result < super :: StringEnum , String > , } impl Default for Pair { fn default () -> Self { Self { a : Ok (super :: defaults :: pair_a ()) , b : Ok (super :: defaults :: pair_b ()) , } } } impl Pair { pub fn a < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < super :: StringEnum > , T :: Error : std :: fmt :: Display , { self . a = value . try_into () . map_err (| e | format ! ("error converting supplied value for a: {}" , e)) ; self } pub fn b < T > (mut self , value : T) -> Self where T : std :: convert :: TryInto < super :: StringEnum > , T :: Error : std :: fmt :: Display , { self . b = value . try_into () . map_err (| e | format ! ("error converting supplied value for b: {}" , e)) ; self } } impl std :: convert :: TryFrom < Pair > for super :: Pair { type Error = String ; fn try_from (value : Pair) -> Result < Self , String > { Ok (Self { a : value . a ? , b : value . b ? , }) } } } mod defaults { pub (super) fn pair_a () -> super :: StringEnum { super :: StringEnum :: One } pub (super) fn pair_b () -> super :: StringEnum { super :: StringEnum :: Two } } } pub fn do_stuff (body : & types :: CompoundType , string : & str , opt_int : Option < u32 > , strenum : types :: StringEnum ,) -> types :: CompoundType { todo ! () } \ No newline at end of file +mod types { + #[derive( + Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, + )] + pub struct AllTheTraits { + pub ok: String, + } + impl From<&AllTheTraits> for AllTheTraits { + fn from(value: &AllTheTraits) -> Self { + value.clone() + } + } + impl AllTheTraits { + pub fn builder() -> builder::AllTheTraits { + builder::AllTheTraits::default() + } + } + #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] + pub struct CompoundType { + pub value1: String, + pub value2: u64, + } + impl From<&CompoundType> for CompoundType { + fn from(value: &CompoundType) -> Self { + value.clone() + } + } + impl CompoundType { + pub fn builder() -> builder::CompoundType { + builder::CompoundType::default() + } + } + #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] + pub struct Pair { + #[serde(default = "defaults::pair_a")] + pub a: StringEnum, + #[serde(default = "defaults::pair_b")] + pub b: StringEnum, + } + impl From<&Pair> for Pair { + fn from(value: &Pair) -> Self { + value.clone() + } + } + impl Pair { + pub fn builder() -> builder::Pair { + builder::Pair::default() + } + } + #[derive( + Clone, Copy, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, + )] + pub enum StringEnum { + One, + Two, + BuckleMyShoe, + } + impl From<&StringEnum> for StringEnum { + fn from(value: &StringEnum) -> Self { + value.clone() + } + } + impl ToString for StringEnum { + fn to_string(&self) -> String { + match *self { + Self::One => "One".to_string(), + Self::Two => "Two".to_string(), + Self::BuckleMyShoe => "BuckleMyShoe".to_string(), + } + } + } + impl std::str::FromStr for StringEnum { + type Err = &'static str; + fn from_str(value: &str) -> Result { + match value { + "One" => Ok(Self::One), + "Two" => Ok(Self::Two), + "BuckleMyShoe" => Ok(Self::BuckleMyShoe), + _ => Err("invalid value"), + } + } + } + impl std::convert::TryFrom<&str> for StringEnum { + type Error = &'static str; + fn try_from(value: &str) -> Result { + value.parse() + } + } + impl std::convert::TryFrom<&String> for StringEnum { + type Error = &'static str; + fn try_from(value: &String) -> Result { + value.parse() + } + } + impl std::convert::TryFrom for StringEnum { + type Error = &'static str; + fn try_from(value: String) -> Result { + value.parse() + } + } + mod builder { + pub struct AllTheTraits { + ok: Result, + } + impl Default for AllTheTraits { + fn default() -> Self { + Self { + ok: Err("no value supplied for ok".to_string()), + } + } + } + impl AllTheTraits { + pub fn ok(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.ok = value + .try_into() + .map_err(|e| format!("error converting supplied value for ok: {}", e)); + self + } + } + impl std::convert::TryFrom for super::AllTheTraits { + type Error = String; + fn try_from(value: AllTheTraits) -> Result { + Ok(Self { ok: value.ok? }) + } + } + pub struct CompoundType { + value1: Result, + value2: Result, + } + impl Default for CompoundType { + fn default() -> Self { + Self { + value1: Err("no value supplied for value1".to_string()), + value2: Err("no value supplied for value2".to_string()), + } + } + } + impl CompoundType { + pub fn value1(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.value1 = value + .try_into() + .map_err(|e| format!("error converting supplied value for value1: {}", e)); + self + } + pub fn value2(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.value2 = value + .try_into() + .map_err(|e| format!("error converting supplied value for value2: {}", e)); + self + } + } + impl std::convert::TryFrom for super::CompoundType { + type Error = String; + fn try_from(value: CompoundType) -> Result { + Ok(Self { + value1: value.value1?, + value2: value.value2?, + }) + } + } + pub struct Pair { + a: Result, + b: Result, + } + impl Default for Pair { + fn default() -> Self { + Self { + a: Ok(super::defaults::pair_a()), + b: Ok(super::defaults::pair_b()), + } + } + } + impl Pair { + pub fn a(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.a = value + .try_into() + .map_err(|e| format!("error converting supplied value for a: {}", e)); + self + } + pub fn b(mut self, value: T) -> Self + where + T: std::convert::TryInto, + T::Error: std::fmt::Display, + { + self.b = value + .try_into() + .map_err(|e| format!("error converting supplied value for b: {}", e)); + self + } + } + impl std::convert::TryFrom for super::Pair { + type Error = String; + fn try_from(value: Pair) -> Result { + Ok(Self { + a: value.a?, + b: value.b?, + }) + } + } + } + mod defaults { + pub(super) fn pair_a() -> super::StringEnum { + super::StringEnum::One + } + pub(super) fn pair_b() -> super::StringEnum { + super::StringEnum::Two + } + } +} +pub fn do_stuff( + body: &types::CompoundType, + string: &str, + opt_int: Option, + strenum: types::StringEnum, +) -> types::CompoundType { + todo!() +} diff --git a/typify-impl/tests/generator.prettyplease.out b/typify-impl/tests/generator.prettyplease.out deleted file mode 100644 index 2db49914..00000000 --- a/typify-impl/tests/generator.prettyplease.out +++ /dev/null @@ -1,264 +0,0 @@ -mod types { - #[derive( - Clone, - Debug, - Deserialize, - Eq, - Hash, - JsonSchema, - Ord, - PartialEq, - PartialOrd, - Serialize - )] - pub struct AllTheTraits { - pub ok: String, - } - impl From<&AllTheTraits> for AllTheTraits { - fn from(value: &AllTheTraits) -> Self { - value.clone() - } - } - impl AllTheTraits { - pub fn builder() -> builder::AllTheTraits { - builder::AllTheTraits::default() - } - } - #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] - pub struct CompoundType { - pub value1: String, - pub value2: u64, - } - impl From<&CompoundType> for CompoundType { - fn from(value: &CompoundType) -> Self { - value.clone() - } - } - impl CompoundType { - pub fn builder() -> builder::CompoundType { - builder::CompoundType::default() - } - } - #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] - pub struct Pair { - #[serde(default = "defaults::pair_a")] - pub a: StringEnum, - #[serde(default = "defaults::pair_b")] - pub b: StringEnum, - } - impl From<&Pair> for Pair { - fn from(value: &Pair) -> Self { - value.clone() - } - } - impl Pair { - pub fn builder() -> builder::Pair { - builder::Pair::default() - } - } - #[derive( - Clone, - Copy, - Debug, - Deserialize, - Eq, - Hash, - JsonSchema, - Ord, - PartialEq, - PartialOrd, - Serialize - )] - pub enum StringEnum { - One, - Two, - BuckleMyShoe, - } - impl From<&StringEnum> for StringEnum { - fn from(value: &StringEnum) -> Self { - value.clone() - } - } - impl ToString for StringEnum { - fn to_string(&self) -> String { - match *self { - Self::One => "One".to_string(), - Self::Two => "Two".to_string(), - Self::BuckleMyShoe => "BuckleMyShoe".to_string(), - } - } - } - impl std::str::FromStr for StringEnum { - type Err = &'static str; - fn from_str(value: &str) -> Result { - match value { - "One" => Ok(Self::One), - "Two" => Ok(Self::Two), - "BuckleMyShoe" => Ok(Self::BuckleMyShoe), - _ => Err("invalid value"), - } - } - } - impl std::convert::TryFrom<&str> for StringEnum { - type Error = &'static str; - fn try_from(value: &str) -> Result { - value.parse() - } - } - impl std::convert::TryFrom<&String> for StringEnum { - type Error = &'static str; - fn try_from(value: &String) -> Result { - value.parse() - } - } - impl std::convert::TryFrom for StringEnum { - type Error = &'static str; - fn try_from(value: String) -> Result { - value.parse() - } - } - mod builder { - pub struct AllTheTraits { - ok: Result, - } - impl Default for AllTheTraits { - fn default() -> Self { - Self { - ok: Err("no value supplied for ok".to_string()), - } - } - } - impl AllTheTraits { - pub fn ok(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self - .ok = value - .try_into() - .map_err(|e| { - format!("error converting supplied value for ok: {}", e) - }); - self - } - } - impl std::convert::TryFrom for super::AllTheTraits { - type Error = String; - fn try_from(value: AllTheTraits) -> Result { - Ok(Self { ok: value.ok? }) - } - } - pub struct CompoundType { - value1: Result, - value2: Result, - } - impl Default for CompoundType { - fn default() -> Self { - Self { - value1: Err("no value supplied for value1".to_string()), - value2: Err("no value supplied for value2".to_string()), - } - } - } - impl CompoundType { - pub fn value1(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self - .value1 = value - .try_into() - .map_err(|e| { - format!("error converting supplied value for value1: {}", e) - }); - self - } - pub fn value2(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self - .value2 = value - .try_into() - .map_err(|e| { - format!("error converting supplied value for value2: {}", e) - }); - self - } - } - impl std::convert::TryFrom for super::CompoundType { - type Error = String; - fn try_from(value: CompoundType) -> Result { - Ok(Self { - value1: value.value1?, - value2: value.value2?, - }) - } - } - pub struct Pair { - a: Result, - b: Result, - } - impl Default for Pair { - fn default() -> Self { - Self { - a: Ok(super::defaults::pair_a()), - b: Ok(super::defaults::pair_b()), - } - } - } - impl Pair { - pub fn a(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self - .a = value - .try_into() - .map_err(|e| { - format!("error converting supplied value for a: {}", e) - }); - self - } - pub fn b(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self - .b = value - .try_into() - .map_err(|e| { - format!("error converting supplied value for b: {}", e) - }); - self - } - } - impl std::convert::TryFrom for super::Pair { - type Error = String; - fn try_from(value: Pair) -> Result { - Ok(Self { a: value.a?, b: value.b? }) - } - } - } - mod defaults { - pub(super) fn pair_a() -> super::StringEnum { - super::StringEnum::One - } - pub(super) fn pair_b() -> super::StringEnum { - super::StringEnum::Two - } - } -} -pub fn do_stuff( - body: &types::CompoundType, - string: &str, - opt_int: Option, - strenum: types::StringEnum, -) -> types::CompoundType { - todo!() -} diff --git a/typify-impl/tests/generator.rustfmt.out b/typify-impl/tests/generator.rustfmt.out deleted file mode 100644 index 41f8e2b4..00000000 --- a/typify-impl/tests/generator.rustfmt.out +++ /dev/null @@ -1,233 +0,0 @@ -mod types { - #[derive( - Clone, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, - )] - pub struct AllTheTraits { - pub ok: String, - } - impl From<&AllTheTraits> for AllTheTraits { - fn from(value: &AllTheTraits) -> Self { - value.clone() - } - } - impl AllTheTraits { - pub fn builder() -> builder::AllTheTraits { - builder::AllTheTraits::default() - } - } - #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] - pub struct CompoundType { - pub value1: String, - pub value2: u64, - } - impl From<&CompoundType> for CompoundType { - fn from(value: &CompoundType) -> Self { - value.clone() - } - } - impl CompoundType { - pub fn builder() -> builder::CompoundType { - builder::CompoundType::default() - } - } - #[derive(Clone, Debug, Deserialize, JsonSchema, Serialize)] - pub struct Pair { - #[serde(default = "defaults::pair_a")] - pub a: StringEnum, - #[serde(default = "defaults::pair_b")] - pub b: StringEnum, - } - impl From<&Pair> for Pair { - fn from(value: &Pair) -> Self { - value.clone() - } - } - impl Pair { - pub fn builder() -> builder::Pair { - builder::Pair::default() - } - } - #[derive( - Clone, Copy, Debug, Deserialize, Eq, Hash, JsonSchema, Ord, PartialEq, PartialOrd, Serialize, - )] - pub enum StringEnum { - One, - Two, - BuckleMyShoe, - } - impl From<&StringEnum> for StringEnum { - fn from(value: &StringEnum) -> Self { - value.clone() - } - } - impl ToString for StringEnum { - fn to_string(&self) -> String { - match *self { - Self::One => "One".to_string(), - Self::Two => "Two".to_string(), - Self::BuckleMyShoe => "BuckleMyShoe".to_string(), - } - } - } - impl std::str::FromStr for StringEnum { - type Err = &'static str; - fn from_str(value: &str) -> Result { - match value { - "One" => Ok(Self::One), - "Two" => Ok(Self::Two), - "BuckleMyShoe" => Ok(Self::BuckleMyShoe), - _ => Err("invalid value"), - } - } - } - impl std::convert::TryFrom<&str> for StringEnum { - type Error = &'static str; - fn try_from(value: &str) -> Result { - value.parse() - } - } - impl std::convert::TryFrom<&String> for StringEnum { - type Error = &'static str; - fn try_from(value: &String) -> Result { - value.parse() - } - } - impl std::convert::TryFrom for StringEnum { - type Error = &'static str; - fn try_from(value: String) -> Result { - value.parse() - } - } - mod builder { - pub struct AllTheTraits { - ok: Result, - } - impl Default for AllTheTraits { - fn default() -> Self { - Self { - ok: Err("no value supplied for ok".to_string()), - } - } - } - impl AllTheTraits { - pub fn ok(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.ok = value - .try_into() - .map_err(|e| format!("error converting supplied value for ok: {}", e)); - self - } - } - impl std::convert::TryFrom for super::AllTheTraits { - type Error = String; - fn try_from(value: AllTheTraits) -> Result { - Ok(Self { ok: value.ok? }) - } - } - pub struct CompoundType { - value1: Result, - value2: Result, - } - impl Default for CompoundType { - fn default() -> Self { - Self { - value1: Err("no value supplied for value1".to_string()), - value2: Err("no value supplied for value2".to_string()), - } - } - } - impl CompoundType { - pub fn value1(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.value1 = value - .try_into() - .map_err(|e| format!("error converting supplied value for value1: {}", e)); - self - } - pub fn value2(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.value2 = value - .try_into() - .map_err(|e| format!("error converting supplied value for value2: {}", e)); - self - } - } - impl std::convert::TryFrom for super::CompoundType { - type Error = String; - fn try_from(value: CompoundType) -> Result { - Ok(Self { - value1: value.value1?, - value2: value.value2?, - }) - } - } - pub struct Pair { - a: Result, - b: Result, - } - impl Default for Pair { - fn default() -> Self { - Self { - a: Ok(super::defaults::pair_a()), - b: Ok(super::defaults::pair_b()), - } - } - } - impl Pair { - pub fn a(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.a = value - .try_into() - .map_err(|e| format!("error converting supplied value for a: {}", e)); - self - } - pub fn b(mut self, value: T) -> Self - where - T: std::convert::TryInto, - T::Error: std::fmt::Display, - { - self.b = value - .try_into() - .map_err(|e| format!("error converting supplied value for b: {}", e)); - self - } - } - impl std::convert::TryFrom for super::Pair { - type Error = String; - fn try_from(value: Pair) -> Result { - Ok(Self { - a: value.a?, - b: value.b?, - }) - } - } - } - mod defaults { - pub(super) fn pair_a() -> super::StringEnum { - super::StringEnum::One - } - pub(super) fn pair_b() -> super::StringEnum { - super::StringEnum::Two - } - } -} -pub fn do_stuff( - body: &types::CompoundType, - string: &str, - opt_int: Option, - strenum: types::StringEnum, -) -> types::CompoundType { - todo!() -} diff --git a/typify-impl/tests/test_generation.rs b/typify-impl/tests/test_generation.rs index 408d35e6..d9c86fa4 100644 --- a/typify-impl/tests/test_generation.rs +++ b/typify-impl/tests/test_generation.rs @@ -108,15 +108,7 @@ fn test_generation() { } }; - let fmt = file.to_string(); - - expectorate::assert_contents("tests/generator.out", fmt.as_str()); - let fmt = rustfmt_wrapper::rustfmt(file.to_string()).unwrap(); expectorate::assert_contents("tests/generator.rustfmt.out", fmt.as_str()); - - let fmt = prettyplease::unparse(&syn::parse2::(file).unwrap()); - - expectorate::assert_contents("tests/generator.prettyplease.out", fmt.as_str()); } diff --git a/typify-test/Cargo.toml b/typify-test/Cargo.toml index 9b49c82b..49553b58 100644 --- a/typify-test/Cargo.toml +++ b/typify-test/Cargo.toml @@ -11,7 +11,7 @@ serde_json = "1.0.94" [build-dependencies] ipnetwork = { version = "0.20.0", features = ["schemars"] } -prettyplease = "0.1" +rustfmt-wrapper = "0.2" schemars = "0.8.12" serde = "1.0.155" syn = "1" diff --git a/typify-test/build.rs b/typify-test/build.rs index 1933770e..df1c4c27 100644 --- a/typify-test/build.rs +++ b/typify-test/build.rs @@ -109,7 +109,7 @@ fn main() { let contents = format!( "{}\n{}", "use serde::{Deserialize, Serialize};", - prettyplease::unparse(&syn::parse2::(type_space.to_stream()).unwrap()) + rustfmt_wrapper::rustfmt(type_space.to_stream().to_string()).unwrap() ); let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf(); From c1944dac242f1488cc0f7c4354238db9fb273197 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 16 Mar 2023 09:47:06 +0100 Subject: [PATCH 4/9] Add changelog entry --- CHANGELOG.adoc | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 6555ae22..3403100e 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -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) From e7e2bdbcd3789130d5a10bc82b5c1cc406affa7b Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 16 Mar 2023 09:48:50 +0100 Subject: [PATCH 5/9] Fix code blocks --- CHANGELOG.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index 3403100e..d94c0ebf 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -20,17 +20,17 @@ pretty printing method of choice. Users can use the `ToTokens` implementation of 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] From 721a5f17199bcb14f9ee2a2fa22c2b3eff89c141 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 16 Mar 2023 09:49:34 +0100 Subject: [PATCH 6/9] Fix path --- typify-impl/tests/test_generation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typify-impl/tests/test_generation.rs b/typify-impl/tests/test_generation.rs index d9c86fa4..64394a63 100644 --- a/typify-impl/tests/test_generation.rs +++ b/typify-impl/tests/test_generation.rs @@ -110,5 +110,5 @@ fn test_generation() { let fmt = rustfmt_wrapper::rustfmt(file.to_string()).unwrap(); - expectorate::assert_contents("tests/generator.rustfmt.out", fmt.as_str()); + expectorate::assert_contents("tests/generator.out", fmt.as_str()); } From 11e7f58df108f27fbf4c7ebecc11eabcc78a58a6 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 16 Mar 2023 09:56:54 +0100 Subject: [PATCH 7/9] Reflect removal of `ToString` in `cargo-typify` --- cargo-typify/src/lib.rs | 2 +- cargo-typify/tests/integration.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-typify/src/lib.rs b/cargo-typify/src/lib.rs index d13517f2..fcfbd86a 100644 --- a/cargo-typify/src/lib.rs +++ b/cargo-typify/src/lib.rs @@ -99,7 +99,7 @@ pub fn convert(args: &CliArgs) -> Result { 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")?; diff --git a/cargo-typify/tests/integration.rs b/cargo-typify/tests/integration.rs index 17fd5229..c59e2d12 100644 --- a/cargo-typify/tests/integration.rs +++ b/cargo-typify/tests/integration.rs @@ -1,5 +1,5 @@ use expectorate::assert_contents; -use newline_converter::{dos2unix, unix2dos}; +use newline_converter::dos2unix; use tempdir::TempDir; #[test] From 5af168ccb26455187444fd5e6da1759e5391843b Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Thu, 16 Mar 2023 09:58:16 +0100 Subject: [PATCH 8/9] Remove `syn` from `typify-test` build deps --- Cargo.lock | 1 - typify-test/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 643ddb4d..a0ce0abb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1081,7 +1081,6 @@ dependencies = [ "schemars", "serde", "serde_json", - "syn", "typify", ] diff --git a/typify-test/Cargo.toml b/typify-test/Cargo.toml index 49553b58..39c24e0f 100644 --- a/typify-test/Cargo.toml +++ b/typify-test/Cargo.toml @@ -14,5 +14,4 @@ ipnetwork = { version = "0.20.0", features = ["schemars"] } rustfmt-wrapper = "0.2" schemars = "0.8.12" serde = "1.0.155" -syn = "1" typify = { path = "../typify" } From 75c64febc418fb9447a074d2afaf27966362b594 Mon Sep 17 00:00:00 2001 From: Matthijs Brobbel Date: Fri, 17 Mar 2023 10:49:45 +0100 Subject: [PATCH 9/9] Use `prettyplease` in examples and add Formatting section to README --- Cargo.lock | 15 ++++++++-- README.md | 63 ++++++++++++++++++++++++++++++---------- example-build/Cargo.toml | 4 +-- example-build/build.rs | 2 +- typify-test/Cargo.toml | 3 +- typify-test/build.rs | 2 +- 6 files changed, 66 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a0ce0abb..d5884f46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -253,7 +253,7 @@ dependencies = [ name = "example-build" version = "0.0.0" dependencies = [ - "rustfmt-wrapper", + "prettyplease", "schemars", "serde", "serde_json", @@ -539,6 +539,16 @@ dependencies = [ "termtree", ] +[[package]] +name = "prettyplease" +version = "0.1.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1076,11 +1086,12 @@ name = "typify-test" version = "0.0.0" dependencies = [ "ipnetwork", + "prettyplease", "regress", - "rustfmt-wrapper", "schemars", "serde", "serde_json", + "syn", "typify", ] diff --git a/README.md b/README.md index bc33051c..4df6bb85 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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`, -`HashSet`, 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` and `HashSet` -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`, `HashSet`, +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` and `HashSet` is only if the +schema's `uniqueItems` field is `false` or `true` respectively. ### Objects @@ -49,7 +50,8 @@ 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 @@ -57,6 +59,34 @@ 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::(typespace.to_stream())?) +``` + ## WIP Typify is a work in progress. Changes that affect output will be indicated with @@ -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 } ``` @@ -98,4 +128,5 @@ struct A { a: Box, } ``` + .. but it does not support more complex cycles such as A -> B -> A. diff --git a/example-build/Cargo.toml b/example-build/Cargo.toml index 25ec0f7c..72985f45 100644 --- a/example-build/Cargo.toml +++ b/example-build/Cargo.toml @@ -9,8 +9,8 @@ serde = "1.0" serde_json = "1.0.94" [build-dependencies] -rustfmt-wrapper = "0.2" +prettyplease = "0.1" schemars = "0.8" serde_json = "1.0.94" -syn = "1" +syn = "1.0.109" typify = { path = "../typify" } diff --git a/example-build/build.rs b/example-build/build.rs index 1e2e4374..71af1b93 100644 --- a/example-build/build.rs +++ b/example-build/build.rs @@ -18,7 +18,7 @@ fn main() { let contents = format!( "{}\n{}", "use serde::{Deserialize, Serialize};", - rustfmt_wrapper::rustfmt(type_space.to_stream().to_string()).unwrap() + prettyplease::unparse(&syn::parse2::(type_space.to_stream()).unwrap()) ); let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf(); diff --git a/typify-test/Cargo.toml b/typify-test/Cargo.toml index 39c24e0f..399e9f7a 100644 --- a/typify-test/Cargo.toml +++ b/typify-test/Cargo.toml @@ -11,7 +11,8 @@ serde_json = "1.0.94" [build-dependencies] ipnetwork = { version = "0.20.0", features = ["schemars"] } -rustfmt-wrapper = "0.2" +prettyplease = "0.1" schemars = "0.8.12" serde = "1.0.155" +syn = "1.0.109" typify = { path = "../typify" } diff --git a/typify-test/build.rs b/typify-test/build.rs index df1c4c27..1933770e 100644 --- a/typify-test/build.rs +++ b/typify-test/build.rs @@ -109,7 +109,7 @@ fn main() { let contents = format!( "{}\n{}", "use serde::{Deserialize, Serialize};", - rustfmt_wrapper::rustfmt(type_space.to_stream().to_string()).unwrap() + prettyplease::unparse(&syn::parse2::(type_space.to_stream()).unwrap()) ); let mut out_file = Path::new(&env::var("OUT_DIR").unwrap()).to_path_buf();