<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 primarly 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(_) = T::matches(content, base_offset) {
                        return Err(LayoutMismatchError::LayoutMismatch {
                            expected: (**content).clone(),
                            obtained: T::build_layout(base_offset),
                        });
                    }

                    if length != $len {
                        return Err(LayoutMismatchError::LayoutMismatch {
                            expected: (**content).clone(),
                            obtained: T::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>Better uniform block layout mismatch error reporting<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 primarly 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>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::{ptr, mem, slice};
use std::cell::Cell;
use arena::TypedArena;

const K_BLOCK_SIZE: usize = 4096;

/// Similar to "Arena" in leveldb C++
/// Note that this implements "interior mutability", so caller
/// does not need to hold a unique reference to the struct in order
/// to call its functions.
pub struct MemPool {
  alloc_ptr: Cell<*mut u8>,
  alloc_bytes_remaining: Cell<usize>,
  arena: TypedArena<Vec<u8>>,
  memory_usage: Cell<i64>
}

impl MemPool {
  pub fn new() -> Self {
    Self {
      alloc_ptr: Cell::new(ptr::null_mut()),
      alloc_bytes_remaining: Cell::new(0),
      arena: TypedArena::new(),
      memory_usage: Cell::new(0)
    }
  }

  /// Allocate a byte slice with length `bytes`.
  /// Return a unique reference to the slice allocated.
  pub fn alloc(&self, bytes: usize) -> &mut [u8] {
    assert!(bytes > 0);
    if bytes <= self.alloc_bytes_remaining.get() {
      assert!(!self.alloc_ptr.get().is_null());
      let result = self.alloc_ptr.get();
      unsafe {
        self.alloc_ptr.set(self.alloc_ptr.get().offset(bytes as isize));
        self.alloc_bytes_remaining.set(
          self.alloc_bytes_remaining.get() - bytes);
        return slice::from_raw_parts_mut(result, bytes)
      }
    }
    self.alloc_fallback(bytes)
  }

  /// Allocate a byte slice with length `bytes` that is aligned to pointer
  /// address.
  /// Return a unique reference to the slice allocated.
  pub fn alloc_aligned(&self, bytes: usize) -> &mut [u8] {
    let ptr_size = mem::size_of::<usize>(); // TODO: double-check this
    assert!(ptr_size <= 128);
    let align = if ptr_size > 8 { ptr_size } else { 8 };
    assert!(align & (align - 1) == 0);
    let current_mod = self.alloc_ptr.get() as usize & (align-1);
    let slop = if current_mod == 0 { 0 } else { align - current_mod };
    let needed = bytes + slop;
    let result =
      if needed <= self.alloc_bytes_remaining.get() {
        unsafe {
          let r = self.alloc_ptr.get().offset(slop as isize);
          self.alloc_ptr.set(self.alloc_ptr.get().offset(needed as isize));
          self.alloc_bytes_remaining.set(
            self.alloc_bytes_remaining.get() - needed);
          r
        }
      } else {
        self.alloc_fallback(bytes).as_mut_ptr()
      };
    assert!(result as usize & (align-1) == 0);
    unsafe {
      slice::from_raw_parts_mut(result, bytes)
    }
  }

  /// Return the memory usage for the memory pool, in number of bytes allocated.
  pub fn memory_usage(&self) -> i64 {
    self.memory_usage.get()
  }

  fn alloc_fallback(&self, bytes: usize) -> &mut [u8] {
    if bytes > K_BLOCK_SIZE / 4 {
      return self.alloc_new(bytes)
    }

    self.alloc_ptr.set(self.alloc_new(K_BLOCK_SIZE).as_mut_ptr());
    self.alloc_bytes_remaining.set(K_BLOCK_SIZE);

    let result = self.alloc_ptr.get();
    unsafe {
      self.alloc_ptr.set(self.alloc_ptr.get().offset(bytes as isize));
      self.alloc_bytes_remaining.set(self.alloc_bytes_remaining.get() - bytes);
      slice::from_raw_parts_mut(result, bytes)
    }
  }

  fn alloc_new(&self, bytes: usize) -> &mut [u8] {
    let mut v = Vec::with_capacity(bytes);
    unsafe {
      v.set_len(bytes);
      ptr::write_bytes(v.as_mut_ptr(), 0, bytes);
    }
    let result = self.arena.alloc(v);
    let memory_usage: i64 = self.memory_usage() + bytes as i64;
    self.memory_usage.set(memory_usage);
    result
  }
}

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

  #[test]
  fn test_new() {
    let mem_pool = MemPool::new();
    assert!(mem_pool.alloc_ptr.get().is_null());
    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 0);
    assert_eq!(mem_pool.memory_usage(), 0);
  }

  #[test]
  fn test_alloc_new() {
    let mem_pool = MemPool::new();

    let v1 = mem_pool.alloc_new(128);
    assert_eq!(v1.len(), 128);

    assert!(mem_pool.alloc_ptr.get().is_null());
    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 0);
    assert_eq!(mem_pool.memory_usage(), 128);

    let v2 = mem_pool.alloc_new(256);
    assert_eq!(v2.len(), 256);

    assert!(mem_pool.alloc_ptr.get().is_null());
    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 0);
    assert_eq!(mem_pool.memory_usage(), 256 + 128);
  }

  #[test]
  fn test_alloc_fallback() {
    let mem_pool = MemPool::new();

    let v1 = mem_pool.alloc_fallback(1025);
    assert_eq!(v1.len(), 1025);

    assert!(mem_pool.alloc_ptr.get().is_null());
    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 0);
    assert_eq!(mem_pool.memory_usage(), 1025);

    let v2 = mem_pool.alloc_fallback(512);
    assert_eq!(v2.len(), 512);

    assert!(!mem_pool.alloc_ptr.get().is_null());
    assert_eq!(mem_pool.alloc_bytes_remaining.get(), K_BLOCK_SIZE - 512);
    assert_eq!(mem_pool.memory_usage(), 1025 + K_BLOCK_SIZE as i64);
  }

  #[test]
  fn test_alloc_aligned() {
    let mem_pool = MemPool::new();
    let ptr_size = ::std::mem::size_of::<usize>();
    assert!(ptr_size > 1);

    let v1 = mem_pool.alloc_fallback(1);
    assert_eq!(v1.len(), 1);

    let v2 = mem_pool.alloc_aligned(512);
    assert_eq!(v2.len(), 512);

    assert!(!mem_pool.alloc_ptr.get().is_null());
    assert_eq!(mem_pool.alloc_bytes_remaining.get(),
               K_BLOCK_SIZE - 512 - ptr_size);
  }

  #[test]
  fn test_alloc() {
    let mem_pool = MemPool::new();

    let _ = mem_pool.alloc(128);

    assert!(!mem_pool.alloc_ptr.get().is_null());
    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 3968);
    assert_eq!(mem_pool.memory_usage(), 4096);

    let _ = mem_pool.alloc(1024); // should allocate from existing block

    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 2944);
    assert_eq!(mem_pool.memory_usage(), 4096);

    let _ = mem_pool.alloc(8192); // should allocate new block

    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 2944);
    assert_eq!(mem_pool.memory_usage(), 12288);

    let _ = mem_pool.alloc(2048); // should allocate from existing block

    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 896);
    assert_eq!(mem_pool.memory_usage(), 12288);

    let _ = mem_pool.alloc(1024); // should allocate new block

    assert_eq!(mem_pool.alloc_bytes_remaining.get(), 3072);
    assert_eq!(mem_pool.memory_usage(), 16384);
  }
}
<commit_msg>Small refactoring on mempool<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.

