<commit_before>/*!
A uniform is a global variable in your program. In order to draw something, you will need to
give `glium` the values of all your uniforms. Objects that implement the `Uniform` trait are
here to do that.

There are two primarily ways to do this. The first one is to create your own structure and put
the `#[uniforms]` attribute on it. See the `glium_macros` crate for more infos.

The second way is to use the `uniform!` macro provided by glium:

```no_run
#[macro_use]
extern crate glium;

# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let tex: f32 = unsafe { std::mem::uninitialized() };
# let matrix: f32 = unsafe { std::mem::uninitialized() };
let uniforms = uniform! {
    texture: tex,
    matrix: matrix
};
# }
```

In both situations, each field must implement the `UniformValue` trait.

## Samplers

In order to customize the way a texture is being sampled, you must use a `Sampler`.

```no_run
#[macro_use]
extern crate glium;

# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };
let uniforms = uniform! {
    texture: glium::uniforms::Sampler::new(&texture)
                        .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
};
# }
```

## Blocks

In GLSL, you can choose to use a uniform *block*. When you use a block, you first need to
upload the content of this block in the video memory thanks to a `UniformBuffer`. Then you
can link the buffer to the name of the block, just like any other uniform.

```no_run
#[macro_use]
extern crate glium;
# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };

let program = glium::Program::from_source(&display,
    "
        #version 110

        attribute vec2 position;

        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
        }
    ",
    "
        #version 330
        uniform layout(std140);

        uniform MyBlock {
            vec3 color;
        };

        void main() {
            gl_FragColor = vec4(color, 1.0);
        }
    ",
    None);

let buffer = glium::uniforms::UniformBuffer::new(&display, (0.5f32, 0.5f32, 0.5f32)).unwrap();

let uniforms = uniform! {
    MyBlock: &buffer
};
# }
```

## Subroutines
OpenGL allows the use of subroutines, which are like function pointers. Subroutines can be used
to change the functionality of a shader program at runtime. This method is usually a lot faster
than using multiple programs that are switched during execution.

A subroutine uniform is unique per shader stage, and not per program.

```no_run
#[macro_use]
extern crate glium;
# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };

let program = glium::Program::from_source(&display,
    "
        #version 150
        in vec2 position;
        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
        }
    ",
    "
        #version 150
        #extension GL_ARB_shader_subroutine : require
        out vec4 fragColor;
        subroutine vec4 modify_t(vec4 color);
        subroutine uniform modify_t modify_color;

        subroutine(modify_t) vec4 delete_r(vec4 color)
        {
          return vec4(0, color.g, color.b, color.a);
        }

        subroutine(modify_t) vec4 delete_b(vec4 color)
        {
          return vec4(color.r, color.g, 0, color.a);
        }

        void main()
        {
            vec4 white= vec4(1, 1, 1, 1);
            fragColor = modify_color(white);
        }
    ", None);

    let uniforms = uniform! {
        modify_color: ("delete_b", glium::program::ShaderStage::Fragment)
    };
# }
```
*/
pub use self::buffer::UniformBuffer;
pub use self::sampler::{SamplerWrapFunction, MagnifySamplerFilter, MinifySamplerFilter};
pub use self::sampler::{Sampler, SamplerBehavior};
pub use self::uniforms::{EmptyUniforms, UniformsStorage};
pub use self::value::{UniformValue, UniformType};

use std::error::Error;
use std::fmt;

use buffer::Content as BufferContent;
use buffer::Buffer;
use program;
use program::BlockLayout;

mod bind;
mod buffer;
mod sampler;
mod uniforms;
mod value;

/// Object that contains the values of all the uniforms to bind to a program.
///
/// Objects of this type can be passed to the `draw()` function.
pub trait Uniforms {
    /// Calls the parameter once with the name and value of each uniform.
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, F);
}

/// Error about a block layout mismatch.
#[derive(Clone, Debug)]
pub enum LayoutMismatchError {
    /// There is a mismatch in the type of one element.
    TypeMismatch {
        /// Type expected by the shader.
        expected: UniformType,
        /// Type that you gave.
        obtained: UniformType,
    },

    /// The expected layout is totally different from what we have.
    LayoutMismatch {
        /// Layout expected by the shader.
        expected: BlockLayout,
        /// Layout of the input.
        obtained: BlockLayout,
    },

    /// The type of data is good, but there is a misalignment.
    OffsetMismatch {
        /// Expected offset of a member.
        expected: usize,
        /// Offset of the same member in the input.
        obtained: usize,
    },

    /// There is a mismatch in a submember of this layout.
    ///
    /// This is kind of a hierarchy inside the `LayoutMismatchError`s.
    MemberMismatch {
        /// Name of the field.
        member: String,
        /// The sub-error.
        err: Box<LayoutMismatchError>,
    },

    /// A field is missing in either the expected of the input data layout.
    MissingField {
        /// Name of the field.
        name: String,
    },
}

impl Error for LayoutMismatchError {
    fn description(&self) -> &str {
        use self::LayoutMismatchError::*;
        match *self {
            TypeMismatch { .. } =>
                "There is a mismatch in the type of one element",
            LayoutMismatch { .. } =>
                "The expected layout is totally different from what we have",
            OffsetMismatch { .. } =>
                "The type of data is good, but there is a misalignment",
            MemberMismatch { .. } =>
                "There is a mismatch in a submember of this layout",
            MissingField { .. } =>
                "A field is missing in either the expected of the input data layout",
        }
    }

    fn cause(&self) -> Option<&Error> {
        use self::LayoutMismatchError::*;
        match *self {
            MemberMismatch{ ref err, .. } => Some(err.as_ref()),
            _ => None,
        }
    }
}

impl fmt::Display for LayoutMismatchError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::LayoutMismatchError::*;
        match *self {
            //duplicate Patternmatching, different Types can't be condensed
            TypeMismatch { ref expected, ref obtained } =>
                write!(
                    fmt,
                    "{}, got: {:?}, expected: {:?}",
                    self.description(),
                    obtained,
                    expected,
                ),
            LayoutMismatch { ref expected, ref obtained } =>
                write!(
                    fmt,
                    "{}, got: {:?}, expected: {:?}",
                    self.description(),
                    obtained,
                    expected,
                ),
            OffsetMismatch { ref expected, ref obtained } =>
                write!(
                    fmt,
                    "{}, got: {}, expected: {}",
                    self.description(),
                    obtained,
                    expected,
                ),
            MemberMismatch { ref member, ref err } =>
                write!(
                    fmt,
                    "{}, {}: {}",
                    self.description(),
                    member,
                    err,
                ),
            MissingField { ref name } =>
                write!(
                    fmt,
                    "{}: {}",
                    self.description(),
                    name,
                ),
        }
    }
}

/// Value that can be used as the value of a uniform.
///
/// This includes buffers and textures for example.
pub trait AsUniformValue {
    /// Builds a `UniformValue`.
    fn as_uniform_value(&self) -> UniformValue;
}

// TODO: no way to bind a slice
impl<'a, T: ?Sized> AsUniformValue for &'a Buffer<T> where T: UniformBlock + BufferContent {
    #[inline]
    fn as_uniform_value(&self) -> UniformValue {
        #[inline]
        fn f<T: ?Sized>(block: &program::UniformBlock)
                        -> Result<(), LayoutMismatchError> where T: UniformBlock + BufferContent
        {
            // TODO: more checks?
            T::matches(&block.layout, 0)
        }

        UniformValue::Block(self.as_slice_any(), f::<T>)
    }
}

/// Objects that are suitable for being inside a uniform block or a SSBO.
pub trait UniformBlock {        // TODO: `: Copy`, but unsized structs don't impl `Copy`
    /// Checks whether the uniforms' layout matches the given block if `Self` starts at
    /// the given offset.
    fn matches(&BlockLayout, base_offset: usize) -> Result<(), LayoutMismatchError>;

    /// Builds the `BlockLayout` corresponding to the current object.
    fn build_layout(base_offset: usize) -> BlockLayout;
}

impl<T> UniformBlock for [T] where T: UniformBlock {
    fn matches(layout: &BlockLayout, base_offset: usize)
               -> Result<(), LayoutMismatchError>
    {
        if let &BlockLayout::Struct { ref members } = layout {
            if members.len() == 1 {
                return Self::matches(&members[0].1, base_offset);
            }
        }

        if let &BlockLayout::DynamicSizedArray { ref content } = layout {
            <T as UniformBlock>::matches(content, base_offset)
                .map_err(|err| {
                    LayoutMismatchError::MemberMismatch {
                        member: "<dynamic array content>".to_owned(),
                        err: Box::new(err),
                    }
                })

        } else if let &BlockLayout::Array { ref content, .. } = layout {
            <T as UniformBlock>::matches(content, base_offset)
                .map_err(|err| {
                    LayoutMismatchError::MemberMismatch {
                        member: "<dynamic array content>".to_owned(),
                        err: Box::new(err),
                    }
                })

        } else {
            Err(LayoutMismatchError::LayoutMismatch {
                expected: layout.clone(),
                obtained: <Self as UniformBlock>::build_layout(base_offset),
            })
        }
    }

    #[inline]
    fn build_layout(base_offset: usize) -> BlockLayout {
        BlockLayout::DynamicSizedArray {
            content: Box::new(<T as UniformBlock>::build_layout(base_offset)),
        }
    }
}

macro_rules! impl_uniform_block_array {
    ($len:expr) => (
        impl<T> UniformBlock for [T; $len] where T: UniformBlock {
            fn matches(layout: &program::BlockLayout, base_offset: usize)
                       -> Result<(), LayoutMismatchError>
            {
                if let &BlockLayout::Struct { ref members } = layout {
                    if members.len() == 1 {
                        return Self::matches(&members[0].1, base_offset);
                    }
                }

                if let &BlockLayout::Array { ref content, length } = layout {
                    if let Err(err) = T::matches(content, base_offset) {
                        return Err(LayoutMismatchError::MemberMismatch {
                            member: "<array content>".to_owned(),
                            err: Box::new(err),
                        });
                    }

                    if length != $len {
                        return Err(LayoutMismatchError::LayoutMismatch {
                            expected: layout.clone(),
                            obtained: Self::build_layout(base_offset),
                        });
                    }

                    Ok(())

                } else {
                    Err(LayoutMismatchError::LayoutMismatch {
                        expected: layout.clone(),
                        obtained: Self::build_layout(base_offset),
                    })
                }
            }

            #[inline]
            fn build_layout(base_offset: usize) -> program::BlockLayout {
                BlockLayout::Array {
                    content: Box::new(T::build_layout(base_offset)),
                    length: $len,
                }
            }
        }
    );
}

