Improve support for zero sized types
This commit is contained in:
+60
-26
@@ -125,50 +125,79 @@ pub enum Type {
|
||||
FuncPtr(Option<Box<Type>>, Vec<Type>),
|
||||
}
|
||||
impl Type {
|
||||
pub fn convert(ty: &syn::Ty) -> ConvertResult<Type> {
|
||||
match ty {
|
||||
pub fn convert(ty: &syn::Ty) -> ConvertResult<Option<Type>> {
|
||||
let converted = match ty {
|
||||
&syn::Ty::Rptr(_, ref mut_ty) => {
|
||||
let converted = try!(Type::convert(&mut_ty.ty));
|
||||
|
||||
Ok(match mut_ty.mutability {
|
||||
let converted = match converted {
|
||||
Some(converted) => converted,
|
||||
None => return Err(format!("cannot have a pointer to a zero sized type")),
|
||||
};
|
||||
|
||||
match mut_ty.mutability {
|
||||
syn::Mutability::Mutable => Type::Ptr(Box::new(converted)),
|
||||
syn::Mutability::Immutable => Type::ConstPtr(Box::new(converted)),
|
||||
})
|
||||
}
|
||||
}
|
||||
&syn::Ty::Ptr(ref mut_ty) => {
|
||||
let converted = try!(Type::convert(&mut_ty.ty));
|
||||
|
||||
Ok(match mut_ty.mutability {
|
||||
let converted = match converted {
|
||||
Some(converted) => converted,
|
||||
None => return Err(format!("cannot have a pointer to a zero sized type")),
|
||||
};
|
||||
|
||||
match mut_ty.mutability {
|
||||
syn::Mutability::Mutable => Type::Ptr(Box::new(converted)),
|
||||
syn::Mutability::Immutable => Type::ConstPtr(Box::new(converted)),
|
||||
})
|
||||
}
|
||||
}
|
||||
&syn::Ty::Path(_, ref p) => {
|
||||
let p = try!(p.convert_to_simple_single_segment());
|
||||
let (name, generics) = try!(p.convert_to_generic_single_segment());
|
||||
|
||||
if let Some(prim) = PrimitiveType::maybe(&p) {
|
||||
Ok(Type::Primitive(prim))
|
||||
if name == "PhantomData" && generics.len() == 1 {
|
||||
return Ok(None);
|
||||
} else if generics.len() != 0 {
|
||||
return Err(format!("cannot have a type with generics"));
|
||||
} else {
|
||||
Ok(Type::Path(p))
|
||||
if let Some(prim) = PrimitiveType::maybe(&name) {
|
||||
Type::Primitive(prim)
|
||||
} else {
|
||||
Type::Path(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
&syn::Ty::Array(ref ty, syn::ConstExpr::Lit(syn::Lit::Int(sz, _))) => {
|
||||
let converted = try!(Type::convert(ty));
|
||||
|
||||
Ok(Type::Array(Box::new(converted), sz))
|
||||
let converted = match converted {
|
||||
Some(converted) => converted,
|
||||
None => return Err(format!("cannot have an array of zero sized types")),
|
||||
};
|
||||
|
||||
Type::Array(Box::new(converted), sz)
|
||||
},
|
||||
&syn::Ty::BareFn(ref f) => {
|
||||
let args = try!(f.inputs.iter()
|
||||
.try_map(|x| Type::convert(&x.ty)));
|
||||
.try_skip_map(|x| Type::convert(&x.ty)));
|
||||
let ret = try!(f.output.as_type());
|
||||
|
||||
Ok(Type::FuncPtr(
|
||||
Type::FuncPtr(
|
||||
ret.map(|x| Box::new(x)),
|
||||
args,
|
||||
))
|
||||
)
|
||||
},
|
||||
&syn::Ty::Tup(ref tys) => {
|
||||
if tys.len() == 0 {
|
||||
return Ok(None);
|
||||
}
|
||||
return Err(format!("tuples are not supported as types"))
|
||||
}
|
||||
_ => Err(format!("unexpected type")),
|
||||
}
|
||||
_ => return Err(format!("unexpected type")),
|
||||
};
|
||||
|
||||
return Ok(Some(converted));
|
||||
}
|
||||
|
||||
pub fn add_deps_with_generics(&self, generic_params: &Vec<String>, library: &Library, out: &mut Vec<PathValue>) {
|
||||
@@ -286,7 +315,7 @@ impl Function {
|
||||
extern_decl: bool) -> ConvertResult<Function>
|
||||
{
|
||||
let args = try!(decl.inputs.iter()
|
||||
.try_map(|x| x.as_ident_and_type()));
|
||||
.try_skip_map(|x| x.as_ident_and_type()));
|
||||
let ret = try!(decl.output.as_type());
|
||||
|
||||
Ok(Function {
|
||||
@@ -426,15 +455,16 @@ impl Struct {
|
||||
let fields = match decl {
|
||||
&syn::VariantData::Struct(ref fields) => {
|
||||
try!(fields.iter()
|
||||
.try_map(|x| x.as_ident_and_type()))
|
||||
.try_skip_map(|x| x.as_ident_and_type()))
|
||||
}
|
||||
&syn::VariantData::Tuple(ref fields) => {
|
||||
let mut out = Vec::new();
|
||||
let mut current = 0;
|
||||
for field in fields {
|
||||
out.push((format!("{}", current),
|
||||
try!(Type::convert(&field.ty))));
|
||||
current += 1;
|
||||
if let Some(x) = try!(Type::convert(&field.ty)) {
|
||||
out.push((format!("{}", current), x));
|
||||
current += 1;
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
@@ -817,11 +847,15 @@ impl Typedef {
|
||||
pub fn convert(name: String,
|
||||
annotations: AnnotationSet,
|
||||
ty: &syn::Ty) -> ConvertResult<Typedef> {
|
||||
Ok(Typedef {
|
||||
name: name,
|
||||
annotations: annotations,
|
||||
aliased: try!(Type::convert(ty)),
|
||||
})
|
||||
if let Some(x) = try!(Type::convert(ty)) {
|
||||
Ok(Typedef {
|
||||
name: name,
|
||||
annotations: annotations,
|
||||
aliased: x,
|
||||
})
|
||||
} else {
|
||||
Err(format!("cannot have a typedef of a zero sized type"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_deps(&self, library: &Library, out: &mut Vec<PathValue>) {
|
||||
|
||||
+30
-17
@@ -13,16 +13,18 @@ pub fn find_first_some<T>(slice: &[Option<T>]) -> Option<&T> {
|
||||
}
|
||||
|
||||
pub trait IterHelpers : Iterator {
|
||||
fn try_map<F, T, E>(&mut self, f: F) -> Result<Vec<T>, E>
|
||||
where F: FnMut(&Self::Item) -> Result<T, E>;
|
||||
fn try_skip_map<F, T, E>(&mut self, f: F) -> Result<Vec<T>, E>
|
||||
where F: FnMut(&Self::Item) -> Result<Option<T>, E>;
|
||||
}
|
||||
impl<I> IterHelpers for I where I: Iterator {
|
||||
fn try_map<F, T, E>(&mut self, mut f: F) -> Result<Vec<T>, E>
|
||||
where F: FnMut(&Self::Item) -> Result<T, E>
|
||||
fn try_skip_map<F, T, E>(&mut self, mut f: F) -> Result<Vec<T>, E>
|
||||
where F: FnMut(&Self::Item) -> Result<Option<T>, E>
|
||||
{
|
||||
let mut out = Vec::new();
|
||||
while let Some(item) = self.next() {
|
||||
out.push(try!(f(&item)));
|
||||
if let Some(x) = try!(f(&item)) {
|
||||
out.push(x);
|
||||
}
|
||||
}
|
||||
Ok(out)
|
||||
}
|
||||
@@ -129,19 +131,29 @@ impl SynFnRetTyHelpers for FunctionRetTy {
|
||||
fn as_type(&self) -> ConvertResult<Option<Type>> {
|
||||
match self {
|
||||
&FunctionRetTy::Default => Ok(None),
|
||||
&FunctionRetTy::Ty(ref t) => Ok(Some(try!(Type::convert(t)))),
|
||||
&FunctionRetTy::Ty(ref t) => {
|
||||
if let Some(x) = try!(Type::convert(t)) {
|
||||
Ok(Some(x))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SynFnArgHelpers {
|
||||
fn as_ident_and_type(&self) -> ConvertResult<(String, Type)>;
|
||||
fn as_ident_and_type(&self) -> ConvertResult<Option<(String, Type)>>;
|
||||
}
|
||||
impl SynFnArgHelpers for FnArg {
|
||||
fn as_ident_and_type(&self) -> ConvertResult<(String, Type)> {
|
||||
fn as_ident_and_type(&self) -> ConvertResult<Option<(String, Type)>> {
|
||||
match self {
|
||||
&FnArg::Captured(Pat::Ident(_, ref ident, _), ref ty) => {
|
||||
Ok((ident.to_string(), try!(Type::convert(ty))))
|
||||
if let Some(x) = try!(Type::convert(ty)) {
|
||||
Ok(Some((ident.to_string(), x)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
_ => Err(format!("unexpected param type")),
|
||||
}
|
||||
@@ -149,14 +161,18 @@ impl SynFnArgHelpers for FnArg {
|
||||
}
|
||||
|
||||
pub trait SynFieldHelpers {
|
||||
fn as_ident_and_type(&self) -> ConvertResult<(String, Type)>;
|
||||
fn as_ident_and_type(&self) -> ConvertResult<Option<(String, Type)>>;
|
||||
}
|
||||
impl SynFieldHelpers for Field {
|
||||
fn as_ident_and_type(&self) -> ConvertResult<(String, Type)> {
|
||||
fn as_ident_and_type(&self) -> ConvertResult<Option<(String, Type)>> {
|
||||
let ident = try!(self.ident.as_ref().ok_or(format!("missing ident"))).clone();
|
||||
let converted_ty = try!(Type::convert(&self.ty));
|
||||
|
||||
Ok((ident.to_string(), converted_ty))
|
||||
if let Some(x) = converted_ty {
|
||||
Ok(Some((ident.to_string(), x)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,11 +216,8 @@ impl SynPathHelpers for Path {
|
||||
return Err(format!("Generic parameter contains bindings, or lifetimes"));
|
||||
}
|
||||
|
||||
let mut generics = Vec::new();
|
||||
for ty in &d.types {
|
||||
generics.push(try!(Type::convert(ty)));
|
||||
}
|
||||
generics
|
||||
try!(d.types.iter()
|
||||
.try_skip_map(|x| Type::convert(x)))
|
||||
}
|
||||
&PathParameters::Parenthesized(_) => {
|
||||
return Err(format!("Path contains parentheses"));
|
||||
|
||||
Reference in New Issue
Block a user