<commit_before>#[feature(globs)];

extern mod OpenCL;
use OpenCL::CL::*;
use OpenCL::CL::ll::*;
use std::ptr;
use std::io;
use std::sys;
use std::libc;
use std::vec;
use std::cast;

#[fixed_stack_segment]
fn main()
{
  unsafe
  {
    let ker =
        ~"__kernel void vector_add(__global const long *A,
                                   __global const long *B,
                                   __global       long *C) {
             int i = get_global_id(0);
             C[i] = A[i] + B[i];
         }";

    let sz    = 8;
    let vec_a = ~[0, 1, 2, -3, 4, 5, 6, 7];
    let vec_b = ~[-7, -6, 5, -4, 0, -1, 2, 3];

    let p_id:   cl_platform_id = ptr::null();
    let device: cl_device_id   = ptr::null();
    let np:     cl_uint        = 0;
    let nd:     cl_uint        = 0;
    let mut r:  cl_int;

    // Get the platform and device information
    clGetPlatformIDs(1,
                     ptr::to_unsafe_ptr(&p_id),
                     ptr::to_unsafe_ptr(&np));

    r = clGetDeviceIDs(p_id,
                       CL_DEVICE_TYPE_CPU,
                       1,
                       ptr::to_unsafe_ptr(&device),
                       ptr::to_unsafe_ptr(&nd));

    if r != CL_SUCCESS as cl_int
    { io::println(fmt!("Can't get device ID. [%?]", r)); }

    // Create OpenCL context and command queue
    let ctx = clCreateContext(ptr::null(),
                              nd,
                              ptr::to_unsafe_ptr(&device),
                              cast::transmute(ptr::null::<&fn ()>()),
                              ptr::null(),
                              ptr::to_unsafe_ptr(&r));

    let cque = clCreateCommandQueue(ctx, device, 0, ptr::to_unsafe_ptr(&r));

    // Create memory buffers
    let A = clCreateBuffer(ctx,
                           CL_MEM_READ_ONLY,
                           (sz * sys::size_of::<int>()) as libc::size_t,
                           ptr::null(),
                           ptr::to_unsafe_ptr(&r));

    let B = clCreateBuffer(ctx,
                           CL_MEM_READ_ONLY,
                           (sz * sys::size_of::<int>()) as libc::size_t,
                           ptr::null(),
                           ptr::to_unsafe_ptr(&r));

    let C = clCreateBuffer(ctx,
                           CL_MEM_WRITE_ONLY,
                           (sz * sys::size_of::<int>()) as libc::size_t,
                           ptr::null(),
                           ptr::to_unsafe_ptr(&r));

    // Copy lists into memory buffers
    clEnqueueWriteBuffer(cque,
                         A,
                         CL_TRUE,
                         0,
                         (sz * sys::size_of::<int>()) as libc::size_t,
                         vec::raw::to_ptr(vec_a) as *libc::c_void,
                         0,
                         ptr::null(),
                         ptr::null());

    clEnqueueWriteBuffer(cque,
                         B,
                         CL_TRUE,
                         0,
                         (sz * sys::size_of::<int>()) as libc::size_t,
                         vec::raw::to_ptr(vec_b) as *libc::c_void,
                         0,
                         ptr::null(),
                         ptr::null());

    // Create a program from the kernel and build it
    do ker.as_imm_buf |bytes, len|
    {
      let prog = clCreateProgramWithSource(ctx,
                                           1,
                                           ptr::to_unsafe_ptr(&(bytes as *libc::c_char)),
                                           ptr::to_unsafe_ptr(&(len as libc::size_t)),
                                           ptr::to_unsafe_ptr(&r));

      r = clBuildProgram(prog,
                         nd,
                         ptr::to_unsafe_ptr(&device),
                         ptr::null(),
                         cast::transmute(ptr::null::<&fn ()>()),
                         ptr::null());

      if r != CL_SUCCESS as cl_int
      { io::println(fmt!("Unable to build program [%?].", r)); }

      // Create the OpenCL kernel
      do "vector_add".as_imm_buf() |bytes, _|
      {
        let kernel = clCreateKernel(prog, bytes as *libc::c_char, ptr::to_unsafe_ptr(&r));
        if r != CL_SUCCESS as cl_int
        { io::println(fmt!("Unable to create kernel [%?].", r)); }

        // Set the arguments of the kernel
        clSetKernelArg(kernel,
                       0,
                       sys::size_of::<cl_mem>() as libc::size_t,
                       ptr::to_unsafe_ptr(&A)   as *libc::c_void);

        clSetKernelArg(kernel,
                       1,
                       sys::size_of::<cl_mem>() as libc::size_t,
                       ptr::to_unsafe_ptr(&B)   as *libc::c_void);

        clSetKernelArg(kernel,
                       2,
                       sys::size_of::<cl_mem>() as libc::size_t,
                       ptr::to_unsafe_ptr(&C)   as *libc::c_void);

        let global_item_size: libc::size_t = (sz * sys::size_of::<int>()) as libc::size_t;
        let local_item_size:  libc::size_t = 64;

        // Execute the OpenCL kernel on the list
        clEnqueueNDRangeKernel(cque,
                               kernel,
                               1,
                               ptr::null(),
                               ptr::to_unsafe_ptr(&global_item_size),
                               ptr::to_unsafe_ptr(&local_item_size),
                               0,
                               ptr::null(),
                               ptr::null());

        // Now let's read back the new list from the device
        let buf = libc::malloc((sz * sys::size_of::<int>()) as libc::size_t);

        clEnqueueReadBuffer(cque,
                            C,
                            CL_TRUE,
                            0,
                            (sz * sys::size_of::<int>()) as libc::size_t,
                            buf,
                            0,
                            ptr::null(),
                            ptr::null());

        let vec_c = vec::from_buf(buf as *int, sz);

        libc::free(buf);

        io::println(fmt!("   %?", vec_a));
        io::println(fmt!("+  %?", vec_b));
        io::println(fmt!("=  %?", vec_c));

        // Cleanup
        clReleaseKernel(kernel);
        clReleaseProgram(prog);
        clReleaseMemObject(C);
        clReleaseMemObject(B);
        clReleaseMemObject(A);
        clReleaseCommandQueue(cque);
        clReleaseContext(ctx);
      }
    }
  }
}
<commit_msg>s/CPU/ALL/<commit_after>#[feature(globs)];

extern mod OpenCL;
use OpenCL::CL::*;
use OpenCL::CL::ll::*;
use std::ptr;
use std::io;
use std::sys;
use std::libc;
use std::vec;
use std::cast;

#[fixed_stack_segment]
fn main()
{
  unsafe
  {
    let ker =
        ~"__kernel void vector_add(__global const long *A,
                                   __global const long *B,
                                   __global       long *C) {
             int i = get_global_id(0);
             C[i] = A[i] + B[i];
         }";

    let sz    = 8;
    let vec_a = ~[0, 1, 2, -3, 4, 5, 6, 7];
    let vec_b = ~[-7, -6, 5, -4, 0, -1, 2, 3];

    let p_id:   cl_platform_id = ptr::null();
    let device: cl_device_id   = ptr::null();
    let np:     cl_uint        = 0;
    let nd:     cl_uint        = 0;
    let mut r:  cl_int;

    // Get the platform and device information
    clGetPlatformIDs(1,
                     ptr::to_unsafe_ptr(&p_id),
                     ptr::to_unsafe_ptr(&np));

    r = clGetDeviceIDs(p_id,
                       CL_DEVICE_TYPE_ALL,
                       1,
                       ptr::to_unsafe_ptr(&device),
                       ptr::to_unsafe_ptr(&nd));

    if r != CL_SUCCESS as cl_int
    { io::println(fmt!("Can't get device ID. [%?]", r)); }

    // Create OpenCL context and command queue
    let ctx = clCreateContext(ptr::null(),
                              nd,
                              ptr::to_unsafe_ptr(&device),
                              cast::transmute(ptr::null::<&fn ()>()),
                              ptr::null(),
                              ptr::to_unsafe_ptr(&r));

    let cque = clCreateCommandQueue(ctx, device, 0, ptr::to_unsafe_ptr(&r));

    // Create memory buffers
    let A = clCreateBuffer(ctx,
                           CL_MEM_READ_ONLY,
                           (sz * sys::size_of::<int>()) as libc::size_t,
                           ptr::null(),
                           ptr::to_unsafe_ptr(&r));

    let B = clCreateBuffer(ctx,
                           CL_MEM_READ_ONLY,
                           (sz * sys::size_of::<int>()) as libc::size_t,
                           ptr::null(),
                           ptr::to_unsafe_ptr(&r));

    let C = clCreateBuffer(ctx,
                           CL_MEM_WRITE_ONLY,
                           (sz * sys::size_of::<int>()) as libc::size_t,
                           ptr::null(),
                           ptr::to_unsafe_ptr(&r));

    // Copy lists into memory buffers
    clEnqueueWriteBuffer(cque,
                         A,
                         CL_TRUE,
                         0,
                         (sz * sys::size_of::<int>()) as libc::size_t,
                         vec::raw::to_ptr(vec_a) as *libc::c_void,
                         0,
                         ptr::null(),
                         ptr::null());

    clEnqueueWriteBuffer(cque,
                         B,
                         CL_TRUE,
                         0,
                         (sz * sys::size_of::<int>()) as libc::size_t,
                         vec::raw::to_ptr(vec_b) as *libc::c_void,
                         0,
                         ptr::null(),
                         ptr::null());

    // Create a program from the kernel and build it
    do ker.as_imm_buf |bytes, len|
    {
      let prog = clCreateProgramWithSource(ctx,
                                           1,
                                           ptr::to_unsafe_ptr(&(bytes as *libc::c_char)),
                                           ptr::to_unsafe_ptr(&(len as libc::size_t)),
                                           ptr::to_unsafe_ptr(&r));

      r = clBuildProgram(prog,
                         nd,
                         ptr::to_unsafe_ptr(&device),
                         ptr::null(),
                         cast::transmute(ptr::null::<&fn ()>()),
                         ptr::null());

      if r != CL_SUCCESS as cl_int
      { io::println(fmt!("Unable to build program [%?].", r)); }

      // Create the OpenCL kernel
      do "vector_add".as_imm_buf() |bytes, _|
      {
        let kernel = clCreateKernel(prog, bytes as *libc::c_char, ptr::to_unsafe_ptr(&r));
        if r != CL_SUCCESS as cl_int
        { io::println(fmt!("Unable to create kernel [%?].", r)); }

        // Set the arguments of the kernel
        clSetKernelArg(kernel,
                       0,
                       sys::size_of::<cl_mem>() as libc::size_t,
                       ptr::to_unsafe_ptr(&A)   as *libc::c_void);

        clSetKernelArg(kernel,
                       1,
                       sys::size_of::<cl_mem>() as libc::size_t,
                       ptr::to_unsafe_ptr(&B)   as *libc::c_void);

        clSetKernelArg(kernel,
                       2,
                       sys::size_of::<cl_mem>() as libc::size_t,
                       ptr::to_unsafe_ptr(&C)   as *libc::c_void);

        let global_item_size: libc::size_t = (sz * sys::size_of::<int>()) as libc::size_t;
        let local_item_size:  libc::size_t = 64;

        // Execute the OpenCL kernel on the list
        clEnqueueNDRangeKernel(cque,
                               kernel,
                               1,
                               ptr::null(),
                               ptr::to_unsafe_ptr(&global_item_size),
                               ptr::to_unsafe_ptr(&local_item_size),
                               0,
                               ptr::null(),
                               ptr::null());

        // Now let's read back the new list from the device
        let buf = libc::malloc((sz * sys::size_of::<int>()) as libc::size_t);

        clEnqueueReadBuffer(cque,
                            C,
                            CL_TRUE,
                            0,
                            (sz * sys::size_of::<int>()) as libc::size_t,
                            buf,
                            0,
                            ptr::null(),
                            ptr::null());

        let vec_c = vec::from_buf(buf as *int, sz);

        libc::free(buf);

        io::println(fmt!("   %?", vec_a));
        io::println(fmt!("+  %?", vec_b));
        io::println(fmt!("=  %?", vec_c));

        // Cleanup
        clReleaseKernel(kernel);
        clReleaseProgram(prog);
        clReleaseMemObject(C);
        clReleaseMemObject(B);
        clReleaseMemObject(A);
        clReleaseCommandQueue(cque);
        clReleaseContext(ctx);
      }
    }
  }
}
<|endoftext|>


