<commit_before>use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;

use syntax::abi;

pub use self::Global::*;
pub use self::Type::*;
pub use self::IKind::*;
pub use self::FKind::*;

#[derive(Clone)]
pub enum Global {
    GType(Rc<RefCell<TypeInfo>>),
    GComp(Rc<RefCell<CompInfo>>),
    GCompDecl(Rc<RefCell<CompInfo>>),
    GEnum(Rc<RefCell<EnumInfo>>),
    GEnumDecl(Rc<RefCell<EnumInfo>>),
    GVar(Rc<RefCell<VarInfo>>),
    GFunc(Rc<RefCell<VarInfo>>),
    GOther
}

impl Global {
    pub fn compinfo(&self) -> Rc<RefCell<CompInfo>> {
        match *self {
            GComp(ref i)
            | GCompDecl(ref i) => i.clone(),
            _ => panic!("global_compinfo")
        }
    }

    pub fn enuminfo(&self) -> Rc<RefCell<EnumInfo>> {
        match *self {
            GEnum(ref i)
            | GEnumDecl(ref i) => i.clone(),
            _ => panic!("global_enuminfo")
        }
    }

    pub fn typeinfo(&self) -> Rc<RefCell<TypeInfo>> {
        match *self {
            GType(ref i) => i.clone(),
            _ => panic!("global_typeinfo")
        }
    }

    pub fn varinfo(&self) -> Rc<RefCell<VarInfo>> {
        match *self {
            GVar(ref i)
            | GFunc(ref i) => i.clone(),
            _ => panic!("global_varinfo")
        }
    }
}

impl fmt::Debug for Global {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GType(ref ti) => ti.borrow().fmt(f),
            GComp(ref ci)
            | GCompDecl(ref ci) => ci.borrow().fmt(f),
            GEnum(ref ei)
            | GEnumDecl(ref ei) => ei.borrow().fmt(f),
            GVar(ref vi)
            | GFunc(ref vi) => vi.borrow().fmt(f),
            GOther => "*".fmt(f),
        }
    }
}

#[derive(Clone, PartialEq, Debug)]
pub struct FuncSig {
    pub ret_ty: Box<Type>,
    pub args: Vec<(String, Type)>,
    pub is_variadic: bool,
    pub is_safe: bool,
    pub abi: abi::Abi,
}

#[derive(Clone, PartialEq, Debug)]
pub enum Type {
    TVoid,
    TInt(IKind, Layout),
    TFloat(FKind, Layout),
    TPtr(Box<Type>, bool, Layout),
    TArray(Box<Type>, usize, Layout),
    TFuncProto(FuncSig),
    TFuncPtr(FuncSig),
    TNamed(Rc<RefCell<TypeInfo>>),
    TComp(Rc<RefCell<CompInfo>>),
    TEnum(Rc<RefCell<EnumInfo>>)
}

impl Type {
    pub fn size(&self) -> usize {
        match *self {
            TInt(_, l)
            | TFloat(_, l)
            | TPtr(_, _, l)
            | TArray(_, _, l) => l.size,
            TNamed(ref ti) => ti.borrow().ty.size(),
            TComp(ref ci) => ci.borrow().layout.size,
            TEnum(ref ei) => ei.borrow().layout.size,
            TVoid
            | TFuncProto(..)
            | TFuncPtr(..) => 0,
        }
    }

    #[allow(dead_code)]
    pub fn align(&self) -> usize {
        match *self {
            TInt(_, l)
            | TFloat(_, l)
            | TPtr(_, _, l)
            | TArray(_, _, l) => l.align,
            TNamed(ref ti) => ti.borrow().ty.align(),
            TComp(ref ci) => ci.borrow().layout.align,
            TEnum(ref ei) => ei.borrow().layout.align,
            TVoid
            | TFuncProto(..)
            | TFuncPtr(..) => 0,
        }
    }

    pub fn can_derive_debug(&self) -> bool {
        match *self {
            TArray(_, size, _) => size <= 32,
            TComp(ref comp) => {
                comp.borrow()
                    .members
                    .iter()
                    .all(|member| match *member {
                        CompMember::Field(ref f) |
                        CompMember::CompField(_, ref f) => f.ty.can_derive_debug(),
                        _ => true,
                    })
            }
            _ => true,
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Layout {
    pub size: usize,
    pub align: usize,
    pub packed: bool,
}

impl Layout {
    pub fn new(size: usize, align: usize) -> Layout {
        Layout { size: size, align: align, packed: false }
    }

    pub fn zero() -> Layout {
        Layout { size: 0, align: 0, packed: false }
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IKind {
    IBool,
    ISChar,
    IUChar,
    IShort,
    IUShort,
    IInt,
    IUInt,
    ILong,
    IULong,
    ILongLong,
    IULongLong
}

impl IKind {
    pub fn is_signed(self) -> bool {
        match self {
            IBool => false,
            ISChar => true,
            IUChar => false,
            IShort => true,
            IUShort => false,
            IInt => true,
            IUInt => false,
            ILong => true,
            IULong => false,
            ILongLong => true,
            IULongLong => false,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum FKind {
    FFloat,
    FDouble
}

#[derive(Clone, PartialEq, Debug)]
pub enum CompMember {
    Field(FieldInfo),
    Comp(Rc<RefCell<CompInfo>>),
    CompField(Rc<RefCell<CompInfo>>, FieldInfo),
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum CompKind {
    Struct,
    Union,
}

#[derive(Clone, PartialEq)]
pub struct CompInfo {
    pub kind: CompKind,
    pub name: String,
    pub members: Vec<CompMember>,
    pub layout: Layout,
}

impl CompInfo {
    pub fn new(name: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
        CompInfo {
            kind: kind,
            name: name,
            members: members,
            layout: layout,
        }
    }
}

impl fmt::Debug for CompInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq, Debug)]
pub struct FieldInfo {
    pub name: String,
    pub ty: Type,
    pub bitfields: Option<Vec<(String, u32)>>,
}

impl FieldInfo {
    pub fn new(name: String, ty: Type, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo {
        FieldInfo {
            name: name,
            ty: ty,
            bitfields: bitfields,
        }
    }
}

#[derive(Clone, PartialEq)]
pub struct EnumInfo {
    pub name: String,
    pub items: Vec<EnumItem>,
    pub kind: IKind,
    pub layout: Layout,
}

impl EnumInfo {
    pub fn new(name: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
        EnumInfo {
            name: name,
            items: items,
            kind: kind,
            layout: layout,
        }
    }
}

impl fmt::Debug for EnumInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone, PartialEq, Debug)]
pub struct EnumItem {
    pub name: String,
    pub val: i64
}

impl EnumItem {
    pub fn new(name: String, val: i64) -> EnumItem {
        EnumItem {
            name: name,
            val: val
        }
    }
}

#[derive(Clone, PartialEq)]
pub struct TypeInfo {
    pub name: String,
    pub ty: Type
}

impl TypeInfo {
    pub fn new(name: String, ty: Type) -> TypeInfo {
        TypeInfo {
            name: name,
            ty: ty
        }
    }
}

impl fmt::Debug for TypeInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

#[derive(Clone)]
pub struct VarInfo {
    pub name: String,
    pub ty: Type,
    //TODO: support non-integer constants
    pub val: Option<i64>,
    pub is_const: bool
}

impl VarInfo {
    pub fn new(name: String, ty: Type) -> VarInfo {
        VarInfo {
            name: name,
            ty: ty,
            val: None,
            is_const: false
        }
    }
}

impl fmt::Debug for VarInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}
<commit_msg>[types.rs] Add comments.<commit_after>use std::cell::RefCell;
use std::fmt;
use std::rc::Rc;

use syntax::abi;

pub use self::Global::*;
pub use self::Type::*;
pub use self::IKind::*;
pub use self::FKind::*;

/// A representation of a top level entity
#[derive(Clone)]
pub enum Global {
    /// A type definition, like `typedef int my_type;`.
    GType(Rc<RefCell<TypeInfo>>),
    /// A C composed type, like a struct or union.
    GComp(Rc<RefCell<CompInfo>>),
    GCompDecl(Rc<RefCell<CompInfo>>),
    /// A C enum.
    GEnum(Rc<RefCell<EnumInfo>>),
    GEnumDecl(Rc<RefCell<EnumInfo>>),
    /// A C global variable.
    GVar(Rc<RefCell<VarInfo>>),
    /// A function prototype, like `int func();`.
    GFunc(Rc<RefCell<VarInfo>>),
    /// Something else.
    GOther
}

impl Global {
    pub fn compinfo(&self) -> Rc<RefCell<CompInfo>> {
        match *self {
            GComp(ref i)
            | GCompDecl(ref i) => i.clone(),
            _ => panic!("global_compinfo")
        }
    }

    pub fn enuminfo(&self) -> Rc<RefCell<EnumInfo>> {
        match *self {
            GEnum(ref i)
            | GEnumDecl(ref i) => i.clone(),
            _ => panic!("global_enuminfo")
        }
    }

    pub fn typeinfo(&self) -> Rc<RefCell<TypeInfo>> {
        match *self {
            GType(ref i) => i.clone(),
            _ => panic!("global_typeinfo")
        }
    }

    pub fn varinfo(&self) -> Rc<RefCell<VarInfo>> {
        match *self {
            GVar(ref i)
            | GFunc(ref i) => i.clone(),
            _ => panic!("global_varinfo")
        }
    }
}

impl fmt::Debug for Global {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GType(ref ti) => ti.borrow().fmt(f),
            GComp(ref ci)
            | GCompDecl(ref ci) => ci.borrow().fmt(f),
            GEnum(ref ei)
            | GEnumDecl(ref ei) => ei.borrow().fmt(f),
            GVar(ref vi)
            | GFunc(ref vi) => vi.borrow().fmt(f),
            GOther => "*".fmt(f),
        }
    }
}

/// A function signature.
#[derive(Clone, PartialEq, Debug)]
pub struct FuncSig {
    /// The return type of the function.
    pub ret_ty: Box<Type>,
    /// The arguments of the function.
    pub args: Vec<(String, Type)>,
    /// Is the function variadic?
    pub is_variadic: bool,
    /// Must it be called in an `unsafe` block?
    pub is_safe: bool,
    /// The ABI of the function
    pub abi: abi::Abi,
}

/// A representation of a C type.
#[derive(Clone, PartialEq, Debug)]
pub enum Type {
    /// The `void` C type.
    TVoid,
    /// A C integer number, like `int` or `char`.
    TInt(IKind, Layout),
    /// A C floating-point number, like `float` or `double`.
    TFloat(FKind, Layout),
    /// A Pointer, the boolean indicating if it is const.
    TPtr(Box<Type>, bool, Layout),
    TArray(Box<Type>, usize, Layout),
    TFuncProto(FuncSig),
    TFuncPtr(FuncSig),
    /// A typedef declaration?
    TNamed(Rc<RefCell<TypeInfo>>),
    /// A C composed type, like a struct or an union.
    TComp(Rc<RefCell<CompInfo>>),
    /// A C enum.
    TEnum(Rc<RefCell<EnumInfo>>)
}

impl Type {
    /// Returns the size in bytes of the type.
    pub fn size(&self) -> usize {
        match *self {
            TInt(_, l)
            | TFloat(_, l)
            | TPtr(_, _, l)
            | TArray(_, _, l) => l.size,
            TNamed(ref ti) => ti.borrow().ty.size(),
            TComp(ref ci) => ci.borrow().layout.size,
            TEnum(ref ei) => ei.borrow().layout.size,
            TVoid
            | TFuncProto(..)
            | TFuncPtr(..) => 0,
        }
    }

    /// Returns the alignement of the type.
    #[allow(dead_code)]
    pub fn align(&self) -> usize {
        match *self {
            TInt(_, l)
            | TFloat(_, l)
            | TPtr(_, _, l)
            | TArray(_, _, l) => l.align,
            TNamed(ref ti) => ti.borrow().ty.align(),
            TComp(ref ci) => ci.borrow().layout.align,
            TEnum(ref ei) => ei.borrow().layout.align,
            TVoid
            | TFuncProto(..)
            | TFuncPtr(..) => 0,
        }
    }

    /// Whether `Debug` can be derived for the type.
    pub fn can_derive_debug(&self) -> bool {
        match *self {
            TArray(_, size, _) => size <= 32,
            TComp(ref comp) => {
                comp.borrow()
                    .members
                    .iter()
                    .all(|member| match *member {
                        CompMember::Field(ref f) |
                        CompMember::CompField(_, ref f) => f.ty.can_derive_debug(),
                        _ => true,
                    })
            }
            _ => true,
        }
    }
}

/// Describes the layout of an element
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct Layout {
    /// The size in bytes of the element.
    pub size: usize,
    pub align: usize,
    /// See `#[repr(C, Packed)]`.
    pub packed: bool,
}

impl Layout {
    pub fn new(size: usize, align: usize) -> Layout {
        Layout { size: size, align: align, packed: false }
    }

    pub fn zero() -> Layout {
        Layout { size: 0, align: 0, packed: false }
    }
}

/// A representation of a C integer kind.
///
/// For example: bool -> IBool, unsigned long -> IULong.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum IKind {
    IBool,
    ISChar,
    IUChar,
    IShort,
    IUShort,
    IInt,
    IUInt,
    ILong,
    IULong,
    ILongLong,
    IULongLong
}

impl IKind {
    pub fn is_signed(self) -> bool {
        match self {
            IBool => false,
            ISChar => true,
            IUChar => false,
            IShort => true,
            IUShort => false,
            IInt => true,
            IUInt => false,
            ILong => true,
            IULong => false,
            ILongLong => true,
            IULongLong => false,
        }
    }
}

#[derive(Copy, Clone, PartialEq, Debug)]
pub enum FKind {
    FFloat,
    FDouble
}

#[derive(Clone, PartialEq, Debug)]
pub enum CompMember {
    Field(FieldInfo),
    Comp(Rc<RefCell<CompInfo>>),
    CompField(Rc<RefCell<CompInfo>>, FieldInfo),
}

/// Is the composed element a struct or an union?
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum CompKind {
    Struct,
    Union,
}

/// Represents a composed element declaration, like a struct or an union.
#[derive(Clone, PartialEq)]
pub struct CompInfo {
    pub kind: CompKind,
    pub name: String,
    pub members: Vec<CompMember>,
    pub layout: Layout,
}

impl CompInfo {
    pub fn new(name: String, kind: CompKind, members: Vec<CompMember>, layout: Layout) -> CompInfo {
        CompInfo {
            kind: kind,
            name: name,
            members: members,
            layout: layout,
        }
    }
}

impl fmt::Debug for CompInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

/// A field in a struct or a union.
#[derive(Clone, PartialEq, Debug)]
pub struct FieldInfo {
    pub name: String,
    pub ty: Type,
    pub bitfields: Option<Vec<(String, u32)>>,
}

impl FieldInfo {
    pub fn new(name: String, ty: Type, bitfields: Option<Vec<(String, u32)>>) -> FieldInfo {
        FieldInfo {
            name: name,
            ty: ty,
            bitfields: bitfields,
        }
    }
}

/// A C enum.
#[derive(Clone, PartialEq)]
pub struct EnumInfo {
    pub name: String,
    pub items: Vec<EnumItem>,
    /// The underlining representation of the enum.
    pub kind: IKind,
    pub layout: Layout,
}

impl EnumInfo {
    pub fn new(name: String, kind: IKind, items: Vec<EnumItem>, layout: Layout) -> EnumInfo {
        EnumInfo {
            name: name,
            items: items,
            kind: kind,
            layout: layout,
        }
    }
}

impl fmt::Debug for EnumInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

/// A variant in a C enum.
#[derive(Clone, PartialEq, Debug)]
pub struct EnumItem {
    pub name: String,
    pub val: i64
}

impl EnumItem {
    pub fn new(name: String, val: i64) -> EnumItem {
        EnumItem {
            name: name,
            val: val
        }
    }
}

#[derive(Clone, PartialEq)]
pub struct TypeInfo {
    pub name: String,
    pub ty: Type
}

impl TypeInfo {
    pub fn new(name: String, ty: Type) -> TypeInfo {
        TypeInfo {
            name: name,
            ty: ty
        }
    }
}

impl fmt::Debug for TypeInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}

/// A C variable declaration.
#[derive(Clone)]
pub struct VarInfo {
    pub name: String,
    pub ty: Type,
    //TODO: support non-integer constants
    pub val: Option<i64>,
    /// Is the variable constant?
    pub is_const: bool
}

impl VarInfo {
    pub fn new(name: String, ty: Type) -> VarInfo {
        VarInfo {
            name: name,
            ty: ty,
            val: None,
            is_const: false
        }
    }
}

impl fmt::Debug for VarInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.name.fmt(f)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::error;
use gl;

pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32
}

