api/macro: add NumberSchema
Adapted from the integer schema, uses f64 type. Signed-off-by: Thomas Lamprecht <t.lamprecht@proxmox.com> Cc: Wolfgang Bumiller <w.bumiller@proxmox.com> Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
81cac5fc29
commit
13007df318
@ -17,6 +17,9 @@ mod structs;
|
||||
pub const INTNAMES: &[&str] = &[
|
||||
"Integer", "i8", "i16", "i32", "i64", "isize", "u8", "u16", "u32", "u64", "usize",
|
||||
];
|
||||
pub const NUMBERNAMES: &[&str] = &[
|
||||
"Number", "f32", "f64",
|
||||
];
|
||||
|
||||
/// The main `Schema` type.
|
||||
///
|
||||
@ -151,6 +154,7 @@ enum SchemaItem {
|
||||
Null,
|
||||
Boolean,
|
||||
Integer,
|
||||
Number,
|
||||
String,
|
||||
Object(SchemaObject),
|
||||
Array(SchemaArray),
|
||||
@ -202,6 +206,8 @@ impl SchemaItem {
|
||||
Ok(SchemaItem::Boolean)
|
||||
} else if INTNAMES.iter().any(|n| name == n) {
|
||||
Ok(SchemaItem::Integer)
|
||||
} else if NUMBERNAMES.iter().any(|n| name == n) {
|
||||
Ok(SchemaItem::Number)
|
||||
} else if name == "String" {
|
||||
Ok(SchemaItem::String)
|
||||
} else if name == "Object" {
|
||||
@ -235,6 +241,10 @@ impl SchemaItem {
|
||||
let description = description?;
|
||||
ts.extend(quote! { ::proxmox::api::schema::IntegerSchema::new(#description) });
|
||||
}
|
||||
SchemaItem::Number => {
|
||||
let description = description?;
|
||||
ts.extend(quote! { ::proxmox::api::schema::NumberSchema::new(#description) });
|
||||
}
|
||||
SchemaItem::String => {
|
||||
let description = description?;
|
||||
ts.extend(quote! { ::proxmox::api::schema::StringSchema::new(#description) });
|
||||
|
@ -204,6 +204,9 @@ fn handle_function_signature(
|
||||
} else if super::INTNAMES.iter().any(|n| path.path.is_ident(n)) {
|
||||
schema.item = SchemaItem::Integer;
|
||||
continue;
|
||||
} else if super::NUMBERNAMES.iter().any(|n| path.path.is_ident(n)) {
|
||||
schema.item = SchemaItem::Number;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
@ -87,6 +87,12 @@ pub fn get_schema_type_text(schema: &Schema, _style: ParameterDisplayStyle) -> S
|
||||
(None, Some(max)) => format!("<integer> (-N - {})", max),
|
||||
_ => String::from("<integer>"),
|
||||
},
|
||||
Schema::Number(number_schema) => match (number_schema.minimum, number_schema.maximum) {
|
||||
(Some(min), Some(max)) => format!("<number> ({} - {})", min, max),
|
||||
(Some(min), None) => format!("<number> ({} - N)", min),
|
||||
(None, Some(max)) => format!("<number> (-N - {})", max),
|
||||
_ => String::from("<integer>"),
|
||||
},
|
||||
Schema::Object(_) => String::from("<object>"),
|
||||
Schema::Array(_) => String::from("<array>"),
|
||||
}
|
||||
@ -106,6 +112,7 @@ pub fn get_property_description(
|
||||
Schema::String(ref schema) => (schema.description, schema.default.map(|v| v.to_owned())),
|
||||
Schema::Boolean(ref schema) => (schema.description, schema.default.map(|v| v.to_string())),
|
||||
Schema::Integer(ref schema) => (schema.description, schema.default.map(|v| v.to_string())),
|
||||
Schema::Number(ref schema) => (schema.description, schema.default.map(|v| v.to_string())),
|
||||
Schema::Object(ref schema) => (schema.description, None),
|
||||
Schema::Array(ref schema) => (schema.description, None),
|
||||
};
|
||||
@ -211,6 +218,10 @@ fn dump_api_return_schema(schema: &Schema) -> String {
|
||||
let description = wrap_text("", "", schema.description, 80);
|
||||
res.push_str(&description);
|
||||
}
|
||||
Schema::Number(schema) => {
|
||||
let description = wrap_text("", "", schema.description, 80);
|
||||
res.push_str(&description);
|
||||
}
|
||||
Schema::String(schema) => {
|
||||
let description = wrap_text("", "", schema.description, 80);
|
||||
res.push_str(&description);
|
||||
|
@ -155,6 +155,73 @@ impl IntegerSchema {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Data type to describe (JSON like) number value
|
||||
#[derive(Debug)]
|
||||
pub struct NumberSchema {
|
||||
pub description: &'static str,
|
||||
/// Optional minimum.
|
||||
pub minimum: Option<f64>,
|
||||
/// Optional maximum.
|
||||
pub maximum: Option<f64>,
|
||||
/// Optional default.
|
||||
pub default: Option<f64>,
|
||||
}
|
||||
|
||||
impl NumberSchema {
|
||||
pub const fn new(description: &'static str) -> Self {
|
||||
NumberSchema {
|
||||
description,
|
||||
default: None,
|
||||
minimum: None,
|
||||
maximum: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn default(mut self, default: f64) -> Self {
|
||||
self.default = Some(default);
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn minimum(mut self, minimum: f64) -> Self {
|
||||
self.minimum = Some(minimum);
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn maximum(mut self, maximium: f64) -> Self {
|
||||
self.maximum = Some(maximium);
|
||||
self
|
||||
}
|
||||
|
||||
pub const fn schema(self) -> Schema {
|
||||
Schema::Number(self)
|
||||
}
|
||||
|
||||
fn check_constraints(&self, value: f64) -> Result<(), Error> {
|
||||
if let Some(minimum) = self.minimum {
|
||||
if value < minimum {
|
||||
bail!(
|
||||
"value must have a minimum value of {} (got {})",
|
||||
minimum,
|
||||
value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(maximum) = self.maximum {
|
||||
if value > maximum {
|
||||
bail!(
|
||||
"value must have a maximum value of {} (got {})",
|
||||
maximum,
|
||||
value
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Data type to describe string values.
|
||||
#[derive(Debug)]
|
||||
pub struct StringSchema {
|
||||
@ -402,6 +469,7 @@ pub enum Schema {
|
||||
Null,
|
||||
Boolean(BooleanSchema),
|
||||
Integer(IntegerSchema),
|
||||
Number(NumberSchema),
|
||||
String(StringSchema),
|
||||
Object(ObjectSchema),
|
||||
Array(ArraySchema),
|
||||
@ -550,6 +618,11 @@ pub fn parse_simple_value(value_str: &str, schema: &Schema) -> Result<Value, Err
|
||||
integer_schema.check_constraints(res)?;
|
||||
Value::Number(res.into())
|
||||
}
|
||||
Schema::Number(number_schema) => {
|
||||
let res: f64 = value_str.parse()?;
|
||||
number_schema.check_constraints(res)?;
|
||||
Value::Number(serde_json::Number::from_f64(res).unwrap())
|
||||
}
|
||||
Schema::String(string_schema) => {
|
||||
string_schema.check_constraints(value_str)?;
|
||||
Value::String(value_str.into())
|
||||
@ -683,6 +756,7 @@ pub fn verify_json(data: &Value, schema: &Schema) -> Result<(), Error> {
|
||||
}
|
||||
Schema::Boolean(boolean_schema) => verify_json_boolean(data, &boolean_schema)?,
|
||||
Schema::Integer(integer_schema) => verify_json_integer(data, &integer_schema)?,
|
||||
Schema::Number(number_schema) => verify_json_number(data, &number_schema)?,
|
||||
Schema::String(string_schema) => verify_json_string(data, &string_schema)?,
|
||||
}
|
||||
Ok(())
|
||||
@ -714,6 +788,15 @@ pub fn verify_json_integer(data: &Value, schema: &IntegerSchema) -> Result<(), E
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify JSON value using an `NumberSchema`.
|
||||
pub fn verify_json_number(data: &Value, schema: &NumberSchema) -> Result<(), Error> {
|
||||
if let Some(value) = data.as_f64() {
|
||||
schema.check_constraints(value)
|
||||
} else {
|
||||
bail!("Expected number value.");
|
||||
}
|
||||
}
|
||||
|
||||
/// Verify JSON value using an `ArraySchema`.
|
||||
pub fn verify_json_array(data: &Value, schema: &ArraySchema) -> Result<(), Error> {
|
||||
let list = match data {
|
||||
|
Loading…
x
Reference in New Issue
Block a user