<commit_before>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed 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.

#![deny(missing_docs, missing_copy_implementations)]

//! Device resource handles

use std::mem;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use super::{shade, tex, Resources, BufferInfo};

/// A service trait to be used by the factory cleanup implementation
pub trait Bare<T> {
    /// Extract a bare handle
    unsafe fn bare(&self) -> T;
}

macro_rules! bare{
    ($name:ident) => {
        impl<R: Resources> Bare<R::$name> for $name<R> {
            unsafe fn bare(&self) -> R::$name { *self.0.deref() }
        }
    }
}

/// Type-safe buffer handle
#[derive(Clone, PartialEq, Debug)]
pub struct Buffer<R: Resources, T> {
    raw: RawBuffer<R>,
    phantom_t: PhantomData<T>,
}

impl<R: Resources, T> Buffer<R, T> {
    /// Create a type-safe BufferHandle from a RawBufferHandle
    pub fn from_raw(handle: RawBuffer<R>) -> Buffer<R, T> {
        Buffer {
            raw: handle,
            phantom_t: PhantomData,
        }
    }

    /// Cast the type this Buffer references
    pub fn cast<U>(self) -> Buffer<R, U> {
        Buffer::from_raw(self.raw)
    }

    /// Get the underlying raw Handle
    pub fn raw(&self) -> &RawBuffer<R> {
        &self.raw
    }

    /// Get the associated information about the buffer
    pub fn get_info(&self) -> &BufferInfo {
        self.raw.get_info()
    }

    /// Get the number of elements in the buffer.
    ///
    /// Fails if `T` is zero-sized.
    pub fn len(&self) -> usize {
        assert!(mem::size_of::<T>() != 0, "Cannot determine the length of zero-sized buffers.");
        self.get_info().size / mem::size_of::<T>()
    }
}

/// Raw (untyped) Buffer Handle
#[derive(Clone, PartialEq, Debug)]
pub struct RawBuffer<R: Resources>(Arc<R::Buffer>, BufferInfo);

impl<R: Resources> Bare<R::Buffer> for RawBuffer<R> {
    unsafe fn bare(&self) -> R::Buffer { *self.0.deref() }
}

impl<R: Resources> RawBuffer<R> {
    /// Get raw buffer info
    pub fn get_info(&self) -> &BufferInfo { &self.1 }
}

/// Array Buffer Handle
#[derive(Clone, PartialEq, Debug)]
pub struct ArrayBuffer<R: Resources>(Arc<R::ArrayBuffer>);
bare!(ArrayBuffer);

/// Shader Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Shader<R: Resources>(Arc<R::Shader>, shade::Stage);
bare!(Shader);

impl<R: Resources> Shader<R> {
    /// Get shader stage
    pub fn get_stage(&self) -> &shade::Stage { &self.1 }
}

/// Program Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Program<R: Resources>(Arc<R::Program>, shade::ProgramInfo);
bare!(Program);

impl<R: Resources> Program<R> {
    /// Get program info
    pub fn get_info(&self) -> &shade::ProgramInfo { &self.1 }
}

/// Frame Buffer Handle
#[derive(Clone, PartialEq, Debug)]
pub struct FrameBuffer<R: Resources>(Arc<R::FrameBuffer>);
bare!(FrameBuffer);

/// Surface Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Surface<R: Resources>(Arc<R::Surface>, tex::SurfaceInfo);
bare!(Surface);

impl<R: Resources> Surface<R> {
    /// Get surface info
    pub fn get_info(&self) -> &tex::SurfaceInfo { &self.1 }
}

/// Texture Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Texture<R: Resources>(Arc<R::Texture>, tex::TextureInfo);
bare!(Texture);

impl<R: Resources> Texture<R> {
    /// Get texture info
    pub fn get_info(&self) -> &tex::TextureInfo { &self.1 }
}

/// Sampler Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Sampler<R: Resources>(Arc<R::Sampler>, tex::SamplerInfo);
bare!(Sampler);

impl<R: Resources> Sampler<R> {
    /// Get sampler info
    pub fn get_info(&self) -> &tex::SamplerInfo { &self.1 }
}

/// Stores reference-counted resources used in a command buffer.
/// Seals actual resource names behind the interface, automatically
/// referencing them both by the Factory on resource creation
/// and the Renderer during CommandBuffer population.
#[allow(missing_docs)]
pub struct Manager<R: Resources> {
    buffers:       Vec<Arc<R::Buffer>>,
    array_buffers: Vec<Arc<R::ArrayBuffer>>,
    shaders:       Vec<Arc<R::Shader>>,
    programs:      Vec<Arc<R::Program>>,
    frame_buffers: Vec<Arc<R::FrameBuffer>>,
    surfaces:      Vec<Arc<R::Surface>>,
    textures:      Vec<Arc<R::Texture>>,
    samplers:      Vec<Arc<R::Sampler>>,
}

/// A service trait to be used by the device implementation
#[allow(missing_docs)]
pub trait Producer<R: Resources> {
    fn make_buffer(&mut self, R::Buffer, BufferInfo) -> RawBuffer<R>;
    fn make_array_buffer(&mut self, R::ArrayBuffer) -> ArrayBuffer<R>;
    fn make_shader(&mut self, R::Shader, shade::Stage) -> Shader<R>;
    fn make_program(&mut self, R::Program, shade::ProgramInfo) -> Program<R>;
    fn make_frame_buffer(&mut self, R::FrameBuffer) -> FrameBuffer<R>;
    fn make_surface(&mut self, R::Surface, tex::SurfaceInfo) -> Surface<R>;
    fn make_texture(&mut self, R::Texture, tex::TextureInfo) -> Texture<R>;
    fn make_sampler(&mut self, R::Sampler, tex::SamplerInfo) -> Sampler<R>;
    /// Walk through all the handles, keep ones that are reference elsewhere
    /// and call the provided delete function (resource-specific) for others
    fn clean_with<T,
        F1: Fn(&mut T, &R::Buffer),
        F2: Fn(&mut T, &R::ArrayBuffer),
        F3: Fn(&mut T, &R::Shader),
        F4: Fn(&mut T, &R::Program),
        F5: Fn(&mut T, &R::FrameBuffer),
        F6: Fn(&mut T, &R::Surface),
        F7: Fn(&mut T, &R::Texture),
        F8: Fn(&mut T, &R::Sampler),
    >(&mut self, &mut T, F1, F2, F3, F4, F5, F6, F7, F8);
}

impl<R: Resources> Producer<R> for Manager<R> {
    fn make_buffer(&mut self, name: R::Buffer, info: BufferInfo) -> RawBuffer<R> {
        let r = Arc::new(name);
        self.buffers.push(r.clone());
        RawBuffer(r, info)
    }

    fn make_array_buffer(&mut self, name: R::ArrayBuffer) -> ArrayBuffer<R> {
        let r = Arc::new(name);
        self.array_buffers.push(r.clone());
        ArrayBuffer(r)
    }

    fn make_shader(&mut self, name: R::Shader, info: shade::Stage) -> Shader<R> {
        let r = Arc::new(name);
        self.shaders.push(r.clone());
        Shader(r, info)
    }

    fn make_program(&mut self, name: R::Program, info: shade::ProgramInfo) -> Program<R> {
        let r = Arc::new(name);
        self.programs.push(r.clone());
        Program(r, info)
    }

    fn make_frame_buffer(&mut self, name: R::FrameBuffer) -> FrameBuffer<R> {
        let r = Arc::new(name);
        self.frame_buffers.push(r.clone());
        FrameBuffer(r)
    }

    fn make_surface(&mut self, name: R::Surface, info: tex::SurfaceInfo) -> Surface<R> {
        let r = Arc::new(name);
        self.surfaces.push(r.clone());
        Surface(r, info)
    }

    fn make_texture(&mut self, name: R::Texture, info: tex::TextureInfo) -> Texture<R> {
        let r = Arc::new(name);
        self.textures.push(r.clone());
        Texture(r, info)
    }

    fn make_sampler(&mut self, name: R::Sampler, info: tex::SamplerInfo) -> Sampler<R> {
        let r = Arc::new(name);
        self.samplers.push(r.clone());
        Sampler(r, info)
    }

    fn clean_with<T,
        F1: Fn(&mut T, &R::Buffer),
        F2: Fn(&mut T, &R::ArrayBuffer),
        F3: Fn(&mut T, &R::Shader),
        F4: Fn(&mut T, &R::Program),
        F5: Fn(&mut T, &R::FrameBuffer),
        F6: Fn(&mut T, &R::Surface),
        F7: Fn(&mut T, &R::Texture),
        F8: Fn(&mut T, &R::Sampler),
    >(&mut self, param: &mut T, f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7, f8: F8) {
        fn clean_vec<X, T, F: Fn(&mut T, &X)>(param: &mut T, vector: &mut Vec<Arc<X>>, fun: F) {
            use alloc::arc::{strong_count, weak_count};
            use std::ops::Deref;
            vector.retain(|v| {
                let free = strong_count(v) == 1 && weak_count(v) == 1;
                if free { fun(param, v.deref()); }
                !free
            });
        }
        clean_vec(param, &mut self.buffers,       f1);
        clean_vec(param, &mut self.array_buffers, f2);
        clean_vec(param, &mut self.shaders,       f3);
        clean_vec(param, &mut self.programs,      f4);
        clean_vec(param, &mut self.frame_buffers, f5);
        clean_vec(param, &mut self.surfaces,      f6);
        clean_vec(param, &mut self.textures,      f7);
        clean_vec(param, &mut self.samplers,      f8);
    }
}