impl Color {
    pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
        Color { r: r, g: g, b: b, a: a}
    }
}

#[derive(Clone, Copy)]
pub struct Viewport {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32
}

impl Viewport {
    pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self {
        Viewport {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

bitflags! {
    flags BufferBits: gl::types::GLbitfield {
        const COLOR_BUFFER_BIT = gl::COLOR_BUFFER_BIT,
        const DEPTH_BUFFER_BIT = gl::DEPTH_BUFFER_BIT,
        const STENCIL_BUFFER_BIT = gl::STENCIL_BUFFER_BIT
    }
}

#[derive(Debug)]
pub enum GLError {
    InvalidEnum,
    InvalidValue,
    InvalidOperation,
    InvalidFramebufferOperation,
    OutOfMemory,
    FramebufferError(GLFramebufferError),
    Message(String)
}

impl fmt::Display for GLError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GLError::InvalidEnum => {
                write!(f, "Invalid enum")
            },
            GLError::InvalidValue => {
                write!(f, "Invalid value")
            },
            GLError::InvalidOperation => {
                write!(f, "Invalid operation")
            },
            GLError::InvalidFramebufferOperation => {
                write!(f, "Invalid framebuffer operation")
            },
            GLError::OutOfMemory => {
                write!(f, "Out of memory")
            },
            GLError::FramebufferError(ref e) => {
                write!(f, "{:?}", e)
            },
            GLError::Message(ref s) => {
                write!(f, "{}", s)
            }
        }
    }
}

impl error::Error for GLError {
    fn description(&self) -> &str {
        match *self {
            GLError::InvalidEnum => "Invalid enum variant in OpenGL call.",
            GLError::InvalidValue => "Out-of-range value in OpenGL call.",
            GLError::InvalidOperation => "The specified OpenGL operation is not allowed in the current state.",
            GLError::InvalidFramebufferOperation => "OpenGL command tried to read or write to an incomplete framebuffer.",
            GLError::OutOfMemory => "There is not enough memory left to execute the specified OpenGL command.",
            GLError::FramebufferError(ref e) => {
                error::Error::description(e)
            },
            GLError::Message(ref s) => &s
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            GLError::FramebufferError(ref e) => { Some(e) },
            _ => { None }
        }
    }
}

#[derive(Debug)]
pub enum GLFramebufferError {
    IncompleteAttachment,
    IncompleteDimensions,
    IncompleteMissingAttachment,
    Unsupported
}

impl fmt::Display for GLFramebufferError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GLFramebufferError::IncompleteAttachment => {
                write!(f, "Incomplete attachment")
            },
            GLFramebufferError::IncompleteDimensions => {
                write!(f, "Incomplete dimensions")
            },
            GLFramebufferError::IncompleteMissingAttachment => {
                write!(f, "Missing attachments")
            },
            GLFramebufferError::Unsupported => {
                write!(f, "Unsupported")
            }
        }
    }
}

impl error::Error for GLFramebufferError {
    fn description(&self) -> &str {
        match *self {
            GLFramebufferError::IncompleteAttachment => "One or more framebuffer attachments are not complete",
            GLFramebufferError::IncompleteDimensions => "Not all images attached to the framebuffer have the same width and height",
            GLFramebufferError::IncompleteMissingAttachment => "The framebuffer has no images attached",
            GLFramebufferError::Unsupported => "The framebuffer contains an unsupported combination of attachments",
        }
    }
}

impl From<GLFramebufferError> for GLError {
    fn from(e: GLFramebufferError) -> GLError {
        GLError::FramebufferError(e)
    }
}

gl_enum! {
    pub gl_enum DrawingMode {
        Points as POINTS = gl::POINTS,
        LineStrip as LINE_STRIP = gl::LINE_STRIP,
        LineLoop as LINE_LOOP = gl::LINE_LOOP,
        Lines as LINES = gl::LINES,
        TriangleStrip as TRIANGLE_STRIP = gl::TRIANGLE_STRIP,
        TriangleFan as TRIANGLE_FAN = gl::TRIANGLE_FAN,
        Triangles as TRIANGLES = gl::TRIANGLES
    }
}

gl_enum! {
    pub gl_enum DataType {
        Byte as BYTE = gl::BYTE,
        UnsignedByte as UNSIGNED_BYTE = gl::UNSIGNED_BYTE,
        Short as SHORT = gl::SHORT,
        UnsignedShort as UNSIGNED_SHORT = gl::UNSIGNED_SHORT,
        Fixed as FIXED = gl::FIXED,
        Float as FLOAT = gl::FLOAT
    }
}
<commit_msg>Add `Capability` enum<commit_after>use std::fmt;
use std::error;
use gl;

pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32
}

impl Color {
    pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
        Color { r: r, g: g, b: b, a: a}
    }
}

#[derive(Clone, Copy)]
pub struct Viewport {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32
}

