<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) == 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);
    }
}
<commit_msg>Removed Bare trait<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};

/// 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> 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>);

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

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);

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>);

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

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);

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);

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>// use std::old_io::{TcpListener, TcpStream};
// use std::old_io::{Acceptor, Listener, IoResult, MemReader};
use std::thread::sleep_ms;
use std::io::{Read, Write, Result, BufRead, BufReader, BufWriter};
use std::fs::File;

use std::net::{TcpListener, TcpStream};
use std::mem::size_of;

use std::sync::mpsc::{Sender, Receiver, channel};

use std::thread;
use std::sync::Arc;
use std::mem;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use communication::{Pushable, BinaryCommunicator, ProcessCommunicator};
use drain::DrainExt;

// TODO : Much of this only relates to BinaryWriter/BinaryReader based communication, not networking.
// TODO : Could be moved somewhere less networking-specific.

#[derive(Copy, Clone)]
pub struct MessageHeader {
    pub graph:      u64,   // graph identifier
    pub channel:    u64,   // index of channel
    pub source:     u64,   // index of worker sending message
    pub target:     u64,   // index of worker receiving message
    pub length:     u64,   // number of bytes in message
}

impl MessageHeader {
    // returns a header when there is enough supporting data
    fn try_read(bytes: &mut &[u8]) -> Option<MessageHeader> {
        if bytes.len() > size_of::<MessageHeader>() {
            // capture original in case we need to rewind
            let original = *bytes;

            // unclear what order struct initializers run in, so ...
            let graph = bytes.read_u64::<LittleEndian>().unwrap();
            let channel = bytes.read_u64::<LittleEndian>().unwrap();
            let source = bytes.read_u64::<LittleEndian>().unwrap();
            let target = bytes.read_u64::<LittleEndian>().unwrap();
            let length = bytes.read_u64::<LittleEndian>().unwrap();

            if bytes.len() >= length as usize {
                Some(MessageHeader {
                    graph: graph,
                    channel: channel,
                    source: source,
                    target: target,
                    length: length,
                })
            }
            else {
                // rewind the reader
                *bytes = original;
                None
            }
        }
        else { None }
    }

    fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
        try!(writer.write_u64::<LittleEndian>(self.graph));
        try!(writer.write_u64::<LittleEndian>(self.channel));
        try!(writer.write_u64::<LittleEndian>(self.source));
        try!(writer.write_u64::<LittleEndian>(self.target));
        try!(writer.write_u64::<LittleEndian>(self.length));
        Ok(())
    }
}

// structure in charge of receiving data from a Reader, for example the network
struct BinaryReceiver<R: Read> {
    reader:     R,          // the generic reader
    buffer:     Vec<u8>,    // current working buffer
    double:     Vec<u8>,    // second working buffer
    staging:    Vec<u8>,    // 1 << 20 of buffer to read into
    targets:    Switchboard<(Sender<Vec<u8>>, Receiver<Vec<u8>>)>,
}

impl<R: Read> BinaryReceiver<R> {
    fn new(reader: R, channels: Receiver<((u64, u64, u64), (Sender<Vec<u8>>, Receiver<Vec<u8>>))>) -> BinaryReceiver<R> {
        BinaryReceiver {

            reader:     reader,
            buffer:     Vec::new(),
            double:     Vec::new(),
            staging:    vec![0u8; 1 << 20],
            targets:    Switchboard::new(channels),
        }
    }

    fn recv_loop(&mut self) {
        loop {

            // attempt to read some more bytes into our buffer
            // TODO : We read in to self.staging because extending a Vec<u8> is hard without
            // TODO : using set_len, which is unsafe.
            // TODO : Could consider optimizing for the self.buffer.len() == 0 case, swapping
            // TODO : self.staging with self.buffer, rather than using write_all.
            let read = self.reader.read(&mut self.staging[..]).unwrap_or(0);
            self.buffer.write_all(&self.staging[..read]).unwrap(); // <-- shouldn't fail

            {
                // get a view of available bytes
                let mut slice = &self.buffer[..];

                while let Some(header) = MessageHeader::try_read(&mut slice) {

                    let h_len = header.length as usize;  // length in bytes
                    let target = self.targets.ensure(header.target, header.graph, header.channel);
                    let mut buffer = target.1.try_recv().unwrap_or(Vec::new());

                    buffer.clear();
                    buffer.write_all(&slice[..h_len]).unwrap();
                    slice = &slice[h_len..];

                    target.0.send(buffer).unwrap();
                }

                // TODO: way inefficient... =/ Fix! :D
                // if slice.len() < self.buffer.len() {
                    self.double.clear();
                    self.double.write_all(slice).unwrap();
                // }
            }

            // if self.double.len() > 0 {
                mem::swap(&mut self.buffer, &mut self.double);
                // self.double.clear();
            // }
        }
    }
}

// structure in charge of sending data to a Writer, for example the network
struct BinarySender<W: Write> {
    id:         u64,    // destination process
    writer:     W,
    sources:    Receiver<(MessageHeader, Vec<u8>)>,
    returns:    Switchboard<Sender<Vec<u8>>>,
}

impl<W: Write> BinarySender<W> {
    fn new(id: u64,
           writer: W,
           sources: Receiver<(MessageHeader, Vec<u8>)>,
           channels: Receiver<((u64, u64, u64), Sender<Vec<u8>>)>) -> BinarySender<W> {
        BinarySender {
            id:         id,
            writer:     writer,
            sources:    sources,
            returns: Switchboard::new(channels),
        }
    }

    fn send_loop(&mut self) {
        let mut stash = Vec::new();

        // block until data to recv
        while let Ok((header, buffer)) = self.sources.recv() {

            stash.push((header, buffer));

            // collect any additional outstanding data to send
            while let Ok((header, buffer)) = self.sources.try_recv() {
                stash.push((header, buffer));
            }

            // println!("send loop to process {}:\tstarting", self.id);
            for (mut header, mut buffer) in stash.drain_temp() {
                header.length = buffer.len() as u64;    // <-- is this really our job? O.o
                header.write_to(&mut self.writer).unwrap();
                self.writer.write_all(&buffer[..]).unwrap();
                buffer.clear();

                // self.returns.ensure(header.source, header.graph, header.channel).send(buffer).unwrap();
            }

            self.writer.flush().unwrap();    // <-- because writer is buffered
        }
    }
}

struct Switchboard<T:Send> {
    source: Receiver<((u64, u64, u64), T)>,
    buffer: Vec<Vec<Vec<Option<T>>>>,
}

impl<T:Send> Switchboard<T> {
    pub fn new(source: Receiver<((u64, u64, u64), T)>) -> Switchboard<T> {
        Switchboard {
            source: source,
            buffer: Vec::new(),
        }
    }

    pub fn ensure(&mut self, a: u64, b: u64, c: u64) -> &mut T {
        let a = a as usize;
        let b = b as usize;
        let c = c as usize;

        while self.buffer.len() <= a { self.buffer.push(Vec::new()); }
        while self.buffer[a].len() <= b { self.buffer[a].push(Vec::new()); }
        while self.buffer[a][b].len() <= c { self.buffer[a][b].push(None); }

        while let None = self.buffer[a][b][c] {
            let ((x, y, z), s) = self.source.recv().unwrap();

            let x = x as usize;
            let y = y as usize;
            let z = z as usize;

            while self.buffer.len() <= x { self.buffer.push(Vec::new()); }
            while self.buffer[x].len() <= y { self.buffer[x].push(Vec::new()); }
            while self.buffer[x][y].len() <= z { self.buffer[x][y].push(None); }
            self.buffer[x][y][z] = Some(s);
        }

        // we've just ensured that this is not None
        self.buffer[a][b][c].as_mut().unwrap()
    }
}

pub fn initialize_networking_from_file(filename: &str, my_index: u64, workers: u64) -> Result<Vec<BinaryCommunicator>> {

    let reader = BufReader::new(try!(File::open(filename)));
    let mut addresses = Vec::new();

    for line in reader.lines() {
        addresses.push(try!(line));
    }

    initialize_networking(addresses, my_index, workers)
}

