<commit_before>use llvm_sys::core::LLVMGetTypeKind;
use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use crate::types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
use crate::types::traits::AsTypeRef;
use crate::values::{BasicValue, BasicValueEnum, IntValue};

use std::convert::TryFrom;

macro_rules! enum_type_set {
    ($(#[$enum_attrs:meta])* $enum_name:ident: { $($(#[$variant_attrs:meta])* $args:ident,)+ }) => (
        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
        $(#[$enum_attrs])*
        pub enum $enum_name<'ctx> {
            $(
                $(#[$variant_attrs])*
                $args($args<'ctx>),
            )*
        }

        impl AsTypeRef for $enum_name<'_> {
            fn as_type_ref(&self) -> LLVMTypeRef {
                match *self {
                    $(
                        $enum_name::$args(ref t) => t.as_type_ref(),
                    )*
                }
            }
        }

        $(
            impl<'ctx> From<$args<'ctx>> for $enum_name<'ctx> {
                fn from(value: $args) -> $enum_name {
                    $enum_name::$args(value)
                }
            }

            impl<'ctx> TryFrom<$enum_name<'ctx>> for $args<'ctx> {
                type Error = ();

                fn try_from(value: $enum_name<'ctx>) -> Result<Self, Self::Error> {
                    match value {
                        $enum_name::$args(ty) => Ok(ty),
                        _ => Err(()),
                    }
                }
            }
        )*
    );
}

enum_type_set! {
    /// A wrapper for any `BasicType`, `VoidType`, or `FunctionType`.
    AnyTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// A function return and parameter definition.
        FunctionType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
        /// A valueless type.
        VoidType,
    }
}
enum_type_set! {
    /// A wrapper for any `BasicType`.
    BasicTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
    }
}