impl Viewport {
    pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self {
        Viewport {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

bitflags! {
    flags BufferBits: gl::types::GLbitfield {
        const COLOR_BUFFER_BIT = gl::COLOR_BUFFER_BIT,
        const DEPTH_BUFFER_BIT = gl::DEPTH_BUFFER_BIT,
        const STENCIL_BUFFER_BIT = gl::STENCIL_BUFFER_BIT
    }
}

gl_enum! {
    pub gl_enum Capability {
        Blend as BLEND
            = gl::BLEND,
        CullFace as CULL_FACE
            = gl::CULL_FACE,
        DepthTest as DEPTH_TEST
            = gl::DEPTH_TEST,
        Dither as DITHER
            = gl::DITHER,
        PolygonOffsetFill as POLYGON_OFFSET_FILL
            = gl::POLYGON_OFFSET_FILL,
        SampleAlphaToCoverage as SAMPLE_ALPHA_TO_COVERAGE =
            gl::SAMPLE_ALPHA_TO_COVERAGE,
        SampleCoverage as SAMPLE_COVERAGE =
            gl::SAMPLE_COVERAGE,
        ScisscorTest as SCISSCOR_TEST =
            gl::SCISSOR_TEST,
        StencilTest as STENCIL_TEST =
            gl::STENCIL_TEST
    }
}

#[derive(Debug)]
pub enum GLError {
    InvalidEnum,
    InvalidValue,
    InvalidOperation,
    InvalidFramebufferOperation,
    OutOfMemory,
    FramebufferError(GLFramebufferError),
    Message(String)
}

impl fmt::Display for GLError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GLError::InvalidEnum => {
                write!(f, "Invalid enum")
            },
            GLError::InvalidValue => {
                write!(f, "Invalid value")
            },
            GLError::InvalidOperation => {
                write!(f, "Invalid operation")
            },
            GLError::InvalidFramebufferOperation => {
                write!(f, "Invalid framebuffer operation")
            },
            GLError::OutOfMemory => {
                write!(f, "Out of memory")
            },
            GLError::FramebufferError(ref e) => {
                write!(f, "{:?}", e)
            },
            GLError::Message(ref s) => {
                write!(f, "{}", s)
            }
        }
    }
}

impl error::Error for GLError {
    fn description(&self) -> &str {
        match *self {
            GLError::InvalidEnum => "Invalid enum variant in OpenGL call.",
            GLError::InvalidValue => "Out-of-range value in OpenGL call.",
            GLError::InvalidOperation => "The specified OpenGL operation is not allowed in the current state.",
            GLError::InvalidFramebufferOperation => "OpenGL command tried to read or write to an incomplete framebuffer.",
            GLError::OutOfMemory => "There is not enough memory left to execute the specified OpenGL command.",
            GLError::FramebufferError(ref e) => {
                error::Error::description(e)
            },
            GLError::Message(ref s) => &s
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            GLError::FramebufferError(ref e) => { Some(e) },
            _ => { None }
        }
    }
}

#[derive(Debug)]
pub enum GLFramebufferError {
    IncompleteAttachment,
    IncompleteDimensions,
    IncompleteMissingAttachment,
    Unsupported
}

impl fmt::Display for GLFramebufferError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GLFramebufferError::IncompleteAttachment => {
                write!(f, "Incomplete attachment")
            },
            GLFramebufferError::IncompleteDimensions => {
                write!(f, "Incomplete dimensions")
            },
            GLFramebufferError::IncompleteMissingAttachment => {
                write!(f, "Missing attachments")
            },
            GLFramebufferError::Unsupported => {
                write!(f, "Unsupported")
            }
        }
    }
}

impl error::Error for GLFramebufferError {
    fn description(&self) -> &str {
        match *self {
            GLFramebufferError::IncompleteAttachment => "One or more framebuffer attachments are not complete",
            GLFramebufferError::IncompleteDimensions => "Not all images attached to the framebuffer have the same width and height",
            GLFramebufferError::IncompleteMissingAttachment => "The framebuffer has no images attached",
            GLFramebufferError::Unsupported => "The framebuffer contains an unsupported combination of attachments",
        }
    }
}

impl From<GLFramebufferError> for GLError {
    fn from(e: GLFramebufferError) -> GLError {
        GLError::FramebufferError(e)
    }
}

gl_enum! {
    pub gl_enum DrawingMode {
        Points as POINTS = gl::POINTS,
        LineStrip as LINE_STRIP = gl::LINE_STRIP,
        LineLoop as LINE_LOOP = gl::LINE_LOOP,
        Lines as LINES = gl::LINES,
        TriangleStrip as TRIANGLE_STRIP = gl::TRIANGLE_STRIP,
        TriangleFan as TRIANGLE_FAN = gl::TRIANGLE_FAN,
        Triangles as TRIANGLES = gl::TRIANGLES
    }
}

gl_enum! {
    pub gl_enum DataType {
        Byte as BYTE = gl::BYTE,
        UnsignedByte as UNSIGNED_BYTE = gl::UNSIGNED_BYTE,
        Short as SHORT = gl::SHORT,
        UnsignedShort as UNSIGNED_SHORT = gl::UNSIGNED_SHORT,
        Fixed as FIXED = gl::FIXED,
        Float as FLOAT = gl::FLOAT
    }
}
<|endoftext|>


<commit_before>//! Globally-used traits, structs, and enums
use ndarray::LinalgScalar;
use svd::types::SVDError;
use eigenvalues::types::EigenError;
use solve_linear::types::SolveError;
use least_squares::LeastSquaresError;
use generate::GenerateError;
use factorization::qr::QRError;
use factorization::lu::LUError;
use factorization::cholesky::CholeskyError;
use std::ops::Sub;
use std::fmt::{Debug, Display};
use num_traits::{Float, Zero, One, NumCast};
use std::{f32, f64};
use rand::distributions::range::SampleRange;
pub use lapack::{c32, c64};

/// Enum for symmetric matrix inputs.
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Symmetric {
    /// Read elements from the upper-triangular portion of the matrix
    Upper = b'U',

    /// Read elements from the lower-triangular portion of the matrix
    Lower = b'L',
}

/// Universal `linxal` error enum
///
/// This enum can be used as a catch-all for errors from `linxal`
/// computations.
pub enum Error {
    SVD(SVDError),
    Eigen(EigenError),
    LeastSquares(LeastSquaresError),
    SolveLinear(SolveError),
    QR(QRError),
    LU(LUError),
    Cholesky(CholeskyError),
    Generate(GenerateError),
}

impl From<SVDError> for Error {
    fn from(e: SVDError) -> Error {
        Error::SVD(e)
    }
}

impl From<EigenError> for Error {
    fn from(e: EigenError) -> Error {
        Error::Eigen(e)
    }
}

impl From<LeastSquaresError> for Error {
    fn from(e: LeastSquaresError) -> Error {
        Error::LeastSquares(e)
    }
}

impl From<SolveError> for Error {
    fn from(e: SolveError) -> Error {
        Error::SolveLinear(e)
    }
}

impl From<QRError> for Error {
    fn from(e: QRError) -> Error {
        Error::QR(e)
    }
}

impl From<LUError> for Error {
    fn from(e: LUError) -> Error {
        Error::LU(e)
    }
}

impl From<CholeskyError> for Error {
    fn from(e: CholeskyError) -> Error {
        Error::Cholesky(e)
    }
}

impl From<GenerateError> for Error {
    fn from(e: GenerateError) -> Error {
        Error::Generate(e)
    }
}

/// Trait for matrix operations and utilities, including conjugation and magnitude.
///
/// This trait is unifies most required operations for real and
/// complex scalars.
pub trait LinxalScalar: Sized + Default + Clone + Debug + Display + Zero + One + Sub<Output=Self> + LinalgScalar {
    type RealPart: LinxalScalar + Float + NumCast + From<f32> + SampleRange;

    /// Return the conjugate of the value.
    fn cj(self) -> Self;

    /// Returns the magnitude of the scalar.
    fn mag(self) -> Self::RealPart;

    /// Return the machine epsilon for the value.
    fn eps() -> Self::RealPart;

    /// Return the default tolerance used for comparisons.
    fn tol() -> Self::RealPart;
}

impl LinxalScalar for f32 {
    type RealPart = f32;

    fn cj(self) -> Self {
        self
    }
    fn eps() -> Self::RealPart {
        f32::EPSILON
    }
    fn mag(self) -> Self::RealPart {
        self.abs()
    }
    fn tol() -> Self::RealPart {
        1e-5
    }
}

impl LinxalScalar for f64 {
    type RealPart = f64;

    fn cj(self) -> Self {
        self
    }
    fn eps() -> Self::RealPart {
        f64::EPSILON
    }
    fn mag(self) -> Self::RealPart {
        self.abs()
    }
    fn tol() -> Self::RealPart {
        2e-14
    }
}

impl LinxalScalar for c32 {
    type RealPart = f32;

    fn cj(self) -> Self{
        self.conj()
    }
    fn eps() -> Self::RealPart {
        f32::EPSILON
    }
    fn mag(self) -> Self::RealPart {
        self.norm()
    }
    fn tol() -> Self::RealPart {
        2e-5
    }
}

impl LinxalScalar for c64 {
    type RealPart = f64;

    fn cj(self) -> Self{
        self.conj()
    }
    fn eps() -> Self::RealPart {
        f64::EPSILON
    }
    fn mag(self) -> Self::RealPart {
        self.norm()
    }
    fn tol() -> Self::RealPart {
        4e-14
    }
}

/// Scalars that are also (real) floats.
pub trait LinxalFloat: LinxalScalar + Float {}
impl<T: LinxalScalar + Float> LinxalFloat for T {}

/// Scalars that are also complex floats.
pub trait LinxalComplex: LinxalScalar {}
impl LinxalComplex for c32 {}
impl LinxalComplex for c64 {}
<commit_msg>Error derives Debug<commit_after>//! Globally-used traits, structs, and enums
use ndarray::LinalgScalar;
use svd::types::SVDError;
use eigenvalues::types::EigenError;
use solve_linear::types::SolveError;
use least_squares::LeastSquaresError;
use generate::GenerateError;
use factorization::qr::QRError;
use factorization::lu::LUError;
use factorization::cholesky::CholeskyError;
use std::ops::Sub;
use std::fmt::{Debug, Display};
use num_traits::{Float, Zero, One, NumCast};
use std::{f32, f64};
use rand::distributions::range::SampleRange;
pub use lapack::{c32, c64};

/// Enum for symmetric matrix inputs.
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Symmetric {
    /// Read elements from the upper-triangular portion of the matrix
    Upper = b'U',

    /// Read elements from the lower-triangular portion of the matrix
    Lower = b'L',
}

/// Universal `linxal` error enum
///
/// This enum can be used as a catch-all for errors from `linxal`
/// computations.
#[derive(Debug)]
pub enum Error {
    SVD(SVDError),
    Eigen(EigenError),
    LeastSquares(LeastSquaresError),
    SolveLinear(SolveError),
    QR(QRError),
    LU(LUError),
    Cholesky(CholeskyError),
    Generate(GenerateError),
}

impl From<SVDError> for Error {
    fn from(e: SVDError) -> Error {
        Error::SVD(e)
    }
}

impl From<EigenError> for Error {
    fn from(e: EigenError) -> Error {
        Error::Eigen(e)
    }
}

impl From<LeastSquaresError> for Error {
    fn from(e: LeastSquaresError) -> Error {
        Error::LeastSquares(e)
    }
}

impl From<SolveError> for Error {
    fn from(e: SolveError) -> Error {
        Error::SolveLinear(e)
    }
}

impl From<QRError> for Error {
    fn from(e: QRError) -> Error {
        Error::QR(e)
    }
}

impl From<LUError> for Error {
    fn from(e: LUError) -> Error {
        Error::LU(e)
    }
}

impl From<CholeskyError> for Error {
    fn from(e: CholeskyError) -> Error {
        Error::Cholesky(e)
    }
}

impl From<GenerateError> for Error {
    fn from(e: GenerateError) -> Error {
        Error::Generate(e)
    }
}

/// Trait for matrix operations and utilities, including conjugation and magnitude.
///
/// This trait is unifies most required operations for real and
/// complex scalars.
pub trait LinxalScalar: Sized + Default + Clone + Debug + Display + Zero + One + Sub<Output=Self> + LinalgScalar {
    type RealPart: LinxalScalar + Float + NumCast + From<f32> + SampleRange;