pub fn initialize_networking(addresses: Vec<String>, my_index: u64, workers: u64) -> Result<Vec<BinaryCommunicator>> {

    let processes = addresses.len() as u64;
    let hosts1 = Arc::new(addresses);
    let hosts2 = hosts1.clone();

    let start_task = thread::spawn(move || start_connections(hosts1, my_index));
    let await_task = thread::spawn(move || await_connections(hosts2, my_index));

    let mut results = try!(start_task.join().unwrap());

    results.push(None);
    let mut to_extend = try!(await_task.join().unwrap());
    results.extend(to_extend.drain_temp());

    println!("worker {}:\tinitialization complete", my_index);

    let mut writers = Vec::new();   // handles to the BinarySenders (to present new channels)
    let mut readers = Vec::new();   // handles to the BinaryReceivers (to present new channels)
    let mut senders = Vec::new();   // destinations for serialized data (to send serialized data)

    // for each process, if a stream exists (i.e. not local) ...
    for index in (0..results.len()) {
        if let Some(stream) = results[index].take() {

            let (writer_channels_s, writer_channels_r) = channel();
            let (reader_channels_s, reader_channels_r) = channel();
            let (sender_channels_s, sender_channels_r) = channel();

            writers.push(writer_channels_s);    //
            readers.push(reader_channels_s);    //
            senders.push(sender_channels_s);    //

            let mut sender = BinarySender::new(index as u64,
                                               BufWriter::with_capacity(1 << 20, stream.try_clone().unwrap()),
                                               sender_channels_r,
                                               writer_channels_r);
            let mut recver = BinaryReceiver::new(stream.try_clone().unwrap(), reader_channels_r);

            // start senders and receivers associated with this stream
            thread::Builder::new().name(format!("send thread {}", index))
                                  .spawn(move || sender.send_loop())
                                  .unwrap();
            thread::Builder::new().name(format!("recv thread {}", index))
                                  .spawn(move || recver.recv_loop())
                                  .unwrap();

        }
    }

    let proc_comms = ProcessCommunicator::new_vector(workers);

    let mut results = Vec::new();
    for (index, proc_comm) in proc_comms.into_iter().enumerate() {
        results.push(BinaryCommunicator {
            inner:          proc_comm,
            index:          my_index * workers + index as u64,
            peers:          workers * processes,
            graph:          0,          // TODO : Fix this
            allocated:      0,
            writers:        writers.clone(),
            readers:        readers.clone(),
            senders:        senders.clone(),
        });
    }

    return Ok(results);
}

// result contains connections [0, my_index - 1].
fn start_connections(addresses: Arc<Vec<String>>, my_index: u64) -> Result<Vec<Option<TcpStream>>> {
    let mut results: Vec<_> = (0..my_index).map(|_| None).collect();
    for index in (0..my_index) {
        let mut connected = false;
        println!("start: waiting {}", index);
        while !connected {
            match TcpStream::connect(&addresses[index as usize][..]) {
                Ok(mut stream) => {
                    try!(stream.write_u64::<LittleEndian>(my_index));
                    results[index as usize] = Some(stream);
                    println!("worker {}:\tconnection to worker {}", my_index, index);
                    connected = true;
                },
                Err(error) => {
                    println!("worker {}:\terror connecting to worker {}: {}; retrying", my_index, index, error);
                    sleep_ms(1000);
                },
            }
        }
        println!("start: connect {}", index);
    }

    println!("start: returning");
    return Ok(results);
}

// result contains connections [my_index + 1, addresses.len() - 1].
fn await_connections(addresses: Arc<Vec<String>>, my_index: u64) -> Result<Vec<Option<TcpStream>>> {
    let mut results: Vec<_> = (0..(addresses.len() - my_index as usize - 1)).map(|_| None).collect();
    let listener = try!(TcpListener::bind(&addresses[my_index as usize][..]));

    for _ in (my_index as usize + 1 .. addresses.len()) {
        println!("await: waiting {}", my_index);
        let mut stream = try!(listener.accept()).0;
        let identifier = try!(stream.read_u64::<LittleEndian>()) as usize;
        results[identifier - my_index as usize - 1] = Some(stream);
        println!("worker {}:\tconnection from worker {}", my_index, identifier);
    }

    println!("await: returning");
    return Ok(results);
}
<commit_msg>printing out status to debug cluster start-up<commit_after>// use std::old_io::{TcpListener, TcpStream};
// use std::old_io::{Acceptor, Listener, IoResult, MemReader};
use std::thread::sleep_ms;
use std::io::{Read, Write, Result, BufRead, BufReader, BufWriter};
use std::fs::File;

use std::net::{TcpListener, TcpStream};
use std::mem::size_of;

use std::sync::mpsc::{Sender, Receiver, channel};

use std::thread;
use std::sync::Arc;
use std::mem;

use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};

use communication::{Pushable, BinaryCommunicator, ProcessCommunicator};
use drain::DrainExt;

// TODO : Much of this only relates to BinaryWriter/BinaryReader based communication, not networking.
// TODO : Could be moved somewhere less networking-specific.

#[derive(Copy, Clone)]
pub struct MessageHeader {
    pub graph:      u64,   // graph identifier
    pub channel:    u64,   // index of channel
    pub source:     u64,   // index of worker sending message
    pub target:     u64,   // index of worker receiving message
    pub length:     u64,   // number of bytes in message
}

impl MessageHeader {
    // returns a header when there is enough supporting data
    fn try_read(bytes: &mut &[u8]) -> Option<MessageHeader> {
        if bytes.len() > size_of::<MessageHeader>() {
            // capture original in case we need to rewind
            let original = *bytes;

            // unclear what order struct initializers run in, so ...
            let graph = bytes.read_u64::<LittleEndian>().unwrap();
            let channel = bytes.read_u64::<LittleEndian>().unwrap();
            let source = bytes.read_u64::<LittleEndian>().unwrap();
            let target = bytes.read_u64::<LittleEndian>().unwrap();
            let length = bytes.read_u64::<LittleEndian>().unwrap();

            if bytes.len() >= length as usize {
                Some(MessageHeader {
                    graph: graph,
                    channel: channel,
                    source: source,
                    target: target,
                    length: length,
                })
            }
            else {
                // rewind the reader
                *bytes = original;
                None
            }
        }
        else { None }
    }

    fn write_to<W: Write>(&self, writer: &mut W) -> Result<()> {
        try!(writer.write_u64::<LittleEndian>(self.graph));
        try!(writer.write_u64::<LittleEndian>(self.channel));
        try!(writer.write_u64::<LittleEndian>(self.source));
        try!(writer.write_u64::<LittleEndian>(self.target));
        try!(writer.write_u64::<LittleEndian>(self.length));
        Ok(())
    }
}

// structure in charge of receiving data from a Reader, for example the network
struct BinaryReceiver<R: Read> {
    reader:     R,          // the generic reader
    buffer:     Vec<u8>,    // current working buffer
    double:     Vec<u8>,    // second working buffer
    staging:    Vec<u8>,    // 1 << 20 of buffer to read into
    targets:    Switchboard<(Sender<Vec<u8>>, Receiver<Vec<u8>>)>,
}

impl<R: Read> BinaryReceiver<R> {
    fn new(reader: R, channels: Receiver<((u64, u64, u64), (Sender<Vec<u8>>, Receiver<Vec<u8>>))>) -> BinaryReceiver<R> {
        BinaryReceiver {

            reader:     reader,
            buffer:     Vec::new(),
            double:     Vec::new(),
            staging:    vec![0u8; 1 << 20],
            targets:    Switchboard::new(channels),
        }
    }

    fn recv_loop(&mut self) {
        loop {

            // attempt to read some more bytes into our buffer
            // TODO : We read in to self.staging because extending a Vec<u8> is hard without
            // TODO : using set_len, which is unsafe.
            // TODO : Could consider optimizing for the self.buffer.len() == 0 case, swapping
            // TODO : self.staging with self.buffer, rather than using write_all.
            let read = self.reader.read(&mut self.staging[..]).unwrap_or(0);
            self.buffer.write_all(&self.staging[..read]).unwrap(); // <-- shouldn't fail

            {
                // get a view of available bytes
                let mut slice = &self.buffer[..];

                while let Some(header) = MessageHeader::try_read(&mut slice) {

                    let h_len = header.length as usize;  // length in bytes
                    let target = self.targets.ensure(header.target, header.graph, header.channel);
                    let mut buffer = target.1.try_recv().unwrap_or(Vec::new());

                    buffer.clear();
                    buffer.write_all(&slice[..h_len]).unwrap();
                    slice = &slice[h_len..];

                    target.0.send(buffer).unwrap();
                }

                // TODO: way inefficient... =/ Fix! :D
                // if slice.len() < self.buffer.len() {
                    self.double.clear();
                    self.double.write_all(slice).unwrap();
                // }
            }

            // if self.double.len() > 0 {
                mem::swap(&mut self.buffer, &mut self.double);
                // self.double.clear();
            // }
        }
    }
}