impl<R: Resources> Manager<R> {
    /// Create a new handle manager
    pub fn new() -> Manager<R> {
        Manager {
            buffers: Vec::new(),
            array_buffers: Vec::new(),
            shaders: Vec::new(),
            programs: Vec::new(),
            frame_buffers: Vec::new(),
            surfaces: Vec::new(),
            textures: Vec::new(),
            samplers: Vec::new(),
        }
    }
    /// Clear all references
    pub fn clear(&mut self) {
        self.buffers.clear();
        self.array_buffers.clear();
        self.shaders.clear();
        self.programs.clear();
        self.frame_buffers.clear();
        self.surfaces.clear();
        self.textures.clear();
        self.samplers.clear();
    }
    /// Extend with all references of another handle manager
    pub fn extend(&mut self, other: &Manager<R>) {
        self.buffers      .extend(other.buffers      .iter().map(|h| h.clone()));
        self.array_buffers.extend(other.array_buffers.iter().map(|h| h.clone()));
        self.shaders      .extend(other.shaders      .iter().map(|h| h.clone()));
        self.programs     .extend(other.programs     .iter().map(|h| h.clone()));
        self.frame_buffers.extend(other.frame_buffers.iter().map(|h| h.clone()));
        self.surfaces     .extend(other.surfaces     .iter().map(|h| h.clone()));
        self.textures     .extend(other.textures     .iter().map(|h| h.clone()));
        self.samplers     .extend(other.samplers     .iter().map(|h| h.clone()));
    }
    /// Count the total number of referenced resources
    pub fn count(&self) -> usize {
        self.buffers.len() +
        self.array_buffers.len() +
        self.shaders.len() +
        self.programs.len() +
        self.frame_buffers.len() +
        self.surfaces.len() +
        self.textures.len() +
        self.samplers.len()
    }
    /// Reference a buffer
    pub fn ref_buffer(&mut self, handle: &RawBuffer<R>) -> R::Buffer {
        self.buffers.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference am array buffer
    pub fn ref_array_buffer(&mut self, handle: &ArrayBuffer<R>) -> R::ArrayBuffer {
        self.array_buffers.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a shader
    pub fn ref_shader(&mut self, handle: &Shader<R>) -> R::Shader {
        self.shaders.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a program
    pub fn ref_program(&mut self, handle: &Program<R>) -> R::Program {
        self.programs.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a frame buffer
    pub fn ref_frame_buffer(&mut self, handle: &FrameBuffer<R>) -> R::FrameBuffer {
        self.frame_buffers.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a surface
    pub fn ref_surface(&mut self, handle: &Surface<R>) -> R::Surface {
        self.surfaces.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a texture
    pub fn ref_texture(&mut self, handle: &Texture<R>) -> R::Texture {
        self.textures.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a sampler
    pub fn ref_sampler(&mut self, handle: &Sampler<R>) -> R::Sampler {
        self.samplers.push(handle.0.clone());
        *handle.0.deref()
    }
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::marker::PhantomData;
    use device::{BufferInfo, BufferUsage, Resources};

    #[derive(Clone, Debug, PartialEq)]
    enum TestResources {}
    impl Resources for TestResources {
        type Buffer = ();
        type ArrayBuffer = ();
        type Shader = ();
        type Program = ();
        type FrameBuffer = ();
        type Surface = ();
        type Texture = ();
        type Sampler = ();
    }

    fn mock_buffer<T>(len: usize) -> super::Buffer<TestResources, T> {
        use super::Producer;
        let mut handler = super::Manager::new();
        super::Buffer {
            raw: handler.make_buffer((), BufferInfo {
                    usage: BufferUsage::Static,
                    size: mem::size_of::<T>() * len,
            }),
            phantom_t: PhantomData,
        }
    }

    #[test]
    fn test_buffer_len() {
        assert_eq!(mock_buffer::<u8>(8).len(), 8);
        assert_eq!(mock_buffer::<u16>(8).len(), 8);
    }

    #[test]
    #[should_fail]
    fn test_buffer_zero_len() {
        let _ = mock_buffer::<()>(0).len();
    }
}
<commit_msg>Added a test for resource cleanup<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed 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.

#![deny(missing_docs, missing_copy_implementations)]

//! Device resource handles

use std::mem;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use super::{shade, tex, Resources, BufferInfo};

/// A service trait to be used by the factory cleanup implementation
pub trait Bare<T> {
    /// Extract a bare handle
    unsafe fn bare(&self) -> T;
}

macro_rules! bare{
    ($name:ident) => {
        impl<R: Resources> Bare<R::$name> for $name<R> {
            unsafe fn bare(&self) -> R::$name { *self.0.deref() }
        }
    }
}

/// Type-safe buffer handle
#[derive(Clone, PartialEq, Debug)]
pub struct Buffer<R: Resources, T> {
    raw: RawBuffer<R>,
    phantom_t: PhantomData<T>,
}

impl<R: Resources, T> Buffer<R, T> {
    /// Create a type-safe BufferHandle from a RawBufferHandle
    pub fn from_raw(handle: RawBuffer<R>) -> Buffer<R, T> {
        Buffer {
            raw: handle,
            phantom_t: PhantomData,
        }
    }

    /// Cast the type this Buffer references
    pub fn cast<U>(self) -> Buffer<R, U> {
        Buffer::from_raw(self.raw)
    }

    /// Get the underlying raw Handle
    pub fn raw(&self) -> &RawBuffer<R> {
        &self.raw
    }

    /// Get the associated information about the buffer
    pub fn get_info(&self) -> &BufferInfo {
        self.raw.get_info()
    }

    /// Get the number of elements in the buffer.
    ///
    /// Fails if `T` is zero-sized.
    pub fn len(&self) -> usize {
        assert!(mem::size_of::<T>() != 0, "Cannot determine the length of zero-sized buffers.");
        self.get_info().size / mem::size_of::<T>()
    }
}

/// Raw (untyped) Buffer Handle
#[derive(Clone, PartialEq, Debug)]
pub struct RawBuffer<R: Resources>(Arc<R::Buffer>, BufferInfo);

impl<R: Resources> Bare<R::Buffer> for RawBuffer<R> {
    unsafe fn bare(&self) -> R::Buffer { *self.0.deref() }
}

impl<R: Resources> RawBuffer<R> {
    /// Get raw buffer info
    pub fn get_info(&self) -> &BufferInfo { &self.1 }
}

/// Array Buffer Handle
#[derive(Clone, PartialEq, Debug)]
pub struct ArrayBuffer<R: Resources>(Arc<R::ArrayBuffer>);
bare!(ArrayBuffer);

/// Shader Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Shader<R: Resources>(Arc<R::Shader>, shade::Stage);
bare!(Shader);

impl<R: Resources> Shader<R> {
    /// Get shader stage
    pub fn get_stage(&self) -> &shade::Stage { &self.1 }
}

/// Program Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Program<R: Resources>(Arc<R::Program>, shade::ProgramInfo);
bare!(Program);

impl<R: Resources> Program<R> {
    /// Get program info
    pub fn get_info(&self) -> &shade::ProgramInfo { &self.1 }
}

/// Frame Buffer Handle
#[derive(Clone, PartialEq, Debug)]
pub struct FrameBuffer<R: Resources>(Arc<R::FrameBuffer>);
bare!(FrameBuffer);

/// Surface Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Surface<R: Resources>(Arc<R::Surface>, tex::SurfaceInfo);
bare!(Surface);

impl<R: Resources> Surface<R> {
    /// Get surface info
    pub fn get_info(&self) -> &tex::SurfaceInfo { &self.1 }
}

/// Texture Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Texture<R: Resources>(Arc<R::Texture>, tex::TextureInfo);
bare!(Texture);

impl<R: Resources> Texture<R> {
    /// Get texture info
    pub fn get_info(&self) -> &tex::TextureInfo { &self.1 }
}

/// Sampler Handle
#[derive(Clone, PartialEq, Debug)]
pub struct Sampler<R: Resources>(Arc<R::Sampler>, tex::SamplerInfo);
bare!(Sampler);

impl<R: Resources> Sampler<R> {
    /// Get sampler info
    pub fn get_info(&self) -> &tex::SamplerInfo { &self.1 }
}

/// Stores reference-counted resources used in a command buffer.
/// Seals actual resource names behind the interface, automatically
/// referencing them both by the Factory on resource creation
/// and the Renderer during CommandBuffer population.
#[allow(missing_docs)]
pub struct Manager<R: Resources> {
    buffers:       Vec<Arc<R::Buffer>>,
    array_buffers: Vec<Arc<R::ArrayBuffer>>,
    shaders:       Vec<Arc<R::Shader>>,
    programs:      Vec<Arc<R::Program>>,
    frame_buffers: Vec<Arc<R::FrameBuffer>>,
    surfaces:      Vec<Arc<R::Surface>>,
    textures:      Vec<Arc<R::Texture>>,
    samplers:      Vec<Arc<R::Sampler>>,
}

/// A service trait to be used by the device implementation
#[allow(missing_docs)]
pub trait Producer<R: Resources> {
    fn make_buffer(&mut self, R::Buffer, BufferInfo) -> RawBuffer<R>;
    fn make_array_buffer(&mut self, R::ArrayBuffer) -> ArrayBuffer<R>;
    fn make_shader(&mut self, R::Shader, shade::Stage) -> Shader<R>;
    fn make_program(&mut self, R::Program, shade::ProgramInfo) -> Program<R>;
    fn make_frame_buffer(&mut self, R::FrameBuffer) -> FrameBuffer<R>;
    fn make_surface(&mut self, R::Surface, tex::SurfaceInfo) -> Surface<R>;
    fn make_texture(&mut self, R::Texture, tex::TextureInfo) -> Texture<R>;
    fn make_sampler(&mut self, R::Sampler, tex::SamplerInfo) -> Sampler<R>;
    /// Walk through all the handles, keep ones that are reference elsewhere
    /// and call the provided delete function (resource-specific) for others
    fn clean_with<T,
        F1: Fn(&mut T, &R::Buffer),
        F2: Fn(&mut T, &R::ArrayBuffer),
        F3: Fn(&mut T, &R::Shader),
        F4: Fn(&mut T, &R::Program),
        F5: Fn(&mut T, &R::FrameBuffer),
        F6: Fn(&mut T, &R::Surface),
        F7: Fn(&mut T, &R::Texture),
        F8: Fn(&mut T, &R::Sampler),
    >(&mut self, &mut T, F1, F2, F3, F4, F5, F6, F7, F8);
}

impl<R: Resources> Producer<R> for Manager<R> {
    fn make_buffer(&mut self, name: R::Buffer, info: BufferInfo) -> RawBuffer<R> {
        let r = Arc::new(name);
        self.buffers.push(r.clone());
        RawBuffer(r, info)
    }

    fn make_array_buffer(&mut self, name: R::ArrayBuffer) -> ArrayBuffer<R> {
        let r = Arc::new(name);
        self.array_buffers.push(r.clone());
        ArrayBuffer(r)
    }

    fn make_shader(&mut self, name: R::Shader, info: shade::Stage) -> Shader<R> {
        let r = Arc::new(name);
        self.shaders.push(r.clone());
        Shader(r, info)
    }

    fn make_program(&mut self, name: R::Program, info: shade::ProgramInfo) -> Program<R> {
        let r = Arc::new(name);
        self.programs.push(r.clone());
        Program(r, info)
    }

    fn make_frame_buffer(&mut self, name: R::FrameBuffer) -> FrameBuffer<R> {
        let r = Arc::new(name);
        self.frame_buffers.push(r.clone());
        FrameBuffer(r)
    }

    fn make_surface(&mut self, name: R::Surface, info: tex::SurfaceInfo) -> Surface<R> {
        let r = Arc::new(name);
        self.surfaces.push(r.clone());
        Surface(r, info)
    }

    fn make_texture(&mut self, name: R::Texture, info: tex::TextureInfo) -> Texture<R> {
        let r = Arc::new(name);
        self.textures.push(r.clone());
        Texture(r, info)
    }

    fn make_sampler(&mut self, name: R::Sampler, info: tex::SamplerInfo) -> Sampler<R> {
        let r = Arc::new(name);
        self.samplers.push(r.clone());
        Sampler(r, info)
    }

    fn clean_with<T,
        F1: Fn(&mut T, &R::Buffer),
        F2: Fn(&mut T, &R::ArrayBuffer),
        F3: Fn(&mut T, &R::Shader),
        F4: Fn(&mut T, &R::Program),
        F5: Fn(&mut T, &R::FrameBuffer),
        F6: Fn(&mut T, &R::Surface),
        F7: Fn(&mut T, &R::Texture),
        F8: Fn(&mut T, &R::Sampler),
    >(&mut self, param: &mut T, f1: F1, f2: F2, f3: F3, f4: F4, f5: F5, f6: F6, f7: F7, f8: F8) {
        fn clean_vec<X, T, F: Fn(&mut T, &X)>(param: &mut T, vector: &mut Vec<Arc<X>>, fun: F) {
            use alloc::arc::{strong_count, weak_count};
            use std::ops::Deref;
            vector.retain(|v| {
                let free = strong_count(v) == 1 && weak_count(v) == 0;
                if free { fun(param, v.deref()); }
                !free
            });
        }
        clean_vec(param, &mut self.buffers,       f1);
        clean_vec(param, &mut self.array_buffers, f2);
        clean_vec(param, &mut self.shaders,       f3);
        clean_vec(param, &mut self.programs,      f4);
        clean_vec(param, &mut self.frame_buffers, f5);
        clean_vec(param, &mut self.surfaces,      f6);
        clean_vec(param, &mut self.textures,      f7);
        clean_vec(param, &mut self.samplers,      f8);
    }
}

impl<R: Resources> Manager<R> {
    /// Create a new handle manager
    pub fn new() -> Manager<R> {
        Manager {
            buffers: Vec::new(),
            array_buffers: Vec::new(),
            shaders: Vec::new(),
            programs: Vec::new(),
            frame_buffers: Vec::new(),
            surfaces: Vec::new(),
            textures: Vec::new(),
            samplers: Vec::new(),
        }
    }
    /// Clear all references
    pub fn clear(&mut self) {
        self.buffers.clear();
        self.array_buffers.clear();
        self.shaders.clear();
        self.programs.clear();
        self.frame_buffers.clear();
        self.surfaces.clear();
        self.textures.clear();
        self.samplers.clear();
    }
    /// Extend with all references of another handle manager
    pub fn extend(&mut self, other: &Manager<R>) {
        self.buffers      .extend(other.buffers      .iter().map(|h| h.clone()));
        self.array_buffers.extend(other.array_buffers.iter().map(|h| h.clone()));
        self.shaders      .extend(other.shaders      .iter().map(|h| h.clone()));
        self.programs     .extend(other.programs     .iter().map(|h| h.clone()));
        self.frame_buffers.extend(other.frame_buffers.iter().map(|h| h.clone()));
        self.surfaces     .extend(other.surfaces     .iter().map(|h| h.clone()));
        self.textures     .extend(other.textures     .iter().map(|h| h.clone()));
        self.samplers     .extend(other.samplers     .iter().map(|h| h.clone()));
    }
    /// Count the total number of referenced resources
    pub fn count(&self) -> usize {
        self.buffers.len() +
        self.array_buffers.len() +
        self.shaders.len() +
        self.programs.len() +
        self.frame_buffers.len() +
        self.surfaces.len() +
        self.textures.len() +
        self.samplers.len()
    }
    /// Reference a buffer
    pub fn ref_buffer(&mut self, handle: &RawBuffer<R>) -> R::Buffer {
        self.buffers.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference am array buffer
    pub fn ref_array_buffer(&mut self, handle: &ArrayBuffer<R>) -> R::ArrayBuffer {
        self.array_buffers.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a shader
    pub fn ref_shader(&mut self, handle: &Shader<R>) -> R::Shader {
        self.shaders.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a program
    pub fn ref_program(&mut self, handle: &Program<R>) -> R::Program {
        self.programs.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a frame buffer
    pub fn ref_frame_buffer(&mut self, handle: &FrameBuffer<R>) -> R::FrameBuffer {
        self.frame_buffers.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a surface
    pub fn ref_surface(&mut self, handle: &Surface<R>) -> R::Surface {
        self.surfaces.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a texture
    pub fn ref_texture(&mut self, handle: &Texture<R>) -> R::Texture {
        self.textures.push(handle.0.clone());
        *handle.0.deref()
    }
    /// Reference a sampler
    pub fn ref_sampler(&mut self, handle: &Sampler<R>) -> R::Sampler {
        self.samplers.push(handle.0.clone());
        *handle.0.deref()
    }
}

#[cfg(test)]
mod test {
    use std::mem;
    use std::marker::PhantomData;
    use device::{BufferInfo, BufferUsage, Resources};

    #[derive(Clone, Debug, PartialEq)]
    enum TestResources {}
    impl Resources for TestResources {
        type Buffer = ();
        type ArrayBuffer = ();
        type Shader = ();
        type Program = ();
        type FrameBuffer = ();
        type Surface = ();
        type Texture = ();
        type Sampler = ();
    }

    fn mock_buffer<T>(len: usize) -> super::Buffer<TestResources, T> {
        use super::{Manager, Producer};
        let mut handler = Manager::new();
        super::Buffer {
            raw: handler.make_buffer((), BufferInfo {
                    usage: BufferUsage::Static,
                    size: mem::size_of::<T>() * len,
            }),
            phantom_t: PhantomData,
        }
    }

    #[test]
    fn test_buffer_len() {
        assert_eq!(mock_buffer::<u8>(8).len(), 8);
        assert_eq!(mock_buffer::<u16>(8).len(), 8);
    }

    #[test]
    #[should_fail]
    fn test_buffer_zero_len() {
        let _ = mock_buffer::<()>(0).len();
    }

    #[test]
    fn test_cleanup() {
        use super::{Manager, Producer};
        let mut man: Manager<TestResources> = Manager::new();
        let _ = man.make_frame_buffer(());
        let mut count = 0u8;
        man.clean_with(&mut count,
            |_,_| (),
            |_,_| (),
            |_,_| (),
            |_,_| (),
            |b,_| { *b += 1; },
            |_,_| (),
            |_,_| (),
            |_,_| ()
            );
        assert_eq!(count, 1);
    }
}
<|endoftext|>


<commit_before>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use std::error::Error;
use std::str::FromStr;
use std::net::SocketAddrV4;

#[derive(Debug)]
pub struct ELBRecord {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: SocketAddrV4,
    backend_address: SocketAddrV4,
    request_processing_time: f32,
    backend_processing_time: f32,
    response_processing_time: f32,
    elb_status_code: u16,
    backend_status_code: u16,
    received_bytes: u64,
    sent_bytes: u64,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

//TODO Reconsider logging based on the standard interfaces included with Rust.
//TODO We really want to accept a function to handle the parsed lines.
pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|possible_line| {
                        match possible_line {
                            Ok(record) => parse_record(record),

                            Err(_) => {
                                Err(ParsingErrors {
                                    record: "".to_string(),
                                    errors: vec![ELBRecordParsingErrors::LineReadError]
                                })
                            }
                        }
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

//TODO Take a look at the error handling once again.  This doesn't feel write given code you've read.

#[derive(Debug)]
pub struct ParsingErrors {
    record: String,
    errors: Vec<ELBRecordParsingErrors>,
}

#[derive(Debug, PartialEq)]
enum ELBRecordParsingErrors {
    MalformedRecord,
    ParsingError { property: &'static str, description: String },
    LineReadError
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum ELBRecordFields {
    Timestamp = 0,
    ELBName,
    ClientAddress,
    BackendAddress,
    RequestProcessingTime,
    BackendProcessingTime,
    ResponseProcessingTime,
    ELBStatusCode,
    BackendStatusCode,
    ReceivedBytes,
    SentBytes,
    RequestMethod,
    RequestURL,
    RequestHTTPVersion
}

impl ELBRecordFields {

  fn idx(self) -> usize {
    self as usize
  }

  fn as_str(self) -> &'static str {
      match self {
          ELBRecordFields::Timestamp => "timestamp",
          ELBRecordFields::ELBName => "ELB name",
          ELBRecordFields::ClientAddress => "client address",
          ELBRecordFields::BackendAddress => "backend address",
          ELBRecordFields::RequestProcessingTime => "request processing time",
          ELBRecordFields::BackendProcessingTime => "backend processing time",
          ELBRecordFields::ResponseProcessingTime => "response processing time",
          ELBRecordFields::ELBStatusCode => "ELB status code",
          ELBRecordFields::BackendStatusCode => "backend status code",
          ELBRecordFields::ReceivedBytes => "received bytes",
          ELBRecordFields::SentBytes => "sent bytes",
          ELBRecordFields::RequestMethod => "request method",
          ELBRecordFields::RequestURL => "request URL",
          ELBRecordFields::RequestHTTPVersion => "request HTTP version"
      }
  }
}

const ELB_RECORD_FIELD_COUNT: usize = 14;
pub fn parse_record(record: String) -> Result<Box<ELBRecord>, ParsingErrors> {
    let mut errors: Vec<ELBRecordParsingErrors> = Vec::new();

    {
        //record is borrowed by the split method which means ownership of record cannot be
        //transferred to ParsingErrors until the borrow is complete.
        //Scoping this section of code seems more readable than creating a separate function
        //just to mitigate the borrow.
        let split_line: Vec<&str> = record.split(' ').collect();
        if split_line.len() != ELB_RECORD_FIELD_COUNT {
            errors.push(ELBRecordParsingErrors::MalformedRecord);
            None
        } else {
            let ts = split_line.parse_property(ELBRecordFields::Timestamp, &mut errors);
            let clnt_addr = split_line.parse_property(ELBRecordFields::ClientAddress, &mut errors);
            let be_addr = split_line.parse_property(ELBRecordFields::BackendAddress, &mut errors);
            let req_proc_time = split_line.parse_property(ELBRecordFields::RequestProcessingTime, &mut errors);
            let be_proc_time = split_line.parse_property(ELBRecordFields::BackendProcessingTime, &mut errors);
            let res_proc_time = split_line.parse_property(ELBRecordFields::ResponseProcessingTime, &mut errors);
            let elb_sc = split_line.parse_property(ELBRecordFields::ELBStatusCode, &mut errors);
            let be_sc = split_line.parse_property(ELBRecordFields::BackendStatusCode, &mut errors);
            let bytes_received = split_line.parse_property(ELBRecordFields::ReceivedBytes, &mut errors);
            let bytes_sent = split_line.parse_property(ELBRecordFields::SentBytes, &mut errors);

            if errors.is_empty() {
                //If errors is empty it is more than likely parsing was successful and unwrap is safe.
                Some(
                    ELBRecord {
                        timestamp: ts.unwrap(),
                        elb_name: split_line[ELBRecordFields::ELBName.idx()].to_string(),
                        client_address: clnt_addr.unwrap(),
                        backend_address: be_addr.unwrap(),
                        request_processing_time: req_proc_time.unwrap(),
                        backend_processing_time: be_proc_time.unwrap(),
                        response_processing_time: res_proc_time.unwrap(),
                        elb_status_code: elb_sc.unwrap(),
                        backend_status_code: be_sc.unwrap(),
                        received_bytes: bytes_received.unwrap(),
                        sent_bytes: bytes_sent.unwrap(),
                        request_method: split_line[ELBRecordFields::RequestMethod.idx()].trim_matches('"').to_string(),
                        request_url: split_line[ELBRecordFields::RequestURL.idx()].to_string(),
                        request_http_version: split_line[ELBRecordFields::RequestHTTPVersion.idx()].trim_matches('"').to_string()
                    }
                )
            } else {
                None
            }
        }
    }.map( |elb_rec|
        Ok(Box::new(elb_rec))
    ).unwrap_or_else( ||
        Err(ParsingErrors {
            record: record,
            errors: errors
        })
    )
}

trait ELBRecordFieldParser {
    fn parse_property<T>(
        &self,
        field_id: ELBRecordFields,
        errors: &mut Vec<ELBRecordParsingErrors>
    ) -> Option<T>
        where T: FromStr,
        T::Err: Error + 'static;
}

impl<'a> ELBRecordFieldParser for Vec<&'a str> {

    fn parse_property<T>(
        &self,
        field_id: ELBRecordFields,
        errors: &mut Vec<ELBRecordParsingErrors>
    ) -> Option<T>
        where T: FromStr,
        T::Err: Error + 'static,
    {
        let raw_prop = self[field_id.idx()];
        match raw_prop.parse::<T>() {
            Ok(parsed) => Some(parsed),

            Err(e) => {
                errors.push(
                    ELBRecordParsingErrors::ParsingError {
                        property: field_id.as_str(),
                        description: e.description().to_string(),
                    }
                );
                None
            }
        }
    }
}

//TODO test the error case.
#[cfg(test)]
mod tests {
    use super::parse_record;
    use super::ELBRecordParsingErrors;

    const TEST_RECORD: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\"\
    ";

    #[test]
	fn parse_record_returns_a_malformed_record_error_for_records_short_on_values() {
        let short_record = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
        172.16.1.5:9000 0.000039 200 200 0 7582 \
        \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
        ";

        let malformed_error = parse_record(short_record.to_string()).unwrap_err().errors.pop();

		assert_eq!(malformed_error, Some(ELBRecordParsingErrors::MalformedRecord))
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_http_version() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_url() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_method() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_method, "GET")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_sent_bytes() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.sent_bytes, 7582)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_received_bytes() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.received_bytes, 0)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_status_code() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_status_code, 200)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_elb_status_code() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.elb_status_code, 200)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_response_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.response_processing_time, 0.00003)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_processing_time, 0.145507)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_address() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_address, "172.16.1.5:9000".parse().unwrap())
	}

    #[test]
	fn parse_record_returns_a_record_with_the_client_address() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.client_address, "172.16.1.6:54814".parse().unwrap())
	}

    #[test]
	fn parse_record_returns_a_record_with_the_timestamp() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_record.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_elb_name() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.elb_name, "elb-name")
	}
}
<commit_msg>Changed the ELBRecordFields.as_str method take a borrow of self.<commit_after>extern crate walkdir;
extern crate chrono;

use std::path;
use self::walkdir::{WalkDir, DirEntry, Error as WalkDirError};
use std::fs::File;
use std::io::BufReader;
use std::io::BufRead;
use self::chrono::{DateTime, UTC};
use std::error::Error;
use std::str::FromStr;
use std::net::SocketAddrV4;

#[derive(Debug)]
pub struct ELBRecord {
    timestamp: DateTime<UTC>,
    elb_name: String,
    client_address: SocketAddrV4,
    backend_address: SocketAddrV4,
    request_processing_time: f32,
    backend_processing_time: f32,
    response_processing_time: f32,
    elb_status_code: u16,
    backend_status_code: u16,
    received_bytes: u64,
    sent_bytes: u64,
    request_method: String,
    request_url: String,
    request_http_version: String
}

pub fn file_list(dir: &path::Path, filenames: &mut Vec<DirEntry>) -> Result<usize, WalkDirError> {
    for entry in WalkDir::new(dir).min_depth(1) {
        match entry {
            Err(err) => return Err(err),
            Ok(entry) => filenames.push(entry),
        }
    }
    Ok(filenames.len())
}

//TODO Reconsider logging based on the standard interfaces included with Rust.
//TODO We really want to accept a function to handle the parsed lines.
pub fn process_files(runtime_context: &::RuntimeContext, filenames: Vec<walkdir::DirEntry>) -> usize {
    let debug = runtime_context.debug;
    let mut record_count = 0;
    for filename in filenames {
        debug!(debug, "Processing file {}.", filename.path().display());
        match File::open(filename.path()) {
            Ok(file) => {
                let buffered_file = BufReader::new(&file);
                let recs: Vec<_> = buffered_file.lines()
                    .map(|possible_line| {
                        match possible_line {
                            Ok(record) => parse_record(record),

                            Err(_) => {
                                Err(ParsingErrors {
                                    record: "".to_string(),
                                    errors: vec![ELBRecordParsingErrors::LineReadError]
                                })
                            }
                        }
                    })
                    .collect();
                record_count += recs.len();
                debug!(debug, "Found {} records in file {}.", recs.len(), filename.path().display());
            },
            Err(e) => {
                println!("ERROR: {}", e);
            }
        }
    }

    record_count
}

//TODO Take a look at the error handling once again.  This doesn't feel write given code you've read.

#[derive(Debug)]
pub struct ParsingErrors {
    record: String,
    errors: Vec<ELBRecordParsingErrors>,
}

#[derive(Debug, PartialEq)]
enum ELBRecordParsingErrors {
    MalformedRecord,
    ParsingError { property: &'static str, description: String },
    LineReadError
}

#[derive(Debug, PartialEq, Clone, Copy)]
enum ELBRecordFields {
    Timestamp = 0,
    ELBName,
    ClientAddress,
    BackendAddress,
    RequestProcessingTime,
    BackendProcessingTime,
    ResponseProcessingTime,
    ELBStatusCode,
    BackendStatusCode,
    ReceivedBytes,
    SentBytes,
    RequestMethod,
    RequestURL,
    RequestHTTPVersion
}

impl ELBRecordFields {

  fn idx(self) -> usize {
    self as usize
  }

  fn as_str(&self) -> &'static str {
      match *self {
          ELBRecordFields::Timestamp => "timestamp",
          ELBRecordFields::ELBName => "ELB name",
          ELBRecordFields::ClientAddress => "client address",
          ELBRecordFields::BackendAddress => "backend address",
          ELBRecordFields::RequestProcessingTime => "request processing time",
          ELBRecordFields::BackendProcessingTime => "backend processing time",
          ELBRecordFields::ResponseProcessingTime => "response processing time",
          ELBRecordFields::ELBStatusCode => "ELB status code",
          ELBRecordFields::BackendStatusCode => "backend status code",
          ELBRecordFields::ReceivedBytes => "received bytes",
          ELBRecordFields::SentBytes => "sent bytes",
          ELBRecordFields::RequestMethod => "request method",
          ELBRecordFields::RequestURL => "request URL",
          ELBRecordFields::RequestHTTPVersion => "request HTTP version"
      }
  }
}

const ELB_RECORD_FIELD_COUNT: usize = 14;
pub fn parse_record(record: String) -> Result<Box<ELBRecord>, ParsingErrors> {
    let mut errors: Vec<ELBRecordParsingErrors> = Vec::new();

    {
        //record is borrowed by the split method which means ownership of record cannot be
        //transferred to ParsingErrors until the borrow is complete.
        //Scoping this section of code seems more readable than creating a separate function
        //just to mitigate the borrow.
        let split_line: Vec<&str> = record.split(' ').collect();
        if split_line.len() != ELB_RECORD_FIELD_COUNT {
            errors.push(ELBRecordParsingErrors::MalformedRecord);
            None
        } else {
            let ts = split_line.parse_property(ELBRecordFields::Timestamp, &mut errors);
            let clnt_addr = split_line.parse_property(ELBRecordFields::ClientAddress, &mut errors);
            let be_addr = split_line.parse_property(ELBRecordFields::BackendAddress, &mut errors);
            let req_proc_time = split_line.parse_property(ELBRecordFields::RequestProcessingTime, &mut errors);
            let be_proc_time = split_line.parse_property(ELBRecordFields::BackendProcessingTime, &mut errors);
            let res_proc_time = split_line.parse_property(ELBRecordFields::ResponseProcessingTime, &mut errors);
            let elb_sc = split_line.parse_property(ELBRecordFields::ELBStatusCode, &mut errors);
            let be_sc = split_line.parse_property(ELBRecordFields::BackendStatusCode, &mut errors);
            let bytes_received = split_line.parse_property(ELBRecordFields::ReceivedBytes, &mut errors);
            let bytes_sent = split_line.parse_property(ELBRecordFields::SentBytes, &mut errors);

            if errors.is_empty() {
                //If errors is empty it is more than likely parsing was successful and unwrap is safe.
                Some(
                    ELBRecord {
                        timestamp: ts.unwrap(),
                        elb_name: split_line[ELBRecordFields::ELBName.idx()].to_string(),
                        client_address: clnt_addr.unwrap(),
                        backend_address: be_addr.unwrap(),
                        request_processing_time: req_proc_time.unwrap(),
                        backend_processing_time: be_proc_time.unwrap(),
                        response_processing_time: res_proc_time.unwrap(),
                        elb_status_code: elb_sc.unwrap(),
                        backend_status_code: be_sc.unwrap(),
                        received_bytes: bytes_received.unwrap(),
                        sent_bytes: bytes_sent.unwrap(),
                        request_method: split_line[ELBRecordFields::RequestMethod.idx()].trim_matches('"').to_string(),
                        request_url: split_line[ELBRecordFields::RequestURL.idx()].to_string(),
                        request_http_version: split_line[ELBRecordFields::RequestHTTPVersion.idx()].trim_matches('"').to_string()
                    }
                )
            } else {
                None
            }
        }
    }.map( |elb_rec|
        Ok(Box::new(elb_rec))
    ).unwrap_or_else( ||
        Err(ParsingErrors {
            record: record,
            errors: errors
        })
    )
}

trait ELBRecordFieldParser {
    fn parse_property<T>(
        &self,
        field_id: ELBRecordFields,
        errors: &mut Vec<ELBRecordParsingErrors>
    ) -> Option<T>
        where T: FromStr,
        T::Err: Error + 'static;
}

impl<'a> ELBRecordFieldParser for Vec<&'a str> {

    fn parse_property<T>(
        &self,
        field_id: ELBRecordFields,
        errors: &mut Vec<ELBRecordParsingErrors>
    ) -> Option<T>
        where T: FromStr,
        T::Err: Error + 'static,
    {
        let raw_prop = self[field_id.idx()];
        match raw_prop.parse::<T>() {
            Ok(parsed) => Some(parsed),

            Err(e) => {
                errors.push(
                    ELBRecordParsingErrors::ParsingError {
                        property: field_id.as_str(),
                        description: e.description().to_string(),
                    }
                );
                None
            }
        }
    }
}

//TODO test the error case.
#[cfg(test)]
mod tests {
    use super::parse_record;
    use super::ELBRecordParsingErrors;

    const TEST_RECORD: &'static str = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
    172.16.1.5:9000 0.000039 0.145507 0.00003 200 200 0 7582 \
    \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\"\
    ";

    #[test]
	fn parse_record_returns_a_malformed_record_error_for_records_short_on_values() {
        let short_record = "2015-08-15T23:43:05.302180Z elb-name 172.16.1.6:54814 \
        172.16.1.5:9000 0.000039 200 200 0 7582 \
        \"GET http://some.domain.com:80/path0/path1?param0=p0&param1=p1 HTTP/1.1\" \
        ";

        let malformed_error = parse_record(short_record.to_string()).unwrap_err().errors.pop();

		assert_eq!(malformed_error, Some(ELBRecordParsingErrors::MalformedRecord))
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_http_version() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_http_version, "HTTP/1.1")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_url() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_url, "http://some.domain.com:80/path0/path1?param0=p0&param1=p1")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_method() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_method, "GET")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_sent_bytes() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.sent_bytes, 7582)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_received_bytes() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.received_bytes, 0)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_status_code() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_status_code, 200)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_elb_status_code() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.elb_status_code, 200)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_response_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.response_processing_time, 0.00003)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_processing_time, 0.145507)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_request_processing_time() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.request_processing_time, 0.000039)
	}

    #[test]
	fn parse_record_returns_a_record_with_the_backend_address() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.backend_address, "172.16.1.5:9000".parse().unwrap())
	}

    #[test]
	fn parse_record_returns_a_record_with_the_client_address() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.client_address, "172.16.1.6:54814".parse().unwrap())
	}

    #[test]
	fn parse_record_returns_a_record_with_the_timestamp() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(format!("{:?}", elb_record.timestamp), "2015-08-15T23:43:05.302180Z")
	}

    #[test]
	fn parse_record_returns_a_record_with_the_elb_name() {
        let elb_record = parse_record(TEST_RECORD.to_string()).unwrap();

		assert_eq!(elb_record.elb_name, "elb-name")
	}
}
<|endoftext|>


