<commit_before>use font::{Font, FontDescriptor, FontGroup, FontStyle, SelectorPlatformIdentifier};
use font::{SelectorStubDummy, SpecifiedFontStyle, UsedFontStyle};
use font_list::FontList;
use native::FontHandle;
use util::cache::Cache;
use util::cache::MonoCache;

use azure::azure_hl::BackendType;
use core::dvec::DVec;
use core::send_map::linear::LinearMap;
use core::send_map::linear;

// TODO(Issue #164): delete, and get default font from font list
const TEST_FONT: [u8 * 33004] = include_bin!("JosefinSans-SemiBold.ttf");

fn test_font_bin() -> ~[u8] {
    return vec::from_fn(33004, |i| TEST_FONT[i]);
}

// TODO(Rust #3934): creating lots of new dummy styles is a workaround
// for not being able to store symbolic enums in top-level constants.
pub fn dummy_style() -> FontStyle {
    use font::FontWeight300;
    return FontStyle {
        pt_size: 20f,
        weight: FontWeight300,
        italic: false,
        oblique: false,
        families: ~"serif, sans-serif",
    }
}

#[cfg(target_os = "macos")]
type FontContextHandle/& = quartz::font_context::QuartzFontContextHandle;

#[cfg(target_os = "linux")]
type FontContextHandle/& = freetype_impl::font_context::FreeTypeFontContextHandle;

pub trait FontContextHandleMethods {
    pure fn clone(&const self) -> FontContextHandle;
    fn create_font_from_identifier(~str, UsedFontStyle) -> Result<FontHandle, ()>;
}

// TODO(Issue #163): this is a workaround for static methods, traits,
// and typedefs not working well together. It should be removed.
pub impl FontContextHandle {
    #[cfg(target_os = "macos")]
    static pub fn new() -> FontContextHandle {
        quartz::font_context::QuartzFontContextHandle::new()
    }

    #[cfg(target_os = "linux")]
    static pub fn new() -> FontContextHandle {
        freetype_impl::font_context::FreeTypeFontContextHandle::new()
    }
}

#[allow(non_implicitly_copyable_typarams)]
pub struct FontContext {
    instance_cache: MonoCache<FontDescriptor, @Font>,
    font_list: Option<FontList>, // only needed by layout
    handle: FontContextHandle,
    backend: BackendType,
    generic_fonts: LinearMap<~str,~str>,
}

#[allow(non_implicitly_copyable_typarams)]
pub impl FontContext {
    static fn new(backend: BackendType, needs_font_list: bool) -> FontContext {
        let handle = FontContextHandle::new();
        let font_list = if needs_font_list { Some(FontList::new(&handle)) } else { None };

        // TODO: Allow users to specify these.
        let mut generic_fonts = linear::linear_map_with_capacity(5);
        generic_fonts.insert(~"serif", ~"Times");
        generic_fonts.insert(~"sans-serif", ~"Arial");
        generic_fonts.insert(~"cursive", ~"Apple Chancery");
        generic_fonts.insert(~"fantasy", ~"Papyrus");
        generic_fonts.insert(~"monospace", ~"Menlo");

        FontContext {
            // TODO(Rust #3902): remove extraneous type parameters once they are inferred correctly.
            instance_cache: Cache::new::<FontDescriptor,@Font,MonoCache<FontDescriptor,@Font>>(10),
            font_list: move font_list,
            handle: move handle,
            backend: backend,
            generic_fonts: move generic_fonts,
        }
    }

    priv pure fn get_font_list(&self) -> &self/FontList {
        option::get_ref(&self.font_list)
    }

    fn get_resolved_font_for_style(style: &SpecifiedFontStyle) -> @FontGroup {
        // TODO(Issue #178, E): implement a cache of FontGroup instances.
        self.create_font_group(style)
    }

    fn get_font_by_descriptor(desc: &FontDescriptor) -> Result<@Font, ()> {
        match self.instance_cache.find(desc) {
            Some(f) => Ok(f),
            None => {
                let result = self.create_font_instance(desc);
                match result {
                    Ok(font) => {
                        self.instance_cache.insert(desc, font);
                    }, _ => {}
                };
                result
            }
        }
    }

    priv fn transform_family(&self, family: &str) -> ~str {
        // FIXME: Need a find_like() in LinearMap.
        let family = family.to_str();
        debug!("(transform family) searching for `%s`", family);
        match self.generic_fonts.find_ref(&family) {
            None => move family,
            Some(move mapped_family) => copy *mapped_family
        }
    }

    // TODO:(Issue #196): cache font groups on the font context.
    priv fn create_font_group(style: &SpecifiedFontStyle) -> @FontGroup {
        let fonts = DVec();

        debug!("(create font group) --- starting ---");

        // TODO(Issue #193): make iteration over 'font-family' more robust.
        for str::split_char_each(style.families, ',') |family| {
            let family_name = str::trim(family);
            let transformed_family_name = self.transform_family(family_name);
            debug!("(create font group) transformed family is `%s`", transformed_family_name);

            let list = self.get_font_list();

            let result = list.find_font_in_family(transformed_family_name, style);
            let mut found = false;
            do result.iter |font_entry| {
                found = true;
                // TODO(Issue #203): route this instantion through FontContext's Font instance cache.
                let instance = Font::new_from_existing_handle(&self, &font_entry.handle, style, self.backend);
                do result::iter(&instance) |font: &@Font| { fonts.push(*font); }
            };

            if !found {
                debug!("(create font group) didn't find `%s`", transformed_family_name);
            }
        }

        // TODO(Issue #194): *always* attach a fallback font to the
        // font list, so that this assertion will never fail.

        // assert fonts.len() > 0;
        if fonts.len() == 0 {
            let desc = FontDescriptor::new(font_context::dummy_style(), SelectorStubDummy);
            debug!("(create font group) trying descriptor `%?`", desc);
            match self.get_font_by_descriptor(&desc) {
                Ok(instance) => fonts.push(instance),
                Err(()) => {}
            }
        }
        assert fonts.len() > 0;
        // TODO(Issue #179): Split FontStyle into specified and used styles
        let used_style = copy *style;

        debug!("(create font group) --- finished ---");

        @FontGroup::new(style.families.to_managed(), &used_style, dvec::unwrap(move fonts))
    }

    priv fn create_font_instance(desc: &FontDescriptor) -> Result<@Font, ()> {
        return match &desc.selector {
            &SelectorStubDummy => {
                Font::new_from_buffer(&self, test_font_bin(), &desc.style, self.backend)
            },
            // TODO(Issue #174): implement by-platform-name font selectors.
            &SelectorPlatformIdentifier(ref identifier) => {
                let result_handle = self.handle.create_font_from_identifier(copy *identifier,
                                                                            copy desc.style);
                result::chain(move result_handle, |handle| {
                    Ok(Font::new_from_adopted_handle(&self,
                                                     move handle,
                                                     &desc.style,
                                                     self.backend))
                })
            }
        };
    }
}
<commit_msg>Make the default serif 'Times New Roman', not 'Times'<commit_after>use font::{Font, FontDescriptor, FontGroup, FontStyle, SelectorPlatformIdentifier};
use font::{SelectorStubDummy, SpecifiedFontStyle, UsedFontStyle};
use font_list::FontList;
use native::FontHandle;
use util::cache::Cache;
use util::cache::MonoCache;

use azure::azure_hl::BackendType;
use core::dvec::DVec;
use core::send_map::linear::LinearMap;
use core::send_map::linear;

// TODO(Issue #164): delete, and get default font from font list
const TEST_FONT: [u8 * 33004] = include_bin!("JosefinSans-SemiBold.ttf");

fn test_font_bin() -> ~[u8] {
    return vec::from_fn(33004, |i| TEST_FONT[i]);
}

// TODO(Rust #3934): creating lots of new dummy styles is a workaround
// for not being able to store symbolic enums in top-level constants.
pub fn dummy_style() -> FontStyle {
    use font::FontWeight300;
    return FontStyle {
        pt_size: 20f,
        weight: FontWeight300,
        italic: false,
        oblique: false,
        families: ~"serif, sans-serif",
    }
}

#[cfg(target_os = "macos")]
type FontContextHandle/& = quartz::font_context::QuartzFontContextHandle;

#[cfg(target_os = "linux")]
type FontContextHandle/& = freetype_impl::font_context::FreeTypeFontContextHandle;

pub trait FontContextHandleMethods {
    pure fn clone(&const self) -> FontContextHandle;
    fn create_font_from_identifier(~str, UsedFontStyle) -> Result<FontHandle, ()>;
}

// TODO(Issue #163): this is a workaround for static methods, traits,
// and typedefs not working well together. It should be removed.
pub impl FontContextHandle {
    #[cfg(target_os = "macos")]
    static pub fn new() -> FontContextHandle {
        quartz::font_context::QuartzFontContextHandle::new()
    }

    #[cfg(target_os = "linux")]
    static pub fn new() -> FontContextHandle {
        freetype_impl::font_context::FreeTypeFontContextHandle::new()
    }
}

#[allow(non_implicitly_copyable_typarams)]
pub struct FontContext {
    instance_cache: MonoCache<FontDescriptor, @Font>,
    font_list: Option<FontList>, // only needed by layout
    handle: FontContextHandle,
    backend: BackendType,
    generic_fonts: LinearMap<~str,~str>,
}