impl<'ctx> AnyTypeEnum<'ctx> {
    pub(crate) fn new(type_: LLVMTypeRef) -> Self {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMVoidTypeKind => AnyTypeEnum::VoidType(VoidType::new(type_)),
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(feature = "llvm11-0")]
            LLVMTypeKind::LLVMBFloatTypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
            LLVMTypeKind::LLVMIntegerTypeKind => AnyTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMFunctionTypeKind => AnyTypeEnum::FunctionType(FunctionType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => AnyTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => AnyTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => AnyTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(feature = "llvm11-0")]
            LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"),
        }
    }

    /// This will panic if type is a void or function type.
    pub(crate) fn to_basic_type_enum(&self) -> BasicTypeEnum<'ctx> {
        BasicTypeEnum::new(self.as_type_ref())
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let AnyTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let AnyTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_function_type(self) -> FunctionType<'ctx> {
        if let AnyTypeEnum::FunctionType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let AnyTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let AnyTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let AnyTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let AnyTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_void_type(self) -> VoidType<'ctx> {
        if let AnyTypeEnum::VoidType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        if let AnyTypeEnum::ArrayType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_float_type(self) -> bool {
        if let AnyTypeEnum::FloatType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_function_type(self) -> bool {
        if let AnyTypeEnum::FunctionType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_int_type(self) -> bool {
        if let AnyTypeEnum::IntType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_pointer_type(self) -> bool {
        if let AnyTypeEnum::PointerType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_struct_type(self) -> bool {
        if let AnyTypeEnum::StructType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_vector_type(self) -> bool {
        if let AnyTypeEnum::VectorType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_void_type(self) -> bool {
        if let AnyTypeEnum::VoidType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn size_of(&self) -> Option<IntValue<'ctx>> {
        match self {
            AnyTypeEnum::ArrayType(t) => t.size_of(),
            AnyTypeEnum::FloatType(t) => Some(t.size_of()),
            AnyTypeEnum::IntType(t) => Some(t.size_of()),
            AnyTypeEnum::PointerType(t) => Some(t.size_of()),
            AnyTypeEnum::StructType(t) => t.size_of(),
            AnyTypeEnum::VectorType(t) => t.size_of(),
            AnyTypeEnum::VoidType(_) => None,
            AnyTypeEnum::FunctionType(_) => None,
        }
    }
}

impl<'ctx> BasicTypeEnum<'ctx> {
    pub(crate) fn new(type_: LLVMTypeRef) -> Self {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(feature= "llvm11-0")]
            LLVMTypeKind::LLVMBFloatTypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => BasicTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => BasicTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => BasicTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(feature= "llvm11-0")]
            LLVMTypeKind::LLVMScalableVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported basic type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported basic type: MMX"),
            LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"),
            LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"),
            LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported basic type: FunctionType"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => unreachable!("Unsupported basic type: Token"),
        }
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let BasicTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let BasicTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let BasicTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let BasicTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let BasicTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let BasicTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        if let BasicTypeEnum::ArrayType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_float_type(self) -> bool {
        if let BasicTypeEnum::FloatType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_int_type(self) -> bool {
        if let BasicTypeEnum::IntType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_pointer_type(self) -> bool {
        if let BasicTypeEnum::PointerType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_struct_type(self) -> bool {
        if let BasicTypeEnum::StructType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_vector_type(self) -> bool {
        if let BasicTypeEnum::VectorType(_) = self {
            true
        } else {
            false
        }
    }

    /// Creates a constant `BasicValueZero`.
    ///
    /// # Example
    /// ```
    /// use inkwell::context::Context;
    /// use crate::inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type().as_basic_type_enum();
    /// let f32_zero = f32_type.const_zero();
    /// ```
    pub fn const_zero(self) -> BasicValueEnum<'ctx> {
        match self {
            BasicTypeEnum::ArrayType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::FloatType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::IntType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::PointerType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::StructType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::VectorType(ty) => ty.const_zero().as_basic_value_enum(),
        }
    }
}

impl<'ctx> TryFrom<AnyTypeEnum<'ctx>> for BasicTypeEnum<'ctx> {
    type Error = ();

    fn try_from(value: AnyTypeEnum<'ctx>) -> Result<Self, Self::Error> {
        Ok(match value {
            AnyTypeEnum::ArrayType(at) => at.into(),
            AnyTypeEnum::FloatType(ft) => ft.into(),
            AnyTypeEnum::IntType(it) => it.into(),
            AnyTypeEnum::PointerType(pt) => pt.into(),
            AnyTypeEnum::StructType(st) => st.into(),
            AnyTypeEnum::VectorType(vt) => vt.into(),
            _ => return Err(()),
        })
    }
}
<commit_msg>use matches! in is_xxx for AnyTypeEnum<commit_after>use llvm_sys::core::LLVMGetTypeKind;
use llvm_sys::LLVMTypeKind;
use llvm_sys::prelude::LLVMTypeRef;

use crate::types::{IntType, VoidType, FunctionType, PointerType, VectorType, ArrayType, StructType, FloatType};
use crate::types::traits::AsTypeRef;
use crate::values::{BasicValue, BasicValueEnum, IntValue};

use std::convert::TryFrom;

macro_rules! enum_type_set {
    ($(#[$enum_attrs:meta])* $enum_name:ident: { $($(#[$variant_attrs:meta])* $args:ident,)+ }) => (
        #[derive(Debug, PartialEq, Eq, Clone, Copy)]
        $(#[$enum_attrs])*
        pub enum $enum_name<'ctx> {
            $(
                $(#[$variant_attrs])*
                $args($args<'ctx>),
            )*
        }

        impl AsTypeRef for $enum_name<'_> {
            fn as_type_ref(&self) -> LLVMTypeRef {
                match *self {
                    $(
                        $enum_name::$args(ref t) => t.as_type_ref(),
                    )*
                }
            }
        }

        $(
            impl<'ctx> From<$args<'ctx>> for $enum_name<'ctx> {
                fn from(value: $args) -> $enum_name {
                    $enum_name::$args(value)
                }
            }

            impl<'ctx> TryFrom<$enum_name<'ctx>> for $args<'ctx> {
                type Error = ();

                fn try_from(value: $enum_name<'ctx>) -> Result<Self, Self::Error> {
                    match value {
                        $enum_name::$args(ty) => Ok(ty),
                        _ => Err(()),
                    }
                }
            }
        )*
    );
}

enum_type_set! {
    /// A wrapper for any `BasicType`, `VoidType`, or `FunctionType`.
    AnyTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// A function return and parameter definition.
        FunctionType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
        /// A valueless type.
        VoidType,
    }
}
enum_type_set! {
    /// A wrapper for any `BasicType`.
    BasicTypeEnum: {
        /// A contiguous homogeneous container type.
        ArrayType,
        /// A floating point type.
        FloatType,
        /// An integer type.
        IntType,
        /// A pointer type.
        PointerType,
        /// A contiguous heterogeneous container type.
        StructType,
        /// A contiguous homogeneous "SIMD" container type.
        VectorType,
    }
}

impl<'ctx> AnyTypeEnum<'ctx> {
    pub(crate) fn new(type_: LLVMTypeRef) -> Self {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMVoidTypeKind => AnyTypeEnum::VoidType(VoidType::new(type_)),
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(feature = "llvm11-0")]
            LLVMTypeKind::LLVMBFloatTypeKind => AnyTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMLabelTypeKind => panic!("FIXME: Unsupported type: Label"),
            LLVMTypeKind::LLVMIntegerTypeKind => AnyTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMFunctionTypeKind => AnyTypeEnum::FunctionType(FunctionType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => AnyTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => AnyTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => AnyTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(feature = "llvm11-0")]
            LLVMTypeKind::LLVMScalableVectorTypeKind => AnyTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => panic!("FIXME: Unsupported type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => panic!("FIXME: Unsupported type: MMX"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => panic!("FIXME: Unsupported type: Token"),
        }
    }

    /// This will panic if type is a void or function type.
    pub(crate) fn to_basic_type_enum(&self) -> BasicTypeEnum<'ctx> {
        BasicTypeEnum::new(self.as_type_ref())
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let AnyTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let AnyTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_function_type(self) -> FunctionType<'ctx> {
        if let AnyTypeEnum::FunctionType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let AnyTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let AnyTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let AnyTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let AnyTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_void_type(self) -> VoidType<'ctx> {
        if let AnyTypeEnum::VoidType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        matches!(self, AnyTypeEnum::ArrayType(_))
    }

    pub fn is_float_type(self) -> bool {
        matches!(self, AnyTypeEnum::FloatType(_))
    }

    pub fn is_function_type(self) -> bool {
        matches!(self, AnyTypeEnum::FunctionType(_))
    }

    pub fn is_int_type(self) -> bool {
        matches!(self, AnyTypeEnum::IntType(_))
    }

    pub fn is_pointer_type(self) -> bool {
        matches!(self, AnyTypeEnum::PointerType(_))
    }

    pub fn is_struct_type(self) -> bool {
        matches!(self, AnyTypeEnum::StructType(_))
    }

    pub fn is_vector_type(self) -> bool {
        matches!(self, AnyTypeEnum::VectorType(_))
    }

    pub fn is_void_type(self) -> bool {
        matches!(self, AnyTypeEnum::VoidType(_))
    }

    pub fn size_of(&self) -> Option<IntValue<'ctx>> {
        match self {
            AnyTypeEnum::ArrayType(t) => t.size_of(),
            AnyTypeEnum::FloatType(t) => Some(t.size_of()),
            AnyTypeEnum::IntType(t) => Some(t.size_of()),
            AnyTypeEnum::PointerType(t) => Some(t.size_of()),
            AnyTypeEnum::StructType(t) => t.size_of(),
            AnyTypeEnum::VectorType(t) => t.size_of(),
            AnyTypeEnum::VoidType(_) => None,
            AnyTypeEnum::FunctionType(_) => None,
        }
    }
}

impl<'ctx> BasicTypeEnum<'ctx> {
    pub(crate) fn new(type_: LLVMTypeRef) -> Self {
        let type_kind = unsafe {
            LLVMGetTypeKind(type_)
        };

        match type_kind {
            LLVMTypeKind::LLVMHalfTypeKind |
            LLVMTypeKind::LLVMFloatTypeKind |
            LLVMTypeKind::LLVMDoubleTypeKind |
            LLVMTypeKind::LLVMX86_FP80TypeKind |
            LLVMTypeKind::LLVMFP128TypeKind |
            LLVMTypeKind::LLVMPPC_FP128TypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            #[cfg(feature= "llvm11-0")]
            LLVMTypeKind::LLVMBFloatTypeKind => BasicTypeEnum::FloatType(FloatType::new(type_)),
            LLVMTypeKind::LLVMIntegerTypeKind => BasicTypeEnum::IntType(IntType::new(type_)),
            LLVMTypeKind::LLVMStructTypeKind => BasicTypeEnum::StructType(StructType::new(type_)),
            LLVMTypeKind::LLVMPointerTypeKind => BasicTypeEnum::PointerType(PointerType::new(type_)),
            LLVMTypeKind::LLVMArrayTypeKind => BasicTypeEnum::ArrayType(ArrayType::new(type_)),
            LLVMTypeKind::LLVMVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            #[cfg(feature= "llvm11-0")]
            LLVMTypeKind::LLVMScalableVectorTypeKind => BasicTypeEnum::VectorType(VectorType::new(type_)),
            LLVMTypeKind::LLVMMetadataTypeKind => unreachable!("Unsupported basic type: Metadata"),
            LLVMTypeKind::LLVMX86_MMXTypeKind => unreachable!("Unsupported basic type: MMX"),
            LLVMTypeKind::LLVMLabelTypeKind => unreachable!("Unsupported basic type: Label"),
            LLVMTypeKind::LLVMVoidTypeKind => unreachable!("Unsupported basic type: VoidType"),
            LLVMTypeKind::LLVMFunctionTypeKind => unreachable!("Unsupported basic type: FunctionType"),
            #[cfg(not(any(feature = "llvm3-6", feature = "llvm3-7")))]
            LLVMTypeKind::LLVMTokenTypeKind => unreachable!("Unsupported basic type: Token"),
        }
    }

    pub fn into_array_type(self) -> ArrayType<'ctx> {
        if let BasicTypeEnum::ArrayType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_float_type(self) -> FloatType<'ctx> {
        if let BasicTypeEnum::FloatType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_int_type(self) -> IntType<'ctx> {
        if let BasicTypeEnum::IntType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_pointer_type(self) -> PointerType<'ctx> {
        if let BasicTypeEnum::PointerType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_struct_type(self) -> StructType<'ctx> {
        if let BasicTypeEnum::StructType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn into_vector_type(self) -> VectorType<'ctx> {
        if let BasicTypeEnum::VectorType(t) = self {
            t
        } else {
            panic!("Found {:?} but expected another variant", self);
        }
    }

    pub fn is_array_type(self) -> bool {
        if let BasicTypeEnum::ArrayType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_float_type(self) -> bool {
        if let BasicTypeEnum::FloatType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_int_type(self) -> bool {
        if let BasicTypeEnum::IntType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_pointer_type(self) -> bool {
        if let BasicTypeEnum::PointerType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_struct_type(self) -> bool {
        if let BasicTypeEnum::StructType(_) = self {
            true
        } else {
            false
        }
    }

    pub fn is_vector_type(self) -> bool {
        if let BasicTypeEnum::VectorType(_) = self {
            true
        } else {
            false
        }
    }

    /// Creates a constant `BasicValueZero`.
    ///
    /// # Example
    /// ```
    /// use inkwell::context::Context;
    /// use crate::inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let f32_type = context.f32_type().as_basic_type_enum();
    /// let f32_zero = f32_type.const_zero();
    /// ```
    pub fn const_zero(self) -> BasicValueEnum<'ctx> {
        match self {
            BasicTypeEnum::ArrayType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::FloatType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::IntType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::PointerType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::StructType(ty) => ty.const_zero().as_basic_value_enum(),
            BasicTypeEnum::VectorType(ty) => ty.const_zero().as_basic_value_enum(),
        }
    }
}

impl<'ctx> TryFrom<AnyTypeEnum<'ctx>> for BasicTypeEnum<'ctx> {
    type Error = ();

    fn try_from(value: AnyTypeEnum<'ctx>) -> Result<Self, Self::Error> {
        Ok(match value {
            AnyTypeEnum::ArrayType(at) => at.into(),
            AnyTypeEnum::FloatType(ft) => ft.into(),
            AnyTypeEnum::IntType(it) => it.into(),
            AnyTypeEnum::PointerType(pt) => pt.into(),
            AnyTypeEnum::StructType(st) => st.into(),
            AnyTypeEnum::VectorType(vt) => vt.into(),
            _ => return Err(()),
        })
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code, non_camel_case_types)]

extern crate libc;

pub use self::utmpx::{UT_NAMESIZE,UT_LINESIZE,DEFAULT_FILE,USER_PROCESS,BOOT_TIME,c_utmp};
#[cfg(target_os = "linux")]
mod utmpx {
    use super::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmp";

    pub const UT_LINESIZE: usize = 32;
    pub const UT_NAMESIZE: usize = 32;
    pub const UT_IDSIZE: usize = 4;
    pub const UT_HOSTSIZE: usize = 256;

    pub const EMPTY: libc::c_short = 0;
    pub const RUN_LVL: libc::c_short = 1;
    pub const BOOT_TIME: libc::c_short = 2;
    pub const NEW_TIME: libc::c_short = 3;
    pub const OLD_TIME: libc::c_short = 4;
    pub const INIT_PROCESS: libc::c_short = 5;
    pub const LOGIN_PROCESS: libc::c_short = 6;
    pub const USER_PROCESS: libc::c_short = 7;
    pub const DEAD_PROCESS: libc::c_short = 8;
    pub const ACCOUNTING: libc::c_short = 9;

    #[repr(C)]
    pub struct timeval {
        pub tv_sec: libc::int32_t,
        pub tv_usec: libc::int32_t,
    }

    #[repr(C)]
    pub struct c_exit_status {
        pub e_termination: libc::c_short,
        pub e_exit: libc::c_short,
    }

    #[repr(C)]
    pub struct c_utmp {
        pub ut_type: libc::c_short,
        pub ut_pid: libc::pid_t,
        pub ut_line: [libc::c_char; UT_LINESIZE],
        pub ut_id: [libc::c_char; UT_IDSIZE],

        pub ut_user: [libc::c_char; UT_NAMESIZE],
        pub ut_host: [libc::c_char; UT_HOSTSIZE],
        pub ut_exit: c_exit_status,
        pub ut_session: libc::int32_t,
        pub ut_tv: timeval,

        pub ut_addr_v6: [libc::int32_t; 4],
        pub __unused: [libc::c_char; 20],
    }
}

#[cfg(target_os = "macos")]
mod utmpx {
    use super::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";

    pub const UT_LINESIZE: usize = 32;
    pub const UT_NAMESIZE: usize = 256;
    pub const UT_IDSIZE: usize = 4;
    pub const UT_HOSTSIZE: usize = 256;

    pub const EMPTY: libc::c_short = 0;
    pub const RUN_LVL: libc::c_short = 1;
    pub const BOOT_TIME: libc::c_short = 2;
    pub const OLD_TIME: libc::c_short = 3;
    pub const NEW_TIME: libc::c_short = 4;
    pub const INIT_PROCESS: libc::c_short = 5;
    pub const LOGIN_PROCESS: libc::c_short = 6;
    pub const USER_PROCESS: libc::c_short = 7;
    pub const DEAD_PROCESS: libc::c_short = 8;
    pub const ACCOUNTING: libc::c_short = 9;

    #[repr(C)]
    pub struct c_exit_status {
        pub e_termination: libc::c_short,
        pub e_exit: libc::c_short,
    }

    #[repr(C)]
    pub struct c_utmp {
        pub ut_user: [libc::c_char; UT_NAMESIZE],
        pub ut_id: [libc::c_char; UT_IDSIZE],
        pub ut_line: [libc::c_char; UT_LINESIZE],
        pub ut_pid: libc::pid_t,
        pub ut_type: libc::c_short,
        pub ut_tv: libc::timeval,
        pub ut_host: [libc::c_char; UT_HOSTSIZE],
        pub __unused: [libc::c_char; 16]
    }
}

#[cfg(target_os = "freebsd")]
mod utmpx {
    use super::libc;

    pub static DEFAULT_FILE : &'static str = "";

    pub const UT_LINESIZE : usize = 16;
    pub const UT_NAMESIZE : usize = 32;
    pub const UT_IDSIZE   : usize = 8;
    pub const UT_HOSTSIZE : usize = 128;

    pub const EMPTY         : libc::c_short = 0;
    pub const BOOT_TIME     : libc::c_short = 1;
    pub const OLD_TIME      : libc::c_short = 2;
    pub const NEW_TIME      : libc::c_short = 3;
    pub const USER_PROCESS  : libc::c_short = 4;
    pub const INIT_PROCESS  : libc::c_short = 5;
    pub const LOGIN_PROCESS : libc::c_short = 6;
    pub const DEAD_PROCESS  : libc::c_short = 7;
    pub const SHUTDOWN_TIME : libc::c_short = 8;

    #[repr(C)]
    pub struct c_utmp {
        pub ut_type : libc::c_short,
        pub ut_tv   : libc::timeval,
        pub ut_id   : [libc::c_char; UT_IDSIZE],
        pub ut_pid  : libc::pid_t,
        pub ut_user : [libc::c_char; UT_NAMESIZE],
        pub ut_line : [libc::c_char; UT_LINESIZE],
        pub ut_host : [libc::c_char; UT_HOSTSIZE],
        pub ut_spare : [libc::c_char; 64],
    }
}
<commit_msg>uucore::utmpx: revert the changes<commit_after>#![allow(dead_code, non_camel_case_types)]

extern crate libc;

pub use self::utmpx::{UT_NAMESIZE,UT_LINESIZE,DEFAULT_FILE,USER_PROCESS,BOOT_TIME,c_utmp};
#[cfg(target_os = "linux")]
mod utmpx {
    use super::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmp";

    pub const UT_LINESIZE: usize = 32;
    pub const UT_NAMESIZE: usize = 32;
    pub const UT_IDSIZE: usize = 4;
    pub const UT_HOSTSIZE: usize = 256;

    pub const EMPTY: libc::c_short = 0;
    pub const RUN_LVL: libc::c_short = 1;
    pub const BOOT_TIME: libc::c_short = 2;
    pub const NEW_TIME: libc::c_short = 3;
    pub const OLD_TIME: libc::c_short = 4;
    pub const INIT_PROCESS: libc::c_short = 5;
    pub const LOGIN_PROCESS: libc::c_short = 6;
    pub const USER_PROCESS: libc::c_short = 7;
    pub const DEAD_PROCESS: libc::c_short = 8;
    pub const ACCOUNTING: libc::c_short = 9;

    #[repr(C)]
    pub struct c_exit_status {
        pub e_termination: libc::c_short,
        pub e_exit: libc::c_short,
    }

    #[repr(C)]
    pub struct c_utmp {
        pub ut_type: libc::c_short,
        pub ut_pid: libc::pid_t,
        pub ut_line: [libc::c_char; UT_LINESIZE],
        pub ut_id: [libc::c_char; UT_IDSIZE],

        pub ut_user: [libc::c_char; UT_NAMESIZE],
        pub ut_host: [libc::c_char; UT_HOSTSIZE],
        pub ut_exit: c_exit_status,
        pub ut_session: libc::c_long,
        pub ut_tv: libc::timeval,

        pub ut_addr_v6: [libc::int32_t; 4],
        pub __unused: [libc::c_char; 20],
    }
}

#[cfg(target_os = "macos")]
mod utmpx {
    use super::libc;

    pub static DEFAULT_FILE: &'static str = "/var/run/utmpx";

    pub const UT_LINESIZE: usize = 32;
    pub const UT_NAMESIZE: usize = 256;
    pub const UT_IDSIZE: usize = 4;
    pub const UT_HOSTSIZE: usize = 256;

    pub const EMPTY: libc::c_short = 0;
    pub const RUN_LVL: libc::c_short = 1;
    pub const BOOT_TIME: libc::c_short = 2;
    pub const OLD_TIME: libc::c_short = 3;
    pub const NEW_TIME: libc::c_short = 4;
    pub const INIT_PROCESS: libc::c_short = 5;
    pub const LOGIN_PROCESS: libc::c_short = 6;
    pub const USER_PROCESS: libc::c_short = 7;
    pub const DEAD_PROCESS: libc::c_short = 8;
    pub const ACCOUNTING: libc::c_short = 9;

    #[repr(C)]
    pub struct c_exit_status {
        pub e_termination: libc::c_short,
        pub e_exit: libc::c_short,
    }

    #[repr(C)]
    pub struct c_utmp {
        pub ut_user: [libc::c_char; UT_NAMESIZE],
        pub ut_id: [libc::c_char; UT_IDSIZE],
        pub ut_line: [libc::c_char; UT_LINESIZE],
        pub ut_pid: libc::pid_t,
        pub ut_type: libc::c_short,
        pub ut_tv: libc::timeval,
        pub ut_host: [libc::c_char; UT_HOSTSIZE],
        pub __unused: [libc::c_char; 16]
    }
}

#[cfg(target_os = "freebsd")]
mod utmpx {
    use super::libc;

    pub static DEFAULT_FILE : &'static str = "";

    pub const UT_LINESIZE : usize = 16;
    pub const UT_NAMESIZE : usize = 32;
    pub const UT_IDSIZE   : usize = 8;
    pub const UT_HOSTSIZE : usize = 128;

    pub const EMPTY         : libc::c_short = 0;
    pub const BOOT_TIME     : libc::c_short = 1;
    pub const OLD_TIME      : libc::c_short = 2;
    pub const NEW_TIME      : libc::c_short = 3;
    pub const USER_PROCESS  : libc::c_short = 4;
    pub const INIT_PROCESS  : libc::c_short = 5;
    pub const LOGIN_PROCESS : libc::c_short = 6;
    pub const DEAD_PROCESS  : libc::c_short = 7;
    pub const SHUTDOWN_TIME : libc::c_short = 8;

    #[repr(C)]
    pub struct c_utmp {
        pub ut_type : libc::c_short,
        pub ut_tv   : libc::timeval,
        pub ut_id   : [libc::c_char; UT_IDSIZE],
        pub ut_pid  : libc::pid_t,
        pub ut_user : [libc::c_char; UT_NAMESIZE],
        pub ut_line : [libc::c_char; UT_LINESIZE],
        pub ut_host : [libc::c_char; UT_HOSTSIZE],
        pub ut_spare : [libc::c_char; 64],
    }
}
<|endoftext|>


<commit_before>use std::io::stdin;
use std::sync::mpsc;
use std::thread;

use termion;
use termion::input::TermRead;

use core::Core;

pub struct Input {
    tx: mpsc::Sender<termion::event::Event>,
    rx: mpsc::Receiver<termion::event::Event>,
}

impl Input {
    pub fn new() -> Input {
        let (tx, rx) = mpsc::channel();
        Input {
            tx: tx,
            rx: rx,
        }
    }

    pub fn run(&mut self) {
        let tx = self.tx.clone();
        thread::spawn(move || {
            for event_res in stdin().events() {
                match event_res {
                    Ok(event) => {
                        tx.send(event).unwrap();
                    },
                    Err(err) => {
                        error!("{:?}", err);
                    }
                }
            }
        });
    }

    pub fn try_recv(&mut self) -> Result<termion::event::Event, mpsc::TryRecvError> {
        self.rx.try_recv()
    }
}

pub fn handle(event: termion::event::Event, core: &mut Core) {
    match event {
        termion::event::Event::Key(key) => {
            match key {
                termion::event::Key::Char(c) => {
                    core.char(c);
                },
                termion::event::Key::Ctrl(c) => {
                    match c {
                        'c' => {
                            info!("received ^C: exiting");
                            return;
                        },
                        'w' => {
                            info!("received ^W: writing current file");
                            core.save();
                        },
                        _ => {}
                    }
                },
                termion::event::Key::Backspace => {
                    core.del();
                },
                termion::event::Key::Left => {
                    core.left();
                },
                termion::event::Key::Right => {
                    core.right();
                },
                termion::event::Key::Up => {
                    core.up();
                },
                termion::event::Key::Down => {
                    core.down();
                },
                termion::event::Key::PageUp => {
                    core.page_up();
                },
                termion::event::Key::PageDown => {
                    core.page_down();
                },
                _ => {
                    error!("unsupported key event");
                }
            }
        },
        termion::event::Event::Mouse(e) => {
            match e {
                termion::event::MouseEvent::Press(_, y, x) => {
                    core.click(x as u64 - 1, y as u64 - 1);
                },
                termion::event::MouseEvent::Release(_, _) => {},
                termion::event::MouseEvent::Hold(y, x) => {
                    core.drag(x as u64 - 1, y as u64 - 1);
                },
            }
        },
        _ => {
            error!("unsupported event");
        }
    }
}
<commit_msg>Fixes input handler to actually exit on Ctrl-C<commit_after>use std;
use std::io::stdin;
use std::sync::mpsc;
use std::thread;

use termion;
use termion::input::TermRead;

use core::Core;

pub struct Input {
    tx: mpsc::Sender<termion::event::Event>,
    rx: mpsc::Receiver<termion::event::Event>,
}

impl Input {
    pub fn new() -> Input {
        let (tx, rx) = mpsc::channel();
        Input {
            tx: tx,
            rx: rx,
        }
    }

    pub fn run(&mut self) {
        let tx = self.tx.clone();
        thread::spawn(move || {
            for event_res in stdin().events() {
                match event_res {
                    Ok(event) => {
                        tx.send(event).unwrap();
                    },
                    Err(err) => {
                        error!("{:?}", err);
                    }
                }
            }
        });
    }

    pub fn try_recv(&mut self) -> Result<termion::event::Event, mpsc::TryRecvError> {
        self.rx.try_recv()
    }
}

pub fn handle(event: termion::event::Event, core: &mut Core) {
    match event {
        termion::event::Event::Key(key) => {
            match key {
                termion::event::Key::Char(c) => {
                    core.char(c);
                },
                termion::event::Key::Ctrl(c) => {
                    match c {
                        'c' => {
                            info!("received ^C: exiting");
                            std::process::exit(0);
                        },
                        'w' => {
                            info!("received ^W: writing current file");
                            core.save();
                        },
                        _ => {}
                    }
                },
                termion::event::Key::Backspace => {
                    core.del();
                },
                termion::event::Key::Left => {
                    core.left();
                },
                termion::event::Key::Right => {
                    core.right();
                },
                termion::event::Key::Up => {
                    core.up();
                },
                termion::event::Key::Down => {
                    core.down();
                },
                termion::event::Key::PageUp => {
                    core.page_up();
                },
                termion::event::Key::PageDown => {
                    core.page_down();
                },
                _ => {
                    error!("unsupported key event");
                }
            }
        },
        termion::event::Event::Mouse(e) => {
            match e {
                termion::event::MouseEvent::Press(_, y, x) => {
                    core.click(x as u64 - 1, y as u64 - 1);
                },
                termion::event::MouseEvent::Release(_, _) => {},
                termion::event::MouseEvent::Hold(y, x) => {
                    core.drag(x as u64 - 1, y as u64 - 1);
                },
            }
        },
        _ => {
            error!("unsupported event");
        }
    }
}
<|endoftext|>


<commit_before>use graphics::Graphics;
use graphics::character::CharacterCache;
use color::{ Color, Colorable };
use point::Point;
use ui_context::UiContext;

pub type FontSize = u32;

/// An enum for passing in label information to widget arguments.
pub enum Labeling<'a> {
    Label(&'a str, FontSize, Color),
    NoLabel,
}

/// Determine the pixel width of the final text bitmap.
#[inline]
pub fn width<C: CharacterCache>(uic: &mut UiContext<C>, size: FontSize, text: &str) -> f64 {
    text.chars().fold(0u32, |a, ch| {
        let character = uic.get_character(size, ch);
        a + character.width() as u32
    }) as f64
}

/// Determine a suitable FontSize from a given rectangle height.
#[inline]
pub fn auto_size_from_rect_height(rect_height: f64) -> FontSize {
    let size = rect_height as u32 - 832;
    if size % 2 == 0 { size } else { size - 1u32 }
}

/// A trait used for widget types that take a label.
pub trait Labelable<'a>: Sized {
    fn label(self, text: &'a str) -> Self;
    fn label_color(self, color: Color) -> Self;
    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.label_color(Color([r, g, b, a]))
    }
    fn label_font_size(self, size: FontSize) -> Self;
    fn small_font<C>(self, uic: &UiContext<C>) -> Self;
    fn medium_font<C>(self, uic: &UiContext<C>) -> Self;
    fn large_font<C>(self, uic: &UiContext<C>) -> Self;
}

/// Label text property.
#[derive(Copy, Clone)]
pub struct LabelText<'a>(pub &'a str);