<commit_before>use piston_window;
use gfx_device_gl::{Resources, Output, CommandBuffer};
use gfx_graphics::GfxGraphics;
use piston_window::Transformed;

pub struct Object {
    x: f64,
    y: f64,
    sprite: Option<piston_window::Texture<Resources>>,
}

impl Object {
    pub fn new() -> Object {
        Object { x: 0., y: 0., sprite: None }
    }

    pub fn mov(&mut self, x: f64, y: f64) {
        self.x += x;
        self.y += y;
    }

    pub fn mov_to(&mut self, x: f64, y: f64) {
        self.x = x;
        self.y = y;
    }

    pub fn set_sprite(&mut self, sprite: piston_window::Texture<Resources>) {
        self.sprite = Some(sprite);
    }

    pub fn render(&self, graphic: &mut GfxGraphics<Resources, CommandBuffer<Resources>, Output>, view: &piston_window::math::Matrix2d) {
        match self.sprite {
            None => {
                let red = [1.0, 0.0, 0.0, 1.0];
                let square = piston_window::rectangle::square(0.0, 0.0, 100.0);
                piston_window::rectangle(red, square, view.trans(self.x, self.y).trans(-50.0, -50.0), graphic);
            }
            Some(ref sprite) => {
                piston_window::image(sprite, view.trans(self.x, self.y).trans(-50.0, -50.0), graphic);
            }
        }
    }
}