use std::{ptr, mem, slice};
use std::cell::{Cell, RefCell};
use arena::TypedArena;

const K_BLOCK_SIZE: usize = 4096;

/// Similar to "Arena" in leveldb C++
/// Note that this implements "interior mutability", so caller
/// does not need to hold a unique reference to the struct in order
/// to call its functions.
pub struct MemPool {
  chunk: RefCell<ChunkInfo>,
  arena: TypedArena<Vec<u8>>,
  memory_usage: Cell<i64>
}

struct ChunkInfo {
  ptr: *mut u8,
  bytes_remaining: usize
}

impl MemPool {
  pub fn new() -> Self {
    let chunk = ChunkInfo { ptr: ptr::null_mut(), bytes_remaining: 0 };
    Self {
      chunk: RefCell::new(chunk),
      arena: TypedArena::new(),
      memory_usage: Cell::new(0)
    }
  }

  /// Allocate a byte slice with length `bytes`.
  /// Return a unique reference to the slice allocated.
  pub fn alloc(&self, bytes: usize) -> &mut [u8] {
    assert!(bytes > 0);
    let bytes_remaining = self.chunk.borrow().bytes_remaining;
    if bytes <= bytes_remaining {
      let mut chunk_info = self.chunk.borrow_mut();
      assert!(!chunk_info.ptr.is_null());
      let result = chunk_info.ptr;
      unsafe {
        chunk_info.ptr = chunk_info.ptr.offset(bytes as isize);
        chunk_info.bytes_remaining -= bytes;
        return slice::from_raw_parts_mut(result, bytes)
      }
    }
    self.alloc_fallback(bytes)
  }

  /// Allocate a byte slice with length `bytes` that is aligned to pointer
  /// address.
  /// Return a unique reference to the slice allocated.
  pub fn alloc_aligned(&self, bytes: usize) -> &mut [u8] {
    let ptr_size = mem::size_of::<usize>(); // TODO: double-check this
    assert!(ptr_size <= 128);
    let align = if ptr_size > 8 { ptr_size } else { 8 };
    assert!(align & (align - 1) == 0);

    let (bytes_remaining, slop) = {
      let chunk_info = self.chunk.borrow();
      let current_mod = chunk_info.ptr as usize & (align-1);
      let slop = if current_mod == 0 { 0 } else { align - current_mod };
      (chunk_info.bytes_remaining, slop)
    };
    let needed = bytes + slop;
    let result = if needed <= bytes_remaining {
      unsafe {
        let mut chunk_info = self.chunk.borrow_mut();
        let p = chunk_info.ptr.offset(slop as isize);
        chunk_info.ptr = chunk_info.ptr.offset(needed as isize);
        chunk_info.bytes_remaining -= needed;
        p
      }
    } else {
      self.alloc_fallback(bytes).as_mut_ptr()
    };
    assert!(result as usize & (align-1) == 0);
    unsafe {
      slice::from_raw_parts_mut(result, bytes)
    }
  }

  /// Return the memory usage for the memory pool, in number of bytes allocated.
  pub fn memory_usage(&self) -> i64 {
    self.memory_usage.get()
  }

  fn alloc_fallback(&self, bytes: usize) -> &mut [u8] {
    if bytes > K_BLOCK_SIZE / 4 {
      return self.alloc_new(bytes)
    }

    let mut chunk_info = self.chunk.borrow_mut();
    chunk_info.ptr = self.alloc_new(K_BLOCK_SIZE).as_mut_ptr();
    chunk_info.bytes_remaining = K_BLOCK_SIZE;

    let result = chunk_info.ptr;
    unsafe {
      chunk_info.ptr = chunk_info.ptr.offset(bytes as isize);
      chunk_info.bytes_remaining -= bytes;
      slice::from_raw_parts_mut(result, bytes)
    }
  }

  fn alloc_new(&self, bytes: usize) -> &mut [u8] {
    let mut v = Vec::with_capacity(bytes);
    unsafe {
      v.set_len(bytes);
      ptr::write_bytes(v.as_mut_ptr(), 0, bytes);
    }
    let result = self.arena.alloc(v);
    let memory_usage: i64 = self.memory_usage() + bytes as i64;
    self.memory_usage.set(memory_usage);
    result
  }
}

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

  #[test]
  fn test_new() {
    let mem_pool = MemPool::new();
    check_chunk_info(&mem_pool, true, 0);
    assert_eq!(mem_pool.memory_usage(), 0);
  }

  #[test]
  fn test_alloc_new() {
    let mem_pool = MemPool::new();

    let v1 = mem_pool.alloc_new(128);
    assert_eq!(v1.len(), 128);

    check_chunk_info(&mem_pool, true, 0);
    assert_eq!(mem_pool.memory_usage(), 128);

    let v2 = mem_pool.alloc_new(256);
    assert_eq!(v2.len(), 256);

    check_chunk_info(&mem_pool, true, 0);
    assert_eq!(mem_pool.memory_usage(), 256 + 128);
  }

  #[test]
  fn test_alloc_fallback() {
    let mem_pool = MemPool::new();

    let v1 = mem_pool.alloc_fallback(1025);
    assert_eq!(v1.len(), 1025);

    check_chunk_info(&mem_pool, true, 0);
    assert_eq!(mem_pool.memory_usage(), 1025);

    let v2 = mem_pool.alloc_fallback(512);
    assert_eq!(v2.len(), 512);

    check_chunk_info(&mem_pool, false, K_BLOCK_SIZE - 512);
    assert_eq!(mem_pool.memory_usage(), 1025 + K_BLOCK_SIZE as i64);
  }

  #[test]
  fn test_alloc_aligned() {
    let mem_pool = MemPool::new();
    let ptr_size = ::std::mem::size_of::<usize>();
    assert!(ptr_size > 1);

    let v1 = mem_pool.alloc_fallback(1);
    assert_eq!(v1.len(), 1);

    let v2 = mem_pool.alloc_aligned(512);
    assert_eq!(v2.len(), 512);

    check_chunk_info(&mem_pool, false, K_BLOCK_SIZE - 512 - ptr_size);
  }

  #[test]
  fn test_alloc() {
    let mem_pool = MemPool::new();

    let _ = mem_pool.alloc(128);

    check_chunk_info(&mem_pool, false, 3968);
    assert_eq!(mem_pool.memory_usage(), 4096);

    let _ = mem_pool.alloc(1024); // should allocate from existing block

    check_chunk_info(&mem_pool, false, 2944);
    assert_eq!(mem_pool.memory_usage(), 4096);

    let _ = mem_pool.alloc(8192); // should allocate new block

    check_chunk_info(&mem_pool, false, 2944);
    assert_eq!(mem_pool.memory_usage(), 12288);

    let _ = mem_pool.alloc(2048); // should allocate from existing block

    check_chunk_info(&mem_pool, false, 896);
    assert_eq!(mem_pool.memory_usage(), 12288);

    let _ = mem_pool.alloc(1024); // should allocate new block

    check_chunk_info(&mem_pool, false, 3072);
    assert_eq!(mem_pool.memory_usage(), 16384);
  }

  fn check_chunk_info(mem_pool: &MemPool, is_null: bool, bytes: usize) {
    let chunk_info = mem_pool.chunk.borrow();
    assert_eq!(chunk_info.ptr.is_null(), is_null);
    assert_eq!(chunk_info.bytes_remaining, bytes);
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 Fabian Schuiki

//! Packages

#![allow(dead_code)]

use std::cell::RefCell;

use common::NodeId;
use common::name::Name;
use common::source::{Span, Spanned};

use arenas::Alloc;
use syntax::ast;

/// A placeholder for an HIR node.
pub struct Slot<'t, T: FromAst<'t> + 't>(RefCell<SlotState<'t, T>>);

