mirror of
https://git.proxmox.com/git/proxmox
synced 2025-05-01 17:07:32 +00:00
use 'quote' in router macro
get rid of a lot of unreadable TokenTree entries Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
7155689724
commit
f3e2e672be
@ -108,12 +108,12 @@ impl From<Ident> for Name {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn need_hyphenated_name(tokens: &mut TokenIter) -> Result<Name, Error> {
|
pub fn need_hyphenated_name(tokens: &mut TokenIter) -> Result<syn::LitStr, Error> {
|
||||||
let start = need_ident(&mut *tokens)?;
|
let start = need_ident(&mut *tokens)?;
|
||||||
finish_hyphenated_name(&mut *tokens, start)
|
finish_hyphenated_name(&mut *tokens, start)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn finish_hyphenated_name(tokens: &mut TokenIter, name: Ident) -> Result<Name, Error> {
|
pub fn finish_hyphenated_name(tokens: &mut TokenIter, name: Ident) -> Result<syn::LitStr, Error> {
|
||||||
let span = name.span();
|
let span = name.span();
|
||||||
let mut name = name.to_string();
|
let mut name = name.to_string();
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ pub fn finish_hyphenated_name(tokens: &mut TokenIter, name: Ident) -> Result<Nam
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Name(name, span))
|
Ok(syn::LitStr::new(&name, span))
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse an object notation:
|
// parse an object notation:
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use proc_macro2::{Delimiter, Ident, TokenStream, TokenTree};
|
use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree};
|
||||||
|
|
||||||
use failure::{bail, Error};
|
use failure::{bail, Error};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
use syn::LitStr;
|
||||||
|
|
||||||
use super::parsing::*;
|
use super::parsing::*;
|
||||||
|
|
||||||
@ -38,8 +39,8 @@ pub fn router_macro(input: TokenStream) -> Result<TokenStream, Error> {
|
|||||||
/// This can either be a fixed set of directories, or a parameter name, in which case it matches
|
/// This can either be a fixed set of directories, or a parameter name, in which case it matches
|
||||||
/// all directory names into the parameter of the specified name.
|
/// all directory names into the parameter of the specified name.
|
||||||
pub enum SubRoute {
|
pub enum SubRoute {
|
||||||
Directories(HashMap<String, Router>),
|
Directories(HashMap<LitStr, Router>),
|
||||||
Parameter(String, Box<Router>),
|
Parameter(LitStr, Box<Router>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SubRoute {
|
impl SubRoute {
|
||||||
@ -49,7 +50,7 @@ impl SubRoute {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a parameter entry with an empty default router.
|
/// Create a parameter entry with an empty default router.
|
||||||
fn parameter(name: String) -> Self {
|
fn parameter(name: LitStr) -> Self {
|
||||||
SubRoute::Parameter(name, Box::new(Router::default()))
|
SubRoute::Parameter(name, Box::new(Router::default()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,9 +79,9 @@ enum Entry {
|
|||||||
/// The components making up a path.
|
/// The components making up a path.
|
||||||
enum Component {
|
enum Component {
|
||||||
/// This component is a fixed sub directory name. Eg. `foo` or `baz` in `/foo/{bar}/baz`.
|
/// This component is a fixed sub directory name. Eg. `foo` or `baz` in `/foo/{bar}/baz`.
|
||||||
Name(String),
|
Name(LitStr),
|
||||||
/// This component matches everything into a parameter. Eg. `bar` in `/foo/{bar}/baz`.
|
/// This component matches everything into a parameter. Eg. `bar` in `/foo/{bar}/baz`.
|
||||||
Match(String),
|
Match(LitStr),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A path is just a list of components.
|
/// A path is just a list of components.
|
||||||
@ -106,7 +107,7 @@ impl Router {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
SubRoute::Parameter(_param, _router) => {
|
SubRoute::Parameter(_param, _router) => {
|
||||||
bail!("subdirectory '{}' clashes with parameter matcher", name);
|
bail!("subdir '{}' clashes with matched parameter", name.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,15 +120,15 @@ impl Router {
|
|||||||
SubRoute::Directories(_) => {
|
SubRoute::Directories(_) => {
|
||||||
bail!(
|
bail!(
|
||||||
"parameter matcher '{}' clashes with existing directory",
|
"parameter matcher '{}' clashes with existing directory",
|
||||||
name
|
name.value()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
SubRoute::Parameter(existing_name, router) => {
|
SubRoute::Parameter(existing_name, router) => {
|
||||||
if name != *existing_name {
|
if name != *existing_name {
|
||||||
bail!(
|
bail!(
|
||||||
"paramter matcher '{}' clashes with existing name '{}'",
|
"paramter matcher '{}' clashes with existing name '{}'",
|
||||||
name,
|
name.value(),
|
||||||
existing_name,
|
existing_name.value(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
at = router.as_mut();
|
at = router.as_mut();
|
||||||
@ -147,23 +148,17 @@ impl Router {
|
|||||||
fn into_token_stream(self, name: Option<Ident>) -> TokenStream {
|
fn into_token_stream(self, name: Option<Ident>) -> TokenStream {
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
|
|
||||||
use proc_macro2::{Group, Literal, Punct, Spacing, Span};
|
use proc_macro2::{Group, Literal, Punct, Spacing};
|
||||||
|
|
||||||
let mut out = vec![
|
let mut out = quote! {
|
||||||
TokenTree::Ident(Ident::new("Router", Span::call_site())),
|
::proxmox::api::Router::new()
|
||||||
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
|
};
|
||||||
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
|
|
||||||
TokenTree::Ident(Ident::new("new", Span::call_site())),
|
|
||||||
TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
|
|
||||||
];
|
|
||||||
|
|
||||||
fn add_method(out: &mut Vec<TokenTree>, name: &str, func_name: Ident) {
|
fn add_method(out: &mut TokenStream, name: &'static str, func_name: Ident) {
|
||||||
out.push(TokenTree::Punct(Punct::new('.', Spacing::Alone)));
|
let name = Ident::new(name, func_name.span());
|
||||||
out.push(TokenTree::Ident(Ident::new(name, Span::call_site())));
|
out.extend(quote! {
|
||||||
out.push(TokenTree::Group(Group::new(
|
.#name(#func_name)
|
||||||
Delimiter::Parenthesis,
|
});
|
||||||
TokenStream::from_iter(vec![TokenTree::Ident(func_name)]),
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(method) = self.get {
|
if let Some(method) = self.get {
|
||||||
@ -182,34 +177,17 @@ impl Router {
|
|||||||
match self.subroute {
|
match self.subroute {
|
||||||
None => (),
|
None => (),
|
||||||
Some(SubRoute::Parameter(name, router)) => {
|
Some(SubRoute::Parameter(name, router)) => {
|
||||||
out.push(TokenTree::Punct(Punct::new('.', Spacing::Alone)));
|
let router = router.into_token_stream(None);
|
||||||
out.push(TokenTree::Ident(Ident::new(
|
out.extend(quote! {
|
||||||
"parameter_subdir",
|
.parameter_subdir(#name, #router)
|
||||||
Span::call_site(),
|
});
|
||||||
)));
|
|
||||||
let mut sub_route = TokenStream::from_iter(vec![
|
|
||||||
TokenTree::Literal(Literal::string(&name)),
|
|
||||||
TokenTree::Punct(Punct::new(',', Spacing::Alone)),
|
|
||||||
]);
|
|
||||||
sub_route.extend(router.into_token_stream(None));
|
|
||||||
out.push(TokenTree::Group(Group::new(
|
|
||||||
Delimiter::Parenthesis,
|
|
||||||
sub_route,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
Some(SubRoute::Directories(hash)) => {
|
Some(SubRoute::Directories(hash)) => {
|
||||||
for (name, router) in hash {
|
for (name, router) in hash {
|
||||||
out.push(TokenTree::Punct(Punct::new('.', Spacing::Alone)));
|
let router = router.into_token_stream(None);
|
||||||
out.push(TokenTree::Ident(Ident::new("subdir", Span::call_site())));
|
out.extend(quote! {
|
||||||
let mut sub_route = TokenStream::from_iter(vec![
|
.subdir(#name, #router)
|
||||||
TokenTree::Literal(Literal::string(&name)),
|
});
|
||||||
TokenTree::Punct(Punct::new(',', Spacing::Alone)),
|
|
||||||
]);
|
|
||||||
sub_route.extend(router.into_token_stream(None));
|
|
||||||
out.push(TokenTree::Group(Group::new(
|
|
||||||
Delimiter::Parenthesis,
|
|
||||||
sub_route,
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -295,6 +273,15 @@ fn parse_entry_key(tokens: &mut TokenIter) -> Result<Option<Entry>, Error> {
|
|||||||
fn parse_path_name(tokens: &mut TokenIter) -> Result<Path, Error> {
|
fn parse_path_name(tokens: &mut TokenIter) -> Result<Path, Error> {
|
||||||
let mut path = Path::new();
|
let mut path = Path::new();
|
||||||
let mut component = String::new();
|
let mut component = String::new();
|
||||||
|
let mut span = None;
|
||||||
|
|
||||||
|
fn push_component(path: &mut Path, component: &mut String, span: &mut Option<Span>) {
|
||||||
|
if !component.is_empty() {
|
||||||
|
path.push(Component::Name(LitStr::new(&component, span.take().unwrap())));
|
||||||
|
component.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match tokens.next() {
|
match tokens.next() {
|
||||||
None => bail!("expected path component"),
|
None => bail!("expected path component"),
|
||||||
@ -303,11 +290,8 @@ fn parse_path_name(tokens: &mut TokenIter) -> Result<Path, Error> {
|
|||||||
bail!("invalid path component: {:?}", group);
|
bail!("invalid path component: {:?}", group);
|
||||||
}
|
}
|
||||||
let name = need_hyphenated_name(&mut group.stream().into_iter().peekable())?;
|
let name = need_hyphenated_name(&mut group.stream().into_iter().peekable())?;
|
||||||
if !component.is_empty() {
|
push_component(&mut path, &mut component, &mut span);
|
||||||
path.push(Component::Name(component));
|
path.push(Component::Match(name));
|
||||||
component = String::new();
|
|
||||||
}
|
|
||||||
path.push(Component::Match(name.into_string()));
|
|
||||||
|
|
||||||
// Now:
|
// Now:
|
||||||
// `component` is empty
|
// `component` is empty
|
||||||
@ -324,6 +308,9 @@ fn parse_path_name(tokens: &mut TokenIter) -> Result<Path, Error> {
|
|||||||
}
|
}
|
||||||
Some(TokenTree::Ident(ident)) => {
|
Some(TokenTree::Ident(ident)) => {
|
||||||
component.push_str(&ident.to_string());
|
component.push_str(&ident.to_string());
|
||||||
|
if span.is_none() {
|
||||||
|
span = Some(ident.span());
|
||||||
|
}
|
||||||
|
|
||||||
// Now:
|
// Now:
|
||||||
// `component` is partially or fully filled
|
// `component` is partially or fully filled
|
||||||
@ -348,10 +335,7 @@ fn parse_path_name(tokens: &mut TokenIter) -> Result<Path, Error> {
|
|||||||
// `component` is partially filled, we need more
|
// `component` is partially filled, we need more
|
||||||
}
|
}
|
||||||
'/' => {
|
'/' => {
|
||||||
if !component.is_empty() {
|
push_component(&mut path, &mut component, &mut span);
|
||||||
path.push(Component::Name(component));
|
|
||||||
component = String::new();
|
|
||||||
}
|
|
||||||
// `component` is cleared, we start the next one
|
// `component` is cleared, we start the next one
|
||||||
}
|
}
|
||||||
other => bail!("invalid punctuation in path: {:?}", other),
|
other => bail!("invalid punctuation in path: {:?}", other),
|
||||||
@ -363,9 +347,7 @@ fn parse_path_name(tokens: &mut TokenIter) -> Result<Path, Error> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !component.is_empty() {
|
push_component(&mut path, &mut component, &mut span);
|
||||||
path.push(Component::Name(component));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(path)
|
Ok(path)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user