extern crate std;
use std::rc::Rc;
use syn;
use syn::TypeParamBound;
#[derive(Clone, Debug)]
pub enum RustType<'e>
{
Ident( &'e syn::Ident ),
Void,
Wrapper( &'e syn::Ident, Rc< TypeInfo<'e> > ),
}
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug)]
pub enum PassBy
{
Value,
Reference,
Ptr,
}
#[derive(Clone, Debug)]
pub struct TypeInfo<'s>
{
pub rust_type: RustType<'s>,
pub pass_by: PassBy,
pub is_mutable: bool,
pub array_length: Option<&'s syn::Expr>,
pub original: &'s syn::Type,
}
pub fn parse<'a, 'b: 'a>(
ty: &'b syn::Type,
) -> Option<TypeInfo<'a>>
{
let resolver = TypeInfoResolver::from_type( ty )?;
Some( TypeInfo::from_resolver( resolver, ty ) )
}
struct TypeInfoResolver<'s>
{
rust_type: RustType<'s>,
pass_by: Option<PassBy>,
is_mutable: Option<bool>,
array_length: Option<&'s syn::Expr>
}
impl<'s, 'p: 's> TypeInfo<'s> {
pub fn get_name(
&self
) -> String
{
match self.rust_type {
RustType::Wrapper( wrapper, _ ) => format!( "{}", wrapper ),
ref t => format!( "{}", t ),
}
}
pub fn get_leaf(
&self
) -> &TypeInfo<'s>
{
match self.rust_type {
RustType::Wrapper( _, ref wrappee ) => wrappee.get_leaf(),
_ => self
}
}
fn from_resolver(
resolver: TypeInfoResolver<'p>,
original: &'p syn::Type,
) -> TypeInfo<'s>
{
let pass_by = resolver.pass_by.unwrap_or( PassBy::Value );
let is_mutable = resolver.is_mutable.unwrap_or( false );
TypeInfo{
rust_type: resolver.rust_type,
pass_by,
is_mutable,
array_length: resolver.array_length,
original,
}
}
}
impl<'s> std::fmt::Display for RustType<'s> {
fn fmt(
&self,
f: &mut std::fmt::Formatter
) -> std::fmt::Result {
match *self {
RustType::Ident( syn_ident ) => write!( f, "{}", syn_ident ),
RustType::Void => write!( f, "void" ),
RustType::Wrapper( wrapper, ref wrapped ) => write!( f, "{}<{}>",
wrapper, wrapped.rust_type )
}
}
}
impl<'s, 'p: 's> TypeInfoResolver<'s> {
fn from_type(
syn_type: &'p syn::Type,
) -> Option<TypeInfoResolver<'s>>
{
match *syn_type {
syn::Type::Slice( ref slice ) => TypeInfoResolver::from_slice( slice ),
syn::Type::Reference( ref reference ) => TypeInfoResolver::from_reference( reference ),
syn::Type::Ptr( ref ptr ) => TypeInfoResolver::from_pointer( ptr ),
syn::Type::Array( ref arr ) => TypeInfoResolver::from_array( arr ),
syn::Type::Path( ref p ) => TypeInfoResolver::from_path( p ),
syn::Type::Tuple( ref t ) if t.elems.is_empty() => Some( TypeInfoResolver::void() ),
syn::Type::TraitObject( ref trait_object ) =>
TypeInfoResolver::from_trait_object( trait_object ),
syn::Type::BareFn(..)
| syn::Type::Never(..)
| syn::Type::Tuple(..)
| syn::Type::ImplTrait(..)
| syn::Type::Paren(..)
| syn::Type::Infer(..)
| syn::Type::Macro(..)
| syn::Type::Verbatim(..)
| syn::Type::Group(..)
=> { dbg!( syn_type ); None },
}
}
fn new(
rust_type: RustType<'s>
) -> TypeInfoResolver<'s>
{
TypeInfoResolver {
rust_type,
pass_by: None,
is_mutable: None,
array_length: None,
}
}
fn void() -> TypeInfoResolver<'s>
{
TypeInfoResolver::new( RustType::Void )
}
fn pass_by(
resolver: TypeInfoResolver<'s>,
pass_by: PassBy,
) -> TypeInfoResolver<'s>
{
if resolver.pass_by.is_some() {
panic!("Cannot set pass_by twice.")
}
TypeInfoResolver {
rust_type: resolver.rust_type,
pass_by: Some( pass_by ),
is_mutable: resolver.is_mutable,
array_length: resolver.array_length,
}
}
fn mutable(
resolver: TypeInfoResolver<'s>,
is_mutable: bool,
) -> TypeInfoResolver<'s>
{
if resolver.is_mutable.is_some() {
panic!("Cannot set is_mutable twice.")
}
TypeInfoResolver {
rust_type: resolver.rust_type,
pass_by: resolver.pass_by,
is_mutable: Some( is_mutable ),
array_length: resolver.array_length,
}
}
fn array(
resolver: TypeInfoResolver<'s>,
array_length: &'p syn::Expr,
) -> TypeInfoResolver<'s>
{
if resolver.array_length.is_some() {
panic!("Cannot set array_length twice.")
}
TypeInfoResolver {
rust_type: resolver.rust_type,
pass_by: resolver.pass_by,
is_mutable: resolver.is_mutable,
array_length: Some( array_length ),
}
}
fn wrapped(
resolver: &TypeInfoResolver<'s>,
args: &'p syn::punctuated::Punctuated< syn::GenericArgument, syn::token::Comma >,
) -> Option<TypeInfoResolver<'s>>
{
if let RustType::Wrapper( _, _ ) = resolver.rust_type {
panic!("Nested wrappers are not allowed.")
}
let nested_type = match **args.first().unwrap().value() {
syn::GenericArgument::Type( ref t ) => t,
_ => return None,
};
let nested_type = TypeInfo::from_resolver(
TypeInfoResolver::from_type( nested_type )?, nested_type );
Some( TypeInfoResolver {
rust_type: RustType::Wrapper(
resolver.get_ident_for_wrapping(), Rc::new( nested_type ) ),
pass_by: resolver.pass_by,
is_mutable: resolver.is_mutable,
array_length: resolver.array_length,
} )
}
fn from_array(
array: &'p syn::TypeArray,
) -> Option<TypeInfoResolver<'s>>
{
let resolver = TypeInfoResolver::from_type( &array.elem )?;
Some( TypeInfoResolver::array( resolver, &array.len ) )
}
fn from_slice(
slice: &'p syn::TypeSlice,
) -> Option<TypeInfoResolver<'s>>
{
TypeInfoResolver::from_type( &slice.elem )
}
fn from_reference(
reference : &'p syn::TypeReference,
) -> Option<TypeInfoResolver<'s>>
{
let resolver = TypeInfoResolver::from_type( &reference.elem )?;
let resolver = TypeInfoResolver::mutable( resolver,
TypeInfoResolver::is_mutable( reference.mutability ) );
Some( TypeInfoResolver::pass_by( resolver, PassBy::Reference ) )
}
fn from_pointer(
ptr : &'p syn::TypePtr,
) -> Option<TypeInfoResolver<'s>>
{
let resolver = TypeInfoResolver::from_type( &ptr.elem )?;
let resolver = TypeInfoResolver::mutable( resolver,
TypeInfoResolver::is_mutable( ptr.mutability ) );
Some( TypeInfoResolver::pass_by( resolver, PassBy::Ptr ) )
}
fn from_path(
type_path: &'p syn::TypePath,
) -> Option<TypeInfoResolver<'s>>
{
TypeInfoResolver::from_segment( type_path.path.segments.last().unwrap().value() )
}
fn from_segment(
segment: &'p syn::PathSegment,
) -> Option<TypeInfoResolver<'s>>
{
let rust_type = format!( "{}", segment.ident );
let args = match segment.arguments {
syn::PathArguments::None
=> None,
syn::PathArguments::AngleBracketed( ref data )
=> Some( &data.args ),
syn::PathArguments::Parenthesized( .. )
=> panic!( "Fn-types are unsupported." ),
};
match rust_type.as_str() {
"ComRc" | "ComItf" | "ComResult" | "InterfacePtr"
=> TypeInfoResolver::wrapped(
&TypeInfoResolver::new( RustType::Ident( &segment.ident ) ),
args.expect( "Wrapper types requires valid wrappee.")
),
_t => Some( TypeInfoResolver::new( RustType::Ident( &segment.ident ) ) ),
}
}
fn from_trait_object(
trait_object: &'p syn::TypeTraitObject,
) -> Option<TypeInfoResolver<'s>>
{
let trait_bound = trait_object.bounds.iter().find_map( |parameter: &TypeParamBound|
if let syn::TypeParamBound::Trait( ref tr ) = parameter { Some( tr ) }
else { None } )?;
TypeInfoResolver::from_segment( trait_bound.path.segments.last().unwrap().value() )
}
fn is_mutable(
mutability: Option<syn::token::Mut>
) -> bool
{
mutability.is_some()
}
fn get_ident_for_wrapping(
&self
) -> &'s syn::Ident
{
match self.rust_type
{
RustType::Ident( ident ) => ident,
_ => panic!( "Only identifiers can wrap other rust types." ),
}
}
}