#[derive(Copy, Clone)]
enum SlotState<'t, T: FromAst<'t> + 't> {
    Fresh(&'t AnyScope, T::Input),
    ReadyOk(&'t T),
    ReadyErr,
}

impl<'t, T: FromAst<'t>> Slot<'t, T> {
    /// Create a new slot.
    pub fn new(scope: &'t AnyScope, ast: T::Input) -> Slot<'t, T> {
        Slot(RefCell::new(SlotState::Fresh(scope, ast)))
    }

    /// Poll the slot, creating the HIR node from AST the first time.
    pub fn poll<A>(&self, arena: &'t A) -> Result<&'t T, ()>
    where
        A: Alloc<T>,
    {
        match *self.0.borrow() {
            SlotState::ReadyOk(x) => return Ok(x),
            SlotState::ReadyErr => return Err(()),
            _ => (),
        }
        ;
        let (scope, ast) = match self.0.replace(SlotState::ReadyErr) {
            SlotState::Fresh(scope, ast) => (scope, ast),
            _ => unreachable!(),
        };
        let node = T::from_ast(scope, ast).map(|x| arena.alloc(x) as &T);
        self.0.replace(match node {
            Ok(x) => SlotState::ReadyOk(x),
            Err(()) => SlotState::ReadyErr,
        });
        node
    }
}

impl<'t, T: FromAst<'t> + Node> Node for Slot<'t, T> {}

pub struct Package2<'t> {
    id: NodeId,
    span: Span,
    name: Spanned<Name>,
    scope: &'t AnyScope,
    decls: Vec<Box<Node + 't>>,
}

impl<'t> Package2<'t> {}

impl<'t> FromAst<'t> for Package2<'t> {
    type Input = &'t ast::PkgDecl;

    fn alloc_slot(scope: &'t AnyScope, ast: Self::Input) -> Result<Slot<'t, Self>, ()> {
        // TODO: register the package name in the scope
        Ok(Slot::new(scope, ast))
    }

    fn from_ast(scope: &'t AnyScope, ast: Self::Input) -> Result<Self, ()> {
        // TODO: create a new scope for the package
        let decls = ast.decls
            .iter()
            .flat_map(|decl| -> Option<Box<Node>> {
                match *decl {
                    ast::DeclItem::PkgDecl(ref decl) => Some(Box::new(Package2::alloc_slot(scope, decl).ok()?)),
                    ast::DeclItem::TypeDecl(ref decl) => Some(Box::new(TypeDecl2::alloc_slot(scope, decl).ok()?)),
                    _ => None,
                }
            })
            .collect::<Vec<_>>();
        Ok(Package2 {
            id: NodeId::alloc(),
            span: ast.span,
            name: ast.name,
            scope: scope,
            decls: decls,
        })
    }
}

impl<'t> Node for Package2<'t> {}

pub struct TypeDecl2 {
    id: NodeId,
    span: Span,
    name: Spanned<Name>,
}

impl<'t> FromAst<'t> for TypeDecl2 {
    type Input = &'t ast::TypeDecl;

    fn alloc_slot(scope: &'t AnyScope, ast: Self::Input) -> Result<Slot<'t, Self>, ()> {
        // TODO: register the type name in the scope
        Ok(Slot::new(scope, ast))
    }

    fn from_ast(_scope: &'t AnyScope, ast: Self::Input) -> Result<Self, ()> {
        Ok(TypeDecl2 {
            id: NodeId::alloc(),
            span: ast.span,
            name: ast.name,
        })
    }
}

impl Node for TypeDecl2 {}

pub trait AnyScope {}
pub trait Node {}

/// Construct something from an AST node.
pub trait FromAst<'t>: Sized {
    type Input;
    fn alloc_slot(scope: &'t AnyScope, ast: Self::Input) -> Result<Slot<'t, Self>, ()>;
    fn from_ast(scope: &'t AnyScope, ast: Self::Input) -> Result<Self, ()>;
}
<commit_msg>vhdl: introduce Arena type parameter<commit_after>// Copyright (c) 2018 Fabian Schuiki

//! Packages

#![allow(dead_code)]

use std::cell::RefCell;

use common::NodeId;
use common::name::Name;
use common::source::{Span, Spanned, INVALID_SPAN};

use arenas::{Alloc, AllocInto};
use syntax::ast;

/// A placeholder for an HIR node.
pub struct Slot<'t, T>(RefCell<SlotState<'t, T>>)
where
    T: FromAst<'t> + 't;

#[derive(Copy, Clone)]
enum SlotState<'t, T>
where
    T: FromAst<'t> + 't,
{
    Fresh(&'t AnyScope, T::Input, T::Arena),
    ReadyOk(&'t T),
    ReadyErr,
}

impl<'t, T> Slot<'t, T>
where
    T: FromAst<'t>,
    T::Arena: AllocInto<'t, T> + Clone,
{
    /// Create a new slot.
    pub fn new(scope: &'t AnyScope, ast: T::Input, arena: T::Arena) -> Slot<'t, T> {
        Slot(RefCell::new(SlotState::Fresh(scope, ast, arena)))
    }

    /// Poll the slot, creating the HIR node from the AST the first time.
    pub fn poll(&self) -> Result<&'t T, ()> {
        match *self.0.borrow() {
            SlotState::ReadyOk(x) => return Ok(x),
            SlotState::ReadyErr => return Err(()),
            _ => (),
        }
        let (scope, ast, arena) = match self.0.replace(SlotState::ReadyErr) {
            SlotState::Fresh(scope, ast, arena) => (scope, ast, arena),
            _ => unreachable!(),
        };
        let node = T::from_ast(scope, ast, arena.clone()).map(|x| arena.alloc(x) as &T);
        self.0.replace(match node {
            Ok(x) => SlotState::ReadyOk(x),
            Err(()) => SlotState::ReadyErr,
        });
        node
    }
}

impl<'t, T> Node for Slot<'t, T>
where
    T: FromAst<'t> + Node,
    T::Arena: AllocInto<'t, T> + Clone,
{
    fn span(&self) -> Span {
        self.poll().map(Node::span).unwrap_or(INVALID_SPAN)
    }
}

pub struct Package2<'t> {
    id: NodeId,
    span: Span,
    name: Spanned<Name>,
    scope: &'t AnyScope,
    decls: Vec<Box<Node + 't>>,
}

impl<'t> FromAst<'t> for Package2<'t> {
    type Input = &'t ast::PkgDecl;
    type Arena = &'t Alloc<Self>;

    fn alloc_slot(
        scope: &'t AnyScope,
        ast: Self::Input,
        arena: Self::Arena,
    ) -> Result<Slot<'t, Self>, ()> {
        // TODO: register the package name in the scope
        Ok(Slot::new(scope, ast, arena))
    }

    fn from_ast(scope: &'t AnyScope, ast: Self::Input, _arena: Self::Arena) -> Result<Self, ()> {
        // TODO: create a new scope for the package
        let decls = ast.decls
            .iter()
            .flat_map(|decl| -> Option<Box<Node>> {
                match *decl {
                    // ast::DeclItem::PkgDecl(ref decl) => {
                    //     Some(Box::new(Package2::alloc_slot(scope, decl, arena).ok()?))
                    // }
                    // ast::DeclItem::TypeDecl(ref decl) => {
                    //     Some(Box::new(TypeDecl2::alloc_slot(scope, decl, arena).ok()?))
                    // }
                    _ => None,
                }
            })
            .collect::<Vec<_>>();
        Ok(Package2 {
            id: NodeId::alloc(),
            span: ast.span,
            name: ast.name,
            scope: scope,
            decls: decls,
        })
    }
}

impl<'t> Node for Package2<'t> {
    fn span(&self) -> Span {
        self.span
    }
}

pub struct TypeDecl2 {
    id: NodeId,
    span: Span,
    name: Spanned<Name>,
}

impl<'t> FromAst<'t> for TypeDecl2 {
    type Input = &'t ast::TypeDecl;
    type Arena = &'t Alloc<Self>;

    fn alloc_slot(
        scope: &'t AnyScope,
        ast: Self::Input,
        arena: Self::Arena,
    ) -> Result<Slot<'t, Self>, ()> {
        // TODO: register the type name in the scope
        Ok(Slot::new(scope, ast, arena))
    }

    fn from_ast(_scope: &'t AnyScope, ast: Self::Input, _arena: Self::Arena) -> Result<Self, ()> {
        Ok(TypeDecl2 {
            id: NodeId::alloc(),
            span: ast.span,
            name: ast.name,
        })
    }
}