#[allow(non_implicitly_copyable_typarams)]
pub impl FontContext {
    static fn new(backend: BackendType, needs_font_list: bool) -> FontContext {
        let handle = FontContextHandle::new();
        let font_list = if needs_font_list { Some(FontList::new(&handle)) } else { None };

        // TODO: Allow users to specify these.
        let mut generic_fonts = linear::linear_map_with_capacity(5);
        generic_fonts.insert(~"serif", ~"Times New Roman");
        generic_fonts.insert(~"sans-serif", ~"Arial");
        generic_fonts.insert(~"cursive", ~"Apple Chancery");
        generic_fonts.insert(~"fantasy", ~"Papyrus");
        generic_fonts.insert(~"monospace", ~"Menlo");

        FontContext {
            // TODO(Rust #3902): remove extraneous type parameters once they are inferred correctly.
            instance_cache: Cache::new::<FontDescriptor,@Font,MonoCache<FontDescriptor,@Font>>(10),
            font_list: move font_list,
            handle: move handle,
            backend: backend,
            generic_fonts: move generic_fonts,
        }
    }

    priv pure fn get_font_list(&self) -> &self/FontList {
        option::get_ref(&self.font_list)
    }

    fn get_resolved_font_for_style(style: &SpecifiedFontStyle) -> @FontGroup {
        // TODO(Issue #178, E): implement a cache of FontGroup instances.
        self.create_font_group(style)
    }

    fn get_font_by_descriptor(desc: &FontDescriptor) -> Result<@Font, ()> {
        match self.instance_cache.find(desc) {
            Some(f) => Ok(f),
            None => {
                let result = self.create_font_instance(desc);
                match result {
                    Ok(font) => {
                        self.instance_cache.insert(desc, font);
                    }, _ => {}
                };
                result
            }
        }
    }

    priv fn transform_family(&self, family: &str) -> ~str {
        // FIXME: Need a find_like() in LinearMap.
        let family = family.to_str();
        debug!("(transform family) searching for `%s`", family);
        match self.generic_fonts.find_ref(&family) {
            None => move family,
            Some(move mapped_family) => copy *mapped_family
        }
    }

    // TODO:(Issue #196): cache font groups on the font context.
    priv fn create_font_group(style: &SpecifiedFontStyle) -> @FontGroup {
        let fonts = DVec();

        debug!("(create font group) --- starting ---");

        // TODO(Issue #193): make iteration over 'font-family' more robust.
        for str::split_char_each(style.families, ',') |family| {
            let family_name = str::trim(family);
            let transformed_family_name = self.transform_family(family_name);
            debug!("(create font group) transformed family is `%s`", transformed_family_name);

            let list = self.get_font_list();

            let result = list.find_font_in_family(transformed_family_name, style);
            let mut found = false;
            do result.iter |font_entry| {
                found = true;
                // TODO(Issue #203): route this instantion through FontContext's Font instance cache.
                let instance = Font::new_from_existing_handle(&self, &font_entry.handle, style, self.backend);
                do result::iter(&instance) |font: &@Font| { fonts.push(*font); }
            };

            if !found {
                debug!("(create font group) didn't find `%s`", transformed_family_name);
            }
        }

        // TODO(Issue #194): *always* attach a fallback font to the
        // font list, so that this assertion will never fail.

        // assert fonts.len() > 0;
        if fonts.len() == 0 {
            let desc = FontDescriptor::new(font_context::dummy_style(), SelectorStubDummy);
            debug!("(create font group) trying descriptor `%?`", desc);
            match self.get_font_by_descriptor(&desc) {
                Ok(instance) => fonts.push(instance),
                Err(()) => {}
            }
        }
        assert fonts.len() > 0;
        // TODO(Issue #179): Split FontStyle into specified and used styles
        let used_style = copy *style;

        debug!("(create font group) --- finished ---");

        @FontGroup::new(style.families.to_managed(), &used_style, dvec::unwrap(move fonts))
    }

    priv fn create_font_instance(desc: &FontDescriptor) -> Result<@Font, ()> {
        return match &desc.selector {
            &SelectorStubDummy => {
                Font::new_from_buffer(&self, test_font_bin(), &desc.style, self.backend)
            },
            // TODO(Issue #174): implement by-platform-name font selectors.
            &SelectorPlatformIdentifier(ref identifier) => {
                let result_handle = self.handle.create_font_from_identifier(copy *identifier,
                                                                            copy desc.style);
                result::chain(move result_handle, |handle| {
                    Ok(Font::new_from_adopted_handle(&self,
                                                     move handle,
                                                     &desc.style,
                                                     self.backend))
                })
            }
        };
    }
}
<|endoftext|>


<commit_before>    //   Copyright 2014 Colin Sherratt
//
//   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.

#![crate_name = "snowmew-render-gfx"]
#![crate_type = "lib"]

#![feature(phase)]
#![allow(dead_code)]

//extern crate debug;

extern crate sync;
extern crate time;
extern crate libc;

extern crate opencl;
extern crate cow;
extern crate gl;
extern crate glfw;

#[phase(plugin)]
extern crate gfx_macros;
extern crate gfx;
extern crate device;
extern crate render;

extern crate snowmew  = "snowmew-core";
extern crate position = "snowmew-position";
extern crate graphics = "snowmew-graphics";
extern crate render_data = "snowmew-render-data";

use std::collections::hashmap::HashMap;

use opencl::hl;
use sync::Arc;

use position::Positions;
use graphics::Graphics;
use snowmew::common::ObjectKey;
use snowmew::io::Window;

use graphics::geometry::{Geo, GeoTex, GeoNorm, GeoTexNorm, GeoTexNormTan};

use cow::join::{join_set_to_map, join_maps};
use render_data::RenderData;

use gfx::{Device, DeviceHelper};

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_150: b"
    #version 150 core
    uniform mat4 proj_mat;
    uniform mat4 view_mat;
    uniform mat4 model_mat;

    in vec3 position;
    in vec2 texture;

    out vec2 o_texture;

    void main() {
        gl_Position = proj_mat * view_mat * model_mat * vec4(position, 1.0);
        o_texture = texture;
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_150: b"
    #version 150 core
    uniform vec4 ka_color;
    uniform int ka_use_texture;
    uniform sampler2D ka_texture;

    in vec2 o_texture;

    out vec4 o_Color;

    void main() {
        if (1 == ka_use_texture) {
            o_Color = texture(ka_texture, o_texture);
        } else {
            o_Color = ka_color;
        }
    }
"
};

#[shader_param(MyProgram)]
struct Params {
    proj_mat: [[f32, ..4], ..4],
    view_mat: [[f32, ..4], ..4],
    model_mat: [[f32, ..4], ..4],
    ka_color: [f32, ..4],
    ka_use_texture: i32,
    ka_texture: gfx::shade::TextureParam,
}

struct Mesh {
    mesh: render::mesh::Mesh,
    index: device::BufferHandle<u32>
}

pub struct RenderManager {
    data: Params,
    graphics: render::Graphics<device::gl::GlDevice, device::gl::draw::GlCommandBuffer>,
    frame: render::target::Frame,
    state: render::state::DrawState,
    prog: device::Handle<u32,device::shade::ProgramInfo>,
    meshes: HashMap<ObjectKey, Mesh>,
    textures: HashMap<ObjectKey, device::TextureHandle>,
    sampler: device::SamplerHandle,
    window: Window
}

impl RenderManager {

    fn _new(mut device: gfx::GlDevice,
            window: Window,
            size: (i32, i32),
            _: Option<Arc<hl::Device>>) -> RenderManager {

        let (width, height) = size;
        let frame = gfx::Frame::new(width as u16, height as u16);
        let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

        let sampler = device.create_sampler(
            gfx::tex::SamplerInfo::new(
                    gfx::tex::Bilinear, gfx::tex::Tile
            )
        );

        let (prog, data) = {
            let tinfo = gfx::tex::TextureInfo {
                width: 1,
                height: 1,
                depth: 1,
                levels: 1,
                kind: gfx::tex::Texture2D,
                format: gfx::tex::RGBA8,
            };

            let img_info = tinfo.to_image_info();
            let dummy_texture = device.create_texture(tinfo)
                                      .ok().expect("Failed to create texture");
            device.update_texture(&dummy_texture,
                                  &img_info,
                                  &vec![0u8, 0, 0, 0].as_slice());

            let data = Params {
                proj_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                view_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                model_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                ka_use_texture: 0,
                ka_color: [1., 1., 1., 1.],
                ka_texture: (dummy_texture, Some(sampler))
            };
            (device.link_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
                  .ok().expect("Failed to link program"),
             data)
        };

        RenderManager {
            data: data,
            graphics: gfx::Graphics::new(device),
            frame: frame,
            state: state,
            prog: prog,
            meshes: HashMap::new(),
            textures: HashMap::new(),
            sampler: sampler,
            window: window
        }
    }