/// Label color property.
#[derive(Copy, Clone)]
pub struct LabelColor(pub Color);

/// Label font size property.
#[derive(Copy, Clone)]
pub struct LabelFontSize(pub FontSize);

/*
impl<'a, T: 'a> Labelable<'a> for T
    where
        (LabelText<'a>, T): Pair<Data = LabelText<'a>, Object = T> + SetAt,
        (LabelColor, T): Pair<Data = LabelColor, Object = T> + SetAt,
        (LabelFontSize, T): Pair<Data = LabelFontSize, Object = T> + SetAt
{
    fn label(self, text: &'a str) -> Self {
        self.set(LabelText(text))
    }

    fn label_color(self, color: Color) -> Self {
        self.set(LabelColor(color))
    }

    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.set(LabelColor(Color([r, g, b, a])))
    }

    fn label_font_size(self, size: FontSize) -> Self {
        self.set(LabelFontSize(size))
    }

    fn small_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_small))
    }

    fn medium_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_medium))
    }

    fn large_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_large))
    }
}
*/

/// A context on which the builder pattern can be implemented.
pub struct Label<'a> {
    text: &'a str,
    pos: Point,
    size: FontSize,
    maybe_color: Option<Color>,
}

impl<'a> Label<'a> {
    /// A builder method for specifying font_size.
    pub fn size(self, size: FontSize) -> Label<'a> {
        Label { size: size, ..self }
    }
}