impl_uniform_block_array!(5);
impl_uniform_block_array!(6);
impl_uniform_block_array!(7);
impl_uniform_block_array!(8);
impl_uniform_block_array!(9);
impl_uniform_block_array!(10);
impl_uniform_block_array!(11);
impl_uniform_block_array!(12);
impl_uniform_block_array!(13);
impl_uniform_block_array!(14);
impl_uniform_block_array!(15);
impl_uniform_block_array!(16);
impl_uniform_block_array!(17);
impl_uniform_block_array!(18);
impl_uniform_block_array!(19);
impl_uniform_block_array!(20);
impl_uniform_block_array!(21);
impl_uniform_block_array!(22);
impl_uniform_block_array!(23);
impl_uniform_block_array!(24);
impl_uniform_block_array!(25);
impl_uniform_block_array!(26);
impl_uniform_block_array!(27);
impl_uniform_block_array!(28);
impl_uniform_block_array!(29);
impl_uniform_block_array!(30);
impl_uniform_block_array!(31);
impl_uniform_block_array!(32);
impl_uniform_block_array!(64);
impl_uniform_block_array!(128);
impl_uniform_block_array!(256);
impl_uniform_block_array!(512);
impl_uniform_block_array!(1024);
impl_uniform_block_array!(2048);
<commit_msg>fix a typo<commit_after>/*!
A uniform is a global variable in your program. In order to draw something, you will need to
give `glium` the values of all your uniforms. Objects that implement the `Uniform` trait are
here to do that.

There are two primary ways to do this. The first one is to create your own structure and put
the `#[uniforms]` attribute on it. See the `glium_macros` crate for more infos.

The second way is to use the `uniform!` macro provided by glium:

```no_run
#[macro_use]
extern crate glium;

# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let tex: f32 = unsafe { std::mem::uninitialized() };
# let matrix: f32 = unsafe { std::mem::uninitialized() };
let uniforms = uniform! {
    texture: tex,
    matrix: matrix
};
# }
```

In both situations, each field must implement the `UniformValue` trait.

## Samplers

In order to customize the way a texture is being sampled, you must use a `Sampler`.

```no_run
#[macro_use]
extern crate glium;

# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };
let uniforms = uniform! {
    texture: glium::uniforms::Sampler::new(&texture)
                        .magnify_filter(glium::uniforms::MagnifySamplerFilter::Nearest)
};
# }
```

## Blocks

In GLSL, you can choose to use a uniform *block*. When you use a block, you first need to
upload the content of this block in the video memory thanks to a `UniformBuffer`. Then you
can link the buffer to the name of the block, just like any other uniform.

```no_run
#[macro_use]
extern crate glium;
# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };

let program = glium::Program::from_source(&display,
    "
        #version 110

        attribute vec2 position;

        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
        }
    ",
    "
        #version 330
        uniform layout(std140);

        uniform MyBlock {
            vec3 color;
        };

        void main() {
            gl_FragColor = vec4(color, 1.0);
        }
    ",
    None);

let buffer = glium::uniforms::UniformBuffer::new(&display, (0.5f32, 0.5f32, 0.5f32)).unwrap();

let uniforms = uniform! {
    MyBlock: &buffer
};
# }
```

## Subroutines
OpenGL allows the use of subroutines, which are like function pointers. Subroutines can be used
to change the functionality of a shader program at runtime. This method is usually a lot faster
than using multiple programs that are switched during execution.

A subroutine uniform is unique per shader stage, and not per program.

```no_run
#[macro_use]
extern crate glium;
# fn main() {
# let display: glium::Display = unsafe { std::mem::uninitialized() };
# let texture: glium::texture::Texture2d = unsafe { std::mem::uninitialized() };

let program = glium::Program::from_source(&display,
    "
        #version 150
        in vec2 position;
        void main() {
            gl_Position = vec4(position, 0.0, 1.0);
        }
    ",
    "
        #version 150
        #extension GL_ARB_shader_subroutine : require
        out vec4 fragColor;
        subroutine vec4 modify_t(vec4 color);
        subroutine uniform modify_t modify_color;

        subroutine(modify_t) vec4 delete_r(vec4 color)
        {
          return vec4(0, color.g, color.b, color.a);
        }

        subroutine(modify_t) vec4 delete_b(vec4 color)
        {
          return vec4(color.r, color.g, 0, color.a);
        }

        void main()
        {
            vec4 white= vec4(1, 1, 1, 1);
            fragColor = modify_color(white);
        }
    ", None);

    let uniforms = uniform! {
        modify_color: ("delete_b", glium::program::ShaderStage::Fragment)
    };
# }
```
*/
pub use self::buffer::UniformBuffer;
pub use self::sampler::{SamplerWrapFunction, MagnifySamplerFilter, MinifySamplerFilter};
pub use self::sampler::{Sampler, SamplerBehavior};
pub use self::uniforms::{EmptyUniforms, UniformsStorage};
pub use self::value::{UniformValue, UniformType};

use std::error::Error;
use std::fmt;

use buffer::Content as BufferContent;
use buffer::Buffer;
use program;
use program::BlockLayout;

mod bind;
mod buffer;
mod sampler;
mod uniforms;
mod value;

/// Object that contains the values of all the uniforms to bind to a program.
///
/// Objects of this type can be passed to the `draw()` function.
pub trait Uniforms {
    /// Calls the parameter once with the name and value of each uniform.
    fn visit_values<'a, F: FnMut(&str, UniformValue<'a>)>(&'a self, F);
}

/// Error about a block layout mismatch.
#[derive(Clone, Debug)]
pub enum LayoutMismatchError {
    /// There is a mismatch in the type of one element.
    TypeMismatch {
        /// Type expected by the shader.
        expected: UniformType,
        /// Type that you gave.
        obtained: UniformType,
    },

    /// The expected layout is totally different from what we have.
    LayoutMismatch {
        /// Layout expected by the shader.
        expected: BlockLayout,
        /// Layout of the input.
        obtained: BlockLayout,
    },

    /// The type of data is good, but there is a misalignment.
    OffsetMismatch {
        /// Expected offset of a member.
        expected: usize,
        /// Offset of the same member in the input.
        obtained: usize,
    },

    /// There is a mismatch in a submember of this layout.
    ///
    /// This is kind of a hierarchy inside the `LayoutMismatchError`s.
    MemberMismatch {
        /// Name of the field.
        member: String,
        /// The sub-error.
        err: Box<LayoutMismatchError>,
    },

    /// A field is missing in either the expected of the input data layout.
    MissingField {
        /// Name of the field.
        name: String,
    },
}

impl Error for LayoutMismatchError {
    fn description(&self) -> &str {
        use self::LayoutMismatchError::*;
        match *self {
            TypeMismatch { .. } =>
                "There is a mismatch in the type of one element",
            LayoutMismatch { .. } =>
                "The expected layout is totally different from what we have",
            OffsetMismatch { .. } =>
                "The type of data is good, but there is a misalignment",
            MemberMismatch { .. } =>
                "There is a mismatch in a submember of this layout",
            MissingField { .. } =>
                "A field is missing in either the expected of the input data layout",
        }
    }

    fn cause(&self) -> Option<&Error> {
        use self::LayoutMismatchError::*;
        match *self {
            MemberMismatch{ ref err, .. } => Some(err.as_ref()),
            _ => None,
        }
    }
}

impl fmt::Display for LayoutMismatchError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::LayoutMismatchError::*;
        match *self {
            //duplicate Patternmatching, different Types can't be condensed
            TypeMismatch { ref expected, ref obtained } =>
                write!(
                    fmt,
                    "{}, got: {:?}, expected: {:?}",
                    self.description(),
                    obtained,
                    expected,
                ),
            LayoutMismatch { ref expected, ref obtained } =>
                write!(
                    fmt,
                    "{}, got: {:?}, expected: {:?}",
                    self.description(),
                    obtained,
                    expected,
                ),
            OffsetMismatch { ref expected, ref obtained } =>
                write!(
                    fmt,
                    "{}, got: {}, expected: {}",
                    self.description(),
                    obtained,
                    expected,
                ),
            MemberMismatch { ref member, ref err } =>
                write!(
                    fmt,
                    "{}, {}: {}",
                    self.description(),
                    member,
                    err,
                ),
            MissingField { ref name } =>
                write!(
                    fmt,
                    "{}: {}",
                    self.description(),
                    name,
                ),
        }
    }
}

/// Value that can be used as the value of a uniform.
///
/// This includes buffers and textures for example.
pub trait AsUniformValue {
    /// Builds a `UniformValue`.
    fn as_uniform_value(&self) -> UniformValue;
}

// TODO: no way to bind a slice
impl<'a, T: ?Sized> AsUniformValue for &'a Buffer<T> where T: UniformBlock + BufferContent {
    #[inline]
    fn as_uniform_value(&self) -> UniformValue {
        #[inline]
        fn f<T: ?Sized>(block: &program::UniformBlock)
                        -> Result<(), LayoutMismatchError> where T: UniformBlock + BufferContent
        {
            // TODO: more checks?
            T::matches(&block.layout, 0)
        }

        UniformValue::Block(self.as_slice_any(), f::<T>)
    }
}

/// Objects that are suitable for being inside a uniform block or a SSBO.
pub trait UniformBlock {        // TODO: `: Copy`, but unsized structs don't impl `Copy`
    /// Checks whether the uniforms' layout matches the given block if `Self` starts at
    /// the given offset.
    fn matches(&BlockLayout, base_offset: usize) -> Result<(), LayoutMismatchError>;

    /// Builds the `BlockLayout` corresponding to the current object.
    fn build_layout(base_offset: usize) -> BlockLayout;
}

impl<T> UniformBlock for [T] where T: UniformBlock {
    fn matches(layout: &BlockLayout, base_offset: usize)
               -> Result<(), LayoutMismatchError>
    {
        if let &BlockLayout::Struct { ref members } = layout {
            if members.len() == 1 {
                return Self::matches(&members[0].1, base_offset);
            }
        }

        if let &BlockLayout::DynamicSizedArray { ref content } = layout {
            <T as UniformBlock>::matches(content, base_offset)
                .map_err(|err| {
                    LayoutMismatchError::MemberMismatch {
                        member: "<dynamic array content>".to_owned(),
                        err: Box::new(err),
                    }
                })

        } else if let &BlockLayout::Array { ref content, .. } = layout {
            <T as UniformBlock>::matches(content, base_offset)
                .map_err(|err| {
                    LayoutMismatchError::MemberMismatch {
                        member: "<dynamic array content>".to_owned(),
                        err: Box::new(err),
                    }
                })

        } else {
            Err(LayoutMismatchError::LayoutMismatch {
                expected: layout.clone(),
                obtained: <Self as UniformBlock>::build_layout(base_offset),
            })
        }
    }

    #[inline]
    fn build_layout(base_offset: usize) -> BlockLayout {
        BlockLayout::DynamicSizedArray {
            content: Box::new(<T as UniformBlock>::build_layout(base_offset)),
        }
    }
}