<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)]
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)]
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 {
    dir: Direction,
    type_system: ModelTypeSystem,
}

impl TypeContext {
    pub fn new( dir : Direction, type_system : ModelTypeSystem ) -> TypeContext {
        TypeContext { dir, 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 ) -> Type
    {
        self.rust_ty()
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self, ident : &Ident
    ) -> 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
    ) -> 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() {
                    "c_void"
                        | "RawComPtr"
                        => quote!( ::std::ptr::null_mut() ),
                    _ => quote!( Default::default() )
                }
            },
            _ => quote!( Default::default() )
        }
    }

    /// Gets the sype system the handler serves if the handler is type system specific. Returns
    /// None if the handler is type system agnostic.
    fn type_system( &self ) -> Option<ModelTypeSystem> { None }
}

/// 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 ) -> Type
    {
        use syn;
        let rust_ty = self.rust_ty();
        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" ),
        };
        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
    ) -> TypeConversion
    {
        let ts = self.context.type_system.as_typesystem_tokens();
        TypeConversion {
            temporary: None,
            value: quote!( ::intercom::ComItf::wrap( #ident.ptr, #ts ) ),
        }
    }

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

/// 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 ) -> Type
    {
        match self.context.dir {
            Direction::In => parse_quote!( ::intercom::raw::InBSTR ),
            Direction::Out | Direction::Retval => parse_quote!( ::intercom::raw::OutBSTR ),
        }
    }

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

            Direction::In => {

                let target_ty = self.rust_ty();
                let intermediate_ty = quote!( &::intercom::BStr );
                let to_intermediate = quote!( ::intercom::BStr::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 => {
                TypeConversion {
                    temporary: None,
                    value: quote!( ::intercom::BString::from_ptr( #ident ).com_into()? ),
                }
            },
        }
    }

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

            Direction::In => {

                let target_ty = self.rust_ty();
                let intermediate_ty = quote!( &::intercom::BStr );
                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 => {
                TypeConversion {
                    temporary: None,
                    value: quote!( ::intercom::BString::from( #ident ).into_ptr() ),
                }
            },
        }
    }

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

    /// String parameters differ between the type systems.
    fn type_system( &self ) -> Option<ModelTypeSystem> {
        Some( self.context.type_system )
    }
}

/// Resolves the `TypeHandler` to use.
pub fn get_ty_handler(
    arg_ty : &Type,
    context : TypeContext,
) -> Rc<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<TypeHandler> {

    match name {

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

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

}
<commit_msg>Improve comments on ComItfParam com_ty<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)]
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)]
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 {
    dir: Direction,
    type_system: ModelTypeSystem,
}

impl TypeContext {
    pub fn new( dir : Direction, type_system : ModelTypeSystem ) -> TypeContext {
        TypeContext { dir, 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 ) -> Type
    {
        self.rust_ty()
    }

    /// Converts a COM parameter named by the ident into a Rust type.
    fn com_to_rust(
        &self, ident : &Ident
    ) -> 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
    ) -> 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() {
                    "c_void"
                        | "RawComPtr"
                        => quote!( ::std::ptr::null_mut() ),
                    _ => quote!( Default::default() )
                }
            },
            _ => quote!( Default::default() )
        }
    }

    /// Gets the sype system the handler serves if the handler is type system specific. Returns
    /// None if the handler is type system agnostic.
    fn type_system( &self ) -> Option<ModelTypeSystem> { None }
}

