From 723500dbfcea8d3874d9176305dc529943395a7c Mon Sep 17 00:00:00 2001 From: Wolfgang Bumiller Date: Fri, 6 Mar 2020 11:57:15 +0100 Subject: [PATCH] api-macro: include default minimum/maximum for integer types Signed-off-by: Wolfgang Bumiller --- proxmox-api-macro/src/api.rs | 40 ++++++++++++++++++++++++++++++--- proxmox-api-macro/src/util.rs | 12 +++++++--- proxmox-api-macro/tests/api2.rs | 5 ++++- 3 files changed, 50 insertions(+), 7 deletions(-) diff --git a/proxmox-api-macro/src/api.rs b/proxmox-api-macro/src/api.rs index 4fa2365c..f3ca9571 100644 --- a/proxmox-api-macro/src/api.rs +++ b/proxmox-api-macro/src/api.rs @@ -14,8 +14,25 @@ mod enums; mod method; mod structs; -pub const INTNAMES: &[&str] = &[ - "Integer", "i8", "i16", "i32", "i64", "isize", "u8", "u16", "u32", "u64", "usize", +pub struct IntType { + pub name: &'static str, + pub minimum: Option<&'static str>, + pub maximum: Option<&'static str>, +} + +#[rustfmt::skip] +pub const INTTYPES: &[IntType] = &[ + IntType { name: "Integer", minimum: None, maximum: None, }, + IntType { name: "i8", minimum: Some("-0x80"), maximum: Some("0x7f"), }, + IntType { name: "i16", minimum: Some("-0x8000"), maximum: Some("0x7fff"), }, + IntType { name: "i32", minimum: Some("-0x80000000"), maximum: Some("0x7fffffff"), }, + IntType { name: "i64", minimum: None, maximum: None, }, + IntType { name: "isize", minimum: None, maximum: None, }, + IntType { name: "u8", minimum: Some("0"), maximum: Some("0xff"), }, + IntType { name: "u16", minimum: Some("0"), maximum: Some("0xffff"), }, + IntType { name: "u32", minimum: Some("0"), maximum: Some("0xffffffff"), }, + IntType { name: "u64", minimum: Some("0"), maximum: None, }, + IntType { name: "usize", minimum: Some("0"), maximum: None, }, ]; pub const NUMBERNAMES: &[&str] = &["Number", "f32", "f64"]; @@ -164,6 +181,23 @@ impl Schema { self.as_object_mut() .and_then(|obj| obj.find_property_by_ident_mut(key)) } + + // FIXME: Should we turn the property list into a map? We used to have no need to find keys in + // it, but we do now... + fn find_schema_property(&self, key: &str) -> Option<&syn::Expr> { + for prop in &self.properties { + if prop.0 == key { + return Some(&prop.1) + } + } + None + } + + pub fn add_default_property(&mut self, key: &str, value: syn::Expr) { + if !self.find_schema_property(key).is_some() { + self.properties.push((Ident::new(key, Span::call_site()), value)); + } + } } pub enum SchemaItem { @@ -220,7 +254,7 @@ impl SchemaItem { Ok(SchemaItem::Null) } else if name == "Boolean" || name == "bool" { Ok(SchemaItem::Boolean) - } else if INTNAMES.iter().any(|n| name == n) { + } else if INTTYPES.iter().any(|n| name == n.name) { Ok(SchemaItem::Integer) } else if NUMBERNAMES.iter().any(|n| name == n) { Ok(SchemaItem::Number) diff --git a/proxmox-api-macro/src/util.rs b/proxmox-api-macro/src/util.rs index 0c88ce91..251ff83b 100644 --- a/proxmox-api-macro/src/util.rs +++ b/proxmox-api-macro/src/util.rs @@ -2,7 +2,7 @@ use std::borrow::Borrow; use std::collections::HashMap; use std::convert::TryFrom; -use proc_macro2::{Ident, Span}; +use proc_macro2::{Ident, Span, TokenStream}; use syn::parse::{Parse, ParseStream}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; @@ -460,7 +460,7 @@ pub fn derive_descriptions( Ok(()) } -pub fn infer_type(schema: &mut Schema, ty: &syn::Type) -> Result { +pub fn infer_type(schema: &mut Schema, ty: &syn::Type) -> Result { if let SchemaItem::Inferred(_) = schema.item { // } else { @@ -479,8 +479,14 @@ pub fn infer_type(schema: &mut Schema, ty: &syn::Type) -> Result { schema.item = SchemaItem::String; } else if path.path.is_ident("bool") { schema.item = SchemaItem::Boolean; - } else if api::INTNAMES.iter().any(|n| path.path.is_ident(n)) { + } else if let Some(ty) = api::INTTYPES.iter().find(|i| path.path.is_ident(i.name)) { schema.item = SchemaItem::Integer; + if let Some(min) = ty.minimum { + schema.add_default_property("minimum", syn::Expr::Verbatim(min.parse()?)); + } + if let Some(max) = ty.maximum { + schema.add_default_property("maximum", syn::Expr::Verbatim(max.parse()?)); + } } else if api::NUMBERNAMES.iter().any(|n| path.path.is_ident(n)) { schema.item = SchemaItem::Number; } else { diff --git a/proxmox-api-macro/tests/api2.rs b/proxmox-api-macro/tests/api2.rs index 64e3c29d..f53eb6ff 100644 --- a/proxmox-api-macro/tests/api2.rs +++ b/proxmox-api-macro/tests/api2.rs @@ -41,7 +41,10 @@ fn number_schema_check() { &[( "num", false, - &::proxmox::api::schema::IntegerSchema::new("The version to upgrade to").schema(), + &::proxmox::api::schema::IntegerSchema::new("The version to upgrade to") + .minimum(0) + .maximum(0xffffffff) + .schema(), )], ), )