// structure in charge of sending data to a Writer, for example the network
struct BinarySender<W: Write> {
    id:         u64,    // destination process
    writer:     W,
    sources:    Receiver<(MessageHeader, Vec<u8>)>,
    returns:    Switchboard<Sender<Vec<u8>>>,
}

impl<W: Write> BinarySender<W> {
    fn new(id: u64,
           writer: W,
           sources: Receiver<(MessageHeader, Vec<u8>)>,
           channels: Receiver<((u64, u64, u64), Sender<Vec<u8>>)>) -> BinarySender<W> {
        BinarySender {
            id:         id,
            writer:     writer,
            sources:    sources,
            returns: Switchboard::new(channels),
        }
    }

    fn send_loop(&mut self) {
        let mut stash = Vec::new();

        // block until data to recv
        while let Ok((header, buffer)) = self.sources.recv() {

            stash.push((header, buffer));

            // collect any additional outstanding data to send
            while let Ok((header, buffer)) = self.sources.try_recv() {
                stash.push((header, buffer));
            }

            // println!("send loop to process {}:\tstarting", self.id);
            for (mut header, mut buffer) in stash.drain_temp() {
                header.length = buffer.len() as u64;    // <-- is this really our job? O.o
                header.write_to(&mut self.writer).unwrap();
                self.writer.write_all(&buffer[..]).unwrap();
                buffer.clear();

                // self.returns.ensure(header.source, header.graph, header.channel).send(buffer).unwrap();
            }

            self.writer.flush().unwrap();    // <-- because writer is buffered
        }
    }
}

struct Switchboard<T:Send> {
    source: Receiver<((u64, u64, u64), T)>,
    buffer: Vec<Vec<Vec<Option<T>>>>,
}

impl<T:Send> Switchboard<T> {
    pub fn new(source: Receiver<((u64, u64, u64), T)>) -> Switchboard<T> {
        Switchboard {
            source: source,
            buffer: Vec::new(),
        }
    }

    pub fn ensure(&mut self, a: u64, b: u64, c: u64) -> &mut T {
        let a = a as usize;
        let b = b as usize;
        let c = c as usize;

        while self.buffer.len() <= a { self.buffer.push(Vec::new()); }
        while self.buffer[a].len() <= b { self.buffer[a].push(Vec::new()); }
        while self.buffer[a][b].len() <= c { self.buffer[a][b].push(None); }

        while let None = self.buffer[a][b][c] {
            let ((x, y, z), s) = self.source.recv().unwrap();

            let x = x as usize;
            let y = y as usize;
            let z = z as usize;

            while self.buffer.len() <= x { self.buffer.push(Vec::new()); }
            while self.buffer[x].len() <= y { self.buffer[x].push(Vec::new()); }
            while self.buffer[x][y].len() <= z { self.buffer[x][y].push(None); }
            self.buffer[x][y][z] = Some(s);
        }

        // we've just ensured that this is not None
        self.buffer[a][b][c].as_mut().unwrap()
    }
}

pub fn initialize_networking_from_file(filename: &str, my_index: u64, workers: u64) -> Result<Vec<BinaryCommunicator>> {

    let reader = BufReader::new(try!(File::open(filename)));
    let mut addresses = Vec::new();

    for line in reader.lines() {
        addresses.push(try!(line));
    }

    initialize_networking(addresses, my_index, workers)
}

pub fn initialize_networking(addresses: Vec<String>, my_index: u64, workers: u64) -> Result<Vec<BinaryCommunicator>> {

    let processes = addresses.len() as u64;
    let hosts1 = Arc::new(addresses);
    let hosts2 = hosts1.clone();

    let start_task = thread::spawn(move || start_connections(hosts1, my_index));
    let await_task = thread::spawn(move || await_connections(hosts2, my_index));

    let mut results = try!(start_task.join().unwrap());

    results.push(None);
    let mut to_extend = try!(await_task.join().unwrap());
    results.extend(to_extend.drain_temp());

    println!("worker {}:\tinitialization complete", my_index);

    let mut writers = Vec::new();   // handles to the BinarySenders (to present new channels)
    let mut readers = Vec::new();   // handles to the BinaryReceivers (to present new channels)
    let mut senders = Vec::new();   // destinations for serialized data (to send serialized data)

    // for each process, if a stream exists (i.e. not local) ...
    for index in (0..results.len()) {
        if let Some(stream) = results[index].take() {

            let (writer_channels_s, writer_channels_r) = channel();
            let (reader_channels_s, reader_channels_r) = channel();
            let (sender_channels_s, sender_channels_r) = channel();

            writers.push(writer_channels_s);    //
            readers.push(reader_channels_s);    //
            senders.push(sender_channels_s);    //

            let mut sender = BinarySender::new(index as u64,
                                               BufWriter::with_capacity(1 << 20, stream.try_clone().unwrap()),
                                               sender_channels_r,
                                               writer_channels_r);
            let mut recver = BinaryReceiver::new(stream.try_clone().unwrap(), reader_channels_r);

            // start senders and receivers associated with this stream
            thread::Builder::new().name(format!("send thread {}", index))
                                  .spawn(move || sender.send_loop())
                                  .unwrap();
            thread::Builder::new().name(format!("recv thread {}", index))
                                  .spawn(move || recver.recv_loop())
                                  .unwrap();

        }
    }

    let proc_comms = ProcessCommunicator::new_vector(workers);

    let mut results = Vec::new();
    for (index, proc_comm) in proc_comms.into_iter().enumerate() {
        results.push(BinaryCommunicator {
            inner:          proc_comm,
            index:          my_index * workers + index as u64,
            peers:          workers * processes,
            graph:          0,          // TODO : Fix this
            allocated:      0,
            writers:        writers.clone(),
            readers:        readers.clone(),
            senders:        senders.clone(),
        });
    }

    return Ok(results);
}

// result contains connections [0, my_index - 1].
fn start_connections(addresses: Arc<Vec<String>>, my_index: u64) -> Result<Vec<Option<TcpStream>>> {
    let mut results: Vec<_> = (0..my_index).map(|_| None).collect();
    for index in (0..my_index) {
        let mut connected = false;
        println!("start: waiting {}", index);
        while !connected {
            match TcpStream::connect(&addresses[index as usize][..]) {
                Ok(mut stream) => {
                    try!(stream.write_u64::<LittleEndian>(my_index));
                    results[index as usize] = Some(stream);
                    println!("worker {}:\tconnection to worker {}", my_index, index);
                    connected = true;
                },
                Err(error) => {
                    println!("worker {}:\terror connecting to worker {}: {}; retrying", my_index, index, error);
                    sleep_ms(1000);
                },
            }
        }
        println!("start: connect {}", index);
    }

    println!("start: returning");
    return Ok(results);
}

// result contains connections [my_index + 1, addresses.len() - 1].
fn await_connections(addresses: Arc<Vec<String>>, my_index: u64) -> Result<Vec<Option<TcpStream>>> {
    let mut results: Vec<_> = (0..(addresses.len() - my_index as usize - 1)).map(|_| None).collect();
    let listener = try!(TcpListener::bind(&addresses[my_index as usize][..]));

    println!("about to wait from {} to {}", my_index + 1, address.len());
    for _ in (my_index as usize + 1 .. addresses.len()) {
        println!("await: waiting {}", my_index);
        let mut stream = try!(listener.accept()).0;
        let identifier = try!(stream.read_u64::<LittleEndian>()) as usize;
        results[identifier - my_index as usize - 1] = Some(stream);
        println!("worker {}:\tconnection from worker {}", my_index, identifier);
    }

    println!("await: returning");
    return Ok(results);
}
<|endoftext|>


<commit_before>use std::ptr;
use std::fs;
use std::io::{Write, SeekFrom, Seek};
use std::os::unix::prelude::AsRawFd;
use mmap::{MemoryMap, MapOption};
use libc;

struct fpgaHk {
    mmap: MemoryMap,
    data: *mut u8,
}