macro_rules! impl_uniform_block_array {
    ($len:expr) => (
        impl<T> UniformBlock for [T; $len] where T: UniformBlock {
            fn matches(layout: &program::BlockLayout, base_offset: usize)
                       -> Result<(), LayoutMismatchError>
            {
                if let &BlockLayout::Struct { ref members } = layout {
                    if members.len() == 1 {
                        return Self::matches(&members[0].1, base_offset);
                    }
                }

                if let &BlockLayout::Array { ref content, length } = layout {
                    if let Err(err) = T::matches(content, base_offset) {
                        return Err(LayoutMismatchError::MemberMismatch {
                            member: "<array content>".to_owned(),
                            err: Box::new(err),
                        });
                    }

                    if length != $len {
                        return Err(LayoutMismatchError::LayoutMismatch {
                            expected: layout.clone(),
                            obtained: Self::build_layout(base_offset),
                        });
                    }

                    Ok(())

                } else {
                    Err(LayoutMismatchError::LayoutMismatch {
                        expected: layout.clone(),
                        obtained: Self::build_layout(base_offset),
                    })
                }
            }

            #[inline]
            fn build_layout(base_offset: usize) -> program::BlockLayout {
                BlockLayout::Array {
                    content: Box::new(T::build_layout(base_offset)),
                    length: $len,
                }
            }
        }
    );
}

impl_uniform_block_array!(5);
impl_uniform_block_array!(6);
impl_uniform_block_array!(7);
impl_uniform_block_array!(8);
impl_uniform_block_array!(9);
impl_uniform_block_array!(10);
impl_uniform_block_array!(11);
impl_uniform_block_array!(12);
impl_uniform_block_array!(13);
impl_uniform_block_array!(14);
impl_uniform_block_array!(15);
impl_uniform_block_array!(16);
impl_uniform_block_array!(17);
impl_uniform_block_array!(18);
impl_uniform_block_array!(19);
impl_uniform_block_array!(20);
impl_uniform_block_array!(21);
impl_uniform_block_array!(22);
impl_uniform_block_array!(23);
impl_uniform_block_array!(24);
impl_uniform_block_array!(25);
impl_uniform_block_array!(26);
impl_uniform_block_array!(27);
impl_uniform_block_array!(28);
impl_uniform_block_array!(29);
impl_uniform_block_array!(30);
impl_uniform_block_array!(31);
impl_uniform_block_array!(32);
impl_uniform_block_array!(64);
impl_uniform_block_array!(128);
impl_uniform_block_array!(256);
impl_uniform_block_array!(512);
impl_uniform_block_array!(1024);
impl_uniform_block_array!(2048);
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::env;
use std::process;

use console::style;
use failure::{Error, Fail};
use lazy_static::lazy_static;
use regex::{Captures, Regex};

use crate::config::Config;

#[cfg(not(windows))]
pub fn run_or_interrupt<F>(f: F)
where
    F: FnOnce() + Send + 'static,
{
    let (tx, rx) = crossbeam_channel::bounded(100);
    let mut signals = signal_hook::iterator::Signals::new(&[
        signal_hook::consts::SIGTERM,
        signal_hook::consts::SIGINT,
    ])
    .unwrap();

    {
        let tx = tx.clone();
        std::thread::spawn(move || {
            f();
            tx.send(0).ok();
        });
    }

    std::thread::spawn(move || {
        for signal in signals.forever() {
            tx.send(signal).ok();
        }
    });

    if let Ok(signal) = rx.recv() {
        if signal == signal_hook::consts::SIGINT {
            eprintln!("Interrupted!");
        }
    }
}

#[cfg(windows)]
pub fn run_or_interrupt<F>(f: F)
where
    F: FnOnce() -> (),
    F: Send + 'static,
{
    f();
}

/// Propagate an exit status outwarts
pub fn propagate_exit_status(status: process::ExitStatus) {
    if !status.success() {
        if let Some(code) = status.code() {
            process::exit(code);
        } else {
            process::exit(1);
        }
    }
}

#[cfg(not(windows))]
fn is_homebrew_install_result() -> Result<bool, Error> {
    let mut exe = env::current_exe()?.canonicalize()?;
    exe.pop();
    exe.set_file_name("INSTALL_RECEIPT.json");
    Ok(exe.is_file())
}

#[cfg(windows)]
fn is_homebrew_install_result() -> Result<bool, Error> {
    Ok(false)
}

fn is_npm_install_result() -> Result<bool, Error> {
    let mut exe = env::current_exe()?.canonicalize()?;
    exe.set_file_name("package.json");
    Ok(exe.is_file())
}

/// Checks if we were installed from homebrew
pub fn is_homebrew_install() -> bool {
    is_homebrew_install_result().unwrap_or(false)
}

/// Checks if we were installed via npm
pub fn is_npm_install() -> bool {
    is_npm_install_result().unwrap_or(false)
}

/// Expands variables in a string
pub fn expand_vars<F: Fn(&str) -> String>(s: &str, f: F) -> Cow<'_, str> {
    lazy_static! {
        static ref VAR_RE: Regex = Regex::new(r"\$(\$|[a-zA-Z0-9_]+|\([^)]+\)|\{[^}]+\})").unwrap();
    }
    VAR_RE.replace_all(s, |caps: &Captures<'_>| {
        let key = &caps[1];
        if key == "$" {
            "$".into()
        } else if &key[..1] == "(" || &key[..1] == "{" {
            f(&key[1..key.len() - 1])
        } else {
            f(key)
        }
    })
}

/// Helper that renders an error to stderr.
pub fn print_error(err: &Error) {
    if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
        clap_err.exit();
    }

    for (idx, cause) in err.iter_chain().enumerate() {
        match idx {
            0 => eprintln!("{} {}", style("error:").red(), cause),
            _ => eprintln!("  {} {}", style("caused by:").dim(), cause),
        }
    }

    if Config::current().get_log_level() < log::LevelFilter::Info {
        eprintln!();
        eprintln!("{}", style("Add --log-level=[info|debug] or export SENTRY_LOG_LEVEL=[info|debug] to see more output.").dim());
        eprintln!(
            "{}",
            style("Please attach the full debug log to all bug reports.").dim()
        );
    }

    if env::var("RUST_BACKTRACE") == Ok("1".into()) {
        eprintln!();
        let backtrace = format!("{:?}", err.backtrace());
        eprintln!("{}", style(&backtrace).dim());
    }
}

/// Initializes the backtrace support
pub fn init_backtrace() {
    std::panic::set_hook(Box::new(|info| {
        let backtrace = backtrace::Backtrace::new();

        let thread = std::thread::current();
        let thread = thread.name().unwrap_or("unnamed");

        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => match info.payload().downcast_ref::<String>() {
                Some(s) => &**s,
                None => "Box<Any>",
            },
        };

        match info.location() {
            Some(location) => {
                eprintln!(
                    "thread '{}' panicked at '{}': {}:{}\n\n{:?}",
                    thread,
                    msg,
                    location.file(),
                    location.line(),
                    backtrace
                );
            }
            None => eprintln!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
        }

        #[cfg(feature = "with_client_implementation")]
        {
            crate::utils::crashreporting::flush_events();
        }
    }));
}

/// Indicates that sentry-cli should quit without printing anything.
#[derive(Fail, Debug)]
#[fail(display = "sentry-cli exit with {}", _0)]
pub struct QuietExit(pub i32);

/// Loads a .env file
pub fn load_dotenv() {
    if env::var("SENTRY_LOAD_DOTENV")
        .map(|x| x.as_str() == "1")
        .unwrap_or(true)
    {
        dotenv::dotenv().ok();
    }
}
<commit_msg>feat: Allow to load dotenv from non-standard path (#1046)<commit_after>use std::borrow::Cow;
use std::env;
use std::process;

use console::style;
use failure::{Error, Fail};
use lazy_static::lazy_static;
use regex::{Captures, Regex};

use crate::config::Config;

#[cfg(not(windows))]
pub fn run_or_interrupt<F>(f: F)
where
    F: FnOnce() + Send + 'static,
{
    let (tx, rx) = crossbeam_channel::bounded(100);
    let mut signals = signal_hook::iterator::Signals::new(&[
        signal_hook::consts::SIGTERM,
        signal_hook::consts::SIGINT,
    ])
    .unwrap();

    {
        let tx = tx.clone();
        std::thread::spawn(move || {
            f();
            tx.send(0).ok();
        });
    }

    std::thread::spawn(move || {
        for signal in signals.forever() {
            tx.send(signal).ok();
        }
    });

    if let Ok(signal) = rx.recv() {
        if signal == signal_hook::consts::SIGINT {
            eprintln!("Interrupted!");
        }
    }
}

#[cfg(windows)]
pub fn run_or_interrupt<F>(f: F)
where
    F: FnOnce() -> (),
    F: Send + 'static,
{
    f();
}

/// Propagate an exit status outwarts
pub fn propagate_exit_status(status: process::ExitStatus) {
    if !status.success() {
        if let Some(code) = status.code() {
            process::exit(code);
        } else {
            process::exit(1);
        }
    }
}

#[cfg(not(windows))]
fn is_homebrew_install_result() -> Result<bool, Error> {
    let mut exe = env::current_exe()?.canonicalize()?;
    exe.pop();
    exe.set_file_name("INSTALL_RECEIPT.json");
    Ok(exe.is_file())
}

#[cfg(windows)]
fn is_homebrew_install_result() -> Result<bool, Error> {
    Ok(false)
}

fn is_npm_install_result() -> Result<bool, Error> {
    let mut exe = env::current_exe()?.canonicalize()?;
    exe.set_file_name("package.json");
    Ok(exe.is_file())
}

/// Checks if we were installed from homebrew
pub fn is_homebrew_install() -> bool {
    is_homebrew_install_result().unwrap_or(false)
}

/// Checks if we were installed via npm
pub fn is_npm_install() -> bool {
    is_npm_install_result().unwrap_or(false)
}

/// Expands variables in a string
pub fn expand_vars<F: Fn(&str) -> String>(s: &str, f: F) -> Cow<'_, str> {
    lazy_static! {
        static ref VAR_RE: Regex = Regex::new(r"\$(\$|[a-zA-Z0-9_]+|\([^)]+\)|\{[^}]+\})").unwrap();
    }
    VAR_RE.replace_all(s, |caps: &Captures<'_>| {
        let key = &caps[1];
        if key == "$" {
            "$".into()
        } else if &key[..1] == "(" || &key[..1] == "{" {
            f(&key[1..key.len() - 1])
        } else {
            f(key)
        }
    })
}

/// Helper that renders an error to stderr.
pub fn print_error(err: &Error) {
    if let Some(clap_err) = err.downcast_ref::<clap::Error>() {
        clap_err.exit();
    }

    for (idx, cause) in err.iter_chain().enumerate() {
        match idx {
            0 => eprintln!("{} {}", style("error:").red(), cause),
            _ => eprintln!("  {} {}", style("caused by:").dim(), cause),
        }
    }

    if Config::current().get_log_level() < log::LevelFilter::Info {
        eprintln!();
        eprintln!("{}", style("Add --log-level=[info|debug] or export SENTRY_LOG_LEVEL=[info|debug] to see more output.").dim());
        eprintln!(
            "{}",
            style("Please attach the full debug log to all bug reports.").dim()
        );
    }

    if env::var("RUST_BACKTRACE") == Ok("1".into()) {
        eprintln!();
        let backtrace = format!("{:?}", err.backtrace());
        eprintln!("{}", style(&backtrace).dim());
    }
}

