Improve support for zero sized types

This commit is contained in:
Ryan Hunt
2017-05-13 22:23:18 -04:00
parent efe4af7fb3
commit b36cc69274
2 changed files with 90 additions and 43 deletions
+60 -26
View File
@@ -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
View File
@@ -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"));