impl<'a> Label<'a> {

    /// A label builder method to be implemented on the UiContext.
    pub fn new(text: &'a str) -> Label<'a> {
        Label {
            text: text,
            pos: [0.0, 0.0],
            size: 24u32,
            maybe_color: None,
        }
    }

}

impl<'a> Colorable for Label<'a> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

/*
quack! {
    label: Label['a]
    get:
    set:
        fn (val: Position) [] { label.pos = val.0 }
    action:
}
*/

impl<'a> ::draw::Drawable for Label<'a> {
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let color = self.maybe_color.unwrap_or(Color::black());
        uic.draw_text(graphics, self.pos, self.size, color, self.text);
    }
}
<commit_msg>Made `Labelable::small_font/medium_font/large_font` provided trait methods<commit_after>use graphics::Graphics;
use graphics::character::CharacterCache;
use color::{ Color, Colorable };
use point::Point;
use ui_context::UiContext;

pub type FontSize = u32;

/// An enum for passing in label information to widget arguments.
pub enum Labeling<'a> {
    Label(&'a str, FontSize, Color),
    NoLabel,
}

/// Determine the pixel width of the final text bitmap.
#[inline]
pub fn width<C: CharacterCache>(uic: &mut UiContext<C>, size: FontSize, text: &str) -> f64 {
    text.chars().fold(0u32, |a, ch| {
        let character = uic.get_character(size, ch);
        a + character.width() as u32
    }) as f64
}