    fn load_meshes<RD: RenderData>(&mut self, db: &RD) {
        for (oid, vb) in db.vertex_buffer_iter() {
            if self.meshes.find(oid).is_none() {
                let mesh = match vb.vertex {
                    Geo(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoTex(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoNorm(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoTexNorm(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoTexNormTan(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    }
                };

                let vb: Vec<u32> = vb.index.iter().map(|&x| x as u32).collect();

                let index = self.graphics.device.create_buffer_static(&vb);

                self.meshes.insert(*oid, Mesh {
                    index: index,
                    mesh: mesh
                });
            }
        }
    }

    fn load_textures<RD: RenderData>(&mut self, db: &RD) {
        for (oid, text) in db.texture_iter() {
            if self.textures.find(oid).is_none() {
                let tinfo = gfx::tex::TextureInfo {
                    width: text.width() as u16,
                    height: text.height() as u16,
                    depth: 1 as u16,
                    levels: 1,
                    kind: gfx::tex::Texture2D,
                    format: match text.depth() {
                        4 => gfx::tex::Unsigned(gfx::tex::RGBA, 8, gfx::attrib::IntNormalized),
                        3 => gfx::tex::Unsigned(gfx::tex::RGB, 8, gfx::attrib::IntNormalized),
                        _ => fail!("Unsupported color depth")
                    }
                };

                let img_info = tinfo.to_image_info();
                let texture = self.graphics.device.create_texture(tinfo)
                                         .ok().expect("Failed to create texture");
                self.graphics.device.update_texture(&texture, &img_info, &text.data().to_vec());
                self.textures.insert(*oid, texture);
            }
        }
    }

    fn draw<RD: RenderData>(&mut self, db: &RD, scene: ObjectKey, camera: ObjectKey) {
        let cdata = gfx::ClearData {
            color: Some([0.3, 0.3, 0.3, 1.0]),
            depth: Some(1.0),
            stencil: None,
        };
        let start = time::precise_time_s();
        self.graphics.clear(cdata, &self.frame);

        let camera_trans = db.position(camera);
        let camera = snowmew::camera::Camera::new(camera_trans);

        let proj = camera.projection_matrix(16. / 9.);
        self.data.proj_mat =
            [[proj.x.x, proj.x.y, proj.x.z, proj.x.w],
             [proj.y.x, proj.y.y, proj.y.z, proj.y.w],
             [proj.z.x, proj.z.y, proj.z.z, proj.z.w],
             [proj.w.x, proj.w.y, proj.w.z, proj.w.w]];

        let view = camera.view_matrix();
        self.data.view_mat =
            [[view.x.x, view.x.y, view.x.z, view.x.w],
             [view.y.x, view.y.y, view.y.z, view.y.w],
             [view.z.x, view.z.y, view.z.z, view.z.w],
             [view.w.x, view.w.y, view.w.z, view.w.w]];

        for (id, (draw, _)) in join_set_to_map(db.scene_iter(scene),
                                               join_maps(db.drawable_iter(),
                                                         db.location_iter())) {

            let geo = db.geometry(draw.geometry).expect("failed to find geometry");
            let mat = db.material(draw.material).expect("Could not find material");
            let vb = self.meshes.find(&geo.vb).expect("Could not get vertex buffer");

            let model = db.position(*id);

            self.data.model_mat =
                [[model.x.x, model.x.y, model.x.z, model.x.w],
                 [model.y.x, model.y.y, model.y.z, model.y.w],
                 [model.z.x, model.z.y, model.z.z, model.z.w],
                 [model.w.x, model.w.y, model.w.z, model.w.w]];

            self.data.ka_use_texture = match mat.map_ka() {
                Some(tid) => {
                    let &texture = self.textures.find(&tid).expect("Texture not loaded");
                    self.data.ka_texture = (texture, Some(self.sampler));
                    1
                }
                None => {
                    let [r, g, b] = mat.ka();
                    self.data.ka_color = [r, g, b, 1.];
                    0
                }
            };

            let batch: MyProgram = self.graphics.make_batch(
                &vb.mesh,
                gfx::IndexSlice32(gfx::TriangleList,
                                  vb.index,
                                  geo.offset as u32,
                                  geo.count as u32),
                &self.prog,
                &self.state
            ).unwrap();

            self.graphics.draw(&batch, &self.data, &self.frame);
        }

        self.graphics.end_frame();
        self.window.swap_buffers();
        let end = time::precise_time_s();
        println!("{0:4.3}ms", (end - start) * 1000.);
    }
}

impl<RD: RenderData+Send> snowmew::Render<RD> for RenderManager {
    fn update(&mut self, db: RD, scene: ObjectKey, camera: ObjectKey) {
        self.load_meshes(&db);
        self.load_textures(&db);
        self.draw(&db, scene, camera);
    }
}

impl<RD: RenderData+Send> snowmew::RenderFactory<RD, RenderManager> for RenderFactory {
    fn init(self: Box<RenderFactory>,
            io: &snowmew::IOManager,
            window: Window,
            size: (i32, i32),
            cl: Option<Arc<hl::Device>>) -> RenderManager {

        window.make_context_current();

        let mut device = gfx::GlDevice::new(|s| io.get_proc_address(s));
        RenderManager::_new(device, window, size, cl)
    }
}

pub struct RenderFactory;

impl RenderFactory {
    pub fn new() -> RenderFactory { RenderFactory }
}<commit_msg>Fix for latest gfx<commit_after>    //   Copyright 2014 Colin Sherratt
//
//   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.

#![crate_name = "snowmew-render-gfx"]
#![crate_type = "lib"]

#![feature(phase)]
#![allow(dead_code)]

//extern crate debug;

extern crate sync;
extern crate time;
extern crate libc;

extern crate opencl;
extern crate cow;
extern crate glfw;

#[phase(plugin)]
extern crate gfx_macros;
extern crate gfx;
extern crate device;
extern crate render;

extern crate snowmew  = "snowmew-core";
extern crate position = "snowmew-position";
extern crate graphics = "snowmew-graphics";
extern crate render_data = "snowmew-render-data";

use std::collections::hashmap::HashMap;

use opencl::hl;
use sync::Arc;

use position::Positions;
use graphics::Graphics;
use snowmew::common::ObjectKey;
use snowmew::io::Window;

use graphics::geometry::{Geo, GeoTex, GeoNorm, GeoTexNorm, GeoTexNormTan};

use cow::join::{join_set_to_map, join_maps};
use render_data::RenderData;

use gfx::{Device, DeviceHelper};

static VERTEX_SRC: gfx::ShaderSource = shaders! {
GLSL_150: b"
    #version 150 core
    uniform mat4 proj_mat;
    uniform mat4 view_mat;
    uniform mat4 model_mat;

    in vec3 position;
    in vec2 texture;

    out vec2 o_texture;

    void main() {
        gl_Position = proj_mat * view_mat * model_mat * vec4(position, 1.0);
        o_texture = texture;
    }
"
};

static FRAGMENT_SRC: gfx::ShaderSource = shaders! {
GLSL_150: b"
    #version 150 core
    uniform vec4 ka_color;
    uniform int ka_use_texture;
    uniform sampler2D ka_texture;

    in vec2 o_texture;

    out vec4 o_Color;

    void main() {
        if (1 == ka_use_texture) {
            o_Color = texture(ka_texture, o_texture);
        } else {
            o_Color = ka_color;
        }
    }
"
};

#[shader_param(MyProgram)]
struct Params {
    proj_mat: [[f32, ..4], ..4],
    view_mat: [[f32, ..4], ..4],
    model_mat: [[f32, ..4], ..4],
    ka_color: [f32, ..4],
    ka_use_texture: i32,
    ka_texture: gfx::shade::TextureParam,
}

struct Mesh {
    mesh: render::mesh::Mesh,
    index: device::BufferHandle<u32>
}

pub struct RenderManager {
    data: Params,
    graphics: render::Graphics<device::gl_device::GlDevice,
                               device::gl_device::GlCommandBuffer>,
    frame: render::target::Frame,
    state: render::state::DrawState,
    prog: device::Handle<u32,device::shade::ProgramInfo>,
    meshes: HashMap<ObjectKey, Mesh>,
    textures: HashMap<ObjectKey, device::TextureHandle>,
    sampler: device::SamplerHandle,
    window: Window
}

impl RenderManager {

    fn _new(mut device: gfx::GlDevice,
            window: Window,
            size: (i32, i32),
            _: Option<Arc<hl::Device>>) -> RenderManager {

        let (width, height) = size;
        let frame = gfx::Frame::new(width as u16, height as u16);
        let state = gfx::DrawState::new().depth(gfx::state::LessEqual, true);

        let sampler = device.create_sampler(
            gfx::tex::SamplerInfo::new(
                    gfx::tex::Bilinear, gfx::tex::Tile
            )
        );

        let (prog, data) = {
            let tinfo = gfx::tex::TextureInfo {
                width: 1,
                height: 1,
                depth: 1,
                levels: 1,
                kind: gfx::tex::Texture2D,
                format: gfx::tex::RGBA8,
            };

            let img_info = tinfo.to_image_info();
            let dummy_texture = device.create_texture(tinfo)
                                      .ok().expect("Failed to create texture");
            device.update_texture(&dummy_texture,
                                  &img_info,
                                  &vec![0u8, 0, 0, 0].as_slice());

            let data = Params {
                proj_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                view_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                model_mat: [
                    [1.0, 0.0, 0.0, 0.0],
                    [0.0, 1.0, 0.0, 0.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0],
                ],
                ka_use_texture: 0,
                ka_color: [1., 1., 1., 1.],
                ka_texture: (dummy_texture, Some(sampler))
            };
            (device.link_program(VERTEX_SRC.clone(), FRAGMENT_SRC.clone())
                  .ok().expect("Failed to link program"),
             data)
        };

        RenderManager {
            data: data,
            graphics: gfx::Graphics::new(device),
            frame: frame,
            state: state,
            prog: prog,
            meshes: HashMap::new(),
            textures: HashMap::new(),
            sampler: sampler,
            window: window
        }
    }

    fn load_meshes<RD: RenderData>(&mut self, db: &RD) {
        for (oid, vb) in db.vertex_buffer_iter() {
            if self.meshes.find(oid).is_none() {
                let mesh = match vb.vertex {
                    Geo(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoTex(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoNorm(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoTexNorm(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    },
                    GeoTexNormTan(ref d) => {
                        self.graphics.device.create_mesh(d.clone())
                    }
                };

                let vb: Vec<u32> = vb.index.iter().map(|&x| x as u32).collect();

                let index = self.graphics.device.create_buffer_static(&vb);

                self.meshes.insert(*oid, Mesh {
                    index: index,
                    mesh: mesh
                });
            }
        }
    }

    fn load_textures<RD: RenderData>(&mut self, db: &RD) {
        for (oid, text) in db.texture_iter() {
            if self.textures.find(oid).is_none() {
                let tinfo = gfx::tex::TextureInfo {
                    width: text.width() as u16,
                    height: text.height() as u16,
                    depth: 1 as u16,
                    levels: 1,
                    kind: gfx::tex::Texture2D,
                    format: match text.depth() {
                        4 => gfx::tex::Unsigned(gfx::tex::RGBA, 8, gfx::attrib::IntNormalized),
                        3 => gfx::tex::Unsigned(gfx::tex::RGB, 8, gfx::attrib::IntNormalized),
                        _ => fail!("Unsupported color depth")
                    }
                };

                let img_info = tinfo.to_image_info();
                let texture = self.graphics.device.create_texture(tinfo)
                                         .ok().expect("Failed to create texture");
                self.graphics.device.update_texture(&texture, &img_info, &text.data().to_vec());
                self.textures.insert(*oid, texture);
            }
        }
    }

    fn draw<RD: RenderData>(&mut self, db: &RD, scene: ObjectKey, camera: ObjectKey) {
        let cdata = gfx::ClearData {
            color: Some([0.3, 0.3, 0.3, 1.0]),
            depth: Some(1.0),
            stencil: None,
        };
        let start = time::precise_time_s();
        self.graphics.clear(cdata, &self.frame);

        let camera_trans = db.position(camera);
        let camera = snowmew::camera::Camera::new(camera_trans);

        let proj = camera.projection_matrix(16. / 9.);
        self.data.proj_mat =
            [[proj.x.x, proj.x.y, proj.x.z, proj.x.w],
             [proj.y.x, proj.y.y, proj.y.z, proj.y.w],
             [proj.z.x, proj.z.y, proj.z.z, proj.z.w],
             [proj.w.x, proj.w.y, proj.w.z, proj.w.w]];

        let view = camera.view_matrix();
        self.data.view_mat =
            [[view.x.x, view.x.y, view.x.z, view.x.w],
             [view.y.x, view.y.y, view.y.z, view.y.w],
             [view.z.x, view.z.y, view.z.z, view.z.w],
             [view.w.x, view.w.y, view.w.z, view.w.w]];

        for (id, (draw, _)) in join_set_to_map(db.scene_iter(scene),
                                               join_maps(db.drawable_iter(),
                                                         db.location_iter())) {

            let geo = db.geometry(draw.geometry).expect("failed to find geometry");
            let mat = db.material(draw.material).expect("Could not find material");
            let vb = self.meshes.find(&geo.vb).expect("Could not get vertex buffer");

            let model = db.position(*id);

            self.data.model_mat =
                [[model.x.x, model.x.y, model.x.z, model.x.w],
                 [model.y.x, model.y.y, model.y.z, model.y.w],
                 [model.z.x, model.z.y, model.z.z, model.z.w],
                 [model.w.x, model.w.y, model.w.z, model.w.w]];

            self.data.ka_use_texture = match mat.map_ka() {
                Some(tid) => {
                    let &texture = self.textures.find(&tid).expect("Texture not loaded");
                    self.data.ka_texture = (texture, Some(self.sampler));
                    1
                }
                None => {
                    let [r, g, b] = mat.ka();
                    self.data.ka_color = [r, g, b, 1.];
                    0
                }
            };

            let batch: MyProgram = self.graphics.make_batch(
                &self.prog,
                &vb.mesh,
                gfx::IndexSlice32(gfx::TriangleList,
                                  vb.index,
                                  geo.offset as u32,
                                  geo.count as u32),
                &self.state
            ).unwrap();

            self.graphics.draw(&batch, &self.data, &self.frame);
        }

        self.graphics.end_frame();
        self.window.swap_buffers();
        let end = time::precise_time_s();
        println!("{0:4.3}ms", (end - start) * 1000.);
    }
}

impl<RD: RenderData+Send> snowmew::Render<RD> for RenderManager {
    fn update(&mut self, db: RD, scene: ObjectKey, camera: ObjectKey) {
        self.load_meshes(&db);
        self.load_textures(&db);
        self.draw(&db, scene, camera);
    }
}

impl<RD: RenderData+Send> snowmew::RenderFactory<RD, RenderManager> for RenderFactory {
    fn init(self: Box<RenderFactory>,
            io: &snowmew::IOManager,
            window: Window,
            size: (i32, i32),
            cl: Option<Arc<hl::Device>>) -> RenderManager {

        window.make_context_current();

        let mut device = gfx::GlDevice::new(|s| io.get_proc_address(s));
        RenderManager::_new(device, window, size, cl)
    }
}

pub struct RenderFactory;

impl RenderFactory {
    pub fn new() -> RenderFactory { RenderFactory }
}<|endoftext|>


<commit_before>use mio::net::UdpSocket;
use mio::{Events, Interests, Poll, Token};
use std::io;

const IN: Token = Token(0);

fn main() {
    // Set up a new socket on port 9000 to listen on.
    let socket = UdpSocket::bind("0.0.0.0:9000".parse().unwrap()).unwrap();
    // Initialize poller.
    let mut poll = Poll::new().unwrap();
    // Register our socket with the token IN (defined above) and an interest
    // in being `READABLE`.
    poll.registry()
        .register(&socket, IN, Interests::READABLE)
        .unwrap();

    // Prepare a buffer for the number of events we can handle at a time.
    // Someone might wat to echo really fast so lets give it some size.
    let mut events = Events::with_capacity(1024);
    // Initialize a buffer for the UDP datagram
    let mut buf = [0; 65535];
    // Main loop
    loop {
        // Poll if we have events waiting for us on the socket.
        poll.poll(&mut events, None).unwrap();
        // If we do iterate throuigh them
        for event in events.iter() {
            // Validate the token we registered our socket with,
            // in this example it will only ever be one but we
            // make sure it's valid non the less.
            match event.token() {
                IN => loop {
                    // In this loop we receive from the socket as long as we
                    // can read data
                    match socket.recv_from(&mut buf) {
                        Ok((n, from_addr)) => {
                            // Send the data right back from where it came from.
                            let _r = socket.send_to(&buf[..n], from_addr);
                        }
                        Err(e) => {
                            // If we failed to receive data we have two cases
                            if e.kind() == io::ErrorKind::WouldBlock {
                                // If the reason was `WouldBlock` we know
                                // our socket has no more data to give so
                                // we can return to the poll to wait politely.
                                break;
                            } else {
                                // If it was any other kind of error, something
                                // went wrong and we panic.
                                panic!("error: {:?}", e)
                            }
                        }
                    }
                },
                // We only have IN as a token, so this should never ever be hit
                _ => unreachable!(),
            }
        }
    }
}
<commit_msg>Replace unwrap with io::Result<commit_after>use mio::net::UdpSocket;
use mio::{Events, Interests, Poll, Token};
use std::io;

const IN: Token = Token(0);

fn main() -> io::Result<()> {
    // Set up a new socket on port 9000 to listen on.
    let socket = UdpSocket::bind("0.0.0.0:9000".parse().unwrap())?;
    // Initialize poller.
    let mut poll = Poll::new()?;
    // Register our socket with the token IN (defined above) and an interest
    // in being `READABLE`.
    poll.registry()
        .register(&socket, IN, Interests::READABLE)?;

    // Prepare a buffer for the number of events we can handle at a time.
    // Someone might wat to echo really fast so lets give it some size.
    let mut events = Events::with_capacity(1024);
    // Initialize a buffer for the UDP datagram
    let mut buf = [0; 65535];
    // Main loop
    loop {
        // Poll if we have events waiting for us on the socket.
        poll.poll(&mut events, None)?;
        // If we do iterate throuigh them
        for event in events.iter() {
            // Validate the token we registered our socket with,
            // in this example it will only ever be one but we
            // make sure it's valid non the less.
            match event.token() {
                IN => loop {
                    // In this loop we receive from the socket as long as we
                    // can read data
                    match socket.recv_from(&mut buf) {
                        Ok((n, from_addr)) => {
                            // Send the data right back from where it came from.
                            socket.send_to(&buf[..n], from_addr)?;
                        }
                        Err(e) => {
                            // If we failed to receive data we have two cases
                            if e.kind() == io::ErrorKind::WouldBlock {
                                // If the reason was `WouldBlock` we know
                                // our socket has no more data to give so
                                // we can return to the poll to wait politely.
                                break;
                            } else {
                                // If it was any other kind of error, something
                                // went wrong and we panic.
                                panic!("error: {:?}", e)
                            }
                        }
                    }
                },
                // We only have IN as a token, so this should never ever be hit
                _ => unreachable!(),
            }
        }
    }
}
<|endoftext|>


<commit_before>// compile-flags: -Zmiri-disable-isolation

use std::time::{SystemTime, Instant};

fn main() {
    // Check `SystemTime`.
    let now1 = SystemTime::now();
    // Do some work to make time pass.
    for _ in 0..10 { drop(vec![42]); }
    let now2 = SystemTime::now();
    assert!(now2 > now1);
    let diff = now2.duration_since(now1).unwrap();
    assert_eq!(now1 + diff, now2);
    assert_eq!(now2 - diff, now1);
    // Sanity-check the time we got.
    let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
    let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365;
    let year = 1970 + years_since_epoch;
    assert!(2020 <= year && year < 2100);

    // Check `Instant`.
    let now1 = Instant::now();
    // Do some work to make time pass.
    for _ in 0..10 { drop(vec![42]); }
    let now2 = Instant::now();
    assert!(now2 > now1);
    let diff = now2.duration_since(now1);
    assert_eq!(now1 + diff, now2);
    assert_eq!(now2 - diff, now1);
    // Sanity-check the difference we got.
    assert!(diff.as_micros() > 1);
    assert!(diff.as_micros() < 1_000_000);
}
<commit_msg>Auto merge of #1336 - RalfJung:instance-sanity, r=RalfJung<commit_after>// compile-flags: -Zmiri-disable-isolation

use std::time::{SystemTime, Instant, Duration};

fn duration_sanity(diff: Duration) {
    // On my laptop, I observed times around 15-40ms. Add 10x lee-way both ways.
    assert!(diff.as_millis() > 1);
    assert!(diff.as_millis() < 500);
}

fn main() {
    // Check `SystemTime`.
    let now1 = SystemTime::now();
    let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs();
    let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365;
    let year = 1970 + years_since_epoch;
    assert!(2020 <= year && year < 2100);
    // Do some work to make time pass.
    for _ in 0..10 { drop(vec![42]); }
    let now2 = SystemTime::now();
    assert!(now2 > now1);
    // Sanity-check the difference we got.
    let diff = now2.duration_since(now1).unwrap();
    assert_eq!(now1 + diff, now2);
    assert_eq!(now2 - diff, now1);
    duration_sanity(diff);

    // Check `Instant`.
    let now1 = Instant::now();
    // Do some work to make time pass.
    for _ in 0..10 { drop(vec![42]); }
    let now2 = Instant::now();
    assert!(now2 > now1);
    // Sanity-check the difference we got.
    let diff = now2.duration_since(now1);
    assert_eq!(now1 + diff, now2);
    assert_eq!(now2 - diff, now1);
    duration_sanity(diff);
}
<|endoftext|>


<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Benoit Benedetti <benoit.benedetti@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

/* last synced with: logname (GNU coreutils) 8.22 */

// spell-checker:ignore (ToDO) getlogin userlogin

#[macro_use]
extern crate uucore;

use std::ffi::CStr;

use clap::App;

extern "C" {
    // POSIX requires using getlogin (or equivalent code)
    pub fn getlogin() -> *const libc::c_char;
}

fn get_userlogin() -> Option<String> {
    unsafe {
        let login: *const libc::c_char = getlogin();
        if login.is_null() {
            None
        } else {
            Some(String::from_utf8_lossy(CStr::from_ptr(login).to_bytes()).to_string())
        }
    }
}

static SUMMARY: &str = "Print user's login name";
static VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn uumain(_: impl uucore::Args) -> i32 {
    let _ = App::new(executable!())
        .version(VERSION)
        .about(SUMMARY)
        .get_matches();

    match get_userlogin() {
        Some(userlogin) => println!("{}", userlogin),
        None => show_error!("no login name"),
    }

    0
}
<commit_msg>logname: align profile<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Benoit Benedetti <benoit.benedetti@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

/* last synced with: logname (GNU coreutils) 8.22 */

// spell-checker:ignore (ToDO) getlogin userlogin

#[macro_use]
extern crate uucore;

use std::ffi::CStr;
use uucore::InvalidEncodingHandling;

use clap::App;

extern "C" {
    // POSIX requires using getlogin (or equivalent code)
    pub fn getlogin() -> *const libc::c_char;
}

fn get_userlogin() -> Option<String> {
    unsafe {
        let login: *const libc::c_char = getlogin();
        if login.is_null() {
            None
        } else {
            Some(String::from_utf8_lossy(CStr::from_ptr(login).to_bytes()).to_string())
        }
    }
}

static SUMMARY: &str = "Print user's login name";
static VERSION: &str = env!("CARGO_PKG_VERSION");

fn get_usage() -> String {
    format!("{0}", executable!())
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let _ = args
        .collect_str(InvalidEncodingHandling::Ignore)
        .accept_any();

    let usage = get_usage();

    let _ = App::new(executable!())
        .version(VERSION)
        .about(SUMMARY)
        .usage(&usage[..])
        .get_matches();

    match get_userlogin() {
        Some(userlogin) => println!("{}", userlogin),
        None => show_error!("no login name"),
    }

    0
}
<|endoftext|>


<commit_before>// Copyright 2015 Nicholas Bishop
//
// Intersection code adapted from "Real-Time Collision Detection" by
// Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// 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.

use sphere::Sphere3f;
use vector::{dot3, Vec3f};

/// Calculate closest point on triangle to an input point
fn triangle_closest_point_to_point(triangle: [Vec3f; 3], p: Vec3f) -> Vec3f {
    let a = triangle[0];
    let b = triangle[1];
    let c = triangle[2];

    // Check if P in vertex region outside A
    let ab = b - a;
    let ac = c - a;
    let ap = p - a;
    let d1 = dot3(ab, ap);
    let d2 = dot3(ac, ap);
    if d1 <= 0.0f32 && d2 <= 0.0f32 {
        return a; // barycentric coordinates (1,0,0)
    }
    // Check if P in vertex region outside B
    let bp = p - b;
    let d3 = dot3(ab, bp);
    let d4 = dot3(ac, bp);
    if d3 >= 0.0f32 && d4 <= d3 {
        return b; // barycentric coordinates (0,1,0)
    }

    // Check if P in edge region of AB, if so return projection of P onto AB
    let vc = d1*d4 - d3*d2;
    if vc <= 0.0f32 && d1 >= 0.0f32 && d3 <= 0.0f32 {
        let v = d1 / (d1 - d3);
        return a + ab * v; // barycentric coordinates (1-v,v,0)
    }
    // Check if P in vertex region outside C
    let cp = p - c;
    let d5 = dot3(ab, cp);
    let d6 = dot3(ac, cp);
    if d6 >= 0.0f32 && d5 <= d6 {
        return c; // barycentric coordinates (0,0,1)
    }

    // Check if P in edge region of AC, if so return projection of P onto AC
    let vb = d5*d2 - d1*d6;
    if vb <= 0.0f32 && d2 >= 0.0f32 && d6 <= 0.0f32 {
        let w = d2 / (d2 - d6);
        return a + ac * w; // barycentric coordinates (1-w,0,w)
    }
    // Check if P in edge region of BC, if so return projection of P onto BC
    let va = d3*d6 - d5*d4;
    if va <= 0.0f32 && (d4 - d3) >= 0.0f32 && (d5 - d6) >= 0.0f32 {
        let w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
        return b + (c - b) * w; // barycentric coordinates (0,1-w,w)
    }
    // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
    let denom = 1.0f32 / (va + vb + vc);
    let v = vb * denom;
    let w = vc * denom;
    return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = 1.0f - v - w
}

// Test for intersection between sphere and triangle
//
// Returns None if the inputs do not intersect, otherwise returns the
// point on the triangle closest to the sphere center.
pub fn intersect_sphere_triangle(sphere: &Sphere3f,
                                 triangle: [Vec3f; 3]) -> Option<Vec3f> {
    // Find point P on triangle ABC closest to sphere center
    let p = triangle_closest_point_to_point(triangle, sphere.center);

    // Sphere and triangle intersect if the (squared) distance from
    // sphere center to point p is less than the (squared) sphere
    // radius
    let v = p - sphere.center;
    if dot3(v, v) <= sphere.radius_squared() {
        Some(p)
    }
    else {
        None
    }
}

#[test]
fn test_intersect_sphere_triangle() {
    use sphere;
    use vector::{vec3f, ZERO_3F};

    let triangle = [
        vec3f(0, 0, 0),
        vec3f(1, 0, 0),
        vec3f(0, 1, 0)];
    assert!(intersect_sphere_triangle(&sphere::UNIT, triangle) ==
            Some(ZERO_3F));
}
<commit_msg>Update unit test<commit_after>// Copyright 2015 Nicholas Bishop
//
// Intersection code adapted from "Real-Time Collision Detection" by
// Christer Ericson, published by Morgan Kaufmann Publishers,
// Copyright 2005 Elsevier Inc
//
// 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.

use sphere::Sphere3f;
use vector::{dot3, Vec3f};

/// Calculate closest point on triangle to an input point
fn triangle_closest_point_to_point(triangle: [Vec3f; 3], p: Vec3f) -> Vec3f {
    let a = triangle[0];
    let b = triangle[1];
    let c = triangle[2];

    // Check if P in vertex region outside A
    let ab = b - a;
    let ac = c - a;
    let ap = p - a;
    let d1 = dot3(ab, ap);
    let d2 = dot3(ac, ap);
    if d1 <= 0.0f32 && d2 <= 0.0f32 {
        return a; // barycentric coordinates (1,0,0)
    }
    // Check if P in vertex region outside B
    let bp = p - b;
    let d3 = dot3(ab, bp);
    let d4 = dot3(ac, bp);
    if d3 >= 0.0f32 && d4 <= d3 {
        return b; // barycentric coordinates (0,1,0)
    }

    // Check if P in edge region of AB, if so return projection of P onto AB
    let vc = d1*d4 - d3*d2;
    if vc <= 0.0f32 && d1 >= 0.0f32 && d3 <= 0.0f32 {
        let v = d1 / (d1 - d3);
        return a + ab * v; // barycentric coordinates (1-v,v,0)
    }
    // Check if P in vertex region outside C
    let cp = p - c;
    let d5 = dot3(ab, cp);
    let d6 = dot3(ac, cp);
    if d6 >= 0.0f32 && d5 <= d6 {
        return c; // barycentric coordinates (0,0,1)
    }

    // Check if P in edge region of AC, if so return projection of P onto AC
    let vb = d5*d2 - d1*d6;
    if vb <= 0.0f32 && d2 >= 0.0f32 && d6 <= 0.0f32 {
        let w = d2 / (d2 - d6);
        return a + ac * w; // barycentric coordinates (1-w,0,w)
    }
    // Check if P in edge region of BC, if so return projection of P onto BC
    let va = d3*d6 - d5*d4;
    if va <= 0.0f32 && (d4 - d3) >= 0.0f32 && (d5 - d6) >= 0.0f32 {
        let w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
        return b + (c - b) * w; // barycentric coordinates (0,1-w,w)
    }
    // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
    let denom = 1.0f32 / (va + vb + vc);
    let v = vb * denom;
    let w = vc * denom;
    return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = 1.0f - v - w
}

// Test for intersection between sphere and triangle
//
// Returns None if the inputs do not intersect, otherwise returns the
// point on the triangle closest to the sphere center.
pub fn intersect_sphere_triangle(sphere: &Sphere3f,
                                 triangle: [Vec3f; 3]) -> Option<Vec3f> {
    // Find point P on triangle ABC closest to sphere center
    let p = triangle_closest_point_to_point(triangle, sphere.center);

    // Sphere and triangle intersect if the (squared) distance from
    // sphere center to point p is less than the (squared) sphere
    // radius
    let v = p - sphere.center;
    if dot3(v, v) <= sphere.radius_squared() {
        Some(p)
    }
    else {
        None
    }
}

#[test]
fn test_intersect_sphere_triangle() {
    use sphere;
    use vector::{vec3f, ZERO_3F};

    let triangle = [
        vec3f(0, 0, 0),
        vec3f(1, 0, 0),
        vec3f(0, 1, 0)];

    assert!(intersect_sphere_triangle(&sphere::UNIT,
                                      triangle) == Some(ZERO_3F));

    assert!(intersect_sphere_triangle(&Sphere3f::new(vec3f(10, 10, 10), 1.0),
                                      triangle) == None);
}
<|endoftext|>


<commit_before>use item_state::ItemState;
use bar_builder::UpdateStream;
use std::rc::Rc;
use xcb::{Connection, Rectangle, Window};
use futures::stream::{Merge, MergedItem};
use futures::{Future, Stream};
use xcb_event_stream::XcbEventStream;
use error::*;
use std::error::Error;
use xcb;
use component::Slot;

type UpdateAndEventStream = Merge<UpdateStream, XcbEventStream>;

/// Struct that contains everything needed to run the bar.
pub struct Bar {
    pub center_items: Vec<ItemState>,
    pub conn: Rc<Connection>,
    pub foreground: u32,
    pub geometry: Rectangle,
    pub item_positions: Vec<(u16, u16)>,
    pub left_items: Vec<ItemState>,
    pub right_items: Vec<ItemState>,
    pub stream: Option<UpdateAndEventStream>,
    pub window: Window,
    pub inner_padding: u16,
}

impl Bar {
    /// Returns `self.stream` without borrowing or consuming `self`.
    /// Panics if called twice.
    fn get_stream(&mut self) -> UpdateAndEventStream {
        ::std::mem::replace(&mut self.stream, None).unwrap()
    }

    /// Launch and run the bar.
    pub fn run(mut self) -> Box<Future<Item = (), Error = ()>> {
        let future = self.get_stream()
            .map_err(|e| ::error::Error::with_chain(e, ErrorKind::ItemError))
            .for_each(move |item| -> Result<()> {
                let (_, update) = match item {
                    MergedItem::First(update) => (None, Some(update)),
                    MergedItem::Second(event) => (Some(event), None),
                    MergedItem::Both(update, event) => (Some(event), Some(update)),
                };

                if let Some(update) = update {
                    let size_changed;

                    // Figure out if the component has chanaged
                    // it's size since the last update.
                    // TODO: Move to a function
                    {
                        let slot_items = match update.slot {
                            Slot::Left => &mut self.left_items,
                            Slot::Center => &mut self.center_items,
                            Slot::Right => &mut self.right_items,
                        };
                        slot_items[update.index].update(update.value)?;

                        let width = slot_items[update.index].get_content_width();
                        size_changed = self.item_positions[update.id].1 != width;
                    }

                    // Redraw only neccessary stuff
                    match update.slot {
                        Slot::Center => self.redraw_center()?,
                        Slot::Left => self.redraw_left(size_changed, update.index)?,
                        Slot::Right => self.redraw_right(size_changed, update.index)?,
                    }
                }
                Ok(())
            })
            .map_err(|err| {
                println!("Error occurred: {}", err);
                let mut cause = err.cause();
                while let Some(err) = cause {
                    println!("  Caused by: {}", err);
                    cause = err.cause();
                }
            });

        Box::new(future)
    }

    /// Redraws components in the center slot.
    /// Unforunately centering means that all components
    /// must be redrawn if even one of them changes size.
    fn redraw_center(&mut self) -> Result<()> {
        let width_all: u16 = self.center_items
            .iter()
            .map(|item| item.get_content_width())
            .sum();

        let mut pos = (self.geometry.width()) / 2 - width_all / 2;

        for item in self.center_items.iter() {
            self.item_positions[item.get_id()].0 = pos;
            self.draw_item(item, pos)?;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            pos += item.get_content_width();
        }

        Ok(())
    }

    /// Pretty much the same as `self.redraw_left` but with `left` replaced with `right`.
    /// The order in which the items are gone through is reversed.
    fn redraw_right(&mut self, size_changed: bool, index: usize) -> Result<()> {
        let mut pos = self.geometry.width() - self.inner_padding;

        for n in 0..self.right_items.len() {
            let item = &self.right_items[self.right_items.len() - n - 1];

            pos -= item.get_content_width();

            if n < self.right_items.len() - index - 1 {
                continue;
            }

            if size_changed {
                let mut bg_start = pos;
                let bg_end = pos + item.get_content_width();

                if n == self.right_items.len() - 1 {
                    let old_start = self.item_positions[item.get_id()].0 as u16;
                    if old_start < bg_start && old_start > 0 {
                        bg_start = old_start;
                    }
                }

                self.paint_bg(bg_start, bg_end)?;
            }

            self.item_positions[item.get_id()].0 = pos;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            self.draw_item(item, pos)?;

            if !size_changed {
                break;
            }
        }

        Ok(())
    }

    /// Redraw only needed items in the right slot.
    /// Symmetric to `self.redraw_left`.
    ///
    /// If the component hasn't changed it's size, it doesn't affect
    /// any other components and we can get away with just painting
    /// the one component.
    ///
    /// However if the component has changed it's size, we must also
    /// redraw every component on the right of it. If the item has shrunk
    /// we must also repaint the exposed background.
    fn redraw_left(&mut self, size_changed: bool, index: usize) -> Result<()> {
        let mut pos = self.inner_padding;

        for n in 0..self.left_items.len() {
            let item = &self.left_items[n];

            if n < index {
                pos += item.get_content_width();
                continue;
            }

            if size_changed {
                let bg_start = pos;
                let mut bg_end = pos + item.get_content_width();

                if n == self.left_items.len() - 1 {
                    let old_end = self.item_positions[item.get_id()].0 +
                        self.item_positions[item.get_id()].1;
                    if bg_end < old_end {
                        bg_end = old_end;
                    }
                }

                self.paint_bg(bg_start, bg_end)?;
            }

            self.item_positions[item.get_id()].0 = pos;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            self.draw_item(item, pos)?;

            if !size_changed {
                break;
            }

            pos += item.get_content_width();
        }

        Ok(())
    }

    /// Copies the item's pixmap to the window.
    fn draw_item(&self, item: &ItemState, pos: u16) -> Result<()> {
        if !item.is_ready() {
            return Ok(());
        }

        try_xcb!(
            xcb::copy_area_checked,
            "failed to copy pixmap",
            &self.conn,
            item.get_pixmap(),
            self.window,
            self.foreground,
            0,
            0,
            pos as i16,
            0,
            item.get_content_width() as u16,
            self.geometry.height()
        );

        Ok(())
    }

    /// Draws the background starting at point a on the x-axis until point b.
    fn paint_bg(&self, a: u16, b: u16) -> Result<()> {
        try_xcb!(
            xcb::poly_fill_rectangle,
            "failed to draw background",
            &self.conn,
            self.window,
            self.foreground,
            &[Rectangle::new(a as i16, 0, b - a, self.geometry.height())]
        );

        Ok(())
    }
}
<commit_msg>Fix center element redraw<commit_after>use item_state::ItemState;
use bar_builder::UpdateStream;
use std::rc::Rc;
use xcb::{Connection, Rectangle, Window};
use futures::stream::{Merge, MergedItem};
use futures::{Future, Stream};
use xcb_event_stream::XcbEventStream;
use error::*;
use std::error::Error;
use xcb;
use component::Slot;

type UpdateAndEventStream = Merge<UpdateStream, XcbEventStream>;

/// Struct that contains everything needed to run the bar.
pub struct Bar {
    pub center_items: Vec<ItemState>,
    pub conn: Rc<Connection>,
    pub foreground: u32,
    pub geometry: Rectangle,
    pub item_positions: Vec<(u16, u16)>,
    pub left_items: Vec<ItemState>,
    pub right_items: Vec<ItemState>,
    pub stream: Option<UpdateAndEventStream>,
    pub window: Window,
    pub inner_padding: u16,
}

impl Bar {
    /// Returns `self.stream` without borrowing or consuming `self`.
    /// Panics if called twice.
    fn get_stream(&mut self) -> UpdateAndEventStream {
        ::std::mem::replace(&mut self.stream, None).unwrap()
    }

    /// Launch and run the bar.
    pub fn run(mut self) -> Box<Future<Item = (), Error = ()>> {
        let future = self.get_stream()
            .map_err(|e| ::error::Error::with_chain(e, ErrorKind::ItemError))
            .for_each(move |item| -> Result<()> {
                let (_, update) = match item {
                    MergedItem::First(update) => (None, Some(update)),
                    MergedItem::Second(event) => (Some(event), None),
                    MergedItem::Both(update, event) => (Some(event), Some(update)),
                };

                if let Some(update) = update {
                    let size_changed;

                    // Figure out if the component has chanaged
                    // it's size since the last update.
                    // TODO: Move to a function
                    {
                        let slot_items = match update.slot {
                            Slot::Left => &mut self.left_items,
                            Slot::Center => &mut self.center_items,
                            Slot::Right => &mut self.right_items,
                        };
                        slot_items[update.index].update(update.value)?;

                        let width = slot_items[update.index].get_content_width();
                        size_changed = self.item_positions[update.id].1 != width;
                    }

                    // Redraw only neccessary stuff
                    match update.slot {
                        Slot::Center => self.redraw_center()?,
                        Slot::Left => self.redraw_left(size_changed, update.index)?,
                        Slot::Right => self.redraw_right(size_changed, update.index)?,
                    }
                }
                Ok(())
            })
            .map_err(|err| {
                println!("Error occurred: {}", err);
                let mut cause = err.cause();
                while let Some(err) = cause {
                    println!("  Caused by: {}", err);
                    cause = err.cause();
                }
            });

        Box::new(future)
    }

    /// Redraws components in the center slot.
    /// Unforunately centering means that all components
    /// must be redrawn if even one of them changes size.
    fn redraw_center(&mut self) -> Result<()> {
        // Draw blank background to prevent leftovers after shrinkage
        if let Some(first) = self.center_items.first() {
            let old_start = self.item_positions[first.get_id()].0;
            let old_width_all: u16 = self.center_items
                .iter()
                .map(|item| self.item_positions[item.get_id()].1)
                .sum();
            self.paint_bg(old_start, old_start + old_width_all)?;
        }

        let width_all: u16 = self.center_items
            .iter()
            .map(|item| item.get_content_width())
            .sum();

        let mut pos = (self.geometry.width()) / 2 - width_all / 2;

        for item in self.center_items.iter() {
            self.item_positions[item.get_id()].0 = pos;
            self.draw_item(item, pos)?;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            pos += item.get_content_width();
        }

        Ok(())
    }

    /// Pretty much the same as `self.redraw_left` but with `left` replaced with `right`.
    /// The order in which the items are gone through is reversed.
    fn redraw_right(&mut self, size_changed: bool, index: usize) -> Result<()> {
        let mut pos = self.geometry.width() - self.inner_padding;

        for n in 0..self.right_items.len() {
            let item = &self.right_items[self.right_items.len() - n - 1];

            pos -= item.get_content_width();

            if n < self.right_items.len() - index - 1 {
                continue;
            }

            if size_changed {
                let mut bg_start = pos;
                let bg_end = pos + item.get_content_width();

                if n == self.right_items.len() - 1 {
                    let old_start = self.item_positions[item.get_id()].0 as u16;
                    if old_start < bg_start && old_start > 0 {
                        bg_start = old_start;
                    }
                }

                self.paint_bg(bg_start, bg_end)?;
            }

            self.item_positions[item.get_id()].0 = pos;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            self.draw_item(item, pos)?;

            if !size_changed {
                break;
            }
        }

        Ok(())
    }

    /// Redraw only needed items in the right slot.
    /// Symmetric to `self.redraw_left`.
    ///
    /// If the component hasn't changed it's size, it doesn't affect
    /// any other components and we can get away with just painting
    /// the one component.
    ///
    /// However if the component has changed it's size, we must also
    /// redraw every component on the right of it. If the item has shrunk
    /// we must also repaint the exposed background.
    fn redraw_left(&mut self, size_changed: bool, index: usize) -> Result<()> {
        let mut pos = self.inner_padding;

        for n in 0..self.left_items.len() {
            let item = &self.left_items[n];

            if n < index {
                pos += item.get_content_width();
                continue;
            }

            if size_changed {
                let bg_start = pos;
                let mut bg_end = pos + item.get_content_width();

                if n == self.left_items.len() - 1 {
                    let old_end = self.item_positions[item.get_id()].0 +
                        self.item_positions[item.get_id()].1;
                    if bg_end < old_end {
                        bg_end = old_end;
                    }
                }

                self.paint_bg(bg_start, bg_end)?;
            }

            self.item_positions[item.get_id()].0 = pos;
            self.item_positions[item.get_id()].1 = item.get_content_width();
            self.draw_item(item, pos)?;

            if !size_changed {
                break;
            }

            pos += item.get_content_width();
        }

        Ok(())
    }

    /// Copies the item's pixmap to the window.
    fn draw_item(&self, item: &ItemState, pos: u16) -> Result<()> {
        if !item.is_ready() {
            return Ok(());
        }

        try_xcb!(
            xcb::copy_area_checked,
            "failed to copy pixmap",
            &self.conn,
            item.get_pixmap(),
            self.window,
            self.foreground,
            0,
            0,
            pos as i16,
            0,
            item.get_content_width() as u16,
            self.geometry.height()
        );

        Ok(())
    }

    /// Draws the background starting at point a on the x-axis until point b.
    fn paint_bg(&self, a: u16, b: u16) -> Result<()> {
        try_xcb!(
            xcb::poly_fill_rectangle,
            "failed to draw background",
            &self.conn,
            self.window,
            self.foreground,
            &[Rectangle::new(a as i16, 0, b - a, self.geometry.height())]
        );

        Ok(())
    }
}
<|endoftext|>


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

//! A wrapper around another RNG that reseeds it after it
//! generates a certain number of random bytes.

use core::prelude::*;

use {Rng, SeedableRng};
use core::default::Default;

/// How many bytes of entropy the underling RNG is allowed to generate
/// before it is reseeded.
static DEFAULT_GENERATION_THRESHOLD: uint = 32 * 1024;

/// A wrapper around any RNG which reseeds the underlying RNG after it
/// has generated a certain number of random bytes.
pub struct ReseedingRng<R, Rsdr> {
    rng: R,
    generation_threshold: uint,
    bytes_generated: uint,
    /// Controls the behaviour when reseeding the RNG.
    pub reseeder: Rsdr,
}

impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
    /// Create a new `ReseedingRng` with the given parameters.
    ///
    /// # Arguments
    ///
    /// * `rng`: the random number generator to use.
    /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
    /// * `reseeder`: the reseeding object to use.
    pub fn new(rng: R, generation_threshold: uint, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
        ReseedingRng {
            rng: rng,
            generation_threshold: generation_threshold,
            bytes_generated: 0,
            reseeder: reseeder
        }
    }

    /// Reseed the internal RNG if the number of bytes that have been
    /// generated exceed the threshold.
    pub fn reseed_if_necessary(&mut self) {
        if self.bytes_generated >= self.generation_threshold {
            self.reseeder.reseed(&mut self.rng);
            self.bytes_generated = 0;
        }
    }
}

impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
    fn next_u32(&mut self) -> u32 {
        self.reseed_if_necessary();
        self.bytes_generated += 4;
        self.rng.next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        self.reseed_if_necessary();
        self.bytes_generated += 8;
        self.rng.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.reseed_if_necessary();
        self.bytes_generated += dest.len();
        self.rng.fill_bytes(dest)
    }
}

impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R> + Default>
     SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
    fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
        self.rng.reseed(seed);
        self.reseeder = rsdr;
        self.bytes_generated = 0;
    }

    /// Create a new `ReseedingRng` from the given reseeder and
    /// seed. This uses a default value for `generation_threshold`.
    fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
        ReseedingRng {
            rng: SeedableRng::from_seed(seed),
            generation_threshold: DEFAULT_GENERATION_THRESHOLD,
            bytes_generated: 0,
            reseeder: rsdr
        }
    }
}

/// Something that can be used to reseed an RNG via `ReseedingRng`.
///
/// # Example
///
/// ```rust
/// use std::rand::{Rng, SeedableRng, StdRng};
/// use std::rand::reseeding::{Reseeder, ReseedingRng};
///
/// struct TickTockReseeder { tick: bool }
/// impl Reseeder<StdRng> for TickTockReseeder {
///     fn reseed(&mut self, rng: &mut StdRng) {
///         let val = if self.tick {0} else {1};
///         rng.reseed(&[val]);
///         self.tick = !self.tick;
///     }
/// }
/// fn main() {
///     let rsdr = TickTockReseeder { tick: true };
///
///     let inner = StdRng::new().unwrap();
///     let mut rng = ReseedingRng::new(inner, 10, rsdr);
///
///     // this will repeat, because it gets reseeded very regularly.
///     let s: String = rng.gen_ascii_chars().take(100).collect();
///     println!("{}", s);
/// }
///
/// ```
pub trait Reseeder<R> {
    /// Reseed the given RNG.
    fn reseed(&mut self, rng: &mut R);
}

/// Reseed an RNG using a `Default` instance. This reseeds by
/// replacing the RNG with the result of a `Default::default` call.
#[derive(Copy)]
pub struct ReseedWithDefault;

impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
    fn reseed(&mut self, rng: &mut R) {
        *rng = Default::default();
    }
}
#[stable(feature = "grandfathered", since = "1.0.0")]
impl Default for ReseedWithDefault {
    #[stable(feature = "grandfathered", since = "1.0.0")]
    fn default() -> ReseedWithDefault { ReseedWithDefault }
}

#[cfg(test)]
mod test {
    use std::prelude::v1::*;