/// Initializes the backtrace support
pub fn init_backtrace() {
    std::panic::set_hook(Box::new(|info| {
        let backtrace = backtrace::Backtrace::new();

        let thread = std::thread::current();
        let thread = thread.name().unwrap_or("unnamed");

        let msg = match info.payload().downcast_ref::<&'static str>() {
            Some(s) => *s,
            None => match info.payload().downcast_ref::<String>() {
                Some(s) => &**s,
                None => "Box<Any>",
            },
        };

        match info.location() {
            Some(location) => {
                eprintln!(
                    "thread '{}' panicked at '{}': {}:{}\n\n{:?}",
                    thread,
                    msg,
                    location.file(),
                    location.line(),
                    backtrace
                );
            }
            None => eprintln!("thread '{}' panicked at '{}'{:?}", thread, msg, backtrace),
        }

        #[cfg(feature = "with_client_implementation")]
        {
            crate::utils::crashreporting::flush_events();
        }
    }));
}

/// Indicates that sentry-cli should quit without printing anything.
#[derive(Fail, Debug)]
#[fail(display = "sentry-cli exit with {}", _0)]
pub struct QuietExit(pub i32);

/// Loads a .env file
pub fn load_dotenv() {
    if env::var("SENTRY_LOAD_DOTENV")
        .map(|x| x.as_str() == "1")
        .unwrap_or(true)
    {
        if let Ok(path) = env::var("SENTRY_DOTENV_PATH") {
            dotenv::from_path(path).ok();
        } else {
            dotenv::dotenv().ok();
        }
    }
}
<|endoftext|>


<commit_before>extern crate itertools;
use super::merge_policy::{MergePolicy, MergeCandidate};
use core::SegmentMeta;

pub struct LogMergePolicy;
use std::f64;

const LEVEL_LOG_SIZE: f64 = 0.75;

impl MergePolicy for LogMergePolicy {
    fn compute_merge_candidates(&self, segments: &[SegmentMeta]) -> Vec<MergeCandidate> {
        if segments.is_empty() {
            return Vec::new();
        }
        let mut size_sorted_tuples = segments.iter()
            .map(|x| {x.num_docs})
            .enumerate()
            .collect::<Vec<(usize, u32)>>();

        size_sorted_tuples.sort_by_key(|x| {x.1});

        let size_sorted_log_tuples: Vec<_> = size_sorted_tuples.iter()
            .map(|x| {(x.0, (x.1 as f64).log2())}).collect();

        let (first_ind, first_score) = size_sorted_log_tuples[0];
        let mut current_max_log_size = first_score;
        let mut levels = Vec::new();
        levels.push(Vec::new());
        levels.last_mut().unwrap().push(first_ind);
        for &(ind, score) in (&size_sorted_log_tuples).iter().skip(1) {
            if score < (current_max_log_size - LEVEL_LOG_SIZE) {
                current_max_log_size = score;
                levels.push(Vec::new());
            }
            levels.last_mut().unwrap().push(ind);
        }

        let result = levels.iter()
            .map(|ind_vec| {
                MergeCandidate(ind_vec.iter()
                    .map(|&ind| {
                        segments[ind].segment_id
                    }).collect())
            }).collect();

        result
    }
}

