From deace5928c13576eb5c0a68e86c06e88ac06b12a Mon Sep 17 00:00:00 2001 From: "Joshua M. Clulow" Date: Tue, 31 Aug 2021 07:27:09 +0000 Subject: [PATCH] basic handling of String newtypes and enumerations --- src/main.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index f5392f5..b7b7d9f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,7 @@ use serde::Deserialize; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fs::{File, OpenOptions}; use std::io::Write; -use std::path::{PathBuf, Path}; +use std::path::{Path, PathBuf}; mod template; @@ -438,6 +438,8 @@ enum TypeDetails { * order in the generated code. */ Object(BTreeMap), + NewType(TypeId), + Enumeration(Vec), } #[derive(Debug)] @@ -541,6 +543,26 @@ impl TypeSpace { format!("[OBJECT {} !NONAME?]", tid.0) } } + TypeDetails::NewType(itid) => { + if let Some(ite) = self.id_to_entry.get(&itid) { + if let Some(n) = &ite.name { + return format!("newtype of {} <{}>", n, itid.0); + } + } + + /* + * If there is no name attached, we should try a + * recursive describe. + */ + format!("newtype of {}", self.describe(itid)) + } + TypeDetails::Enumeration(_) => { + if let Some(n) = &te.name { + format!("enum {}", n) + } else { + format!("[ENUMERATION {} !NONAME?]", tid.0) + } + } TypeDetails::Unknown => { format!("[UNKNOWN {}]", tid.0) } @@ -566,7 +588,9 @@ impl TypeSpace { TypeDetails::Optional(itid) => { Ok(format!("Option<{}>", self.render_type(itid, in_mod)?)) } - TypeDetails::Object(_) => { + TypeDetails::Object(_) + | TypeDetails::NewType(_) + | TypeDetails::Enumeration(_) => { if let Some(n) = &te.name { if in_mod { Ok(n.to_string()) @@ -720,7 +744,27 @@ impl TypeSpace { ) } Empty => { - (Some("String".to_string()), TypeDetails::Basic) + use TypeDetails::{Enumeration, NewType}; + + if !st.enumeration.is_empty() { + if let Some(name) = name { + ( + Some(name.to_string()), + Enumeration(st.enumeration.clone()), + ) + } else { + bail!("enumeration without name: {:?}", st); + } + } else if let Some(name) = name { + /* + * Create a newtype struct for strings that have + * a name of their own. + */ + let id = self.id_for_name("String"); + (Some(name.to_string()), NewType(id)) + } else { + (Some("String".to_string()), TypeDetails::Basic) + } } x => { bail!("XXX string format {:?}", x); @@ -906,6 +950,37 @@ fn gen(api: &OpenAPI, ts: &mut TypeSpace) -> Result { a(" }"); a(""); } + TypeDetails::NewType(tid) => { + a(" #[derive(Serialize, Deserialize, Debug)]"); + a(&format!( + " pub struct {}({});", + te.name.as_deref().unwrap(), + ts.render_type(tid, true)?, + )); + a(""); + } + TypeDetails::Enumeration(list) => { + a(" #[derive(Serialize, Deserialize, Debug)]"); + a(&format!(" pub enum {} {{", te.name.as_deref().unwrap())); + for name in list.iter() { + /* + * Attempt to make the first letter a capital letter. + */ + let mut name = name.chars().collect::>(); + if name[0].is_ascii_alphabetic() { + name[0] = name[0].to_ascii_uppercase(); + } + + a( + &format!( + " {},", + name.iter().collect::(), + ), + ); + } + a(" }"); + a(""); + } TypeDetails::Basic => {} TypeDetails::Unknown => {} TypeDetails::Array(_) => {} @@ -1292,9 +1367,8 @@ fn main() -> Result<()> { percent-encoding = \"2.1\"\n\ reqwest = {{ version = \"0.11\", features = [\"json\"] }}\n\ serde = {{ version = \"1\", features = [\"derive\"] }}\n", - name, - version, - ); + name, version, + ); save(&toml, tomlout.as_str())?; /*