#[test]
fn object_new() {
    let object = Object::new();
    assert_eq!(object.x, 0.0);
    assert_eq!(object.y, 0.0);
}

#[test]
fn object_mov() {
    let mut object = Object::new();
    assert_eq!(object.x, 0.);
    assert_eq!(object.y, 0.);

    object.mov(0., 0.);
    assert_eq!(object.x, 0.);
    assert_eq!(object.y, 0.);

    object.mov(1., 1.);
    assert_eq!(object.x, 1.);
    assert_eq!(object.y, 1.);

    object.mov(-3., -3.);
    assert_eq!(object.x, -2.);
    assert_eq!(object.y, -2.);
}
<commit_msg>Object mov_to test<commit_after>use piston_window;
use gfx_device_gl::{Resources, Output, CommandBuffer};
use gfx_graphics::GfxGraphics;
use piston_window::Transformed;

pub struct Object {
    x: f64,
    y: f64,
    sprite: Option<piston_window::Texture<Resources>>,
}

impl Object {
    pub fn new() -> Object {
        Object { x: 0., y: 0., sprite: None }
    }

    pub fn mov(&mut self, x: f64, y: f64) {
        self.x += x;
        self.y += y;
    }

    pub fn mov_to(&mut self, x: f64, y: f64) {
        self.x = x;
        self.y = y;
    }