impl fpgaHk {
  pub fn new() -> fpgaHk {
    let size: usize = 0x1000;

    let mut f = fs::OpenOptions::new().read(true)
                                      .write(true)
                                      .open("/dev/uio0")
                                      .unwrap();

    let mmap_opts = &[
        // Then make the mapping *public* so it is written back to the file
        MapOption::MapNonStandardFlags(libc::MAP_SHARED),
        MapOption::MapReadable,
        MapOption::MapWritable,
        MapOption::MapFd(f.as_raw_fd()),
    ];

    let mmap = MemoryMap::new(size, mmap_opts).unwrap();

    let data = mmap.data();

    if data.is_null() {
        panic!("Could not access data from memory mapped file")
    }
    else {
        println!("successful data access to memory mapped file");
    }

    fpgaHk {mmap: mmap, data: data}
  }

  pub fn toggle(&mut self, led_pin: u32) {
      unsafe {
          *(self.data.offset(0x30) as *mut u32) ^= 1 << led_pin;
      }
  }
}<commit_msg>updated code<commit_after>use std::ptr;
use std::fs;
use std::io::{Write, SeekFrom, Seek};
use std::os::unix::prelude::AsRawFd;
use mmap::{MemoryMap, MapOption};
use libc;
use std::f32;
use std::default::Default;

const HK_BASE_ADDR: isize = 0x000000;

struct hk_reg {
  id: u32,
  dna_low: u32,
  dna_high: u32,
  reserved1: u32,
  exp_dir_p: u32,
  exp_dir_n: u32,
  exp_out_p: u32,
  exp_out_n: u32,
  exp_in_p: u32,
  exp_in_n: u32,
  reserved2: u32,
  reserved3: u32,
  led_ctrl: u32, // 0x30
}

pub struct fpgaHk {
  mmap: MemoryMap,
  data: *mut u8,
  hkReg: *mut hk_reg,
}

impl fpgaHk {
  pub fn new() -> fpgaHk {
    let size: usize = 0x400000;

    let mut f = fs::OpenOptions::new().read(true)
                                      .write(true)
                                      .open("/dev/uio0")
                                      .unwrap();

    let mmap_opts = &[
        // Then make the mapping *public* so it is written back to the file
        MapOption::MapNonStandardFlags(libc::MAP_SHARED),
        MapOption::MapReadable,
        MapOption::MapWritable,
        MapOption::MapFd(f.as_raw_fd()),
    ];

    let mmap = MemoryMap::new(size, mmap_opts).unwrap();

    let data = mmap.data();

    if data.is_null() {
        panic!("Could not access data from memory mapped file")
    }

    let hkReg: *mut hk_reg;

    unsafe {
        hkReg = data.offset(HK_BASE_ADDR) as *mut hk_reg;
    }

    fpgaHk {mmap: mmap, data: data, hkReg: hkReg}
  }

  pub fn toggle(&mut self, led_pin: u32) {
      unsafe {
          (*self.hkReg).led_ctrl ^= 1 << led_pin;
      }
  }

  pub fn set_exp_p_dir(&mut self, dir: u32) {
      unsafe {
          (*self.hkReg).exp_dir_p = dir;
      }
  }

  pub fn toggle_exp_p_gpo(&mut self, pin: u32) {
      unsafe {
          (*self.hkReg).exp_out_p ^= 1 << pin;
      }
  }

  //pub fn clear_exp_p_gpo(&mut self, pin: u32) {
  //    unsafe {
  //        (*self.hkReg).exp_out_p = ~(1 << pin);
  //    }
  //}

  pub fn set_exp_p_gpo(&mut self, pin: u32) {
      unsafe {
          (*self.hkReg).exp_out_p |= 1 << pin;
      }
  }
}<|endoftext|>


<commit_before>/// Strongly borrowed from TypedArena
/// Differs in growth strategy (non-doubling)
/// And only for variable-sized strings

use std::borrow::Borrow;
use std::cell::{Cell,RefCell};
use std::cmp::max;
use std::collections::LinkedList;
use std::collections::hash_map::Entry::{Occupied,Vacant};
use std::collections::hash_map::HashMap;
use std::default::Default;
use std::ops::Deref;
use std::slice;
use std::{fmt,hash,mem,ptr,str};

struct Chunk {
    start: *mut u8,
    capacity: usize,
}

impl Chunk {
    fn new(capacity: usize) -> Chunk {
        let mut slab: Vec<u8> = Vec::with_capacity(capacity);
        let start = slab.as_mut_ptr();

        // We will manually track the buffer and then drop it ourselves
        unsafe {
            mem::forget(slab);
        }

        Chunk {
            start: start,
            capacity: capacity,
        }
    }

    // Returns a pointer to the beginning of the allocated space.
    #[inline]
    fn start(&self) -> *const u8 {
        self.start as *const u8
    }

    // Returns a pointer to the end of the allocated space.
    #[inline]
    fn end(&self) -> *const u8 {
        unsafe { self.start().offset(self.capacity as isize) }
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        // This is safe because we only ever store u8, which doesn't
        // have a destructor. This means the len doesn't matter, only
        // the capacity.
        unsafe {
            Vec::from_raw_parts(self.start, self.capacity, self.capacity);
        }
    }
}

#[allow(raw_pointer_derive)]
#[derive(Copy,Clone)]
pub struct InternedString {
    data: *const u8,
    len: usize,
}

impl InternedString {
    fn from_parts(data: *const u8, len: usize) -> InternedString {
        InternedString {
            data: data,
            len: len,
        }
    }

    pub fn from_str(s: &str) -> InternedString {
        let bytes: &[u8] = s.as_bytes();
        InternedString {
            data: bytes.as_ptr(),
            len: bytes.len(),
        }
    }

    pub fn as_slice<'s>(&self) -> &'s str {
        unsafe {
            let bytes = slice::from_raw_parts(self.data, self.len);
            str::from_utf8_unchecked(bytes)
        }
    }
}

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

impl PartialEq for InternedString {
    fn eq(&self, other: &InternedString) -> bool {
        self.as_slice().eq(other.as_slice())
    }
}

impl PartialEq<str> for InternedString {
    fn eq(&self, other: &str) -> bool {
        self.as_slice().eq(other)
    }
}

impl Eq for InternedString {}

impl hash::Hash for InternedString {
    fn hash<H>(&self, state: &mut H)
        where H: hash::Hasher
    {
        self.as_slice().hash(state)
    }
}

impl Borrow<str> for InternedString {
    fn borrow(&self) -> &str {
        self.as_slice()
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_slice()
    }
}

pub struct StringPool {
    start: Cell<*mut u8>,
    end: Cell<*const u8>,
    chunks: RefCell<LinkedList<Chunk>>,
    index: RefCell<HashMap<InternedString, InternedString>>,
}

static CAPACITY: usize = 10240;

impl StringPool {
    pub fn new() -> StringPool {
        StringPool{
            start: Cell::new(ptr::null_mut()),
            end: Cell::new(ptr::null()),
            chunks: RefCell::new(LinkedList::new()),
            index: RefCell::new(Default::default()),
        }
    }

    pub fn intern<'s>(&'s self, s: &str) -> &'s str {
        if s == "" { return ""; }

        let search_string = InternedString::from_str(s);

        let interned_str = match self.index.borrow_mut().entry(search_string) {
            Occupied(entry) => *entry.get(),
            Vacant(entry) => *entry.insert(self.do_intern(s)),
        };

        // The lifetime is really matched to us
        unsafe { mem::transmute(interned_str) }
    }

    fn do_intern(&self, s: &str) -> InternedString {
        self.ensure_capacity(s.len());
        self.store(s)
    }

    fn ensure_capacity(&self, str_len: usize) {
        let remaining = self.end.get() as usize - self.start.get() as usize;
        if remaining < str_len {
            self.allocate_another(max(CAPACITY, str_len))
        }
    }

    fn allocate_another(&self, capacity: usize) {
        let chunk = Chunk::new(capacity);
        self.start.set(chunk.start() as *mut u8);
        self.end.set(chunk.end());
        self.chunks.borrow_mut().push_front(chunk);
    }

    fn store(&self, s: &str) -> InternedString {
        let str_start = s.as_bytes().as_ptr();
        let str_len = s.len();

        unsafe {
            ptr::copy_nonoverlapping(str_start, self.start.get(), str_len);

            // Rebuild the string from our buffer
            let interned_str = InternedString::from_parts(self.start.get() as *const u8, str_len);

            // Increase current pointer
            self.start.set(self.start.get().offset(str_len as isize));

            interned_str
        }
    }
}

