<commit_before>
use ::prelude::*;
use std::rc::Rc;
use syn::*;

use ast_converters::*;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Direction { In, Out, Retval }

pub struct TypeConversion {

    /// Possible temporary values that need to be kept alive for the duration
    /// of the conversion result usage.
    pub temporary: Option<TokenStream>,

    /// Conversion result value. Possibly referencing the temporary value.
    pub value : TokenStream,
}

#[derive(PartialEq, Eq, Debug, Hash)]
pub struct ModelTypeSystemConfig {
    pub effective_system : ModelTypeSystem,
    pub is_default : bool,
}

impl ModelTypeSystemConfig {
    pub fn get_unique_name( &self, base : &str ) -> String {
        match self.is_default {
            true => base.to_string(),
            false => format!( "{}_{:?}", base, self.effective_system ),
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
pub enum ModelTypeSystem {

    /// COM Automation compatible type system.
    Automation,

    /// Raw type system.
    Raw,
}

impl ModelTypeSystem {

    /// Converts the model type system into public type system tokens.
    pub fn as_typesystem_tokens( self ) -> TokenStream {
        match self {
            ModelTypeSystem::Automation =>
                    quote!( ::intercom::TypeSystem::Automation ),
            ModelTypeSystem::Raw =>
                    quote!( ::intercom::TypeSystem::Raw ),
        }
    }
}

/// Type usage context.
pub struct TypeContext {
    type_system: ModelTypeSystem,
}

impl TypeContext {
    pub fn new( type_system : ModelTypeSystem ) -> TypeContext {
        TypeContext { type_system }
    }
}

/// Defines Type-specific logic for handling the various parameter types in the
/// Rust/COM interface.
pub trait TypeHandler {

    /// The Rust type.
    fn rust_ty( &self ) -> Type;

    /// The COM type.
    fn com_ty( &self, _dir: Direction ) -> Type
    {
        self.rust_ty()
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self,
        ident : &Ident,
        _dir: Direction,
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() ),
        }
    }

    /// Converts a Rust parameter named by the ident into a COM type.
    fn rust_to_com(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() )
        }
    }

    /// Gets the default value for the type.
    fn default_value( &self ) -> TokenStream
    {
        match self.rust_ty() {
            Type::Path( ref p ) => {
                let ident = p.path.get_ident().unwrap();
                let name = ident.to_string();
                match name.as_ref() {
                    "RawComPtr" => quote!( ::std::ptr::null_mut() ),
                    _ => quote!( Default::default() )
                }
            },
            Type::Ptr( .. ) => quote!( ::std::ptr::null_mut() ),
            _ => quote!( Default::default() )
        }
    }
}

/// Identity parameter handler.
///
/// No special logic.
struct IdentityParam( Type );

impl TypeHandler for IdentityParam {
    fn rust_ty( &self ) -> Type { self.0.clone() }
}

/// `ComItf` parameter handler. Supports `ComItf` Rust type and ensures the this
/// to/from `RawComPtr` COM type.
struct ComItfParam { ty: Type, context: TypeContext }

impl TypeHandler for ComItfParam {

    fn rust_ty( &self ) -> Type { self.ty.clone() }

    /// The COM type.
    fn com_ty( &self, _dir: Direction ) -> Type
    {
        let rust_ty = self.rust_ty();

        // Extract the interface type T from the ComItf<T> type definition
        use syn;
        let itf_ty = match rust_ty {
            syn::Type::Path( path ) =>
                match path.path.segments.last().unwrap().value().arguments {
                    syn::PathArguments::AngleBracketed( ref ab ) =>
                            match ab.args.last().unwrap().value() {
                                syn::GenericArgument::Type( ref t ) => t.clone(),
                                _ => panic!( "ComItf generic argument must be type" ),
                            },
                    _ => panic!( "ComItf type parameter must be angle bracketed" ),
                },
            _ => panic!( "ComItf type parameter must be a type path" ),
        };

        // Construct the final InterfacePtr<T> type.
        parse_quote!( ::intercom::raw::InterfacePtr< #itf_ty > )
    }

    fn default_value( &self ) -> TokenStream
    {
        quote!( ::intercom::raw::InterfacePtr::new( ::std::ptr::null_mut() ) )
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        let ts = self.context.type_system.as_typesystem_tokens();
        TypeConversion {
            temporary: None,
            value: quote!( ::intercom::ComItf::wrap( #ident, #ts ) ),
        }
    }

    /// Converts a Rust parameter named by the ident into a COM type.
    fn rust_to_com(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        let ts = self.context.type_system.as_typesystem_tokens();
        TypeConversion {
            temporary: None,
            value: quote!( ::intercom::ComItf::ptr( &#ident.into(), #ts ) )
        }
    }
}

/// `bool` parameter handler. Supports `VARIANT_BOOL` for automation type system.
struct BoolParam { context: TypeContext }

impl TypeHandler for BoolParam {

    fn rust_ty( &self ) -> Type { parse_quote!( bool ) }

    /// The COM type.
    fn com_ty( &self, _dir: Direction ) -> Type
    {
        match self.context.type_system {
            ModelTypeSystem::Automation => parse_quote!( ::intercom::raw::VariantBool ),
            ModelTypeSystem::Raw => parse_quote!( bool ),
        }
    }

    fn default_value( &self ) -> TokenStream
    {
        match self.context.type_system {
            ModelTypeSystem::Automation => quote!( false.into() ),
            ModelTypeSystem::Raw => quote!( false ),
        }
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() )
        }
    }

    /// Converts a Rust parameter named by the ident into a COM type.
    fn rust_to_com(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() )
        }
    }
}

/// `Variant` parameter handler. Supports `VARIANT` for automation type system.
struct VariantParam { ty: Type }

impl TypeHandler for VariantParam {

    fn rust_ty( &self ) -> Type { self.ty.clone() }

    /// The COM type.
    fn com_ty( &self, _dir: Direction ) -> Type
    {
        parse_quote!( ::intercom::raw::Variant )
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() )
        }
    }

    /// Converts a Rust parameter named by the ident into a COM type.
    fn rust_to_com(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.com_into()? )
        }
    }
}

/// String parameter handler. Converts between Rust String and COM BSTR types.
struct StringParam { ty: Type, context: TypeContext }
impl TypeHandler for StringParam
{
    fn rust_ty( &self ) -> Type { self.ty.clone() }

    fn com_ty( &self, dir: Direction ) -> Type
    {
        match self.context.type_system {
            ModelTypeSystem::Automation => match dir {
                Direction::In => parse_quote!( ::intercom::raw::InBSTR ),
                Direction::Out | Direction::Retval => parse_quote!( ::intercom::raw::OutBSTR ),
            },
            ModelTypeSystem::Raw => match dir {
                Direction::In => parse_quote!( ::intercom::raw::InCStr ),
                Direction::Out | Direction::Retval => parse_quote!( ::intercom::raw::OutCStr ),
            },
        }
    }