    use core::iter::{order, repeat};
    use super::{ReseedingRng, ReseedWithDefault};
    use std::default::Default;
    use {SeedableRng, Rng};

    struct Counter {
        i: u32
    }

    impl Rng for Counter {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            // very random
            self.i - 1
        }
    }
    impl Default for Counter {
        fn default() -> Counter {
            Counter { i: 0 }
        }
    }
    impl SeedableRng<u32> for Counter {
        fn reseed(&mut self, seed: u32) {
            self.i = seed;
        }
        fn from_seed(seed: u32) -> Counter {
            Counter { i: seed }
        }
    }
    type MyRng = ReseedingRng<Counter, ReseedWithDefault>;

    #[test]
    fn test_reseeding() {
        let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);

        let mut i = 0;
        for _ in range(0u, 1000) {
            assert_eq!(rs.next_u32(), i % 100);
            i += 1;
        }
    }

    #[test]
    fn test_rng_seeded() {
        let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
        let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
        assert!(order::equals(ra.gen_ascii_chars().take(100),
                              rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_reseed() {
        let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
        let string1: String = r.gen_ascii_chars().take(100).collect();

        r.reseed((ReseedWithDefault, 3));

        let string2: String = r.gen_ascii_chars().take(100).collect();
        assert_eq!(string1, string2);
    }

    static FILL_BYTES_V_LEN: uint = 13579;
    #[test]
    fn test_rng_fill_bytes() {
        let mut v = repeat(0u8).take(FILL_BYTES_V_LEN).collect::<Vec<_>>();
        ::test::rng().fill_bytes(v.as_mut_slice());

        // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
        // recursed.
        assert_eq!(v.len(), FILL_BYTES_V_LEN);

        // To test that `fill_bytes` actually did something, check that the
        // average of `v` is not 0.
        let mut sum = 0.0;
        for &x in v.iter() {
            sum += x as f64;
        }
        assert!(sum / v.len() as f64 != 0.0);
    }
}
<commit_msg>grandfathered -> rust1<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A wrapper around another RNG that reseeds it after it
//! generates a certain number of random bytes.

use core::prelude::*;

use {Rng, SeedableRng};
use core::default::Default;

/// How many bytes of entropy the underling RNG is allowed to generate
/// before it is reseeded.
static DEFAULT_GENERATION_THRESHOLD: uint = 32 * 1024;

/// A wrapper around any RNG which reseeds the underlying RNG after it
/// has generated a certain number of random bytes.
pub struct ReseedingRng<R, Rsdr> {
    rng: R,
    generation_threshold: uint,
    bytes_generated: uint,
    /// Controls the behaviour when reseeding the RNG.
    pub reseeder: Rsdr,
}

impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
    /// Create a new `ReseedingRng` with the given parameters.
    ///
    /// # Arguments
    ///
    /// * `rng`: the random number generator to use.
    /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
    /// * `reseeder`: the reseeding object to use.
    pub fn new(rng: R, generation_threshold: uint, reseeder: Rsdr) -> ReseedingRng<R,Rsdr> {
        ReseedingRng {
            rng: rng,
            generation_threshold: generation_threshold,
            bytes_generated: 0,
            reseeder: reseeder
        }
    }

    /// Reseed the internal RNG if the number of bytes that have been
    /// generated exceed the threshold.
    pub fn reseed_if_necessary(&mut self) {
        if self.bytes_generated >= self.generation_threshold {
            self.reseeder.reseed(&mut self.rng);
            self.bytes_generated = 0;
        }
    }
}

impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
    fn next_u32(&mut self) -> u32 {
        self.reseed_if_necessary();
        self.bytes_generated += 4;
        self.rng.next_u32()
    }

    fn next_u64(&mut self) -> u64 {
        self.reseed_if_necessary();
        self.bytes_generated += 8;
        self.rng.next_u64()
    }

    fn fill_bytes(&mut self, dest: &mut [u8]) {
        self.reseed_if_necessary();
        self.bytes_generated += dest.len();
        self.rng.fill_bytes(dest)
    }
}

impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R> + Default>
     SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
    fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
        self.rng.reseed(seed);
        self.reseeder = rsdr;
        self.bytes_generated = 0;
    }

    /// Create a new `ReseedingRng` from the given reseeder and
    /// seed. This uses a default value for `generation_threshold`.
    fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
        ReseedingRng {
            rng: SeedableRng::from_seed(seed),
            generation_threshold: DEFAULT_GENERATION_THRESHOLD,
            bytes_generated: 0,
            reseeder: rsdr
        }
    }
}

/// Something that can be used to reseed an RNG via `ReseedingRng`.
///
/// # Example
///
/// ```rust
/// use std::rand::{Rng, SeedableRng, StdRng};
/// use std::rand::reseeding::{Reseeder, ReseedingRng};
///
/// struct TickTockReseeder { tick: bool }
/// impl Reseeder<StdRng> for TickTockReseeder {
///     fn reseed(&mut self, rng: &mut StdRng) {
///         let val = if self.tick {0} else {1};
///         rng.reseed(&[val]);
///         self.tick = !self.tick;
///     }
/// }
/// fn main() {
///     let rsdr = TickTockReseeder { tick: true };
///
///     let inner = StdRng::new().unwrap();
///     let mut rng = ReseedingRng::new(inner, 10, rsdr);
///
///     // this will repeat, because it gets reseeded very regularly.
///     let s: String = rng.gen_ascii_chars().take(100).collect();
///     println!("{}", s);
/// }
///
/// ```
pub trait Reseeder<R> {
    /// Reseed the given RNG.
    fn reseed(&mut self, rng: &mut R);
}