/// Determine a suitable FontSize from a given rectangle height.
#[inline]
pub fn auto_size_from_rect_height(rect_height: f64) -> FontSize {
    let size = rect_height as u32 - 832;
    if size % 2 == 0 { size } else { size - 1u32 }
}

/// A trait used for widget types that take a label.
pub trait Labelable<'a>: Sized {
    fn label(self, text: &'a str) -> Self;
    fn label_color(self, color: Color) -> Self;
    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.label_color(Color([r, g, b, a]))
    }
    fn label_font_size(self, size: FontSize) -> Self;
    fn small_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_small)
    }
    fn medium_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_medium)
    }
    fn large_font<C>(self, uic: &UiContext<C>) -> Self {
        self.label_font_size(uic.theme.font_size_large)
    }
}

/// Label text property.
#[derive(Copy, Clone)]
pub struct LabelText<'a>(pub &'a str);

/// Label color property.
#[derive(Copy, Clone)]
pub struct LabelColor(pub Color);

/// Label font size property.
#[derive(Copy, Clone)]
pub struct LabelFontSize(pub FontSize);

/*
impl<'a, T: 'a> Labelable<'a> for T
    where
        (LabelText<'a>, T): Pair<Data = LabelText<'a>, Object = T> + SetAt,
        (LabelColor, T): Pair<Data = LabelColor, Object = T> + SetAt,
        (LabelFontSize, T): Pair<Data = LabelFontSize, Object = T> + SetAt
{
    fn label(self, text: &'a str) -> Self {
        self.set(LabelText(text))
    }

    fn label_color(self, color: Color) -> Self {
        self.set(LabelColor(color))
    }

    fn label_rgba(self, r: f32, g: f32, b: f32, a: f32) -> Self {
        self.set(LabelColor(Color([r, g, b, a])))
    }

    fn label_font_size(self, size: FontSize) -> Self {
        self.set(LabelFontSize(size))
    }

    fn small_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_small))
    }

    fn medium_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_medium))
    }

    fn large_font<C>(self, uic: &UiContext<C>) -> Self {
        self.set(LabelFontSize(uic.theme.font_size_large))
    }
}
*/

/// A context on which the builder pattern can be implemented.
pub struct Label<'a> {
    text: &'a str,
    pos: Point,
    size: FontSize,
    maybe_color: Option<Color>,
}

impl<'a> Label<'a> {
    /// A builder method for specifying font_size.
    pub fn size(self, size: FontSize) -> Label<'a> {
        Label { size: size, ..self }
    }
}

impl<'a> Label<'a> {