    /// Return the conjugate of the value.
    fn cj(self) -> Self;

    /// Returns the magnitude of the scalar.
    fn mag(self) -> Self::RealPart;

    /// Return the machine epsilon for the value.
    fn eps() -> Self::RealPart;

    /// Return the default tolerance used for comparisons.
    fn tol() -> Self::RealPart;
}

impl LinxalScalar for f32 {
    type RealPart = f32;

    fn cj(self) -> Self {
        self
    }
    fn eps() -> Self::RealPart {
        f32::EPSILON
    }
    fn mag(self) -> Self::RealPart {
        self.abs()
    }
    fn tol() -> Self::RealPart {
        1e-5
    }
}

impl LinxalScalar for f64 {
    type RealPart = f64;

    fn cj(self) -> Self {
        self
    }
    fn eps() -> Self::RealPart {
        f64::EPSILON
    }
    fn mag(self) -> Self::RealPart {
        self.abs()
    }
    fn tol() -> Self::RealPart {
        2e-14
    }
}

impl LinxalScalar for c32 {
    type RealPart = f32;

    fn cj(self) -> Self{
        self.conj()
    }
    fn eps() -> Self::RealPart {
        f32::EPSILON
    }
    fn mag(self) -> Self::RealPart {
        self.norm()
    }
    fn tol() -> Self::RealPart {
        2e-5
    }
}

impl LinxalScalar for c64 {
    type RealPart = f64;

    fn cj(self) -> Self{
        self.conj()
    }
    fn eps() -> Self::RealPart {
        f64::EPSILON
    }
    fn mag(self) -> Self::RealPart {
        self.norm()
    }
    fn tol() -> Self::RealPart {
        4e-14
    }
}

/// Scalars that are also (real) floats.
pub trait LinxalFloat: LinxalScalar + Float {}
impl<T: LinxalScalar + Float> LinxalFloat for T {}

/// Scalars that are also complex floats.
pub trait LinxalComplex: LinxalScalar {}
impl LinxalComplex for c32 {}
impl LinxalComplex for c64 {}
<|endoftext|>


<commit_before>use super::gl_lib as gl;

pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32
}

impl Color {
    pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
        Color { r: r, g: g, b: b, a: a}
    }
}

pub struct Viewport {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32
}

impl Viewport {
    pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self {
        Viewport {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

bitflags! {
    flags BufferBits: gl::types::GLbitfield {
        const COLOR_BUFFER_BIT = gl::COLOR_BUFFER_BIT,
        const DEPTH_BUFFER_BIT = gl::DEPTH_BUFFER_BIT,
        const STENCIL_BUFFER_BIT = gl::STENCIL_BUFFER_BIT
    }
}

#[derive(Debug)]
pub enum GLError {
    InvalidEnum,
    InvalidValue,
    InvalidOperation,
    InvalidFramebufferOperation,
    OutOfMemory,
    Message(String)
}

#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum DrawingMode {
    POINTS = gl::POINTS as isize,
    LINE_STRIP = gl::LINE_STRIP as isize,
    LINE_LOOP = gl::LINE_LOOP as isize,
    LINES = gl::LINES as isize,
    TRIANGLE_STRIP = gl::TRIANGLE_STRIP as isize,
    TRIANGLE_FAN = gl::TRIANGLE_FAN as isize,
    TRIANGLES = gl::TRIANGLES as isize
}
pub use self::DrawingMode::*;
<commit_msg>Impl `Display` for `GLError`<commit_after>use std::fmt;
use super::gl_lib as gl;

pub struct Color {
    pub r: f32,
    pub g: f32,
    pub b: f32,
    pub a: f32
}

impl Color {
    pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Self {
        Color { r: r, g: g, b: b, a: a}
    }
}

pub struct Viewport {
    pub x: u32,
    pub y: u32,
    pub width: u32,
    pub height: u32
}

impl Viewport {
    pub fn new(x: u32, y: u32, width: u32, height: u32) -> Self {
        Viewport {
            x: x,
            y: y,
            width: width,
            height: height
        }
    }
}

bitflags! {
    flags BufferBits: gl::types::GLbitfield {
        const COLOR_BUFFER_BIT = gl::COLOR_BUFFER_BIT,
        const DEPTH_BUFFER_BIT = gl::DEPTH_BUFFER_BIT,
        const STENCIL_BUFFER_BIT = gl::STENCIL_BUFFER_BIT
    }
}

#[derive(Debug)]
pub enum GLError {
    InvalidEnum,
    InvalidValue,
    InvalidOperation,
    InvalidFramebufferOperation,
    OutOfMemory,
    Message(String)
}

impl fmt::Display for GLError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            GLError::InvalidEnum => {
                write!(f, "Invalid enum")
            },
            GLError::InvalidValue => {
                write!(f, "Invalid value")
            },
            GLError::InvalidOperation => {
                write!(f, "Invalid operation")
            },
            GLError::InvalidFramebufferOperation => {
                write!(f, "Invalid framebuffer operation")
            },
            GLError::OutOfMemory => {
                write!(f, "Out of memory")
            },
            GLError::Message(ref s) => {
                write!(f, "{}", s)
            }
        }
    }
}

#[derive(Debug, Clone, Copy)]
#[allow(non_camel_case_types)]
pub enum DrawingMode {
    POINTS = gl::POINTS as isize,
    LINE_STRIP = gl::LINE_STRIP as isize,
    LINE_LOOP = gl::LINE_LOOP as isize,
    LINES = gl::LINES as isize,
    TRIANGLE_STRIP = gl::TRIANGLE_STRIP as isize,
    TRIANGLE_FAN = gl::TRIANGLE_FAN as isize,
    TRIANGLES = gl::TRIANGLES as isize
}
pub use self::DrawingMode::*;
<|endoftext|>


<commit_before>
use std::string;
use std::iter;

static STANDARD_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

pub fn encode(b: &[u8]) -> Result<String, string::FromUtf8Error> {
    let mut out = Vec::new();
    let mut n: u64 = 0;

    for i in 0 .. b.len() {
        // Calculate the shift (32, 24, 16, 8, 0)
        let shift = 8 * (4 - (i % 5));
        n |= (b[i] as u64) << shift;

        // If the shift was zero, or this is the last character of input, extract
        // each 5-bit group from n.
        if shift == 0 || (i == b.len()-1) {
            // Determine number of output groups, based on the shift
            let groups = match shift {
                32 => 2,
                24 => 4,
                16 => 5,
                8  => 7,
                _  => 8
            };

            // Pull out each 5-bit index
            for j in iter::range_step(35, (35 - (groups * 5)), -5) {
                let ndx = (n >> j as u32) & 31;
                out.push(STANDARD_CHARS[ndx as usize]);
            }

            // Reset n
            n = 0;
        }
    }

    String::from_utf8(out)
}

pub fn decode(b: &[u8]) -> Vec<u8> {
    let mut out: Vec<u8> = Vec::new();
    let mut n: u64 = 0;

    for i in range(0, b.len()) {
        // Use the character to generate an index
        let c = b[i];
        let idx = match c as char {
            'A' ... 'Z' => c - 65, // A..Z => 65..90
            _ => 26 + (c - 50)     // 2..7 => 50..55
        };

        // Calculate the shift for this 5-bit group (35, 25, ..., 0)
        let shift = 35 - (5 * (i % 8));
        n |= (idx as u64 & 31) << shift;

        // If the shift is zero or this is the last character of input, extract
        // each 8-bit group from n.
        if shift == 0 || (i == b.len()-1) {
            // Determine number of output groups, based on shift
            let groups = match shift {
                35 => 0,
                30 => 1,
                25 => 2,
                20 => 2,
                15 => 3,
                10 => 4,
                5  => 4,
                _  => 5
            };

            // Pull out each 8-bit group
            for j in iter::range_step(32, (32 - (groups * 8)), -8) {
                let v = ((n >> j as u8) & 255) as u8;
                out.push(v);
            }

            // Reset n
            n = 0;
        }
    }

    out
}

macro_rules! check_encode(
    ($input:expr, $expected:expr) => ( {
        let x: Result<String, string::FromUtf8Error> = encode($input.as_bytes());
        assert_eq!(x.is_ok(), true);
        assert_eq!($expected, x.unwrap());
    });
    );

macro_rules! check_decode(
    ($expected:expr, $input:expr) => (
        assert_eq!($expected.as_bytes(), decode($input.as_bytes()));
        );
);

#[test]
fn encode_tests() {
    check_encode!("", "");
    check_encode!("f", "MY");
    check_encode!("foo", "MZXW6");
    check_encode!("foob", "MZXW6YQ");
    check_encode!("fooba", "MZXW6YTB");
    check_encode!("foobar", "MZXW6YTBOI");
}

#[test]
fn decode_tests() {
    check_decode!("", "");
    check_decode!("f", "MY");
    check_decode!("foo", "MZXW6");
    check_decode!("foob", "MZXW6YQ");
    check_decode!("fooba", "MZXW6YTB");
    check_decode!("foobar", "MZXW6YTBOI");
}

<commit_msg>ignore case for encode<commit_after>
use std::string;
use std::iter;
use std::ascii::AsciiExt;

static STANDARD_CHARS: &'static[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";

pub fn encode(b: &[u8]) -> Result<String, string::FromUtf8Error> {
    let mut out = Vec::new();
    let mut n: u64 = 0;

    for i in 0 .. b.len() {
        // Calculate the shift (32, 24, 16, 8, 0)
        let shift = 8 * (4 - (i % 5));
        n |= (b[i] as u64) << shift;

        // If the shift was zero, or this is the last character of input, extract
        // each 5-bit group from n.
        if shift == 0 || (i == b.len()-1) {
            // Determine number of output groups, based on the shift
            let groups = match shift {
                32 => 2,
                24 => 4,
                16 => 5,
                8  => 7,
                _  => 8
            };

            // Pull out each 5-bit index
            for j in iter::range_step(35, (35 - (groups * 5)), -5) {
                let ndx = (n >> j as u32) & 31;
                out.push(STANDARD_CHARS[ndx as usize]);
            }

            // Reset n
            n = 0;
        }
    }

    String::from_utf8(out)
}

pub fn decode(b: &[u8]) -> Vec<u8> {
    let mut out: Vec<u8> = Vec::new();
    let mut n: u64 = 0;

    for i in range(0, b.len()) {
        // Use the character to generate an index
        let c = b[i];
        let idx = match c as char {
            'A' ... 'Z' => c - 65, // A..Z => 65..90
            _ => 26 + (c - 50)     // 2..7 => 50..55
        };

        // Calculate the shift for this 5-bit group (35, 25, ..., 0)
        let shift = 35 - (5 * (i % 8));
        n |= (idx as u64 & 31) << shift;

        // If the shift is zero or this is the last character of input, extract
        // each 8-bit group from n.
        if shift == 0 || (i == b.len()-1) {
            // Determine number of output groups, based on shift
            let groups = match shift {
                35 => 0,
                30 => 1,
                25 => 2,
                20 => 2,
                15 => 3,
                10 => 4,
                5  => 4,
                _  => 5
            };

            // Pull out each 8-bit group
            for j in iter::range_step(32, (32 - (groups * 8)), -8) {
                let v = ((n >> j as u8) & 255) as u8;
                out.push(v);
            }

            // Reset n
            n = 0;
        }
    }

    out
}