    pub fn set_sprite(&mut self, sprite: piston_window::Texture<Resources>) {
        self.sprite = Some(sprite);
    }

    pub fn render(&self, graphic: &mut GfxGraphics<Resources, CommandBuffer<Resources>, Output>, view: &piston_window::math::Matrix2d) {
        match self.sprite {
            None => {
                let red = [1.0, 0.0, 0.0, 1.0];
                let square = piston_window::rectangle::square(0.0, 0.0, 100.0);
                piston_window::rectangle(red, square, view.trans(self.x, self.y).trans(-50.0, -50.0), graphic);
            }
            Some(ref sprite) => {
                piston_window::image(sprite, view.trans(self.x, self.y).trans(-50.0, -50.0), graphic);
            }
        }
    }
}

#[test]
fn object_new() {
    let object = Object::new();
    assert_eq!(object.x, 0.0);
    assert_eq!(object.y, 0.0);
}

#[test]
fn object_mov() {
    let mut object = Object::new();
    assert_eq!(object.x, 0.);
    assert_eq!(object.y, 0.);

    object.mov(0., 0.);
    assert_eq!(object.x, 0.);
    assert_eq!(object.y, 0.);

    object.mov(1., 1.);
    assert_eq!(object.x, 1.);
    assert_eq!(object.y, 1.);

    object.mov(-3., -3.);
    assert_eq!(object.x, -2.);
    assert_eq!(object.y, -2.);
}