    /// A label builder method to be implemented on the UiContext.
    pub fn new(text: &'a str) -> Label<'a> {
        Label {
            text: text,
            pos: [0.0, 0.0],
            size: 24u32,
            maybe_color: None,
        }
    }

}

impl<'a> Colorable for Label<'a> {
    fn color(mut self, color: Color) -> Self {
        self.maybe_color = Some(color);
        self
    }
}

/*
quack! {
    label: Label['a]
    get:
    set:
        fn (val: Position) [] { label.pos = val.0 }
    action:
}
*/

impl<'a> ::draw::Drawable for Label<'a> {
    fn draw<B, C>(&mut self, uic: &mut UiContext<C>, graphics: &mut B)
        where
            B: Graphics<Texture = <C as CharacterCache>::Texture>,
            C: CharacterCache
    {
        let color = self.maybe_color.unwrap_or(Color::black());
        uic.draw_text(graphics, self.pos, self.size, color, self.text);
    }
}
<|endoftext|>


<commit_before>use crate::token;

// TODO: Why byte? Maybe just use char and support unicode language out of box? wtp?
#[derive(Default, Debug, Clone)]
pub struct Lexer {
    input: String,
    position: u32,
    read_position: u32,
    ch: u8,
}

impl Lexer {
    pub fn new(input: String) -> Self {
        let mut lexer = Lexer {
            input,
            ..Default::default()
        };

        // Setup lexer:
        // 1) load first character
        // 2) move reader position
        // ...see read_char for details.
        lexer.read_char();

        lexer
    }

    // At the beginning position and read_position are zeroes.
    // After the first iteration situation changes to position: 0, read_position: 1.
    fn read_char(&mut self) {
        if self.read_position >= self.input.len() as u32 {
            self.ch = 0
        } else {
            self.ch = self.input.as_bytes()[self.read_position as usize]
        }

        self.position = self.read_position;
        self.read_position += 1;
    }

