2017-05-16 05:24:06 +00:00
|
|
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
|
|
|
|
2019-02-01 13:01:18 +00:00
|
|
|
use crate::method::{FnArg, FnSpec, FnType};
|
|
|
|
use crate::py_method::{
|
|
|
|
impl_py_getter_def, impl_py_setter_def, impl_wrap_getter, impl_wrap_setter,
|
|
|
|
};
|
|
|
|
use crate::utils;
|
2018-07-03 20:28:40 +00:00
|
|
|
use proc_macro2::{Span, TokenStream};
|
2019-02-01 13:01:18 +00:00
|
|
|
use quote::quote;
|
2018-07-04 17:07:27 +00:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use syn;
|
2018-05-13 19:24:40 +00:00
|
|
|
|
2018-07-04 17:07:27 +00:00
|
|
|
pub fn build_py_class(class: &mut syn::ItemStruct, attr: &Vec<syn::Expr>) -> TokenStream {
|
2017-07-28 02:47:01 +00:00
|
|
|
let (params, flags, base) = parse_attribute(attr);
|
2018-07-04 17:07:27 +00:00
|
|
|
let doc = utils::get_doc(&class.attrs, true);
|
2017-08-05 02:53:23 +00:00
|
|
|
let mut descriptors = Vec::new();
|
2018-05-13 19:24:40 +00:00
|
|
|
|
2018-07-04 17:07:27 +00:00
|
|
|
if let syn::Fields::Named(ref mut fields) = class.fields {
|
|
|
|
for field in fields.named.iter_mut() {
|
2018-11-12 13:15:11 +00:00
|
|
|
let field_descs = parse_descriptors(field);
|
|
|
|
if !field_descs.is_empty() {
|
|
|
|
descriptors.push((field.clone(), field_descs));
|
2017-05-28 05:45:48 +00:00
|
|
|
}
|
2018-05-13 19:24:40 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-07-08 21:33:48 +00:00
|
|
|
panic!("#[pyclass] can only be used with C-style structs")
|
2017-05-17 06:43:39 +00:00
|
|
|
}
|
|
|
|
|
2018-11-12 13:15:11 +00:00
|
|
|
impl_class(&class.ident, &base, doc, params, flags, descriptors)
|
2017-05-16 05:24:06 +00:00
|
|
|
}
|
|
|
|
|
2017-08-05 02:53:23 +00:00
|
|
|
fn parse_descriptors(item: &mut syn::Field) -> Vec<FnType> {
|
|
|
|
let mut descs = Vec::new();
|
|
|
|
let mut new_attrs = Vec::new();
|
|
|
|
for attr in item.attrs.iter() {
|
2018-05-13 19:24:40 +00:00
|
|
|
if let Some(syn::Meta::List(ref list)) = attr.interpret_meta() {
|
2018-06-15 20:41:16 +00:00
|
|
|
match list.ident.to_string().as_str() {
|
2018-05-13 19:24:40 +00:00
|
|
|
"prop" => {
|
|
|
|
for meta in list.nested.iter() {
|
|
|
|
if let &syn::NestedMeta::Meta(ref metaitem) = meta {
|
2018-06-15 20:41:16 +00:00
|
|
|
match metaitem.name().to_string().as_str() {
|
2018-05-13 19:24:40 +00:00
|
|
|
"get" => {
|
|
|
|
descs.push(FnType::Getter(None));
|
|
|
|
}
|
|
|
|
"set" => {
|
|
|
|
descs.push(FnType::Setter(None));
|
|
|
|
}
|
2018-07-06 10:56:40 +00:00
|
|
|
x => {
|
|
|
|
panic!(r#"Only "get" and "set" supported are, not "{}""#, x);
|
2017-08-05 02:53:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-05-13 19:24:40 +00:00
|
|
|
_ => new_attrs.push(attr.clone()),
|
2017-08-05 02:53:23 +00:00
|
|
|
}
|
2018-05-13 19:24:40 +00:00
|
|
|
} else {
|
|
|
|
new_attrs.push(attr.clone());
|
2017-08-05 02:53:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
item.attrs.clear();
|
|
|
|
item.attrs.extend(new_attrs);
|
|
|
|
descs
|
|
|
|
}
|
|
|
|
|
2019-01-30 14:26:45 +00:00
|
|
|
/// The orphan rule disallows using a generic inventory struct, so we create the whole boilerplate
|
|
|
|
/// once per class
|
|
|
|
fn impl_inventory(cls: &syn::Ident) -> TokenStream {
|
|
|
|
// Try to build a unique type that gives a hint about it's function when
|
|
|
|
// it comes up in error messages
|
|
|
|
let name = cls.to_string() + "GeneratedPyo3Inventory";
|
|
|
|
let inventory_cls = syn::Ident::new(&name, Span::call_site());
|
|
|
|
|
|
|
|
quote! {
|
|
|
|
#[doc(hidden)]
|
|
|
|
pub struct #inventory_cls {
|
|
|
|
methods: &'static [::pyo3::class::PyMethodDefType],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ::pyo3::class::methods::PyMethodsInventory for #inventory_cls {
|
|
|
|
fn new(methods: &'static [::pyo3::class::PyMethodDefType]) -> Self {
|
|
|
|
Self {
|
|
|
|
methods
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_methods(&self) -> &'static [::pyo3::class::PyMethodDefType] {
|
|
|
|
self.methods
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ::pyo3::class::methods::PyMethodsInventoryDispatch for #cls {
|
|
|
|
type InventoryType = #inventory_cls;
|
|
|
|
}
|
|
|
|
|
|
|
|
::pyo3::inventory::collect!(#inventory_cls);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-13 19:24:40 +00:00
|
|
|
fn impl_class(
|
|
|
|
cls: &syn::Ident,
|
|
|
|
base: &syn::TypePath,
|
|
|
|
doc: syn::Lit,
|
|
|
|
params: HashMap<&'static str, syn::Expr>,
|
|
|
|
flags: Vec<syn::Expr>,
|
2018-07-03 20:28:40 +00:00
|
|
|
descriptors: Vec<(syn::Field, Vec<FnType>)>,
|
2018-06-15 20:41:16 +00:00
|
|
|
) -> TokenStream {
|
2017-06-09 19:30:13 +00:00
|
|
|
let cls_name = match params.get("name") {
|
2018-05-13 19:24:40 +00:00
|
|
|
Some(name) => quote! { #name }.to_string(),
|
2018-07-03 20:28:40 +00:00
|
|
|
None => quote! { #cls }.to_string(),
|
2017-06-09 19:30:13 +00:00
|
|
|
};
|
2017-05-18 23:57:39 +00:00
|
|
|
|
2017-06-09 21:27:37 +00:00
|
|
|
let extra = {
|
|
|
|
if let Some(freelist) = params.get("freelist") {
|
2018-11-12 13:58:16 +00:00
|
|
|
quote! {
|
2018-06-15 20:50:26 +00:00
|
|
|
impl ::pyo3::freelist::PyObjectWithFreeList for #cls {
|
2017-06-09 21:27:37 +00:00
|
|
|
#[inline]
|
2018-06-15 20:50:26 +00:00
|
|
|
fn get_free_list() -> &'static mut ::pyo3::freelist::FreeList<*mut ::pyo3::ffi::PyObject> {
|
|
|
|
static mut FREELIST: *mut ::pyo3::freelist::FreeList<*mut ::pyo3::ffi::PyObject> = 0 as *mut _;
|
2017-06-09 21:27:37 +00:00
|
|
|
unsafe {
|
|
|
|
if FREELIST.is_null() {
|
|
|
|
FREELIST = Box::into_raw(Box::new(
|
2018-06-15 20:50:26 +00:00
|
|
|
::pyo3::freelist::FreeList::with_capacity(#freelist)));
|
2017-06-09 21:27:37 +00:00
|
|
|
|
2019-02-12 22:15:03 +00:00
|
|
|
<#cls as ::pyo3::typeob::PyTypeObject>::init_type();
|
2017-06-09 21:27:37 +00:00
|
|
|
}
|
2017-07-18 14:10:56 +00:00
|
|
|
&mut *FREELIST
|
2017-06-09 21:27:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-11-12 13:58:16 +00:00
|
|
|
}
|
2017-06-09 21:27:37 +00:00
|
|
|
} else {
|
2018-11-12 13:58:16 +00:00
|
|
|
quote! {
|
|
|
|
impl ::pyo3::typeob::PyObjectAlloc for #cls {}
|
|
|
|
}
|
2017-06-09 21:27:37 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-08-05 02:53:23 +00:00
|
|
|
let extra = if !descriptors.is_empty() {
|
2018-06-15 20:41:16 +00:00
|
|
|
let ty = syn::parse_str(&cls.to_string()).expect("no name");
|
2017-08-05 02:53:23 +00:00
|
|
|
let desc_impls = impl_descriptors(&ty, descriptors);
|
2018-11-12 13:58:16 +00:00
|
|
|
quote! {
|
2017-08-05 02:53:23 +00:00
|
|
|
#desc_impls
|
|
|
|
#extra
|
2018-11-12 13:58:16 +00:00
|
|
|
}
|
2017-08-05 02:53:23 +00:00
|
|
|
} else {
|
|
|
|
extra
|
|
|
|
};
|
|
|
|
|
2017-07-24 20:03:18 +00:00
|
|
|
// insert space for weak ref
|
|
|
|
let mut has_weakref = false;
|
2017-07-28 14:21:59 +00:00
|
|
|
let mut has_dict = false;
|
2017-07-24 20:03:18 +00:00
|
|
|
for f in flags.iter() {
|
2018-05-13 19:24:40 +00:00
|
|
|
if let syn::Expr::Path(ref epath) = f {
|
2019-02-01 13:01:18 +00:00
|
|
|
if epath.path == syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_WEAKREF} {
|
2018-05-13 19:24:40 +00:00
|
|
|
has_weakref = true;
|
2019-02-01 13:01:18 +00:00
|
|
|
} else if epath.path == syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_DICT} {
|
2018-05-13 19:24:40 +00:00
|
|
|
has_dict = true;
|
|
|
|
}
|
2017-07-24 20:03:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let weakref = if has_weakref {
|
2018-07-04 17:07:27 +00:00
|
|
|
quote! {std::mem::size_of::<*const ::pyo3::ffi::PyObject>()}
|
2017-07-24 20:03:18 +00:00
|
|
|
} else {
|
2018-07-04 17:07:27 +00:00
|
|
|
quote! {0}
|
2017-07-24 20:03:18 +00:00
|
|
|
};
|
2017-07-28 14:21:59 +00:00
|
|
|
let dict = if has_dict {
|
2018-07-04 17:07:27 +00:00
|
|
|
quote! {std::mem::size_of::<*const ::pyo3::ffi::PyObject>()}
|
2017-07-28 14:21:59 +00:00
|
|
|
} else {
|
2018-07-04 17:07:27 +00:00
|
|
|
quote! {0}
|
2017-07-28 14:21:59 +00:00
|
|
|
};
|
2017-07-24 20:03:18 +00:00
|
|
|
|
2019-01-30 14:26:45 +00:00
|
|
|
let inventory_impl = impl_inventory(&cls);
|
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
quote! {
|
2018-06-15 20:50:26 +00:00
|
|
|
impl ::pyo3::typeob::PyTypeInfo for #cls {
|
2017-05-23 06:19:14 +00:00
|
|
|
type Type = #cls;
|
2017-07-28 02:47:01 +00:00
|
|
|
type BaseType = #base;
|
|
|
|
|
2017-07-13 23:45:50 +00:00
|
|
|
const NAME: &'static str = #cls_name;
|
|
|
|
const DESCRIPTION: &'static str = #doc;
|
2017-07-27 05:29:55 +00:00
|
|
|
const FLAGS: usize = #(#flags)|*;
|
2017-05-23 06:19:14 +00:00
|
|
|
|
2017-07-28 02:47:01 +00:00
|
|
|
const SIZE: usize = {
|
|
|
|
Self::OFFSET as usize +
|
2018-09-26 22:55:45 +00:00
|
|
|
::std::mem::size_of::<#cls>() + #weakref + #dict
|
2017-07-28 02:47:01 +00:00
|
|
|
};
|
|
|
|
const OFFSET: isize = {
|
|
|
|
// round base_size up to next multiple of align
|
|
|
|
(
|
2018-06-15 20:50:26 +00:00
|
|
|
(<#base as ::pyo3::typeob::PyTypeInfo>::SIZE +
|
2018-09-26 22:55:45 +00:00
|
|
|
::std::mem::align_of::<#cls>() - 1) /
|
|
|
|
::std::mem::align_of::<#cls>() * ::std::mem::align_of::<#cls>()
|
2017-07-28 02:47:01 +00:00
|
|
|
) as isize
|
|
|
|
};
|
2017-07-24 19:19:05 +00:00
|
|
|
|
2017-05-17 06:43:39 +00:00
|
|
|
#[inline]
|
2018-06-15 20:50:26 +00:00
|
|
|
unsafe fn type_object() -> &'static mut ::pyo3::ffi::PyTypeObject {
|
|
|
|
static mut TYPE_OBJECT: ::pyo3::ffi::PyTypeObject = ::pyo3::ffi::PyTypeObject_INIT;
|
2017-07-13 23:45:50 +00:00
|
|
|
&mut TYPE_OBJECT
|
2017-05-17 06:43:39 +00:00
|
|
|
}
|
|
|
|
}
|
2017-05-25 05:43:07 +00:00
|
|
|
|
2018-09-06 16:04:13 +00:00
|
|
|
impl ::pyo3::IntoPyObject for #cls {
|
2018-09-08 22:19:55 +00:00
|
|
|
fn into_object(self, py: ::pyo3::Python) -> ::pyo3::PyObject {
|
2019-02-07 18:07:09 +00:00
|
|
|
::pyo3::Py::new(py, self).unwrap().into_object(py)
|
2018-09-06 16:04:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-30 14:26:45 +00:00
|
|
|
#inventory_impl
|
|
|
|
|
2017-05-28 05:45:48 +00:00
|
|
|
#extra
|
2017-05-16 05:24:06 +00:00
|
|
|
}
|
|
|
|
}
|
2017-06-01 16:45:00 +00:00
|
|
|
|
2018-07-03 20:28:40 +00:00
|
|
|
fn impl_descriptors(cls: &syn::Type, descriptors: Vec<(syn::Field, Vec<FnType>)>) -> TokenStream {
|
|
|
|
let methods: Vec<TokenStream> = descriptors
|
|
|
|
.iter()
|
|
|
|
.flat_map(|&(ref field, ref fns)| {
|
|
|
|
fns.iter()
|
|
|
|
.map(|desc| {
|
|
|
|
let name = field.ident.clone().unwrap();
|
|
|
|
let field_ty = &field.ty;
|
|
|
|
match *desc {
|
|
|
|
FnType::Getter(_) => {
|
|
|
|
quote! {
|
|
|
|
impl #cls {
|
|
|
|
fn #name(&self) -> ::pyo3::PyResult<#field_ty> {
|
|
|
|
Ok(self.#name.clone())
|
|
|
|
}
|
|
|
|
}
|
2017-08-05 02:53:23 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-03 20:28:40 +00:00
|
|
|
FnType::Setter(_) => {
|
|
|
|
let setter_name =
|
|
|
|
syn::Ident::new(&format!("set_{}", name), Span::call_site());
|
|
|
|
quote! {
|
|
|
|
impl #cls {
|
|
|
|
fn #setter_name(&mut self, value: #field_ty) -> ::pyo3::PyResult<()> {
|
|
|
|
self.#name = value;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2017-08-05 02:53:23 +00:00
|
|
|
}
|
|
|
|
}
|
2018-07-03 20:28:40 +00:00
|
|
|
_ => unreachable!(),
|
2017-08-05 02:53:23 +00:00
|
|
|
}
|
2018-07-03 20:28:40 +00:00
|
|
|
})
|
|
|
|
.collect::<Vec<TokenStream>>()
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
let py_methods: Vec<TokenStream> = descriptors
|
|
|
|
.iter()
|
|
|
|
.flat_map(|&(ref field, ref fns)| {
|
|
|
|
fns.iter()
|
|
|
|
.map(|desc| {
|
|
|
|
let name = field.ident.clone().unwrap();
|
|
|
|
|
|
|
|
// FIXME better doc?
|
|
|
|
let doc: syn::Lit = syn::parse_str(&format!("\"{}\"", name)).unwrap();
|
|
|
|
|
|
|
|
let field_ty = &field.ty;
|
|
|
|
match *desc {
|
|
|
|
FnType::Getter(ref getter) => {
|
|
|
|
impl_py_getter_def(&name, doc, getter, &impl_wrap_getter(&cls, &name))
|
|
|
|
}
|
|
|
|
FnType::Setter(ref setter) => {
|
|
|
|
let setter_name =
|
|
|
|
syn::Ident::new(&format!("set_{}", name), Span::call_site());
|
|
|
|
let spec = FnSpec {
|
|
|
|
tp: FnType::Setter(None),
|
|
|
|
attrs: Vec::new(),
|
|
|
|
args: vec![FnArg {
|
|
|
|
name: &name,
|
|
|
|
mutability: &None,
|
|
|
|
by_ref: &None,
|
|
|
|
ty: field_ty,
|
|
|
|
optional: None,
|
|
|
|
py: true,
|
|
|
|
reference: false,
|
|
|
|
}],
|
2019-02-01 13:01:18 +00:00
|
|
|
output: syn::parse_quote!(PyResult<()>),
|
2018-07-03 20:28:40 +00:00
|
|
|
};
|
|
|
|
impl_py_setter_def(
|
|
|
|
&name,
|
|
|
|
doc,
|
|
|
|
setter,
|
|
|
|
&impl_wrap_setter(&cls, &setter_name, &spec),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
_ => unreachable!(),
|
|
|
|
}
|
2018-09-28 21:34:57 +00:00
|
|
|
})
|
|
|
|
.collect::<Vec<TokenStream>>()
|
|
|
|
})
|
|
|
|
.collect();
|
2017-08-05 02:53:23 +00:00
|
|
|
|
2018-07-03 19:11:56 +00:00
|
|
|
quote! {
|
2017-08-05 02:53:23 +00:00
|
|
|
#(#methods)*
|
|
|
|
|
2019-01-30 14:26:45 +00:00
|
|
|
::pyo3::inventory::submit! {
|
2019-02-01 13:49:25 +00:00
|
|
|
#![crate = pyo3] {
|
2019-01-30 14:26:45 +00:00
|
|
|
type ClsInventory = <#cls as ::pyo3::class::methods::PyMethodsInventoryDispatch>::InventoryType;
|
|
|
|
<ClsInventory as ::pyo3::class::methods::PyMethodsInventory>::new(&[#(#py_methods),*])
|
2017-08-05 02:53:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-13 19:24:40 +00:00
|
|
|
fn parse_attribute(
|
|
|
|
args: &Vec<syn::Expr>,
|
|
|
|
) -> (
|
|
|
|
HashMap<&'static str, syn::Expr>,
|
|
|
|
Vec<syn::Expr>,
|
2018-07-03 20:28:40 +00:00
|
|
|
syn::TypePath,
|
2018-05-13 19:24:40 +00:00
|
|
|
) {
|
2017-06-09 19:30:13 +00:00
|
|
|
let mut params = HashMap::new();
|
2018-09-02 21:33:45 +00:00
|
|
|
// We need the 0 as value for the constant we're later building using quote for when there
|
|
|
|
// are no other flags
|
2019-02-01 13:01:18 +00:00
|
|
|
let mut flags = vec![syn::parse_quote! {0}];
|
|
|
|
let mut base: syn::TypePath = syn::parse_quote! {::pyo3::types::PyObjectRef};
|
2017-06-09 19:30:13 +00:00
|
|
|
|
2018-05-13 19:24:40 +00:00
|
|
|
for expr in args.iter() {
|
|
|
|
match expr {
|
|
|
|
// Match a single flag
|
2018-09-02 21:33:45 +00:00
|
|
|
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
|
|
|
|
let flag = exp.path.segments.first().unwrap().value().ident.to_string();
|
|
|
|
let path = match flag.as_str() {
|
|
|
|
"gc" => {
|
2019-02-01 13:01:18 +00:00
|
|
|
syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_GC}
|
2018-09-02 21:33:45 +00:00
|
|
|
}
|
|
|
|
"weakref" => {
|
2019-02-01 13:01:18 +00:00
|
|
|
syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_WEAKREF}
|
2018-09-02 21:33:45 +00:00
|
|
|
}
|
|
|
|
"subclass" => {
|
2019-02-01 13:01:18 +00:00
|
|
|
syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_BASETYPE}
|
2018-09-02 21:33:45 +00:00
|
|
|
}
|
|
|
|
"dict" => {
|
2019-02-01 13:01:18 +00:00
|
|
|
syn::parse_quote! {::pyo3::typeob::PY_TYPE_FLAG_DICT}
|
2018-09-02 21:33:45 +00:00
|
|
|
}
|
|
|
|
param => panic!("Unsupported parameter: {}", param),
|
|
|
|
};
|
|
|
|
|
|
|
|
flags.push(syn::Expr::Path(path));
|
|
|
|
}
|
2017-07-24 19:19:05 +00:00
|
|
|
|
2018-05-13 19:24:40 +00:00
|
|
|
// Match a key/value flag
|
|
|
|
syn::Expr::Assign(ref ass) => {
|
|
|
|
let key = match *ass.left {
|
|
|
|
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
|
2018-06-15 20:41:16 +00:00
|
|
|
exp.path.segments.first().unwrap().value().ident.to_string()
|
2017-06-09 19:30:13 +00:00
|
|
|
}
|
2018-07-03 20:28:40 +00:00
|
|
|
_ => panic!("could not parse argument: {:?}", ass),
|
2018-05-13 19:24:40 +00:00
|
|
|
};
|
|
|
|
|
2018-06-15 20:41:16 +00:00
|
|
|
match key.as_str() {
|
2018-05-13 19:24:40 +00:00
|
|
|
"freelist" => {
|
|
|
|
// TODO: check if int literal
|
|
|
|
params.insert("freelist", *ass.right.clone());
|
2018-07-03 20:28:40 +00:00
|
|
|
}
|
|
|
|
"name" => match *ass.right {
|
|
|
|
syn::Expr::Path(ref exp) if exp.path.segments.len() == 1 => {
|
|
|
|
params.insert("name", exp.clone().into());
|
2018-05-13 19:24:40 +00:00
|
|
|
}
|
2018-09-02 21:33:45 +00:00
|
|
|
_ => panic!("Wrong 'name' format: {:?}", *ass.right),
|
2018-05-13 19:24:40 +00:00
|
|
|
},
|
2018-07-15 09:58:33 +00:00
|
|
|
"extends" => match *ass.right {
|
2018-07-03 20:28:40 +00:00
|
|
|
syn::Expr::Path(ref exp) => {
|
|
|
|
base = syn::TypePath {
|
|
|
|
path: exp.path.clone(),
|
|
|
|
qself: None,
|
|
|
|
};
|
2017-06-09 19:30:13 +00:00
|
|
|
}
|
2018-09-02 21:33:45 +00:00
|
|
|
_ => panic!("Wrong 'base' format: {:?}", *ass.right),
|
2018-07-03 20:28:40 +00:00
|
|
|
},
|
2018-05-13 19:24:40 +00:00
|
|
|
_ => {
|
2018-09-02 21:33:45 +00:00
|
|
|
panic!("Unsupported parameter: {:?}", key);
|
2017-07-27 05:29:55 +00:00
|
|
|
}
|
2017-06-09 19:30:13 +00:00
|
|
|
}
|
|
|
|
}
|
2018-05-13 19:24:40 +00:00
|
|
|
|
|
|
|
_ => panic!("could not parse arguments"),
|
2017-06-09 19:30:13 +00:00
|
|
|
}
|
|
|
|
}
|
2017-07-24 19:19:05 +00:00
|
|
|
|
2017-07-27 05:29:55 +00:00
|
|
|
(params, flags, base)
|
2017-06-09 19:30:13 +00:00
|
|
|
}
|