/// 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 ) -> 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
    ) -> TypeConversion
    {
        let ts = self.context.type_system.as_typesystem_tokens();
        TypeConversion {
            temporary: None,
            value: quote!( ::intercom::ComItf::wrap( #ident.ptr, #ts ) ),
        }
    }

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

/// 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 ) -> Type
    {
        match self.context.dir {
            Direction::In => parse_quote!( ::intercom::raw::InBSTR ),
            Direction::Out | Direction::Retval => parse_quote!( ::intercom::raw::OutBSTR ),
        }
    }

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

            Direction::In => {

                let target_ty = self.rust_ty();
                let intermediate_ty = quote!( &::intercom::BStr );
                let to_intermediate = quote!( ::intercom::BStr::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 => {
                TypeConversion {
                    temporary: None,
                    value: quote!( ::intercom::BString::from_ptr( #ident ).com_into()? ),
                }
            },
        }
    }

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

            Direction::In => {

                let target_ty = self.rust_ty();
                let intermediate_ty = quote!( &::intercom::BStr );
                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 => {
                TypeConversion {
                    temporary: None,
                    value: quote!( ::intercom::BString::from( #ident ).into_ptr() ),
                }
            },
        }
    }

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

    /// String parameters differ between the type systems.
    fn type_system( &self ) -> Option<ModelTypeSystem> {
        Some( self.context.type_system )
    }
}

/// Resolves the `TypeHandler` to use.
pub fn get_ty_handler(
    arg_ty : &Type,
    context : TypeContext,
) -> Rc<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<TypeHandler> {

    match name {

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

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

}
<|endoftext|>


<commit_before>extern crate bio;
extern crate gte;

use gte::{GffType, GffReader,
          ExonFeatureKind as EFK, Strand};
use Strand::*;

static SINGLE_GENE_GTF: &'static str = include_str!("data/single_gene.gtf");

#[test]
fn gtf_reader_multiple_transcripts() {
    let mut reader = GffReader::from_reader(SINGLE_GENE_GTF.as_bytes(), GffType::GTF2);
    let mut transcripts = reader.transcripts(None, None, None, None, false).expect("transcripts");

    let trx1 = transcripts.next().expect("a transcript result").expect("a transcript");
    assert_eq!(trx1.seq_name(), "chr2");
    assert_eq!(trx1.start(), 176188578);
    assert_eq!(trx1.end(), 176190907);
    assert_eq!(trx1.strand(), &Forward);
    assert_eq!(trx1.exons().len(), 2);
    let trx1_exon1 = [
        ((176188578, 176188801), EFK::UTR5),
        ((176188801, 176188804), EFK::StartCodon { frame: Some(0) }),
        ((176188801, 176189453), EFK::CDS { frame: Some(0) })];
    for (eidx, feat) in trx1.exons()[0].features().iter().enumerate() {
        assert_eq!(feat.start(), (trx1_exon1[eidx].0).0);
        assert_eq!(feat.end(), (trx1_exon1[eidx].0).1);
        assert_eq!(feat.kind(), &trx1_exon1[eidx].1)
    }
    let trx1_exon2 = [
        ((176189807, 176190139), EFK::CDS { frame: Some(2) }),
        ((176190139, 176190142), EFK::StopCodon { frame: Some(0) }),
        ((176190142, 176190907), EFK::UTR3)];
    for (eidx, feat) in trx1.exons()[1].features().iter().enumerate() {
        assert_eq!(feat.start(), (trx1_exon2[eidx].0).0);
        assert_eq!(feat.end(), (trx1_exon2[eidx].0).1);
        assert_eq!(feat.kind(), &trx1_exon2[eidx].1)
    }

    let trx2 = transcripts.next().expect("a transcript result").expect("a transcript");
    assert_eq!(trx2.seq_name(), "chr2");
    assert_eq!(trx2.start(), 176188842);
    assert_eq!(trx2.end(), 176188901);
    assert_eq!(trx2.strand(), &Forward);
    assert_eq!(trx2.exons().len(), 1);
    assert_eq!(trx2.exons()[0].features().len(), 0);

    assert!(transcripts.next().is_none());
}
<commit_msg>Fix .transcripts() call in test<commit_after>extern crate bio;
extern crate gte;

use gte::{GffType, GffReader,
          ExonFeatureKind as EFK, Strand};
use Strand::*;

static SINGLE_GENE_GTF: &'static str = include_str!("data/single_gene.gtf");

#[test]
fn gtf_reader_multiple_transcripts() {
    let mut reader = GffReader::from_reader(SINGLE_GENE_GTF.as_bytes(), GffType::GTF2);
    let mut transcripts = reader.transcripts().expect("transcripts");

    let trx1 = transcripts.next().expect("a transcript result").expect("a transcript");
    assert_eq!(trx1.seq_name(), "chr2");
    assert_eq!(trx1.start(), 176188578);
    assert_eq!(trx1.end(), 176190907);
    assert_eq!(trx1.strand(), &Forward);
    assert_eq!(trx1.exons().len(), 2);
    let trx1_exon1 = [
        ((176188578, 176188801), EFK::UTR5),
        ((176188801, 176188804), EFK::StartCodon { frame: Some(0) }),
        ((176188801, 176189453), EFK::CDS { frame: Some(0) })];
    for (eidx, feat) in trx1.exons()[0].features().iter().enumerate() {
        assert_eq!(feat.start(), (trx1_exon1[eidx].0).0);
        assert_eq!(feat.end(), (trx1_exon1[eidx].0).1);
        assert_eq!(feat.kind(), &trx1_exon1[eidx].1)
    }
    let trx1_exon2 = [
        ((176189807, 176190139), EFK::CDS { frame: Some(2) }),
        ((176190139, 176190142), EFK::StopCodon { frame: Some(0) }),
        ((176190142, 176190907), EFK::UTR3)];
    for (eidx, feat) in trx1.exons()[1].features().iter().enumerate() {
        assert_eq!(feat.start(), (trx1_exon2[eidx].0).0);
        assert_eq!(feat.end(), (trx1_exon2[eidx].0).1);
        assert_eq!(feat.kind(), &trx1_exon2[eidx].1)
    }

    let trx2 = transcripts.next().expect("a transcript result").expect("a transcript");
    assert_eq!(trx2.seq_name(), "chr2");
    assert_eq!(trx2.start(), 176188842);
    assert_eq!(trx2.end(), 176188901);
    assert_eq!(trx2.strand(), &Forward);
    assert_eq!(trx2.exons().len(), 1);
    assert_eq!(trx2.exons()[0].features().len(), 0);

    assert!(transcripts.next().is_none());
}
<|endoftext|>


<commit_before>use std::env;
use std::process::{Command, Stdio};
use std::path::PathBuf;
use std::io::{Read, Write};
use std::fs::File;

extern crate nom_bibtex;
use nom_bibtex::Bibtex;

mod text;

fn read_file(filename: &str) -> Vec<u8> {
    let mut file = File::open(filename).unwrap();
    let mut content = Vec::new();
    file.read_to_end(&mut content).unwrap();

    content
}

fn get_bin_dir() -> PathBuf {
    env::current_exe()
        .expect("test bin's directory")
        .parent()
        .expect("test bin's parent directory")
        .parent()
        .expect("executable's directory")
        .to_path_buf()
}

fn cmd_aux2bib() -> Command {
    let path;
    if cfg!(not(windows)) {
        path = get_bin_dir().join("aux2bib");
    } else {
        path = get_bin_dir().join("aux2bib.exe");
    }
    if !path.is_file() {
        panic!("aux2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear().stderr(Stdio::piped()).stdout(
        Stdio::piped(),
    );

    cmd
}

fn cmd_blg2bib() -> Command {
    let path;
    if cfg!(not(windows)) {
        path = get_bin_dir().join("blg2bib");
    } else {
        path = get_bin_dir().join("blg2bib.exe");
    }
    if !path.is_file() {
        panic!("blg2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear().stderr(Stdio::piped()).stdout(
        Stdio::piped(),
    );

    cmd
}

#[cfg(not(windows))]
#[test]
fn aux2bib_runs() {
    let mut cmd = cmd_aux2bib().arg("--help").spawn().expect(
        "Failed to execute aux2bib",
    );

    let error_code = cmd.wait().expect("Failed to wait on aux2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn blg2bib_runs() {
    let mut cmd = cmd_blg2bib().arg("--help").spawn().expect(
        "Failed to execute blg2bib",
    );

    let error_code = cmd.wait().expect("Failed to wait on blg2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_empty() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_empty() {
    let mut child = cmd_blg2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute blg2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_bibtex() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let input = read_file("example_files/test_bibtex.aux");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");
    let bib = bibtex.bibliographies();
    assert_eq!(2, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Higgs:2014aqa");
    assert_eq!(
        bib[0].tags()[0],
        ("author".into(), "Higgs, Peter W.".into())
    );
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{Nobel Lecture: Evading the Goldstone theorem}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "2014".into()));

    assert_eq!(bib[1].entry_type(), "article");
    assert_eq!(bib[1].citation_key(), "Higgs:2015mei");
    assert_eq!(bib[1].tags()[0], ("author".into(), "Higgs, P. W.".into()));
    assert_eq!(bib[1].tags()[1], (
        "title".into(),
        "{Evading the Goldstone theorem}".into(),
    ));
    assert_eq!(bib[1].tags()[4], ("year".into(), "2015".into()));
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_biblatex() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let input = read_file("example_files/test_biber.aux");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex_raw = &[
        text::MONTH_STRINGS,
        std::str::from_utf8(&output.stdout).unwrap(),
    ].join("\n");
    let bibtex = Bibtex::parse(bibtex_raw).expect("Valid bibtex file content");
    let bib = bibtex.bibliographies();
    assert_eq!(4, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Guth:1980zm");
    assert_eq!(bib[0].tags()[0], ("author".into(), "Guth, Alan H.".into()));
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{The Inflationary Universe: A Possible Solution to the\n                        Horizon and Flatness Problems}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "1981".into()));

    assert_eq!(bib[3].entry_type(), "ARTICLE");
    assert_eq!(bib[3].citation_key(), "1982PhRvL..48.1220A");
    assert_eq!(bib[3].tags()[1], (
        "title".into(),
        "{Cosmology for grand unified theories with radiatively induced symmetry breaking}"
            .into(),
    ));
    assert_eq!(bib[3].tags()[4], ("year".into(), "1982".into()));
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_bibtex() {
    let mut child = cmd_blg2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let input = read_file("example_files/test_bibtex.blg");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");
    let bib = bibtex.bibliographies();
    assert_eq!(2, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Higgs:2014aqa");
    assert_eq!(
        bib[0].tags()[0],
        ("author".into(), "Higgs, Peter W.".into())
    );
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{Nobel Lecture: Evading the Goldstone theorem}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "2014".into()));

    assert_eq!(bib[1].entry_type(), "article");
    assert_eq!(bib[1].citation_key(), "Higgs:2015mei");
    assert_eq!(bib[1].tags()[0], ("author".into(), "Higgs, P. W.".into()));
    assert_eq!(bib[1].tags()[1], (
        "title".into(),
        "{Evading the Goldstone theorem}".into(),
    ));
    assert_eq!(bib[1].tags()[4], ("year".into(), "2015".into()));
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_biblatex() {
    let mut child = cmd_blg2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute blg2bib",
    );

    {
        let input = read_file("example_files/test_biber.blg");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex_raw = &[
        text::MONTH_STRINGS,
        std::str::from_utf8(&output.stdout).unwrap(),
    ].join("\n");
    let bibtex = Bibtex::parse(bibtex_raw).expect("Valid bibtex file content");
    let bib = bibtex.bibliographies();
    assert_eq!(4, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Guth:1980zm");
    assert_eq!(bib[0].tags()[0], ("author".into(), "Guth, Alan H.".into()));
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{The Inflationary Universe: A Possible Solution to the\n                        Horizon and Flatness Problems}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "1981".into()));

    assert_eq!(bib[3].entry_type(), "ARTICLE");
    assert_eq!(bib[3].citation_key(), "1982PhRvL..48.1220A");
    assert_eq!(bib[3].tags()[1], (
        "title".into(),
        "{Cosmology for grand unified theories with radiatively induced symmetry breaking}"
            .into(),
    ));
    assert_eq!(bib[3].tags()[4], ("year".into(), "1982".into()));
}
<commit_msg>refactor: factor out tests of output from binaries<commit_after>use std::env;
use std::process::{Command, Stdio};
use std::path::PathBuf;
use std::io::{Read, Write};
use std::fs::File;

extern crate nom_bibtex;
use nom_bibtex::Bibtex;

mod text;

fn read_file(filename: &str) -> Vec<u8> {
    let mut file = File::open(filename).unwrap();
    let mut content = Vec::new();
    file.read_to_end(&mut content).unwrap();

    content
}

fn get_bin_dir() -> PathBuf {
    env::current_exe()
        .expect("test bin's directory")
        .parent()
        .expect("test bin's parent directory")
        .parent()
        .expect("executable's directory")
        .to_path_buf()
}

fn cmd_aux2bib() -> Command {
    let path;
    if cfg!(not(windows)) {
        path = get_bin_dir().join("aux2bib");
    } else {
        path = get_bin_dir().join("aux2bib.exe");
    }
    if !path.is_file() {
        panic!("aux2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear().stderr(Stdio::piped()).stdout(
        Stdio::piped(),
    );

    cmd
}

fn cmd_blg2bib() -> Command {
    let path;
    if cfg!(not(windows)) {
        path = get_bin_dir().join("blg2bib");
    } else {
        path = get_bin_dir().join("blg2bib.exe");
    }
    if !path.is_file() {
        panic!("blg2bib binary {:?} was not found", path);
    }
    let mut cmd = Command::new(path);
    cmd.env_clear().stderr(Stdio::piped()).stdout(
        Stdio::piped(),
    );

    cmd
}

fn check_output_aux_bibtex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(2, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Higgs:2014aqa");
    assert_eq!(
        bib[0].tags()[0],
        ("author".into(), "Higgs, Peter W.".into())
    );
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{Nobel Lecture: Evading the Goldstone theorem}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "2014".into()));

    assert_eq!(bib[1].entry_type(), "article");
    assert_eq!(bib[1].citation_key(), "Higgs:2015mei");
    assert_eq!(bib[1].tags()[0], ("author".into(), "Higgs, P. W.".into()));
    assert_eq!(bib[1].tags()[1], (
        "title".into(),
        "{Evading the Goldstone theorem}".into(),
    ));
    assert_eq!(bib[1].tags()[4], ("year".into(), "2015".into()));
}

fn check_output_aux_biblatex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(4, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Guth:1980zm");
    assert_eq!(bib[0].tags()[0], ("author".into(), "Guth, Alan H.".into()));
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{The Inflationary Universe: A Possible Solution to the\n                        Horizon and Flatness Problems}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "1981".into()));

    assert_eq!(bib[3].entry_type(), "ARTICLE");
    assert_eq!(bib[3].citation_key(), "1982PhRvL..48.1220A");
    assert_eq!(bib[3].tags()[1], (
        "title".into(),
        "{Cosmology for grand unified theories with radiatively induced symmetry breaking}"
            .into(),
    ));
    assert_eq!(bib[3].tags()[4], ("year".into(), "1982".into()));
}

fn check_output_blg_bibtex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(2, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Higgs:2014aqa");
    assert_eq!(
        bib[0].tags()[0],
        ("author".into(), "Higgs, Peter W.".into())
    );
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{Nobel Lecture: Evading the Goldstone theorem}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "2014".into()));

    assert_eq!(bib[1].entry_type(), "article");
    assert_eq!(bib[1].citation_key(), "Higgs:2015mei");
    assert_eq!(bib[1].tags()[0], ("author".into(), "Higgs, P. W.".into()));
    assert_eq!(bib[1].tags()[1], (
        "title".into(),
        "{Evading the Goldstone theorem}".into(),
    ));
    assert_eq!(bib[1].tags()[4], ("year".into(), "2015".into()));
}

fn check_output_blg_biblatex(bibtex: &Bibtex) {
    let bib = bibtex.bibliographies();
    assert_eq!(4, bib.len());

    // Output could conceivably change in future, so just check that some things are right
    assert_eq!(bib[0].entry_type(), "article");
    assert_eq!(bib[0].citation_key(), "Guth:1980zm");
    assert_eq!(bib[0].tags()[0], ("author".into(), "Guth, Alan H.".into()));
    assert_eq!(bib[0].tags()[1], (
        "title".into(),
        "{The Inflationary Universe: A Possible Solution to the\n                        Horizon and Flatness Problems}"
            .into(),
    ));
    assert_eq!(bib[0].tags()[4], ("year".into(), "1981".into()));

    assert_eq!(bib[3].entry_type(), "ARTICLE");
    assert_eq!(bib[3].citation_key(), "1982PhRvL..48.1220A");
    assert_eq!(bib[3].tags()[1], (
        "title".into(),
        "{Cosmology for grand unified theories with radiatively induced symmetry breaking}"
            .into(),
    ));
    assert_eq!(bib[3].tags()[4], ("year".into(), "1982".into()));
}

#[cfg(not(windows))]
#[test]
fn aux2bib_runs() {
    let mut cmd = cmd_aux2bib().arg("--help").spawn().expect(
        "Failed to execute aux2bib",
    );

    let error_code = cmd.wait().expect("Failed to wait on aux2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn blg2bib_runs() {
    let mut cmd = cmd_blg2bib().arg("--help").spawn().expect(
        "Failed to execute blg2bib",
    );

    let error_code = cmd.wait().expect("Failed to wait on blg2bib");

    assert!(error_code.success());
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_empty() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_empty() {
    let mut child = cmd_blg2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute blg2bib",
    );

    {
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(b"").expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());
    assert_eq!(output.stdout, []);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_bibtex() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let input = read_file("example_files/test_bibtex.aux");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");

    check_output_aux_bibtex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn aux2bib_stdin_stdout_biblatex() {
    let mut child = cmd_aux2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let input = read_file("example_files/test_biber.aux");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex_raw = &[
        text::MONTH_STRINGS,
        std::str::from_utf8(&output.stdout).unwrap(),
    ].join("\n");
    let bibtex = Bibtex::parse(bibtex_raw).expect("Valid bibtex file content");

    check_output_aux_biblatex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_bibtex() {
    let mut child = cmd_blg2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute aux2bib",
    );

    {
        let input = read_file("example_files/test_bibtex.blg");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex = Bibtex::parse(std::str::from_utf8(&output.stdout).unwrap())
        .expect("Valid bibtex file content");

    check_output_blg_bibtex(&bibtex);
}

#[cfg(not(windows))]
#[test]
fn blg2bib_stdin_stdout_biblatex() {
    let mut child = cmd_blg2bib().stdin(Stdio::piped()).spawn().expect(
        "Failed to execute blg2bib",
    );

    {
        let input = read_file("example_files/test_biber.blg");
        let stdin = child.stdin.as_mut().expect("Failed to get stdin");
        stdin.write_all(&input).expect("Failed to write to stdin");
    }

    let output = child.wait_with_output().expect("Failed to wait on aux2bib");

    assert!(output.status.success());

    let bibtex_raw = &[
        text::MONTH_STRINGS,
        std::str::from_utf8(&output.stdout).unwrap(),
    ].join("\n");
    let bibtex = Bibtex::parse(bibtex_raw).expect("Valid bibtex file content");

    check_output_blg_biblatex(&bibtex);
}
<|endoftext|>


<commit_before>extern crate memcache;
extern crate rand;

use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use std::iter;
use std::thread;
use std::thread::JoinHandle;
use std::time;

fn gen_random_key() -> String {
    return iter::repeat(())
        .map(|()| thread_rng().sample(Alphanumeric))
        .take(10)
        .collect::<String>();
}

#[test]
fn test() {
    let mut urls = vec![
        "memcache://localhost:12346?tcp_nodelay=true",
        "memcache://localhost:12347?timeout=10",
        "memcache://localhost:12348",
        "memcache://localhost:12349",
    ];
    if cfg!(unix) {
        urls.push("memcache:///tmp/memcached2.sock");
    }
    let mut client = memcache::Client::connect(urls).unwrap();

    client.version().unwrap();

    client.set("foo", "bar", 0).unwrap();
    client.flush().unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    client.set("foo", "bar", 0).unwrap();
    client.flush_with_delay(3).unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("bar")));
    thread::sleep(time::Duration::from_secs(4));
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    let mut keys: Vec<String> = Vec::new();
    for _ in 0..1000 {
        let key = gen_random_key();
        keys.push(key.clone());
        client.set(key.as_str(), "xxx", 0).unwrap();
    }

    for key in keys {
        let value: String = client.get(key.as_str()).unwrap().unwrap();
        assert_eq!(value, "xxx");
    }
}

#[test]
fn udp_test() {
    let urls = vec!["memcache+udp://localhost:22345"];
    let mut client = memcache::Client::connect(urls).unwrap();

    client.version().unwrap();

    client.set("foo", "bar", 0).unwrap();
    client.flush().unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    client.set("foo", "bar", 0).unwrap();
    client.flush_with_delay(3).unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("bar")));
    thread::sleep(time::Duration::from_secs(4));
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    client.set("foo", "bar", 0).unwrap();
    let value = client.add("foo", "baz", 0);
    assert_eq!(value.is_err(), true);

    client.delete("foo").unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    client.add("foo", "bar", 0).unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("bar")));

    client.replace("foo", "baz", 0).unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("baz")));

    client.append("foo", "bar").unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("bazbar")));

    client.prepend("foo", "bar").unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("barbazbar")));

    client.set("fooo", 0, 0).unwrap();
    client.increment("fooo", 1).unwrap();
    let value: Option<String> = client.get("fooo").unwrap();
    assert_eq!(value, Some(String::from("1")));

    client.decrement("fooo", 1).unwrap();
    let value: Option<String> = client.get("fooo").unwrap();
    assert_eq!(value, Some(String::from("0")));

    assert_eq!(client.touch("foooo", 123).unwrap(), false);
    assert_eq!(client.touch("fooo", 12345).unwrap(), true);

    // gets is not supported for udp
    let value: Result<std::collections::HashMap<String, String>, _> = client.gets(vec!["foo", "fooo"]);
    assert_eq!(value.is_ok(), false);

    let mut keys: Vec<String> = Vec::new();
    for _ in 0..1000 {
        let key = gen_random_key();
        keys.push(key.clone());
        client.set(key.as_str(), "xxx", 0).unwrap();
    }

    for key in keys {
        let value: String = client.get(key.as_str()).unwrap().unwrap();

        assert_eq!(value, "xxx");
    }

    // test with multiple udp connections
    let mut handles: Vec<Option<JoinHandle<_>>> = Vec::new();
    for i in 0..10 {
        handles.push(Some(thread::spawn(move || {
            let key = format!("key{}", i);
            let value = format!("value{}", i);
            let mut client = memcache::Client::connect("memcache://localhost:22345?udp=true").unwrap();
            for j in 0..50 {
                let value = format!("{}{}", value, j);
                client.set(key.as_str(), value.clone(), 0).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(value.clone()));

                let result = client.add(key.as_str(), value.clone(), 0);
                assert_eq!(result.is_err(), true);

                client.delete(key.as_str()).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, None);

                client.add(key.as_str(), value.clone(), 0).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(value.clone()));

                client.replace(key.as_str(), value.clone(), 0).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(value.clone()));

                client.append(key.as_str(), value.clone()).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(format!("{}{}", value, value)));

                client.prepend(key.as_str(), value.clone()).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(format!("{}{}{}", value, value, value)));
            }
        })));
    }

    for i in 0..10 {
        handles[i].take().unwrap().join().unwrap();
    }
}
<commit_msg>:white_check_mark: Run more tests on ascii<commit_after>extern crate memcache;
extern crate rand;