#[test]
fn object_mov_to() {
    let mut object = Object::new();
    assert_eq!(object.x, 0.);
    assert_eq!(object.y, 0.);

    object.mov_to(0., 0.);
    assert_eq!(object.x, 0.);
    assert_eq!(object.y, 0.);

    object.mov_to(10., 10.);
    assert_eq!(object.x, 10.);
    assert_eq!(object.y, 10.);

    object.mov_to(-30., -30.);
    assert_eq!(object.x, -30.);
    assert_eq!(object.y, -30.);
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use num::rational::Rational32;
use data::frame::MediaKind;

enum CodecID {
    //
}

pub struct CodecParams {
    kind: MediaKind,
    codec_id: CodecID,
    extradata: Vec<u8>,
    tag: u32,
    bit_rate: usize,
    bits_per_coded_sample: usize,
    profile: usize,
    level: usize,
}

pub struct Stream {
    id: usize,
    index: usize,
//  params : CodecParams,
//  seek_index : SeekIndex
}

pub struct StreamGroup<'a> {
    id: usize,
    start: u64,
    end: u64,
    streams: &'a [Stream],
}
<commit_msg>stream: Add CodecParams and timing information<commit_after>#![allow(dead_code)]

use num::rational::Rational32;
use data::frame::MediaKind;

enum CodecID {
    //
}

pub struct CodecParams {
    kind: MediaKind,
    codec_id: CodecID,
    extradata: Vec<u8>,
    tag: u32,
    bit_rate: usize,
    bits_per_coded_sample: usize,
    profile: usize,
    level: usize,
}

pub struct Stream {
    id: usize,
    index: usize,
    params : CodecParams,
    start: Option<u64>,
    duration: Option<u64>,
    timebase : Rational32,
//  seek_index : SeekIndex
}

pub struct StreamGroup<'a> {
    id: usize,
    start: u64,
    end: u64,
    streams: &'a [Stream],
}
<|endoftext|>


<commit_before>#[derive(Debug)]
pub struct Register8 {
    value: u8,
}

impl Register8 {
    pub fn new(v: u8) -> Register8 {
        Register8 { value: v }
    }

    pub fn get(&self) -> u8 {
        self.value
    }

    pub fn set(&mut self, value: u8) {
        self.value = value;
    }

    pub fn increase(&mut self) {
        self.value.wrapping_add(1);
    }
}

#[derive(Debug)]
pub struct Register16 {
    pub low: Register8,
    pub high: Register8,
}

impl Register16 {
    pub fn new(v: u16) -> Register16 {
        let low = (v & 0x00FF) as u8;
        let high = ((v & 0xFF00) >> 8) as u8;

        Register16 {
            low: Register8::new(low),
            high: Register8::new(high),
        }
    }

    pub fn increase(&mut self) {
        let new_value = self.get().wrapping_add(1);
        self.set(new_value);
    }

    pub fn get(&self) -> u16 {
        ((self.high.get() as u16) << 8) | self.low.get() as u16
    }

    pub fn set(&mut self, v: u16) {
        let low = (v & 0x00FF) as u8;
        let high = (v >> 8) as u8;

        self.low.set(low);
        self.high.set(high);
    }
}

#[derive(Debug)]
pub struct Registers {
    // registers are 16 bit wide and can be accessed as L(low) and H(high)
    // register AF is used for (A) accumulator and (F) flags
    pub af: Register16,
    pub bc: Register16,
    pub de: Register16,
    pub hl: Register16,

    pub pc: Register16, // program counter
    pub sp: Register16, // stack pointer
}

impl Registers {
    /// true if bit 7 of flags is 1
    pub fn zero_flag(&self) -> bool {
        (self.af.low.get() & 0x80) == 0x80
    }

    /// true if bit 6 of flags is 1
    pub fn add_sub_flag(&self) -> bool {
        (self.af.low.get() & 0x40) == 0x40
    }

    /// true if bit 5 of flags is 1
    pub fn half_carry_flag(&self) -> bool {
        (self.af.low.get() & 0x20) == 0x20
    }

    /// true if bit 4 of flags is 1
    pub fn carry_flag(&self) -> bool {
        (self.af.low.get() & 0x10) == 0x10
    }

    /// sets bit 7 of flags to the specified bool value
    pub fn set_zero_flag(&mut self, flag: bool) {
        let f = self.af.low.get();

        match flag {
            true => self.af.low.set(f | 0x80),
            false => self.af.low.set(f & 0x7F),
        };
    }

    /// sets bit 6 of flags to the specified bool value
    pub fn set_add_sub_flag(&mut self, flag: bool) {
        let f = {self.af.low.get()};

        match flag {
            true => self.af.low.set(f | 0x40),
            false => self.af.low.set(f & 0xBF),
        };
    }

    /// sets bit 5 of flags to the specified bool value
    pub fn set_half_carry_flag(&mut self, flag: bool) {
        let f = {self.af.low.get()};

        match flag {
            true => self.af.low.set(f | 0x20),
            false => self.af.low.set(f & 0xDF),
        };
    }

    /// sets bit 4 of flags to the specified bool value
    pub fn set_carry_flag(&mut self, flag: bool) {
        let f = {self.af.low.get()};

        match flag {
            true => self.af.low.set(f | 0x10),
            false => self.af.low.set(f & 0xEF),
        };
    }

}
<commit_msg>custom debug impl for register8/16, docs<commit_after>use std::fmt;

/// An 8 bit register. This struct simply wraps an u8 value, it is also meant to offer simple
/// arithmetic operations with wrapping in case of overflows.
pub struct Register8 {
    value: u8,
}

impl fmt::Debug for Register8 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:02X}", self.value)
    }
}