#[cfg(test)]
mod test {
    use std::borrow::ToOwned;

    use super::StringPool;

    #[test]
    fn keeps_the_same_string() {
        let s = StringPool::new();

        let interned = s.intern("hello");

        assert_eq!(interned, "hello");
    }

    #[test]
    fn does_not_reuse_the_pointer_of_the_input() {
        let s = StringPool::new();
        let input = "hello";

        let interned = s.intern(input);

        assert!(
            input.as_bytes().as_ptr() !=
            interned.as_bytes().as_ptr()
        );
    }

    #[test]
    fn reuses_the_pointer_for_repeated_input() {
        let s = StringPool::new();

        let interned1 = s.intern("world");
        let interned2 = s.intern("world");

        assert_eq!(
            interned1.as_bytes().as_ptr(),
            interned2.as_bytes().as_ptr()
        );
    }

    #[test]
    #[cfg(feature = "compile_failure")]
    fn string_cannot_outlive_the_pool() {
        let z = {
            let s = StringPool::new();
            s.intern("hello")
        };
    }

    #[test]
    fn ignores_the_lifetime_of_the_input_string() {
        let s = StringPool::new();

        let interned = {
            let allocated_string = "green".to_owned();
            s.intern(&allocated_string)
        };

        // allocated_string is gone now, but we should be able to
        // access the result value until the storage goes away.

        assert_eq!(interned, "green");
    }

    #[test]
    fn can_be_dropped_immediately() {
        StringPool::new();
    }

    fn return_populated_storage() -> (StringPool, *const u8) {
        let s = StringPool::new();
        let ptr = {
            let interned = s.intern("hello");
            interned.as_ptr()
        };
        (s, ptr)
    }

    #[test]
    fn can_return_storage_populated_with_values() {
        let (s, ptr_val) = return_populated_storage();
        let interned = s.intern("hello");
        assert_eq!(interned.as_ptr(), ptr_val);
    }
}

#[cfg(test)]
mod bench {
    use test::Bencher;

    use super::StringPool;

    #[bench]
    fn single_string(b: &mut Bencher) {
        let s = StringPool::new();
        b.iter(|| s.intern("hello"));
        b.bytes = "hello".len() as u64;
    }

    #[bench]
    fn many_unique_string(b: &mut Bencher) {
        let s = StringPool::new();

        let strings: Vec<String> =
            (0..1000)
            .map(|i| format!("str{}str", i))
            .collect();
        b.iter(|| {
            for ss in strings.iter() {
                s.intern(ss);
            }
        });
        b.bytes = strings.iter().fold(0, |a, s| a + s.len()) as u64;
    }

    #[bench]
    fn many_repeated_string(b: &mut Bencher) {
        let s = StringPool::new();

        let strings: Vec<String> =
            (0..1000)
            .map(|i| format!("str{}str", i % 100))
            .collect();
        b.iter(|| {
            for ss in strings.iter() {
                s.intern(ss);
            }
        });
        b.bytes = strings.iter().fold(0, |a, s| a + s.len()) as u64;
    }
}
<commit_msg>Use the entry API instead of matching manually<commit_after>/// Strongly borrowed from TypedArena
/// Differs in growth strategy (non-doubling)
/// And only for variable-sized strings

use std::borrow::Borrow;
use std::cell::{Cell,RefCell};
use std::cmp::max;
use std::collections::LinkedList;
use std::collections::hash_map::HashMap;
use std::default::Default;
use std::ops::Deref;
use std::slice;
use std::{fmt,hash,mem,ptr,str};

struct Chunk {
    start: *mut u8,
    capacity: usize,
}

impl Chunk {
    fn new(capacity: usize) -> Chunk {
        let mut slab: Vec<u8> = Vec::with_capacity(capacity);
        let start = slab.as_mut_ptr();

        // We will manually track the buffer and then drop it ourselves
        unsafe {
            mem::forget(slab);
        }

        Chunk {
            start: start,
            capacity: capacity,
        }
    }

    // Returns a pointer to the beginning of the allocated space.
    #[inline]
    fn start(&self) -> *const u8 {
        self.start as *const u8
    }

    // Returns a pointer to the end of the allocated space.
    #[inline]
    fn end(&self) -> *const u8 {
        unsafe { self.start().offset(self.capacity as isize) }
    }
}

impl Drop for Chunk {
    fn drop(&mut self) {
        // This is safe because we only ever store u8, which doesn't
        // have a destructor. This means the len doesn't matter, only
        // the capacity.
        unsafe {
            Vec::from_raw_parts(self.start, self.capacity, self.capacity);
        }
    }
}

#[allow(raw_pointer_derive)]
#[derive(Copy,Clone)]
pub struct InternedString {
    data: *const u8,
    len: usize,
}

impl InternedString {
    fn from_parts(data: *const u8, len: usize) -> InternedString {
        InternedString {
            data: data,
            len: len,
        }
    }

    pub fn from_str(s: &str) -> InternedString {
        let bytes: &[u8] = s.as_bytes();
        InternedString {
            data: bytes.as_ptr(),
            len: bytes.len(),
        }
    }

    pub fn as_slice<'s>(&self) -> &'s str {
        unsafe {
            let bytes = slice::from_raw_parts(self.data, self.len);
            str::from_utf8_unchecked(bytes)
        }
    }
}

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

impl PartialEq for InternedString {
    fn eq(&self, other: &InternedString) -> bool {
        self.as_slice().eq(other.as_slice())
    }
}

impl PartialEq<str> for InternedString {
    fn eq(&self, other: &str) -> bool {
        self.as_slice().eq(other)
    }
}

impl Eq for InternedString {}

impl hash::Hash for InternedString {
    fn hash<H>(&self, state: &mut H)
        where H: hash::Hasher
    {
        self.as_slice().hash(state)
    }
}

impl Borrow<str> for InternedString {
    fn borrow(&self) -> &str {
        self.as_slice()
    }
}

impl Deref for InternedString {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_slice()
    }
}

pub struct StringPool {
    start: Cell<*mut u8>,
    end: Cell<*const u8>,
    chunks: RefCell<LinkedList<Chunk>>,
    index: RefCell<HashMap<InternedString, InternedString>>,
}

static CAPACITY: usize = 10240;

impl StringPool {
    pub fn new() -> StringPool {
        StringPool{
            start: Cell::new(ptr::null_mut()),
            end: Cell::new(ptr::null()),
            chunks: RefCell::new(LinkedList::new()),
            index: RefCell::new(Default::default()),
        }
    }

    pub fn intern<'s>(&'s self, s: &str) -> &'s str {
        if s == "" { return ""; }

        let search_string = InternedString::from_str(s);

        let mut index = self.index.borrow_mut();
        let interned_str = *index.entry(search_string).or_insert_with(|| self.do_intern(s));

        // The lifetime is really matched to us
        unsafe { mem::transmute(interned_str) }
    }

    fn do_intern(&self, s: &str) -> InternedString {
        self.ensure_capacity(s.len());
        self.store(s)
    }

    fn ensure_capacity(&self, str_len: usize) {
        let remaining = self.end.get() as usize - self.start.get() as usize;
        if remaining < str_len {
            self.allocate_another(max(CAPACITY, str_len))
        }
    }

    fn allocate_another(&self, capacity: usize) {
        let chunk = Chunk::new(capacity);
        self.start.set(chunk.start() as *mut u8);
        self.end.set(chunk.end());
        self.chunks.borrow_mut().push_front(chunk);
    }

    fn store(&self, s: &str) -> InternedString {
        let str_start = s.as_bytes().as_ptr();
        let str_len = s.len();

        unsafe {
            ptr::copy_nonoverlapping(str_start, self.start.get(), str_len);

            // Rebuild the string from our buffer
            let interned_str = InternedString::from_parts(self.start.get() as *const u8, str_len);

            // Increase current pointer
            self.start.set(self.start.get().offset(str_len as isize));

            interned_str
        }
    }
}

#[cfg(test)]
mod test {
    use std::borrow::ToOwned;

    use super::StringPool;

    #[test]
    fn keeps_the_same_string() {
        let s = StringPool::new();

        let interned = s.intern("hello");

        assert_eq!(interned, "hello");
    }