use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};
use std::iter;
use std::thread;
use std::thread::JoinHandle;
use std::time;

fn gen_random_key() -> String {
    return iter::repeat(())
        .map(|()| thread_rng().sample(Alphanumeric))
        .take(10)
        .collect::<String>();
}

#[test]
fn test() {
    let mut urls = vec![
        "memcache://localhost:12346?tcp_nodelay=true",
        "memcache://localhost:12347?timeout=10",
        "memcache://localhost:12348?protocol=ascii",
        "memcache://localhost:12349?",
    ];
    if cfg!(unix) {
        urls.push("memcache:///tmp/memcached2.sock");
    }
    let mut client = memcache::Client::connect(urls).unwrap();

    client.version().unwrap();

    client.set("foo", "bar", 0).unwrap();
    client.flush().unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    client.set("foo", "bar", 0).unwrap();
    client.flush_with_delay(3).unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("bar")));
    thread::sleep(time::Duration::from_secs(4));
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    let mut keys: Vec<String> = Vec::new();
    for _ in 0..1000 {
        let key = gen_random_key();
        keys.push(key.clone());
        client.set(key.as_str(), "xxx", 0).unwrap();
    }

    for key in keys {
        let value: String = client.get(key.as_str()).unwrap().unwrap();
        assert_eq!(value, "xxx");
    }
}