impl Register8 {
    pub fn new(v: u8) -> Register8 {
        Register8 { value: v }
    }

    pub fn get(&self) -> u8 {
        self.value
    }

    pub fn set(&mut self, value: u8) {
        self.value = value;
    }

    pub fn increase(&mut self) {
        self.value.wrapping_add(1);
    }
}

/// A 16 bit register. It is composed of 2 Register8 structs, making the high and low parts of the
/// 16 bits. The struct also offers the ability to get/set individual 8 bit registers or act as a
/// whole u16 number.
pub struct Register16 {
    pub low: Register8,
    pub high: Register8,
}

impl fmt::Debug for Register16 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "0x{:04X}", self.get())
    }
}

impl Register16 {
    pub fn new(v: u16) -> Register16 {
        let low = (v & 0x00FF) as u8;
        let high = ((v & 0xFF00) >> 8) as u8;

        Register16 {
            low: Register8::new(low),
            high: Register8::new(high),
        }
    }

    pub fn increase(&mut self) {
        let new_value = self.get().wrapping_add(1);
        self.set(new_value);
    }

    pub fn get(&self) -> u16 {
        ((self.high.get() as u16) << 8) | self.low.get() as u16
    }

    pub fn set(&mut self, v: u16) {
        let low = (v & 0x00FF) as u8;
        let high = (v >> 8) as u8;

        self.low.set(low);
        self.high.set(high);
    }
}

/// The main registers in a gameboy CPU.
/// Registers are 16 bit wide and can be accessed as L(low) and H(high).
/// Register AF is used for (A) accumulator and (F) flags
/// This struct also offers convenience methods to get and set individual flags.
#[derive(Debug)]
pub struct Registers {

    pub af: Register16,
    pub bc: Register16,
    pub de: Register16,
    pub hl: Register16,

    pub pc: Register16, // program counter
    pub sp: Register16, // stack pointer
}

impl Registers {
    /// true if bit 7 of flags is 1
    pub fn zero_flag(&self) -> bool {
        (self.af.low.get() & 0x80) == 0x80
    }

    /// true if bit 6 of flags is 1
    pub fn add_sub_flag(&self) -> bool {
        (self.af.low.get() & 0x40) == 0x40
    }

    /// true if bit 5 of flags is 1
    pub fn half_carry_flag(&self) -> bool {
        (self.af.low.get() & 0x20) == 0x20
    }

    /// true if bit 4 of flags is 1
    pub fn carry_flag(&self) -> bool {
        (self.af.low.get() & 0x10) == 0x10
    }

    /// sets bit 7 of flags to the specified bool value
    pub fn set_zero_flag(&mut self, flag: bool) {
        let f = self.af.low.get();

        match flag {
            true => self.af.low.set(f | 0x80),
            false => self.af.low.set(f & 0x7F),
        };
    }

    /// sets bit 6 of flags to the specified bool value
    pub fn set_add_sub_flag(&mut self, flag: bool) {
        let f = {self.af.low.get()};

        match flag {
            true => self.af.low.set(f | 0x40),
            false => self.af.low.set(f & 0xBF),
        };
    }

    /// sets bit 5 of flags to the specified bool value
    pub fn set_half_carry_flag(&mut self, flag: bool) {
        let f = {self.af.low.get()};

        match flag {
            true => self.af.low.set(f | 0x20),
            false => self.af.low.set(f & 0xDF),
        };
    }

    /// sets bit 4 of flags to the specified bool value
    pub fn set_carry_flag(&mut self, flag: bool) {
        let f = {self.af.low.get()};

        match flag {
            true => self.af.low.set(f | 0x10),
            false => self.af.low.set(f & 0xEF),
        };
    }

}
<|endoftext|>


<commit_before>//! Create cryptographic signatures for files and verify them.
//!
//! This is based on [signify], the OpenBSD tool to sign and verify signatures on files.
//! It is based on the [Ed25519 public-key signature system][ed25519] by Bernstein et al.
//!
//! `libsignify` can verify and create signatures that are interoperable with BSD signify.
//! You can read more about the ideas and concepts behind `signify` in [Securing OpenBSD From Us To You](https://www.openbsd.org/papers/bsdcan-signify.html).
//!
//! This crate is `#![no_std]` by default, but still relies on `liballoc` so your platform must
//! provide an allocator to use `libsignify`.
//!
//! To enable support for `std::error::Error`, enable the `std` feature.
//!
//! [signify]: https://github.com/aperezdc/signify
//! [ed25519]: https://ed25519.cr.yp.to/
#![warn(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![no_std]

extern crate alloc;

pub mod consts;
pub use consts::KeyNumber;

mod encoding;
pub use encoding::Codeable;

mod errors;
pub use errors::{Error, FormatError};

mod key;
pub use key::{NewKeyOpts, PrivateKey, PublicKey, Signature};

use ed25519_dalek::{Signer as _, Verifier as _};

impl PrivateKey {
    /// Signs a message with this secret key and returns the signature.
    pub fn sign(&self, msg: &[u8]) -> Signature {
        // This `unwrap` is erased in release mode.
        let keypair = ed25519_dalek::Keypair::from_bytes(self.complete_key.as_ref()).unwrap();
        let sig = keypair.sign(msg).to_bytes();
        Signature::new(self.keynum, sig)
    }
}

impl PublicKey {
    /// Use this key to verify that the provided signature for the given message
    /// is authentic.
    ///
    /// # Errors
    ///
    /// This method errors if this key's number didn't match the ID of the key
    /// which created the signature or if the signature couldn't be verified.
    pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> {
        let current_keynum = self.keynum();
        let expected_keynum = signature.keynum;

        if expected_keynum != current_keynum {
            return Err(Error::MismatchedKey {
                expected: expected_keynum,
                found: current_keynum,
            });
        }

        let public_key = ed25519_dalek::PublicKey::from_bytes(&self.key()).unwrap();
        let signature = ed25519_dalek::Signature::from_bytes(&signature.signature()).unwrap();

        public_key
            .verify(msg, &signature)
            .map_err(|_| Error::BadSignature)
    }
}
<commit_msg>Remove unwraps on ed25519 errors<commit_after>//! Create cryptographic signatures for files and verify them.
//!
//! This is based on [signify], the OpenBSD tool to sign and verify signatures on files.
//! It is based on the [Ed25519 public-key signature system][ed25519] by Bernstein et al.
//!
//! `libsignify` can verify and create signatures that are interoperable with BSD signify.
//! You can read more about the ideas and concepts behind `signify` in [Securing OpenBSD From Us To You](https://www.openbsd.org/papers/bsdcan-signify.html).
//!
//! This crate is `#![no_std]` by default, but still relies on `liballoc` so your platform must
//! provide an allocator to use `libsignify`.
//!
//! To enable support for `std::error::Error`, enable the `std` feature.
//!
//! [signify]: https://github.com/aperezdc/signify
//! [ed25519]: https://ed25519.cr.yp.to/
#![warn(missing_docs)]
#![deny(rustdoc::broken_intra_doc_links)]
#![no_std]

extern crate alloc;

pub mod consts;
pub use consts::KeyNumber;

mod encoding;
pub use encoding::Codeable;

mod errors;
pub use errors::{Error, FormatError};

mod key;
pub use key::{NewKeyOpts, PrivateKey, PublicKey, Signature};

use ed25519_dalek::{Signer as _, Verifier as _};

impl PrivateKey {
    /// Signs a message with this secret key and returns the signature.
    pub fn sign(&self, msg: &[u8]) -> Signature {
        // This `unwrap` is erased in release mode.
        let keypair = ed25519_dalek::Keypair::from_bytes(self.complete_key.as_ref()).unwrap();
        let sig = keypair.sign(msg).to_bytes();
        Signature::new(self.keynum, sig)
    }
}

impl PublicKey {
    /// Use this key to verify that the provided signature for the given message
    /// is authentic.
    ///
    /// # Errors
    ///
    /// This method errors if this key's number didn't match the ID of the key
    /// which created the signature or if the signature couldn't be verified.
    pub fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), Error> {
        let current_keynum = self.keynum();
        let expected_keynum = signature.keynum;

        if expected_keynum != current_keynum {
            return Err(Error::MismatchedKey {
                expected: expected_keynum,
                found: current_keynum,
            });
        }

        // Both the key data and signature data are not verified yet,
        // so the ed25519 math can still go wrong.
        // In that case all we need to communicate is that it was a bad signature.

        let public_key =
            ed25519_dalek::PublicKey::from_bytes(&self.key()).map_err(|_| Error::BadSignature)?;
        let signature = ed25519_dalek::Signature::from_bytes(&signature.signature())
            .map_err(|_| Error::BadSignature)?;

        public_key
            .verify(msg, &signature)
            .map_err(|_| Error::BadSignature)
    }
}
<|endoftext|>


<commit_before>use parser::Identifier;
use operations::{Operation, Error};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, ScopeItem, TypeId};

