api-macro: add json_schema!() macro

This allows using the json schema notation to generate `Schema`
expressions.

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2025-01-07 17:40:24 +01:00
parent 619c290cf8
commit dce9102163
3 changed files with 47 additions and 1 deletions

View File

@ -761,3 +761,13 @@ pub(crate) fn api(attr: TokenStream, item: TokenStream) -> Result<TokenStream, E
_ => bail!(item => "api macro only works on functions"),
}
}
/// Directly convert a json schema into a `Schema` expression.
pub(crate) fn json_schema(item: TokenStream) -> Result<TokenStream, Error> {
let attribs = JSONObject::parse_inner.parse2(item)?;
let schema: Schema = attribs.try_into()?;
let mut ts = TokenStream::new();
schema.to_schema(&mut ts)?;
Ok(ts)
}

View File

@ -295,6 +295,24 @@ pub fn api(attr: TokenStream_1, item: TokenStream_1) -> TokenStream_1 {
handle_error(item.clone(), api::api(attr.into(), item)).into()
}
/// *Experimental:* Transform a json-like schema definition into an expression yielding a `Schema`.
///
/// This is currently considered experimental as it should not be required for normal code.
#[proc_macro]
pub fn json_schema(item: TokenStream_1) -> TokenStream_1 {
let _error_guard = init_local_error();
let item: TokenStream = item.into();
let mut output = take_non_fatal_errors();
match api::json_schema(item) {
Ok(ts) => output.extend(ts),
Err(err) => match err.downcast::<syn::Error>() {
Ok(err) => output.extend(err.to_compile_error()),
Err(err) => panic!("error in json_schema!() macro: {err}"),
},
}
quote::quote!({ #output }).into()
}
/// This is a dummy derive macro actually handled by `#[api]`!
#[doc(hidden)]
#[proc_macro_derive(Updater, attributes(updater, serde))]

View File

@ -5,7 +5,7 @@
use std::collections::HashMap;
use proxmox_api_macro::api;
use proxmox_api_macro::{api, json_schema};
use proxmox_schema as schema;
use proxmox_schema::{ApiType, EnumEntry};
@ -68,6 +68,24 @@ fn test_struct() {
.schema();
assert_eq!(TEST_SCHEMA, TestStruct::API_SCHEMA);
const TEST_JSON_SCHEMA: ::proxmox_schema::Schema = json_schema! {
description: "An example of a simple struct type.",
properties: {
another: {
type: String,
description: "An optional auto-derived value for testing:",
optional: true,
},
test_string: {
type: String,
description: "A test string.",
optional: false,
},
},
};
assert_eq!(TEST_SCHEMA, TEST_JSON_SCHEMA);
}
#[api]