    #[test]
    fn does_not_reuse_the_pointer_of_the_input() {
        let s = StringPool::new();
        let input = "hello";

        let interned = s.intern(input);

        assert!(
            input.as_bytes().as_ptr() !=
            interned.as_bytes().as_ptr()
        );
    }

    #[test]
    fn reuses_the_pointer_for_repeated_input() {
        let s = StringPool::new();

        let interned1 = s.intern("world");
        let interned2 = s.intern("world");

        assert_eq!(
            interned1.as_bytes().as_ptr(),
            interned2.as_bytes().as_ptr()
        );
    }

    #[test]
    #[cfg(feature = "compile_failure")]
    fn string_cannot_outlive_the_pool() {
        let z = {
            let s = StringPool::new();
            s.intern("hello")
        };
    }

    #[test]
    fn ignores_the_lifetime_of_the_input_string() {
        let s = StringPool::new();

        let interned = {
            let allocated_string = "green".to_owned();
            s.intern(&allocated_string)
        };

        // allocated_string is gone now, but we should be able to
        // access the result value until the storage goes away.

        assert_eq!(interned, "green");
    }

    #[test]
    fn can_be_dropped_immediately() {
        StringPool::new();
    }

    fn return_populated_storage() -> (StringPool, *const u8) {
        let s = StringPool::new();
        let ptr = {
            let interned = s.intern("hello");
            interned.as_ptr()
        };
        (s, ptr)
    }

    #[test]
    fn can_return_storage_populated_with_values() {
        let (s, ptr_val) = return_populated_storage();
        let interned = s.intern("hello");
        assert_eq!(interned.as_ptr(), ptr_val);
    }
}

#[cfg(test)]
mod bench {
    use test::Bencher;

    use super::StringPool;

    #[bench]
    fn single_string(b: &mut Bencher) {
        let s = StringPool::new();
        b.iter(|| s.intern("hello"));
        b.bytes = "hello".len() as u64;
    }

    #[bench]
    fn many_unique_string(b: &mut Bencher) {
        let s = StringPool::new();

        let strings: Vec<String> =
            (0..1000)
            .map(|i| format!("str{}str", i))
            .collect();
        b.iter(|| {
            for ss in strings.iter() {
                s.intern(ss);
            }
        });
        b.bytes = strings.iter().fold(0, |a, s| a + s.len()) as u64;
    }

    #[bench]
    fn many_repeated_string(b: &mut Bencher) {
        let s = StringPool::new();

        let strings: Vec<String> =
            (0..1000)
            .map(|i| format!("str{}str", i % 100))
            .collect();
        b.iter(|| {
            for ss in strings.iter() {
                s.intern(ss);
            }
        });
        b.bytes = strings.iter().fold(0, |a, s| a + s.len()) as u64;
    }
}
<|endoftext|>


<commit_before>use std::mem::size_of;

#[allow(dead_code)]
struct S {
    a: u64,
    b: u64,
    c: u64,
    d: u64,
}

fn main() {
    println!("{}", size_of::<u32>()); // 4
    println!("{}", size_of::<u64>()); // 8
    println!("{}", size_of::<Option<u32>>()); // 8
    println!("{}", size_of::<Option<u64>>()); // 16

    println!("{}", size_of::<S>()); // 32
    println!("{}", size_of::<Option<S>>()); // 40

    assert_eq!(size_of::<S>() + 8, size_of::<Option<S>>());
}
<commit_msg>[Rust] The size of Option<pointer-like> is the same with pointer-like<commit_after>use std::mem::size_of;

#[allow(dead_code)]
struct S {
    a: u64,
    b: u64,
    c: u64,
    d: u64,
}

fn main() {
    println!("{}", size_of::<u32>()); // 4
    println!("{}", size_of::<u64>()); // 8
    println!("{}", size_of::<Option<u32>>()); // 8
    println!("{}", size_of::<Option<u64>>()); // 16

    println!("{}", size_of::<S>()); // 32
    println!("{}", size_of::<Option<S>>()); // 40

    assert_eq!(size_of::<S>() + 8, size_of::<Option<S>>());

    println!("{}", size_of::<&S>()); // 8
    println!("{}", size_of::<Option<&S>>()); // 8
    println!("{}", size_of::<Box<S>>()); // 8
    println!("{}", size_of::<Option<Box<S>>>()); // 8

    assert_eq!(size_of::<&S>(), size_of::<Option<&S>>());
    assert_eq!(size_of::<Box<S>>(), size_of::<Option<Box<S>>>());
}
<|endoftext|>


<commit_before>use std::io;
use std::path::{PathBuf, Path};
use std::fs::File;
use std::collections::HashMap;
use object::{Object, File as OFile};
use memmap::MmapOptions;
use gimli::*;
use rustc_demangle::demangle;
use cargo::core::Workspace;

use config::Config;
use source_analysis::*;
use traces::*;

/// Describes a function as `low_pc`, `high_pc` and bool representing `is_test`.
type FuncDesc = (u64, u64, FunctionType);

#[derive(Clone, Copy, PartialEq)]
enum FunctionType {
    Generated,
    Test,
    Standard
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
pub enum LineType {
    /// Generated test main. Shouldn't be traced.
    TestMain,
    /// Entry of function known to be a test
    TestEntry(u64),
    /// Entry of function. May or may not be test
    FunctionEntry(u64),
    /// Standard statement
    Statement,
    /// Condition
    Condition,
    /// Unknown type
    Unknown,
    /// Unused meta-code
    UnusedGeneric,
}

#[derive(Clone, PartialEq, Eq, Hash)]
struct SourceLocation {
    pub path: PathBuf,
    pub line: u64,
}

#[derive(Debug, Clone)]
pub struct TracerData {
    /// Currently used to find generated __test::main and remove from coverage,
    /// may have uses in future for finding conditions etc
    pub trace_type: LineType,
    /// Start address of the line
    pub address: Option<u64>,
    /// Length of the instruction
    pub length: u64,
}

fn generate_func_desc<R, Offset>(die: &DebuggingInformationEntry<R, Offset>,
                                 debug_str: &DebugStr<R>) -> Result<FuncDesc>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut func_type = FunctionType::Standard;
    let low = die.attr_value(DW_AT_low_pc)?;
    let high = die.attr_value(DW_AT_high_pc)?;
    let linkage = die.attr_value(DW_AT_linkage_name)?;

    // Low is a program counter address so stored in an Addr
    let low = match low {
        Some(AttributeValue::Addr(x)) => x,
        _ => 0u64,
    };
    // High is an offset from the base pc, therefore is u64 data.
    let high = match high {
        Some(AttributeValue::Udata(x)) => x,
        _ => 0u64,
    };
    if let Some(AttributeValue::DebugStrRef(offset)) = linkage {
        let name = debug_str.get_str(offset)
            .and_then(|r| r.to_string().map(|s| s.to_string()))
            .unwrap_or("".into());
        let name = demangle(name.as_ref()).to_string();
        // Simplest test is whether it's in tests namespace.
        // Rust guidelines recommend all tests are in a tests module.
        func_type = if name.contains("tests::") {
            FunctionType::Test
        } else if name.contains("__test::main") {
            FunctionType::Generated
        } else {
            FunctionType::Standard
        };
    }
    Ok((low, high, func_type))
}

/// Finds all function entry points and returns a vector
/// This will identify definite tests, but may be prone to false negatives.
fn get_entry_points<R, Offset>(debug_info: &CompilationUnitHeader<R, Offset>,
                               debug_abbrev: &Abbreviations,
                               debug_str: &DebugStr<R>) -> Vec<FuncDesc>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut result:Vec<FuncDesc> = Vec::new();
    let mut cursor = debug_info.entries(debug_abbrev);
    // skip compilation unit root.
    let _ = cursor.next_entry();
    while let Ok(Some((_, node))) = cursor.next_dfs() {
        // Function DIE
        if node.tag() == DW_TAG_subprogram {

            if let Ok(fd) = generate_func_desc(node, debug_str) {
                result.push(fd);
            }
        }
    }
    result
}

