diff options
Diffstat (limited to 'src/bindgen/ir/ty.rs')
-rw-r--r-- | src/bindgen/ir/ty.rs | 1017 |
1 files changed, 1017 insertions, 0 deletions
diff --git a/src/bindgen/ir/ty.rs b/src/bindgen/ir/ty.rs new file mode 100644 index 0000000..5a31fb6 --- /dev/null +++ b/src/bindgen/ir/ty.rs @@ -0,0 +1,1017 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use std::borrow::Cow; +use std::io::Write; + +use syn::ext::IdentExt; + +use crate::bindgen::cdecl; +use crate::bindgen::config::{Config, Language}; +use crate::bindgen::declarationtyperesolver::DeclarationTypeResolver; +use crate::bindgen::dependencies::Dependencies; +use crate::bindgen::ir::{GenericArgument, GenericParams, GenericPath, Path}; +use crate::bindgen::library::Library; +use crate::bindgen::monomorph::Monomorphs; +use crate::bindgen::utilities::IterHelpers; +use crate::bindgen::writer::{Source, SourceWriter}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum PrimitiveType { + Void, + Bool, + Char, + SChar, + UChar, + Char32, + Float, + Double, + VaList, + PtrDiffT, + Integer { + zeroable: bool, + signed: bool, + kind: IntKind, + }, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum IntKind { + Short, + Int, + Long, + LongLong, + SizeT, + Size, + B8, + B16, + B32, + B64, +} + +impl PrimitiveType { + pub fn maybe(path: &str) -> Option<PrimitiveType> { + Some(match path { + "c_void" => PrimitiveType::Void, + "c_char" => PrimitiveType::Char, + "c_schar" => PrimitiveType::SChar, + "c_uchar" => PrimitiveType::UChar, + "c_float" => PrimitiveType::Float, + "c_double" => PrimitiveType::Double, + "ptrdiff_t" => PrimitiveType::PtrDiffT, + "VaList" => PrimitiveType::VaList, + "bool" => PrimitiveType::Bool, + "char" => PrimitiveType::Char32, + + "f32" => PrimitiveType::Float, + "f64" => PrimitiveType::Double, + + _ => { + let (kind, signed) = match path { + "c_short" => (IntKind::Short, true), + "c_int" => (IntKind::Int, true), + "c_long" => (IntKind::Long, true), + "c_longlong" => (IntKind::LongLong, true), + "ssize_t" => (IntKind::SizeT, true), + "c_ushort" => (IntKind::Short, false), + "c_uint" => (IntKind::Int, false), + "c_ulong" => (IntKind::Long, false), + "c_ulonglong" => (IntKind::LongLong, false), + "size_t" => (IntKind::SizeT, false), + "RawFd" => (IntKind::Int, true), + + "isize" | "intptr_t" => (IntKind::Size, true), + "usize" | "uintptr_t" => (IntKind::Size, false), + + "u8" | "uint8_t" => (IntKind::B8, false), + "u16" | "uint16_t" => (IntKind::B16, false), + "u32" | "uint32_t" => (IntKind::B32, false), + "u64" | "uint64_t" => (IntKind::B64, false), + "i8" | "int8_t" => (IntKind::B8, true), + "i16" | "int16_t" => (IntKind::B16, true), + "i32" | "int32_t" => (IntKind::B32, true), + "i64" | "int64_t" => (IntKind::B64, true), + _ => return None, + }; + PrimitiveType::Integer { + zeroable: true, + signed, + kind, + } + } + }) + } + + pub fn to_repr_rust(&self) -> &'static str { + match *self { + PrimitiveType::Bool => "bool", + PrimitiveType::Void => "c_void", + PrimitiveType::Char => "c_char", + PrimitiveType::SChar => "c_schar", + PrimitiveType::UChar => "c_uchar", + PrimitiveType::Char32 => "char", + PrimitiveType::Integer { + kind, + signed, + zeroable: _, + } => match kind { + IntKind::Short => { + if signed { + "c_short" + } else { + "c_ushort" + } + } + IntKind::Int => { + if signed { + "c_int" + } else { + "c_uint" + } + } + IntKind::Long => { + if signed { + "c_long" + } else { + "c_ulong" + } + } + IntKind::LongLong => { + if signed { + "c_longlong" + } else { + "c_ulonglong" + } + } + IntKind::SizeT => { + if signed { + "ssize_t" + } else { + "size_t" + } + } + IntKind::Size => { + if signed { + "isize" + } else { + "usize" + } + } + IntKind::B8 => { + if signed { + "i8" + } else { + "u8" + } + } + IntKind::B16 => { + if signed { + "i16" + } else { + "u16" + } + } + IntKind::B32 => { + if signed { + "i32" + } else { + "u32" + } + } + IntKind::B64 => { + if signed { + "i64" + } else { + "u64" + } + } + }, + PrimitiveType::Float => "f32", + PrimitiveType::Double => "f64", + PrimitiveType::PtrDiffT => "ptrdiff_t", + PrimitiveType::VaList => "va_list", + } + } + + pub fn to_repr_c(&self, config: &Config) -> &'static str { + match *self { + PrimitiveType::Void => "void", + PrimitiveType::Bool => "bool", + PrimitiveType::Char => "char", + PrimitiveType::SChar => "signed char", + PrimitiveType::UChar => "unsigned char", + // NOTE: It'd be nice to use a char32_t, but: + // + // * uchar.h is not present on mac (see #423). + // + // * char32_t isn't required to be compatible with Rust's char, as + // the C++ spec only requires it to be the same size as + // uint_least32_t, which is _not_ guaranteed to be 4-bytes. + // + PrimitiveType::Char32 => "uint32_t", + PrimitiveType::Integer { + kind, + signed, + zeroable: _, + } => match kind { + IntKind::Short => { + if signed { + "short" + } else { + "unsigned short" + } + } + IntKind::Int => { + if signed { + "int" + } else { + "unsigned int" + } + } + IntKind::Long => { + if signed { + "long" + } else { + "unsigned long" + } + } + IntKind::LongLong => { + if signed { + "long long" + } else { + "unsigned long long" + } + } + IntKind::SizeT => { + if signed { + "ssize_t" + } else { + "size_t" + } + } + IntKind::Size => { + if config.usize_is_size_t { + if signed { + "ptrdiff_t" + } else { + "size_t" + } + } else if signed { + "intptr_t" + } else { + "uintptr_t" + } + } + IntKind::B8 => { + if signed { + "int8_t" + } else { + "uint8_t" + } + } + IntKind::B16 => { + if signed { + "int16_t" + } else { + "uint16_t" + } + } + IntKind::B32 => { + if signed { + "int32_t" + } else { + "uint32_t" + } + } + IntKind::B64 => { + if signed { + "int64_t" + } else { + "uint64_t" + } + } + }, + PrimitiveType::Float => "float", + PrimitiveType::Double => "double", + PrimitiveType::PtrDiffT => "ptrdiff_t", + PrimitiveType::VaList => "va_list", + } + } + + fn can_cmp_order(&self) -> bool { + !matches!(*self, PrimitiveType::Bool) + } + + fn can_cmp_eq(&self) -> bool { + true + } +} + +/// Constant expressions. +/// +/// Used for the `U` part of `[T; U]` and const generics. We support a very +/// limited vocabulary here: only identifiers and literals. +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum ConstExpr { + Name(String), + Value(String), +} + +impl ConstExpr { + pub fn as_str(&self) -> &str { + match *self { + ConstExpr::Name(ref string) | ConstExpr::Value(ref string) => string, + } + } + + pub fn rename_for_config(&mut self, config: &Config) { + if let ConstExpr::Name(ref mut name) = self { + config.export.rename(name); + } + } + + pub fn load(expr: &syn::Expr) -> Result<Self, String> { + match *expr { + syn::Expr::Lit(syn::ExprLit { ref lit, .. }) => { + let val = match *lit { + syn::Lit::Bool(syn::LitBool { value, .. }) => value.to_string(), + syn::Lit::Int(ref len) => len.base10_digits().to_string(), + syn::Lit::Byte(ref byte) => u8::to_string(&byte.value()), + syn::Lit::Char(ref ch) => u32::to_string(&ch.value().into()), + _ => return Err(format!("can't handle const expression {:?}", lit)), + }; + Ok(ConstExpr::Value(val)) + } + syn::Expr::Path(ref path) => { + let generic_path = GenericPath::load(&path.path)?; + Ok(ConstExpr::Name(generic_path.export_name().to_owned())) + } + _ => Err(format!("can't handle const expression {:?}", expr)), + } + } + + pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> ConstExpr { + match *self { + ConstExpr::Name(ref name) => { + let path = Path::new(name); + for &(param, value) in mappings { + if path == *param { + match *value { + GenericArgument::Type(Type::Path(ref path)) + if path.is_single_identifier() => + { + // This happens when the generic argument is a path. + return ConstExpr::Name(path.name().to_string()); + } + GenericArgument::Const(ref expr) => { + return expr.clone(); + } + _ => { + // unsupported argument type - really should be an error + } + } + } + } + } + ConstExpr::Value(_) => {} + } + self.clone() + } +} + +impl Source for ConstExpr { + fn write<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) { + write!(out, "{}", self.as_str()); + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub enum Type { + Ptr { + ty: Box<Type>, + is_const: bool, + is_nullable: bool, + // FIXME: This is a bit of a hack, this is only to get us to codegen + // `T&` / `const T&`, but we should probably pass that down as an option + // to code generation or something. + is_ref: bool, + }, + Path(GenericPath), + Primitive(PrimitiveType), + Array(Box<Type>, ConstExpr), + FuncPtr { + ret: Box<Type>, + args: Vec<(Option<String>, Type)>, + is_nullable: bool, + never_return: bool, + }, +} + +impl Type { + pub fn const_ref_to(ty: &Self) -> Self { + Type::Ptr { + ty: Box::new(ty.clone()), + is_const: true, + is_nullable: false, + is_ref: true, + } + } + + pub fn load_from_output(output: &syn::ReturnType) -> Result<(Type, bool), String> { + let mut never_return = false; + let ty = match output { + syn::ReturnType::Default => Type::Primitive(PrimitiveType::Void), + syn::ReturnType::Type(_, ref ty) => { + if let syn::Type::Never(_) = ty.as_ref() { + never_return = true; + Type::Primitive(PrimitiveType::Void) + } else { + Type::load(ty)?.unwrap_or(Type::Primitive(PrimitiveType::Void)) + } + } + }; + Ok((ty, never_return)) + } + + pub fn load(ty: &syn::Type) -> Result<Option<Type>, String> { + let converted = match *ty { + syn::Type::Reference(ref reference) => { + let converted = Type::load(&reference.elem)?; + + let converted = match converted { + Some(converted) => converted, + None => Type::Primitive(PrimitiveType::Void), + }; + + // TODO(emilio): we could make these use is_ref: true. + let is_const = reference.mutability.is_none(); + Type::Ptr { + ty: Box::new(converted), + is_const, + is_nullable: false, + is_ref: false, + } + } + syn::Type::Ptr(ref pointer) => { + let converted = Type::load(&pointer.elem)?; + + let converted = match converted { + Some(converted) => converted, + None => Type::Primitive(PrimitiveType::Void), + }; + + let is_const = pointer.mutability.is_none(); + Type::Ptr { + ty: Box::new(converted), + is_const, + is_nullable: true, + is_ref: false, + } + } + syn::Type::Path(ref path) => { + let generic_path = GenericPath::load(&path.path)?; + + if generic_path.name() == "PhantomData" || generic_path.name() == "PhantomPinned" { + return Ok(None); + } + + if let Some(prim) = PrimitiveType::maybe(generic_path.name()) { + if !generic_path.generics().is_empty() { + return Err("Primitive has generics.".to_owned()); + } + Type::Primitive(prim) + } else { + Type::Path(generic_path) + } + } + syn::Type::Array(syn::TypeArray { + ref elem, ref len, .. + }) => { + let converted = Type::load(elem)?; + + let converted = match converted { + Some(converted) => converted, + None => return Err("Cannot have an array of zero sized types.".to_owned()), + }; + + let len = ConstExpr::load(len)?; + Type::Array(Box::new(converted), len) + } + syn::Type::BareFn(ref function) => { + let mut wildcard_counter = 0; + let args = function.inputs.iter().try_skip_map(|x| { + Type::load(&x.ty).map(|opt_ty| { + opt_ty.map(|ty| { + ( + x.name.as_ref().map(|(ref ident, _)| { + if ident == "_" { + wildcard_counter += 1; + if wildcard_counter == 1 { + "_".to_owned() + } else { + format!("_{}", wildcard_counter - 1) + } + } else { + ident.unraw().to_string() + } + }), + ty, + ) + }) + }) + })?; + let (ret, never_return) = Type::load_from_output(&function.output)?; + Type::FuncPtr { + ret: Box::new(ret), + args, + is_nullable: false, + never_return, + } + } + syn::Type::Tuple(ref tuple) => { + if tuple.elems.is_empty() { + return Ok(None); + } + return Err("Tuples are not supported types.".to_owned()); + } + syn::Type::Verbatim(ref tokens) if tokens.to_string() == "..." => { + Type::Primitive(PrimitiveType::VaList) + } + _ => return Err(format!("Unsupported type: {:?}", ty)), + }; + + Ok(Some(converted)) + } + + pub fn is_ptr(&self) -> bool { + matches!(*self, Type::Ptr { .. } | Type::FuncPtr { .. }) + } + + pub fn is_primitive_or_ptr_primitive(&self) -> bool { + match *self { + Type::Primitive(..) => true, + Type::Ptr { ref ty, .. } => matches!(ty.as_ref(), Type::Primitive(..)), + _ => false, + } + } + + pub fn make_zeroable(&self) -> Option<Self> { + let (kind, signed) = match *self { + Type::Primitive(PrimitiveType::Integer { + zeroable: false, + kind, + signed, + }) => (kind, signed), + _ => return None, + }; + + Some(Type::Primitive(PrimitiveType::Integer { + kind, + signed, + zeroable: true, + })) + } + + pub fn make_nullable(&self) -> Option<Self> { + match *self { + Type::Ptr { + ref ty, + is_const, + is_ref, + is_nullable: false, + } => Some(Type::Ptr { + ty: ty.clone(), + is_const, + is_ref, + is_nullable: true, + }), + Type::FuncPtr { + ref ret, + ref args, + is_nullable: false, + never_return, + } => Some(Type::FuncPtr { + ret: ret.clone(), + args: args.clone(), + is_nullable: true, + never_return, + }), + _ => None, + } + } + + fn nonzero_to_primitive(&self) -> Option<Self> { + let path = match *self { + Type::Path(ref p) => p, + _ => return None, + }; + + if !path.generics().is_empty() { + return None; + } + + let name = path.name(); + if !name.starts_with("NonZero") { + return None; + } + + let (kind, signed) = match path.name() { + "NonZeroU8" => (IntKind::B8, false), + "NonZeroU16" => (IntKind::B16, false), + "NonZeroU32" => (IntKind::B32, false), + "NonZeroU64" => (IntKind::B64, false), + "NonZeroUSize" => (IntKind::Size, false), + "NonZeroI8" => (IntKind::B8, true), + "NonZeroI16" => (IntKind::B16, true), + "NonZeroI32" => (IntKind::B32, true), + "NonZeroI64" => (IntKind::B64, true), + "NonZeroISize" => (IntKind::Size, true), + _ => return None, + }; + + Some(Type::Primitive(PrimitiveType::Integer { + zeroable: false, + signed, + kind, + })) + } + + fn simplified_type(&self, config: &Config) -> Option<Self> { + let path = match *self { + Type::Path(ref p) => p, + _ => return None, + }; + + if path.generics().is_empty() { + return self.nonzero_to_primitive(); + } + + if path.generics().len() != 1 { + return None; + } + + let unsimplified_generic = match path.generics()[0] { + GenericArgument::Type(ref ty) => ty, + GenericArgument::Const(_) => return None, + }; + + let generic = match unsimplified_generic.simplified_type(config) { + Some(generic) => Cow::Owned(generic), + None => Cow::Borrowed(unsimplified_generic), + }; + match path.name() { + "Option" => { + if let Some(nullable) = generic.make_nullable() { + return Some(nullable); + } + if let Some(zeroable) = generic.make_zeroable() { + return Some(zeroable); + } + None + } + "NonNull" => Some(Type::Ptr { + ty: Box::new(generic.into_owned()), + is_const: false, + is_nullable: false, + is_ref: false, + }), + "Box" if config.language != Language::Cxx => Some(Type::Ptr { + ty: Box::new(generic.into_owned()), + is_const: false, + is_nullable: false, + is_ref: false, + }), + "Cell" => Some(generic.into_owned()), + "ManuallyDrop" | "MaybeUninit" | "Pin" if config.language != Language::Cxx => { + Some(generic.into_owned()) + } + _ => None, + } + } + + pub fn simplify_standard_types(&mut self, config: &Config) { + self.visit_types(|ty| ty.simplify_standard_types(config)); + if let Some(ty) = self.simplified_type(config) { + *self = ty; + } + } + + pub fn replace_self_with(&mut self, self_ty: &Path) { + if let Type::Path(ref mut generic_path) = *self { + generic_path.replace_self_with(self_ty); + } + self.visit_types(|ty| ty.replace_self_with(self_ty)) + } + + fn visit_types(&mut self, mut visitor: impl FnMut(&mut Type)) { + match *self { + Type::Array(ref mut ty, ..) | Type::Ptr { ref mut ty, .. } => visitor(ty), + Type::Path(ref mut path) => { + for generic in path.generics_mut() { + match *generic { + GenericArgument::Type(ref mut ty) => visitor(ty), + GenericArgument::Const(_) => {} + } + } + } + Type::Primitive(..) => {} + Type::FuncPtr { + ref mut ret, + ref mut args, + .. + } => { + visitor(ret); + for arg in args { + visitor(&mut arg.1) + } + } + } + } + + pub fn get_root_path(&self) -> Option<Path> { + let mut current = self; + loop { + match *current { + Type::Ptr { ref ty, .. } => current = ty, + Type::Path(ref generic) => { + return Some(generic.path().clone()); + } + Type::Primitive(..) => { + return None; + } + Type::Array(..) => { + return None; + } + Type::FuncPtr { .. } => { + return None; + } + }; + } + } + + pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> Type { + match *self { + Type::Ptr { + ref ty, + is_const, + is_nullable, + is_ref, + } => Type::Ptr { + ty: Box::new(ty.specialize(mappings)), + is_const, + is_nullable, + is_ref, + }, + Type::Path(ref generic_path) => { + for &(param, value) in mappings { + if generic_path.path() == param { + if let GenericArgument::Type(ref ty) = *value { + return ty.clone(); + } + } + } + + let specialized = GenericPath::new( + generic_path.path().clone(), + generic_path + .generics() + .iter() + .map(|x| x.specialize(mappings)) + .collect(), + ); + Type::Path(specialized) + } + Type::Primitive(ref primitive) => Type::Primitive(primitive.clone()), + Type::Array(ref ty, ref constant) => Type::Array( + Box::new(ty.specialize(mappings)), + constant.specialize(mappings), + ), + Type::FuncPtr { + ref ret, + ref args, + is_nullable, + never_return, + } => Type::FuncPtr { + ret: Box::new(ret.specialize(mappings)), + args: args + .iter() + .cloned() + .map(|(name, ty)| (name, ty.specialize(mappings))) + .collect(), + is_nullable, + never_return, + }, + } + } + + pub fn add_dependencies_ignoring_generics( + &self, + generic_params: &GenericParams, + library: &Library, + out: &mut Dependencies, + ) { + match *self { + Type::Ptr { ref ty, .. } => { + ty.add_dependencies_ignoring_generics(generic_params, library, out); + } + Type::Path(ref generic) => { + for generic_value in generic.generics() { + if let GenericArgument::Type(ref ty) = *generic_value { + ty.add_dependencies_ignoring_generics(generic_params, library, out); + } + } + let path = generic.path(); + if !generic_params.iter().any(|param| param.name() == path) { + if let Some(items) = library.get_items(path) { + if !out.items.contains(path) { + out.items.insert(path.clone()); + + for item in &items { + item.deref().add_dependencies(library, out); + } + for item in items { + out.order.push(item); + } + } + } else { + warn!( + "Can't find {}. This usually means that this type was incompatible or \ + not found.", + path + ); + } + } + } + Type::Primitive(_) => {} + Type::Array(ref ty, _) => { + ty.add_dependencies_ignoring_generics(generic_params, library, out); + } + Type::FuncPtr { + ref ret, ref args, .. + } => { + ret.add_dependencies_ignoring_generics(generic_params, library, out); + for (_, ref arg) in args { + arg.add_dependencies_ignoring_generics(generic_params, library, out); + } + } + } + } + + pub fn add_dependencies(&self, library: &Library, out: &mut Dependencies) { + self.add_dependencies_ignoring_generics(&GenericParams::default(), library, out) + } + + pub fn add_monomorphs(&self, library: &Library, out: &mut Monomorphs) { + match *self { + Type::Ptr { ref ty, .. } => { + ty.add_monomorphs(library, out); + } + Type::Path(ref generic) => { + if generic.generics().is_empty() || out.contains(generic) { + return; + } + let path = generic.path(); + if let Some(items) = library.get_items(path) { + for item in items { + item.deref() + .instantiate_monomorph(generic.generics(), library, out); + } + } + } + Type::Primitive(_) => {} + Type::Array(ref ty, _) => { + ty.add_monomorphs(library, out); + } + Type::FuncPtr { + ref ret, ref args, .. + } => { + ret.add_monomorphs(library, out); + for (_, ref arg) in args { + arg.add_monomorphs(library, out); + } + } + } + } + + pub fn rename_for_config(&mut self, config: &Config, generic_params: &GenericParams) { + match *self { + Type::Ptr { ref mut ty, .. } => { + ty.rename_for_config(config, generic_params); + } + Type::Path(ref mut ty) => { + ty.rename_for_config(config, generic_params); + } + Type::Primitive(_) => {} + Type::Array(ref mut ty, ref mut len) => { + ty.rename_for_config(config, generic_params); + len.rename_for_config(config); + } + Type::FuncPtr { + ref mut ret, + ref mut args, + .. + } => { + ret.rename_for_config(config, generic_params); + for (_, arg) in args { + arg.rename_for_config(config, generic_params); + } + } + } + } + + pub fn resolve_declaration_types(&mut self, resolver: &DeclarationTypeResolver) { + match *self { + Type::Ptr { ref mut ty, .. } => { + ty.resolve_declaration_types(resolver); + } + Type::Path(ref mut generic_path) => { + generic_path.resolve_declaration_types(resolver); + } + Type::Primitive(_) => {} + Type::Array(ref mut ty, _) => { + ty.resolve_declaration_types(resolver); + } + Type::FuncPtr { + ref mut ret, + ref mut args, + .. + } => { + ret.resolve_declaration_types(resolver); + for (_, ref mut arg) in args { + arg.resolve_declaration_types(resolver); + } + } + } + } + + pub fn mangle_paths(&mut self, monomorphs: &Monomorphs) { + match *self { + Type::Ptr { ref mut ty, .. } => { + ty.mangle_paths(monomorphs); + } + Type::Path(ref mut generic_path) => { + if generic_path.generics().is_empty() { + return; + } + + if let Some(mangled_path) = monomorphs.mangle_path(generic_path) { + *generic_path = GenericPath::new(mangled_path.clone(), vec![]); + } else { + warn!( + "Cannot find a mangling for generic path {:?}. This usually means that a \ + type referenced by this generic was incompatible or not found.", + generic_path + ); + } + } + Type::Primitive(_) => {} + Type::Array(ref mut ty, _) => { + ty.mangle_paths(monomorphs); + } + Type::FuncPtr { + ref mut ret, + ref mut args, + .. + } => { + ret.mangle_paths(monomorphs); + for (_, ref mut arg) in args { + arg.mangle_paths(monomorphs); + } + } + } + } + + pub fn can_cmp_order(&self) -> bool { + match *self { + // FIXME: Shouldn't this look at ty.can_cmp_order() as well? + Type::Ptr { is_ref, .. } => !is_ref, + Type::Path(..) => true, + Type::Primitive(ref p) => p.can_cmp_order(), + Type::Array(..) => false, + Type::FuncPtr { .. } => false, + } + } + + pub fn can_cmp_eq(&self) -> bool { + match *self { + Type::Ptr { ref ty, is_ref, .. } => !is_ref || ty.can_cmp_eq(), + Type::Path(..) => true, + Type::Primitive(ref p) => p.can_cmp_eq(), + Type::Array(..) => false, + Type::FuncPtr { .. } => true, + } + } +} + +impl Source for String { + fn write<F: Write>(&self, _config: &Config, out: &mut SourceWriter<F>) { + write!(out, "{}", self); + } +} + +impl Source for Type { + fn write<F: Write>(&self, config: &Config, out: &mut SourceWriter<F>) { + cdecl::write_type(out, self, config); + } +} |