impl Default for LogMergePolicy {
    fn default() -> LogMergePolicy {
        LogMergePolicy
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use indexer::merge_policy::MergePolicy;
    #[test]
    fn test_log_merge_policy_empty() {
        let y = Vec::new();
        let result_list = LogMergePolicy::default().compute_merge_candidates(&y);
        assert!(result_list.len() == 0);
    }
}<commit_msg>added another simple test for LogMergePolicy, minor reformatting<commit_after>extern crate itertools;
use super::merge_policy::{MergePolicy, MergeCandidate};
use core::SegmentMeta;

pub struct LogMergePolicy;
use std::f64;

const LEVEL_LOG_SIZE: f64 = 0.75;

impl MergePolicy for LogMergePolicy {
    fn compute_merge_candidates(&self, segments: &[SegmentMeta]) -> Vec<MergeCandidate> {
        if segments.is_empty() {
            return Vec::new();
        }
        let mut size_sorted_tuples = segments.iter()
            .map(|x| x.num_docs)
            .enumerate()
            .collect::<Vec<(usize, u32)>>();

        size_sorted_tuples.sort_by_key(|x| x.1);

        let size_sorted_log_tuples: Vec<_> = size_sorted_tuples.iter()
            .map(|x| (x.0, (x.1 as f64).log2()))
            .collect();

        let (first_ind, first_score) = size_sorted_log_tuples[0];
        let mut current_max_log_size = first_score;
        let mut levels = Vec::new();
        levels.push(Vec::new());
        levels.last_mut().unwrap().push(first_ind);
        for &(ind, score) in (&size_sorted_log_tuples).iter().skip(1) {
            if score < (current_max_log_size - LEVEL_LOG_SIZE) {
                current_max_log_size = score;
                levels.push(Vec::new());
            }
            levels.last_mut().unwrap().push(ind);
        }

        let result = levels.iter()
            .map(|ind_vec| {
                MergeCandidate(ind_vec.iter()
                    .map(|&ind| segments[ind].segment_id)
                    .collect())
            })
            .collect();

        result
    }
}

impl Default for LogMergePolicy {
    fn default() -> LogMergePolicy {
        LogMergePolicy
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use indexer::merge_policy::MergePolicy;
    use core::{SegmentMeta, SegmentId};

    #[test]
    fn test_log_merge_policy_empty() {
        let y = Vec::new();
        let result_list = LogMergePolicy::default().compute_merge_candidates(&y);
        assert!(result_list.len() == 0);
    }

    #[test]
    fn test_log_merge_policy_pair() {
        let test_input = vec![SegmentMeta::new(SegmentId::generate_random(), 10),
                              SegmentMeta::new(SegmentId::generate_random(), 10)];
        let result_list = LogMergePolicy::default().compute_merge_candidates(&test_input);
        assert!(result_list.len() == 1);
    }

    #[test]
    fn test_log_merge_policy_levels() {
        // multiple levels all get merged correctly
    }

    #[test]
    fn test_log_merge_policy_small() {
        // deal correctly with tiny segments?
    }

    // what else... deletions? threading/concurrency?
}<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! [Flexible target specification.](https://github.com/rust-lang/rfcs/pull/131)
//!
//! Rust targets a wide variety of usecases, and in the interest of flexibility,
//! allows new target triples to be defined in configuration files. Most users
//! will not need to care about these, but this is invaluable when porting Rust
//! to a new platform, and allows for an unprecedented level of control over how
//! the compiler works.
//!
//! # Using custom targets
//!
//! A target triple, as passed via `rustc --target=TRIPLE`, will first be
//! compared against the list of built-in targets. This is to ease distributing
//! rustc (no need for configuration files) and also to hold these built-in
//! targets as immutable and sacred. If `TRIPLE` is not one of the built-in
//! targets, rustc will check if a file named `TRIPLE` exists. If it does, it
//! will be loaded as the target configuration. If the file does not exist,
//! rustc will search each directory in the environment variable
//! `RUST_TARGET_PATH` for a file named `TRIPLE.json`. The first one found will
//! be loaded. If no file is found in any of those directories, a fatal error
//! will be given.  `RUST_TARGET_PATH` includes `/etc/rustc` as its last entry,
//! to be searched by default.
//!
//! Projects defining their own targets should use
//! `--target=path/to/my-awesome-platform.json` instead of adding to
//! `RUST_TARGET_PATH`.
//!
//! # Defining a new target
//!
//! Targets are defined using [JSON](http://json.org/). The `Target` struct in
//! this module defines the format the JSON file should take, though each
//! underscore in the field names should be replaced with a hyphen (`-`) in the
//! JSON file. Some fields are required in every target specification, such as
//! `data-layout`, `llvm-target`, `target-endian`, `target-word-size`, and
//! `arch`. In general, options passed to rustc with `-C` override the target's
//! settings, though `target-feature` and `link-args` will *add* to the list
//! specified by the target, rather than replace.

use serialize::json::Json;
use syntax::{diagnostic, abi};
use std::default::Default;
use std::io::fs::PathExtensions;

mod windows_base;
mod linux_base;
mod apple_base;
mod freebsd_base;
mod dragonfly_base;

mod arm_apple_ios;
mod arm_linux_androideabi;
mod arm_unknown_linux_gnueabi;
mod arm_unknown_linux_gnueabihf;
mod i686_apple_darwin;
mod i386_apple_ios;
mod i686_pc_windows_gnu;
mod i686_unknown_linux_gnu;
mod mips_unknown_linux_gnu;
mod mipsel_unknown_linux_gnu;
mod x86_64_apple_darwin;
mod x86_64_pc_windows_gnu;
mod x86_64_unknown_freebsd;
mod x86_64_unknown_dragonfly;
mod x86_64_unknown_linux_gnu;

/// Everything `rustc` knows about how to compile for a specific target.
///
/// Every field here must be specified, and has no default value.
#[deriving(Clone, Show)]
pub struct Target {
    /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
    pub data_layout: String,
    /// Target triple to pass to LLVM.
    pub llvm_target: String,
    /// String to use as the `target_endian` `cfg` variable.
    pub target_endian: String,
    /// String to use as the `target_word_size` `cfg` variable.
    pub target_word_size: String,
    /// OS name to use for conditional compilation.
    pub target_os: String,
    /// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm", and
    /// "mips". "mips" includes "mipsel".
    pub arch: String,
    /// Optional settings with defaults.
    pub options: TargetOptions,
}

/// Optional aspects of a target specification.
///
/// This has an implementation of `Default`, see each field for what the default is. In general,
/// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
#[deriving(Clone, Show)]
pub struct TargetOptions {
    /// Linker to invoke. Defaults to "cc".
    pub linker: String,
    /// Linker arguments that are unconditionally passed *before* any user-defined libraries.
    pub pre_link_args: Vec<String>,
    /// Linker arguments that are unconditionally passed *after* any user-defined libraries.
    pub post_link_args: Vec<String>,
    /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults to "default".
    pub cpu: String,
    /// Default target features to pass to LLVM. These features will *always* be passed, and cannot
    /// be disabled even via `-C`. Corresponds to `llc -mattr=$features`.
    pub features: String,
    /// Whether dynamic linking is available on this target. Defaults to false.
    pub dynamic_linking: bool,
    /// Whether executables are available on this target. iOS, for example, only allows static
    /// libraries. Defaults to false.
    pub executables: bool,
    /// Whether LLVM's segmented stack prelude is supported by whatever runtime is available.
    /// Will emit stack checks and calls to __morestack. Defaults to false.
    pub morestack: bool,
    /// Relocation model to use in object file. Corresponds to `llc
    /// -relocation-model=$relocation_model`. Defaults to "pic".
    pub relocation_model: String,
    /// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default".
    pub code_model: String,
    /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
    pub disable_redzone: bool,
    /// Eliminate frame pointers from stack frames if possible. Defaults to true.
    pub eliminate_frame_pointer: bool,
    /// Emit each function in its own section. Defaults to true.
    pub function_sections: bool,
    /// String to prepend to the name of every dynamic library. Defaults to "lib".
    pub dll_prefix: String,
    /// String to append to the name of every dynamic library. Defaults to ".so".
    pub dll_suffix: String,
    /// String to append to the name of every executable.
    pub exe_suffix: String,
    /// String to prepend to the name of every static library. Defaults to "lib".
    pub staticlib_prefix: String,
    /// String to append to the name of every static library. Defaults to ".a".
    pub staticlib_suffix: String,
    /// Whether the target toolchain is like OSX's. Only useful for compiling against iOS/OS X, in
    /// particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
    pub is_like_osx: bool,
    /// Whether the target toolchain is like Windows'. Only useful for compiling against Windows,
    /// only realy used for figuring out how to find libraries, since Windows uses its own
    /// library naming convention. Defaults to false.
    pub is_like_windows: bool,
    /// Whether the linker support GNU-like arguments such as -O. Defaults to false.
    pub linker_is_gnu: bool,
    /// Whether the linker support rpaths or not. Defaults to false.
    pub has_rpath: bool,
    /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM will emit references
    /// to the functions that compiler-rt provides.
    pub no_compiler_rt: bool,
    /// Dynamically linked executables can be compiled as position independent if the default
    /// relocation model of position independent code is not changed. This is a requirement to take
    /// advantage of ASLR, as otherwise the functions in the executable are not randomized and can
    /// be used during an exploit of a vulnerability in any code.
    pub position_independant_executables: bool,
}

impl Default for TargetOptions {
    /// Create a set of "sane defaults" for any target. This is still incomplete, and if used for
    /// compilation, will certainly not work.
    fn default() -> TargetOptions {
        TargetOptions {
            linker: "cc".to_string(),
            pre_link_args: Vec::new(),
            post_link_args: Vec::new(),
            cpu: "generic".to_string(),
            features: "".to_string(),
            dynamic_linking: false,
            executables: false,
            morestack: false,
            relocation_model: "pic".to_string(),
            code_model: "default".to_string(),
            disable_redzone: false,
            eliminate_frame_pointer: true,
            function_sections: true,
            dll_prefix: "lib".to_string(),
            dll_suffix: ".so".to_string(),
            exe_suffix: "".to_string(),
            staticlib_prefix: "lib".to_string(),
            staticlib_suffix: ".a".to_string(),
            is_like_osx: false,
            is_like_windows: false,
            linker_is_gnu: false,
            has_rpath: false,
            no_compiler_rt: false,
            position_independant_executables: false,
        }
    }
}

impl Target {
    /// Given a function ABI, turn "System" into the correct ABI for this target.
    pub fn adjust_abi(&self, abi: abi::Abi) -> abi::Abi {
        match abi {
            abi::System => {
                if self.options.is_like_windows && self.arch.as_slice() == "x86" {
                    abi::Stdcall
                } else {
                    abi::C
                }
            },
            abi => abi
        }
    }

    /// Load a target descriptor from a JSON object.
    pub fn from_json(obj: Json) -> Target {
        // this is 1. ugly, 2. error prone.

        let handler = diagnostic::default_handler(diagnostic::Auto, None);

        let get_req_field = |name: &str| {
            match obj.find(&name.to_string())
                     .map(|s| s.as_string())
                     .and_then(|os| os.map(|s| s.to_string())) {
                Some(val) => val,
                None =>
                    handler.fatal((format!("Field {} in target specification is required", name))
                                  .as_slice())
            }
        };

        let mut base = Target {
            data_layout: get_req_field("data-layout"),
            llvm_target: get_req_field("llvm-target"),
            target_endian: get_req_field("target-endian"),
            target_word_size: get_req_field("target-word-size"),
            arch: get_req_field("arch"),
            target_os: get_req_field("os"),
            options: Default::default(),
        };

        macro_rules! key (
            ($key_name:ident) => ( {
                let name = (stringify!($key_name)).replace("_", "-");
                obj.find(&name).map(|o| o.as_string()
                                    .map(|s| base.options.$key_name = s.to_string()));
            } );
            ($key_name:ident, bool) => ( {
                let name = (stringify!($key_name)).replace("_", "-");
                obj.find(&name).map(|o| o.as_boolean().map(|s| base.options.$key_name = s));
            } );
            ($key_name:ident, list) => ( {
                let name = (stringify!($key_name)).replace("_", "-");
                obj.find(&name).map(|o| o.as_list()
                    .map(|v| base.options.$key_name = v.iter()
                        .map(|a| a.as_string().unwrap().to_string()).collect()
                        )
                    );
            } );
        )

        key!(cpu);
        key!(linker);
        key!(relocation_model);
        key!(code_model);
        key!(dll_prefix);
        key!(dll_suffix);
        key!(exe_suffix);
        key!(staticlib_prefix);
        key!(staticlib_suffix);
        key!(features);
        key!(dynamic_linking, bool);
        key!(executables, bool);
        key!(morestack, bool);
        key!(disable_redzone, bool);
        key!(eliminate_frame_pointer, bool);
        key!(function_sections, bool);
        key!(is_like_osx, bool);
        key!(is_like_windows, bool);
        key!(linker_is_gnu, bool);
        key!(has_rpath, bool);
        key!(no_compiler_rt, bool);
        key!(pre_link_args, list);
        key!(post_link_args, list);

        base
    }

    /// Search RUST_TARGET_PATH for a JSON file specifying the given target triple. Note that it
    /// could also just be a bare filename already, so also check for that. If one of the hardcoded
    /// targets we know about, just return it directly.
    ///
    /// The error string could come from any of the APIs called, including filesystem access and
    /// JSON decoding.
    pub fn search(target: &str) -> Result<Target, String> {
        use std::os;
        use std::io::File;
        use std::path::Path;
        use serialize::json;

        fn load_file(path: &Path) -> Result<Target, String> {
            let mut f = try!(File::open(path).map_err(|e| e.to_string()));
            let obj = try!(json::from_reader(&mut f).map_err(|e| e.to_string()));
            Ok(Target::from_json(obj))
        }

        // this would use a match if stringify! were allowed in pattern position
        macro_rules! load_specific (
            ( $($name:ident),+ ) => (
                {
                    let target = target.replace("-", "_");
                    let target = target.as_slice();
                    if false { }
                    $(
                        else if target == stringify!($name) {
                            let t = $name::target();
                            debug!("Got builtin target: {}", t);
                            return Ok(t);
                        }
                    )*
                    else if target == "x86_64-w64-mingw32" {
                        let t = x86_64_pc_windows_gnu::target();
                        return Ok(t);
                    } else if target == "i686-w64-mingw32" {
                        let t = i686_pc_windows_gnu::target();
                        return Ok(t);
                    }
                }
            )
        )

        load_specific!(
            x86_64_unknown_linux_gnu,
            i686_unknown_linux_gnu,
            mips_unknown_linux_gnu,
            mipsel_unknown_linux_gnu,
            arm_linux_androideabi,
            arm_unknown_linux_gnueabi,
            arm_unknown_linux_gnueabihf,

            x86_64_unknown_freebsd,

            x86_64_unknown_dragonfly,

            x86_64_apple_darwin,
            i686_apple_darwin,
            i386_apple_ios,
            arm_apple_ios,

            x86_64_pc_windows_gnu,
            i686_pc_windows_gnu
        )

        let path = Path::new(target);

        if path.is_file() {
            return load_file(&path);
        }

        let path = {
            let mut target = target.to_string();
            target.push_str(".json");
            Path::new(target)
        };

        let target_path = os::getenv("RUST_TARGET_PATH").unwrap_or(String::new());

        let paths = os::split_paths(target_path.as_slice());
        // FIXME 16351: add a sane default search path?

        for dir in paths.iter() {
            let p =  dir.join(path.clone());
            if p.is_file() {
                return load_file(&p);
            }
        }

        Err(format!("Could not find specification for target {}", target))
    }
}
<commit_msg>Update for collections reform<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! [Flexible target specification.](https://github.com/rust-lang/rfcs/pull/131)
//!
//! Rust targets a wide variety of usecases, and in the interest of flexibility,
//! allows new target triples to be defined in configuration files. Most users
//! will not need to care about these, but this is invaluable when porting Rust
//! to a new platform, and allows for an unprecedented level of control over how
//! the compiler works.
//!
//! # Using custom targets
//!
//! A target triple, as passed via `rustc --target=TRIPLE`, will first be
//! compared against the list of built-in targets. This is to ease distributing
//! rustc (no need for configuration files) and also to hold these built-in
//! targets as immutable and sacred. If `TRIPLE` is not one of the built-in
//! targets, rustc will check if a file named `TRIPLE` exists. If it does, it
//! will be loaded as the target configuration. If the file does not exist,
//! rustc will search each directory in the environment variable
//! `RUST_TARGET_PATH` for a file named `TRIPLE.json`. The first one found will
//! be loaded. If no file is found in any of those directories, a fatal error
//! will be given.  `RUST_TARGET_PATH` includes `/etc/rustc` as its last entry,
//! to be searched by default.
//!
//! Projects defining their own targets should use
//! `--target=path/to/my-awesome-platform.json` instead of adding to
//! `RUST_TARGET_PATH`.
//!
//! # Defining a new target
//!
//! Targets are defined using [JSON](http://json.org/). The `Target` struct in
//! this module defines the format the JSON file should take, though each
//! underscore in the field names should be replaced with a hyphen (`-`) in the
//! JSON file. Some fields are required in every target specification, such as
//! `data-layout`, `llvm-target`, `target-endian`, `target-word-size`, and
//! `arch`. In general, options passed to rustc with `-C` override the target's
//! settings, though `target-feature` and `link-args` will *add* to the list
//! specified by the target, rather than replace.

use serialize::json::Json;
use syntax::{diagnostic, abi};
use std::default::Default;
use std::io::fs::PathExtensions;

mod windows_base;
mod linux_base;
mod apple_base;
mod freebsd_base;
mod dragonfly_base;

mod arm_apple_ios;
mod arm_linux_androideabi;
mod arm_unknown_linux_gnueabi;
mod arm_unknown_linux_gnueabihf;
mod i686_apple_darwin;
mod i386_apple_ios;
mod i686_pc_windows_gnu;
mod i686_unknown_linux_gnu;
mod mips_unknown_linux_gnu;
mod mipsel_unknown_linux_gnu;
mod x86_64_apple_darwin;
mod x86_64_pc_windows_gnu;
mod x86_64_unknown_freebsd;
mod x86_64_unknown_dragonfly;
mod x86_64_unknown_linux_gnu;

/// Everything `rustc` knows about how to compile for a specific target.
///
/// Every field here must be specified, and has no default value.
#[deriving(Clone, Show)]
pub struct Target {
    /// [Data layout](http://llvm.org/docs/LangRef.html#data-layout) to pass to LLVM.
    pub data_layout: String,
    /// Target triple to pass to LLVM.
    pub llvm_target: String,
    /// String to use as the `target_endian` `cfg` variable.
    pub target_endian: String,
    /// String to use as the `target_word_size` `cfg` variable.
    pub target_word_size: String,
    /// OS name to use for conditional compilation.
    pub target_os: String,
    /// Architecture to use for ABI considerations. Valid options: "x86", "x86_64", "arm", and
    /// "mips". "mips" includes "mipsel".
    pub arch: String,
    /// Optional settings with defaults.
    pub options: TargetOptions,
}

/// Optional aspects of a target specification.
///
/// This has an implementation of `Default`, see each field for what the default is. In general,
/// these try to take "minimal defaults" that don't assume anything about the runtime they run in.
#[deriving(Clone, Show)]
pub struct TargetOptions {
    /// Linker to invoke. Defaults to "cc".
    pub linker: String,
    /// Linker arguments that are unconditionally passed *before* any user-defined libraries.
    pub pre_link_args: Vec<String>,
    /// Linker arguments that are unconditionally passed *after* any user-defined libraries.
    pub post_link_args: Vec<String>,
    /// Default CPU to pass to LLVM. Corresponds to `llc -mcpu=$cpu`. Defaults to "default".
    pub cpu: String,
    /// Default target features to pass to LLVM. These features will *always* be passed, and cannot
    /// be disabled even via `-C`. Corresponds to `llc -mattr=$features`.
    pub features: String,
    /// Whether dynamic linking is available on this target. Defaults to false.
    pub dynamic_linking: bool,
    /// Whether executables are available on this target. iOS, for example, only allows static
    /// libraries. Defaults to false.
    pub executables: bool,
    /// Whether LLVM's segmented stack prelude is supported by whatever runtime is available.
    /// Will emit stack checks and calls to __morestack. Defaults to false.
    pub morestack: bool,
    /// Relocation model to use in object file. Corresponds to `llc
    /// -relocation-model=$relocation_model`. Defaults to "pic".
    pub relocation_model: String,
    /// Code model to use. Corresponds to `llc -code-model=$code_model`. Defaults to "default".
    pub code_model: String,
    /// Do not emit code that uses the "red zone", if the ABI has one. Defaults to false.
    pub disable_redzone: bool,
    /// Eliminate frame pointers from stack frames if possible. Defaults to true.
    pub eliminate_frame_pointer: bool,
    /// Emit each function in its own section. Defaults to true.
    pub function_sections: bool,
    /// String to prepend to the name of every dynamic library. Defaults to "lib".
    pub dll_prefix: String,
    /// String to append to the name of every dynamic library. Defaults to ".so".
    pub dll_suffix: String,
    /// String to append to the name of every executable.
    pub exe_suffix: String,
    /// String to prepend to the name of every static library. Defaults to "lib".
    pub staticlib_prefix: String,
    /// String to append to the name of every static library. Defaults to ".a".
    pub staticlib_suffix: String,
    /// Whether the target toolchain is like OSX's. Only useful for compiling against iOS/OS X, in
    /// particular running dsymutil and some other stuff like `-dead_strip`. Defaults to false.
    pub is_like_osx: bool,
    /// Whether the target toolchain is like Windows'. Only useful for compiling against Windows,
    /// only realy used for figuring out how to find libraries, since Windows uses its own
    /// library naming convention. Defaults to false.
    pub is_like_windows: bool,
    /// Whether the linker support GNU-like arguments such as -O. Defaults to false.
    pub linker_is_gnu: bool,
    /// Whether the linker support rpaths or not. Defaults to false.
    pub has_rpath: bool,
    /// Whether to disable linking to compiler-rt. Defaults to false, as LLVM will emit references
    /// to the functions that compiler-rt provides.
    pub no_compiler_rt: bool,
    /// Dynamically linked executables can be compiled as position independent if the default
    /// relocation model of position independent code is not changed. This is a requirement to take
    /// advantage of ASLR, as otherwise the functions in the executable are not randomized and can
    /// be used during an exploit of a vulnerability in any code.
    pub position_independant_executables: bool,
}

impl Default for TargetOptions {
    /// Create a set of "sane defaults" for any target. This is still incomplete, and if used for
    /// compilation, will certainly not work.
    fn default() -> TargetOptions {
        TargetOptions {
            linker: "cc".to_string(),
            pre_link_args: Vec::new(),
            post_link_args: Vec::new(),
            cpu: "generic".to_string(),
            features: "".to_string(),
            dynamic_linking: false,
            executables: false,
            morestack: false,
            relocation_model: "pic".to_string(),
            code_model: "default".to_string(),
            disable_redzone: false,
            eliminate_frame_pointer: true,
            function_sections: true,
            dll_prefix: "lib".to_string(),
            dll_suffix: ".so".to_string(),
            exe_suffix: "".to_string(),
            staticlib_prefix: "lib".to_string(),
            staticlib_suffix: ".a".to_string(),
            is_like_osx: false,
            is_like_windows: false,
            linker_is_gnu: false,
            has_rpath: false,
            no_compiler_rt: false,
            position_independant_executables: false,
        }
    }
}

impl Target {
    /// Given a function ABI, turn "System" into the correct ABI for this target.
    pub fn adjust_abi(&self, abi: abi::Abi) -> abi::Abi {
        match abi {
            abi::System => {
                if self.options.is_like_windows && self.arch.as_slice() == "x86" {
                    abi::Stdcall
                } else {
                    abi::C
                }
            },
            abi => abi
        }
    }

    /// Load a target descriptor from a JSON object.
    pub fn from_json(obj: Json) -> Target {
        // this is 1. ugly, 2. error prone.

        let handler = diagnostic::default_handler(diagnostic::Auto, None);

        let get_req_field = |name: &str| {
            match obj.find(name)
                     .map(|s| s.as_string())
                     .and_then(|os| os.map(|s| s.to_string())) {
                Some(val) => val,
                None =>
                    handler.fatal((format!("Field {} in target specification is required", name))
                                  .as_slice())
            }
        };

        let mut base = Target {
            data_layout: get_req_field("data-layout"),
            llvm_target: get_req_field("llvm-target"),
            target_endian: get_req_field("target-endian"),
            target_word_size: get_req_field("target-word-size"),
            arch: get_req_field("arch"),
            target_os: get_req_field("os"),
            options: Default::default(),
        };

        macro_rules! key (
            ($key_name:ident) => ( {
                let name = (stringify!($key_name)).replace("_", "-");
                obj.find(name[]).map(|o| o.as_string()
                                    .map(|s| base.options.$key_name = s.to_string()));
            } );
            ($key_name:ident, bool) => ( {
                let name = (stringify!($key_name)).replace("_", "-");
                obj.find(name[]).map(|o| o.as_boolean().map(|s| base.options.$key_name = s));
            } );
            ($key_name:ident, list) => ( {
                let name = (stringify!($key_name)).replace("_", "-");
                obj.find(name[]).map(|o| o.as_list()
                    .map(|v| base.options.$key_name = v.iter()
                        .map(|a| a.as_string().unwrap().to_string()).collect()
                        )
                    );
            } );
        )

        key!(cpu);
        key!(linker);
        key!(relocation_model);
        key!(code_model);
        key!(dll_prefix);
        key!(dll_suffix);
        key!(exe_suffix);
        key!(staticlib_prefix);
        key!(staticlib_suffix);
        key!(features);
        key!(dynamic_linking, bool);
        key!(executables, bool);
        key!(morestack, bool);
        key!(disable_redzone, bool);
        key!(eliminate_frame_pointer, bool);
        key!(function_sections, bool);
        key!(is_like_osx, bool);
        key!(is_like_windows, bool);
        key!(linker_is_gnu, bool);
        key!(has_rpath, bool);
        key!(no_compiler_rt, bool);
        key!(pre_link_args, list);
        key!(post_link_args, list);

        base
    }

    /// Search RUST_TARGET_PATH for a JSON file specifying the given target triple. Note that it
    /// could also just be a bare filename already, so also check for that. If one of the hardcoded
    /// targets we know about, just return it directly.
    ///
    /// The error string could come from any of the APIs called, including filesystem access and
    /// JSON decoding.
    pub fn search(target: &str) -> Result<Target, String> {
        use std::os;
        use std::io::File;
        use std::path::Path;
        use serialize::json;

        fn load_file(path: &Path) -> Result<Target, String> {
            let mut f = try!(File::open(path).map_err(|e| e.to_string()));
            let obj = try!(json::from_reader(&mut f).map_err(|e| e.to_string()));
            Ok(Target::from_json(obj))
        }

        // this would use a match if stringify! were allowed in pattern position
        macro_rules! load_specific (
            ( $($name:ident),+ ) => (
                {
                    let target = target.replace("-", "_");
                    let target = target.as_slice();
                    if false { }
                    $(
                        else if target == stringify!($name) {
                            let t = $name::target();
                            debug!("Got builtin target: {}", t);
                            return Ok(t);
                        }
                    )*
                    else if target == "x86_64-w64-mingw32" {
                        let t = x86_64_pc_windows_gnu::target();
                        return Ok(t);
                    } else if target == "i686-w64-mingw32" {
                        let t = i686_pc_windows_gnu::target();
                        return Ok(t);
                    }
                }
            )
        )

        load_specific!(
            x86_64_unknown_linux_gnu,
            i686_unknown_linux_gnu,
            mips_unknown_linux_gnu,
            mipsel_unknown_linux_gnu,
            arm_linux_androideabi,
            arm_unknown_linux_gnueabi,
            arm_unknown_linux_gnueabihf,

            x86_64_unknown_freebsd,

            x86_64_unknown_dragonfly,

            x86_64_apple_darwin,
            i686_apple_darwin,
            i386_apple_ios,
            arm_apple_ios,

            x86_64_pc_windows_gnu,
            i686_pc_windows_gnu
        )

        let path = Path::new(target);

        if path.is_file() {
            return load_file(&path);
        }

        let path = {
            let mut target = target.to_string();
            target.push_str(".json");
            Path::new(target)
        };

        let target_path = os::getenv("RUST_TARGET_PATH").unwrap_or(String::new());

        let paths = os::split_paths(target_path.as_slice());
        // FIXME 16351: add a sane default search path?

        for dir in paths.iter() {
            let p =  dir.join(path.clone());
            if p.is_file() {
                return load_file(&p);
            }
        }

        Err(format!("Could not find specification for target {}", target))
    }
}
<|endoftext|>


<commit_before>use std::num::Wrapping;
use std::cmp::max;
use libc::c_ulong;
use std::ffi::CString;
use std::ptr::{
  null,
  null_mut,
};

use x11::xlib;
use config;
use config::KeyCmd;

pub struct WindowSystem {
    display:    *mut xlib::Display,
    root:       xlib::Window,
    x:          i32,
    y:          i32,
    w:          u32,
    h:          u32,
    button_id:  u32,
}

impl WindowSystem {
    pub fn new() -> WindowSystem {
        unsafe {
            // Open display
            let display = xlib::XOpenDisplay(null());
            if display == null_mut() {
                panic!("Exiting: Cannot find display");
            }

            // Create window
            let screen = xlib::XDefaultScreenOfDisplay(display);
            let root = xlib::XRootWindowOfScreen(screen);

            WindowSystem {
                display: display,
                root: root,
                x: 0,
                y: 0,
                w: 0,
                h: 0,
                button_id: 0,
            }
        }
    }

    pub fn on_init( &mut self ) {
        use x11::xlib::*;
        let mut wa = XSetWindowAttributes {
            background_pixmap: 0,
            background_pixel: 0,
            border_pixmap: 0,
            border_pixel: 0,
            bit_gravity: 0,
            win_gravity: 0,
            backing_store: 0,
            backing_planes: 0,
            backing_pixel: 0,
            save_under: 0,
            do_not_propagate_mask: 0,
            override_redirect: 0,
            colormap: 0,
            cursor: 0,
            event_mask:
                        SubstructureRedirectMask|
                        SubstructureNotifyMask|
                        StructureNotifyMask|
                        ButtonPressMask|
                        ButtonReleaseMask|
                        PropertyChangeMask,
        };

        unsafe {

            // Grab keys
            // Exit key behavior
            let kc_exit = xlib::XKeysymToKeycode( self.display, KeyCmd::get_keysym( config::EXIT_KEY ) );
            xlib::XGrabKey( self.display, kc_exit as i32, KeyCmd::get_modifier( config::EXIT_KEY ),
                self.root as c_ulong, 1, xlib::GrabModeAsync, xlib::GrabModeAsync );

            // Grab mouse
            xlib::XGrabButton( self.display, config::MOUSE_MOVE.button, config::MOUSE_MOVE.modifier,
                self.root, 1, xlib::ButtonPressMask as u32, xlib::GrabModeAsync, xlib::GrabModeAsync, 0, 0 );
            xlib::XGrabButton( self.display, config::MOUSE_RESIZE.button, config::MOUSE_RESIZE.modifier,
                self.root, 1, xlib::ButtonPressMask as u32, xlib::GrabModeAsync, xlib::GrabModeAsync, 0, 0 );
            xlib::XGrabButton( self.display, config::MOUSE_RAISE.button, config::MOUSE_RAISE.modifier,
                self.root, 1, xlib::ButtonPressMask as u32, xlib::GrabModeAsync, xlib::GrabModeAsync, 0, 0 );

            // Set up window events
            XChangeWindowAttributes( self.display, self.root, CWEventMask|CWCursor, &mut wa );
            XSelectInput( self.display, self.root, wa.event_mask );
        }
    }

    pub fn on_update( &mut self ) -> bool {
        let mut ev = xlib::XEvent { pad : [0; 24] };
        unsafe {
            xlib::XNextEvent( self.display, &mut ev );
        }
        let event_type = ev.get_type();

        match event_type {
            xlib::MotionNotify => {
                unsafe {
                    while xlib::XCheckTypedEvent( self.display, xlib::MotionNotify, &mut ev ) == 1 {};
                }

                let event = xlib::XMotionEvent::from(ev);
                unsafe {
                    self.on_motion( &event );
                }
            },

            xlib::ButtonPress => {
                let event = xlib::XButtonEvent::from(ev);
                println!("Button Pressed: {}", event.button);
                unsafe {
                    self.on_button_press( &event );
                }
            },

            xlib::ButtonRelease => {
                let event = xlib::XButtonEvent::from(ev);
                unsafe {
                    self.on_button_release( &event );
                }
            },

            xlib::ClientMessage => {
                let event = xlib::XClientMessageEvent::from(ev);
                unsafe {
                    self.on_client_message( &event );
                }
            },

            xlib::DestroyNotify => {
                println!("Got destroy notify");
            },

            xlib::MapRequest => {
                let mut event = xlib::XMapRequestEvent::from(ev);
                unsafe {
                    self.on_map_request( &mut event );
                }
            },

//            xlib::CreateNotify => {
//                println!("Got create notify");
//            }

            xlib::KeyPress => {
                unsafe {
                    let event = xlib::XKeyEvent::from(ev);
                    if self.on_keypress( &event ) {
                        return true;
                    }
                }
            },

            _ => {},
        }
        false
    }

    pub fn flush(&self) {
        unsafe {
            xlib::XFlush(self.display);
        }
    }

    unsafe fn on_client_message( &mut self, event: &xlib::XClientMessageEvent ) {
        println!("Client message: {}", event.window);
//        let data: [i32; 5] = [
//            event.data.get_long(0) as i32,
//            event.data.get_long(1) as i32,
//            event.data.get_long(2) as i32,
//            event.data.get_long(3) as i32,
//            event.data.get_long(4) as i32, ];
    }

    unsafe fn on_map_request( &mut self, event: &mut xlib::XMapRequestEvent ) {
        let screen = xlib::XDefaultScreenOfDisplay( self.display );
        let visual = xlib::XDefaultVisual( self.display, xlib::XDefaultScreen( self.display) );
        let mut wa = xlib::XWindowAttributes {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            border_width: 0,
            depth: 0,
            visual: visual,
            root: 0,
            class: 0,
            bit_gravity: 0,
            win_gravity: 0,
            backing_store: 0,
            backing_planes: 0,
            backing_pixel: 0,
            save_under: 0,
            colormap: 0,
            map_installed: 0,
            map_state: 0,
            all_event_masks: 0,
            your_event_mask: 0,
            do_not_propagate_mask: 0,
            override_redirect: 0,
            screen: screen,
        };

        if xlib::XGetWindowAttributes( self.display, event.window, &mut wa ) == 0 {
            return;
        }

        if wa.override_redirect == 1 {
            return;
        }

        let mut wc = xlib::XWindowChanges {
            x: wa.x,
            y: wa.y,
            width: wa.width,
            height: wa.height,
            border_width: 10,
            sibling: 0,
            stack_mode: 0,
        };

        xlib::XConfigureWindow( self.display, event.window, xlib::CWBorderWidth as u32, &mut wc );
        xlib::XSetWindowBorder( self.display, event.window, wc.border_width as u64 );
        xlib::XMoveResizeWindow( self.display, event.window, wc.x, wc.y, wc.width as u32, wc.height as u32 );
        xlib::XSelectInput( self.display, event.window,
                    xlib::EnterWindowMask|
                    xlib::FocusChangeMask|
                    xlib::PropertyChangeMask|
                    xlib::StructureNotifyMask );
        xlib::XMapWindow( self.display, event.window );
    }

    unsafe fn on_keypress( &mut self, event: &xlib::XKeyEvent ) -> bool {
        use config::*;
        let key = xlib::XKeysymToString(
            xlib::XKeycodeToKeysym( self.display, event.keycode as u8, 0 ) );
        let key = CString::from_raw(key);

        let key_info = KeyCmd::new( key.to_str().unwrap(), event.state );

        // Handle key events
        match key_info {
            EXIT_KEY => {
                println!( "Exiting!" );
                return true;
            },

            _ => {},
        }

        false
    }

    unsafe fn on_resize_move( &mut self, event: &xlib::XButtonEvent ) {
        if event.button == 1 {
            self.x = event.x_root;
            self.y = event.y_root;
        }
        if event.button == 3 {
            self.w = event.x_root as u32;
            self.h = event.y_root as u32;
        }

        self.button_id = event.button;
        println!("Pointer grabbed");
        xlib::XGrabPointer( self.display, event.subwindow, 1,
            (xlib::PointerMotionMask|xlib::ButtonReleaseMask) as u32,
            xlib::GrabModeAsync, xlib::GrabModeAsync,
            0, 0, event.time);
    }

    unsafe fn on_button_press( &mut self, event: &xlib::XButtonEvent ) {
        let button_info = config::MouseCmd::new( event.button, event.state );

        match button_info {
            config::MOUSE_RESIZE => {
                if event.subwindow != 0 {
                    println!("Resize");
                    xlib::XRaiseWindow( self.display, event.subwindow );
                    self.on_resize_move( &event );
                }
            },

            config::MOUSE_MOVE => {
                if event.subwindow != 0 {
                    println!("Move");
                    xlib::XRaiseWindow( self.display, event.subwindow );
                    self.on_resize_move( &event );
                }
            },

            config::MOUSE_RAISE => {
                if event.subwindow != 0 {
                    xlib::XRaiseWindow( self.display, event.subwindow );
                }
            },

            _ => {},
        }

        println!("End button press function");
    }

    unsafe fn on_button_release( &mut self, event: &xlib::XButtonEvent ) {
        println!("Ungrab pointer");
        xlib::XUngrabPointer( self.display, event.time );
    }

    unsafe fn on_motion( &mut self, event: &xlib::XMotionEvent ) {
        if self.button_id == 1 {
            self.on_move( &event );
        }
        if self.button_id == 3 {
            self.on_resize( &event );
        }

        self.flush();
    }

    unsafe fn on_resize( &mut self, event: &xlib::XMotionEvent ) {
        let mut wa = self.get_empty_wa();
        if xlib::XGetWindowAttributes( self.display, event.window, &mut wa ) == 0 {
            return;
        }

        let xdiff = Wrapping::<u32>( event.x_root as u32 ) - Wrapping::<u32>( self.w );
        let ydiff = Wrapping::<u32>( event.y_root as u32 ) - Wrapping::<u32>( self.h );

        self.w = event.x_root as u32;
        self.h = event.y_root as u32;

        let new_w = Wrapping::<u32>(wa.width as u32) + xdiff;
        let new_h = Wrapping::<u32>(wa.height as u32) + ydiff;

        let new_w = max(1, new_w.0);
        let new_h = max(1, new_h.0);

        println!("Coord Diffs: {}, {}", xdiff.0, ydiff.0);
        println!("Coords: {}, {}", new_w, new_h );
        xlib::XResizeWindow( self.display, event.window, new_w, new_h );
    }

    unsafe fn on_move( &mut self, event: &xlib::XMotionEvent ) {
        let mut wa = self.get_empty_wa();
        if xlib::XGetWindowAttributes( self.display, event.window, &mut wa ) == 0 {
            return;
        }

        let xdiff = event.x_root - self.x;
        let ydiff = event.y_root - self.y;

        self.x = event.x_root;
        self.y = event.y_root;

        let new_x = wa.x + xdiff;
        let new_y = wa.y + ydiff;

        println!("Coords: {}, {}", new_x, new_y );
        xlib::XMoveWindow( self.display, event.window, new_x, new_y );
    }

    unsafe fn get_empty_wa ( &self ) -> xlib::XWindowAttributes {
        let screen = xlib::XDefaultScreenOfDisplay( self.display );
        let visual = xlib::XDefaultVisual( self.display, xlib::XDefaultScreen( self.display ) );
        xlib::XWindowAttributes {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            border_width: 0,
            depth: 0,
            visual: visual,
            root: 0,
            class: 0,
            bit_gravity: 0,
            win_gravity: 0,
            backing_store: 0,
            backing_planes: 0,
            backing_pixel: 0,
            save_under: 0,
            colormap: 0,
            map_installed: 0,
            map_state: 0,
            all_event_masks: 0,
            your_event_mask: 0,
            do_not_propagate_mask: 0,
            override_redirect: 0,
            screen: screen,
        }
    }
}
<commit_msg>Cleaned up old code and refactored some unsafe blocks<commit_after>use std::num::Wrapping;
use std::cmp::max;
use libc::c_ulong;
use std::ffi::CString;
use std::ptr::{
  null,
  null_mut,
};

use x11::xlib;
use config;
use config::KeyCmd;

pub struct WindowSystem {
    display:    *mut xlib::Display,
    root:       xlib::Window,
    x:          i32,
    y:          i32,
    w:          u32,
    h:          u32,
    button_id:  u32,
}

impl WindowSystem {
    pub fn new() -> WindowSystem {
        unsafe {
            // Open display
            let display = xlib::XOpenDisplay(null());
            if display == null_mut() {
                panic!("Exiting: Cannot find display");
            }

            // Create window
            let screen = xlib::XDefaultScreenOfDisplay(display);
            let root = xlib::XRootWindowOfScreen(screen);

            WindowSystem {
                display: display,
                root: root,
                x: 0,
                y: 0,
                w: 0,
                h: 0,
                button_id: 0,
            }
        }
    }

    pub fn on_init( &mut self ) {
        use x11::xlib::*;
        let mut wa = XSetWindowAttributes {
            background_pixmap: 0,
            background_pixel: 0,
            border_pixmap: 0,
            border_pixel: 0,
            bit_gravity: 0,
            win_gravity: 0,
            backing_store: 0,
            backing_planes: 0,
            backing_pixel: 0,
            save_under: 0,
            do_not_propagate_mask: 0,
            override_redirect: 0,
            colormap: 0,
            cursor: 0,
            event_mask:
                        SubstructureRedirectMask|
                        SubstructureNotifyMask|
                        StructureNotifyMask|
                        ButtonPressMask|
                        ButtonReleaseMask|
                        PropertyChangeMask,
        };

        unsafe {

            // Grab keys
            // Exit key behavior
            let kc_exit = xlib::XKeysymToKeycode( self.display, KeyCmd::get_keysym( config::EXIT_KEY ) );
            xlib::XGrabKey( self.display, kc_exit as i32, KeyCmd::get_modifier( config::EXIT_KEY ),
                self.root as c_ulong, 1, xlib::GrabModeAsync, xlib::GrabModeAsync );

            // Grab mouse
            xlib::XGrabButton( self.display, config::MOUSE_MOVE.button, config::MOUSE_MOVE.modifier,
                self.root, 1, xlib::ButtonPressMask as u32, xlib::GrabModeAsync, xlib::GrabModeAsync, 0, 0 );
            xlib::XGrabButton( self.display, config::MOUSE_RESIZE.button, config::MOUSE_RESIZE.modifier,
                self.root, 1, xlib::ButtonPressMask as u32, xlib::GrabModeAsync, xlib::GrabModeAsync, 0, 0 );
            xlib::XGrabButton( self.display, config::MOUSE_RAISE.button, config::MOUSE_RAISE.modifier,
                self.root, 1, xlib::ButtonPressMask as u32, xlib::GrabModeAsync, xlib::GrabModeAsync, 0, 0 );

            // Set up window events
            XChangeWindowAttributes( self.display, self.root, CWEventMask|CWCursor, &mut wa );
            XSelectInput( self.display, self.root, wa.event_mask );
        }
    }

    pub fn on_update( &mut self ) -> bool {
        let mut ev = xlib::XEvent { pad : [0; 24] };
        unsafe {
            xlib::XNextEvent( self.display, &mut ev );
        }
        let event_type = ev.get_type();

        match event_type {
            xlib::MotionNotify => {
                unsafe {
                    while xlib::XCheckTypedEvent( self.display, xlib::MotionNotify, &mut ev ) == 1 {};
                }

                let event = xlib::XMotionEvent::from(ev);
                self.on_motion( &event );
            },

            xlib::ButtonPress => {
                let event = xlib::XButtonEvent::from(ev);
                println!("Button Pressed: {}", event.button);
                self.on_button_press( &event );
            },

            xlib::ButtonRelease => {
                let event = xlib::XButtonEvent::from(ev);
                self.on_button_release( &event );
            },

            xlib::ClientMessage => {
                let event = xlib::XClientMessageEvent::from(ev);
                self.on_client_message( &event );
            },

            xlib::DestroyNotify => {
                println!("Got destroy notify");
            },

            xlib::MapRequest => {
                let mut event = xlib::XMapRequestEvent::from(ev);
                self.on_map_request( &mut event );
            },

//            xlib::CreateNotify => {
//                println!("Got create notify");
//            }

            xlib::KeyPress => {
                let event = xlib::XKeyEvent::from(ev);
                if self.on_keypress( &event ) {
                    return true;
                }
            },

            _ => {},
        }
        false
    }

    pub fn flush(&self) {
        unsafe {
            xlib::XFlush(self.display);
        }
    }

    fn on_client_message( &mut self, event: &xlib::XClientMessageEvent ) {
        println!("Client message: {}", event.window);
    }

    fn on_map_request( &mut self, event: &mut xlib::XMapRequestEvent ) {
        unsafe {
            let mut wa = self.get_empty_wa();

            if xlib::XGetWindowAttributes( self.display, event.window, &mut wa ) == 0 {
                return;
            }

            if wa.override_redirect == 1 {
                return;
            }

            let mut wc = xlib::XWindowChanges {
                x: wa.x,
                y: wa.y,
                width: wa.width,
                height: wa.height,
                border_width: 10,
                sibling: 0,
                stack_mode: 0,
            };

            xlib::XConfigureWindow( self.display, event.window, xlib::CWBorderWidth as u32, &mut wc );
            xlib::XSetWindowBorder( self.display, event.window, wc.border_width as u64 );
            xlib::XMoveResizeWindow( self.display, event.window, wc.x, wc.y, wc.width as u32, wc.height as u32 );
            xlib::XSelectInput( self.display, event.window,
                        xlib::EnterWindowMask|
                        xlib::FocusChangeMask|
                        xlib::PropertyChangeMask|
                        xlib::StructureNotifyMask );
            xlib::XMapWindow( self.display, event.window );
        }
    }

    fn on_keypress( &mut self, event: &xlib::XKeyEvent ) -> bool {
        use config::*;

        unsafe {
            let key = xlib::XKeysymToString(
                xlib::XKeycodeToKeysym( self.display, event.keycode as u8, 0 ) );
            let key = CString::from_raw(key);

            let key_info = KeyCmd::new( key.to_str().unwrap(), event.state );

            // Handle key events
            match key_info {
                EXIT_KEY => {
                    println!( "Exiting!" );
                    return true;
                },

                _ => {},
            }
        }
        false
    }

    fn on_resize_move( &mut self, event: &xlib::XButtonEvent ) {
        if event.button == 1 {
            self.x = event.x_root;
            self.y = event.y_root;
        }
        if event.button == 3 {
            self.w = event.x_root as u32;
            self.h = event.y_root as u32;
        }

        self.button_id = event.button;
        println!("Pointer grabbed");
        unsafe {
            xlib::XGrabPointer( self.display, event.subwindow, 1,
                (xlib::PointerMotionMask|xlib::ButtonReleaseMask) as u32,
                xlib::GrabModeAsync, xlib::GrabModeAsync,
                0, 0, event.time);
        }
    }

    fn on_button_press( &mut self, event: &xlib::XButtonEvent ) {
        let button_info = config::MouseCmd::new( event.button, event.state );

        match button_info {
            config::MOUSE_RESIZE => {
                if event.subwindow != 0 {
                    println!("Resize");
                    unsafe {
                        xlib::XRaiseWindow( self.display, event.subwindow );
                    }
                    self.on_resize_move( &event );
                }
            },

            config::MOUSE_MOVE => {
                if event.subwindow != 0 {
                    println!("Move");
                    unsafe {
                        xlib::XRaiseWindow( self.display, event.subwindow );
                    }
                    self.on_resize_move( &event );
                }
            },

            config::MOUSE_RAISE => {
                if event.subwindow != 0 {
                    unsafe {
                        xlib::XRaiseWindow( self.display, event.subwindow );
                    }
                }
            },

            _ => {},
        }

        println!("End button press function");
    }

    fn on_button_release( &mut self, event: &xlib::XButtonEvent ) {
        println!("Ungrab pointer");
        unsafe {
            xlib::XUngrabPointer( self.display, event.time );
        }
    }

    fn on_motion( &mut self, event: &xlib::XMotionEvent ) {
        if self.button_id == 1 {
            self.on_move( &event );
        }
        if self.button_id == 3 {
            self.on_resize( &event );
        }

        self.flush();
    }

    fn on_resize( &mut self, event: &xlib::XMotionEvent ) {
        unsafe {
            let mut wa = self.get_empty_wa();
            if xlib::XGetWindowAttributes( self.display, event.window, &mut wa ) == 0 {
                return;
            }

            let xdiff = Wrapping::<u32>( event.x_root as u32 ) - Wrapping::<u32>( self.w );
            let ydiff = Wrapping::<u32>( event.y_root as u32 ) - Wrapping::<u32>( self.h );

            self.w = event.x_root as u32;
            self.h = event.y_root as u32;

            let new_w = Wrapping::<u32>(wa.width as u32) + xdiff;
            let new_h = Wrapping::<u32>(wa.height as u32) + ydiff;

            let new_w = max(1, new_w.0);
            let new_h = max(1, new_h.0);

            println!("Coord Diffs: {}, {}", xdiff.0, ydiff.0);
            println!("Coords: {}, {}", new_w, new_h );
            xlib::XResizeWindow( self.display, event.window, new_w, new_h );
        }
    }

    fn on_move( &mut self, event: &xlib::XMotionEvent ) {
        unsafe {
            let mut wa = self.get_empty_wa();
            if xlib::XGetWindowAttributes( self.display, event.window, &mut wa ) == 0 {
                return;
            }

            let xdiff = event.x_root - self.x;
            let ydiff = event.y_root - self.y;

            self.x = event.x_root;
            self.y = event.y_root;

            let new_x = wa.x + xdiff;
            let new_y = wa.y + ydiff;

            println!("Coords: {}, {}", new_x, new_y );
            xlib::XMoveWindow( self.display, event.window, new_x, new_y );
        }
    }

    unsafe fn get_empty_wa ( &self ) -> xlib::XWindowAttributes {
        let screen = xlib::XDefaultScreenOfDisplay( self.display );
        let visual = xlib::XDefaultVisual( self.display, xlib::XDefaultScreen( self.display ) );
        xlib::XWindowAttributes {
            x: 0,
            y: 0,
            width: 0,
            height: 0,
            border_width: 0,
            depth: 0,
            visual: visual,
            root: 0,
            class: 0,
            bit_gravity: 0,
            win_gravity: 0,
            backing_store: 0,
            backing_planes: 0,
            backing_pixel: 0,
            save_under: 0,
            colormap: 0,
            map_installed: 0,
            map_state: 0,
            all_event_masks: 0,
            your_event_mask: 0,
            do_not_propagate_mask: 0,
            override_redirect: 0,
            screen: screen,
        }
    }
}
<|endoftext|>