#[test]
fn udp_test() {
    let urls = vec!["memcache+udp://localhost:22345"];
    let mut client = memcache::Client::connect(urls).unwrap();

    client.version().unwrap();

    client.set("foo", "bar", 0).unwrap();
    client.flush().unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    client.set("foo", "bar", 0).unwrap();
    client.flush_with_delay(3).unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("bar")));
    thread::sleep(time::Duration::from_secs(4));
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    client.set("foo", "bar", 0).unwrap();
    let value = client.add("foo", "baz", 0);
    assert_eq!(value.is_err(), true);

    client.delete("foo").unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, None);

    client.add("foo", "bar", 0).unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("bar")));

    client.replace("foo", "baz", 0).unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("baz")));

    client.append("foo", "bar").unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("bazbar")));

    client.prepend("foo", "bar").unwrap();
    let value: Option<String> = client.get("foo").unwrap();
    assert_eq!(value, Some(String::from("barbazbar")));

    client.set("fooo", 0, 0).unwrap();
    client.increment("fooo", 1).unwrap();
    let value: Option<String> = client.get("fooo").unwrap();
    assert_eq!(value, Some(String::from("1")));

    client.decrement("fooo", 1).unwrap();
    let value: Option<String> = client.get("fooo").unwrap();
    assert_eq!(value, Some(String::from("0")));

    assert_eq!(client.touch("foooo", 123).unwrap(), false);
    assert_eq!(client.touch("fooo", 12345).unwrap(), true);

    // gets is not supported for udp
    let value: Result<std::collections::HashMap<String, String>, _> = client.gets(vec!["foo", "fooo"]);
    assert_eq!(value.is_ok(), false);

    let mut keys: Vec<String> = Vec::new();
    for _ in 0..1000 {
        let key = gen_random_key();
        keys.push(key.clone());
        client.set(key.as_str(), "xxx", 0).unwrap();
    }

    for key in keys {
        let value: String = client.get(key.as_str()).unwrap().unwrap();

        assert_eq!(value, "xxx");
    }

    // test with multiple udp connections
    let mut handles: Vec<Option<JoinHandle<_>>> = Vec::new();
    for i in 0..10 {
        handles.push(Some(thread::spawn(move || {
            let key = format!("key{}", i);
            let value = format!("value{}", i);
            let mut client = memcache::Client::connect("memcache://localhost:22345?udp=true").unwrap();
            for j in 0..50 {
                let value = format!("{}{}", value, j);
                client.set(key.as_str(), value.clone(), 0).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(value.clone()));

                let result = client.add(key.as_str(), value.clone(), 0);
                assert_eq!(result.is_err(), true);

                client.delete(key.as_str()).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, None);

                client.add(key.as_str(), value.clone(), 0).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(value.clone()));

                client.replace(key.as_str(), value.clone(), 0).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(value.clone()));

                client.append(key.as_str(), value.clone()).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(format!("{}{}", value, value)));

                client.prepend(key.as_str(), value.clone()).unwrap();
                let result: Option<String> = client.get(key.as_str()).unwrap();
                assert_eq!(result, Some(format!("{}{}{}", value, value, value)));
            }
        })));
    }

    for i in 0..10 {
        handles[i].take().unwrap().join().unwrap();
    }
}
<|endoftext|>


<commit_before>use neb::ram::types;
use neb::ram::chunk;
use std::*;

macro_rules! test_nums {
    (
        $sym:ident, $io:ident, $name:ident
    ) => (
        #[test]
        fn $name () {
            let test_data = vec![$sym::MIN, $sym::MAX, 0, 1, 2, 255];
            let chunk = &chunk::init(1, 2048).list[0];
            for d in test_data {
                types::$io::write(d, chunk.addr);
                assert!(types::$io::read(chunk.addr) == d);
            }
        }
    );
}

#[test]
fn init () {

}

test_nums!(i8, i8_io, i8_test);<commit_msg>all primitive number tests<commit_after>use neb::ram::types;
use neb::ram::chunk;

macro_rules! test_nums {
    (
        $t:ident, $io:ident
    ) => (
        mod $t {
            use neb::ram::types;
            use neb::ram::chunk;
            use std;
            #[test]
            fn test () {
                let test_data = vec![std::$t::MIN, std::$t::MAX, 0 as $t, 1 as $t, 2 as $t, 255 as $t];
                let chunk = &chunk::init(1, 2048).list[0];
                for d in test_data {
                    types::$io::write(d, chunk.addr);
                    assert!(types::$io::read(chunk.addr) == d);
                }
            }
        }
    );
}

#[test]
fn init () {

}

test_nums!(i8, i8_io);
test_nums!(i16, i16_io);
test_nums!(i32, i32_io);
test_nums!(i64, i64_io);

test_nums!(u8, u8_io);
test_nums!(u16, u16_io);
test_nums!(u32, u32_io);
test_nums!(u64, u64_io);

test_nums!(isize, isize_io);
test_nums!(usize, usize_io);
test_nums!(f32, f32_io);
test_nums!(f64, f64_io);<|endoftext|>


<commit_before>use libc;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::ptr;
use std::rc::Rc;

use allowed_url::AllowedUrl;
use handle::{self, RsvgHandle};
use node::{Node, RsvgNode};
use util::utf8_cstr;

pub enum RsvgDefs {}

pub struct Defs {
    nodes: HashMap<String, Rc<Node>>,
    externs: HashMap<String, *const RsvgHandle>,
}

impl Defs {
    pub fn new() -> Defs {
        Defs {
            nodes: Default::default(),
            externs: Default::default(),
        }
    }

    pub fn insert(&mut self, id: &str, node: &Rc<Node>) {
        self.nodes.entry(id.to_string()).or_insert(node.clone());
    }

    /// Returns a node from an URI reference, or `None`
    ///
    /// This may return a node within the same RSVG handle, or a node in a secondary RSVG
    /// handle that is referenced by the current one.  If the element's id is not found,
    /// returns `None`.
    pub fn lookup(&mut self, handle: *const RsvgHandle, name: &str) -> Option<&Rc<Node>> {
        if let Ok(reference) = Reference::parse(name) {
            match reference {
                Reference::PlainUri(_) => None,
                Reference::FragmentId(fragment) => self.nodes.get(fragment),
                Reference::UriWithFragmentId(href, fragment) => {
                    match self.get_extern_handle(handle, href) {
                        Ok(extern_handle) => handle::get_defs(extern_handle).nodes.get(fragment),
                        Err(()) => None,
                    }
                }
            }
        } else {
            None
        }
    }