macro_rules! check_encode(
    ($input:expr, $expected:expr) => ( {
        let x: Result<String, string::FromUtf8Error> = encode($input.as_bytes());
        assert_eq!(x.is_ok(), true);
        assert!(x.unwrap().eq_ignore_ascii_case($expected));
    });
    );

macro_rules! check_decode(
    ($expected:expr, $input:expr) => (
        assert_eq!($expected.as_bytes(), decode($input.as_bytes()));
        );
);

#[test]
fn encode_tests() {
    check_encode!("", "");
    check_encode!("f", "MY");
    check_encode!("foo", "MZXw6");
    check_encode!("foob", "MZXW6YQ");
    check_encode!("fooba", "MZXW6YTB");
    check_encode!("foobar", "MZXW6YTBOI");
}

#[test]
fn decode_tests() {
    check_decode!("", "");
    check_decode!("f", "MY");
    check_decode!("foo", "MZXW6");
    check_decode!("foob", "MZXW6YQ");
    check_decode!("fooba", "MZXW6YTB");
    check_decode!("foobar", "MZXW6YTBOI");
}

<|endoftext|>


<commit_before>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::RefCell;
use std::mem::transmute;

pub use glib::signal::Inhibit;
use glib::SourceId;
use glib::translate::*;
use glib::signal::SignalHandlerId;

use glib_ffi::{self, gboolean, gpointer};

use {
    Continue,
    ScrollType,
    SpinButton,
};

// idle_add and timeout_add fixed to the main thread

unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
    callback_guard!();
    let func: &RefCell<Box<FnMut() -> Continue + 'static>> = transmute(func);
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    callback_guard!();
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// Similar to `glib::idle_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn idle_add<F>(func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline),
            into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// Similar to `glib::timeout_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(
            glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline),
                 into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// Similar to `glib::timeout_add_seconds` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

pub trait EditableSignals {
    fn connect_changed<F>(&self, changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static;
    fn connect_delete_text<F>(&self, delete_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, i32, i32) + 'static;
    fn connect_insert_text<F>(&self, insert_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, &str, &mut i32) + 'static;
}

mod editable {
    use Editable;
    use Object;
    use std::mem::transmute;
    use ffi::GtkEditable;
    use glib::signal::{SignalHandlerId, connect};
    use glib::translate::*;
    use IsA;
    use libc::{c_char, c_int, c_uchar};
    use std::ffi::CStr;
    use std::str;
    use glib::object::Downcast;
    use std::slice;