/// Reseed an RNG using a `Default` instance. This reseeds by
/// replacing the RNG with the result of a `Default::default` call.
#[derive(Copy)]
pub struct ReseedWithDefault;

impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
    fn reseed(&mut self, rng: &mut R) {
        *rng = Default::default();
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl Default for ReseedWithDefault {
    #[stable(feature = "rust1", since = "1.0.0")]
    fn default() -> ReseedWithDefault { ReseedWithDefault }
}

#[cfg(test)]
mod test {
    use std::prelude::v1::*;

    use core::iter::{order, repeat};
    use super::{ReseedingRng, ReseedWithDefault};
    use std::default::Default;
    use {SeedableRng, Rng};

    struct Counter {
        i: u32
    }

    impl Rng for Counter {
        fn next_u32(&mut self) -> u32 {
            self.i += 1;
            // very random
            self.i - 1
        }
    }
    impl Default for Counter {
        fn default() -> Counter {
            Counter { i: 0 }
        }
    }
    impl SeedableRng<u32> for Counter {
        fn reseed(&mut self, seed: u32) {
            self.i = seed;
        }
        fn from_seed(seed: u32) -> Counter {
            Counter { i: seed }
        }
    }
    type MyRng = ReseedingRng<Counter, ReseedWithDefault>;

    #[test]
    fn test_reseeding() {
        let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);

        let mut i = 0;
        for _ in range(0u, 1000) {
            assert_eq!(rs.next_u32(), i % 100);
            i += 1;
        }
    }

    #[test]
    fn test_rng_seeded() {
        let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
        let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
        assert!(order::equals(ra.gen_ascii_chars().take(100),
                              rb.gen_ascii_chars().take(100)));
    }

    #[test]
    fn test_rng_reseed() {
        let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
        let string1: String = r.gen_ascii_chars().take(100).collect();

        r.reseed((ReseedWithDefault, 3));

        let string2: String = r.gen_ascii_chars().take(100).collect();
        assert_eq!(string1, string2);
    }

    static FILL_BYTES_V_LEN: uint = 13579;
    #[test]
    fn test_rng_fill_bytes() {
        let mut v = repeat(0u8).take(FILL_BYTES_V_LEN).collect::<Vec<_>>();
        ::test::rng().fill_bytes(v.as_mut_slice());

        // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
        // recursed.
        assert_eq!(v.len(), FILL_BYTES_V_LEN);

        // To test that `fill_bytes` actually did something, check that the
        // average of `v` is not 0.
        let mut sum = 0.0;
        for &x in v.iter() {
            sum += x as f64;
        }
        assert!(sum / v.len() as f64 != 0.0);
    }
}
<|endoftext|>