impl Node for TypeDecl2 {
    fn span(&self) -> Span {
        self.span
    }
}

pub trait AnyScope {}

pub trait Node {
    /// The source file location of this node.
    fn span(&self) -> Span;
}

/// Construct something from an AST node.
pub trait FromAst<'t>: Sized {
    type Input;
    type Arena;

    fn alloc_slot(
        scope: &'t AnyScope,
        ast: Self::Input,
        arena: Self::Arena,
    ) -> Result<Slot<'t, Self>, ()>;

    fn from_ast(scope: &'t AnyScope, ast: Self::Input, arena: Self::Arena) -> Result<Self, ()>;
}
<|endoftext|>


<commit_before>#![deny(unused_import_braces,
        unused_comparisons, unused_must_use,
        unused_variables, non_shorthand_field_patterns,
        unreachable_code)]

extern crate trie;
extern crate sputnikvm;
extern crate sha3;
extern crate block;
extern crate rlp;

use sputnikvm::{H256, U256, M256, Address};
use sputnikvm::vm::{self, ValidTransaction, HeaderParams, Memory, TransactionVM, VM,
                    AccountCommitment, Patch, SeqMemory};
use sputnikvm::vm::errors::RequireError;
use sha3::{Keccak256, Digest};
use trie::{Trie, SecureTrie, FixedSecureTrie, DatabaseGuard, MemoryDatabase, MemoryDatabaseGuard, Database, DatabaseOwned};
use block::Account;
use std::collections::HashMap;
use std::cmp::min;

pub struct Stateful<G, D> {
    database: D,
    code_hashes: G,
    root: H256,
}

impl<G, D> Stateful<G, D> {
    pub fn new(database: D, code_hashes: G, root: H256) -> Self {
        Self {
            database,
            code_hashes,
            root
        }
    }
}

impl<G: Default, D: Default> Default for Stateful<G, D> {
    fn default() -> Self {
        Self {
            database: D::default(),
            code_hashes: G::default(),
            root: MemoryDatabase::new().create_empty().root(),
        }
    }
}

impl<G: DatabaseGuard, D: DatabaseOwned> Stateful<G, D> {
    fn is_empty_hash(hash: H256) -> bool {
        hash == H256::from(Keccak256::digest(&[]).as_slice())
    }