    impl<T: IsA<Editable> + IsA<Object>> super::EditableSignals for T {
        fn connect_changed<F>(&self, changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self) + 'static>> =
                    Box::new(Box::new(changed_func));
                connect(self.to_glib_none().0, "changed",
                    transmute(trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_delete_text<F>(&self, delete_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, i32, i32) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self, i32, i32) + 'static>> =
                    Box::new(Box::new(delete_text_func));
                connect(self.to_glib_none().0, "delete-text",
                    transmute(delete_trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_insert_text<F>(&self, insert_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, &str, &mut i32) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self, &str, &mut i32) + 'static>> =
                    Box::new(Box::new(insert_text_func));
                connect(self.to_glib_none().0, "insert-text",
                    transmute(insert_trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }
    }

    unsafe extern "C" fn trampoline<T>(this: *mut GtkEditable,
                                       f: &&(Fn(&T) + 'static))
    where T: IsA<Editable> {
        callback_guard!();
        f(&Editable::from_glib_borrow(this).downcast_unchecked());
    }

    unsafe extern "C" fn delete_trampoline<T>(this: *mut GtkEditable,
                                              start_pos: c_int,
                                              end_pos: c_int,
                                              f: &&(Fn(&T, i32, i32) + 'static))
    where T: IsA<Editable> {
        callback_guard!();
        f(&Editable::from_glib_borrow(this).downcast_unchecked(), start_pos, end_pos);
    }

    unsafe extern "C" fn insert_trampoline<T>(this: *mut GtkEditable,
                                              new_text: *mut c_char,
                                              new_text_length: c_int,
                                              position: *mut c_int,
                                              f: &&(Fn(&T, &str, &mut i32) + 'static))
    where T: IsA<Editable> {
        callback_guard!();
        let buf = if new_text_length != -1 {
            slice::from_raw_parts(new_text as *mut c_uchar,
                                  new_text_length as usize)
        } else {
            CStr::from_ptr(new_text).to_bytes()
        };
        let string = str::from_utf8(buf).unwrap();
        f(&Editable::from_glib_borrow(this).downcast_unchecked(),
          string,
          transmute(position));
    }
}

pub trait SpinButtonSignals {
    fn connect_change_value<F>(&self, change_value_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton, ScrollType) + 'static;
    fn connect_input<F>(&self, input_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static;
    fn connect_output<F>(&self, output_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) -> Inhibit + 'static;
    fn connect_value_changed<F>(&self, value_changed_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) + 'static;
    fn connect_wrapped<F>(&self, wrapped_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) + 'static;
}

mod spin_button {
    use Inhibit;
    use SpinButton;
    use ScrollType;
    use ffi::{GTK_INPUT_ERROR, GtkSpinButton};
    use glib::signal::{SignalHandlerId, connect};
    use glib::translate::*;
    use glib_ffi::{GTRUE, GFALSE};
    use libc::{c_int, c_double};
    use std::boxed::Box as Box_;
    use std::mem::transmute;
    use glib_ffi::gboolean;

    impl ::SpinButtonSignals for SpinButton {
        fn connect_change_value<F>(&self, change_value_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton, ScrollType) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton, ScrollType) + 'static>> =
                    Box::new(Box::new(change_value_func));
                connect(self.to_glib_none().0, "change_value",
                        transmute(change_trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_input<F>(&self, f: F) -> SignalHandlerId
        where F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static {
            unsafe {
                let f: Box_<Box_<Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static>> = Box_::new(Box_::new(f));
                connect(self.to_glib_none().0, "input",
                        transmute(input_trampoline as usize), Box_::into_raw(f) as *mut _)
            }
        }

        fn connect_output<F>(&self, output_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) -> Inhibit + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) -> Inhibit + 'static>> =
                    Box::new(Box::new(output_func));
                connect(self.to_glib_none().0, "output",
                        transmute(output_trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_value_changed<F>(&self, value_changed_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) + 'static>> =
                    Box::new(Box::new(value_changed_func));
                connect(self.to_glib_none().0, "value-changed",
                        transmute(trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_wrapped<F>(&self, wrapped_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) + 'static>> =
                    Box::new(Box::new(wrapped_func));
                connect(self.to_glib_none().0, "wrapped",
                        transmute(trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }
    }

    unsafe extern "C" fn change_trampoline(this: *mut GtkSpinButton,
                                           scroll: ScrollType,
                                           f: &&(Fn(&SpinButton, ScrollType) + 'static)) {
        callback_guard!();
        f(&from_glib_borrow(this), scroll)
    }

    unsafe extern "C" fn input_trampoline(this: *mut GtkSpinButton,
                                          new_value: *mut c_double,
                                          f: &&(Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static))
                                          -> c_int {
        callback_guard!();
        match f(&from_glib_borrow(this)) {
            Some(Ok(v)) => {
                *new_value = v;
                GTRUE
            }
            Some(Err(_)) => GTK_INPUT_ERROR,
            None => GFALSE,
        }
    }

    unsafe extern "C" fn output_trampoline(this: *mut GtkSpinButton,
                                           f: &&(Fn(&SpinButton) -> Inhibit + 'static))
                                           -> gboolean {
        callback_guard!();
        f(&from_glib_borrow(this)).to_glib()
    }

    unsafe extern "C" fn trampoline(this: *mut GtkSpinButton,
                                    f: &&(Fn(&SpinButton) + 'static)) {
        callback_guard!();
        f(&from_glib_borrow(this))
    }
}
<commit_msg>Add signal Overlay::get-child-position<commit_after>// Copyright 2015, The Gtk-rs Project Developers.
// See the COPYRIGHT file at the top-level directory of this distribution.
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

use std::cell::RefCell;
use std::mem::transmute;

pub use glib::signal::Inhibit;
use glib::SourceId;
use glib::translate::*;
use glib::signal::SignalHandlerId;
use gdk::Rectangle;

use glib_ffi::{self, gboolean, gpointer};

use {
    Continue,
    ScrollType,
    SpinButton,
    Widget,
};

// idle_add and timeout_add fixed to the main thread

unsafe extern "C" fn trampoline(func: gpointer) -> gboolean {
    callback_guard!();
    let func: &RefCell<Box<FnMut() -> Continue + 'static>> = transmute(func);
    (&mut *func.borrow_mut())().to_glib()
}

unsafe extern "C" fn destroy_closure(ptr: gpointer) {
    callback_guard!();
    Box::<RefCell<Box<FnMut() -> Continue + 'static>>>::from_raw(ptr as *mut _);
}

fn into_raw<F: FnMut() -> Continue + 'static>(func: F) -> gpointer {
    let func: Box<RefCell<Box<FnMut() -> Continue + 'static>>> =
        Box::new(RefCell::new(Box::new(func)));
    Box::into_raw(func) as gpointer
}

/// Adds a closure to be called by the default main loop when it's idle.
///
/// `func` will be called repeatedly until it returns `Continue(false)`.
///
/// Similar to `glib::idle_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn idle_add<F>(func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(glib_ffi::g_idle_add_full(glib_ffi::G_PRIORITY_DEFAULT_IDLE, Some(trampoline),
            into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with millisecond granularity.
///
/// `func` will be called repeatedly every `interval` milliseconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events. Prefer `timeout_add_seconds` when millisecond
/// precision is not necessary.
///
/// Similar to `glib::timeout_add` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(
            glib_ffi::g_timeout_add_full(glib_ffi::G_PRIORITY_DEFAULT, interval, Some(trampoline),
                 into_raw(func), Some(destroy_closure)))
    }
}

/// Adds a closure to be called by the default main loop at regular intervals
/// with second granularity.
///
/// `func` will be called repeatedly every `interval` seconds until it
/// returns `Continue(false)`. Precise timing is not guaranteed, the timeout may
/// be delayed by other events.
///
/// Similar to `glib::timeout_add_seconds` but only callable from the main thread and
/// doesn't require `Send`.
pub fn timeout_add_seconds<F>(interval: u32, func: F) -> SourceId
    where F: FnMut() -> Continue + 'static {
    assert_initialized_main_thread!();
    unsafe {
        from_glib(glib_ffi::g_timeout_add_seconds_full(glib_ffi::G_PRIORITY_DEFAULT, interval,
            Some(trampoline), into_raw(func), Some(destroy_closure)))
    }
}

pub trait EditableSignals {
    fn connect_changed<F>(&self, changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static;
    fn connect_delete_text<F>(&self, delete_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, i32, i32) + 'static;
    fn connect_insert_text<F>(&self, insert_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, &str, &mut i32) + 'static;
}

mod editable {
    use Editable;
    use Object;
    use std::mem::transmute;
    use ffi::GtkEditable;
    use glib::signal::{SignalHandlerId, connect};
    use glib::translate::*;
    use IsA;
    use libc::{c_char, c_int, c_uchar};
    use std::ffi::CStr;
    use std::str;
    use glib::object::Downcast;
    use std::slice;

    impl<T: IsA<Editable> + IsA<Object>> super::EditableSignals for T {
        fn connect_changed<F>(&self, changed_func: F) -> SignalHandlerId
        where F: Fn(&Self) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self) + 'static>> =
                    Box::new(Box::new(changed_func));
                connect(self.to_glib_none().0, "changed",
                    transmute(trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_delete_text<F>(&self, delete_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, i32, i32) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self, i32, i32) + 'static>> =
                    Box::new(Box::new(delete_text_func));
                connect(self.to_glib_none().0, "delete-text",
                    transmute(delete_trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_insert_text<F>(&self, insert_text_func: F) -> SignalHandlerId
        where F: Fn(&Self, &str, &mut i32) + 'static {
            unsafe {
                let f: Box<Box<Fn(&Self, &str, &mut i32) + 'static>> =
                    Box::new(Box::new(insert_text_func));
                connect(self.to_glib_none().0, "insert-text",
                    transmute(insert_trampoline::<Self> as usize), Box::into_raw(f) as *mut _)
            }
        }
    }

    unsafe extern "C" fn trampoline<T>(this: *mut GtkEditable,
                                       f: &&(Fn(&T) + 'static))
    where T: IsA<Editable> {
        callback_guard!();
        f(&Editable::from_glib_borrow(this).downcast_unchecked());
    }

    unsafe extern "C" fn delete_trampoline<T>(this: *mut GtkEditable,
                                              start_pos: c_int,
                                              end_pos: c_int,
                                              f: &&(Fn(&T, i32, i32) + 'static))
    where T: IsA<Editable> {
        callback_guard!();
        f(&Editable::from_glib_borrow(this).downcast_unchecked(), start_pos, end_pos);
    }

    unsafe extern "C" fn insert_trampoline<T>(this: *mut GtkEditable,
                                              new_text: *mut c_char,
                                              new_text_length: c_int,
                                              position: *mut c_int,
                                              f: &&(Fn(&T, &str, &mut i32) + 'static))
    where T: IsA<Editable> {
        callback_guard!();
        let buf = if new_text_length != -1 {
            slice::from_raw_parts(new_text as *mut c_uchar,
                                  new_text_length as usize)
        } else {
            CStr::from_ptr(new_text).to_bytes()
        };
        let string = str::from_utf8(buf).unwrap();
        f(&Editable::from_glib_borrow(this).downcast_unchecked(),
          string,
          transmute(position));
    }
}

pub trait SpinButtonSignals {
    fn connect_change_value<F>(&self, change_value_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton, ScrollType) + 'static;
    fn connect_input<F>(&self, input_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static;
    fn connect_output<F>(&self, output_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) -> Inhibit + 'static;
    fn connect_value_changed<F>(&self, value_changed_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) + 'static;
    fn connect_wrapped<F>(&self, wrapped_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) + 'static;
}

mod spin_button {
    use Inhibit;
    use SpinButton;
    use ScrollType;
    use ffi::{GTK_INPUT_ERROR, GtkSpinButton};
    use glib::signal::{SignalHandlerId, connect};
    use glib::translate::*;
    use glib_ffi::{GTRUE, GFALSE};
    use libc::{c_int, c_double};
    use std::boxed::Box as Box_;
    use std::mem::transmute;
    use glib_ffi::gboolean;

    impl ::SpinButtonSignals for SpinButton {
        fn connect_change_value<F>(&self, change_value_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton, ScrollType) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton, ScrollType) + 'static>> =
                    Box::new(Box::new(change_value_func));
                connect(self.to_glib_none().0, "change_value",
                        transmute(change_trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_input<F>(&self, f: F) -> SignalHandlerId
        where F: Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static {
            unsafe {
                let f: Box_<Box_<Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static>> = Box_::new(Box_::new(f));
                connect(self.to_glib_none().0, "input",
                        transmute(input_trampoline as usize), Box_::into_raw(f) as *mut _)
            }
        }

        fn connect_output<F>(&self, output_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) -> Inhibit + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) -> Inhibit + 'static>> =
                    Box::new(Box::new(output_func));
                connect(self.to_glib_none().0, "output",
                        transmute(output_trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_value_changed<F>(&self, value_changed_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) + 'static>> =
                    Box::new(Box::new(value_changed_func));
                connect(self.to_glib_none().0, "value-changed",
                        transmute(trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }

        fn connect_wrapped<F>(&self, wrapped_func: F) -> SignalHandlerId
        where F: Fn(&SpinButton) + 'static {
            unsafe {
                let f: Box<Box<Fn(&SpinButton) + 'static>> =
                    Box::new(Box::new(wrapped_func));
                connect(self.to_glib_none().0, "wrapped",
                        transmute(trampoline as usize), Box::into_raw(f) as *mut _)
            }
        }
    }

    unsafe extern "C" fn change_trampoline(this: *mut GtkSpinButton,
                                           scroll: ScrollType,
                                           f: &&(Fn(&SpinButton, ScrollType) + 'static)) {
        callback_guard!();
        f(&from_glib_borrow(this), scroll)
    }

    unsafe extern "C" fn input_trampoline(this: *mut GtkSpinButton,
                                          new_value: *mut c_double,
                                          f: &&(Fn(&SpinButton) -> Option<Result<f64, ()>> + 'static))
                                          -> c_int {
        callback_guard!();
        match f(&from_glib_borrow(this)) {
            Some(Ok(v)) => {
                *new_value = v;
                GTRUE
            }
            Some(Err(_)) => GTK_INPUT_ERROR,
            None => GFALSE,
        }
    }

    unsafe extern "C" fn output_trampoline(this: *mut GtkSpinButton,
                                           f: &&(Fn(&SpinButton) -> Inhibit + 'static))
                                           -> gboolean {
        callback_guard!();
        f(&from_glib_borrow(this)).to_glib()
    }

    unsafe extern "C" fn trampoline(this: *mut GtkSpinButton,
                                    f: &&(Fn(&SpinButton) + 'static)) {
        callback_guard!();
        f(&from_glib_borrow(this))
    }
}

pub trait OverlaySignals {
    fn connect_get_child_position<F>(&self, f: F) -> SignalHandlerId
    where
        F: Fn(&Self, &Widget) -> Option<Rectangle> + 'static;
}

mod overlay {
    use gdk::Rectangle;
    use ffi::{GtkOverlay, GtkWidget};
    use gdk_ffi::GdkRectangle;
    use glib::signal::{connect, SignalHandlerId};
    use glib::translate::*;
    use glib::object::Downcast;
    use std::mem::transmute;
    use std::ptr;
    use glib_ffi::{gboolean, gpointer};
    use IsA;
    use Object;
    use Overlay;
    use Widget;

    impl<O: IsA<Overlay> + IsA<Object>> ::OverlaySignals for O {
        fn connect_get_child_position<F>(&self, f: F) -> SignalHandlerId
        where
            F: Fn(&Self, &Widget) -> Option<Rectangle> + 'static,
        {
            unsafe {
                let f: Box<Box<Fn(&Self, &Widget) -> Option<Rectangle> + 'static>> =
                    Box::new(Box::new(f));
                connect(
                    self.to_glib_none().0,
                    "get-child-position",
                    transmute(get_child_position_trampoline::<Self> as usize),
                    Box::into_raw(f) as *mut _,
                )
            }
        }
    }

    unsafe extern "C" fn get_child_position_trampoline<T>(
        this: *mut GtkOverlay,
        widget: *mut GtkWidget,
        allocation: *mut GdkRectangle,
        f: gpointer,
    ) -> gboolean
    where
        T: IsA<Overlay> + IsA<Object>,
    {
        callback_guard!();
        let f: &&(Fn(&T, &Widget) -> Option<Rectangle> + 'static) = transmute(f);
        match f(
            &Overlay::from_glib_borrow(this).downcast_unchecked(),
            &from_glib_borrow(widget),
        ) {
            Some(rect) => {
                ptr::write(allocation, ptr::read(rect.to_glib_none().0));
                true
            }
            None => false,
        }.to_glib()
    }
}
<|endoftext|>


<commit_before>use std::io::IoError;
use std::ptr::null;
use std::num::zero;
use std::time::duration::Duration;
use std::default::Default;
use std::io::process::Process;
use libc::types::os::common::posix01::timespec;
use time::{Timespec, get_time};

pub use libc::consts::os::posix88::{SIGTERM, SIGINT, SIGQUIT, EINTR};
use libc::{c_int, pid_t};

static SIGCHLD: c_int = 17;
static WNOHANG: c_int = 1;

#[deriving(Show)]
pub enum Signal {
    Terminate(int),  // Actual signal for termination: INT, TERM, QUIT...
    Child(pid_t, int),  //  pid and result code
    Reboot,
    Timeout,  // Not actually a OS signal, but it's a signal for our app
}

#[deriving(Default)]
#[repr(C)]
struct CSignalInfo {
    signo: c_int,
    pid: pid_t,
    status: c_int,
}

extern {
    fn block_all_signals();
    fn wait_any_signal(ptr: *mut CSignalInfo, timeout: *const timespec)
        -> c_int;
    fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
}

pub fn block_all() {
    unsafe { block_all_signals() };
}

fn _convert_status(status: i32) -> int {
    if status & 0xff == 0 {
        return ((status & 0xff00) >> 8) as int;
    }
    return (128 + (status & 0x7f)) as int;  // signal
}

pub fn wait_next(reboot_supported: bool, timeout: Option<Timespec>) -> Signal {
    let mut status: i32 = 0;
    let pid = unsafe { waitpid(-1, &mut status, WNOHANG) };
    if pid > 0 {
        return Child(pid, _convert_status(status));
    }
    loop {
        let mut ptr = Default::default();
        let res = match timeout {
            Some(tm) => {
                let dur = tm - get_time();
                let c_dur = if dur < zero() {
                    timespec { tv_sec: 0, tv_nsec: 0 }
                } else {
                    timespec {
                        tv_sec: dur.num_seconds(),
                        tv_nsec: (dur - Duration::seconds(dur.num_seconds()))
                            .num_nanoseconds().unwrap(),
                    }
                };
                unsafe { wait_any_signal(&mut ptr, &c_dur) }
            }
            None => {
                unsafe { wait_any_signal(&mut ptr, null()) }
            }
        };
        if res != 0 {
            //  Any error is ok, because application should be always prepared
            //  for spurious timeouts
            //  only EAGAIN and EINTR expected
            return Timeout;
        }
        match ptr.signo {
            SIGCHLD => {
                loop {
                    status = 0;
                    let rc = unsafe { waitpid(ptr.pid, &mut status, WNOHANG) };
                    if rc < 0 {
                        if rc == EINTR {
                            continue;
                        }
                        fail!("Failure '{}' not expected, on death of {}",
                            IoError::last_error(), ptr.pid);
                    }
                    assert_eq!(rc, ptr.pid);
                    break;
                }
                assert_eq!(_convert_status(status), ptr.status as int);
                return Child(ptr.pid, ptr.status as int);
            }
            SIGQUIT if reboot_supported => {
                return Reboot;
            }
            sig@SIGTERM | sig@SIGINT | sig@SIGQUIT => {
                return Terminate(sig as int);
            }
            _ => continue,   // TODO(tailhook) improve logging
        }
    }
}

pub fn send_signal(pid: pid_t, sig: int) {
    Process::kill(pid, sig).ok();
}
<commit_msg>Fix death signal handling<commit_after>use std::os::errno;
use std::io::IoError;
use std::ptr::null;
use std::num::zero;
use std::time::duration::Duration;
use std::default::Default;
use std::io::process::Process;
use libc::types::os::common::posix01::timespec;
use time::{Timespec, get_time};

pub use libc::consts::os::posix88::{SIGTERM, SIGINT, SIGQUIT, EINTR, ECHILD};
use libc::{c_int, pid_t};

static SIGCHLD: c_int = 17;
static WNOHANG: c_int = 1;

#[deriving(Show)]
pub enum Signal {
    Terminate(int),  // Actual signal for termination: INT, TERM, QUIT...
    Child(pid_t, int),  //  pid and result code
    Reboot,
    Timeout,  // Not actually a OS signal, but it's a signal for our app
}

#[deriving(Default)]
#[repr(C)]
struct CSignalInfo {
    signo: c_int,
    pid: pid_t,
    status: c_int,
}

extern {
    fn block_all_signals();
    fn wait_any_signal(ptr: *mut CSignalInfo, timeout: *const timespec)
        -> c_int;
    fn waitpid(pid: pid_t, status: *mut c_int, options: c_int) -> pid_t;
}

pub fn block_all() {
    unsafe { block_all_signals() };
}

fn _convert_status(status: i32) -> int {
    if status & 0xff == 0 {
        return ((status & 0xff00) >> 8) as int;
    }
    return (128 + (status & 0x7f)) as int;  // signal
}

pub fn wait_next(reboot_supported: bool, timeout: Option<Timespec>) -> Signal {
    let mut status: i32 = 0;
    let pid = unsafe { waitpid(-1, &mut status, WNOHANG) };
    if pid > 0 {
        return Child(pid, _convert_status(status));
    }
    loop {
        let mut ptr = Default::default();
        let res = match timeout {
            Some(tm) => {
                let dur = tm - get_time();
                let c_dur = if dur < zero() {
                    timespec { tv_sec: 0, tv_nsec: 0 }
                } else {
                    timespec {
                        tv_sec: dur.num_seconds(),
                        tv_nsec: (dur - Duration::seconds(dur.num_seconds()))
                            .num_nanoseconds().unwrap(),
                    }
                };
                unsafe { wait_any_signal(&mut ptr, &c_dur) }
            }
            None => {
                unsafe { wait_any_signal(&mut ptr, null()) }
            }
        };
        if res != 0 {
            //  Any error is ok, because application should be always prepared
            //  for spurious timeouts
            //  only EAGAIN and EINTR expected
            return Timeout;
        }
        match ptr.signo {
            SIGCHLD => {
                loop {
                    status = 0;
                    let rc = unsafe { waitpid(ptr.pid, &mut status, WNOHANG) };
                    if rc < 0 {
                        if errno() == EINTR as int {
                            continue;
                        }
                        if errno() != ECHILD as int {
                            fail!("Failure '{}' not expected, on death of {}",
                                IoError::last_error(), ptr.pid);
                        }
                    } else {
                        assert_eq!(rc, ptr.pid);
                        assert_eq!(_convert_status(status), ptr.status as int);
                    }
                    break;
                }
                return Child(ptr.pid, ptr.status as int);
            }
            SIGQUIT if reboot_supported => {
                return Reboot;
            }
            sig@SIGTERM | sig@SIGINT | sig@SIGQUIT => {
                return Terminate(sig as int);
            }
            _ => continue,   // TODO(tailhook) improve logging
        }
    }
}

pub fn send_signal(pid: pid_t, sig: int) {
    Process::kill(pid, sig).ok();
}
<|endoftext|>


<commit_before>#![deny(warnings)]
extern crate coreutils;
extern crate extra;

use std::env;
use std::fs;
use std::fs::FileType;
use std::path::Path;
use std::io::{stdout, stderr, Stderr, Write, BufWriter};
use std::os::unix::fs::MetadataExt;
use std::process::exit;
use std::vec::Vec;

use coreutils::{ArgParser, to_human_readable_string, format_system_time};
use coreutils::columns::print_columns;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{ls} */ r#"
NAME
    ls - list directory contents

SYNOPSIS
    ls [ -h | --help | -l ] [FILE]...

DESCRIPTION
    List information about the FILE(s), or the current directory

OPTIONS
    -a, --all
        do not ignore entries starting with .
    -h, --human-readable
        with -l, print human readable sizes
    --help
        display this help and exit
    -l
        use a long listing format
    -r, --reverse
        reverse order while sorting
    -R, --recursive
        list subdirectories recursively
    --mdate --modified-date
        display date of last modification
    --adate --accessed-date
        display date of last access
    --cdate --created-date
        display date of creation

"#; /* @MANEND */

fn mode_to_human_readable(file_type: &FileType, symlink_file_type: &FileType, mode: u32) -> String {

    let mut result = String::from("");
    if symlink_file_type.is_symlink() {
        result.push('l')
    } else if file_type.is_dir() {
        result.push('d');
    } else {
        result.push('-');
    }

    let mode_str = format!("{:>6o}", mode);
    let mode_chars = mode_str[3..].chars();
    for i in mode_chars {
        match i {
            '7' => result.push_str("rwx"),
            '6' => result.push_str("rw-"),
            '5' => result.push_str("r-x"),
            '4' => result.push_str("r--"),
            '3' => result.push_str("-wx"),
            '2' => result.push_str("-w-"),
            '1' => result.push_str("--x"),
            _ => result.push_str("---"),
        }
    }

    return result;
}

fn print_item(item_path: &str, parser: &ArgParser, output: &mut Vec<String>, stderr: &mut Stderr) {

    let mut link_error = "";
    let symlink_metadata = fs::symlink_metadata(&item_path).try(stderr);
    let metadata = match fs::metadata(&item_path) {
        Ok(metadata) => metadata,
        Err(_) => {
            link_error = "broken link";
            fs::symlink_metadata(&item_path).try(stderr)
        }
    };
    if parser.found("long-format") {
        output.push(format!("{} {:>5} {:>5} ",
                              mode_to_human_readable(&(metadata.file_type()), &(symlink_metadata.file_type()), metadata.mode()),
                              metadata.uid(),
                              metadata.gid())
                    );
        if parser.found("human-readable") {
            output.push(format!("{:>6} ", to_human_readable_string(metadata.size())));
        } else {
            output.push(format!("{:>8} ", metadata.size()));
        }
    }
    if parser.found("modified-date") || parser.found("long-format") {
        let mtime = match metadata.modified(){
            Ok(mtime) => format_system_time(mtime),
            Err(_) => "mdate err".to_string(),
        };
        output.push(format!("{:>20} ", mtime));
    }
    if parser.found("accessed-date") {
        let atime = match metadata.accessed(){
            Ok(atime) => format_system_time(atime),
            Err(_) => "adate err".to_string(),
        };
        output.push(format!("{:>20} ", atime));
    }
    if parser.found("created-date") {
        let ctime = match metadata.created(){
            Ok(ctime) => format_system_time(ctime),
            Err(_) => "cdate err".to_string(),
        };
        output.push(format!("{:>20} ", ctime));
    }

    if item_path.starts_with("./") {
        output.push(item_path[2..].to_string());
    } else {
        output.push(item_path.to_string());
    }
    if parser.found("long-format") && symlink_metadata.file_type().is_symlink() {
        let symlink_target = fs::read_link(item_path)
            .expect("can't read link")
            .into_os_string()
            .into_string()
            .expect("can't get path as string");
        output.push(format!(" -> {}", symlink_target));
        if !link_error.is_empty() {
            output.push(format!(" ({})", link_error));
        }
    }
}

fn list_dir(path: &str, parser: &ArgParser, output: &mut Vec<String>, stderr: &mut Stderr) {
    let show_hidden = parser.found("all");

    let metadata = fs::metadata(path).try(stderr);
    if metadata.is_dir() {
        let read_dir = Path::new(path).read_dir().try(stderr);

        let mut entries: Vec<String> = read_dir.filter_map(|x| x.ok())
            .map(|x| {
                let file_name = x.file_name().to_string_lossy().into_owned();
                file_name
            })
            .filter(|x| show_hidden || !x.starts_with("."))
            .collect();

        if parser.found("reverse") {
            entries.sort_by(|a, b| b.cmp(a));
        } else {
            entries.sort_by(|a, b| a.cmp(b));
        }

        for entry in entries.iter() {
            let mut entry_path = path.to_owned();
            if !entry_path.ends_with('/') {
                entry_path.push('/');
            }
            entry_path.push_str(&entry);
            print_item(&entry_path, &parser, output, stderr);
            if parser.found("recursive") && metadata.is_dir() {
                list_dir(&entry_path, parser, output, stderr);
            }
        }
    } else {
        print_item(&path, &parser, output, stderr);
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = BufWriter::new(stdout.lock());
    let mut stderr = stderr();

    let mut parser = ArgParser::new(6)
        .add_flag(&["a", "all"])
        .add_flag(&["l", "long-format"])
        .add_flag(&["h", "human-readable"])
        .add_flag(&["r", "reverse"])
        .add_flag(&["R", "recursive"])
        .add_flag(&["mdate", "modified-date"])
        .add_flag(&["adate", "accessed-date"])
        .add_flag(&["cdate", "created-date"])
        .add_flag(&["", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let mut output = Vec::new();
    if parser.args.is_empty() {
        list_dir(".", &parser, &mut output, &mut stderr);
    } else {
        for dir in parser.args.iter() {
            list_dir(&dir, &parser, &mut output, &mut stderr);
        }
    }

    if parser.found("long-format") {
        for (i, word) in output.iter().enumerate() {
            stdout.write(word.as_bytes()).try(&mut stderr);
            if i % 4 == 3 {
                !stdout.write("\n".as_bytes()).try(&mut stderr);
            }
        }
    } else {
        print_columns(output);
    }
    stdout.flush().try(&mut stderr);
}

/*
fn print_columns(words: Vec<String>) {
    let stdout = stdout();
    let mut stdout = BufWriter::new(stdout.lock());
    let mut stderr = stderr();

    let terminal_size = termion::terminal_size().unwrap().0 as usize;
    let columned = make_columns(words, terminal_size);
    for i in 0..columned[0].len() {
        for j in 0..columned.len() {
            if i < columned[j].len() {
                stdout.write(columned[j][i].as_bytes()).try(&mut stderr);
            }
        }
        stdout.write("\n".as_bytes()).try(&mut stderr);
    }
    stdout.flush().try(&mut stderr);
}

fn make_columns(mut words: Vec<String>, terminal_width: usize) -> Vec<Vec<String>> {

    let word_lengths: Vec<usize> =
        words.iter().map(|x: &String| -> usize {(&x).len() + 2}).collect();

    let columns_amt = bin_search( word_lengths.iter().fold(0   , |x, y| {min(x, *y)})
                                , word_lengths.iter().fold(1000, |x, y| {max(x, *y)})
                                , &word_lengths
                                , terminal_width);

    let longest_words: Vec<usize> =
        split_into_columns( &word_lengths
                          , columns_amt
                          , (words.len() / columns_amt) + 1
                          ).iter().map(longest_word).collect();

    let mut words_with_space: Vec<String> = Vec::new();
    let lines_amt = (words.len() / columns_amt) + 1;
    let mut longest_words_rep = Vec::new();
    for longest_word in longest_words {
        for _ in 0..lines_amt {
            longest_words_rep.push(longest_word.clone());
        }
    }

    for i in 0..words.len() {

        let whitespace = " ".repeat(longest_words_rep[i] - words[i].len());
        words[i].push_str(whitespace.as_str());
        words_with_space.push(words[i].clone());
    }

    split_into_columns::<String>(&words_with_space, columns_amt, (words.len() / columns_amt) + 1)
}

fn bin_search(min: usize, max: usize, words: &Vec<usize>, terminal_width: usize) -> usize {
    let diff = min as isize - max as isize;
    let fits = try_rows(words, min + (max - min) / 2, terminal_width);
    if  diff == -1 || diff == 0 || diff == 1{
        return min;
    } else if fits {
        return bin_search(min + (max - min) / 2, max, words, terminal_width);
    } else {
        return bin_search(min, min + (max - min) / 2, words, terminal_width);
    }
}

fn longest_word(words: &Vec<usize>) -> usize {
    words.iter().fold(0, |x, y| {max(x, *y)})
}

fn split_into_columns<T: Clone>(words: &Vec<T>, columns: usize, lines_amt: usize) -> Vec<Vec<T>> {
    let mut outputs: Vec<Vec<T>> = Vec::new();
    for _ in 0..columns {
        outputs.push(Vec::new())
    }
    let mut i = 0;
    'outer: for output in &mut outputs {
        let mut j = 0;
        while j < lines_amt {
            if i >= words.len() {
                break 'outer;
            }
            output.push(words.get(i).unwrap().clone());
            i += 1;
            j += 1;
        }
    }
    outputs
}

fn try_rows(input: &Vec<usize>, columns: usize, width: usize) -> bool {

    let lines_amt = (input.len() / columns) + 1;

    let sum_line_widths = |widths_list: Vec<usize>| -> usize {
        widths_list.iter().fold(0, |x, y| { x + *y})
    };

    sum_line_widths(
        split_into_columns(input, columns, lines_amt).iter().map(
            longest_word
        ).collect()
    ) <= width
}
*/

#[test]
fn test_human_readable() {
    assert_eq!(to_human_readable_string(0), "0");
    assert_eq!(to_human_readable_string(1023), "1023");
    assert_eq!(to_human_readable_string(1024), "1.0K");
    assert_eq!(to_human_readable_string(1024 + 100), "1.1K");
    assert_eq!(to_human_readable_string(1024u64.pow(2) * 2), "2.0M");
    assert_eq!(to_human_readable_string(1024u64.pow(3) * 3), "3.0G");
    assert_eq!(to_human_readable_string(1024u64.pow(4) * 4), "4.0T");
    assert_eq!(to_human_readable_string(1024u64.pow(5) * 5), "5.0P");
    assert_eq!(to_human_readable_string(1024u64.pow(6) * 6), "6.0E");
}

#[test]
fn test_format_system_time() {
    use std::ops::Add;
    use std::time::{SystemTime, Duration};
    let now = SystemTime::now();
    let future = SystemTime::now().add(Duration::from_secs(10));
    assert_ne!(format_system_time(now), format_system_time(future));
    // compare up to ten minutes: 2017-03-21 17:1_:__
    assert_eq!(format_system_time(now)[..15], format_system_time(future)[..15]);
}
<commit_msg>remove code from ls.rs that moved into lib.rs anyway<commit_after>#![deny(warnings)]
extern crate coreutils;
extern crate extra;

use std::env;
use std::fs;
use std::fs::FileType;
use std::path::Path;
use std::io::{stdout, stderr, Stderr, Write, BufWriter};
use std::os::unix::fs::MetadataExt;
use std::process::exit;
use std::vec::Vec;

use coreutils::{ArgParser, to_human_readable_string, format_system_time};
use coreutils::columns::print_columns;
use extra::option::OptionalExt;

const MAN_PAGE: &'static str = /* @MANSTART{ls} */ r#"
NAME
    ls - list directory contents

SYNOPSIS
    ls [ -h | --help | -l ] [FILE]...

DESCRIPTION
    List information about the FILE(s), or the current directory

OPTIONS
    -a, --all
        do not ignore entries starting with .
    -h, --human-readable
        with -l, print human readable sizes
    --help
        display this help and exit
    -l
        use a long listing format
    -r, --reverse
        reverse order while sorting
    -R, --recursive
        list subdirectories recursively
    --mdate --modified-date
        display date of last modification
    --adate --accessed-date
        display date of last access
    --cdate --created-date
        display date of creation

"#; /* @MANEND */

fn mode_to_human_readable(file_type: &FileType, symlink_file_type: &FileType, mode: u32) -> String {

    let mut result = String::from("");
    if symlink_file_type.is_symlink() {
        result.push('l')
    } else if file_type.is_dir() {
        result.push('d');
    } else {
        result.push('-');
    }

    let mode_str = format!("{:>6o}", mode);
    let mode_chars = mode_str[3..].chars();
    for i in mode_chars {
        match i {
            '7' => result.push_str("rwx"),
            '6' => result.push_str("rw-"),
            '5' => result.push_str("r-x"),
            '4' => result.push_str("r--"),
            '3' => result.push_str("-wx"),
            '2' => result.push_str("-w-"),
            '1' => result.push_str("--x"),
            _ => result.push_str("---"),
        }
    }

    return result;
}

fn print_item(item_path: &str, parser: &ArgParser, output: &mut Vec<String>, stderr: &mut Stderr) {

    let mut link_error = "";
    let symlink_metadata = fs::symlink_metadata(&item_path).try(stderr);
    let metadata = match fs::metadata(&item_path) {
        Ok(metadata) => metadata,
        Err(_) => {
            link_error = "broken link";
            fs::symlink_metadata(&item_path).try(stderr)
        }
    };
    if parser.found("long-format") {
        output.push(format!("{} {:>5} {:>5} ",
                              mode_to_human_readable(&(metadata.file_type()), &(symlink_metadata.file_type()), metadata.mode()),
                              metadata.uid(),
                              metadata.gid())
                    );
        if parser.found("human-readable") {
            output.push(format!("{:>6} ", to_human_readable_string(metadata.size())));
        } else {
            output.push(format!("{:>8} ", metadata.size()));
        }
    }
    if parser.found("modified-date") || parser.found("long-format") {
        let mtime = match metadata.modified(){
            Ok(mtime) => format_system_time(mtime),
            Err(_) => "mdate err".to_string(),
        };
        output.push(format!("{:>20} ", mtime));
    }
    if parser.found("accessed-date") {
        let atime = match metadata.accessed(){
            Ok(atime) => format_system_time(atime),
            Err(_) => "adate err".to_string(),
        };
        output.push(format!("{:>20} ", atime));
    }
    if parser.found("created-date") {
        let ctime = match metadata.created(){
            Ok(ctime) => format_system_time(ctime),
            Err(_) => "cdate err".to_string(),
        };
        output.push(format!("{:>20} ", ctime));
    }

    if item_path.starts_with("./") {
        output.push(item_path[2..].to_string());
    } else {
        output.push(item_path.to_string());
    }
    if parser.found("long-format") && symlink_metadata.file_type().is_symlink() {
        let symlink_target = fs::read_link(item_path)
            .expect("can't read link")
            .into_os_string()
            .into_string()
            .expect("can't get path as string");
        output.push(format!(" -> {}", symlink_target));
        if !link_error.is_empty() {
            output.push(format!(" ({})", link_error));
        }
    }
}

fn list_dir(path: &str, parser: &ArgParser, output: &mut Vec<String>, stderr: &mut Stderr) {
    let show_hidden = parser.found("all");

    let metadata = fs::metadata(path).try(stderr);
    if metadata.is_dir() {
        let read_dir = Path::new(path).read_dir().try(stderr);

        let mut entries: Vec<String> = read_dir.filter_map(|x| x.ok())
            .map(|x| {
                let file_name = x.file_name().to_string_lossy().into_owned();
                file_name
            })
            .filter(|x| show_hidden || !x.starts_with("."))
            .collect();

        if parser.found("reverse") {
            entries.sort_by(|a, b| b.cmp(a));
        } else {
            entries.sort_by(|a, b| a.cmp(b));
        }

        for entry in entries.iter() {
            let mut entry_path = path.to_owned();
            if !entry_path.ends_with('/') {
                entry_path.push('/');
            }
            entry_path.push_str(&entry);
            print_item(&entry_path, &parser, output, stderr);
            if parser.found("recursive") && metadata.is_dir() {
                list_dir(&entry_path, parser, output, stderr);
            }
        }
    } else {
        print_item(&path, &parser, output, stderr);
    }
}

fn main() {
    let stdout = stdout();
    let mut stdout = BufWriter::new(stdout.lock());
    let mut stderr = stderr();

    let mut parser = ArgParser::new(6)
        .add_flag(&["a", "all"])
        .add_flag(&["l", "long-format"])
        .add_flag(&["h", "human-readable"])
        .add_flag(&["r", "reverse"])
        .add_flag(&["R", "recursive"])
        .add_flag(&["mdate", "modified-date"])
        .add_flag(&["adate", "accessed-date"])
        .add_flag(&["cdate", "created-date"])
        .add_flag(&["", "help"]);
    parser.parse(env::args());

    if parser.found("help") {
        stdout.write(MAN_PAGE.as_bytes()).try(&mut stderr);
        stdout.flush().try(&mut stderr);
        exit(0);
    }

    let mut output = Vec::new();
    if parser.args.is_empty() {
        list_dir(".", &parser, &mut output, &mut stderr);
    } else {
        for dir in parser.args.iter() {
            list_dir(&dir, &parser, &mut output, &mut stderr);
        }
    }

    if parser.found("long-format") {
        for (i, word) in output.iter().enumerate() {
            stdout.write(word.as_bytes()).try(&mut stderr);
            if i % 4 == 3 {
                !stdout.write("\n".as_bytes()).try(&mut stderr);
            }
        }
    } else {
        print_columns(output);
    }
    stdout.flush().try(&mut stderr);
}

#[test]
fn test_human_readable() {
    assert_eq!(to_human_readable_string(0), "0");
    assert_eq!(to_human_readable_string(1023), "1023");
    assert_eq!(to_human_readable_string(1024), "1.0K");
    assert_eq!(to_human_readable_string(1024 + 100), "1.1K");
    assert_eq!(to_human_readable_string(1024u64.pow(2) * 2), "2.0M");
    assert_eq!(to_human_readable_string(1024u64.pow(3) * 3), "3.0G");
    assert_eq!(to_human_readable_string(1024u64.pow(4) * 4), "4.0T");
    assert_eq!(to_human_readable_string(1024u64.pow(5) * 5), "5.0P");
    assert_eq!(to_human_readable_string(1024u64.pow(6) * 6), "6.0E");
}

#[test]
fn test_format_system_time() {
    use std::ops::Add;
    use std::time::{SystemTime, Duration};
    let now = SystemTime::now();
    let future = SystemTime::now().add(Duration::from_secs(10));
    assert_ne!(format_system_time(now), format_system_time(future));
    // compare up to ten minutes: 2017-03-21 17:1_:__
    assert_eq!(format_system_time(now)[..15], format_system_time(future)[..15]);
}
<|endoftext|>