fn get_addresses_from_program<R, Offset>(prog: IncompleteLineNumberProgram<R>,
                                         entries: &[(u64, LineType)],
                                         project: &Path,
                                         result: &mut HashMap<SourceLocation, Vec<TracerData>>) -> Result<()>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let ( cprog, seq) = prog.sequences()?;
    for s in seq {
        let mut temp_map: HashMap<SourceLocation, TracerData> = HashMap::new();
        let mut sm = cprog.resume_from(&s);
         while let Ok(Some((header, &ln_row))) = sm.next_row() {
            if let Some(file) = ln_row.file(header) {
                let mut path = PathBuf::new();

                if let Some(dir) = file.directory(header) {
                    if let Ok(temp) = dir.to_string() {
                        path.push(temp.as_ref());
                    }
                }
                if let Ok(p) = path.canonicalize() {
                    path = p;
                }
                // Fix relative paths and determine if in target directory
                // Source in target directory shouldn't be covered as it's either
                // autogenerated or resulting from the projects Cargo.lock
                let is_target = if path.is_relative() {
                    path.starts_with("target")
                } else {
                    path.starts_with(project.join("target"))
                };
                // Source is part of project so we cover it.
                if !is_target && path.starts_with(project) {
                    if let Some(file) = ln_row.file(header) {
                        // If we can't map to line, we can't trace it.
                        let line = match ln_row.line() {
                            Some(l) => l,
                            None => continue,
                        };
                        let file = file.path_name();

                        if let Ok(file) = file.to_string() {
                            path.push(file.as_ref());
                            if !path.is_file() {
                                // Not really a source file!
                                continue;
                            }
                            let address = ln_row.address();

                            let desc = entries.iter()
                                              .filter(|&&(addr, _)| addr == address )
                                              .map(|&(_, t)| t)
                                              .nth(0)
                                              .unwrap_or(LineType::Unknown);
                            let loc = SourceLocation {
                                path: path,
                                line: line,
                            };
                            // This keeps the lowest addressed instrumentation point
                            if !temp_map.contains_key(&loc) && desc != LineType::TestMain {
                                temp_map.insert(loc, TracerData {
                                    address: Some(address),
                                    trace_type: desc,
                                    length: 1
                                });
                            }
                        }
                    }
                }
            }
        }
        // Merge temp_map into result. This gets a trace point for each line number
        // sequence a trace appears in.
        for (k, v) in &temp_map {
            if result.contains_key(k) {
                let mut x = result.get_mut(k).unwrap();
                x.push(v.clone());
            } else {
                result.insert(k.clone(), vec![v.clone()]);
            }
        }
    }
    Ok(())
}