    fn get_extern_handle(
        &mut self,
        handle: *const RsvgHandle,
        href: &str,
    ) -> Result<*const RsvgHandle, ()> {
        let aurl =
            AllowedUrl::from_href(href, handle::get_base_url(handle).as_ref()).map_err(|_| ())?;

        match self.externs.entry(aurl.url().as_str().to_string()) {
            Entry::Occupied(e) => Ok(*(e.get())),
            Entry::Vacant(e) => {
                let extern_handle = handle::load_extern(handle, e.key())?;
                e.insert(extern_handle);
                Ok(extern_handle)
            }
        }
    }
}

/// Represents a possibly non-canonical URI with an optional fragment identifier
///
/// Sometimes in SVG element references (e.g. the `href` in the `<feImage>` element) we
/// must decide between referencing an external file, or using a plain fragment identifier
/// like `href="#foo"` as a reference to an SVG element in the same file as the one being
/// processes.  This enum makes that distinction.
#[derive(Debug, PartialEq)]
pub enum Reference<'a> {
    PlainUri(&'a str),
    FragmentId(&'a str),
    UriWithFragmentId(&'a str, &'a str),
}

impl<'a> Reference<'a> {
    pub fn parse(s: &str) -> Result<Reference, ()> {
        let (uri, fragment) = match s.rfind('#') {
            None => (Some(s), None),
            Some(p) if p == 0 => (None, Some(&s[1..])),
            Some(p) => (Some(&s[..p]), Some(&s[(p + 1)..])),
        };

        match (uri, fragment) {
            (None, Some(f)) if f.len() == 0 => Err(()),
            (None, Some(f)) => Ok(Reference::FragmentId(f)),
            (Some(u), _) if u.len() == 0 => Err(()),
            (Some(u), None) => Ok(Reference::PlainUri(u)),
            (Some(_u), Some(f)) if f.len() == 0 => Err(()),
            (Some(u), Some(f)) => Ok(Reference::UriWithFragmentId(u, f)),
            (_, _) => Err(()),
        }
    }
}

#[no_mangle]
pub extern "C" fn rsvg_defs_free(defs: *mut RsvgDefs) {
    assert!(!defs.is_null());

    unsafe {
        let defs = { &mut *(defs as *mut Defs) };
        Box::from_raw(defs);
    }
}

#[no_mangle]
pub extern "C" fn rsvg_defs_lookup(
    defs: *mut RsvgDefs,
    handle: *const RsvgHandle,
    name: *const libc::c_char,
) -> *const RsvgNode {
    assert!(!defs.is_null());
    assert!(!name.is_null());

    let defs = unsafe { &mut *(defs as *mut Defs) };
    let name = unsafe { utf8_cstr(name) };

    match defs.lookup(handle, name) {
        Some(n) => n as *const RsvgNode,
        None => ptr::null(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reference_kinds() {
        assert_eq!(Reference::parse("uri"), Ok(Reference::PlainUri("uri")));
        assert_eq!(
            Reference::parse("#fragment"),
            Ok(Reference::FragmentId("fragment"))
        );
        assert_eq!(
            Reference::parse("uri#fragment"),
            Ok(Reference::UriWithFragmentId("uri", "fragment"))
        );
    }

    #[test]
    fn reference_errors() {
        assert!(Reference::parse("").is_err());
        assert!(Reference::parse("#").is_err());
        assert!(Reference::parse("uri#").is_err());
    }
}
<commit_msg>Reference: store owned Strings internally, not string slices<commit_after>use libc;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use std::ptr;
use std::rc::Rc;

use allowed_url::AllowedUrl;
use handle::{self, RsvgHandle};
use node::{Node, RsvgNode};
use util::utf8_cstr;

pub enum RsvgDefs {}

pub struct Defs {
    nodes: HashMap<String, Rc<Node>>,
    externs: HashMap<String, *const RsvgHandle>,
}

impl Defs {
    pub fn new() -> Defs {
        Defs {
            nodes: Default::default(),
            externs: Default::default(),
        }
    }

    pub fn insert(&mut self, id: &str, node: &Rc<Node>) {
        self.nodes.entry(id.to_string()).or_insert(node.clone());
    }

    /// Returns a node from an URI reference, or `None`
    ///
    /// This may return a node within the same RSVG handle, or a node in a secondary RSVG
    /// handle that is referenced by the current one.  If the element's id is not found,
    /// returns `None`.
    pub fn lookup(&mut self, handle: *const RsvgHandle, name: &str) -> Option<&Rc<Node>> {
        if let Ok(reference) = Reference::parse(name) {
            match reference {
                Reference::PlainUri(_) => None,
                Reference::FragmentId(fragment) => self.nodes.get(&fragment),
                Reference::UriWithFragmentId(href, fragment) => {
                    match self.get_extern_handle(handle, &href) {
                        Ok(extern_handle) => handle::get_defs(extern_handle).nodes.get(&fragment),
                        Err(()) => None,
                    }
                }
            }
        } else {
            None
        }
    }

    fn get_extern_handle(
        &mut self,
        handle: *const RsvgHandle,
        href: &str,
    ) -> Result<*const RsvgHandle, ()> {
        let aurl =
            AllowedUrl::from_href(href, handle::get_base_url(handle).as_ref()).map_err(|_| ())?;

        match self.externs.entry(aurl.url().as_str().to_string()) {
            Entry::Occupied(e) => Ok(*(e.get())),
            Entry::Vacant(e) => {
                let extern_handle = handle::load_extern(handle, e.key())?;
                e.insert(extern_handle);
                Ok(extern_handle)
            }
        }
    }
}

/// Represents a possibly non-canonical URI with an optional fragment identifier
///
/// Sometimes in SVG element references (e.g. the `href` in the `<feImage>` element) we
/// must decide between referencing an external file, or using a plain fragment identifier
/// like `href="#foo"` as a reference to an SVG element in the same file as the one being
/// processes.  This enum makes that distinction.
#[derive(Debug, PartialEq)]
pub enum Reference {
    PlainUri(String),
    FragmentId(String),
    UriWithFragmentId(String, String),
}

impl Reference {
    pub fn parse(s: &str) -> Result<Reference, ()> {
        let (uri, fragment) = match s.rfind('#') {
            None => (Some(s), None),
            Some(p) if p == 0 => (None, Some(&s[1..])),
            Some(p) => (Some(&s[..p]), Some(&s[(p + 1)..])),
        };

        match (uri, fragment) {
            (None, Some(f)) if f.len() == 0 => Err(()),
            (None, Some(f)) => Ok(Reference::FragmentId(f.to_string())),
            (Some(u), _) if u.len() == 0 => Err(()),
            (Some(u), None) => Ok(Reference::PlainUri(u.to_string())),
            (Some(_u), Some(f)) if f.len() == 0 => Err(()),
            (Some(u), Some(f)) => Ok(Reference::UriWithFragmentId(u.to_string(), f.to_string())),
            (_, _) => Err(()),
        }
    }
}

#[no_mangle]
pub extern "C" fn rsvg_defs_free(defs: *mut RsvgDefs) {
    assert!(!defs.is_null());

    unsafe {
        let defs = { &mut *(defs as *mut Defs) };
        Box::from_raw(defs);
    }
}

#[no_mangle]
pub extern "C" fn rsvg_defs_lookup(
    defs: *mut RsvgDefs,
    handle: *const RsvgHandle,
    name: *const libc::c_char,
) -> *const RsvgNode {
    assert!(!defs.is_null());
    assert!(!name.is_null());

    let defs = unsafe { &mut *(defs as *mut Defs) };
    let name = unsafe { utf8_cstr(name) };

    match defs.lookup(handle, name) {
        Some(n) => n as *const RsvgNode,
        None => ptr::null(),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn reference_kinds() {
        assert_eq!(Reference::parse("uri"), Ok(Reference::PlainUri("uri".to_string())));
        assert_eq!(
            Reference::parse("#fragment"),
            Ok(Reference::FragmentId("fragment".to_string()))
        );
        assert_eq!(
            Reference::parse("uri#fragment"),
            Ok(Reference::UriWithFragmentId("uri".to_string(), "fragment".to_string()))
        );
    }

    #[test]
    fn reference_errors() {
        assert!(Reference::parse("").is_err());
        assert!(Reference::parse("#").is_err());
        assert!(Reference::parse("uri#").is_err());
    }
}
<|endoftext|>


<commit_before>use std::fmt::{Debug,Formatter,Result};
use value::{Value,ToValue,Tuple};
use self::EveFn::*;
use value::Value::Float;

// Enums...
// Expression Enum ------------------------------------------------------------
#[derive(Clone)]
pub enum Expression {
	Constant(Constant),
	Variable(Variable),
	Call(Call),
	Match(Match),
	Value(Value),
}

impl Debug for Expression {

	fn fmt(&self, f: &mut Formatter) -> Result {
		match *self {
			Expression::Constant(ref x) => write!(f,"{:?}",*x),
			Expression::Call(ref x) => write!(f,"{:?}",*x),
			_ => unimplemented!(),
		}
	}
}

pub trait ToExpression { fn to_expr(self) -> Expression; }

impl ToExpression for Expression { fn to_expr(self) -> Expression { self } }
impl ToExpression for Constant { fn to_expr(self) -> Expression { Expression::Constant(self) } }
impl ToExpression for Call { fn to_expr(self) -> Expression { Expression::Call(self) } }
impl ToExpression for i32 { fn to_expr(self) -> Expression { Expression::Value(self.to_value()) } }
impl ToExpression for f64 { fn to_expr(self) -> Expression { Expression::Value(self.to_value()) } }
impl<'a> ToExpression for &'a str { fn to_expr(self) -> Expression { Expression::Value(self.to_value()) } }
impl ToExpression for Value { fn to_expr(self) -> Expression { Expression::Value(self) } }

// End Expression Enum --------------------------------------------------------

#[derive(Clone,Debug)]
pub enum EveFn {
	// Basic ops
	Add,Subtract,Multiply,Divide,Exponentiate,

	// General math
	Sqrt,Log,Log10,Log2,Ln,Abs,Sign,Exp,

	//Trig
	Sin,Cos,Tan,ASin,ACos,ATan,ATan2,

	// Aggregates
	Sum,Prod,

	// Strings
	StrConcat,StrUpper,StrLower,StrLength,StrReplace,StrSplit,
}

#[derive(Clone)]
pub enum Variable {
	Variable(String),
}

#[derive(Clone)]
pub enum Pattern {
	Constant(Constant),
	Tuple(Tuple),
}

/*
#[derive(Clone)]
pub enum Tuple {
	Patterns(PatternVec),
}
*/

// Constant Enum --------------------------------------------------------------
#[derive(Clone,PartialEq)]
pub enum Constant {
	StringConstant(String),
	Value(Value),
}

impl Debug for Constant {

	fn fmt(&self, f: &mut Formatter) -> Result {
		match *self {
			Constant::StringConstant(ref x) => write!(f,"{:?}",*x),
			_ => unimplemented!(),
		}
	}
}

// End Constant Enum ----------------------------------------------------------

// Structs...
#[derive(Clone,Debug)]
pub struct Call {
	pub fun: EveFn,
	pub args: ExpressionVec,
}

#[derive(Clone)]
pub struct Match {
	pub patterns: PatternVec,
	pub handlers: ExpressionVec,
}

// Some type aliases
pub type PatternVec = Vec<Pattern>;
pub type ExpressionVec = Vec<Expression>;

// Macro for creating expression vectors
#[macro_export]
macro_rules! exprvec {
    ( $( $x:expr ),* ) => {
        {
            let mut temp_vec = ExpressionVec::new();
            $(
                temp_vec.push($x.to_expr());
            )*
            temp_vec
        }
    };
}

// This is the main interface to the interpreter. Pass in an expression, get a value back
pub fn calculate(e: & Expression) -> Value {

	process_expression(e)

}

fn process_expression(e: & Expression) -> Value {

	match *e {
		//Expression::Constant(ref x) =>  x.clone(),
		Expression::Call(ref x) => process_call(x),
		//Expression::Constant(ref x) => process_constant(x),
		Expression::Value(ref x) => x.clone(),
		_ => unimplemented!(),
	}
}

/*
fn process_constant(c: & Constant) -> &Value {

	match *c {
		Constant::NumericConstant(ref x) => unwrap_numeric(x).to_value(),
		Constant::StringConstant(ref x) => x.to_value(),
		_ => unimplemented!(),
	}
}
*/

fn process_call(c: &Call) -> Value {

	let args: Vec<Value> = c.args.iter().map(process_expression).collect();

	match(&c.fun, &args[..]) {

		// Basic Math
		(&Add,[Float(x),Float(y)]) => Float(x+y),
		(&Subtract,[Float(x),Float(y)]) => Float(x-y),
		(&Multiply,[Float(x),Float(y)]) => Float(x*y),
		(&Divide,[Float(x),Float(y)]) => Float(x/y),
		(&Exponentiate,[Float(x),Float(y)]) => Float(x.powf(y)),

		// Some general math functions
		(&Abs,[Float(x)]) => Float(x.abs()),
		(&Sqrt,[Float(x)]) => Float(x.sqrt()),
		(&Sign,[Float(x)]) => Float(x.signum()),
		(&Exp,[Float(x)]) => Float(x.exp()),
		(&Ln,[Float(x)]) => Float(x.ln()),
		(&Log10,[Float(x)]) => Float(x.log10()),
		(&Log2,[Float(x)]) => Float(x.log2()),

		// Trig functions
		(&Sin,[Float(x)]) => Float(x.sin()),
		(&Cos,[Float(x)]) => Float(x.cos()),
		(&Tan,[Float(x)]) => Float(x.tan()),
		(&ASin,[Float(x)]) => Float(x.asin()),
		(&ACos,[Float(x)]) => Float(x.acos()),
		(&ATan,[Float(x)]) => Float(x.atan()),
		(&ATan2,[Float(x),Float(y)]) => Float(x.atan2(y)),

		// String functions
		(&StrConcat,[Value::String(ref s1),Value::String(ref s2)]) => Value::String(s1.to_string()+&s2[..]),
		(&StrUpper,[Value::String(ref s)]) => Value::String(s.to_uppercase()),
		(&StrLower,[Value::String(ref s)]) => Value::String(s.to_lowercase()),
		(&StrLength,[Value::String(ref s)]) => Float(s.len() as f64),
		(&StrReplace,[Value::String(ref s),Value::String(ref q),Value::String(ref r)]) => Value::String(s.replace(&q[..],&r[..])),
		(&StrSplit,[Value::String(ref s)]) => {
			let w: Vec<Value> = s.words().map(|x| x.to_value()).collect();
			Value::Tuple(w)
		},

		// Aggregate functions
		//&Sum => general_agg(|x,y|{x+y},0f64,&c.args),
		//&Prod => general_agg(|x,y|{x*y},1f64,&c.args),

		// Returns an empty string for the purpose of handling incomplete function
		(_, _) => Value::String("".to_string()),
	}
}

/*
// Aggregate Functions --------------------------------------------------------

fn general_agg<F: Fn(f64,f64) -> f64>(f: F, base: f64, args: &ExpressionVec) -> Value {

	// Some fold magic!
	let acc = args.iter().fold(base,|acc,next_arg| f(acc,process_expression(next_arg).to_f64().unwrap()) );

	acc.to_value()

}
// End Aggregate Functions ----------------------------------------------------
*/<commit_msg>Handle division by 0 explicitly. We will probably push through an error to the UI instead of a panic<commit_after>use std::fmt::{Debug,Formatter,Result};
use value::{Value,ToValue,Tuple};
use self::EveFn::*;
use value::Value::Float;

// Enums...
// Expression Enum ------------------------------------------------------------
#[derive(Clone)]
pub enum Expression {
	Constant(Constant),
	Variable(Variable),
	Call(Call),
	Match(Match),
	Value(Value),
}

impl Debug for Expression {

	fn fmt(&self, f: &mut Formatter) -> Result {
		match *self {
			Expression::Constant(ref x) => write!(f,"{:?}",*x),
			Expression::Call(ref x) => write!(f,"{:?}",*x),
			_ => unimplemented!(),
		}
	}
}

pub trait ToExpression { fn to_expr(self) -> Expression; }

impl ToExpression for Expression { fn to_expr(self) -> Expression { self } }
impl ToExpression for Constant { fn to_expr(self) -> Expression { Expression::Constant(self) } }
impl ToExpression for Call { fn to_expr(self) -> Expression { Expression::Call(self) } }
impl ToExpression for i32 { fn to_expr(self) -> Expression { Expression::Value(self.to_value()) } }
impl ToExpression for f64 { fn to_expr(self) -> Expression { Expression::Value(self.to_value()) } }
impl<'a> ToExpression for &'a str { fn to_expr(self) -> Expression { Expression::Value(self.to_value()) } }
impl ToExpression for Value { fn to_expr(self) -> Expression { Expression::Value(self) } }

// End Expression Enum --------------------------------------------------------

#[derive(Clone,Debug)]
pub enum EveFn {
	// Basic ops
	Add,Subtract,Multiply,Divide,Exponentiate,

	// General math
	Sqrt,Log,Log10,Log2,Ln,Abs,Sign,Exp,

	//Trig
	Sin,Cos,Tan,ASin,ACos,ATan,ATan2,

	// Aggregates
	Sum,Prod,

	// Strings
	StrConcat,StrUpper,StrLower,StrLength,StrReplace,StrSplit,
}

#[derive(Clone)]
pub enum Variable {
	Variable(String),
}

#[derive(Clone)]
pub enum Pattern {
	Constant(Constant),
	Tuple(Tuple),
}

/*
#[derive(Clone)]
pub enum Tuple {
	Patterns(PatternVec),
}
*/

// Constant Enum --------------------------------------------------------------
#[derive(Clone,PartialEq)]
pub enum Constant {
	StringConstant(String),
	Value(Value),
}

impl Debug for Constant {

	fn fmt(&self, f: &mut Formatter) -> Result {
		match *self {
			Constant::StringConstant(ref x) => write!(f,"{:?}",*x),
			_ => unimplemented!(),
		}
	}
}

// End Constant Enum ----------------------------------------------------------

// Structs...
#[derive(Clone,Debug)]
pub struct Call {
	pub fun: EveFn,
	pub args: ExpressionVec,
}

#[derive(Clone)]
pub struct Match {
	pub patterns: PatternVec,
	pub handlers: ExpressionVec,
}

// Some type aliases
pub type PatternVec = Vec<Pattern>;
pub type ExpressionVec = Vec<Expression>;

// Macro for creating expression vectors
#[macro_export]
macro_rules! exprvec {
    ( $( $x:expr ),* ) => {
        {
            let mut temp_vec = ExpressionVec::new();
            $(
                temp_vec.push($x.to_expr());
            )*
            temp_vec
        }
    };
}

// This is the main interface to the interpreter. Pass in an expression, get a value back
pub fn calculate(e: & Expression) -> Value {

	process_expression(e)

}

fn process_expression(e: & Expression) -> Value {

	match *e {
		//Expression::Constant(ref x) =>  x.clone(),
		Expression::Call(ref x) => process_call(x),
		//Expression::Constant(ref x) => process_constant(x),
		Expression::Value(ref x) => x.clone(),
		_ => unimplemented!(),
	}
}

/*
fn process_constant(c: & Constant) -> &Value {

	match *c {
		Constant::NumericConstant(ref x) => unwrap_numeric(x).to_value(),
		Constant::StringConstant(ref x) => x.to_value(),
		_ => unimplemented!(),
	}
}
*/

fn process_call(c: &Call) -> Value {

	let args: Vec<Value> = c.args.iter().map(process_expression).collect();

	match(&c.fun, &args[..]) {

		// Basic Math
		(&Add,[Float(x),Float(y)]) => Float(x+y),
		(&Subtract,[Float(x),Float(y)]) => Float(x-y),
		(&Multiply,[Float(x),Float(y)]) => Float(x*y),
		(&Divide,[Float(x),Float(y)]) => {
			if y == 0f64 { panic!("Error: Division by 0"); }
			Float(x/y)
		},
		(&Exponentiate,[Float(x),Float(y)]) => Float(x.powf(y)),

		// Some general math functions
		(&Abs,[Float(x)]) => Float(x.abs()),
		(&Sqrt,[Float(x)]) => Float(x.sqrt()),
		(&Sign,[Float(x)]) => Float(x.signum()),
		(&Exp,[Float(x)]) => Float(x.exp()),
		(&Ln,[Float(x)]) => Float(x.ln()),
		(&Log10,[Float(x)]) => Float(x.log10()),
		(&Log2,[Float(x)]) => Float(x.log2()),

		// Trig functions
		(&Sin,[Float(x)]) => Float(x.sin()),
		(&Cos,[Float(x)]) => Float(x.cos()),
		(&Tan,[Float(x)]) => Float(x.tan()),
		(&ASin,[Float(x)]) => Float(x.asin()),
		(&ACos,[Float(x)]) => Float(x.acos()),
		(&ATan,[Float(x)]) => Float(x.atan()),
		(&ATan2,[Float(x),Float(y)]) => Float(x.atan2(y)),

		// String functions
		(&StrConcat,[Value::String(ref s1),Value::String(ref s2)]) => Value::String(s1.to_string()+&s2[..]),
		(&StrUpper,[Value::String(ref s)]) => Value::String(s.to_uppercase()),
		(&StrLower,[Value::String(ref s)]) => Value::String(s.to_lowercase()),
		(&StrLength,[Value::String(ref s)]) => Float(s.len() as f64),
		(&StrReplace,[Value::String(ref s),Value::String(ref q),Value::String(ref r)]) => Value::String(s.replace(&q[..],&r[..])),
		(&StrSplit,[Value::String(ref s)]) => {
			let w: Vec<Value> = s.words().map(|x| x.to_value()).collect();
			Value::Tuple(w)
		},

		// Aggregate functions
		//&Sum => general_agg(|x,y|{x+y},0f64,&c.args),
		//&Prod => general_agg(|x,y|{x*y},1f64,&c.args),

		// Returns an empty string for the purpose of handling incomplete function
		(_, _) => Value::String("".to_string()),
	}
}

/*
// Aggregate Functions --------------------------------------------------------

fn general_agg<F: Fn(f64,f64) -> f64>(f: F, base: f64, args: &ExpressionVec) -> Value {

	// Some fold magic!
	let acc = args.iter().fold(base,|acc,next_arg| f(acc,process_expression(next_arg).to_f64().unwrap()) );

	acc.to_value()

}
// End Aggregate Functions ----------------------------------------------------
*/<|endoftext|>


<commit_before>fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

// ANCHOR: here
fn calculate_length(s: &String) -> usize { // s is a reference to a String
    s.len()
} // 这里，s 离开了作用域。但因为它并不拥有引用值的所有权，
  // 所以什么也不会发生
// ANCHOR_END: here
<commit_msg>comment没有翻译<commit_after>fn main() {
    let s1 = String::from("hello");

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

// ANCHOR: here
fn calculate_length(s: &String) -> usize { // s是String的引用
    s.len()
} // 这里，s 离开了作用域。但因为它并不拥有引用值的所有权，
  // 所以什么也不会发生
// ANCHOR_END: here
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

//! Common Parquet errors and macros.

use std::{cell, convert, io, result};

use quick_error::quick_error;
use snap;
use thrift;

quick_error! {
  /// Set of errors that can be produced during different operations in Parquet.
  #[derive(Debug, PartialEq)]
  pub enum ParquetError {
      /// General Parquet error.
      /// Returned when code violates normal workflow of working with Parquet files.
      General(message: String) {
          display("Parquet error: {}", message)
              description(message)
              from(e: io::Error) -> (format!("underlying IO error: {}", e))
              from(e: snap::Error) -> (format!("underlying snap error: {}", e))
              from(e: thrift::Error) -> (format!("underlying Thrift error: {}", e))
              from(e: cell::BorrowMutError) -> (format!("underlying borrow error: {}", e))
      }
      /// "Not yet implemented" Parquet error.
      /// Returned when functionality is not yet available.
      NYI(message: String) {
          display("NYI: {}", message)
              description(message)
      }
      /// "End of file" Parquet error.
      /// Returned when IO related failures occur, e.g. when there are not enough bytes to
      /// decode.
      EOF(message: String) {
          display("EOF: {}", message)
              description(message)
      }
      /// Arrow error.
      /// Returned when reading into arrow or writing from arrow.
      ArrowError(message:  String) {
          display("Arrow: {}", message)
              description(message)
      }
  }
}

/// A specialized `Result` for Parquet errors.
pub type Result<T> = result::Result<T, ParquetError>;

// ----------------------------------------------------------------------
// Conversion from `ParquetError` to other types of `Error`s

impl convert::From<ParquetError> for io::Error {
    fn from(e: ParquetError) -> Self {
        io::Error::new(io::ErrorKind::Other, e)
    }
}

// ----------------------------------------------------------------------
// Convenient macros for different errors

macro_rules! general_err {
    ($fmt:expr) => (ParquetError::General($fmt.to_owned()));
    ($fmt:expr, $($args:expr),*) => (ParquetError::General(format!($fmt, $($args),*)));
    ($e:expr, $fmt:expr) => (ParquetError::General($fmt.to_owned(), $e));
    ($e:ident, $fmt:expr, $($args:tt),*) => (
        ParquetError::General(&format!($fmt, $($args),*), $e));
}

macro_rules! nyi_err {
    ($fmt:expr) => (ParquetError::NYI($fmt.to_owned()));
    ($fmt:expr, $($args:expr),*) => (ParquetError::NYI(format!($fmt, $($args),*)));
}

macro_rules! eof_err {
    ($fmt:expr) => (ParquetError::EOF($fmt.to_owned()));
    ($fmt:expr, $($args:expr),*) => (ParquetError::EOF(format!($fmt, $($args),*)));
}
<commit_msg>ARROW-4525: [Rust] [Parquet] Enable conversion of ArrowError to ParquetError<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.

//! Common Parquet errors and macros.

use std::{cell, convert, io, result};

use arrow::error::ArrowError;
use quick_error::quick_error;
use snap;
use thrift;

quick_error! {
  /// Set of errors that can be produced during different operations in Parquet.
  #[derive(Debug, PartialEq)]
  pub enum ParquetError {
      /// General Parquet error.
      /// Returned when code violates normal workflow of working with Parquet files.
      General(message: String) {
          display("Parquet error: {}", message)
              description(message)
              from(e: io::Error) -> (format!("underlying IO error: {}", e))
              from(e: snap::Error) -> (format!("underlying snap error: {}", e))
              from(e: thrift::Error) -> (format!("underlying Thrift error: {}", e))
              from(e: cell::BorrowMutError) -> (format!("underlying borrow error: {}", e))
      }
      /// "Not yet implemented" Parquet error.
      /// Returned when functionality is not yet available.
      NYI(message: String) {
          display("NYI: {}", message)
              description(message)
      }
      /// "End of file" Parquet error.
      /// Returned when IO related failures occur, e.g. when there are not enough bytes to
      /// decode.
      EOF(message: String) {
          display("EOF: {}", message)
              description(message)
      }
      /// Arrow error.
      /// Returned when reading into arrow or writing from arrow.
      ArrowError(message:  String) {
          display("Arrow: {}", message)
              description(message)
              from(e: ArrowError) -> (format!("underlying Arrow error: {:?}", e))
      }
  }
}

/// A specialized `Result` for Parquet errors.
pub type Result<T> = result::Result<T, ParquetError>;

// ----------------------------------------------------------------------
// Conversion from `ParquetError` to other types of `Error`s

impl convert::From<ParquetError> for io::Error {
    fn from(e: ParquetError) -> Self {
        io::Error::new(io::ErrorKind::Other, e)
    }
}

// ----------------------------------------------------------------------
// Convenient macros for different errors

macro_rules! general_err {
    ($fmt:expr) => (ParquetError::General($fmt.to_owned()));
    ($fmt:expr, $($args:expr),*) => (ParquetError::General(format!($fmt, $($args),*)));
    ($e:expr, $fmt:expr) => (ParquetError::General($fmt.to_owned(), $e));
    ($e:ident, $fmt:expr, $($args:tt),*) => (
        ParquetError::General(&format!($fmt, $($args),*), $e));
}

macro_rules! nyi_err {
    ($fmt:expr) => (ParquetError::NYI($fmt.to_owned()));
    ($fmt:expr, $($args:expr),*) => (ParquetError::NYI(format!($fmt, $($args),*)));
}

macro_rules! eof_err {
    ($fmt:expr) => (ParquetError::EOF($fmt.to_owned()));
    ($fmt:expr, $($args:expr),*) => (ParquetError::EOF(format!($fmt, $($args),*)));
}
<|endoftext|>