pub fn define_u8(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let unit_type = scope.primitives().unit();

    let u8_type = scope.declare_type(
        Identifier::from("u8"),
        ItemType::Primitive(1)
    );
    scope.register_primitive("u8", u8_type);

    scope.declare_builtin_function(
        // Special method for converting from literal
        // This name is such that it could never be called directly
        // from the language itself
        Identifier::from("std::convert::From<{unsigned integer}>"),
        ItemType::Function {
            // This takes a single literal of the type specific within
            // the curly braces {} in the name
            args: vec![FuncArgType::Arg(u8_type)],
            // Return type signifies which type we are declaring supports integer literals
            return_type: u8_type,
        },
        move |scope, args, target| {
            let value = args[0].numeric_literal_value();

            // 8 is the size of this numeric type in bytes
            // We use >= here because 0 is reserved for zero so we
            // have (2^size - 1) numbers available
            if value >= (1 << 8) {
                Err(Error::OverflowingLiteral {
                    typ: scope.get_type(u8_type).clone()
                })
            }
            else {
                Ok(vec![
                    Operation::Increment {
                        target: target.position(),
                        amount: value as u8,
                    }
                ])
            }
        }
    );

    scope.declare_builtin_function(
        // Special method for displaying this primitive (used from print/println)
        // This name is such that it could never be called directly
        // from the language itself
        Identifier::from("std::fmt::Display::print"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(u8_type)],
            return_type: unit_type,
        },
        move |_, args, _| {
            let mem = match args[0] {
                ScopeItem::TypedBlock {memory, ..} => memory,
                _ => unreachable!(),
            };

            Ok(vec![
                // Need to display numbers as numbers by first incrementing them to the proper
                // ascii code and then decrementing them again
                Operation::Increment {
                    target: mem.position(),
                    amount: b'0',
                },
                Operation::Write {
                    target: mem,
                },
                // Need to make sure we reverse the operation after or else there will be
                // unintended consequences
                Operation::Decrement {
                    target: mem.position(),
                    amount: b'0',
                },
            ])
        }
    );

    scope.declare_builtin_function(
        Identifier::from("increment"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(u8_type)],
            return_type: unit_type,
        },
        move |_scope, args, _target| {
            let mem = match args[0] {
                ScopeItem::TypedBlock {memory, ..} => memory,
                _ => unreachable!(),
            };

            debug_assert!(mem.size() == 1);

            Ok(vec![
                Operation::Increment {
                    target: mem.position(),
                    amount: 1,
                }
            ])
        }
    );

    scope.declare_builtin_function(
        Identifier::from("decrement"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(u8_type)],
            return_type: unit_type,
        },
        move |_scope, args, _target| {
            let mem = match args[0] {
                ScopeItem::TypedBlock {memory, ..} => memory,
                _ => unreachable!(),
            };

            debug_assert!(mem.size() == 1);

            Ok(vec![
                Operation::Decrement {
                    target: mem.position(),
                    amount: 1,
                }
            ])
        }
    );

    // Method on [u8; _]
    scope.declare_builtin_function(
        // Special method for displaying this primitive (used from print/println)
        // This name is such that it could never be called directly
        // from the language itself
        Identifier::from("std::fmt::Display::print"),
        ItemType::Function {
            args: vec![FuncArgType::Array {item: u8_type, size: None}],
            return_type: unit_type,
        },
        move |scope, args, _| {
            match args[0] {
                ScopeItem::Array {memory, ..} => Ok(vec![
                    Operation::Write {
                        target: memory,
                    },
                ]),
                ScopeItem::ByteLiteral(ref bytes) => {
                    let u8_type = scope.primitives().u8();
                    let mem = scope.allocate(u8_type);

                    Ok(vec![
                        Operation::TempAllocate {
                            temp: mem,
                            body: bytes.iter().flat_map(|&ch| vec![
                                Operation::Increment {
                                    target: mem.position(),
                                    amount: ch,
                                },
                                Operation::Write {
                                    target: mem,
                                },
                                Operation::Decrement {
                                    target: mem.position(),
                                    amount: ch,
                                },
                            ]).collect(),
                        },
                    ])
                },
                _ => unreachable!(),
            }
        }
    );

    u8_type
}

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

    use operations::scope::{ScopeType};

    #[test]
    fn defines_primitive() {
        let mut scope = ScopeStack::new();
        define_u8(&mut scope);

        let u8_type_id = match **scope.lookup_type(&Identifier::from("u8")).first().unwrap() {
            ScopeType::Type(id) => id,
        };
        assert_eq!(scope.primitives().u8(), u8_type_id);
    }
}
<commit_msg>Hack to prevent the [u8; N] print declaration from overwriting the one for u8<commit_after>use parser::Identifier;
use operations::{Operation, Error};
use operations::item_type::{ItemType, FuncArgType};
use operations::scope::{ScopeStack, ScopeItem, TypeId};

pub fn define_u8(scope: &mut ScopeStack) -> TypeId {
    // Taking advantage of the scope system to simulate modules
    // This will be replaced with something better in:
    // https://github.com/brain-lang/brain/issues/37
    scope.push_scope();

    let unit_type = scope.primitives().unit();

    let u8_type = scope.declare_type(
        Identifier::from("u8"),
        ItemType::Primitive(1)
    );
    scope.register_primitive("u8", u8_type);

    scope.declare_builtin_function(
        // Special method for converting from literal
        // This name is such that it could never be called directly
        // from the language itself
        Identifier::from("std::convert::From<{unsigned integer}>"),
        ItemType::Function {
            // This takes a single literal of the type specific within
            // the curly braces {} in the name
            args: vec![FuncArgType::Arg(u8_type)],
            // Return type signifies which type we are declaring supports integer literals
            return_type: u8_type,
        },
        move |scope, args, target| {
            let value = args[0].numeric_literal_value();

            // 8 is the size of this numeric type in bytes
            // We use >= here because 0 is reserved for zero so we
            // have (2^size - 1) numbers available
            if value >= (1 << 8) {
                Err(Error::OverflowingLiteral {
                    typ: scope.get_type(u8_type).clone()
                })
            }
            else {
                Ok(vec![
                    Operation::Increment {
                        target: target.position(),
                        amount: value as u8,
                    }
                ])
            }
        }
    );

    scope.declare_builtin_function(
        // Special method for displaying this primitive (used from print/println)
        // This name is such that it could never be called directly
        // from the language itself
        Identifier::from("std::fmt::Display::print"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(u8_type)],
            return_type: unit_type,
        },
        move |_, args, _| {
            let mem = match args[0] {
                ScopeItem::TypedBlock {memory, ..} => memory,
                _ => unreachable!(),
            };

            Ok(vec![
                // Need to display numbers as numbers by first incrementing them to the proper
                // ascii code and then decrementing them again
                Operation::Increment {
                    target: mem.position(),
                    amount: b'0',
                },
                Operation::Write {
                    target: mem,
                },
                // Need to make sure we reverse the operation after or else there will be
                // unintended consequences
                Operation::Decrement {
                    target: mem.position(),
                    amount: b'0',
                },
            ])
        }
    );

    scope.declare_builtin_function(
        Identifier::from("increment"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(u8_type)],
            return_type: unit_type,
        },
        move |_scope, args, _target| {
            let mem = match args[0] {
                ScopeItem::TypedBlock {memory, ..} => memory,
                _ => unreachable!(),
            };

            debug_assert!(mem.size() == 1);

            Ok(vec![
                Operation::Increment {
                    target: mem.position(),
                    amount: 1,
                }
            ])
        }
    );

    scope.declare_builtin_function(
        Identifier::from("decrement"),
        ItemType::Function {
            args: vec![FuncArgType::Arg(u8_type)],
            return_type: unit_type,
        },
        move |_scope, args, _target| {
            let mem = match args[0] {
                ScopeItem::TypedBlock {memory, ..} => memory,
                _ => unreachable!(),
            };

            debug_assert!(mem.size() == 1);

            Ok(vec![
                Operation::Decrement {
                    target: mem.position(),
                    amount: 1,
                }
            ])
        }
    );

    // Need this so that this next method definition does not overwrite the previous one
    scope.push_scope();

    // Method on [u8; _]
    scope.declare_builtin_function(
        // Special method for displaying this primitive (used from print/println)
        // This name is such that it could never be called directly
        // from the language itself
        Identifier::from("std::fmt::Display::print"),
        ItemType::Function {
            args: vec![FuncArgType::Array {item: u8_type, size: None}],
            return_type: unit_type,
        },
        move |scope, args, _| {
            match args[0] {
                ScopeItem::Array {memory, ..} => Ok(vec![
                    Operation::Write {
                        target: memory,
                    },
                ]),
                ScopeItem::ByteLiteral(ref bytes) => {
                    let u8_type = scope.primitives().u8();
                    let mem = scope.allocate(u8_type);

                    Ok(vec![
                        Operation::TempAllocate {
                            temp: mem,
                            body: bytes.iter().flat_map(|&ch| vec![
                                Operation::Increment {
                                    target: mem.position(),
                                    amount: ch,
                                },
                                Operation::Write {
                                    target: mem,
                                },
                                Operation::Decrement {
                                    target: mem.position(),
                                    amount: ch,
                                },
                            ]).collect(),
                        },
                    ])
                },
                _ => unreachable!(),
            }
        }
    );

    u8_type
}

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

    use operations::scope::{ScopeType};

    #[test]
    fn defines_primitive() {
        let mut scope = ScopeStack::new();
        define_u8(&mut scope);

        let u8_type_id = match **scope.lookup_type(&Identifier::from("u8")).first().unwrap() {
            ScopeType::Type(id) => id,
        };
        assert_eq!(scope.primitives().u8(), u8_type_id);
    }
}
<|endoftext|>