fn get_line_addresses(endian: RunTimeEndian,
                      project: &Path,
                      obj: &OFile,
                      analysis: &HashMap<PathBuf, LineAnalysis>,
                      config: &Config) -> Result<TraceMap>  {

    let mut result = TraceMap::new();
    let debug_info = obj.section_data_by_name(".debug_info").unwrap_or(&[]);
    let debug_info = DebugInfo::new(debug_info, endian);
    let debug_abbrev = obj.section_data_by_name(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = DebugAbbrev::new(debug_abbrev, endian);
    let debug_strings = obj.section_data_by_name(".debug_str").unwrap_or(&[]);
    let debug_strings = DebugStr::new(debug_strings, endian);
    let debug_line = obj.section_data_by_name(".debug_line").unwrap_or(&[]);
    let debug_line = DebugLine::new(debug_line, endian);

    let mut iter = debug_info.units();
    while let Ok(Some(cu)) = iter.next() {
        let addr_size = cu.address_size();
        let abbr = match cu.abbreviations(&debug_abbrev) {
            Ok(a) => a,
            _ => continue,
        };
        let entries = get_entry_points(&cu, &abbr, &debug_strings)
            .iter()
            .map(|&(a, b, c)| {
                match c {
                    FunctionType::Test => (a, LineType::TestEntry(b)),
                    FunctionType::Standard => (a, LineType::FunctionEntry(b)),
                    FunctionType::Generated => (a, LineType::TestMain),
                }
            }).collect::<Vec<_>>();
        if let Ok(Some((_, root))) = cu.entries(&abbr).next_dfs() {
            let offset = match root.attr_value(DW_AT_stmt_list) {
                Ok(Some(AttributeValue::DebugLineRef(o))) => o,
                _ => continue,
            };
            let prog = debug_line.program(offset, addr_size, None, None)?;
            let mut temp_map:HashMap<SourceLocation, Vec<TracerData>> = HashMap::new();
            if let Err(e) = get_addresses_from_program(prog, &entries, project, &mut temp_map) {
                if config.verbose {
                    println!("Potential issue reading test addresses {}", e);
                }
            }
            else {

                let temp_map = temp_map.into_iter()
                                       .filter(|&(ref k, _)| !(config.ignore_tests && k.path.starts_with(project.join("tests"))))
                                       .filter(|&(ref k, _)| !(config.exclude_path(&k.path)))
                                       .filter(|&(ref k, _)| !analysis.should_ignore(k.path.as_ref(), &(k.line as usize)))
                                       .collect::<HashMap<SourceLocation, Vec<TracerData>>>();
                let mut tracemap = TraceMap::new();
                for (k, val) in &temp_map {
                    for v in val.iter() {
                        tracemap.add_trace(&k.path, Trace {
                            line: k.line,
                            address: v.address,
                            length: 1,
                            stats: CoverageStat::Line(0)
                        });
                    }
                }
                result.merge(&tracemap);
            }
        }
    }

    for (file, ref line_analysis) in analysis.iter() {
        if config.exclude_path(file) {
            continue;
        }
        for line in &line_analysis.cover {
            let line = *line as u64;
            if !result.contains_location(file, line) && !line_analysis.should_ignore(&(line as usize)) {
                result.add_trace(file, Trace {
                    line: line,
                    address: None,
                    length: 0,
                    stats: CoverageStat::Line(0),
                });
            }
        }
    }
    Ok(result)
}

pub fn generate_tracemap(project: &Workspace, test: &Path, config: &Config) -> io::Result<TraceMap> {
    let manifest = project.root();
    let file = File::open(test)?;
    let file = unsafe {
        MmapOptions::new().map(&file)?
    };
    if let Ok(obj) = OFile::parse(&*file) {
        let analysis = get_line_analysis(project, config);
        let endian = if obj.is_little_endian() {
            RunTimeEndian::Little
        } else {
            RunTimeEndian::Big
        };
        if let Ok(result) = get_line_addresses(endian, manifest, &obj, &analysis, config) {
            Ok(result)
        } else {
            Err(io::Error::new(io::ErrorKind::InvalidData, "Error while parsing"))
        }
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}

<commit_msg>Improved coverage of chained calls<commit_after>use std::io;
use std::path::{PathBuf, Path};
use std::fs::File;
use std::collections::HashMap;
use object::{Object, File as OFile};
use memmap::MmapOptions;
use gimli::*;
use rustc_demangle::demangle;
use cargo::core::Workspace;

use config::Config;
use source_analysis::*;
use traces::*;

/// Describes a function as `low_pc`, `high_pc` and bool representing `is_test`.
type FuncDesc = (u64, u64, FunctionType);

#[derive(Clone, Copy, PartialEq)]
enum FunctionType {
    Generated,
    Test,
    Standard
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
pub enum LineType {
    /// Generated test main. Shouldn't be traced.
    TestMain,
    /// Entry of function known to be a test
    TestEntry(u64),
    /// Entry of function. May or may not be test
    FunctionEntry(u64),
    /// Standard statement
    Statement,
    /// Condition
    Condition,
    /// Unknown type
    Unknown,
    /// Unused meta-code
    UnusedGeneric,
}

#[derive(Clone, PartialEq, Eq, Hash)]
struct SourceLocation {
    pub path: PathBuf,
    pub line: u64,
}

#[derive(Debug, Clone)]
pub struct TracerData {
    /// Currently used to find generated __test::main and remove from coverage,
    /// may have uses in future for finding conditions etc
    pub trace_type: LineType,
    /// Start address of the line
    pub address: Option<u64>,
    /// Length of the instruction
    pub length: u64,
}

fn generate_func_desc<R, Offset>(die: &DebuggingInformationEntry<R, Offset>,
                                 debug_str: &DebugStr<R>) -> Result<FuncDesc>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut func_type = FunctionType::Standard;
    let low = die.attr_value(DW_AT_low_pc)?;
    let high = die.attr_value(DW_AT_high_pc)?;
    let linkage = die.attr_value(DW_AT_linkage_name)?;

    // Low is a program counter address so stored in an Addr
    let low = match low {
        Some(AttributeValue::Addr(x)) => x,
        _ => 0u64,
    };
    // High is an offset from the base pc, therefore is u64 data.
    let high = match high {
        Some(AttributeValue::Udata(x)) => x,
        _ => 0u64,
    };
    if let Some(AttributeValue::DebugStrRef(offset)) = linkage {
        let name = debug_str.get_str(offset)
            .and_then(|r| r.to_string().map(|s| s.to_string()))
            .unwrap_or("".into());
        let name = demangle(name.as_ref()).to_string();
        // Simplest test is whether it's in tests namespace.
        // Rust guidelines recommend all tests are in a tests module.
        func_type = if name.contains("tests::") {
            FunctionType::Test
        } else if name.contains("__test::main") {
            FunctionType::Generated
        } else {
            FunctionType::Standard
        };
    }
    Ok((low, high, func_type))
}

/// Finds all function entry points and returns a vector
/// This will identify definite tests, but may be prone to false negatives.
fn get_entry_points<R, Offset>(debug_info: &CompilationUnitHeader<R, Offset>,
                               debug_abbrev: &Abbreviations,
                               debug_str: &DebugStr<R>) -> Vec<FuncDesc>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let mut result:Vec<FuncDesc> = Vec::new();
    let mut cursor = debug_info.entries(debug_abbrev);
    // skip compilation unit root.
    let _ = cursor.next_entry();
    while let Ok(Some((_, node))) = cursor.next_dfs() {
        // Function DIE
        if node.tag() == DW_TAG_subprogram {

            if let Ok(fd) = generate_func_desc(node, debug_str) {
                result.push(fd);
            }
        }
    }
    result
}

fn get_addresses_from_program<R, Offset>(prog: IncompleteLineNumberProgram<R>,
                                         entries: &[(u64, LineType)],
                                         project: &Path,
                                         result: &mut HashMap<SourceLocation, Vec<TracerData>>) -> Result<()>
    where R: Reader<Offset = Offset>,
          Offset: ReaderOffset
{
    let ( cprog, seq) = prog.sequences()?;
    for s in seq {
        let mut last_loc = SourceLocation{
            path: PathBuf::new(),
            line: 0,
        };
        let mut sm = cprog.resume_from(&s);
         while let Ok(Some((header, &ln_row))) = sm.next_row() {
            if let Some(file) = ln_row.file(header) {
                let mut path = PathBuf::new();

                if let Some(dir) = file.directory(header) {
                    if let Ok(temp) = dir.to_string() {
                        path.push(temp.as_ref());
                    }
                }
                if let Ok(p) = path.canonicalize() {
                    path = p;
                }
                // Fix relative paths and determine if in target directory
                // Source in target directory shouldn't be covered as it's either
                // autogenerated or resulting from the projects Cargo.lock
                let is_target = if path.is_relative() {
                    path.starts_with("target")
                } else {
                    path.starts_with(project.join("target"))
                };
                // Source is part of project so we cover it.
                if !is_target && path.starts_with(project) {
                    if let Some(file) = ln_row.file(header) {
                        // If we can't map to line, we can't trace it.
                        let line = match ln_row.line() {
                            Some(l) => l,
                            None => continue,
                        };
                        let file = file.path_name();

                        if let Ok(file) = file.to_string() {
                            path.push(file.as_ref());
                            if !path.is_file() {
                                // Not really a source file!
                                continue;
                            }
                            let address = ln_row.address();

                            let desc = entries.iter()
                                              .filter(|&&(addr, _)| addr == address )
                                              .map(|&(_, t)| t)
                                              .nth(0)
                                              .unwrap_or(LineType::Unknown);
                            let loc = SourceLocation {
                                path: path,
                                line: line,
                            };
                            if loc != last_loc && desc != LineType::TestMain {
                                let temp_trace = TracerData {
                                    address: Some(address),
                                    trace_type: desc,
                                    length: 1,
                                };
                                if result.contains_key(&loc) {
                                    let mut x = result.get_mut(&loc).unwrap();
                                    x.push(temp_trace);
                                } else {
                                    result.insert(loc.clone(), vec![temp_trace]);
                                }
                            }
                            last_loc = loc;
                        }
                    }
                }
            }
        }
    }
    Ok(())
}

fn get_line_addresses(endian: RunTimeEndian,
                      project: &Path,
                      obj: &OFile,
                      analysis: &HashMap<PathBuf, LineAnalysis>,
                      config: &Config) -> Result<TraceMap>  {

    let mut result = TraceMap::new();
    let debug_info = obj.section_data_by_name(".debug_info").unwrap_or(&[]);
    let debug_info = DebugInfo::new(debug_info, endian);
    let debug_abbrev = obj.section_data_by_name(".debug_abbrev").unwrap_or(&[]);
    let debug_abbrev = DebugAbbrev::new(debug_abbrev, endian);
    let debug_strings = obj.section_data_by_name(".debug_str").unwrap_or(&[]);
    let debug_strings = DebugStr::new(debug_strings, endian);
    let debug_line = obj.section_data_by_name(".debug_line").unwrap_or(&[]);
    let debug_line = DebugLine::new(debug_line, endian);

    let mut iter = debug_info.units();
    while let Ok(Some(cu)) = iter.next() {
        let addr_size = cu.address_size();
        let abbr = match cu.abbreviations(&debug_abbrev) {
            Ok(a) => a,
            _ => continue,
        };
        let entries = get_entry_points(&cu, &abbr, &debug_strings)
            .iter()
            .map(|&(a, b, c)| {
                match c {
                    FunctionType::Test => (a, LineType::TestEntry(b)),
                    FunctionType::Standard => (a, LineType::FunctionEntry(b)),
                    FunctionType::Generated => (a, LineType::TestMain),
                }
            }).collect::<Vec<_>>();
        if let Ok(Some((_, root))) = cu.entries(&abbr).next_dfs() {
            let offset = match root.attr_value(DW_AT_stmt_list) {
                Ok(Some(AttributeValue::DebugLineRef(o))) => o,
                _ => continue,
            };
            let prog = debug_line.program(offset, addr_size, None, None)?;
            let mut temp_map:HashMap<SourceLocation, Vec<TracerData>> = HashMap::new();
            if let Err(e) = get_addresses_from_program(prog, &entries, project, &mut temp_map) {
                if config.verbose {
                    println!("Potential issue reading test addresses {}", e);
                }
            }
            else {

                let temp_map = temp_map.into_iter()
                                       .filter(|&(ref k, _)| !(config.ignore_tests && k.path.starts_with(project.join("tests"))))
                                       .filter(|&(ref k, _)| !(config.exclude_path(&k.path)))
                                       .filter(|&(ref k, _)| !analysis.should_ignore(k.path.as_ref(), &(k.line as usize)))
                                       .collect::<HashMap<SourceLocation, Vec<TracerData>>>();
                let mut tracemap = TraceMap::new();
                for (k, val) in &temp_map {
                    for v in val.iter() {
                        tracemap.add_trace(&k.path, Trace {
                            line: k.line,
                            address: v.address,
                            length: 1,
                            stats: CoverageStat::Line(0)
                        });
                    }
                }
                result.merge(&tracemap);
            }
        }
    }

    for (file, ref line_analysis) in analysis.iter() {
        if config.exclude_path(file) {
            continue;
        }
        for line in &line_analysis.cover {
            let line = *line as u64;
            if !result.contains_location(file, line) && !line_analysis.should_ignore(&(line as usize)) {
                result.add_trace(file, Trace {
                    line: line,
                    address: None,
                    length: 0,
                    stats: CoverageStat::Line(0),
                });
            }
        }
    }
    Ok(result)
}

pub fn generate_tracemap(project: &Workspace, test: &Path, config: &Config) -> io::Result<TraceMap> {
    let manifest = project.root();
    let file = File::open(test)?;
    let file = unsafe {
        MmapOptions::new().map(&file)?
    };
    if let Ok(obj) = OFile::parse(&*file) {
        let analysis = get_line_analysis(project, config);
        let endian = if obj.is_little_endian() {
            RunTimeEndian::Little
        } else {
            RunTimeEndian::Big
        };
        if let Ok(result) = get_line_addresses(endian, manifest, &obj, &analysis, config) {
            Ok(result)
        } else {
            Err(io::Error::new(io::ErrorKind::InvalidData, "Error while parsing"))
        }
    } else {
        Err(io::Error::new(io::ErrorKind::InvalidData, "Unable to parse binary."))
    }
}

<|endoftext|>