    fn com_to_rust( &self, ident : &Ident, dir: Direction ) -> TypeConversion
    {
        match dir {

            Direction::In => {

                let str_type = match self.context.type_system {
                    ModelTypeSystem::Automation => quote!( BStr ),
                    ModelTypeSystem::Raw => quote!( CStr ),
                };

                let target_ty = self.rust_ty();
                let intermediate_ty = quote!( &::intercom::#str_type );
                let to_intermediate = quote!( ::intercom::#str_type::from_ptr( #ident ) );
                let as_trait = quote!( < #target_ty as ::intercom::FromWithTemporary< #intermediate_ty > > );

                let temp_ident = Ident::new( &format!( "__{}_temporary", ident.to_string() ), Span::call_site() );
                TypeConversion {
                    temporary: Some( quote!( let mut #temp_ident = #as_trait::to_temporary( #to_intermediate )?; ) ),
                    value: quote!( #as_trait::from_temporary( &mut #temp_ident )? ),
                }
            },
            Direction::Out | Direction::Retval => {

                // The type system input 'ident' should represent either a BString or CString
                // depending on the type system.
                let str_type = match self.context.type_system {
                    ModelTypeSystem::Automation => quote!( BString::from_ptr ),
                    ModelTypeSystem::Raw => quote!( CString::from_raw ),
                };

                // Get the type system string as Rust string.
                let ts_string = quote!( ::intercom::#str_type( #ident ) );

                // Convert the TS string into whatever string type the method requires.
                TypeConversion {
                    temporary: None,
                    value: quote!( #ts_string.com_into()? ),
                }
            },
        }
    }

    fn rust_to_com( &self, ident : &Ident, dir: Direction ) -> TypeConversion
    {
        match dir {

            Direction::In => {

                let str_type = match self.context.type_system {
                    ModelTypeSystem::Automation => quote!( BStr ),
                    ModelTypeSystem::Raw => quote!( CStr ),
                };

                let target_ty = self.rust_ty();
                let intermediate_ty = quote!( &::intercom::#str_type );
                let as_trait = quote!( < #intermediate_ty as ::intercom::FromWithTemporary< #target_ty > > );

                let temp_ident = Ident::new( &format!( "__{}_temporary", ident.to_string() ), Span::call_site() );
                TypeConversion {
                    temporary: Some( quote!( let mut #temp_ident = #as_trait::to_temporary( #ident )?; ) ),
                    value: quote!( #as_trait::from_temporary( &mut #temp_ident )?.as_ptr() ),
                }
            },
            Direction::Out | Direction::Retval => {

                // The Rust string value `ident` must be first converted into a type system
                // compatible Rust string, either BString or CSTring.
                // depending on the type system.
                let str_type = match self.context.type_system {
                    ModelTypeSystem::Automation => quote!( BString ),
                    ModelTypeSystem::Raw => quote!( CString ),
                };

                // Convert the `ident` into the required string type.
                let ts_string = quote!( ::intercom::ComInto::< ::intercom::#str_type >::com_into( #ident )? );

                TypeConversion {
                    temporary: None,
                    value: match self.context.type_system {
                        ModelTypeSystem::Automation =>
                            quote!( #ts_string.into_ptr() ),
                        ModelTypeSystem::Raw =>
                            quote!( #ts_string.into_raw() ),
                    }
                }
            },
        }
    }

    fn default_value( &self ) -> TokenStream
    {
        quote!( ::std::ptr::null_mut() )
    }
}

/// Resolves the `TypeHandler` to use.
pub fn get_ty_handler(
    arg_ty : &Type,
    context : TypeContext,
) -> Rc<dyn TypeHandler>
{
    let type_info = ::type_parser::parse( arg_ty )
            .unwrap_or_else( || panic!( "Type {:?} could not be parsed.", arg_ty ) );

    map_by_name(
            type_info.get_name().as_ref(), type_info.original.clone(),
            context )
}

/// Selects type handler based on the name of the type.
fn map_by_name(
    name: &str,
    original_type: Type,
    context: TypeContext,
) -> Rc<dyn TypeHandler> {

    match name {

        "ComItf" => Rc::new( ComItfParam { ty: original_type, context } ),
        "CString" | "CStr" | "BString" | "BStr" | "String" | "str" =>
            Rc::new( StringParam { ty: original_type, context } ),
        "bool" =>
            Rc::new( BoolParam { context } ),
        "Variant" =>
            Rc::new( VariantParam { ty: original_type } ),
        // "str" => Rc::new( StringRefParam( original_type ) ),

        // Unknown. Use IdentityParam.
        _ => Rc::new( IdentityParam( original_type ) )
    }

}
<commit_msg>Removed unnecessary "use" statement<commit_after>
use ::prelude::*;
use std::rc::Rc;
use syn::*;

use ast_converters::*;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Direction { In, Out, Retval }

pub struct TypeConversion {

    /// Possible temporary values that need to be kept alive for the duration
    /// of the conversion result usage.
    pub temporary: Option<TokenStream>,

    /// Conversion result value. Possibly referencing the temporary value.
    pub value : TokenStream,
}

#[derive(PartialEq, Eq, Debug, Hash)]
pub struct ModelTypeSystemConfig {
    pub effective_system : ModelTypeSystem,
    pub is_default : bool,
}

impl ModelTypeSystemConfig {
    pub fn get_unique_name( &self, base : &str ) -> String {
        match self.is_default {
            true => base.to_string(),
            false => format!( "{}_{:?}", base, self.effective_system ),
        }
    }
}

#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
pub enum ModelTypeSystem {

    /// COM Automation compatible type system.
    Automation,

    /// Raw type system.
    Raw,
}

impl ModelTypeSystem {

    /// Converts the model type system into public type system tokens.
    pub fn as_typesystem_tokens( self ) -> TokenStream {
        match self {
            ModelTypeSystem::Automation =>
                    quote!( ::intercom::TypeSystem::Automation ),
            ModelTypeSystem::Raw =>
                    quote!( ::intercom::TypeSystem::Raw ),
        }
    }
}

/// Type usage context.
pub struct TypeContext {
    type_system: ModelTypeSystem,
}

impl TypeContext {
    pub fn new( type_system : ModelTypeSystem ) -> TypeContext {
        TypeContext { type_system }
    }
}

/// Defines Type-specific logic for handling the various parameter types in the
/// Rust/COM interface.
pub trait TypeHandler {

    /// The Rust type.
    fn rust_ty( &self ) -> Type;

    /// The COM type.
    fn com_ty( &self, _dir: Direction ) -> Type
    {
        self.rust_ty()
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self,
        ident : &Ident,
        _dir: Direction,
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() ),
        }
    }

    /// Converts a Rust parameter named by the ident into a COM type.
    fn rust_to_com(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() )
        }
    }

    /// Gets the default value for the type.
    fn default_value( &self ) -> TokenStream
    {
        match self.rust_ty() {
            Type::Path( ref p ) => {
                let ident = p.path.get_ident().unwrap();
                let name = ident.to_string();
                match name.as_ref() {
                    "RawComPtr" => quote!( ::std::ptr::null_mut() ),
                    _ => quote!( Default::default() )
                }
            },
            Type::Ptr( .. ) => quote!( ::std::ptr::null_mut() ),
            _ => quote!( Default::default() )
        }
    }
}

/// Identity parameter handler.
///
/// No special logic.
struct IdentityParam( Type );

impl TypeHandler for IdentityParam {
    fn rust_ty( &self ) -> Type { self.0.clone() }
}

/// `ComItf` parameter handler. Supports `ComItf` Rust type and ensures the this
/// to/from `RawComPtr` COM type.
struct ComItfParam { ty: Type, context: TypeContext }

impl TypeHandler for ComItfParam {

    fn rust_ty( &self ) -> Type { self.ty.clone() }

    /// The COM type.
    fn com_ty( &self, _dir: Direction ) -> Type
    {
        let rust_ty = self.rust_ty();

        // Extract the interface type T from the ComItf<T> type definition
        let itf_ty = match rust_ty {
            syn::Type::Path( path ) =>
                match path.path.segments.last().unwrap().value().arguments {
                    syn::PathArguments::AngleBracketed( ref ab ) =>
                            match ab.args.last().unwrap().value() {
                                syn::GenericArgument::Type( ref t ) => t.clone(),
                                _ => panic!( "ComItf generic argument must be type" ),
                            },
                    _ => panic!( "ComItf type parameter must be angle bracketed" ),
                },
            _ => panic!( "ComItf type parameter must be a type path" ),
        };

        // Construct the final InterfacePtr<T> type.
        parse_quote!( ::intercom::raw::InterfacePtr< #itf_ty > )
    }

    fn default_value( &self ) -> TokenStream
    {
        quote!( ::intercom::raw::InterfacePtr::new( ::std::ptr::null_mut() ) )
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        let ts = self.context.type_system.as_typesystem_tokens();
        TypeConversion {
            temporary: None,
            value: quote!( ::intercom::ComItf::wrap( #ident, #ts ) ),
        }
    }

    /// Converts a Rust parameter named by the ident into a COM type.
    fn rust_to_com(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        let ts = self.context.type_system.as_typesystem_tokens();
        TypeConversion {
            temporary: None,
            value: quote!( ::intercom::ComItf::ptr( &#ident.into(), #ts ) )
        }
    }
}

/// `bool` parameter handler. Supports `VARIANT_BOOL` for automation type system.
struct BoolParam { context: TypeContext }

impl TypeHandler for BoolParam {

    fn rust_ty( &self ) -> Type { parse_quote!( bool ) }

    /// The COM type.
    fn com_ty( &self, _dir: Direction ) -> Type
    {
        match self.context.type_system {
            ModelTypeSystem::Automation => parse_quote!( ::intercom::raw::VariantBool ),
            ModelTypeSystem::Raw => parse_quote!( bool ),
        }
    }

    fn default_value( &self ) -> TokenStream
    {
        match self.context.type_system {
            ModelTypeSystem::Automation => quote!( false.into() ),
            ModelTypeSystem::Raw => quote!( false ),
        }
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() )
        }
    }

    /// Converts a Rust parameter named by the ident into a COM type.
    fn rust_to_com(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() )
        }
    }
}

/// `Variant` parameter handler. Supports `VARIANT` for automation type system.
struct VariantParam { ty: Type }

impl TypeHandler for VariantParam {

    fn rust_ty( &self ) -> Type { self.ty.clone() }

    /// The COM type.
    fn com_ty( &self, _dir: Direction ) -> Type
    {
        parse_quote!( ::intercom::raw::Variant )
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.into() )
        }
    }

    /// Converts a Rust parameter named by the ident into a COM type.
    fn rust_to_com(
        &self, ident : &Ident, _dir: Direction
    ) -> TypeConversion
    {
        TypeConversion {
            temporary: None,
            value: quote!( #ident.com_into()? )
        }
    }
}

/// String parameter handler. Converts between Rust String and COM BSTR types.
struct StringParam { ty: Type, context: TypeContext }
impl TypeHandler for StringParam
{
    fn rust_ty( &self ) -> Type { self.ty.clone() }

    fn com_ty( &self, dir: Direction ) -> Type
    {
        match self.context.type_system {
            ModelTypeSystem::Automation => match dir {
                Direction::In => parse_quote!( ::intercom::raw::InBSTR ),
                Direction::Out | Direction::Retval => parse_quote!( ::intercom::raw::OutBSTR ),
            },
            ModelTypeSystem::Raw => match dir {
                Direction::In => parse_quote!( ::intercom::raw::InCStr ),
                Direction::Out | Direction::Retval => parse_quote!( ::intercom::raw::OutCStr ),
            },
        }
    }

    fn com_to_rust( &self, ident : &Ident, dir: Direction ) -> TypeConversion
    {
        match dir {

            Direction::In => {

                let str_type = match self.context.type_system {
                    ModelTypeSystem::Automation => quote!( BStr ),
                    ModelTypeSystem::Raw => quote!( CStr ),
                };

                let target_ty = self.rust_ty();
                let intermediate_ty = quote!( &::intercom::#str_type );
                let to_intermediate = quote!( ::intercom::#str_type::from_ptr( #ident ) );
                let as_trait = quote!( < #target_ty as ::intercom::FromWithTemporary< #intermediate_ty > > );

                let temp_ident = Ident::new( &format!( "__{}_temporary", ident.to_string() ), Span::call_site() );
                TypeConversion {
                    temporary: Some( quote!( let mut #temp_ident = #as_trait::to_temporary( #to_intermediate )?; ) ),
                    value: quote!( #as_trait::from_temporary( &mut #temp_ident )? ),
                }
            },
            Direction::Out | Direction::Retval => {

                // The type system input 'ident' should represent either a BString or CString
                // depending on the type system.
                let str_type = match self.context.type_system {
                    ModelTypeSystem::Automation => quote!( BString::from_ptr ),
                    ModelTypeSystem::Raw => quote!( CString::from_raw ),
                };

                // Get the type system string as Rust string.
                let ts_string = quote!( ::intercom::#str_type( #ident ) );

                // Convert the TS string into whatever string type the method requires.
                TypeConversion {
                    temporary: None,
                    value: quote!( #ts_string.com_into()? ),
                }
            },
        }
    }

    fn rust_to_com( &self, ident : &Ident, dir: Direction ) -> TypeConversion
    {
        match dir {

            Direction::In => {

                let str_type = match self.context.type_system {
                    ModelTypeSystem::Automation => quote!( BStr ),
                    ModelTypeSystem::Raw => quote!( CStr ),
                };

                let target_ty = self.rust_ty();
                let intermediate_ty = quote!( &::intercom::#str_type );
                let as_trait = quote!( < #intermediate_ty as ::intercom::FromWithTemporary< #target_ty > > );

                let temp_ident = Ident::new( &format!( "__{}_temporary", ident.to_string() ), Span::call_site() );
                TypeConversion {
                    temporary: Some( quote!( let mut #temp_ident = #as_trait::to_temporary( #ident )?; ) ),
                    value: quote!( #as_trait::from_temporary( &mut #temp_ident )?.as_ptr() ),
                }
            },
            Direction::Out | Direction::Retval => {

                // The Rust string value `ident` must be first converted into a type system
                // compatible Rust string, either BString or CSTring.
                // depending on the type system.
                let str_type = match self.context.type_system {
                    ModelTypeSystem::Automation => quote!( BString ),
                    ModelTypeSystem::Raw => quote!( CString ),
                };

                // Convert the `ident` into the required string type.
                let ts_string = quote!( ::intercom::ComInto::< ::intercom::#str_type >::com_into( #ident )? );

                TypeConversion {
                    temporary: None,
                    value: match self.context.type_system {
                        ModelTypeSystem::Automation =>
                            quote!( #ts_string.into_ptr() ),
                        ModelTypeSystem::Raw =>
                            quote!( #ts_string.into_raw() ),
                    }
                }
            },
        }
    }

    fn default_value( &self ) -> TokenStream
    {
        quote!( ::std::ptr::null_mut() )
    }
}

/// Resolves the `TypeHandler` to use.
pub fn get_ty_handler(
    arg_ty : &Type,
    context : TypeContext,
) -> Rc<dyn TypeHandler>
{
    let type_info = ::type_parser::parse( arg_ty )
            .unwrap_or_else( || panic!( "Type {:?} could not be parsed.", arg_ty ) );

    map_by_name(
            type_info.get_name().as_ref(), type_info.original.clone(),
            context )
}

/// Selects type handler based on the name of the type.
fn map_by_name(
    name: &str,
    original_type: Type,
    context: TypeContext,
) -> Rc<dyn TypeHandler> {

    match name {

        "ComItf" => Rc::new( ComItfParam { ty: original_type, context } ),
        "CString" | "CStr" | "BString" | "BStr" | "String" | "str" =>
            Rc::new( StringParam { ty: original_type, context } ),
        "bool" =>
            Rc::new( BoolParam { context } ),
        "Variant" =>
            Rc::new( VariantParam { ty: original_type } ),
        // "str" => Rc::new( StringRefParam( original_type ) ),

        // Unknown. Use IdentityParam.
        _ => Rc::new( IdentityParam( original_type ) )
    }

}
<|endoftext|>


<commit_before>//
//    Stachanov
//    Copyright (C) 2017 Stachanov Developer Collective
//
//    This file is part of Stachanov.
//
//    This program is free software: you can redistribute it and/or
//    modify it under the terms of the GNU Affero General Public
//    License, version 3, as published by the Free Software Foundation.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the
//               GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

use blockchain::block::Block;
use blockchain::block::BlockId;
use blockchain::errors::IdCollisionError;
use blockchain::transactions::TxId;
use blockchain::transactions::TxLinkMap;
use blockchain::transactions::Transaction;

pub trait Hashable {
    fn to_sha3_hash(&self) -> [u8; 32];
}

/// The ChainStorage trait must be implemented by all storage backends.
/// We allow for different backends (redis, postgres, etc) as not
/// every storage type fits for every service built around the core.

pub trait ChainStorage{

    /// Fetches a block identified by its unique block id
    /// * `block_id`: The block identifier (equivalent to the
    ///               the sha3 hash of the block header)

    fn get_block(&self, block_id: BlockId) -> Option<Block>;

    /// Fetches the block *after* the supplied block id. This
    /// is mainly an interface for block iteration.
    /// * `block_id`: The block identifier (equivalent to the
    ///               the sha3 hash of the block header)

    fn get_after(&self, block_id: BlockId) -> Option<Block>;

    /// Fetches the block that has a timestamp greater or
    /// equal to the specified timestamp.
    /// * `timestamp`: A unix timestamp

    // NOTE: This is a difference to the bitcoin timestamp
    // implementation. In stachanov a block header must have a
    // timestamp greater than the timestamp of its predecessor

    fn get_after_timestamp(&self, timestamp: u64) -> Option<Block>;

    /// Fetches the last block in the whole chain

    fn get_tail_block(&self) -> Option<Block>;

    /// Append a block to the chain *without* checking its
    /// validity. Will return an IdCollisionError if there
    /// already is a block with the same block id.
    /// * `block`: The verified block

    fn append_verified_block(&self, block: Block) -> Result<(), IdCollisionError>;

    /// Fetches a transaction identifier by its id
    /// * `tx_id`: the transaction id

    fn get_transaction(&self, tx_id: TxId) -> Option<Transaction>;

    /// Fetches the link map of a transaction
    /// * `tx_id`: the transaction id

    fn get_linkmap(&self, tx_id: TxId) -> Option<TxLinkMap>;

    /// Updates the TxLinkMap of a transaction
    /// * `tx_id`: the transaction id
    /// * `map`: the appropriate link map

    fn set_linkmap(&self, tx_id: TxId, map: TxLinkMap);

}
<commit_msg>FIX Made self in ChainStorage setters mutable<commit_after>//
//    Stachanov
//    Copyright (C) 2017 Stachanov Developer Collective
//
//    This file is part of Stachanov.
//
//    This program is free software: you can redistribute it and/or
//    modify it under the terms of the GNU Affero General Public
//    License, version 3, as published by the Free Software Foundation.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU Affero General Public License for more details.
//
//    You should have received a copy of the
//               GNU Affero General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.
//

use blockchain::block::Block;
use blockchain::block::BlockId;
use blockchain::errors::IdCollisionError;
use blockchain::transactions::TxId;
use blockchain::transactions::TxLinkMap;
use blockchain::transactions::Transaction;

pub trait Hashable {
    fn to_sha3_hash(&self) -> [u8; 32];
}

/// The ChainStorage trait must be implemented by all storage backends.
/// We allow for different backends (redis, postgres, etc) as not
/// every storage type fits for every service built around the core.

pub trait ChainStorage{

    /// Fetches a block identified by its unique block id
    /// * `block_id`: The block identifier (equivalent to the
    ///               the sha3 hash of the block header)

    fn get_block(&self, block_id: BlockId) -> Option<Block>;

    /// Fetches the block *after* the supplied block id. This
    /// is mainly an interface for block iteration.
    /// * `block_id`: The block identifier (equivalent to the
    ///               the sha3 hash of the block header)

    fn get_after(&self, block_id: BlockId) -> Option<Block>;

    /// Fetches the block that has a timestamp greater or
    /// equal to the specified timestamp.
    /// * `timestamp`: A unix timestamp

    // NOTE: This is a difference to the bitcoin timestamp
    // implementation. In stachanov a block header must have a
    // timestamp greater than the timestamp of its predecessor

    fn get_after_timestamp(&self, timestamp: u64) -> Option<Block>;

    /// Fetches the last block in the whole chain

    fn get_tail_block(&self) -> Option<Block>;

    /// Append a block to the chain *without* checking its
    /// validity. Will return an IdCollisionError if there
    /// already is a block with the same block id.
    /// * `block`: The verified block

    fn append_verified_block(&mut self, block: Block) -> Result<(), IdCollisionError>;

    /// Fetches a transaction identifier by its id
    /// * `tx_id`: the transaction id

    fn get_transaction(&self, tx_id: TxId) -> Option<Transaction>;

    /// Fetches the link map of a transaction
    /// * `tx_id`: the transaction id

    fn get_linkmap(&self, tx_id: TxId) -> Option<TxLinkMap>;

    /// Updates the TxLinkMap of a transaction
    /// * `tx_id`: the transaction id
    /// * `map`: the appropriate link map

    fn set_linkmap(&mut self, tx_id: TxId, map: TxLinkMap);

}
<|endoftext|>


<commit_before>extern crate libc;

use self::libc::{c_char, c_uchar};

/// Creates and saves in secured Wallet identity that can be used to
/// issue and verify Identity Ledger transaction.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// identity_json: Identity information as json. For current moment it is NYM transaction
///   data with optional information for creation of sign key (DID, Verkey, Role, Alias, Seed and etc...).
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// String identifier of this Identity.
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_create_identity(client_id: i32, command_id: i32,
                                             identity_json: *const c_char,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           identity_id: *const c_char)) {
    unimplemented!();
}

/// Returns public information for Identity stored in secured Wallet.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// identity_id: Id of Identity stored in secured Wallet.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// Public Identity information as json (DID, Verkey, Role, Alias and etc...).
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_get_identity(client_id: i32, command_id: i32,
                                          identity_id: *const c_char,
                                          cb: extern fn(xcommand_id: i32, err: i32,
                                                        identity_json: *const c_char)) {
    unimplemented!();
}

/// Returns list of ids for Identities stored in secured Wallet.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// List of stored identity ids.
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_get_identities(client_id: i32, command_id: i32,
                                            cb: extern fn(xcommand_id: i32, err: i32,
                                                          identity_ids: [*const c_char])) {
    unimplemented!();
}<commit_msg>Added wallet_anoncreds_create_schema function<commit_after>extern crate libc;

use self::libc::{c_char, c_uchar};

/// Creates and saves in secured Wallet identity that can be used to
/// issue and verify Identity Ledger transaction.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// identity_json: Identity information as json. For current moment it is NYM transaction
///   data with optional information for creation of sign key (DID, Verkey, Role, Alias, Seed and etc...).
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// String identifier of this Identity.
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_create_identity(client_id: i32, command_id: i32,
                                             identity_json: *const c_char,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           identity_id: *const c_char)) {
    unimplemented!();
}

/// Returns public information for Identity stored in secured Wallet.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// identity_id: Id of Identity stored in secured Wallet.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// Public Identity information as json (DID, Verkey, Role, Alias and etc...).
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_get_identity(client_id: i32, command_id: i32,
                                          identity_id: *const c_char,
                                          cb: extern fn(xcommand_id: i32, err: i32,
                                                        identity_json: *const c_char)) {
    unimplemented!();
}

/// Returns list of ids for Identities stored in secured Wallet.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// List of stored identity ids.
///
/// #Errors
/// No method specific errors.
/// See `SovrinError` docs for common errors description.
#[no_mangle]
pub  extern fn wallet_sovrin_get_identities(client_id: i32, command_id: i32,
                                            cb: extern fn(xcommand_id: i32, err: i32,
                                                          identity_ids: [*const c_char])) {
    unimplemented!();
}

/// Creates all necessary keys and objects depends on received schema and return schema_id.
///
/// #Params
/// client_id: id of sovrin client instance.
/// command_id: command id to map of callback to user context.
/// schema_json: Schema as a json. Includes name, version, attributes, keys, accumulator and etc.
///     Every empty field in the schema will be filled with the right value.
///     For example: if schema have an empty public key value, function will generate it. If it's
///         not necessary, value for public key field should be None.
/// cb: Callback that takes command result as parameter.
///
/// #Returns
/// Returns id of schema.
///
/// #Errors
/// No method specific errors.
/// See `AnoncredsError` docs for common errors description.
#[no_mangle]
pub extern fn wallet_anoncreds_create_schema(client_id: i32, command_id: i32,
                                             schema_json: *const c_char,
                                             cb: extern fn(xcommand_id: i32, err: i32,
                                                           schema_id: *const c_char)) {
    unimplemented!();
}<|endoftext|>


<commit_before>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::num::{zero, one, cast, sqrt};

use angle::{Angle, Rad, acos, cos, sin, sin_cos};
use approx::ApproxEq;
use array::{Array, build};
use matrix::{Mat3, ToMat3};
use vector::{Vec3, Vector, EuclideanVector};

/// A quaternion in scalar/vector form
#[deriving(Clone, Eq)]
pub struct Quat<S> { s: S, v: Vec3<S> }

array!(impl<S> Quat<S> -> [S, ..4] _4)

pub trait ToQuat<S: Float> {
    fn to_quat(&self) -> Quat<S>;
}

impl<S: Float + ApproxEq<S>>
Quat<S> {
    /// Construct a new quaternion from one scalar component and three
    /// imaginary components
    #[inline]
    pub fn new(w: S, xi: S, yj: S, zk: S) -> Quat<S> {
        Quat::from_sv(w, Vec3::new(xi, yj, zk))
    }

    /// Construct a new quaternion from a scalar and a vector
    #[inline]
    pub fn from_sv(s: S, v: Vec3<S>) -> Quat<S> {
        Quat { s: s, v: v }
    }

    /// Create a matrix from a rotation around the `x` axis (pitch).
    #[inline]
    pub fn from_angle_x(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, s, zero(), zero())
    }

    /// Create a matrix from a rotation around the `y` axis (yaw).
    #[inline]
    pub fn from_angle_y(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, zero(), s, zero())
    }

    /// Create a matrix from a rotation around the `z` axis (roll).
    #[inline]
    pub fn from_angle_z(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, zero(), zero(), s)
    }

    /// Create a quaternion from a set of euler angles.
    ///
    /// # Parameters
    ///
    /// - `x`: the angular rotation around the `x` axis (pitch).
    /// - `y`: the angular rotation around the `y` axis (yaw).
    /// - `z`: the angular rotation around the `z` axis (roll).
    pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Quat<S> {
        // http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Conversion
        let (sx2, cx2) = sin_cos(x.mul_s(cast(0.5).unwrap()));
        let (sy2, cy2) = sin_cos(y.mul_s(cast(0.5).unwrap()));
        let (sz2, cz2) = sin_cos(z.mul_s(cast(0.5).unwrap()));

        Quat::new(cz2 * cx2 * cy2 + sz2 * sx2 * sy2,
                  sz2 * cx2 * cy2 - cz2 * sx2 * sy2,
                  cz2 * sx2 * cy2 + sz2 * cx2 * sy2,
                  cz2 * cx2 * sy2 - sz2 * sx2 * cy2)
    }

    /// Create a quaternion from a rotation around an arbitrary axis
    #[inline]
    pub fn from_axis_angle(axis: &Vec3<S>, angle: Rad<S>) -> Quat<S> {
        let half = angle.mul_s(cast(0.5).unwrap());
        Quat::from_sv(cos(half.clone()),
                      axis.mul_s(sin(half)))
    }

    /// The additive identity, ie: `q = 0 + 0i + 0j + 0i`
    #[inline]
    pub fn zero() -> Quat<S> {
        Quat::new(zero(), zero(), zero(), zero())
    }

    /// The multiplicative identity, ie: `q = 1 + 0i + 0j + 0i`
    #[inline]
    pub fn identity() -> Quat<S> {
        Quat::from_sv(one::<S>(), Vec3::zero())
    }

    /// The result of multiplying the quaternion a scalar
    #[inline]
    pub fn mul_s(&self, value: S) -> Quat<S> {
        Quat::from_sv(self.s * value, self.v.mul_s(value))
    }

    /// The result of dividing the quaternion a scalar
    #[inline]
    pub fn div_s(&self, value: S) -> Quat<S> {
        Quat::from_sv(self.s / value, self.v.div_s(value))
    }

    /// The result of multiplying the quaternion by a vector
    #[inline]
    pub fn mul_v(&self, vec: &Vec3<S>) -> Vec3<S>  {
        let tmp = self.v.cross(vec).add_v(&vec.mul_s(self.s.clone()));
        self.v.cross(&tmp).mul_s(cast(2).unwrap()).add_v(vec)
    }

    /// The sum of this quaternion and `other`
    #[inline]
    pub fn add_q(&self, other: &Quat<S>) -> Quat<S> {
        build(|i| self.i(i).add(other.i(i)))
    }

    /// The difference between this quaternion and `other`
    #[inline]
    pub fn sub_q(&self, other: &Quat<S>) -> Quat<S> {
        build(|i| self.i(i).add(other.i(i)))
    }

    /// The the result of multipliplying the quaternion by `other`
    pub fn mul_q(&self, other: &Quat<S>) -> Quat<S> {
        Quat::new(self.s * other.s - self.v.x * other.v.x - self.v.y * other.v.y - self.v.z * other.v.z,
                  self.s * other.v.x + self.v.x * other.s + self.v.y * other.v.z - self.v.z * other.v.y,
                  self.s * other.v.y + self.v.y * other.s + self.v.z * other.v.x - self.v.x * other.v.z,
                  self.s * other.v.z + self.v.z * other.s + self.v.x * other.v.y - self.v.y * other.v.x)
    }

    #[inline]
    pub fn mul_self_s(&mut self, s: S) {
        self.each_mut(|_, x| *x = x.mul(&s))
    }

    #[inline]
    pub fn div_self_s(&mut self, s: S) {
        self.each_mut(|_, x| *x = x.div(&s))
    }

    #[inline]
    pub fn add_self_q(&mut self, other: &Quat<S>) {
        self.each_mut(|i, x| *x = x.add(other.i(i)));
    }

    #[inline]
    pub fn sub_self_q(&mut self, other: &Quat<S>) {
        self.each_mut(|i, x| *x = x.sub(other.i(i)));
    }

    #[inline]
    pub fn mul_self_q(&mut self, other: &Quat<S>) {
        *self = self.mul_q(other);
    }

    /// The dot product of the quaternion and `other`
    #[inline]
    pub fn dot(&self, other: &Quat<S>) -> S {
        self.s * other.s + self.v.dot(&other.v)
    }

    /// The conjugate of the quaternion
    #[inline]
    pub fn conjugate(&self) -> Quat<S> {
        Quat::from_sv(self.s.clone(), -self.v.clone())
    }

    /// The squared magnitude of the quaternion. This is useful for
    /// magnitude comparisons where the exact magnitude does not need to be
    /// calculated.
    #[inline]
    pub fn magnitude2(&self) -> S {
        self.s * self.s + self.v.length2()
    }

    /// The magnitude of the quaternion
    ///
    /// # Performance notes
    ///
    /// For instances where the exact magnitude of the quaternion does not need
    /// to be known, for example for quaternion-quaternion magnitude comparisons,
    /// it is advisable to use the `magnitude2` method instead.
    #[inline]
    pub fn magnitude(&self) -> S {
        sqrt(self.magnitude2())
    }

    /// The normalized quaternion
    #[inline]
    pub fn normalize(&self) -> Quat<S> {
        self.mul_s(one::<S>() / self.magnitude())
    }

    /// Normalised linear interpolation
    ///
    /// # Return value
    ///
    /// The intoperlated quaternion
    pub fn nlerp(&self, other: &Quat<S>, amount: S) -> Quat<S> {
        self.mul_s(one::<S>() - amount).add_q(&other.mul_s(amount)).normalize()
    }
}

impl<S: Float + ApproxEq<S>>
Quat<S> {
    /// Spherical Linear Intoperlation
    ///
    /// Perform a spherical linear interpolation between the quaternion and
    /// `other`. Both quaternions should be normalized first.
    ///
    /// # Return value
    ///
    /// The intoperlated quaternion
    ///
    /// # Performance notes
    ///
    /// The `acos` operation used in `slerp` is an expensive operation, so unless
    /// your quarternions a far away from each other it's generally more advisable
    /// to use `nlerp` when you know your rotations are going to be small.
    ///
    /// - [Understanding Slerp, Then Not Using It]
    ///   (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/)
    /// - [Arcsynthesis OpenGL tutorial]
    ///   (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html)
    pub fn slerp(&self, other: &Quat<S>, amount: S) -> Quat<S> {
        use std::num::cast;

        let dot = self.dot(other);
        let dot_threshold = cast(0.9995).unwrap();

        // if quaternions are close together use `nlerp`
        if dot > dot_threshold {
            self.nlerp(other, amount)
        } else {
            // stay within the domain of acos()
            let robust_dot = dot.clamp(&-one::<S>(), &one::<S>());

            let theta: Rad<S> = acos(robust_dot.clone());

            let scale1 = sin(theta.mul_s(one::<S>() - amount));
            let scale2 = sin(theta.mul_s(amount));

            self.mul_s(scale1)
                .add_q(&other.mul_s(scale2))
                .mul_s(sin(theta).recip())
        }
    }
}

impl<S: Float + ApproxEq<S>>
ToMat3<S> for Quat<S> {
    /// Convert the quaternion to a 3 x 3 rotation matrix
    fn to_mat3(&self) -> Mat3<S> {
        let x2 = self.v.x + self.v.x;
        let y2 = self.v.y + self.v.y;
        let z2 = self.v.z + self.v.z;

        let xx2 = x2 * self.v.x;
        let xy2 = x2 * self.v.y;
        let xz2 = x2 * self.v.z;

        let yy2 = y2 * self.v.y;
        let yz2 = y2 * self.v.z;
        let zz2 = z2 * self.v.z;

        let sy2 = y2 * self.s;
        let sz2 = z2 * self.s;
        let sx2 = x2 * self.s;

        Mat3::new(one::<S>() - yy2 - zz2, xy2 + sz2, xz2 - sy2,
                  xy2 - sz2, one::<S>() - xx2 - zz2, yz2 + sx2,
                  xz2 + sy2, yz2 - sx2, one::<S>() - xx2 - yy2)
    }
}

impl<S: Float + ApproxEq<S>>
Neg<Quat<S>> for Quat<S> {
    #[inline]
    fn neg(&self) -> Quat<S> {
        Quat::from_sv(-self.s, -self.v)
    }
}

impl<S: fmt::Default> ToStr for Quat<S> {
    fn to_str(&self) -> ~str {
        format!("{} + {}i + {}j + {}k", self.s, self.v.x, self.v.y, self.v.z)
    }
}
<commit_msg>Fix comments on Quat::from_angle_{x|y|z} functions<commit_after>// Copyright 2013 The CGMath Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::fmt;
use std::num::{zero, one, cast, sqrt};

use angle::{Angle, Rad, acos, cos, sin, sin_cos};
use approx::ApproxEq;
use array::{Array, build};
use matrix::{Mat3, ToMat3};
use vector::{Vec3, Vector, EuclideanVector};

/// A quaternion in scalar/vector form
#[deriving(Clone, Eq)]
pub struct Quat<S> { s: S, v: Vec3<S> }

array!(impl<S> Quat<S> -> [S, ..4] _4)

pub trait ToQuat<S: Float> {
    fn to_quat(&self) -> Quat<S>;
}

impl<S: Float + ApproxEq<S>>
Quat<S> {
    /// Construct a new quaternion from one scalar component and three
    /// imaginary components
    #[inline]
    pub fn new(w: S, xi: S, yj: S, zk: S) -> Quat<S> {
        Quat::from_sv(w, Vec3::new(xi, yj, zk))
    }

    /// Construct a new quaternion from a scalar and a vector
    #[inline]
    pub fn from_sv(s: S, v: Vec3<S>) -> Quat<S> {
        Quat { s: s, v: v }
    }

    /// Create a quaternion from a rotation around the `x` axis (pitch).
    #[inline]
    pub fn from_angle_x(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, s, zero(), zero())
    }

    /// Create a quaternion from a rotation around the `y` axis (yaw).
    #[inline]
    pub fn from_angle_y(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, zero(), s, zero())
    }

    /// Create a quaternion from a rotation around the `z` axis (roll).
    #[inline]
    pub fn from_angle_z(theta: Rad<S>) -> Quat<S> {
        let (s, c) = sin_cos(theta.mul_s(cast(0.5).unwrap()));
        Quat::new(c, zero(), zero(), s)
    }

    /// Create a quaternion from a set of euler angles.
    ///
    /// # Parameters
    ///
    /// - `x`: the angular rotation around the `x` axis (pitch).
    /// - `y`: the angular rotation around the `y` axis (yaw).
    /// - `z`: the angular rotation around the `z` axis (roll).
    pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Quat<S> {
        // http://en.wikipedia.org/wiki/Conversion_between_quaternions_and_Euler_angles#Conversion
        let (sx2, cx2) = sin_cos(x.mul_s(cast(0.5).unwrap()));
        let (sy2, cy2) = sin_cos(y.mul_s(cast(0.5).unwrap()));
        let (sz2, cz2) = sin_cos(z.mul_s(cast(0.5).unwrap()));

        Quat::new(cz2 * cx2 * cy2 + sz2 * sx2 * sy2,
                  sz2 * cx2 * cy2 - cz2 * sx2 * sy2,
                  cz2 * sx2 * cy2 + sz2 * cx2 * sy2,
                  cz2 * cx2 * sy2 - sz2 * sx2 * cy2)
    }

    /// Create a quaternion from a rotation around an arbitrary axis
    #[inline]
    pub fn from_axis_angle(axis: &Vec3<S>, angle: Rad<S>) -> Quat<S> {
        let half = angle.mul_s(cast(0.5).unwrap());
        Quat::from_sv(cos(half.clone()),
                      axis.mul_s(sin(half)))
    }

    /// The additive identity, ie: `q = 0 + 0i + 0j + 0i`
    #[inline]
    pub fn zero() -> Quat<S> {
        Quat::new(zero(), zero(), zero(), zero())
    }

    /// The multiplicative identity, ie: `q = 1 + 0i + 0j + 0i`
    #[inline]
    pub fn identity() -> Quat<S> {
        Quat::from_sv(one::<S>(), Vec3::zero())
    }

    /// The result of multiplying the quaternion a scalar
    #[inline]
    pub fn mul_s(&self, value: S) -> Quat<S> {
        Quat::from_sv(self.s * value, self.v.mul_s(value))
    }

    /// The result of dividing the quaternion a scalar
    #[inline]
    pub fn div_s(&self, value: S) -> Quat<S> {
        Quat::from_sv(self.s / value, self.v.div_s(value))
    }

    /// The result of multiplying the quaternion by a vector
    #[inline]
    pub fn mul_v(&self, vec: &Vec3<S>) -> Vec3<S>  {
        let tmp = self.v.cross(vec).add_v(&vec.mul_s(self.s.clone()));
        self.v.cross(&tmp).mul_s(cast(2).unwrap()).add_v(vec)
    }

    /// The sum of this quaternion and `other`
    #[inline]
    pub fn add_q(&self, other: &Quat<S>) -> Quat<S> {
        build(|i| self.i(i).add(other.i(i)))
    }

    /// The difference between this quaternion and `other`
    #[inline]
    pub fn sub_q(&self, other: &Quat<S>) -> Quat<S> {
        build(|i| self.i(i).add(other.i(i)))
    }

    /// The the result of multipliplying the quaternion by `other`
    pub fn mul_q(&self, other: &Quat<S>) -> Quat<S> {
        Quat::new(self.s * other.s - self.v.x * other.v.x - self.v.y * other.v.y - self.v.z * other.v.z,
                  self.s * other.v.x + self.v.x * other.s + self.v.y * other.v.z - self.v.z * other.v.y,
                  self.s * other.v.y + self.v.y * other.s + self.v.z * other.v.x - self.v.x * other.v.z,
                  self.s * other.v.z + self.v.z * other.s + self.v.x * other.v.y - self.v.y * other.v.x)
    }

    #[inline]
    pub fn mul_self_s(&mut self, s: S) {
        self.each_mut(|_, x| *x = x.mul(&s))
    }

    #[inline]
    pub fn div_self_s(&mut self, s: S) {
        self.each_mut(|_, x| *x = x.div(&s))
    }

    #[inline]
    pub fn add_self_q(&mut self, other: &Quat<S>) {
        self.each_mut(|i, x| *x = x.add(other.i(i)));
    }

    #[inline]
    pub fn sub_self_q(&mut self, other: &Quat<S>) {
        self.each_mut(|i, x| *x = x.sub(other.i(i)));
    }

    #[inline]
    pub fn mul_self_q(&mut self, other: &Quat<S>) {
        *self = self.mul_q(other);
    }

    /// The dot product of the quaternion and `other`
    #[inline]
    pub fn dot(&self, other: &Quat<S>) -> S {
        self.s * other.s + self.v.dot(&other.v)
    }

    /// The conjugate of the quaternion
    #[inline]
    pub fn conjugate(&self) -> Quat<S> {
        Quat::from_sv(self.s.clone(), -self.v.clone())
    }

    /// The squared magnitude of the quaternion. This is useful for
    /// magnitude comparisons where the exact magnitude does not need to be
    /// calculated.
    #[inline]
    pub fn magnitude2(&self) -> S {
        self.s * self.s + self.v.length2()
    }

    /// The magnitude of the quaternion
    ///
    /// # Performance notes
    ///
    /// For instances where the exact magnitude of the quaternion does not need
    /// to be known, for example for quaternion-quaternion magnitude comparisons,
    /// it is advisable to use the `magnitude2` method instead.
    #[inline]
    pub fn magnitude(&self) -> S {
        sqrt(self.magnitude2())
    }

    /// The normalized quaternion
    #[inline]
    pub fn normalize(&self) -> Quat<S> {
        self.mul_s(one::<S>() / self.magnitude())
    }

    /// Normalised linear interpolation
    ///
    /// # Return value
    ///
    /// The intoperlated quaternion
    pub fn nlerp(&self, other: &Quat<S>, amount: S) -> Quat<S> {
        self.mul_s(one::<S>() - amount).add_q(&other.mul_s(amount)).normalize()
    }
}

impl<S: Float + ApproxEq<S>>
Quat<S> {
    /// Spherical Linear Intoperlation
    ///
    /// Perform a spherical linear interpolation between the quaternion and
    /// `other`. Both quaternions should be normalized first.
    ///
    /// # Return value
    ///
    /// The intoperlated quaternion
    ///
    /// # Performance notes
    ///
    /// The `acos` operation used in `slerp` is an expensive operation, so unless
    /// your quarternions a far away from each other it's generally more advisable
    /// to use `nlerp` when you know your rotations are going to be small.
    ///
    /// - [Understanding Slerp, Then Not Using It]
    ///   (http://number-none.com/product/Understanding%20Slerp,%20Then%20Not%20Using%20It/)
    /// - [Arcsynthesis OpenGL tutorial]
    ///   (http://www.arcsynthesis.org/gltut/Positioning/Tut08%20Interpolation.html)
    pub fn slerp(&self, other: &Quat<S>, amount: S) -> Quat<S> {
        use std::num::cast;

        let dot = self.dot(other);
        let dot_threshold = cast(0.9995).unwrap();

        // if quaternions are close together use `nlerp`
        if dot > dot_threshold {
            self.nlerp(other, amount)
        } else {
            // stay within the domain of acos()
            let robust_dot = dot.clamp(&-one::<S>(), &one::<S>());

            let theta: Rad<S> = acos(robust_dot.clone());

            let scale1 = sin(theta.mul_s(one::<S>() - amount));
            let scale2 = sin(theta.mul_s(amount));

            self.mul_s(scale1)
                .add_q(&other.mul_s(scale2))
                .mul_s(sin(theta).recip())
        }
    }
}

impl<S: Float + ApproxEq<S>>
ToMat3<S> for Quat<S> {
    /// Convert the quaternion to a 3 x 3 rotation matrix
    fn to_mat3(&self) -> Mat3<S> {
        let x2 = self.v.x + self.v.x;
        let y2 = self.v.y + self.v.y;
        let z2 = self.v.z + self.v.z;

        let xx2 = x2 * self.v.x;
        let xy2 = x2 * self.v.y;
        let xz2 = x2 * self.v.z;

        let yy2 = y2 * self.v.y;
        let yz2 = y2 * self.v.z;
        let zz2 = z2 * self.v.z;

        let sy2 = y2 * self.s;
        let sz2 = z2 * self.s;
        let sx2 = x2 * self.s;

        Mat3::new(one::<S>() - yy2 - zz2, xy2 + sz2, xz2 - sy2,
                  xy2 - sz2, one::<S>() - xx2 - zz2, yz2 + sx2,
                  xz2 + sy2, yz2 - sx2, one::<S>() - xx2 - yy2)
    }
}

impl<S: Float + ApproxEq<S>>
Neg<Quat<S>> for Quat<S> {
    #[inline]
    fn neg(&self) -> Quat<S> {
        Quat::from_sv(-self.s, -self.v)
    }
}

impl<S: fmt::Default> ToStr for Quat<S> {
    fn to_str(&self) -> ~str {
        format!("{} + {}i + {}j + {}k", self.s, self.v.x, self.v.y, self.v.z)
    }
}
<|endoftext|>


<commit_before>// -*- rust -*-

import front.parser;
import front.token;
import front.eval;
import middle.trans;
import middle.resolve;
import middle.typeck;
import util.common;

import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

fn default_environment(session.session sess,
                       str argv0,
                       str input) -> eval.env {

    auto libc = "libc.so";
    alt (sess.get_targ_cfg().os) {
        case (session.os_win32) { libc = "msvcrt.dll"; }
        case (session.os_macos) { libc = "libc.dylib"; }
        case (session.os_linux) { libc = "libc.so.6"; }
    }

    ret
        vec(
            // Target bindings.
            tup("target_os", eval.val_str(std.os.target_os())),
            tup("target_arch", eval.val_str("x86")),
            tup("target_libc", eval.val_str(libc)),

            // Build bindings.
            tup("build_compiler", eval.val_str(argv0)),
            tup("build_input", eval.val_str(input))
            );
}

impure fn parse_input(session.session sess,
                      parser.parser p,
                      str input) -> @front.ast.crate {
    if (_str.ends_with(input, ".rc")) {
        ret parser.parse_crate_from_crate_file(p);
    } else if (_str.ends_with(input, ".rs")) {
        ret parser.parse_crate_from_source_file(p);
    }
    sess.err("unknown unput file type: " + input);
    fail;
}

impure fn compile_input(session.session sess,
                        eval.env env,
                        str input, str output,
                        bool shared) {
    auto def = tup(0, 0);
    auto p = parser.new_parser(sess, env, def, input);
    auto crate = parse_input(sess, p, input);
    crate = resolve.resolve_crate(sess, crate);
    crate = typeck.check_crate(sess, crate);
    trans.trans_crate(sess, crate, output, shared);
}

impure fn pretty_print_input(session.session sess,
                             eval.env env,
                             str input) {
    auto def = tup(0, 0);
    auto p = front.parser.new_parser(sess, env, def, input);
    auto crate = front.parser.parse_crate_from_source_file(p);
    pretty.pprust.print_ast(crate.node.module, std.io.stdout());
}

fn warn_wrong_compiler() {
    log "This is the rust 'self-hosted' compiler.";
    log "The one written in rust.";
    log "It is currently incomplete.";
    log "You may want rustboot instead, the compiler next door.";
}

fn usage(session.session sess, str argv0) {
    log #fmt("usage: %s [options] <input>", argv0);
    log "options:";
    log "";
    log "    -o <filename>      write output to <filename>";
    log "    -nowarn            suppress wrong-compiler warning";
    log "    -glue              generate glue.bc file";
    log "    -shared            compile a shared-library crate";
    log "    -pp                pretty-print the input instead of compiling";
    log "    -h                 display this message";
    log "";
    log "";
}

fn get_os() -> session.os {
    auto s = std.os.target_os();
    if (_str.eq(s, "win32")) { ret session.os_win32; }
    if (_str.eq(s, "macos")) { ret session.os_macos; }
    if (_str.eq(s, "linux")) { ret session.os_linux; }
}

impure fn main(vec[str] args) {

    // FIXME: don't hard-wire this.
    auto target_cfg = rec(os = get_os(),
                          arch = session.arch_x86,
                          int_type = common.ty_i32,
                          uint_type = common.ty_u32,
                          float_type = common.ty_f64 );

    auto sess = session.session(target_cfg);
    let option.t[str] input_file = none[str];
    let option.t[str] output_file = none[str];
    let bool do_warn = true;
    let bool shared = false;
    let bool pretty = false;
    let bool glue = false;

    auto i = 1u;
    auto len = _vec.len[str](args);

    // FIXME: a getopt module would be nice.
    while (i < len) {
        auto arg = args.(i);
        if (_str.byte_len(arg) > 0u && arg.(0) == '-' as u8) {
            if (_str.eq(arg, "-nowarn")) {
                do_warn = false;
            } else if (_str.eq(arg, "-glue")) {
                glue = true;
            } else if (_str.eq(arg, "-shared")) {
                shared = true;
            } else if (_str.eq(arg, "-pp")) {
                pretty = true;
            } else if (_str.eq(arg, "-o")) {
                if (i+1u < len) {
                    output_file = some(args.(i+1u));
                    i += 1u;
                } else {
                    usage(sess, args.(0));
                    sess.err("-o requires an argument");
                }
            } else if (_str.eq(arg, "-h")) {
                usage(sess, args.(0));
            } else {
                usage(sess, args.(0));
                sess.err("unrecognized option: " + arg);
            }
        } else {
            alt (input_file) {
                case (some[str](_)) {
                    usage(sess, args.(0));
                    sess.err("multiple inputs provided");
                }
                case (none[str]) {
                    input_file = some[str](arg);
                }
            }
        }
        i += 1u;
    }

    if (do_warn) {
        warn_wrong_compiler();
    }

    if (glue) {
        alt (output_file) {
            case (none[str]) {
                middle.trans.make_common_glue("glue.bc");
            }
            case (some[str](?s)) {
                middle.trans.make_common_glue(s);
            }
        }
        ret;
    }

    alt (input_file) {
        case (none[str]) {
            usage(sess, args.(0));
            sess.err("no input filename");
        }
        case (some[str](?ifile)) {

            auto env = default_environment(sess, args.(0), ifile);
            if (pretty) {
                pretty_print_input(sess, env, ifile);
            }
            else {
                alt (output_file) {
                    case (none[str]) {
                        let vec[str] parts = _str.split(ifile, '.' as u8);
                        parts = _vec.pop[str](parts);
                        parts += ".bc";
                        auto ofile = _str.concat(parts);
                        compile_input(sess, env, ifile, ofile, shared);
                    }
                    case (some[str](?ofile)) {
                        compile_input(sess, env, ifile, ofile, shared);
                    }
                }
            }
        }
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>rustc: Typo: "unput" -> "input"<commit_after>// -*- rust -*-

import front.parser;
import front.token;
import front.eval;
import middle.trans;
import middle.resolve;
import middle.typeck;
import util.common;

import std.option;
import std.option.some;
import std.option.none;
import std._str;
import std._vec;

fn default_environment(session.session sess,
                       str argv0,
                       str input) -> eval.env {

    auto libc = "libc.so";
    alt (sess.get_targ_cfg().os) {
        case (session.os_win32) { libc = "msvcrt.dll"; }
        case (session.os_macos) { libc = "libc.dylib"; }
        case (session.os_linux) { libc = "libc.so.6"; }
    }

    ret
        vec(
            // Target bindings.
            tup("target_os", eval.val_str(std.os.target_os())),
            tup("target_arch", eval.val_str("x86")),
            tup("target_libc", eval.val_str(libc)),

            // Build bindings.
            tup("build_compiler", eval.val_str(argv0)),
            tup("build_input", eval.val_str(input))
            );
}

impure fn parse_input(session.session sess,
                      parser.parser p,
                      str input) -> @front.ast.crate {
    if (_str.ends_with(input, ".rc")) {
        ret parser.parse_crate_from_crate_file(p);
    } else if (_str.ends_with(input, ".rs")) {
        ret parser.parse_crate_from_source_file(p);
    }
    sess.err("unknown input file type: " + input);
    fail;
}

impure fn compile_input(session.session sess,
                        eval.env env,
                        str input, str output,
                        bool shared) {
    auto def = tup(0, 0);
    auto p = parser.new_parser(sess, env, def, input);
    auto crate = parse_input(sess, p, input);
    crate = resolve.resolve_crate(sess, crate);
    crate = typeck.check_crate(sess, crate);
    trans.trans_crate(sess, crate, output, shared);
}

impure fn pretty_print_input(session.session sess,
                             eval.env env,
                             str input) {
    auto def = tup(0, 0);
    auto p = front.parser.new_parser(sess, env, def, input);
    auto crate = front.parser.parse_crate_from_source_file(p);
    pretty.pprust.print_ast(crate.node.module, std.io.stdout());
}

fn warn_wrong_compiler() {
    log "This is the rust 'self-hosted' compiler.";
    log "The one written in rust.";
    log "It is currently incomplete.";
    log "You may want rustboot instead, the compiler next door.";
}

fn usage(session.session sess, str argv0) {
    log #fmt("usage: %s [options] <input>", argv0);
    log "options:";
    log "";
    log "    -o <filename>      write output to <filename>";
    log "    -nowarn            suppress wrong-compiler warning";
    log "    -glue              generate glue.bc file";
    log "    -shared            compile a shared-library crate";
    log "    -pp                pretty-print the input instead of compiling";
    log "    -h                 display this message";
    log "";
    log "";
}

fn get_os() -> session.os {
    auto s = std.os.target_os();
    if (_str.eq(s, "win32")) { ret session.os_win32; }
    if (_str.eq(s, "macos")) { ret session.os_macos; }
    if (_str.eq(s, "linux")) { ret session.os_linux; }
}

impure fn main(vec[str] args) {

    // FIXME: don't hard-wire this.
    auto target_cfg = rec(os = get_os(),
                          arch = session.arch_x86,
                          int_type = common.ty_i32,
                          uint_type = common.ty_u32,
                          float_type = common.ty_f64 );

    auto sess = session.session(target_cfg);
    let option.t[str] input_file = none[str];
    let option.t[str] output_file = none[str];
    let bool do_warn = true;
    let bool shared = false;
    let bool pretty = false;
    let bool glue = false;

    auto i = 1u;
    auto len = _vec.len[str](args);

    // FIXME: a getopt module would be nice.
    while (i < len) {
        auto arg = args.(i);
        if (_str.byte_len(arg) > 0u && arg.(0) == '-' as u8) {
            if (_str.eq(arg, "-nowarn")) {
                do_warn = false;
            } else if (_str.eq(arg, "-glue")) {
                glue = true;
            } else if (_str.eq(arg, "-shared")) {
                shared = true;
            } else if (_str.eq(arg, "-pp")) {
                pretty = true;
            } else if (_str.eq(arg, "-o")) {
                if (i+1u < len) {
                    output_file = some(args.(i+1u));
                    i += 1u;
                } else {
                    usage(sess, args.(0));
                    sess.err("-o requires an argument");
                }
            } else if (_str.eq(arg, "-h")) {
                usage(sess, args.(0));
            } else {
                usage(sess, args.(0));
                sess.err("unrecognized option: " + arg);
            }
        } else {
            alt (input_file) {
                case (some[str](_)) {
                    usage(sess, args.(0));
                    sess.err("multiple inputs provided");
                }
                case (none[str]) {
                    input_file = some[str](arg);
                }
            }
        }
        i += 1u;
    }

    if (do_warn) {
        warn_wrong_compiler();
    }

    if (glue) {
        alt (output_file) {
            case (none[str]) {
                middle.trans.make_common_glue("glue.bc");
            }
            case (some[str](?s)) {
                middle.trans.make_common_glue(s);
            }
        }
        ret;
    }

    alt (input_file) {
        case (none[str]) {
            usage(sess, args.(0));
            sess.err("no input filename");
        }
        case (some[str](?ifile)) {

            auto env = default_environment(sess, args.(0), ifile);
            if (pretty) {
                pretty_print_input(sess, env, ifile);
            }
            else {
                alt (output_file) {
                    case (none[str]) {
                        let vec[str] parts = _str.split(ifile, '.' as u8);
                        parts = _vec.pop[str](parts);
                        parts += ".bc";
                        auto ofile = _str.concat(parts);
                        compile_input(sess, env, ifile, ofile, shared);
                    }
                    case (some[str](?ofile)) {
                        compile_input(sess, env, ifile, ofile, shared);
                    }
                }
            }
        }
    }
}

// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>import std._str;
import std._vec;
import std._str.rustrt.sbuf;
import std._vec.rustrt.vbuf;
import std.map.hashmap;

import front.ast;
import driver.session;
import back.x86;
import back.abi;

import util.common.istr;
import util.common.new_str_hash;

import lib.llvm.llvm;
import lib.llvm.builder;
import lib.llvm.llvm.ModuleRef;
import lib.llvm.llvm.ValueRef;
import lib.llvm.llvm.TypeRef;
import lib.llvm.llvm.BuilderRef;
import lib.llvm.llvm.BasicBlockRef;

import lib.llvm.False;
import lib.llvm.True;

type glue_fns = rec(ValueRef activate_glue,
                    ValueRef yield_glue,
                    vec[ValueRef] upcall_glues);

type trans_ctxt = rec(session.session sess,
                      ModuleRef llmod,
                      hashmap[str,ValueRef] upcalls,
                      @glue_fns glues,
                      str path);

type fn_ctxt = rec(ValueRef llfn,
                   ValueRef lloutptr,
                   ValueRef lltaskptr,
                   @trans_ctxt tcx);

type terminator = fn(@fn_ctxt cx, builder build);

type block_ctxt = rec(BasicBlockRef llbb,
                      builder build,
                      terminator term,
                      @fn_ctxt fcx);

// LLVM type constructors.

fn T_nil() -> TypeRef {
    ret llvm.LLVMVoidType();
}

fn T_int() -> TypeRef {
    ret llvm.LLVMInt32Type();
}

fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
                              False);
}

fn T_ptr(TypeRef t) -> TypeRef {
    ret llvm.LLVMPointerType(t, 0u);
}

fn T_struct(vec[TypeRef] elts) -> TypeRef {
    ret llvm.LLVMStructType(_vec.buf[TypeRef](elts),
                            _vec.len[TypeRef](elts),
                            False);
}

fn T_opaque() -> TypeRef {
    ret llvm.LLVMOpaqueType();
}

fn T_task() -> TypeRef {
    ret T_struct(vec(T_int(),      // Refcount
                     T_int(),      // Delegate pointer
                     T_int(),      // Stack segment pointer
                     T_int(),      // Runtime SP
                     T_int(),      // Rust SP
                     T_int(),      // GC chain
                     T_int(),      // Domain pointer
                     T_int()       // Crate cache pointer
                     ));
}

fn T_double() -> TypeRef {
    ret llvm.LLVMDoubleType();
}

fn T_taskptr() -> TypeRef {
    ret T_ptr(T_task());
}

// LLVM constant constructors.

fn C_null(TypeRef t) -> ValueRef {
    ret llvm.LLVMConstNull(t);
}

fn C_int(int i) -> ValueRef {
    // FIXME. We can't use LLVM.ULongLong with our existing minimal native
    // API, which only knows word-sized args.  Lucky for us LLVM has a "take a
    // string encoding" version.  Hilarious. Please fix to handle:
    //
    // ret llvm.LLVMConstInt(T_int(), t as LLVM.ULongLong, False);
    //
    ret llvm.LLVMConstIntOfString(T_int(),
                                  _str.buf(istr(i)), 10);
}

fn C_str(str s) -> ValueRef {
    ret llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
}

fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

fn decl_cdecl_fn(ModuleRef llmod, str name,
                 vec[TypeRef] inputs, TypeRef output) -> ValueRef {
    let TypeRef llty = T_fn(inputs, output);
    log "declaring " + name + " with type " + lib.llvm.type_to_str(llty);
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
    llvm.LLVMSetFunctionCallConv(llfn, lib.llvm.LLVMCCallConv);
    ret llfn;
}

fn decl_glue(ModuleRef llmod, str s) -> ValueRef {
    ret decl_cdecl_fn(llmod, s, vec(T_taskptr()), T_nil());
}

fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef {
    // It doesn't actually matter what type we come up with here, at the
    // moment, as we cast the upcall function pointers to int before passing
    // them to the indirect upcall-invocation glue.  But eventually we'd like
    // to call them directly, once we have a calling convention worked out.
    let int n = _n as int;
    let str s = abi.upcall_glue_name(n);
    let vec[TypeRef] args =
        vec(T_taskptr(), // taskptr
            T_int())     // callee
        + _vec.init_elt[TypeRef](T_int(), n as uint);

    ret decl_cdecl_fn(llmod, s, args, T_int());
}

fn get_upcall(@trans_ctxt cx, str name, int n_args) -> ValueRef {
    if (cx.upcalls.contains_key(name)) {
        ret cx.upcalls.get(name);
    }
    auto inputs = vec(T_taskptr());
    inputs += _vec.init_elt[TypeRef](T_int(), n_args as uint);
    auto output = T_nil();
    auto f = decl_cdecl_fn(cx.llmod, name, inputs, output);
    cx.upcalls.insert(name, f);
    ret f;
}

fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> ValueRef {
    let int n = _vec.len[ValueRef](args) as int;
    let ValueRef llupcall = get_upcall(cx.fcx.tcx, name, n);
    llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());

    let ValueRef llglue = cx.fcx.tcx.glues.upcall_glues.(n);
    let vec[ValueRef] call_args = vec(cx.fcx.lltaskptr, llupcall) + args;
    log "emitting indirect-upcall via " + abi.upcall_glue_name(n);
    for (ValueRef v in call_args) {
        log "arg: " + lib.llvm.type_to_str(llvm.LLVMTypeOf(v));
    }
    log "emitting call to callee of type: " +
        lib.llvm.type_to_str(llvm.LLVMTypeOf(llglue));
    ret cx.build.Call(llglue, call_args);
}

fn trans_log(@block_ctxt cx, &ast.atom a) {
    alt (a) {
        case (ast.atom_lit(?lit)) {
            alt (*lit) {
                case (ast.lit_int(?i)) {
                    trans_upcall(cx, "upcall_log_int", vec(C_int(i)));
                }
                case (_) {
                    cx.fcx.tcx.sess.unimpl("literal variant in trans_log");
                }
            }
        }
        case (_) {
            cx.fcx.tcx.sess.unimpl("atom variant in trans_log");
        }
    }
}

fn trans_stmt(@block_ctxt cx, &ast.stmt s) {
    alt (s) {
        case (ast.stmt_log(?a)) {
            trans_log(cx, *a);
        }
        case (_) {
            cx.fcx.tcx.sess.unimpl("stmt variant");
        }
    }
}

fn default_terminate(@fn_ctxt cx, builder build) {
    build.RetVoid();
}

fn trans_block(@fn_ctxt cx, &ast.block b, terminator term) {
    let BasicBlockRef llbb =
        llvm.LLVMAppendBasicBlock(cx.llfn, _str.buf(""));
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    auto bcx = @rec(llbb=llbb,
                    build=builder(llbuild),
                    term=term,
                    fcx=cx);
    for (@ast.stmt s in b) {
        trans_stmt(bcx, *s);
    }
    bcx.term(cx, bcx.build);
}

fn trans_fn(@trans_ctxt cx, &ast._fn f) {
    let vec[TypeRef] args = vec(T_ptr(T_int()), // outptr.
                                T_taskptr()     // taskptr
                                );
    let ValueRef llfn = decl_cdecl_fn(cx.llmod, cx.path, args, T_nil());
    let ValueRef lloutptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 1u);
    auto fcx = @rec(llfn=llfn,
                    lloutptr=lloutptr,
                    lltaskptr=lltaskptr,
                    tcx=cx);
    auto term = default_terminate;
    trans_block(fcx, f.body, term);
}

fn trans_item(@trans_ctxt cx, &str name, &ast.item item) {
    auto sub_cx = @rec(path=cx.path + "." + name with *cx);
    alt (item) {
        case (ast.item_fn(?f)) {
            trans_fn(sub_cx, *f);
        }
        case (ast.item_mod(?m)) {
            trans_mod(sub_cx, *m);
        }
    }
}

fn trans_mod(@trans_ctxt cx, &ast._mod m) {
    for each (tup(str, ast.item) pair in m.items()) {
        trans_item(cx, pair._0, pair._1);
    }
}

fn trans_crate(session.session sess, ast.crate crate) {
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));

    auto glues = @rec(activate_glue = decl_glue(llmod,
                                                abi.activate_glue_name()),
                      yield_glue = decl_glue(llmod, abi.yield_glue_name()),
                      upcall_glues =
                      _vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
                                             abi.n_upcall_glues as uint));

    auto cx = @rec(sess = sess,
                   llmod = llmod,
                   upcalls = new_str_hash[ValueRef](),
                   glues = glues,
                   path = "");

    trans_mod(cx, crate.module);

    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf("rust_out.bc"));
    llvm.LLVMDisposeModule(llmod);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>Construct the crate constant in rustc.<commit_after>import std._str;
import std._vec;
import std._str.rustrt.sbuf;
import std._vec.rustrt.vbuf;
import std.map.hashmap;

import front.ast;
import driver.session;
import back.x86;
import back.abi;

import util.common.istr;
import util.common.new_str_hash;

import lib.llvm.llvm;
import lib.llvm.builder;
import lib.llvm.llvm.ModuleRef;
import lib.llvm.llvm.ValueRef;
import lib.llvm.llvm.TypeRef;
import lib.llvm.llvm.BuilderRef;
import lib.llvm.llvm.BasicBlockRef;

import lib.llvm.False;
import lib.llvm.True;

type glue_fns = rec(ValueRef activate_glue,
                    ValueRef yield_glue,
                    vec[ValueRef] upcall_glues);

type trans_ctxt = rec(session.session sess,
                      ModuleRef llmod,
                      hashmap[str,ValueRef] upcalls,
                      @glue_fns glues,
                      str path);

type fn_ctxt = rec(ValueRef llfn,
                   ValueRef lloutptr,
                   ValueRef lltaskptr,
                   @trans_ctxt tcx);

type terminator = fn(@fn_ctxt cx, builder build);

type block_ctxt = rec(BasicBlockRef llbb,
                      builder build,
                      terminator term,
                      @fn_ctxt fcx);

// LLVM type constructors.

fn T_nil() -> TypeRef {
    ret llvm.LLVMVoidType();
}

fn T_int() -> TypeRef {
    ret llvm.LLVMInt32Type();
}

fn T_fn(vec[TypeRef] inputs, TypeRef output) -> TypeRef {
    ret llvm.LLVMFunctionType(output,
                              _vec.buf[TypeRef](inputs),
                              _vec.len[TypeRef](inputs),
                              False);
}

fn T_ptr(TypeRef t) -> TypeRef {
    ret llvm.LLVMPointerType(t, 0u);
}

fn T_struct(vec[TypeRef] elts) -> TypeRef {
    ret llvm.LLVMStructType(_vec.buf[TypeRef](elts),
                            _vec.len[TypeRef](elts),
                            False);
}

fn T_opaque() -> TypeRef {
    ret llvm.LLVMOpaqueType();
}

fn T_task() -> TypeRef {
    ret T_struct(vec(T_int(),      // Refcount
                     T_int(),      // Delegate pointer
                     T_int(),      // Stack segment pointer
                     T_int(),      // Runtime SP
                     T_int(),      // Rust SP
                     T_int(),      // GC chain
                     T_int(),      // Domain pointer
                     T_int()       // Crate cache pointer
                     ));
}

fn T_crate() -> TypeRef {
    ret T_struct(vec(T_int(),      // ptrdiff_t image_base_off
                     T_int(),      // uintptr_t self_addr
                     T_int(),      // ptrdiff_t debug_abbrev_off
                     T_int(),      // size_t debug_abbrev_sz
                     T_int(),      // ptrdiff_t debug_info_off
                     T_int(),      // size_t debug_info_sz
                     T_int(),      // size_t activate_glue_off
                     T_int(),      // size_t yield_glue_off
                     T_int(),      // size_t unwind_glue_off
                     T_int(),      // size_t gc_glue_off
                     T_int(),      // size_t main_exit_task_glue_off
                     T_int(),      // int n_rust_syms
                     T_int(),      // int n_c_syms
                     T_int()       //int n_libs
                     ));
}

fn T_double() -> TypeRef {
    ret llvm.LLVMDoubleType();
}

fn T_taskptr() -> TypeRef {
    ret T_ptr(T_task());
}

// LLVM constant constructors.

fn C_null(TypeRef t) -> ValueRef {
    ret llvm.LLVMConstNull(t);
}

fn C_int(int i) -> ValueRef {
    // FIXME. We can't use LLVM.ULongLong with our existing minimal native
    // API, which only knows word-sized args.  Lucky for us LLVM has a "take a
    // string encoding" version.  Hilarious. Please fix to handle:
    //
    // ret llvm.LLVMConstInt(T_int(), t as LLVM.ULongLong, False);
    //
    ret llvm.LLVMConstIntOfString(T_int(),
                                  _str.buf(istr(i)), 10);
}

fn C_str(str s) -> ValueRef {
    ret llvm.LLVMConstString(_str.buf(s), _str.byte_len(s), False);
}

fn C_struct(vec[ValueRef] elts) -> ValueRef {
    ret llvm.LLVMConstStruct(_vec.buf[ValueRef](elts),
                             _vec.len[ValueRef](elts),
                             False);
}

fn decl_cdecl_fn(ModuleRef llmod, str name,
                 vec[TypeRef] inputs, TypeRef output) -> ValueRef {
    let TypeRef llty = T_fn(inputs, output);
    log "declaring " + name + " with type " + lib.llvm.type_to_str(llty);
    let ValueRef llfn =
        llvm.LLVMAddFunction(llmod, _str.buf(name), llty);
    llvm.LLVMSetFunctionCallConv(llfn, lib.llvm.LLVMCCallConv);
    ret llfn;
}

fn decl_glue(ModuleRef llmod, str s) -> ValueRef {
    ret decl_cdecl_fn(llmod, s, vec(T_taskptr()), T_nil());
}

fn decl_upcall(ModuleRef llmod, uint _n) -> ValueRef {
    // It doesn't actually matter what type we come up with here, at the
    // moment, as we cast the upcall function pointers to int before passing
    // them to the indirect upcall-invocation glue.  But eventually we'd like
    // to call them directly, once we have a calling convention worked out.
    let int n = _n as int;
    let str s = abi.upcall_glue_name(n);
    let vec[TypeRef] args =
        vec(T_taskptr(), // taskptr
            T_int())     // callee
        + _vec.init_elt[TypeRef](T_int(), n as uint);

    ret decl_cdecl_fn(llmod, s, args, T_int());
}

fn get_upcall(@trans_ctxt cx, str name, int n_args) -> ValueRef {
    if (cx.upcalls.contains_key(name)) {
        ret cx.upcalls.get(name);
    }
    auto inputs = vec(T_taskptr());
    inputs += _vec.init_elt[TypeRef](T_int(), n_args as uint);
    auto output = T_nil();
    auto f = decl_cdecl_fn(cx.llmod, name, inputs, output);
    cx.upcalls.insert(name, f);
    ret f;
}

fn trans_upcall(@block_ctxt cx, str name, vec[ValueRef] args) -> ValueRef {
    let int n = _vec.len[ValueRef](args) as int;
    let ValueRef llupcall = get_upcall(cx.fcx.tcx, name, n);
    llupcall = llvm.LLVMConstPointerCast(llupcall, T_int());

    let ValueRef llglue = cx.fcx.tcx.glues.upcall_glues.(n);
    let vec[ValueRef] call_args = vec(cx.fcx.lltaskptr, llupcall) + args;
    log "emitting indirect-upcall via " + abi.upcall_glue_name(n);
    for (ValueRef v in call_args) {
        log "arg: " + lib.llvm.type_to_str(llvm.LLVMTypeOf(v));
    }
    log "emitting call to callee of type: " +
        lib.llvm.type_to_str(llvm.LLVMTypeOf(llglue));
    ret cx.build.Call(llglue, call_args);
}

fn trans_log(@block_ctxt cx, &ast.atom a) {
    alt (a) {
        case (ast.atom_lit(?lit)) {
            alt (*lit) {
                case (ast.lit_int(?i)) {
                    trans_upcall(cx, "upcall_log_int", vec(C_int(i)));
                }
                case (_) {
                    cx.fcx.tcx.sess.unimpl("literal variant in trans_log");
                }
            }
        }
        case (_) {
            cx.fcx.tcx.sess.unimpl("atom variant in trans_log");
        }
    }
}

fn trans_stmt(@block_ctxt cx, &ast.stmt s) {
    alt (s) {
        case (ast.stmt_log(?a)) {
            trans_log(cx, *a);
        }
        case (_) {
            cx.fcx.tcx.sess.unimpl("stmt variant");
        }
    }
}

fn default_terminate(@fn_ctxt cx, builder build) {
    build.RetVoid();
}

fn trans_block(@fn_ctxt cx, &ast.block b, terminator term) {
    let BasicBlockRef llbb =
        llvm.LLVMAppendBasicBlock(cx.llfn, _str.buf(""));
    let BuilderRef llbuild = llvm.LLVMCreateBuilder();
    llvm.LLVMPositionBuilderAtEnd(llbuild, llbb);
    auto bcx = @rec(llbb=llbb,
                    build=builder(llbuild),
                    term=term,
                    fcx=cx);
    for (@ast.stmt s in b) {
        trans_stmt(bcx, *s);
    }
    bcx.term(cx, bcx.build);
}

fn trans_fn(@trans_ctxt cx, &ast._fn f) {
    let vec[TypeRef] args = vec(T_ptr(T_int()), // outptr.
                                T_taskptr()     // taskptr
                                );
    let ValueRef llfn = decl_cdecl_fn(cx.llmod, cx.path, args, T_nil());
    let ValueRef lloutptr = llvm.LLVMGetParam(llfn, 0u);
    let ValueRef lltaskptr = llvm.LLVMGetParam(llfn, 1u);
    auto fcx = @rec(llfn=llfn,
                    lloutptr=lloutptr,
                    lltaskptr=lltaskptr,
                    tcx=cx);
    auto term = default_terminate;
    trans_block(fcx, f.body, term);
}

fn trans_item(@trans_ctxt cx, &str name, &ast.item item) {
    auto sub_cx = @rec(path=cx.path + "." + name with *cx);
    alt (item) {
        case (ast.item_fn(?f)) {
            trans_fn(sub_cx, *f);
        }
        case (ast.item_mod(?m)) {
            trans_mod(sub_cx, *m);
        }
    }
}

fn trans_mod(@trans_ctxt cx, &ast._mod m) {
    for each (tup(str, ast.item) pair in m.items()) {
        trans_item(cx, pair._0, pair._1);
    }
}

fn crate_constant(@trans_ctxt cx) -> ValueRef {

    let ValueRef crate_ptr =
        llvm.LLVMAddGlobal(cx.llmod, T_ptr(T_crate()),
                           _str.buf("rust_crate"));

    fn p2i(ValueRef v) -> ValueRef {
        ret llvm.LLVMConstPtrToInt(v, T_int());
    }

    let ValueRef crate_addr = p2i(crate_ptr);

    let ValueRef activate_glue_off =
        llvm.LLVMConstSub(p2i(cx.glues.activate_glue), crate_addr);

    let ValueRef yield_glue_off =
        llvm.LLVMConstSub(p2i(cx.glues.yield_glue), crate_addr);

    // FIXME: we aren't generating the exit-task glue yet.
    // llvm.LLVMConstSub(p2i(cx.glues.exit_task_glue), crate_addr);
    let ValueRef exit_task_glue_off = C_null(T_int());

    let ValueRef crate_val =
        C_struct(vec(C_null(T_int()),     // ptrdiff_t image_base_off
                     crate_ptr,           // uintptr_t self_addr
                     C_null(T_int()),     // ptrdiff_t debug_abbrev_off
                     C_null(T_int()),     // size_t debug_abbrev_sz
                     C_null(T_int()),     // ptrdiff_t debug_info_off
                     C_null(T_int()),     // size_t debug_info_sz
                     activate_glue_off,   // size_t activate_glue_off
                     yield_glue_off,      // size_t yield_glue_off
                     C_null(T_int()),     // size_t unwind_glue_off
                     C_null(T_int()),     // size_t gc_glue_off
                     exit_task_glue_off,  // size_t main_exit_task_glue_off
                     C_null(T_int()),     // int n_rust_syms
                     C_null(T_int()),     // int n_c_syms
                     C_null(T_int())      // int n_libs
                     ));

    llvm.LLVMSetInitializer(crate_ptr, crate_val);
    ret crate_ptr;
}

fn trans_crate(session.session sess, ast.crate crate) {
    auto llmod =
        llvm.LLVMModuleCreateWithNameInContext(_str.buf("rust_out"),
                                               llvm.LLVMGetGlobalContext());

    llvm.LLVMSetModuleInlineAsm(llmod, _str.buf(x86.get_module_asm()));

    auto glues = @rec(activate_glue = decl_glue(llmod,
                                                abi.activate_glue_name()),
                      yield_glue = decl_glue(llmod, abi.yield_glue_name()),
                      upcall_glues =
                      _vec.init_fn[ValueRef](bind decl_upcall(llmod, _),
                                             abi.n_upcall_glues as uint));

    auto cx = @rec(sess = sess,
                   llmod = llmod,
                   upcalls = new_str_hash[ValueRef](),
                   glues = glues,
                   path = "_rust");

    trans_mod(cx, crate.module);

    llvm.LLVMWriteBitcodeToFile(llmod, _str.buf("rust_out.bc"));
    llvm.LLVMDisposeModule(llmod);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C ../.. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::all)]
#![allow(improper_ctypes)]
//! This module exposes the raw [HTSlib](https://github.com/samtools/htslib) bindings for reading and writing
//! genomics file formats like SAM, BAM, CRAM, VCF, BCF.
//! Instead of using this crate directly, it is recommended to use [rust-htslib](https://docs.rs/rust-htslib)
//! instead, which has a more idiomatic and high-level API and builds on top of this crate.

#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "curl")]
extern crate curl_sys;
#[cfg(feature = "libdeflate")]
extern crate libdeflate_sys;
extern crate libz_sys;
#[cfg(feature = "lzma")]
extern crate lzma_sys;

// include on-the-fly generated bindings
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<commit_msg>fix: dummy release<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(clippy::all)]
#![allow(improper_ctypes)]
//! This module exposes the raw [HTSlib](https://github.com/samtools/htslib) bindings for reading and writing
//! genomics file formats like SAM, BAM, CRAM, VCF, BCF and tabix.
//! Instead of using this crate directly, it is recommended to use [rust-htslib](https://docs.rs/rust-htslib)
//! instead, which has a more idiomatic and high-level API and builds on top of this crate.

#[cfg(feature = "bzip2")]
extern crate bzip2_sys;
#[cfg(feature = "curl")]
extern crate curl_sys;
#[cfg(feature = "libdeflate")]
extern crate libdeflate_sys;
extern crate libz_sys;
#[cfg(feature = "lzma")]
extern crate lzma_sys;

// include on-the-fly generated bindings
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
<|endoftext|>