    pub fn call<M: Memory + Default>(
        &self, transaction: ValidTransaction, block: HeaderParams,
        patch: &'static Patch, most_recent_block_hashes: &[H256]
    ) -> TransactionVM<M> {
        assert!(U256::from(most_recent_block_hashes.len()) >=
                min(block.number, U256::from(256)));

        let mut vm = TransactionVM::new(transaction, block.clone(), patch);
        let state = self.database.create_fixed_secure_trie(self.root);

        loop {
            match vm.fire() {
                Ok(()) => break,
                Err(RequireError::Account(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            vm.commit_account(AccountCommitment::Full {
                                nonce: account.nonce,
                                address: address,
                                balance: account.balance,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountCode(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            vm.commit_account(AccountCommitment::Code {
                                address: address,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountStorage(address, index)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());

                            vm.commit_account(AccountCommitment::Storage {
                                address: address,
                                index, value
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::Blockhash(number)) => {
                    let index = (block.number - number).as_usize();
                    vm.commit_blockhash(number, most_recent_block_hashes[index]).unwrap();
                },
            }
        }

        vm
    }

    pub fn transit(
        &mut self, accounts: &[vm::Account]
    ) {
        let mut state = self.database.create_fixed_secure_trie(self.root);

        for account in accounts {
            match account.clone() {
                vm::Account::Full {
                    nonce, address, balance, changing_storage, code
                } => {
                    let changing_storage: HashMap<U256, M256> = changing_storage.into();

                    let mut account: Account = state.get(&address).unwrap();

                    let mut storage_trie = self.database.create_fixed_secure_trie(account.storage_root);
                    for (key, value) in changing_storage {
                        storage_trie.insert(H256::from(key), value);
                    }

                    account.balance = balance;
                    account.nonce = nonce;
                    account.storage_root = storage_trie.root();
                    assert!(account.code_hash == H256::from(Keccak256::digest(&code).as_slice()));

                    state.insert(address, account);
                },
                vm::Account::IncreaseBalance(address, value) => {
                    let mut account: Account = state.get(&address).unwrap();

                    account.balance = account.balance + value;

                    state.insert(address, account);
                },
                vm::Account::DecreaseBalance(address, value) => {
                    let mut account: Account = state.get(&address).unwrap();

                    account.balance = account.balance - value;

                    state.insert(address, account);
                },
                vm::Account::Create {
                    nonce, address, balance, storage, code, exists
                } => {
                    if !exists {
                        state.remove(&address);
                    } else {
                        let storage: HashMap<U256, M256> = storage.into();

                        let mut storage_trie = self.database.create_fixed_secure_empty();
                        for (key, value) in storage {
                            storage_trie.insert(H256::from(key), value);
                        }

                        let code_hash = H256::from(Keccak256::digest(&code).as_slice());
                        self.code_hashes.set(code_hash, code);

                        let account = Account {
                            nonce: nonce,
                            balance: balance,
                            storage_root: storage_trie.root(),
                            code_hash
                        };

                        state.insert(address, account);
                    }
                },
            }
        }

        self.root = state.root();
    }

    pub fn execute<M: Memory + Default>(
        &mut self, transaction: ValidTransaction, block: HeaderParams,
        patch: &'static Patch, most_recent_block_hashes: &[H256]
    ) -> TransactionVM<M> {
        let vm = self.call(transaction, block, patch, most_recent_block_hashes);
        let mut accounts = Vec::new();
        for account in vm.accounts() {
            accounts.push(account.clone());
        }
        self.transit(&accounts);
        vm
    }

    pub fn root(&self) -> H256 {
        self.root
    }

    pub fn state<'a>(&'a self) -> FixedSecureTrie<<D as Database<'a>>::Guard, Address, Account> {
        self.database.create_fixed_secure_trie::<Address, Account>(self.root())
    }
}

pub type MemoryStateful = Stateful<HashMap<H256, Vec<u8>>, MemoryDatabase>;
<commit_msg>stateful: query storage state<commit_after>#![deny(unused_import_braces,
        unused_comparisons, unused_must_use,
        unused_variables, non_shorthand_field_patterns,
        unreachable_code)]

extern crate trie;
extern crate sputnikvm;
extern crate sha3;
extern crate block;
extern crate rlp;

use sputnikvm::{H256, U256, M256, Address};
use sputnikvm::vm::{self, ValidTransaction, HeaderParams, Memory, TransactionVM, VM,
                    AccountCommitment, Patch, SeqMemory};
use sputnikvm::vm::errors::RequireError;
use sha3::{Keccak256, Digest};
use trie::{Trie, SecureTrie, FixedSecureTrie, DatabaseGuard, MemoryDatabase, MemoryDatabaseGuard, Database, DatabaseOwned};
use block::Account;
use std::collections::HashMap;
use std::cmp::min;

pub struct Stateful<G, D> {
    database: D,
    code_hashes: G,
    root: H256,
}

impl<G, D> Stateful<G, D> {
    pub fn new(database: D, code_hashes: G, root: H256) -> Self {
        Self {
            database,
            code_hashes,
            root
        }
    }
}

impl<G: Default, D: Default> Default for Stateful<G, D> {
    fn default() -> Self {
        Self {
            database: D::default(),
            code_hashes: G::default(),
            root: MemoryDatabase::new().create_empty().root(),
        }
    }
}

impl<G: DatabaseGuard, D: DatabaseOwned> Stateful<G, D> {
    fn is_empty_hash(hash: H256) -> bool {
        hash == H256::from(Keccak256::digest(&[]).as_slice())
    }

    pub fn call<M: Memory + Default>(
        &self, transaction: ValidTransaction, block: HeaderParams,
        patch: &'static Patch, most_recent_block_hashes: &[H256]
    ) -> TransactionVM<M> {
        assert!(U256::from(most_recent_block_hashes.len()) >=
                min(block.number, U256::from(256)));

        let mut vm = TransactionVM::new(transaction, block.clone(), patch);
        let state = self.database.create_fixed_secure_trie(self.root);

        loop {
            match vm.fire() {
                Ok(()) => break,
                Err(RequireError::Account(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            vm.commit_account(AccountCommitment::Full {
                                nonce: account.nonce,
                                address: address,
                                balance: account.balance,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountCode(address)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let code = if Self::is_empty_hash(account.code_hash) {
                                Vec::new()
                            } else {
                                self.code_hashes.get(account.code_hash).unwrap()
                            };

                            vm.commit_account(AccountCommitment::Code {
                                address: address,
                                code: code,
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::AccountStorage(address, index)) => {
                    let account: Option<Account> = state.get(&address);

                    match account {
                        Some(account) => {
                            let storage = self.database.create_fixed_secure_trie(account.storage_root);
                            let value = storage.get(&H256::from(index)).unwrap_or(M256::zero());

                            vm.commit_account(AccountCommitment::Storage {
                                address: address,
                                index, value
                            }).unwrap();
                        },
                        None => {
                            vm.commit_account(AccountCommitment::Nonexist(address)).unwrap();
                        },
                    }
                },
                Err(RequireError::Blockhash(number)) => {
                    let index = (block.number - number).as_usize();
                    vm.commit_blockhash(number, most_recent_block_hashes[index]).unwrap();
                },
            }
        }

        vm
    }

    pub fn transit(
        &mut self, accounts: &[vm::Account]
    ) {
        let mut state = self.database.create_fixed_secure_trie(self.root);

        for account in accounts {
            match account.clone() {
                vm::Account::Full {
                    nonce, address, balance, changing_storage, code
                } => {
                    let changing_storage: HashMap<U256, M256> = changing_storage.into();

                    let mut account: Account = state.get(&address).unwrap();

                    let mut storage_trie = self.database.create_fixed_secure_trie(account.storage_root);
                    for (key, value) in changing_storage {
                        storage_trie.insert(H256::from(key), value);
                    }

                    account.balance = balance;
                    account.nonce = nonce;
                    account.storage_root = storage_trie.root();
                    assert!(account.code_hash == H256::from(Keccak256::digest(&code).as_slice()));

                    state.insert(address, account);
                },
                vm::Account::IncreaseBalance(address, value) => {
                    let mut account: Account = state.get(&address).unwrap();

                    account.balance = account.balance + value;

                    state.insert(address, account);
                },
                vm::Account::DecreaseBalance(address, value) => {
                    let mut account: Account = state.get(&address).unwrap();

                    account.balance = account.balance - value;

                    state.insert(address, account);
                },
                vm::Account::Create {
                    nonce, address, balance, storage, code, exists
                } => {
                    if !exists {
                        state.remove(&address);
                    } else {
                        let storage: HashMap<U256, M256> = storage.into();

                        let mut storage_trie = self.database.create_fixed_secure_empty();
                        for (key, value) in storage {
                            storage_trie.insert(H256::from(key), value);
                        }

                        let code_hash = H256::from(Keccak256::digest(&code).as_slice());
                        self.code_hashes.set(code_hash, code);

                        let account = Account {
                            nonce: nonce,
                            balance: balance,
                            storage_root: storage_trie.root(),
                            code_hash
                        };

                        state.insert(address, account);
                    }
                },
            }
        }

        self.root = state.root();
    }

    pub fn execute<M: Memory + Default>(
        &mut self, transaction: ValidTransaction, block: HeaderParams,
        patch: &'static Patch, most_recent_block_hashes: &[H256]
    ) -> TransactionVM<M> {
        let vm = self.call(transaction, block, patch, most_recent_block_hashes);
        let mut accounts = Vec::new();
        for account in vm.accounts() {
            accounts.push(account.clone());
        }
        self.transit(&accounts);
        vm
    }

    pub fn root(&self) -> H256 {
        self.root
    }

    pub fn state<'a>(&'a self) -> FixedSecureTrie<<D as Database<'a>>::Guard, Address, Account> {
        self.database.create_fixed_secure_trie::<Address, Account>(self.root())
    }

    pub fn storage_state<'a>(&'a self, address: Address) -> Option<FixedSecureTrie<<D as Database<'a>>::Guard, H256, M256>> {
        let state = self.state();
        let account = state.get(&address);

        match account {
            Some(account) => {
                let storage_root = account.storage_root;
                Some(self.database.create_fixed_secure_trie::<H256, M256>(storage_root))
            },
            None => None,
        }
    }
}

pub type MemoryStateful = Stateful<HashMap<H256, Vec<u8>>, MemoryDatabase>;
<|endoftext|>


<commit_before>#![allow(bad_style, improper_ctypes)]
extern crate libc;

use libc::*;

include!(concat!(env!("OUT_DIR"), "/linux_fcntl.rs"));
<commit_msg>Remove warnings in libc-test<commit_after>#![allow(bad_style, improper_ctypes, unused)]

extern crate libc;

use libc::*;

include!(concat!(env!("OUT_DIR"), "/linux_fcntl.rs"));
<|endoftext|>


<commit_before>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::ptr::NonNull;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::OsRng;
use super::std::Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.

// Number of generated bytes after which to reseed `ThreadRng`.
// According to benchmarks, reseeding has a noticable impact with thresholds
// of 32 kB and less. We choose 64 kB to avoid significant overhead.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance.
/// As hinted by the name, the generator is thread-local. `ThreadRng` is a
/// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`.
///
/// Unlike `StdRng`, `ThreadRng` uses the  [`ReseedingRng`] wrapper to reseed
/// the PRNG from fresh entropy every 64 kiB of random data.
/// [`OsRng`] is used to provide seed data.
///
/// Note that the reseeding is done as an extra precaution against side-channel
/// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
/// The PRNG algorithms used are assumed to be secure.
///
/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
/// [`StdRng`]: crate::rngs::StdRng
#[derive(Copy, Clone, Debug)]
pub struct ThreadRng {
    // inner raw pointer implies type is neither Send nor Sync
    rng: NonNull<ReseedingRng<Core, OsRng>>,
}

thread_local!(
    static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Core, OsRng>> = {
        let r = Core::from_rng(OsRng).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    OsRng);
        UnsafeCell::new(rng)
    }
);

/// Retrieve the lazily-initialized thread-local random number generator,
/// seeded by the system. Intended to be used in method chaining style,
/// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.  Invoked by the `Default` trait, making
/// `ThreadRng::default()` equivalent.
///
/// For more information see [`ThreadRng`].
pub fn thread_rng() -> ThreadRng {
    let raw = THREAD_RNG_KEY.with(|t| t.get());
    let nn = unsafe { NonNull::new_unchecked(raw) };
    ThreadRng { rng: nn }
}

impl Default for ThreadRng {
    fn default() -> ThreadRng {
        ::prelude::thread_rng()
    }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { self.rng.as_mut().next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { self.rng.as_mut().next_u64() }
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        unsafe { self.rng.as_mut().fill_bytes(dest) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { self.rng.as_mut().try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<commit_msg>Use safe NonNull constructor in ThreadRng<commit_after>// Copyright 2018 Developers of the Rand project.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::ptr::NonNull;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::OsRng;
use super::std::Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.

// Number of generated bytes after which to reseed `ThreadRng`.
// According to benchmarks, reseeding has a noticable impact with thresholds
// of 32 kB and less. We choose 64 kB to avoid significant overhead.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 1024 * 64;

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses the same PRNG as [`StdRng`] for security and performance.
/// As hinted by the name, the generator is thread-local. `ThreadRng` is a
/// handle to this generator and thus supports `Copy`, but not `Send` or `Sync`.
///
/// Unlike `StdRng`, `ThreadRng` uses the  [`ReseedingRng`] wrapper to reseed
/// the PRNG from fresh entropy every 64 kiB of random data.
/// [`OsRng`] is used to provide seed data.
///
/// Note that the reseeding is done as an extra precaution against side-channel
/// attacks and mis-use (e.g. if somehow weak entropy were supplied initially).
/// The PRNG algorithms used are assumed to be secure.
///
/// [`ReseedingRng`]: crate::rngs::adapter::ReseedingRng
/// [`StdRng`]: crate::rngs::StdRng
#[derive(Copy, Clone, Debug)]
pub struct ThreadRng {
    // inner raw pointer implies type is neither Send nor Sync
    rng: NonNull<ReseedingRng<Core, OsRng>>,
}

thread_local!(
    static THREAD_RNG_KEY: UnsafeCell<ReseedingRng<Core, OsRng>> = {
        let r = Core::from_rng(OsRng).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    OsRng);
        UnsafeCell::new(rng)
    }
);

/// Retrieve the lazily-initialized thread-local random number generator,
/// seeded by the system. Intended to be used in method chaining style,
/// e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.  Invoked by the `Default` trait, making
/// `ThreadRng::default()` equivalent.
///
/// For more information see [`ThreadRng`].
pub fn thread_rng() -> ThreadRng {
    let raw = THREAD_RNG_KEY.with(|t| t.get());
    let nn = NonNull::new(raw).unwrap();
    ThreadRng { rng: nn }
}

impl Default for ThreadRng {
    fn default() -> ThreadRng {
        ::prelude::thread_rng()
    }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { self.rng.as_mut().next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { self.rng.as_mut().next_u64() }
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        unsafe { self.rng.as_mut().fill_bytes(dest) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { self.rng.as_mut().try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<|endoftext|>


<commit_before>/// Implements the actual raytracer which produces the final image
use std::num::{Float, NumCast};
use std::old_io;
use std::old_io::stdio;
use std::default::Default;
use std::fmt::Debug;
use super::vec::Vector;
use super::group::SphericalGroup;
use super::primitive::{Intersectable, Ray};

pub trait PixelWriter<T> {
    /// To be called before writing the first pixel
    /// x and y are the max image resolution
    fn begin(&mut self, x: u16, y: u16);

    /// Write one line after another, when x is width, skip to next line
    /// This must be assured by the caller
    /// Color range is 0.0 to 1.0, everything higher leads to overflows
    fn write_next_pixel(&mut self, color: &Vector<T>);
}

pub struct Renderer<T> {
    pub width: u16,
    pub height: u16,
    pub samples_per_pixel: u16,
}

pub struct Scene<T> {
    pub group: SphericalGroup<T>,
    pub omni_light_pos: Vector<T>,
    pub eye: Vector<T>,
}

impl<T: Float + Default + Debug> Default for Scene<T> {
    fn default() -> Scene<T> {
        let one: T = Float::one();
        let zero: T = Float::zero();
        Scene {
            group: SphericalGroup::<T>::pyramid(8, &Vector { x: one,
                                                             y: -one,
                                                             z: zero }, one),
            omni_light_pos: Vector { x: -one, y: -(one+one+one), z: (one+one) },
            eye: Vector { x: zero, y: zero, z: -(one+one+one+one) }
        }
    }
}

impl<T: Float + Default> Renderer<T> {

    fn raytrace(&self, s: &Scene<T>, r: &Ray<T>, c: &mut Vector<T>) {
        let h = s.group.intersect(Float::infinity(), r);
        match h {
            Some(h) => {
                c.x = c.x + Float::one();
                c.y = c.y + Float::one();
                c.z = c.z + Float::one();
            }
            _ => {}
        }
    }

    // Use runtime dispatching for the image writer to remain flexible
    // (And to test this ;))
    pub fn render(&self, scene: &Scene<T>, writer: &mut PixelWriter<T>) {
        writer.begin(self.width, self.height);
        let ssf: T = NumCast::from(self.samples_per_pixel).unwrap();
        let wf: T = NumCast::from(self.width).unwrap();
        let hf: T = NumCast::from(self.height).unwrap();

        let mut ray = Ray { pos: scene.eye,
                            dir: Default::default() };
        let two = <T as Float>::one() + Float::one();

        for y in range(0, self.height) {
            for x in range(0, self.width) {
                let mut g: Vector<T> = Default::default();

                for ssx in range(0, self.samples_per_pixel) {
                    for ssy in range(0, self.samples_per_pixel) {
                        let xres = <T as NumCast>::from(x).unwrap() +
                                   <T as NumCast>::from(ssx).unwrap() / ssf;
                        let yres = <T as NumCast>::from(y).unwrap() +
                                   <T as NumCast>::from(ssy).unwrap() / ssf;
                        ray.dir.x = xres - wf / two;
                        ray.dir.y = yres - hf / two;
                        ray.dir.z = wf;
                        ray.dir.normalize();
                        self.raytrace(scene, &ray, &mut g);
                    }//for each ss y
                }// for each ss x

                g.mulf((ssf * ssf).recip());
                writer.write_next_pixel(&g);
            }// for each x
        }// for each y
    }
}

pub struct PPMStdoutPixelWriter {
    out: old_io::LineBufferedWriter<stdio::StdWriter>,
    rgb: bool,
}

impl PPMStdoutPixelWriter {
    pub fn new(write_RGB: bool) -> PPMStdoutPixelWriter {
        PPMStdoutPixelWriter { out: old_io::stdout(), rgb: write_RGB }
    }
}

impl<T: Float + Debug> PixelWriter<T> for PPMStdoutPixelWriter {
    fn begin(&mut self, x: u16, y: u16) {
        let mut ptype: &str = "P5";
        if self.rgb {
            ptype = "P6"
        }
        self.out.write_line(ptype);
        self.out.write_line(&format!("{} {}", x, y)[]);
        self.out.write_line("255");
    }

    fn write_next_pixel(&mut self, c: &Vector<T>) {
        let one: T = Float::one();
        let two55 = (one+one).powi(8) - one; // 255

        if self.rgb {
            self.out.write_u8(<u8 as NumCast>::from(two55 * c.x).unwrap());
            self.out.write_u8(<u8 as NumCast>::from(two55 * c.y).unwrap());
            self.out.write_u8(<u8 as NumCast>::from(two55 * c.z).unwrap());
        } else {
            let avg = (c.x + c.y + c.z) / (one+one+one);
            self.out.write_u8(<u8 as NumCast>::from(two55 * avg).unwrap());
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use super::*;
    use super::super::vec::Vector;
    use super::super::group::SphericalGroup;
    use std::default::Default;

    #[derive(Default)]
    struct DummyWriter {
        begin_called: bool,
        write_count: usize,
    }

    impl<T> PixelWriter<T> for DummyWriter {
        fn begin(&mut self, x: u16, y: u16) {
            self.begin_called = true;
        }
        fn write_next_pixel(&mut self, color: &Vector<T>) {
            self.write_count += 1;
        }
    }

    const W: usize = 32;
    const H: usize = 16;

    #[test]
    fn basic_rendering() {
        let s: Scene<f32> = Default::default();
        let r = Renderer { width: W as u16,
                           height: H as u16,
                           samples_per_pixel: 2 };

        let mut dw: DummyWriter = Default::default();
        r.render(&s, &mut dw);

        assert!(dw.begin_called);
        assert!(dw.write_count == W * H);
    }

    #[bench]
    fn bench_rendering(b: &mut test::Bencher) {
        const SPP: usize = 1;
        let s: Scene<f32> = Default::default();
        let r = Renderer { width: H as u16,
                           height: H as u16,
                           samples_per_pixel: SPP as u16 };

        let mut dw: DummyWriter = Default::default();
        b.iter(|| {
            r.render(&s, &mut dw);
        });
        b.bytes += (H * H * SPP * SPP) as u64;
    }
}<commit_msg>Implemented proper 'ligthing' , but there seems to be some sort of error in there<commit_after>/// Implements the actual raytracer which produces the final image
use std::num::{Float, NumCast};
use std::old_io;
use std::old_io::stdio;
use std::default::Default;
use std::fmt::Debug;
use super::vec::Vector;
use super::group::SphericalGroup;
use super::primitive::{Intersectable, Ray};

pub trait PixelWriter<T> {
    /// To be called before writing the first pixel
    /// x and y are the max image resolution
    fn begin(&mut self, x: u16, y: u16);

    /// Write one line after another, when x is width, skip to next line
    /// This must be assured by the caller
    /// Color range is 0.0 to 1.0, everything higher leads to overflows
    fn write_next_pixel(&mut self, color: &Vector<T>);
}

pub struct Renderer<T> {
    pub width: u16,
    pub height: u16,
    pub samples_per_pixel: u16,
}

pub struct Scene<T> {
    pub group: SphericalGroup<T>,
    pub omni_light_pos: Vector<T>,
    pub eye: Vector<T>,
}

impl<T: Float + Default + Debug> Default for Scene<T> {
    fn default() -> Scene<T> {
        let one: T = Float::one();
        let zero: T = Float::zero();
        Scene {
            group: SphericalGroup::<T>::pyramid(8, &Vector { x: one,
                                                             y: -one,
                                                             z: zero }, one),
            omni_light_pos: Vector { x: -one, y: -(one+one+one), z: (one+one) },
            eye: Vector { x: zero, y: zero, z: -(one+one+one+one) }
        }
    }
}

impl<T: Float + Default> Renderer<T> {

    fn raytrace(&self, s: &Scene<T>, r: &Ray<T>, c: &mut Vector<T>) {
        if let Some(ref mut h) = s.group.intersect(Float::infinity(), r) {
                let g: T = h.pos.dot(&s.omni_light_pos);
                if g >= <T as Float>::zero() {
                    return
                }
                let p = r.pos +
                            (r.dir.mulfed(h.distance)) +
                            *h.pos.mulf(h.distance*<T as Float>::epsilon().sqrt());

                if let Some(ref h) = s.group.intersect(
                                    Float::infinity(),
                                    &Ray { pos: p,
                                           dir: s.omni_light_pos.mulfed(-<T as Float>::one())}) {
                        c.x = c.x - g;
                        c.y = c.y - g;
                        c.z = c.z - g;
                }
        }
    }

    // Use runtime dispatching for the image writer to remain flexible
    // (And to test this ;))
    pub fn render(&self, scene: &Scene<T>, writer: &mut PixelWriter<T>) {
        writer.begin(self.width, self.height);
        let ssf: T = NumCast::from(self.samples_per_pixel).unwrap();
        let wf: T = NumCast::from(self.width).unwrap();
        let hf: T = NumCast::from(self.height).unwrap();

        let mut ray = Ray { pos: scene.eye,
                            dir: Default::default() };
        let two = <T as Float>::one() + Float::one();

        for y in range(0, self.height) {
            for x in range(0, self.width) {
                let mut g: Vector<T> = Default::default();

                for ssx in range(0, self.samples_per_pixel) {
                    for ssy in range(0, self.samples_per_pixel) {
                        let xres = <T as NumCast>::from(x).unwrap() +
                                   <T as NumCast>::from(ssx).unwrap() / ssf;
                        let yres = <T as NumCast>::from(y).unwrap() +
                                   <T as NumCast>::from(ssy).unwrap() / ssf;
                        ray.dir.x = xres - wf / two;
                        ray.dir.y = yres - hf / two;
                        ray.dir.z = wf;
                        ray.dir.normalize();
                        self.raytrace(scene, &ray, &mut g);
                    }//for each ss y
                }// for each ss x

                g.mulf((ssf * ssf).recip());
                writer.write_next_pixel(&g);
            }// for each x
        }// for each y
    }
}

pub struct PPMStdoutPixelWriter {
    out: old_io::LineBufferedWriter<stdio::StdWriter>,
    rgb: bool,
}

impl PPMStdoutPixelWriter {
    pub fn new(write_RGB: bool) -> PPMStdoutPixelWriter {
        PPMStdoutPixelWriter { out: old_io::stdout(), rgb: write_RGB }
    }
}

impl<T: Float + Debug> PixelWriter<T> for PPMStdoutPixelWriter {
    fn begin(&mut self, x: u16, y: u16) {
        let mut ptype: &str = "P5";
        if self.rgb {
            ptype = "P6"
        }
        self.out.write_line(ptype);
        self.out.write_line(&format!("{} {}", x, y)[]);
        self.out.write_line("255");
    }

    fn write_next_pixel(&mut self, c: &Vector<T>) {
        let one: T = Float::one();
        let two55 = (one+one).powi(8) - one; // 255

        if self.rgb {
            self.out.write_u8(<u8 as NumCast>::from(two55 * c.x).unwrap());
            self.out.write_u8(<u8 as NumCast>::from(two55 * c.y).unwrap());
            self.out.write_u8(<u8 as NumCast>::from(two55 * c.z).unwrap());
        } else {
            let avg = (c.x + c.y + c.z) / (one+one+one);
            self.out.write_u8(<u8 as NumCast>::from(two55 * avg).unwrap());
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate test;

    use super::*;
    use super::super::vec::Vector;
    use super::super::group::SphericalGroup;
    use std::default::Default;

    #[derive(Default)]
    struct DummyWriter {
        begin_called: bool,
        write_count: usize,
    }

    impl<T> PixelWriter<T> for DummyWriter {
        fn begin(&mut self, x: u16, y: u16) {
            self.begin_called = true;
        }
        fn write_next_pixel(&mut self, color: &Vector<T>) {
            self.write_count += 1;
        }
    }

    const W: usize = 32;
    const H: usize = 16;

    #[test]
    fn basic_rendering() {
        let s: Scene<f32> = Default::default();
        let r = Renderer { width: W as u16,
                           height: H as u16,
                           samples_per_pixel: 2 };

        let mut dw: DummyWriter = Default::default();
        r.render(&s, &mut dw);

        assert!(dw.begin_called);
        assert!(dw.write_count == W * H);
    }

    #[bench]
    fn bench_rendering(b: &mut test::Bencher) {
        const SPP: usize = 1;
        let s: Scene<f32> = Default::default();
        let r = Renderer { width: H as u16,
                           height: H as u16,
                           samples_per_pixel: SPP as u16 };

        let mut dw: DummyWriter = Default::default();
        b.iter(|| {
            r.render(&s, &mut dw);
        });
        b.bytes += (H * H * SPP * SPP) as u64;
    }
}<|endoftext|>


<commit_before>//! This module integrates the buddy heap allocator into the Rust runtime.
use spin::Mutex;
use core::ptr;

use ::Allocator;
use super::{BuddyHeapAllocator, FreeList};

static ALLOC: Mutex<Option<BuddyHeapAllocator<'static>>>
    = Mutex::new(None);

static mut KERNEL_FREE_LISTS: [FreeList; 17]
    // TODO: I really wish there was a less awful way to do this...
    = [ FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      ];

pub unsafe fn init_heap(start_addr: *mut u8, heap_size: usize ) {
    trace!("init_heap() was called.");
    *(ALLOC.lock())
        = Some(BuddyHeapAllocator::new( start_addr
                                      , &mut KERNEL_FREE_LISTS
                                      , heap_size));
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    trace!("__rust_allocate() was called.");
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot allocate memory, no system allocator exists!")
             .allocate(size, align)
             .map(|blck| {
                 trace!("__rust_allocate: allocatedd {:?}", blck);
                 blck })
             .unwrap_or(ptr::null_mut())
    }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate( ptr: *mut u8, old_size: usize
                                   , align: usize ) {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot deallocate memory, no system allocator exists!")
             .deallocate(ptr, old_size, align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate( ptr: *mut u8, old_size: usize
                                   , size: usize, align: usize )
                                   -> *mut u8 {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot reallocate memory, no system allocator exists!")
             .reallocate(ptr, old_size, size, align)
             .unwrap_or(ptr::null_mut())
            //  .expect("Memory could not be reallocated; either the allocator\
            //          is out of memory, or the allocation request was invalid.")
     }
}

/// This is currently unsupported, so we just silently ignore it
/// and return the old size.
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace( ptr: *mut u8, old_size: usize
                                           , _size: usize, _align: usize )
                                           -> usize {
    old_size
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize {
    size
}
<commit_msg>[alloc] Remove commented-out cold<commit_after>//! This module integrates the buddy heap allocator into the Rust runtime.
use spin::Mutex;
use core::ptr;

use ::Allocator;
use super::{BuddyHeapAllocator, FreeList};

static ALLOC: Mutex<Option<BuddyHeapAllocator<'static>>>
    = Mutex::new(None);

static mut KERNEL_FREE_LISTS: [FreeList; 17]
    // TODO: I really wish there was a less awful way to do this...
    = [ FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      , FreeList::new()
      ];

pub unsafe fn init_heap(start_addr: *mut u8, heap_size: usize ) {
    trace!("init_heap() was called.");
    *(ALLOC.lock())
        = Some(BuddyHeapAllocator::new( start_addr
                                      , &mut KERNEL_FREE_LISTS
                                      , heap_size));
}

#[no_mangle]
pub extern "C" fn __rust_allocate(size: usize, align: usize) -> *mut u8 {
    trace!("__rust_allocate() was called.");
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot allocate memory, no system allocator exists!")
             .allocate(size, align)
             .map(|blck| {
                 trace!("__rust_allocate: allocatedd {:?}", blck);
                 blck })
             .unwrap_or(ptr::null_mut())
    }
}

#[no_mangle]
pub extern "C" fn __rust_deallocate( ptr: *mut u8, old_size: usize
                                   , align: usize ) {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot deallocate memory, no system allocator exists!")
             .deallocate(ptr, old_size, align)
    }
}

#[no_mangle]
pub extern "C" fn __rust_reallocate( ptr: *mut u8, old_size: usize
                                   , size: usize, align: usize )
                                   -> *mut u8 {
    unsafe {
        ALLOC.lock().as_mut()
             .expect("Cannot reallocate memory, no system allocator exists!")
             .reallocate(ptr, old_size, size, align)
             .unwrap_or(ptr::null_mut())
     }
}

/// This is currently unsupported, so we just silently ignore it
/// and return the old size.
#[no_mangle]
pub extern "C" fn __rust_reallocate_inplace( ptr: *mut u8, old_size: usize
                                           , _size: usize, _align: usize )
                                           -> usize {
    old_size
}

#[no_mangle]
pub extern "C" fn __rust_usable_size(size: usize, _align: usize) -> usize {
    size
}
<|endoftext|>