mirror of
https://git.proxmox.com/git/proxmox
synced 2025-08-13 20:15:10 +00:00
macro: helpers for error handling
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
a1c8b00f17
commit
145abf62a5
@ -3,8 +3,8 @@ use std::collections::HashMap;
|
|||||||
use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
|
use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
|
||||||
|
|
||||||
use failure::{bail, format_err, Error};
|
use failure::{bail, format_err, Error};
|
||||||
use quote::{quote, quote_spanned, ToTokens};
|
use quote::{quote, ToTokens};
|
||||||
use syn::{Expr, Token};
|
use syn::{spanned::Spanned, Expr, Token};
|
||||||
|
|
||||||
use super::api_def::{CommonTypeDefinition, ParameterDefinition};
|
use super::api_def::{CommonTypeDefinition, ParameterDefinition};
|
||||||
use super::parsing::*;
|
use super::parsing::*;
|
||||||
@ -17,7 +17,7 @@ pub fn api_macro(attr: TokenStream, item: TokenStream) -> Result<TokenStream, Er
|
|||||||
|
|
||||||
let definition = match definition {
|
let definition = match definition {
|
||||||
TokenTree::Group(ref group) if group.delimiter() == Delimiter::Brace => group.stream(),
|
TokenTree::Group(ref group) if group.delimiter() == Delimiter::Brace => group.stream(),
|
||||||
_ => bail!("expected api definition in braces"),
|
_ => cbail!(definition.span() => "expected api definition in braces"),
|
||||||
};
|
};
|
||||||
|
|
||||||
let definition = parse_object(definition)?;
|
let definition = parse_object(definition)?;
|
||||||
@ -34,7 +34,7 @@ pub fn api_macro(attr: TokenStream, item: TokenStream) -> Result<TokenStream, Er
|
|||||||
Ok(output)
|
Ok(output)
|
||||||
}
|
}
|
||||||
syn::Item::Fn(func) => handle_function(definition, func),
|
syn::Item::Fn(func) => handle_function(definition, func),
|
||||||
_ => bail!("api macro currently only applies to structs and functions"),
|
_ => cbail!(item.span() => "api macro currently only applies to structs and functions"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,9 +43,10 @@ fn handle_function(
|
|||||||
mut item: syn::ItemFn,
|
mut item: syn::ItemFn,
|
||||||
) -> Result<TokenStream, Error> {
|
) -> Result<TokenStream, Error> {
|
||||||
if item.decl.generics.lt_token.is_some() {
|
if item.decl.generics.lt_token.is_some() {
|
||||||
return Ok(quote_spanned! { item.decl.generics.lt_token.unwrap().span =>
|
cbail!(
|
||||||
compile_error!("cannot use generic functions for api macros currently");
|
item.decl.generics.span(),
|
||||||
}.into());
|
"cannot use generic functions for api macros currently",
|
||||||
|
);
|
||||||
// Not until we stabilize our generated representation!
|
// Not until we stabilize our generated representation!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
24
proxmox-api-macro/src/error.rs
Normal file
24
proxmox-api-macro/src/error.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CompileError {
|
||||||
|
pub tokens: proc_macro::TokenStream,
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for CompileError {}
|
||||||
|
unsafe impl Sync for CompileError {}
|
||||||
|
|
||||||
|
impl std::fmt::Display for CompileError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "generic compile error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for CompileError {}
|
||||||
|
|
||||||
|
macro_rules! cbail {
|
||||||
|
($span:expr => $($msg:tt)*) => {
|
||||||
|
return Err(::failure::Error::from(crate::error::CompileError {
|
||||||
|
tokens: ::quote::quote_spanned! { $span => compile_error!($($msg)*); }.into()
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
($span:expr, $($msg:tt)*) => { cbail!($span => $($msg)*) }
|
||||||
|
}
|
@ -5,6 +5,9 @@ extern crate proc_macro2;
|
|||||||
|
|
||||||
use proc_macro::TokenStream;
|
use proc_macro::TokenStream;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
mod error;
|
||||||
|
|
||||||
mod api_def;
|
mod api_def;
|
||||||
mod parsing;
|
mod parsing;
|
||||||
mod util;
|
mod util;
|
||||||
@ -12,6 +15,13 @@ mod util;
|
|||||||
mod api_macro;
|
mod api_macro;
|
||||||
mod router_macro;
|
mod router_macro;
|
||||||
|
|
||||||
|
fn handle_error(kind: &'static str, err: failure::Error) -> TokenStream {
|
||||||
|
match err.downcast::<error::CompileError>() {
|
||||||
|
Ok(err) => err.tokens,
|
||||||
|
Err(err) => panic!("error in {}: {}", kind, err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is the `#[api(api definition)]` attribute for functions. An Api definition defines the
|
/// This is the `#[api(api definition)]` attribute for functions. An Api definition defines the
|
||||||
/// parameters and return type of an API call. The function will automatically be wrapped in a
|
/// parameters and return type of an API call. The function will automatically be wrapped in a
|
||||||
/// function taking and returning a json `Value`, while performing validity checks on both input
|
/// function taking and returning a json `Value`, while performing validity checks on both input
|
||||||
@ -44,7 +54,7 @@ mod router_macro;
|
|||||||
pub fn api(attr: TokenStream, item: TokenStream) -> TokenStream {
|
pub fn api(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||||
match api_macro::api_macro(attr.into(), item.into()) {
|
match api_macro::api_macro(attr.into(), item.into()) {
|
||||||
Ok(output) => output.into(),
|
Ok(output) => output.into(),
|
||||||
Err(err) => panic!("error in api definition: {}", err),
|
Err(err) => handle_error("api definition", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +145,6 @@ pub fn router(input: TokenStream) -> TokenStream {
|
|||||||
// TODO...
|
// TODO...
|
||||||
match router_macro::router_macro(input.into()) {
|
match router_macro::router_macro(input.into()) {
|
||||||
Ok(output) => output.into(),
|
Ok(output) => output.into(),
|
||||||
Err(err) => panic!("error in router macro: {}", err),
|
Err(err) => handle_error("router", err),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user