    // TODO: rethink types. Current one are not very nice.
    pub fn next_token(&mut self) -> token::Token {
        self.skip_whitespace();

        let tok = match self.ch {
            b'=' => {
                if self.peek_char() == b'=' {
                    let ch = self.ch;
                    self.read_char();
                    let literal = [ch, self.ch].iter().map(|&c| c as char).collect::<String>();
                    token::Token {
                        token_type: token::EQ.to_string(),
                        literal,
                    }
                } else {
                    token::Token {
                        token_type: token::ASSIGN.to_string(),
                        literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
                    }
                }
            }
            b'+' => token::Token {
                token_type: token::PLUS.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'-' => token::Token {
                token_type: token::MINUS.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'!' => {
                if self.peek_char() == b'=' {
                    let ch = self.ch;
                    self.read_char();
                    let literal = [ch, self.ch].iter().map(|&c| c as char).collect::<String>();
                    token::Token {
                        token_type: token::NOT_EQ.to_string(),
                        literal,
                    }
                } else {
                    token::Token {
                        token_type: token::BANG.to_string(),
                        literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
                    }
                }
            }
            b'/' => token::Token {
                token_type: token::SLASH.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'*' => token::Token {
                token_type: token::ASTERISK.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'<' => token::Token {
                token_type: token::LT.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'>' => token::Token {
                token_type: token::GT.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b';' => token::Token {
                token_type: token::SEMICOLON.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'(' => token::Token {
                token_type: token::LPAREN.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b')' => token::Token {
                token_type: token::RPAREN.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b',' => token::Token {
                token_type: token::COMMA.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'{' => token::Token {
                token_type: token::LBRACE.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'}' => token::Token {
                token_type: token::RBRACE.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'"' => token::Token {
                token_type: token::STRING.to_string(),
                literal: self.read_string(),
            },
            0 => token::Token {
                token_type: token::EOF.to_string(),
                literal: "".to_string(),
            },
            _ => {
                let character = self.ch as char;

                if character.is_ascii_alphabetic() || character == '_' {
                    let literal = self.read_identifier();
                    let token_type = token::lookup_ident(literal.clone());
                    // We need early return here because
                    // in the end of function we run read_char(),
                    // but read_identifier() already at last position
                    return token::Token {
                        token_type,
                        literal,
                    };
                } else if character.is_digit(10) {
                    // TODO: Add linenumber and position to track the error
                    // and show output to user.
                    let literal = self.read_number();
                    let token_type = token::INT.to_string();
                    // We need early return here because
                    // in the end of function we run read_char(),
                    // but read_number() already at last position
                    return token::Token {
                        token_type,
                        literal,
                    };
                } else {
                    token::Token {
                        token_type: token::ILLEGAL.to_string(),
                        literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
                    }
                }
            }
        };

        self.read_char();

        tok
    }

    fn read_identifier(&mut self) -> String {
        let position = self.position;
        while self.is_letter(self.ch) {
            self.read_char()
        }
        self.input.as_bytes()[position as usize..self.position as usize]
            .iter()
            .map(|&c| c as char)
            .collect::<String>()
    }

    fn read_string(&mut self) -> String {
        self.read_char(); // ignore opening `"`
        let position = self.position;

        while self.ch != b'"' || self.ch != 0 {
            self.read_char();
        }

        self.input.as_bytes()[position as usize..self.position as usize]
            .iter()
            .map(|&c| c as char)
            .collect::<String>()
    }

    fn read_number(&mut self) -> String {
        let position = self.position;
        while (self.ch as char).is_digit(10) {
            self.read_char()
        }

        self.input.as_bytes()[position as usize..self.position as usize]
            .iter()
            .map(|&c| c as char)
            .collect::<String>()
    }

    fn peek_char(&self) -> u8 {
        if self.read_position >= self.input.len() as u32 {
            0
        } else {
            self.input.as_bytes()[self.read_position as usize]
        }
    }

    fn is_letter(&self, c: u8) -> bool {
        let character = c as char;
        character.is_ascii_alphabetic() || character == '_'
    }

    fn skip_whitespace(&mut self) {
        while self.ch == b' ' || self.ch == b'\t' || self.ch == b'\n' || self.ch == b'\r' {
            self.read_char()
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::lexer::Lexer;
    use crate::token;

    #[test]
    fn test_next_token_basic() {
        let input = String::from("=+(){},;");

        let expected = vec![
            (token::ASSIGN.to_string(), String::from("=")),
            (token::PLUS.to_string(), String::from("+")),
            (token::LPAREN.to_string(), String::from("(")),
            (token::RPAREN.to_string(), String::from(")")),
            (token::LBRACE.to_string(), String::from("{")),
            (token::RBRACE.to_string(), String::from("}")),
            (token::COMMA.to_string(), String::from(",")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::EOF.to_string(), String::from("")),
        ];

        let mut lexer = Lexer::new(input);

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }

    #[test]
    fn test_next_token_clojurium_snippet() {
        let input = r###"
          let five = 5;
          let ten = 10;

          let add = fn(x, y) {
            x + y;
          };

          let result = add(five, ten);
          "kobushka";
        "###
        .to_string();

        let expected = vec![
            (token::LET.to_string(), String::from("let")),
            (token::IDENT.to_string(), String::from("five")),
            (token::ASSIGN.to_string(), String::from("=")),
            (token::INT.to_string(), String::from("5")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::LET.to_string(), String::from("let")),
            (token::IDENT.to_string(), String::from("ten")),
            (token::ASSIGN.to_string(), String::from("=")),
            (token::INT.to_string(), String::from("10")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::LET.to_string(), String::from("let")),
            (token::IDENT.to_string(), String::from("add")),
            (token::ASSIGN.to_string(), String::from("=")),
            (token::FUNCTION.to_string(), String::from("fn")),
            (token::LPAREN.to_string(), String::from("(")),
            (token::IDENT.to_string(), String::from("x")),
            (token::COMMA.to_string(), String::from(",")),
            (token::IDENT.to_string(), String::from("y")),
            (token::RPAREN.to_string(), String::from(")")),
            (token::LBRACE.to_string(), String::from("{")),
            (token::IDENT.to_string(), String::from("x")),
            (token::PLUS.to_string(), String::from("+")),
            (token::IDENT.to_string(), String::from("y")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::RBRACE.to_string(), String::from("}")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::LET.to_string(), String::from("let")),
            (token::IDENT.to_string(), String::from("result")),
            (token::ASSIGN.to_string(), String::from("=")),
            (token::IDENT.to_string(), String::from("add")),
            (token::LPAREN.to_string(), String::from("(")),
            (token::IDENT.to_string(), String::from("five")),
            (token::COMMA.to_string(), String::from(",")),
            (token::IDENT.to_string(), String::from("ten")),
            (token::RPAREN.to_string(), String::from(")")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::STRING.to_string(), String::from("kobushka")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::EOF.to_string(), String::from("")),
        ];

        let mut lexer = Lexer::new(input);

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }

    #[test]
    fn test_arithmetic_operators() {
        let input = r###"
         !-/*5;
         5 < 10 > 5;
       "###
        .to_string();

        let mut lexer = Lexer::new(input);

        let expected = vec![
            (token::BANG.to_string(), String::from("!")),
            (token::MINUS.to_string(), String::from("-")),
            (token::SLASH.to_string(), String::from("/")),
            (token::ASTERISK.to_string(), String::from("*")),
            (token::INT.to_string(), String::from("5")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::INT.to_string(), String::from("5")),
            (token::LT.to_string(), String::from("<")),
            (token::INT.to_string(), String::from("10")),
            (token::GT.to_string(), String::from(">")),
            (token::INT.to_string(), String::from("5")),
            (token::SEMICOLON.to_string(), String::from(";")),
        ];

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }

    #[test]
    fn test_flow_control_keywords() {
        let input = r###"
          if (2 < 3) {
              return true;
          } else {
              return false;
          }
        "###
        .to_string();

        let expected = vec![
            (token::IF.to_string(), String::from("if")),
            (token::LPAREN.to_string(), String::from("(")),
            (token::INT.to_string(), String::from("2")),
            (token::LT.to_string(), String::from("<")),
            (token::INT.to_string(), String::from("3")),
            (token::RPAREN.to_string(), String::from(")")),
            (token::LBRACE.to_string(), String::from("{")),
            (token::RETURN.to_string(), String::from("return")),
            (token::TRUE.to_string(), String::from("true")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::RBRACE.to_string(), String::from("}")),
            (token::ELSE.to_string(), String::from("else")),
            (token::LBRACE.to_string(), String::from("{")),
            (token::RETURN.to_string(), String::from("return")),
            (token::FALSE.to_string(), String::from("false")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::RBRACE.to_string(), String::from("}")),
        ];

        let mut lexer = Lexer::new(input);

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }

    #[test]
    fn test_multichar_operators() {
        let input = r###"1 == 1 1 != 2"###.to_string();

        let expected = vec![
            (token::INT.to_string(), String::from("1")),
            (token::EQ.to_string(), String::from("==")),
            (token::INT.to_string(), String::from("1")),
            (token::INT.to_string(), String::from("1")),
            (token::NOT_EQ.to_string(), String::from("!=")),
            (token::INT.to_string(), String::from("2")),
        ];

        let mut lexer = Lexer::new(input);

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }
}
<commit_msg>fix endless loop in read_string()<commit_after>use crate::token;

// TODO: Why byte? Maybe just use char and support unicode language out of box? wtp?
#[derive(Default, Debug, Clone)]
pub struct Lexer {
    input: String,
    position: u32,
    read_position: u32,
    ch: u8,
}

impl Lexer {
    pub fn new(input: String) -> Self {
        let mut lexer = Lexer {
            input,
            ..Default::default()
        };

        // Setup lexer:
        // 1) load first character
        // 2) move reader position
        // ...see read_char for details.
        lexer.read_char();

        lexer
    }

    // At the beginning position and read_position are zeroes.
    // After the first iteration situation changes to position: 0, read_position: 1.
    fn read_char(&mut self) {
        if self.read_position >= self.input.len() as u32 {
            self.ch = 0
        } else {
            self.ch = self.input.as_bytes()[self.read_position as usize]
        }

        self.position = self.read_position;
        self.read_position += 1;
    }

    // TODO: rethink types. Current one are not very nice.
    pub fn next_token(&mut self) -> token::Token {
        self.skip_whitespace();

        let tok = match self.ch {
            b'=' => {
                if self.peek_char() == b'=' {
                    let ch = self.ch;
                    self.read_char();
                    let literal = [ch, self.ch].iter().map(|&c| c as char).collect::<String>();
                    token::Token {
                        token_type: token::EQ.to_string(),
                        literal,
                    }
                } else {
                    token::Token {
                        token_type: token::ASSIGN.to_string(),
                        literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
                    }
                }
            }
            b'+' => token::Token {
                token_type: token::PLUS.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'-' => token::Token {
                token_type: token::MINUS.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'!' => {
                if self.peek_char() == b'=' {
                    let ch = self.ch;
                    self.read_char();
                    let literal = [ch, self.ch].iter().map(|&c| c as char).collect::<String>();
                    token::Token {
                        token_type: token::NOT_EQ.to_string(),
                        literal,
                    }
                } else {
                    token::Token {
                        token_type: token::BANG.to_string(),
                        literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
                    }
                }
            }
            b'/' => token::Token {
                token_type: token::SLASH.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'*' => token::Token {
                token_type: token::ASTERISK.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'<' => token::Token {
                token_type: token::LT.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'>' => token::Token {
                token_type: token::GT.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b';' => token::Token {
                token_type: token::SEMICOLON.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'(' => token::Token {
                token_type: token::LPAREN.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b')' => token::Token {
                token_type: token::RPAREN.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b',' => token::Token {
                token_type: token::COMMA.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'{' => token::Token {
                token_type: token::LBRACE.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'}' => token::Token {
                token_type: token::RBRACE.to_string(),
                literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
            },
            b'"' => token::Token {
                token_type: token::STRING.to_string(),
                literal: self.read_string(),
            },
            0 => token::Token {
                token_type: token::EOF.to_string(),
                literal: "".to_string(),
            },
            _ => {
                let character = self.ch as char;

                if character.is_ascii_alphabetic() || character == '_' {
                    let literal = self.read_identifier();
                    let token_type = token::lookup_ident(literal.clone());
                    // We need early return here because
                    // in the end of function we run read_char(),
                    // but read_identifier() already at last position
                    return token::Token {
                        token_type,
                        literal,
                    };
                } else if character.is_digit(10) {
                    // TODO: Add linenumber and position to track the error
                    // and show output to user.
                    let literal = self.read_number();
                    let token_type = token::INT.to_string();
                    // We need early return here because
                    // in the end of function we run read_char(),
                    // but read_number() already at last position
                    return token::Token {
                        token_type,
                        literal,
                    };
                } else {
                    token::Token {
                        token_type: token::ILLEGAL.to_string(),
                        literal: [self.ch].iter().map(|&c| c as char).collect::<String>(),
                    }
                }
            }
        };

        self.read_char();

        tok
    }

    fn read_identifier(&mut self) -> String {
        let position = self.position;
        while self.is_letter(self.ch) {
            self.read_char()
        }
        self.input.as_bytes()[position as usize..self.position as usize]
            .iter()
            .map(|&c| c as char)
            .collect::<String>()
    }

    fn read_string(&mut self) -> String {
        let position = self.position + 1; // ignore opening `"`

        loop {
            self.read_char();

            if self.ch == b'"' || self.ch == 0 {
                break
            }
        }

        self.input.as_bytes()[position as usize..self.position as usize]
            .iter()
            .map(|&c| c as char)
            .collect::<String>()
    }

    fn read_number(&mut self) -> String {
        let position = self.position;
        while (self.ch as char).is_digit(10) {
            self.read_char()
        }

        self.input.as_bytes()[position as usize..self.position as usize]
            .iter()
            .map(|&c| c as char)
            .collect::<String>()
    }

    fn peek_char(&self) -> u8 {
        if self.read_position >= self.input.len() as u32 {
            0
        } else {
            self.input.as_bytes()[self.read_position as usize]
        }
    }

    fn is_letter(&self, c: u8) -> bool {
        let character = c as char;
        character.is_ascii_alphabetic() || character == '_'
    }

    fn skip_whitespace(&mut self) {
        while self.ch == b' ' || self.ch == b'\t' || self.ch == b'\n' || self.ch == b'\r' {
            self.read_char()
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::lexer::Lexer;
    use crate::token;

    #[test]
    fn test_next_token_basic() {
        let input = String::from("=+(){},;");

        let expected = vec![
            (token::ASSIGN.to_string(), String::from("=")),
            (token::PLUS.to_string(), String::from("+")),
            (token::LPAREN.to_string(), String::from("(")),
            (token::RPAREN.to_string(), String::from(")")),
            (token::LBRACE.to_string(), String::from("{")),
            (token::RBRACE.to_string(), String::from("}")),
            (token::COMMA.to_string(), String::from(",")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::EOF.to_string(), String::from("")),
        ];

        let mut lexer = Lexer::new(input);

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }

    #[test]
    fn test_next_token_clojurium_snippet() {
        let input = r###"
          let five = 5;
          let ten = 10;

          let add = fn(x, y) {
            x + y;
          };

          let result = add(five, ten);
          "kobushka";
        "###
        .to_string();

        let expected = vec![
            (token::LET.to_string(), String::from("let")),
            (token::IDENT.to_string(), String::from("five")),
            (token::ASSIGN.to_string(), String::from("=")),
            (token::INT.to_string(), String::from("5")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::LET.to_string(), String::from("let")),
            (token::IDENT.to_string(), String::from("ten")),
            (token::ASSIGN.to_string(), String::from("=")),
            (token::INT.to_string(), String::from("10")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::LET.to_string(), String::from("let")),
            (token::IDENT.to_string(), String::from("add")),
            (token::ASSIGN.to_string(), String::from("=")),
            (token::FUNCTION.to_string(), String::from("fn")),
            (token::LPAREN.to_string(), String::from("(")),
            (token::IDENT.to_string(), String::from("x")),
            (token::COMMA.to_string(), String::from(",")),
            (token::IDENT.to_string(), String::from("y")),
            (token::RPAREN.to_string(), String::from(")")),
            (token::LBRACE.to_string(), String::from("{")),
            (token::IDENT.to_string(), String::from("x")),
            (token::PLUS.to_string(), String::from("+")),
            (token::IDENT.to_string(), String::from("y")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::RBRACE.to_string(), String::from("}")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::LET.to_string(), String::from("let")),
            (token::IDENT.to_string(), String::from("result")),
            (token::ASSIGN.to_string(), String::from("=")),
            (token::IDENT.to_string(), String::from("add")),
            (token::LPAREN.to_string(), String::from("(")),
            (token::IDENT.to_string(), String::from("five")),
            (token::COMMA.to_string(), String::from(",")),
            (token::IDENT.to_string(), String::from("ten")),
            (token::RPAREN.to_string(), String::from(")")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::STRING.to_string(), String::from("kobushka")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::EOF.to_string(), String::from("")),
        ];

        let mut lexer = Lexer::new(input);

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }

    #[test]
    fn test_arithmetic_operators() {
        let input = r###"
         !-/*5;
         5 < 10 > 5;
       "###
        .to_string();

        let mut lexer = Lexer::new(input);

        let expected = vec![
            (token::BANG.to_string(), String::from("!")),
            (token::MINUS.to_string(), String::from("-")),
            (token::SLASH.to_string(), String::from("/")),
            (token::ASTERISK.to_string(), String::from("*")),
            (token::INT.to_string(), String::from("5")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::INT.to_string(), String::from("5")),
            (token::LT.to_string(), String::from("<")),
            (token::INT.to_string(), String::from("10")),
            (token::GT.to_string(), String::from(">")),
            (token::INT.to_string(), String::from("5")),
            (token::SEMICOLON.to_string(), String::from(";")),
        ];

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }

    #[test]
    fn test_flow_control_keywords() {
        let input = r###"
          if (2 < 3) {
              return true;
          } else {
              return false;
          }
        "###
        .to_string();

        let expected = vec![
            (token::IF.to_string(), String::from("if")),
            (token::LPAREN.to_string(), String::from("(")),
            (token::INT.to_string(), String::from("2")),
            (token::LT.to_string(), String::from("<")),
            (token::INT.to_string(), String::from("3")),
            (token::RPAREN.to_string(), String::from(")")),
            (token::LBRACE.to_string(), String::from("{")),
            (token::RETURN.to_string(), String::from("return")),
            (token::TRUE.to_string(), String::from("true")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::RBRACE.to_string(), String::from("}")),
            (token::ELSE.to_string(), String::from("else")),
            (token::LBRACE.to_string(), String::from("{")),
            (token::RETURN.to_string(), String::from("return")),
            (token::FALSE.to_string(), String::from("false")),
            (token::SEMICOLON.to_string(), String::from(";")),
            (token::RBRACE.to_string(), String::from("}")),
        ];

        let mut lexer = Lexer::new(input);

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }

    #[test]
    fn test_multichar_operators() {
        let input = r###"1 == 1 1 != 2"###.to_string();

        let expected = vec![
            (token::INT.to_string(), String::from("1")),
            (token::EQ.to_string(), String::from("==")),
            (token::INT.to_string(), String::from("1")),
            (token::INT.to_string(), String::from("1")),
            (token::NOT_EQ.to_string(), String::from("!=")),
            (token::INT.to_string(), String::from("2")),
        ];

        let mut lexer = Lexer::new(input);

        expected.into_iter().for_each(|(token_type, literal)| {
            let token = lexer.next_token();

            assert_eq!(token.token_type, token_type);
            assert_eq!(token.literal, literal);
        });
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::{self, Error};
use std::mem;

use libc::{
    c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, sockaddr, sockaddr_ll, socket,
    socklen_t, AF_AX25, AF_PACKET, SOCK_RAW,
};

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    fd: i32,
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            match l {
                Ok(line) => {
                    let device_name = line.trim().split(":").next().unwrap();
                    if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                        devices.push(net_dev);
                    }
                }
                Err(_) => (),
            }
        }
        Ok(devices)
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = mem::transmute::<*const sockaddr_ll, *const sockaddr>(&sa);
            sendto(
                self.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = mem::transmute::<*mut sockaddr_ll, *mut sockaddr>(&mut addr_struct);
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let ref valid_buf = buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf
            .into_iter()
            .skip_while(|&c| *c == 0)
            .cloned()
            .collect();
        Ok(filtered)
    }
}

fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as c_char;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None,
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex,
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union,
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default(),
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24],
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union { data: [0; 24] }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(
            ((self.data[0] as c_int) << 24)
                + ((self.data[1] as c_int) << 16)
                + ((self.data[2] as c_int) << 8)
                + (self.data[3] as c_int),
        )
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8]
            .iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Some(addr) = String::from_utf8(addr_utf8).ok() {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}
<commit_msg>Fix one more linux clippy lint<commit_after>use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::io::{self, Error};
use std::mem;

use libc::{
    c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, sockaddr, sockaddr_ll, socket,
    socklen_t, AF_AX25, AF_PACKET, SOCK_RAW,
};

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    fd: i32,
}

impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(":").next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = mem::transmute::<*const sockaddr_ll, *const sockaddr>(&sa);
            sendto(
                self.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = mem::transmute::<*mut sockaddr_ll, *mut sockaddr>(&mut addr_struct);
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let ref valid_buf = buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf
            .into_iter()
            .skip_while(|&c| *c == 0)
            .cloned()
            .collect();
        Ok(filtered)
    }
}

fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as c_char;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None,
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex,
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union,
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default(),
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24],
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union { data: [0; 24] }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(
            ((self.data[0] as c_int) << 24)
                + ((self.data[1] as c_int) << 16)
                + ((self.data[2] as c_int) << 8)
                + (self.data[3] as c_int),
        )
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8]
            .iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Some(addr) = String::from_utf8(addr_utf8).ok() {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}
<|endoftext|>