<commit_before>// This whole file is inspired by: https://github.com/jeaye/q3/blob/master/src/client/ui/ttf/renderer.rs
// available under the BSD-3 licence.
// It has been modified to work with gl-rs, nalgebra, and rust-freetype

use na::{Point2, Point3, Vector2};
use rusttype;
use rusttype::gpu_cache::{Cache, CacheBuilder};
use std::mem;
use std::rc::Rc;

use context::{Context, Texture};
use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform};
use text::Font;

#[path = "../error.rs"]
mod error;

struct TextRenderContext {
    len: usize,
    scale: f32,
    color: Point3<f32>,
    pos: Point2<f32>,
    font: Rc<Font>,
}

/// A ttf text renderer.
pub struct TextRenderer {
    text: String,
    texture: Texture,
    shader: Effect,
    cache: Cache<'static>,
    invsz: ShaderUniform<Vector2<f32>>,
    tex: ShaderUniform<i32>,
    color: ShaderUniform<Point3<f32>>,
    pos: ShaderAttribute<Point2<f32>>,
    uvs: ShaderAttribute<Point2<f32>>,
    contexts: Vec<TextRenderContext>,
    coords: GPUVec<Point2<f32>>,
}

impl TextRenderer {
    /// Creates a new text renderer with `font` as the default font.
    pub fn new() -> TextRenderer {
        //
        // Create cache.
        //
        let atlas_width = 1024;
        let atlas_height = 1024;
        let cache = CacheBuilder {
            width: atlas_width,
            height: atlas_height,
            ..CacheBuilder::default()
        }.build();

        //
        // Create texture.
        //
        let ctxt = Context::get();

        /* We're using 1 byte alignment buffering. */
        verify!(ctxt.pixel_storei(Context::UNPACK_ALIGNMENT, 1));

        let texture = verify!(
            ctxt.create_texture()
                .expect("Font texture creation failed.")
        );
        verify!(ctxt.bind_texture(Context::TEXTURE_2D, Some(&texture)));
        verify!(ctxt.tex_image2d(
            Context::TEXTURE_2D,
            0,
            Context::RED as i32,
            atlas_width as i32,
            atlas_height as i32,
            0,
            Context::RED,
            None
        ));

        /* Clamp to the edge to avoid artifacts when scaling. */
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_S,
            Context::CLAMP_TO_EDGE as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_T,
            Context::CLAMP_TO_EDGE as i32
        ));

        /* Linear filtering usually looks best for text. */
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_MIN_FILTER,
            Context::LINEAR as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_MAG_FILTER,
            Context::LINEAR as i32
        ));

        //
        // Create shader.
        //
        let mut shader = Effect::new_from_str(TEXT_VERTEX_SRC, TEXT_FRAGMENT_SRC);
        shader.use_program();

        TextRenderer {
            text: String::new(),
            cache,
            texture,
            invsz: shader.get_uniform("invsz").expect("Could not find invsz"),
            tex: shader.get_uniform("tex0").expect("Could not find tex0"),
            color: shader.get_uniform("color").expect("Could not find color"),
            pos: shader.get_attrib("pos").expect("Could not find pos"),
            uvs: shader.get_attrib("uvs").expect("Could not find uvs"),
            shader: shader,
            contexts: Vec::new(),
            coords: GPUVec::new(Vec::new(), BufferType::Array, AllocationType::StreamDraw),
        }
    }

    /// Adds a piece of text to be drawn during the next frame. The text is not persistent between
    /// frames. This method must be called for each text to draw, and at each update loop
    /// iteration.
    pub fn draw_text(
        &mut self,
        text: &str,
        pos: &Point2<f32>,
        scale: f32,
        font: &Rc<Font>,
        color: &Point3<f32>,
    ) {
        self.text.push_str(text);
        self.contexts.push(TextRenderContext {
            len: text.len(),
            scale,
            color: *color,
            pos: *pos,
            font: font.clone(),
        })
    }

    /// Actually draws the text.
    pub fn render(&mut self, width: f32, height: f32) {
        if self.contexts.len() == 0 {
            return;
        }

        let ctxt = Context::get();
        self.shader.use_program();

        verify!(ctxt.polygon_mode(Context::FRONT_AND_BACK, Context::FILL));
        verify!(ctxt.enable(Context::BLEND));
        verify!(ctxt.blend_func(Context::SRC_ALPHA, Context::ONE_MINUS_SRC_ALPHA));
        verify!(ctxt.disable(Context::DEPTH_TEST));

        self.pos.enable();
        self.uvs.enable();
        self.tex.upload(&0);
        self.invsz.upload(&Vector2::new(1.0 / width, -1.0 / height));

        verify!(ctxt.bind_texture(Context::TEXTURE_2D, Some(&self.texture)));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_S,
            Context::CLAMP_TO_EDGE as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_T,
            Context::CLAMP_TO_EDGE as i32
        ));

        let mut pos = 0;

        for context in self.contexts.iter() {
            let text = &self.text[pos..pos + context.len];
            let font_uid = Font::uid(&context.font);

            for (line_count, line) in text.lines().enumerate() {
                let scale = rusttype::Scale::uniform(context.scale);
                let orig = rusttype::Point {
                    x: context.pos.x,
                    y: context.pos.y,
                };
                let layout = context.font.font().layout(line, scale, orig);

                for glyph in layout {
                    let gly: rusttype::PositionedGlyph<'static> = context
                        .font
                        .font()
                        .glyph(glyph.id())
                        .scaled(glyph.scale())
                        .positioned(glyph.position());
                    self.cache.queue_glyph(font_uid, gly); // FIXME: is the call to `.standalone()` costly?
                }

                self.cache.cache_queued(|rect, data| {
                    verify!(ctxt.tex_sub_image2d(
                        Context::TEXTURE_2D,
                        0,
                        rect.min.x as i32,
                        rect.min.y as i32,
                        rect.width() as i32,
                        rect.height() as i32,
                        Context::RED,
                        Some(&data)
                    ));
                });

                let layout = context.font.font().layout(line, scale, orig);

                {
                    let vmetrics = context.font.font().v_metrics(scale);
                    let coords = self.coords.data_mut().as_mut().unwrap();
                    for glyph in layout {
                        if let Some(Some((tex, rect))) = self.cache.rect_for(font_uid, &glyph).ok()
                        {
                            let min_px = rect.min.x as f32;
                            let min_py = rect.min.y as f32 + vmetrics.ascent;
                            let max_px = rect.max.x as f32;
                            let max_py = rect.max.y as f32 + vmetrics.ascent;

                            coords.push(Point2::new(min_px, min_py));
                            coords.push(Point2::new(tex.min.x, tex.min.y));

                            coords.push(Point2::new(min_px, max_py));
                            coords.push(Point2::new(tex.min.x, tex.max.y));

                            coords.push(Point2::new(max_px, min_py));
                            coords.push(Point2::new(tex.max.x, tex.min.y));

                            coords.push(Point2::new(max_px, min_py));
                            coords.push(Point2::new(tex.max.x, tex.min.y));

                            coords.push(Point2::new(min_px, max_py));
                            coords.push(Point2::new(tex.min.x, tex.max.y));

                            coords.push(Point2::new(max_px, max_py));
                            coords.push(Point2::new(tex.max.x, tex.max.y));
                        }
                    }
                }

                self.pos.bind_sub_buffer(&mut self.coords, 1, 0);
                self.uvs.bind_sub_buffer(&mut self.coords, 1, 1);
                self.color.upload(&context.color);

                verify!(ctxt.draw_arrays(Context::TRIANGLES, 0, (self.coords.len() / 2) as i32));
            }
            pos += context.len;

            self.coords.data_mut().as_mut().unwrap().clear();
        }

        self.pos.disable();
        self.uvs.enable();

        verify!(ctxt.enable(Context::DEPTH_TEST));
        verify!(ctxt.disable(Context::BLEND));

        self.contexts.clear();
    }
}

/// Vertex shader used by the material to display line.
pub static TEXT_VERTEX_SRC: &'static str = A_VERY_LONG_STRING;
/// Fragment shader used by the material to display line.
pub static TEXT_FRAGMENT_SRC: &'static str = ANOTHER_VERY_LONG_STRING;

const A_VERY_LONG_STRING: &'static str = "
#version 100

uniform vec2 invsz;
uniform vec3 color;

attribute vec2 pos;
attribute vec2 uvs;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_Position = vec4(pos.x * invsz.x - 1.0, pos.y * invsz.y + 1.0, -1.0, 1.0);
    tex         = uvs;
    Color       = color;
}
";

const ANOTHER_VERY_LONG_STRING: &'static str = "
#version 100

#ifdef GL_FRAGMENT_PRECISION_HIGH
   precision highp float;
#else
   precision mediump float;
#endif

uniform sampler2D tex0;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_FragColor = vec4(Color, texture2D(tex0, tex).r);
}
";
<commit_msg>Clear the string buffer on the text renderer.<commit_after>// This whole file is inspired by: https://github.com/jeaye/q3/blob/master/src/client/ui/ttf/renderer.rs
// available under the BSD-3 licence.
// It has been modified to work with gl-rs, nalgebra, and rust-freetype

use na::{Point2, Point3, Vector2};
use rusttype;
use rusttype::gpu_cache::{Cache, CacheBuilder};
use std::mem;
use std::rc::Rc;

use context::{Context, Texture};
use resource::{AllocationType, BufferType, Effect, GPUVec, ShaderAttribute, ShaderUniform};
use text::Font;

#[path = "../error.rs"]
mod error;

struct TextRenderContext {
    len: usize,
    scale: f32,
    color: Point3<f32>,
    pos: Point2<f32>,
    font: Rc<Font>,
}

/// A ttf text renderer.
pub struct TextRenderer {
    text: String,
    texture: Texture,
    shader: Effect,
    cache: Cache<'static>,
    invsz: ShaderUniform<Vector2<f32>>,
    tex: ShaderUniform<i32>,
    color: ShaderUniform<Point3<f32>>,
    pos: ShaderAttribute<Point2<f32>>,
    uvs: ShaderAttribute<Point2<f32>>,
    contexts: Vec<TextRenderContext>,
    coords: GPUVec<Point2<f32>>,
}

impl TextRenderer {
    /// Creates a new text renderer with `font` as the default font.
    pub fn new() -> TextRenderer {
        //
        // Create cache.
        //
        let atlas_width = 1024;
        let atlas_height = 1024;
        let cache = CacheBuilder {
            width: atlas_width,
            height: atlas_height,
            ..CacheBuilder::default()
        }.build();

        //
        // Create texture.
        //
        let ctxt = Context::get();

        /* We're using 1 byte alignment buffering. */
        verify!(ctxt.pixel_storei(Context::UNPACK_ALIGNMENT, 1));

        let texture = verify!(
            ctxt.create_texture()
                .expect("Font texture creation failed.")
        );
        verify!(ctxt.bind_texture(Context::TEXTURE_2D, Some(&texture)));
        verify!(ctxt.tex_image2d(
            Context::TEXTURE_2D,
            0,
            Context::RED as i32,
            atlas_width as i32,
            atlas_height as i32,
            0,
            Context::RED,
            None
        ));

        /* Clamp to the edge to avoid artifacts when scaling. */
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_S,
            Context::CLAMP_TO_EDGE as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_T,
            Context::CLAMP_TO_EDGE as i32
        ));

        /* Linear filtering usually looks best for text. */
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_MIN_FILTER,
            Context::LINEAR as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_MAG_FILTER,
            Context::LINEAR as i32
        ));

        //
        // Create shader.
        //
        let mut shader = Effect::new_from_str(TEXT_VERTEX_SRC, TEXT_FRAGMENT_SRC);
        shader.use_program();

        TextRenderer {
            text: String::new(),
            cache,
            texture,
            invsz: shader.get_uniform("invsz").expect("Could not find invsz"),
            tex: shader.get_uniform("tex0").expect("Could not find tex0"),
            color: shader.get_uniform("color").expect("Could not find color"),
            pos: shader.get_attrib("pos").expect("Could not find pos"),
            uvs: shader.get_attrib("uvs").expect("Could not find uvs"),
            shader: shader,
            contexts: Vec::new(),
            coords: GPUVec::new(Vec::new(), BufferType::Array, AllocationType::StreamDraw),
        }
    }

    /// Adds a piece of text to be drawn during the next frame. The text is not persistent between
    /// frames. This method must be called for each text to draw, and at each update loop
    /// iteration.
    pub fn draw_text(
        &mut self,
        text: &str,
        pos: &Point2<f32>,
        scale: f32,
        font: &Rc<Font>,
        color: &Point3<f32>,
    ) {
        self.text.push_str(text);
        self.contexts.push(TextRenderContext {
            len: text.len(),
            scale,
            color: *color,
            pos: *pos,
            font: font.clone(),
        })
    }

    /// Actually draws the text.
    pub fn render(&mut self, width: f32, height: f32) {
        if self.contexts.len() == 0 {
            return;
        }

        let ctxt = Context::get();
        self.shader.use_program();

        verify!(ctxt.polygon_mode(Context::FRONT_AND_BACK, Context::FILL));
        verify!(ctxt.enable(Context::BLEND));
        verify!(ctxt.blend_func(Context::SRC_ALPHA, Context::ONE_MINUS_SRC_ALPHA));
        verify!(ctxt.disable(Context::DEPTH_TEST));

        self.pos.enable();
        self.uvs.enable();
        self.tex.upload(&0);
        self.invsz.upload(&Vector2::new(1.0 / width, -1.0 / height));

        verify!(ctxt.bind_texture(Context::TEXTURE_2D, Some(&self.texture)));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_S,
            Context::CLAMP_TO_EDGE as i32
        ));
        verify!(ctxt.tex_parameteri(
            Context::TEXTURE_2D,
            Context::TEXTURE_WRAP_T,
            Context::CLAMP_TO_EDGE as i32
        ));

        let mut pos = 0;

        for context in self.contexts.iter() {
            let text = &self.text[pos..pos + context.len];
            let font_uid = Font::uid(&context.font);

            for (line_count, line) in text.lines().enumerate() {
                let scale = rusttype::Scale::uniform(context.scale);
                let orig = rusttype::Point {
                    x: context.pos.x,
                    y: context.pos.y,
                };
                let layout = context.font.font().layout(line, scale, orig);

                for glyph in layout {
                    let gly: rusttype::PositionedGlyph<'static> = context
                        .font
                        .font()
                        .glyph(glyph.id())
                        .scaled(glyph.scale())
                        .positioned(glyph.position());
                    self.cache.queue_glyph(font_uid, gly); // FIXME: is the call to `.standalone()` costly?
                }

                self.cache.cache_queued(|rect, data| {
                    verify!(ctxt.tex_sub_image2d(
                        Context::TEXTURE_2D,
                        0,
                        rect.min.x as i32,
                        rect.min.y as i32,
                        rect.width() as i32,
                        rect.height() as i32,
                        Context::RED,
                        Some(&data)
                    ));
                });

                let layout = context.font.font().layout(line, scale, orig);

                {
                    let vmetrics = context.font.font().v_metrics(scale);
                    let coords = self.coords.data_mut().as_mut().unwrap();
                    for glyph in layout {
                        if let Some(Some((tex, rect))) = self.cache.rect_for(font_uid, &glyph).ok()
                        {
                            let min_px = rect.min.x as f32;
                            let min_py = rect.min.y as f32 + vmetrics.ascent;
                            let max_px = rect.max.x as f32;
                            let max_py = rect.max.y as f32 + vmetrics.ascent;

                            coords.push(Point2::new(min_px, min_py));
                            coords.push(Point2::new(tex.min.x, tex.min.y));

                            coords.push(Point2::new(min_px, max_py));
                            coords.push(Point2::new(tex.min.x, tex.max.y));

                            coords.push(Point2::new(max_px, min_py));
                            coords.push(Point2::new(tex.max.x, tex.min.y));

                            coords.push(Point2::new(max_px, min_py));
                            coords.push(Point2::new(tex.max.x, tex.min.y));

                            coords.push(Point2::new(min_px, max_py));
                            coords.push(Point2::new(tex.min.x, tex.max.y));

                            coords.push(Point2::new(max_px, max_py));
                            coords.push(Point2::new(tex.max.x, tex.max.y));
                        }
                    }
                }

                self.pos.bind_sub_buffer(&mut self.coords, 1, 0);
                self.uvs.bind_sub_buffer(&mut self.coords, 1, 1);
                self.color.upload(&context.color);

                verify!(ctxt.draw_arrays(Context::TRIANGLES, 0, (self.coords.len() / 2) as i32));
            }
            pos += context.len;

            self.coords.data_mut().as_mut().unwrap().clear();
        }

        self.pos.disable();
        self.uvs.enable();

        verify!(ctxt.enable(Context::DEPTH_TEST));
        verify!(ctxt.disable(Context::BLEND));

        self.contexts.clear();
        self.text.clear();
    }
}

/// Vertex shader used by the material to display line.
pub static TEXT_VERTEX_SRC: &'static str = A_VERY_LONG_STRING;
/// Fragment shader used by the material to display line.
pub static TEXT_FRAGMENT_SRC: &'static str = ANOTHER_VERY_LONG_STRING;

const A_VERY_LONG_STRING: &'static str = "
#version 100

uniform vec2 invsz;
uniform vec3 color;

attribute vec2 pos;
attribute vec2 uvs;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_Position = vec4(pos.x * invsz.x - 1.0, pos.y * invsz.y + 1.0, -1.0, 1.0);
    tex         = uvs;
    Color       = color;
}
";

const ANOTHER_VERY_LONG_STRING: &'static str = "
#version 100

#ifdef GL_FRAGMENT_PRECISION_HIGH
   precision highp float;
#else
   precision mediump float;
#endif

uniform sampler2D tex0;

varying vec2 tex;
varying vec3 Color;

void main() {
    gl_FragColor = vec4(Color, texture2D(tex0, tex).r);
}
";
<|endoftext|>


<commit_before>
extern crate chrono;
extern crate rustc_serialize;

mod daterecord;
mod direction;
mod error;
mod timeentry;
mod traits;
mod iterators;

use chrono::*;
use csv;
pub use self::daterecord::DateRecord;
pub use self::direction::Direction;
pub use self::error::TimeClockError;
pub use self::iterators::*;
pub use self::timeentry::{TimeEntry, TimeEntryPair};
pub use self::traits::*;
use std::fs::File;
use std::io::SeekFrom;
use std::io::prelude::*;

pub fn read_timesheet<R: Read>(file: R)
                               -> Result<Vec<TimeEntry>, TimeClockError> {
    let mut rdr = csv::Reader::from_reader(file).has_headers(false);
    let mut in_v = rdr.decode().collect::<csv::Result<Vec<TimeEntry>>>()?;
    in_v.sort_by_key(|k| k.time);

    Ok(in_v)
}

/// Reduce pairs of `TimeEntrys` into `DateRecords`
pub fn collect_date_records(records: Vec<TimeEntry>) -> Vec<DateRecord> {
    let mut res: Vec<DateRecord> = Vec::new();
    for rec in timeentry_pairs(records.into_iter()).daterecords() {
        match res.pop() {
            Some(mut r) => {
                if r.combine(&rec) {
                    res.push(r);
                } else {
                    res.push(rec);
                }
            }
            None => res.push(rec),
        }
    }
    res
}

/// Marks the time.
pub fn mark_time(d: Direction,
                 time: DateTime<FixedOffset>,
                 memo: String,
                 mut file: File) {
    let record = TimeEntry {
        dir: d,
        time: time,
        memo: memo,
    };
    // seek in case we write without reading first
    let _ = file.seek(SeekFrom::End(0));
    let mut wtr = csv::Writer::from_writer(file);
    let _ = wtr.encode(record);
}

/// Get the current date and time as a `DateTime`<`FixedOffset`>
pub fn now() -> DateTime<FixedOffset> {
    let lt: DateTime<Local> = Local::now();
    DateTime::parse_from_rfc3339(lt.to_rfc3339().as_ref()).unwrap()
}

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

    #[test]
    fn read_timesheet_test() {
        // test for sorting and general function
        let s = "Out,2016-12-18T16:53:33-0600,\n\
                 In,2016-12-19T20:54:53-0600,\n\
                 In,2016-12-18T13:01:50-0600,\n\
                 Out,2016-12-19T20:54:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let records = read_timesheet(buff).unwrap();
        for slc in records.chunks(2) {
            assert!(slc[0].dir == Direction::In);
            assert!(slc[1].dir == Direction::Out);
        }
        // test ordering
        assert!(records[0].time < records[1].time);
        assert!(records[1].time < records[2].time);
        assert!(records[2].time < records[3].time);
    }

    #[test]
    fn read_timesheet_haggis_test() {
        // test for sorting and general function
        let s = "Fair fa' your honest, sonsie face,\n\
                 Great chieftain o' the pudding-race!\n\
                 Aboon them a' ye tak your place,\n\
                 Painch, tripe, or thairm:\n\
                 Weel are ye wordy o' a grace\n\
                 As lang's my arm.";
        let buff = Cursor::new(s.as_bytes());
        let records = read_timesheet(buff);
        assert!(records.is_err());
    }

    #[test]
    fn pair_time_entries_test() {
        let s = "Out,2016-12-18T13:01:50-0600,\n\
                 In,2016-12-19T20:54:57-0600,\n\
                 Out,2016-12-20T20:50:57-0600,\n\
                 Out,2016-12-20T20:50:59-0600,\n\
                 In,2016-12-20T21:04:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = timeentry_pairs(entries.into_iter())
            .collect::<Vec<TimeEntryPair>>();

        assert!(records.len() == 4);

        for tep in records {
            assert!(tep.start().dir == Direction::In);
            assert!(tep.end().dir == Direction::Out);
        }
    }

    #[test]
    fn pair_time_entries_double_in_test() {
        let s = "In,2016-12-20T21:01:57-0600,\n\
                 In,2016-12-20T21:04:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = timeentry_pairs(entries.into_iter())
            .collect::<Vec<TimeEntryPair>>();

        assert!(records.len() == 2);

        for tep in records {
            assert!(tep.start().dir == Direction::In);
            assert!(tep.end().dir == Direction::Out);
        }
    }

    #[test]
    fn collect_date_records_test() {
        let time = now();
        let records = vec![TimeEntry::new(Direction::In, time, "In"),
                           TimeEntry::new(Direction::Out, time, "Out")];

        let res = collect_date_records(records);
        assert_eq!(res.len(), 1);
        let dr = res.first().unwrap();
        assert_eq!(dr.date(), time.date());
        assert_eq!(dr.hours(), 0.0);
    }

    #[test]
    fn collect_date_records_tz_test() {
        // test mismatched timezones
        let s = "In,2016-12-18T13:01:50-0500,\n\
                 Out,2016-12-18T13:01:50-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = collect_date_records(entries);

        assert!(records.len() == 1);
        println!("\n{}", records[0].seconds());
        assert!(records[0].seconds() == 3600.0);
    }
}
<commit_msg>Fixed issue with dropped DateRecords<commit_after>
extern crate chrono;
extern crate rustc_serialize;

mod daterecord;
mod direction;
mod error;
mod timeentry;
mod traits;
mod iterators;

use chrono::*;
use csv;
pub use self::daterecord::DateRecord;
pub use self::direction::Direction;
pub use self::error::TimeClockError;
pub use self::iterators::*;
pub use self::timeentry::{TimeEntry, TimeEntryPair};
pub use self::traits::*;
use std::fs::File;
use std::io::SeekFrom;
use std::io::prelude::*;

pub fn read_timesheet<R: Read>(file: R)
                               -> Result<Vec<TimeEntry>, TimeClockError> {
    let mut rdr = csv::Reader::from_reader(file).has_headers(false);
    let mut in_v = rdr.decode().collect::<csv::Result<Vec<TimeEntry>>>()?;
    in_v.sort_by_key(|k| k.time);

    Ok(in_v)
}

/// Reduce pairs of `TimeEntrys` into `DateRecords`
pub fn collect_date_records(records: Vec<TimeEntry>) -> Vec<DateRecord> {
    let mut res: Vec<DateRecord> = Vec::new();
    for rec in timeentry_pairs(records.into_iter()).daterecords() {
        match res.pop() {
            Some(mut r) => {
                if r.combine(&rec) {
                    res.push(r);
                } else {
                    res.push(r);
                    res.push(rec);
                }
            }
            None => res.push(rec),
        }
    }
    res
}

/// Marks the time.
pub fn mark_time(d: Direction,
                 time: DateTime<FixedOffset>,
                 memo: String,
                 mut file: File) {
    let record = TimeEntry {
        dir: d,
        time: time,
        memo: memo,
    };
    // seek in case we write without reading first
    let _ = file.seek(SeekFrom::End(0));
    let mut wtr = csv::Writer::from_writer(file);
    let _ = wtr.encode(record);
}

/// Get the current date and time as a `DateTime`<`FixedOffset`>
pub fn now() -> DateTime<FixedOffset> {
    let lt: DateTime<Local> = Local::now();
    DateTime::parse_from_rfc3339(lt.to_rfc3339().as_ref()).unwrap()
}

#[cfg(test)]
mod tests {
    use chrono::duration::Duration;
    use std::io::Cursor;
    use super::*;

    #[test]
    fn read_timesheet_test() {
        // test for sorting and general function
        let s = "Out,2016-12-18T16:53:33-0600,\n\
                 In,2016-12-19T20:54:53-0600,\n\
                 In,2016-12-18T13:01:50-0600,\n\
                 Out,2016-12-19T20:54:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let records = read_timesheet(buff).unwrap();
        for slc in records.chunks(2) {
            assert!(slc[0].dir == Direction::In);
            assert!(slc[1].dir == Direction::Out);
        }
        // test ordering
        assert!(records[0].time < records[1].time);
        assert!(records[1].time < records[2].time);
        assert!(records[2].time < records[3].time);
    }

    #[test]
    fn read_timesheet_haggis_test() {
        // test for sorting and general function
        let s = "Fair fa' your honest, sonsie face,\n\
                 Great chieftain o' the pudding-race!\n\
                 Aboon them a' ye tak your place,\n\
                 Painch, tripe, or thairm:\n\
                 Weel are ye wordy o' a grace\n\
                 As lang's my arm.";
        let buff = Cursor::new(s.as_bytes());
        let records = read_timesheet(buff);
        assert!(records.is_err());
    }

    #[test]
    fn pair_time_entries_test() {
        let s = "Out,2016-12-18T13:01:50-0600,\n\
                 In,2016-12-19T20:54:57-0600,\n\
                 Out,2016-12-20T20:50:57-0600,\n\
                 Out,2016-12-20T20:50:59-0600,\n\
                 In,2016-12-20T21:04:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = timeentry_pairs(entries.into_iter())
            .collect::<Vec<TimeEntryPair>>();

        assert!(records.len() == 4);

        for tep in records {
            assert!(tep.start().dir == Direction::In);
            assert!(tep.end().dir == Direction::Out);
        }
    }

    #[test]
    fn pair_time_entries_double_in_test() {
        let s = "In,2016-12-20T21:01:57-0600,\n\
                 In,2016-12-20T21:04:57-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = timeentry_pairs(entries.into_iter())
            .collect::<Vec<TimeEntryPair>>();

        assert!(records.len() == 2);

        for tep in records {
            assert!(tep.start().dir == Direction::In);
            assert!(tep.end().dir == Direction::Out);
        }
    }

    #[test]
    fn collect_date_records_test() {
        let time = now();
        let day = Duration::days(1);
        let records = vec![TimeEntry::new(Direction::In, time, "In"),
                           TimeEntry::new(Direction::Out, time, "Out"),
                           TimeEntry::new(Direction::In, time, "In"),
                           TimeEntry::new(Direction::Out, time, "Out"),
                           TimeEntry::new(Direction::In, time + day, "In"),
                           TimeEntry::new(Direction::Out, time + day, "Out")];

        let res = collect_date_records(records);
        assert_eq!(res.len(), 2);
        let dr = res.first().unwrap();
        assert_eq!(dr.date(), time.date());
        assert_eq!(dr.hours(), 0.0);
        let dr = res.last().unwrap();
        assert_eq!(dr.date(), time.date() + day);
        assert_eq!(dr.hours(), 0.0);
    }

    #[test]
    fn collect_date_records_tz_test() {
        // test mismatched timezones
        let s = "In,2016-12-18T13:01:50-0500,\n\
                 Out,2016-12-18T13:01:50-0600,";
        let buff = Cursor::new(s.as_bytes());
        let entries = read_timesheet(buff).unwrap();
        let records = collect_date_records(entries);

        assert!(records.len() == 1);
        println!("\n{}", records[0].seconds());
        assert!(records[0].seconds() == 3600.0);
    }
}
<|endoftext|>


<commit_before>use nix::sys::uio::*;
use nix::unistd::*;
use rand::{thread_rng, Rng};
use std::{cmp, iter};
use std::fs::{OpenOptions, remove_file};
use std::os::unix::io::AsRawFd;

use tempdir::TempDir;

#[test]
fn test_writev() {
    let mut to_write = Vec::with_capacity(16 * 128);
    for _ in 0..16 {
        let s: String = thread_rng().gen_ascii_chars().take(128).collect();
        let b = s.as_bytes();
        to_write.extend(b.iter().map(|x| x.clone()));
    }
    // Allocate and fill iovecs
    let mut iovecs = Vec::new();
    let mut consumed = 0;
    while consumed < to_write.len() {
        let left = to_write.len() - consumed;
        let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
        let b = &to_write[consumed..consumed+slice_len];
        iovecs.push(IoVec::from_slice(b));
        consumed += slice_len;
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // FileDesc will close its filedesc (reader).
    let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
    // Blocking io, should write all data.
    let write_res = writev(writer, &iovecs);
    // Successful write
    assert!(write_res.is_ok());
    let written = write_res.ok().unwrap();
    // Check whether we written all data
    assert_eq!(to_write.len(), written);
    let read_res = read(reader, &mut read_buf[..]);
    // Successful read
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap() as usize;
    // Check we have read as much as we written
    assert_eq!(read, written);
    // Check equality of written and read data
    assert_eq!(&to_write, &read_buf);
    let close_res = close(writer);
    assert!(close_res.is_ok());
    let close_res = close(reader);
    assert!(close_res.is_ok());
}

#[test]
fn test_readv() {
    let s:String = thread_rng().gen_ascii_chars().take(128).collect();
    let to_write = s.as_bytes().to_vec();
    let mut storage = Vec::new();
    let mut allocated = 0;
    while allocated < to_write.len() {
        let left = to_write.len() - allocated;
        let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
        let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
        storage.push(v);
        allocated += vec_len;
    }
    let mut iovecs = Vec::with_capacity(storage.len());
    for v in storage.iter_mut() {
        iovecs.push(IoVec::from_mut_slice(&mut v[..]));
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // Blocking io, should write all data.
    let write_res = write(writer, &to_write);
    // Successful write
    assert!(write_res.is_ok());
    let read_res = readv(reader, &mut iovecs[..]);
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap();
    // Check whether we've read all data
    assert_eq!(to_write.len(), read);
    // Cccumulate data from iovecs
    let mut read_buf = Vec::with_capacity(to_write.len());
    for iovec in iovecs.iter() {
        read_buf.extend(iovec.as_slice().iter().map(|x| x.clone()));
    }
    // Check whether iovecs contain all written data
    assert_eq!(read_buf.len(), to_write.len());
    // Check equality of written and read data
    assert_eq!(&read_buf, &to_write);
    let close_res = close(reader);
    assert!(close_res.is_ok());
    let close_res = close(writer);
    assert!(close_res.is_ok());
}

#[test]
fn test_pwrite() {
    use std::io::Read;

    let path = "pwrite_test_file";
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();
    let buf = [1u8;8];
    assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
    let mut file_content = Vec::new();
    file.read_to_end(&mut file_content).unwrap();
    let mut expected = vec![0u8;8];
    expected.extend(vec![1;8]);
    assert_eq!(file_content, expected);

    remove_file(path).unwrap();
}

#[test]
fn test_pread() {
    use std::io::Write;

    let tempdir = TempDir::new("nix-test_pread").unwrap();

    let path = tempdir.path().join("pread_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();
    let file_content: Vec<u8> = (0..64).collect();
    file.write_all(&file_content).unwrap();

    let mut buf = [0u8;16];
    assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
    let expected: Vec<_> = (16..32).collect();
    assert_eq!(&buf[..], &expected[..]);
}

#[test]
#[cfg(feature = "preadv_pwritev")]
fn test_pwritev() {
    use std::io::Read;

    let to_write: Vec<u8> = (0..128).collect();
    let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();

    let iovecs = [
        IoVec::from_slice(&to_write[0..17]),
        IoVec::from_slice(&to_write[17..64]),
        IoVec::from_slice(&to_write[64..128]),
    ];

    let tempdir = TempDir::new("nix-test_pwritev").unwrap();

    // pwritev them into a temporary file
    let path = tempdir.path().join("pwritev_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();

    let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
    assert_eq!(written, to_write.len());

    // Read the data back and make sure it matches
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(contents, expected);
}

#[test]
#[cfg(feature = "preadv_pwritev")]
fn test_preadv() {
    use std::io::Write;

    let to_write: Vec<u8> = (0..200).collect();
    let expected: Vec<u8> = (100..200).collect();

    let tempdir = TempDir::new("nix-test_preadv").unwrap();

    let path = tempdir.path().join("preadv_test_file");

    let mut file = OpenOptions::new().read(true).write(true).create(true)
                                    .truncate(true).open(path).unwrap();
    file.write_all(&to_write).unwrap();

    let mut buffers: Vec<Vec<u8>> = vec![
        vec![0; 24],
        vec![0; 1],
        vec![0; 75],
    ];

    {
        // Borrow the buffers into IoVecs and preadv into them
        let mut iovecs: Vec<_> = buffers.iter_mut().map(
            |buf| IoVec::from_mut_slice(&mut buf[..])).collect();
        assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
    }

    let all = buffers.concat();
    assert_eq!(all, expected);
}
<commit_msg>Auto merge of #443 - asomers:mkstemp, r=posborne<commit_after>use nix::sys::uio::*;
use nix::unistd::*;
use rand::{thread_rng, Rng};
use std::{cmp, iter};
use std::fs::{OpenOptions, remove_file};
use std::os::unix::io::AsRawFd;

use tempdir::TempDir;
use tempfile::tempfile;

#[test]
fn test_writev() {
    let mut to_write = Vec::with_capacity(16 * 128);
    for _ in 0..16 {
        let s: String = thread_rng().gen_ascii_chars().take(128).collect();
        let b = s.as_bytes();
        to_write.extend(b.iter().map(|x| x.clone()));
    }
    // Allocate and fill iovecs
    let mut iovecs = Vec::new();
    let mut consumed = 0;
    while consumed < to_write.len() {
        let left = to_write.len() - consumed;
        let slice_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
        let b = &to_write[consumed..consumed+slice_len];
        iovecs.push(IoVec::from_slice(b));
        consumed += slice_len;
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // FileDesc will close its filedesc (reader).
    let mut read_buf: Vec<u8> = iter::repeat(0u8).take(128 * 16).collect();
    // Blocking io, should write all data.
    let write_res = writev(writer, &iovecs);
    // Successful write
    assert!(write_res.is_ok());
    let written = write_res.ok().unwrap();
    // Check whether we written all data
    assert_eq!(to_write.len(), written);
    let read_res = read(reader, &mut read_buf[..]);
    // Successful read
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap() as usize;
    // Check we have read as much as we written
    assert_eq!(read, written);
    // Check equality of written and read data
    assert_eq!(&to_write, &read_buf);
    let close_res = close(writer);
    assert!(close_res.is_ok());
    let close_res = close(reader);
    assert!(close_res.is_ok());
}

#[test]
fn test_readv() {
    let s:String = thread_rng().gen_ascii_chars().take(128).collect();
    let to_write = s.as_bytes().to_vec();
    let mut storage = Vec::new();
    let mut allocated = 0;
    while allocated < to_write.len() {
        let left = to_write.len() - allocated;
        let vec_len = if left <= 64 { left } else { thread_rng().gen_range(64, cmp::min(256, left)) };
        let v: Vec<u8> = iter::repeat(0u8).take(vec_len).collect();
        storage.push(v);
        allocated += vec_len;
    }
    let mut iovecs = Vec::with_capacity(storage.len());
    for v in storage.iter_mut() {
        iovecs.push(IoVec::from_mut_slice(&mut v[..]));
    }
    let pipe_res = pipe();
    assert!(pipe_res.is_ok());
    let (reader, writer) = pipe_res.ok().unwrap();
    // Blocking io, should write all data.
    let write_res = write(writer, &to_write);
    // Successful write
    assert!(write_res.is_ok());
    let read_res = readv(reader, &mut iovecs[..]);
    assert!(read_res.is_ok());
    let read = read_res.ok().unwrap();
    // Check whether we've read all data
    assert_eq!(to_write.len(), read);
    // Cccumulate data from iovecs
    let mut read_buf = Vec::with_capacity(to_write.len());
    for iovec in iovecs.iter() {
        read_buf.extend(iovec.as_slice().iter().map(|x| x.clone()));
    }
    // Check whether iovecs contain all written data
    assert_eq!(read_buf.len(), to_write.len());
    // Check equality of written and read data
    assert_eq!(&read_buf, &to_write);
    let close_res = close(reader);
    assert!(close_res.is_ok());
    let close_res = close(writer);
    assert!(close_res.is_ok());
}

#[test]
fn test_pwrite() {
    use std::io::Read;

    let mut file = tempfile().unwrap();
    let buf = [1u8;8];
    assert_eq!(Ok(8), pwrite(file.as_raw_fd(), &buf, 8));
    let mut file_content = Vec::new();
    file.read_to_end(&mut file_content).unwrap();
    let mut expected = vec![0u8;8];
    expected.extend(vec![1;8]);
    assert_eq!(file_content, expected);
}

#[test]
fn test_pread() {
    use std::io::Write;

    let tempdir = TempDir::new("nix-test_pread").unwrap();

    let path = tempdir.path().join("pread_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();
    let file_content: Vec<u8> = (0..64).collect();
    file.write_all(&file_content).unwrap();

    let mut buf = [0u8;16];
    assert_eq!(Ok(16), pread(file.as_raw_fd(), &mut buf, 16));
    let expected: Vec<_> = (16..32).collect();
    assert_eq!(&buf[..], &expected[..]);
}

#[test]
#[cfg(feature = "preadv_pwritev")]
fn test_pwritev() {
    use std::io::Read;

    let to_write: Vec<u8> = (0..128).collect();
    let expected: Vec<u8> = [vec![0;100], to_write.clone()].concat();

    let iovecs = [
        IoVec::from_slice(&to_write[0..17]),
        IoVec::from_slice(&to_write[17..64]),
        IoVec::from_slice(&to_write[64..128]),
    ];

    let tempdir = TempDir::new("nix-test_pwritev").unwrap();

    // pwritev them into a temporary file
    let path = tempdir.path().join("pwritev_test_file");
    let mut file = OpenOptions::new().write(true).read(true).create(true)
                                    .truncate(true).open(path).unwrap();

    let written = pwritev(file.as_raw_fd(), &iovecs, 100).ok().unwrap();
    assert_eq!(written, to_write.len());

    // Read the data back and make sure it matches
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    assert_eq!(contents, expected);
}

#[test]
#[cfg(feature = "preadv_pwritev")]
fn test_preadv() {
    use std::io::Write;

    let to_write: Vec<u8> = (0..200).collect();
    let expected: Vec<u8> = (100..200).collect();

    let tempdir = TempDir::new("nix-test_preadv").unwrap();

    let path = tempdir.path().join("preadv_test_file");

    let mut file = OpenOptions::new().read(true).write(true).create(true)
                                    .truncate(true).open(path).unwrap();
    file.write_all(&to_write).unwrap();

    let mut buffers: Vec<Vec<u8>> = vec![
        vec![0; 24],
        vec![0; 1],
        vec![0; 75],
    ];

    {
        // Borrow the buffers into IoVecs and preadv into them
        let mut iovecs: Vec<_> = buffers.iter_mut().map(
            |buf| IoVec::from_mut_slice(&mut buf[..])).collect();
        assert_eq!(Ok(100), preadv(file.as_raw_fd(), &mut iovecs, 100));
    }

    let all = buffers.concat();
    assert_eq!(all, expected);
}
<|endoftext|>


<commit_before>// Copyright 2016 Matthew Collins
//
// 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.

pub struct Map {
    bits: Vec<u64>,
    pub bit_size: usize,
    length: usize,
}

#[test]
fn test_map() {
    let mut map = Map::new(4096, 4);
    for i in 0..4096 {
        for j in 0..16 {
            map.set(i, j);
            if map.get(i) != j {
                panic!("Fail");
            }
        }
    }
}

#[test]
fn test_map_odd() {
    for size in 1..16 {
        let mut map = Map::new(64 * 3, size);
        let max = (1 << size) - 1;
        for i in 0..64 * 3 {
            for j in 0..max {
                map.set(i, j);
                if map.get(i) != j {
                    panic!("Index: {} wanted {} and got {}", i, j, map.get(i));
                }
            }
        }
    }
}

impl Map {
    pub fn new(len: usize, size: usize) -> Map {
        let mut map = Map {
            bit_size: size,
            length: len,
            bits: Vec::with_capacity((len * size) / 64),
        };
        for _ in 0..len {
            map.bits.push(0)
        }
        map
    }
    pub fn from_raw(bits: Vec<u64>, size: usize) -> Map {
        Map {
            length: (bits.len()*64 + 63) / size,
            bit_size: size,
            bits: bits,
        }
    }

    pub fn resize(&self, size: usize) -> Map {
        let mut n = Map::new(self.length, size);
        for i in 0..self.length {
            n.set(i, self.get(i));
        }
        n
    }

    pub fn set(&mut self, i: usize, val: usize) {
        let i = i * self.bit_size;
        let pos = i / 64;
        let mask = (1 << self.bit_size) - 1;
        let ii = i % 64;
        self.bits[pos] = (self.bits[pos] & !(mask << ii)) | ((val << ii) as u64);
        let pos2 = (i + self.bit_size - 1) / 64;
        if pos2 != pos {
            let used = 64 - ii;
            let rem = self.bit_size - used;
            self.bits[pos2] = self.bits[pos2] >> rem << rem | (val as u64 >> used);
        }
    }

    pub fn get(&self, i: usize) -> usize {
        let i = i * self.bit_size;
        let pos = i / 64;
        let mask = (1 << self.bit_size) - 1;
        let ii = i % 64;
        let pos2 = (i + self.bit_size - 1) / 64;
        if pos2 == pos {
            ((self.bits[pos] >> ii) & mask) as usize
        } else {
            let used = 64 - ii;
            (((self.bits[pos] >> ii) | (self.bits[pos2] << used)) & mask) as usize
        }
    }
}
<commit_msg>Fix a bit::Map overflow on 32 bit machines<commit_after>// Copyright 2016 Matthew Collins
//
// 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.

pub struct Map {
    bits: Vec<u64>,
    pub bit_size: usize,
    length: usize,
}

#[test]
fn test_map() {
    let mut map = Map::new(4096, 4);
    for i in 0..4096 {
        for j in 0..16 {
            map.set(i, j);
            if map.get(i) != j {
                panic!("Fail");
            }
        }
    }
}

#[test]
fn test_map_odd() {
    for size in 1..16 {
        let mut map = Map::new(64 * 3, size);
        let max = (1 << size) - 1;
        for i in 0..64 * 3 {
            for j in 0..max {
                map.set(i, j);
                if map.get(i) != j {
                    panic!("Index: {} wanted {} and got {}", i, j, map.get(i));
                }
            }
        }
    }
}

impl Map {
    pub fn new(len: usize, size: usize) -> Map {
        let mut map = Map {
            bit_size: size,
            length: len,
            bits: Vec::with_capacity((len * size) / 64),
        };
        for _ in 0..len {
            map.bits.push(0)
        }
        map
    }
    pub fn from_raw(bits: Vec<u64>, size: usize) -> Map {
        Map {
            length: (bits.len()*64 + 63) / size,
            bit_size: size,
            bits: bits,
        }
    }

    pub fn resize(&self, size: usize) -> Map {
        let mut n = Map::new(self.length, size);
        for i in 0..self.length {
            n.set(i, self.get(i));
        }
        n
    }

    pub fn set(&mut self, i: usize, val: usize) {
        let i = i * self.bit_size;
        let pos = i / 64;
        let mask = (1u64 << self.bit_size) - 1;
        let ii = i % 64;
        self.bits[pos] = (self.bits[pos] & !(mask << ii)) | ((val as u64) << ii);
        let pos2 = (i + self.bit_size - 1) / 64;
        if pos2 != pos {
            let used = 64 - ii;
            let rem = self.bit_size - used;
            self.bits[pos2] = self.bits[pos2] >> rem << rem | (val as u64 >> used);
        }
    }

    pub fn get(&self, i: usize) -> usize {
        let i = i * self.bit_size;
        let pos = i / 64;
        let mask = (1 << self.bit_size) - 1;
        let ii = i % 64;
        let pos2 = (i + self.bit_size - 1) / 64;
        if pos2 == pos {
            ((self.bits[pos] >> ii) & mask) as usize
        } else {
            let used = 64 - ii;
            (((self.bits[pos] >> ii) | (self.bits[pos2] << used)) & mask) as usize
        }
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;

use wlroots::{CompositorHandle, Origin, SurfaceHandle, SurfaceHandler,
              XdgShellSurfaceHandle, XdgShellHandler, XdgShellManagerHandler};
use wlroots::xdg_shell_events::{MoveEvent, ResizeEvent};

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Xdg {
    shell_surface: XdgShellSurfaceHandle
}

impl Xdg {
    pub fn new() -> Self {
        Xdg { .. Xdg::default()}
    }
}

impl XdgShellHandler for Xdg {
    fn resize_request(&mut self,
                      compositor: CompositorHandle,
                      _: SurfaceHandle,
                      shell_surface: XdgShellSurfaceHandle,
                      event: &ResizeEvent) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut seat,
                         ref mut views,
                         ref mut cursor,
                         .. } = *server;
            let resizing_shell = shell_surface.into();

            if let Some(view) = views.iter().find(|view| view.shell == resizing_shell).cloned() {
                seat.begin_resize(cursor, view.clone(), views, event.edges())
            }
        }).unwrap();
    }

    fn move_request(&mut self,
                    compositor: CompositorHandle,
                    _: SurfaceHandle,
                    shell_surface: XdgShellSurfaceHandle,
                    _: &MoveEvent) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut ::Server = compositor.into();
            let ref mut seat = server.seat;
            let ref mut cursor = server.cursor;

            if let Some(ref mut view) = seat.focused {
                let shell: ::Shell = shell_surface.into();
                let action = &mut seat.action;
                if view.shell == shell {
                    with_handles!([(cursor: {cursor})] => {
                        let (lx, ly) = cursor.coords();
                        let Origin { x: shell_x, y: shell_y } = view.origin.get();
                        let (view_sx, view_sy) = (lx - shell_x as f64, ly - shell_y as f64);
                        let start = Origin::new(view_sx as _, view_sy as _);
                        *action = Some(::Action::Moving { start: start });
                    }).unwrap();
                }
            }
        }).unwrap();
    }

    fn on_commit(&mut self,
                 compositor: CompositorHandle,
                 _: SurfaceHandle,
                 shell_surface: XdgShellSurfaceHandle) {
        let configure_serial = {
            with_handles!([(shell_surface: {shell_surface.clone()})] => {
                shell_surface.configure_serial()
            }).unwrap()
        };

        let surface = shell_surface.into();
        with_handles!([(compositor: {compositor})] => {
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut views, .. } = *server;

            if let Some(view) = views.iter().find(|view| view.shell == surface).cloned() {
                if let Some(move_resize) = view.pending_move_resize.get() {
                    if move_resize.serial >= configure_serial {
                        let Origin {mut x, mut y} = view.origin.get();
                        if move_resize.update_x {
                            x  = move_resize.area.origin.x + move_resize.area.size.width -
                                 view.get_size().width;
                        }
                        if move_resize.update_y {
                            y  = move_resize.area.origin.y + move_resize.area.size.height -
                                 view.get_size().height;
                        }

                        view.origin.set(Origin { x, y });

                        if move_resize.serial == configure_serial {
                            view.pending_move_resize.set(None);
                        }
                    }
                }
            }
        }).unwrap();
    }

    fn destroyed(&mut self,
                 compositor: CompositorHandle,
                 shell_surface: XdgShellSurfaceHandle) {
        let surface = shell_surface.into();
        dehandle!(
            @compositor = {compositor};
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut views, .. } = *server;
            if let Some(index) = views.iter().position(|view| view.shell == surface) {
                views.remove(index);
            }
        );
    }
}

pub struct XdgShellManager;

impl XdgShellManagerHandler for XdgShellManager {
    fn new_surface(&mut self,
                   compositor: CompositorHandle,
                   xdg_surface: XdgShellSurfaceHandle)
                   -> (Option<Box<XdgShellHandler>>, Option<Box<SurfaceHandler>>) {
        dehandle!(
            @compositor = {compositor};
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut views, .. } = *server;
            // TODO We should only push it once it's mapped.
            views.push(Rc::new(::View::new(::Shell::Xdg(xdg_surface.clone().into()))))
        );
        (Some(Box::new(::Xdg::new())), None)
    }
}
<commit_msg>way-cooler: xdg-shell add view on map<commit_after>use std::rc::Rc;

use wlroots::{CompositorHandle, Origin, SurfaceHandle, SurfaceHandler,
              XdgShellSurfaceHandle, XdgShellHandler, XdgShellManagerHandler, XdgShellState::*};
use wlroots::xdg_shell_events::{MoveEvent, ResizeEvent};

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct Xdg {
    shell_surface: XdgShellSurfaceHandle
}

impl Xdg {
    pub fn new() -> Self {
        Xdg { .. Xdg::default()}
    }
}

impl XdgShellHandler for Xdg {
    fn resize_request(&mut self,
                      compositor: CompositorHandle,
                      _: SurfaceHandle,
                      shell_surface: XdgShellSurfaceHandle,
                      event: &ResizeEvent) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut seat,
                         ref mut views,
                         ref mut cursor,
                         .. } = *server;
            let resizing_shell = shell_surface.into();

            if let Some(view) = views.iter().find(|view| view.shell == resizing_shell).cloned() {
                seat.begin_resize(cursor, view.clone(), views, event.edges())
            }
        }).unwrap();
    }

    fn move_request(&mut self,
                    compositor: CompositorHandle,
                    _: SurfaceHandle,
                    shell_surface: XdgShellSurfaceHandle,
                    _: &MoveEvent) {
        with_handles!([(compositor: {compositor})] => {
            let server: &mut ::Server = compositor.into();
            let ref mut seat = server.seat;
            let ref mut cursor = server.cursor;

            if let Some(ref mut view) = seat.focused {
                let shell: ::Shell = shell_surface.into();
                let action = &mut seat.action;
                if view.shell == shell {
                    with_handles!([(cursor: {cursor})] => {
                        let (lx, ly) = cursor.coords();
                        let Origin { x: shell_x, y: shell_y } = view.origin.get();
                        let (view_sx, view_sy) = (lx - shell_x as f64, ly - shell_y as f64);
                        let start = Origin::new(view_sx as _, view_sy as _);
                        *action = Some(::Action::Moving { start: start });
                    }).unwrap();
                }
            }
        }).unwrap();
    }

    fn on_commit(&mut self,
                 compositor: CompositorHandle,
                 _: SurfaceHandle,
                 shell_surface: XdgShellSurfaceHandle) {
        let configure_serial = {
            with_handles!([(shell_surface: {shell_surface.clone()})] => {
                shell_surface.configure_serial()
            }).unwrap()
        };

        let surface = shell_surface.into();
        with_handles!([(compositor: {compositor})] => {
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut views, .. } = *server;

            if let Some(view) = views.iter().find(|view| view.shell == surface).cloned() {
                if let Some(move_resize) = view.pending_move_resize.get() {
                    if move_resize.serial >= configure_serial {
                        let Origin {mut x, mut y} = view.origin.get();
                        if move_resize.update_x {
                            x  = move_resize.area.origin.x + move_resize.area.size.width -
                                 view.get_size().width;
                        }
                        if move_resize.update_y {
                            y  = move_resize.area.origin.y + move_resize.area.size.height -
                                 view.get_size().height;
                        }

                        view.origin.set(Origin { x, y });

                        if move_resize.serial == configure_serial {
                            view.pending_move_resize.set(None);
                        }
                    }
                }
            }
        }).unwrap();
    }

    fn map_request(&mut self,
                   compositor: CompositorHandle,
                   _: SurfaceHandle,
                   shell_surface_handle: XdgShellSurfaceHandle) {
        let is_toplevel = with_handles!([(shell_surface: {&shell_surface_handle})] => {
            match shell_surface.state().unwrap() {
                TopLevel(_) => true,
                _ => false
            }
        }).unwrap();
        dehandle!(
            @compositor = {compositor};
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut seat,
                         ref mut views,
                         ref cursor,
                         ref mut xcursor_manager,
                         .. } = *server;
            if is_toplevel {
                let view = Rc::new(::View::new(::Shell::Xdg(shell_surface_handle.into())));
                views.push(view.clone());
                seat.focus_view(view, views);
            };
            @cursor = {cursor};
            seat.update_cursor_position(cursor, xcursor_manager, views, None)
        );
    }

    fn unmap_request(&mut self,
                     compositor: CompositorHandle,
                     _: SurfaceHandle,
                     shell_surface: XdgShellSurfaceHandle) {
        dehandle!(
            @compositor = {compositor};
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut seat,
                           ref mut views,
                           ref cursor,
                           ref mut xcursor_manager,
                           .. } = *server;
            let destroyed_shell = shell_surface.into();
            views.retain(|view| view.shell != destroyed_shell);

            if views.len() > 0 {
                seat.focus_view(views[0].clone(), views);
            } else {
                seat.clear_focus();
            };
            @cursor = {cursor};
            seat.update_cursor_position(cursor, xcursor_manager, views, None)
        );
    }

    fn destroyed(&mut self,
                 compositor: CompositorHandle,
                 shell_surface: XdgShellSurfaceHandle) {
        let surface = shell_surface.into();
        dehandle!(
            @compositor = {compositor};
            let server: &mut ::Server = compositor.into();
            let ::Server { ref mut views, .. } = *server;
            if let Some(index) = views.iter().position(|view| view.shell == surface) {
                views.remove(index);
            }
        );
    }
}

pub struct XdgShellManager;

impl XdgShellManagerHandler for XdgShellManager {
    fn new_surface(&mut self,
                   compositor: CompositorHandle,
                   xdg_surface: XdgShellSurfaceHandle)
                   -> (Option<Box<XdgShellHandler>>, Option<Box<SurfaceHandler>>) {
        (Some(Box::new(::Xdg::new())), None)
    }
}
<|endoftext|>


<commit_before>extern crate parse_collada as collada;

pub use self::collada::{ArrayElement, Collada, GeometricElement, Geometry, Node, PrimitiveElements, VisualScene};

use math::*;
use polygon::geometry::*;
use std::collections::HashSet;

#[derive(Debug, Clone)]
pub enum Error {
    /// Indicates an error that occurred when the MeshBuilder was validating the mesh data. If the
    /// COLLADA document passed parsing this should not occur.
    BuildMeshError(BuildMeshError),

    IncorrectPrimitiveIndicesCount {
        primitive_count: usize,
        stride: usize,
        index_count: usize,
    },

    /// Indicates that there was an input with the "NORMAL" semantic but the associated source
    /// was missing.
    MissingNormalSource,

    /// Indicates that an <input> element specified a <source> element that was missing.
    MissingSourceData,

    /// Indicates that the <source> element with the "POSITION" semantic was missing an
    /// array element.
    MissingPositionData,

    /// Indicates that the <source> element with the "NORMAL" semantic was missing an array element.
    MissingNormalData,

    /// Indicates that a <vertices> element had and <input> element with no "POSITION" semantic.
    ///
    /// NOTE: This error means that the COLLADA document is ill-formed and should have failed
    /// parsing. This indicates that there is a bug in the parse-collada library that should be
    /// fixed.
    MissingPositionSemantic,

    /// Indicates that the <mesh> had no primitive elements.
    MissingPrimitiveElement,

    /// Indicates that one of the primitive elements (e.g. <trianges> et al) were missing a

    /// child element. While this is technically allowed by the standard I'm not really sure what
    /// to do with that? Like how do you define a mesh without indices?
    MissingPrimitiveIndices,

    UnsupportedGeometricElement,
    UnsupportedPrimitiveType,

    /// Indicates that a <source> element's array element was of a type other than <float_array>.
    UnsupportedSourceData,
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub enum VertexSemantic {
    Position,
    Normal,
    TexCoord,
}

/// Load the mesh data from a COLLADA .dae file.
///
/// The data in a COLLADA files is formatted for efficiency, but isn't necessarily
/// organized in a way that is supported by the graphics API. This method reformats the
/// data so that it can be sent straight to the GPU without further manipulation.
///
/// In order to to this, it reorganizes the normals, UVs, and other vertex attributes to
/// be in the same order as the vertex positions.
pub fn geometry_to_mesh(geometry: &Geometry) -> Result<Mesh> {
    match geometry.geometric_element {
        GeometricElement::Mesh(ref mesh) => collada_mesh_to_mesh(mesh),
        _ => Err(Error::UnsupportedGeometricElement),
    }
}

fn collada_mesh_to_mesh(mesh: &collada::Mesh) -> Result<Mesh> {
    // Grab the first primitive element in the mesh.
    // TODO: Handle all primitive elements in the mesh, not just one. This is dependent on polygon
    // being able to support submeshes.
    let primitive = try!(
        mesh.primitive_elements.first()
        .ok_or(Error::MissingPrimitiveElement));

    let triangles = match *primitive {
        PrimitiveElements::Triangles(ref triangles) => triangles,
        _ => return Err(Error::UnsupportedPrimitiveType),
    };

    let primitive_indices = try!(
        triangles.p
        .as_ref()
        .ok_or(Error::MissingPrimitiveIndices));

    // Iterate over the indices, rearranging the normal data to match the position data.
    let stride = triangles.input.len(); // TODO: Do we have a better way of calculating stride? What if one of the sources isn't used? OR USED TWICE!?
    let count  = triangles.count;
    let index_count = primitive_indices.len();
    let vertex_count = count as u32 * 3;

    // Verify we have the right number of indices to build the vertices.
    if count * stride * 3 != index_count {
        return Err(Error::IncorrectPrimitiveIndicesCount {
            primitive_count: count,
            stride: stride,
            index_count: index_count,
        });
    }

    // The indices list is a just a raw list of indices. They are implicity grouped based on the
    // number of inputs for the primitive element (e.g. if there are 3 inputs for the primitive
    // then there are 3 indices per vertex). To handle this we use GroupBy to do a strided
    // iteration over indices list and build each vertex one at a time. Internally the mesh
    // builder handles the details of how to assemble the vertex data in memory.

    // Build a mapping between the vertex indices and the source that they use.
    let mut source_map = Vec::new();
    for (offset, input) in triangles.input.iter().enumerate() {
        // Retrieve the approriate source. If the semantic is "VERTEX" then the offset is
        // associated with all of the sources specified by the <vertex> element.
        let source_ids = match &*input.semantic {
            "VERTEX" => {
                mesh.vertices.input
                .iter()
                .map(|input| (input.semantic.as_ref(), input.source.as_ref()))
                .collect()
            },
            _ => vec![(input.semantic.as_ref(), input.source.as_ref())],
        };

        // For each of the semantics at the current offset, push their info into the source map.
        for (semantic, source_id) in source_ids {
            // Retrieve the <source> element for the input.
            let source = try!(mesh.source
            .iter()
            .find(|source| source.id == source_id)
            .ok_or(Error::MissingSourceData));

            // Retrieve it's array_element, which is technically optional according to the spec but is
            // probably going to be there for the position data.
            let array_element = try!(
                source.array_element
                .as_ref()
                .ok_or(Error::MissingPositionData));

            // Get float data. Raw mesh data should only be float data (the only one that even
            // remotely makes sense is int data, and even then that seems unlikely), so emit an
            // error if the data is in the wrong format.
            let data = match *array_element {
                ArrayElement::Float(ref float_array) => float_array.contents.as_ref(),
                _ => return Err(Error::UnsupportedSourceData),
            };

            source_map.push(IndexMapper {
                offset: offset,
                semantic: semantic,
                data: data,
            });
        }
    }

    let mut mesh_builder = MeshBuilder::new();
    let mut unsupported_semantic_flag = false;
    for vertex_indices in GroupBy::new(primitive_indices, stride).unwrap() { // TODO: This can't fail... right? I'm pretty sure the above checks make sure this is correct.
        // We iterate over each group of indices where each group represents the indices for a
        // single vertex. Within that vertex we need
        let mut vertex = Vertex::new(Point::origin());

        for (offset, index) in vertex_indices.iter().enumerate() {
            for mapper in source_map.iter().filter(|mapper| mapper.offset == offset) {
                match mapper.semantic {
                    "POSITION" => {
                        vertex.position = Point::new(
                            // TODO: Don't assume that the position data is encoded as 3 coordinate
                            // vectors. The <technique_common> element for the source should have
                            // an <accessor> describing how the data is laid out.
                            mapper.data[index * 3 + 0],
                            mapper.data[index * 3 + 1],
                            mapper.data[index * 3 + 2],
                        );
                    },
                    "NORMAL" => {
                        vertex.normal = Some(Vector3::new(
                            mapper.data[index * 3 + 0],
                            mapper.data[index * 3 + 1],
                            mapper.data[index * 3 + 2],
                        ));
                    },
                    "TEXCOORD" => {
                        vertex.texcoord.push(Vector2::new(
                            mapper.data[index * 2 + 0],
                            mapper.data[index * 2 + 1],
                        ));
                    },
                    _ => if !unsupported_semantic_flag {
                        unsupported_semantic_flag = true;
                        println!("WARNING: Unsupported vertex semantic {} in mesh will not be used", mapper.semantic);
                    },
                }
            }
        }

        mesh_builder.add_vertex(vertex);
    }

    let indices: Vec<u32> = (0..vertex_count).collect();

    mesh_builder
    .set_indices(&*indices)
    .build()
    .map_err(|err| Error::BuildMeshError(err))
}

struct IndexMapper<'a> {
    offset:   usize,
    semantic: &'a str,
    data:     &'a [f32],
}

// TODO: Where even should this live? It's generally useful but I'm only using it here right now.
struct GroupBy<'a, T: 'a> {
    next:     *const T,
    end:      *const T,
    stride:   usize,
    _phantom: ::std::marker::PhantomData<&'a T>,
}

impl<'a, T: 'a> GroupBy<'a, T> {
    fn new(slice: &'a [T], stride: usize) -> ::std::result::Result<GroupBy<'a, T>, ()> {
        if slice.len() % stride != 0 {
            return Err(());
        }

        Ok(GroupBy {
            next: slice.as_ptr(),
            end: unsafe { slice.as_ptr().offset(slice.len() as isize) },
            stride: stride,
            _phantom: ::std::marker::PhantomData,
        })
    }
}

impl<'a, T: 'a> Iterator for GroupBy<'a, T> {
    type Item = &'a [T];

    fn next(&mut self) -> Option<&'a [T]> {
        if self.next == self.end {
            return None;
        }

        let next = self.next;
        self.next = unsafe { self.next.offset(self.stride as isize) };

        Some(unsafe {
            ::std::slice::from_raw_parts(next, self.stride)
        })
    }
}
<commit_msg>chore(resource::collda): add warning about meshes with multiple primitive elements<commit_after>extern crate parse_collada as collada;

pub use self::collada::{ArrayElement, Collada, GeometricElement, Geometry, Node, PrimitiveElements, VisualScene};

use math::*;
use polygon::geometry::*;
use std::collections::HashSet;

#[derive(Debug, Clone)]
pub enum Error {
    /// Indicates an error that occurred when the MeshBuilder was validating the mesh data. If the
    /// COLLADA document passed parsing this should not occur.
    BuildMeshError(BuildMeshError),

    IncorrectPrimitiveIndicesCount {
        primitive_count: usize,
        stride: usize,
        index_count: usize,
    },

    /// Indicates that there was an input with the "NORMAL" semantic but the associated source
    /// was missing.
    MissingNormalSource,

    /// Indicates that an <input> element specified a <source> element that was missing.
    MissingSourceData,

    /// Indicates that the <source> element with the "POSITION" semantic was missing an
    /// array element.
    MissingPositionData,

    /// Indicates that the <source> element with the "NORMAL" semantic was missing an array element.
    MissingNormalData,

    /// Indicates that a <vertices> element had and <input> element with no "POSITION" semantic.
    ///
    /// NOTE: This error means that the COLLADA document is ill-formed and should have failed
    /// parsing. This indicates that there is a bug in the parse-collada library that should be
    /// fixed.
    MissingPositionSemantic,

    /// Indicates that the <mesh> had no primitive elements.
    MissingPrimitiveElement,

    /// Indicates that one of the primitive elements (e.g. <trianges> et al) were missing a

    /// child element. While this is technically allowed by the standard I'm not really sure what
    /// to do with that? Like how do you define a mesh without indices?
    MissingPrimitiveIndices,

    UnsupportedGeometricElement,
    UnsupportedPrimitiveType,

    /// Indicates that a <source> element's array element was of a type other than <float_array>.
    UnsupportedSourceData,
}

pub type Result<T> = ::std::result::Result<T, Error>;

pub enum VertexSemantic {
    Position,
    Normal,
    TexCoord,
}

/// Load the mesh data from a COLLADA .dae file.
///
/// The data in a COLLADA files is formatted for efficiency, but isn't necessarily
/// organized in a way that is supported by the graphics API. This method reformats the
/// data so that it can be sent straight to the GPU without further manipulation.
///
/// In order to to this, it reorganizes the normals, UVs, and other vertex attributes to
/// be in the same order as the vertex positions.
pub fn geometry_to_mesh(geometry: &Geometry) -> Result<Mesh> {
    match geometry.geometric_element {
        GeometricElement::Mesh(ref mesh) => collada_mesh_to_mesh(mesh),
        _ => Err(Error::UnsupportedGeometricElement),
    }
}

fn collada_mesh_to_mesh(mesh: &collada::Mesh) -> Result<Mesh> {
    if mesh.primitive_elements.len() > 1 {
        println!("WARNING: Mesh is composed of more than one geometric primitive, which is not currently supported, only part of the mesh will be loaded");
    }

    // Grab the first primitive element in the mesh.
    // TODO: Handle all primitive elements in the mesh, not just one. This is dependent on polygon
    // being able to support submeshes.
    let primitive = try!(
        mesh.primitive_elements.first()
        .ok_or(Error::MissingPrimitiveElement));

    let triangles = match *primitive {
        PrimitiveElements::Triangles(ref triangles) => triangles,
        _ => return Err(Error::UnsupportedPrimitiveType),
    };

    let primitive_indices = try!(
        triangles.p
        .as_ref()
        .ok_or(Error::MissingPrimitiveIndices));

    // Iterate over the indices, rearranging the normal data to match the position data.
    let stride = triangles.input.len(); // TODO: Do we have a better way of calculating stride? What if one of the sources isn't used? OR USED TWICE!?
    let count  = triangles.count;
    let index_count = primitive_indices.len();
    let vertex_count = count as u32 * 3;

    // Verify we have the right number of indices to build the vertices.
    if count * stride * 3 != index_count {
        return Err(Error::IncorrectPrimitiveIndicesCount {
            primitive_count: count,
            stride: stride,
            index_count: index_count,
        });
    }

    // The indices list is a just a raw list of indices. They are implicity grouped based on the
    // number of inputs for the primitive element (e.g. if there are 3 inputs for the primitive
    // then there are 3 indices per vertex). To handle this we use GroupBy to do a strided
    // iteration over indices list and build each vertex one at a time. Internally the mesh
    // builder handles the details of how to assemble the vertex data in memory.

    // Build a mapping between the vertex indices and the source that they use.
    let mut source_map = Vec::new();
    for (offset, input) in triangles.input.iter().enumerate() {
        // Retrieve the approriate source. If the semantic is "VERTEX" then the offset is
        // associated with all of the sources specified by the <vertex> element.
        let source_ids = match &*input.semantic {
            "VERTEX" => {
                mesh.vertices.input
                .iter()
                .map(|input| (input.semantic.as_ref(), input.source.as_ref()))
                .collect()
            },
            _ => vec![(input.semantic.as_ref(), input.source.as_ref())],
        };

        // For each of the semantics at the current offset, push their info into the source map.
        for (semantic, source_id) in source_ids {
            // Retrieve the <source> element for the input.
            let source = try!(mesh.source
            .iter()
            .find(|source| source.id == source_id)
            .ok_or(Error::MissingSourceData));

            // Retrieve it's array_element, which is technically optional according to the spec but is
            // probably going to be there for the position data.
            let array_element = try!(
                source.array_element
                .as_ref()
                .ok_or(Error::MissingPositionData));

            // Get float data. Raw mesh data should only be float data (the only one that even
            // remotely makes sense is int data, and even then that seems unlikely), so emit an
            // error if the data is in the wrong format.
            let data = match *array_element {
                ArrayElement::Float(ref float_array) => float_array.contents.as_ref(),
                _ => return Err(Error::UnsupportedSourceData),
            };

            source_map.push(IndexMapper {
                offset: offset,
                semantic: semantic,
                data: data,
            });
        }
    }

    let mut mesh_builder = MeshBuilder::new();
    let mut unsupported_semantic_flag = false;
    for vertex_indices in GroupBy::new(primitive_indices, stride).unwrap() { // TODO: This can't fail... right? I'm pretty sure the above checks make sure this is correct.
        // We iterate over each group of indices where each group represents the indices for a
        // single vertex. Within that vertex we need
        let mut vertex = Vertex::new(Point::origin());

        for (offset, index) in vertex_indices.iter().enumerate() {
            for mapper in source_map.iter().filter(|mapper| mapper.offset == offset) {
                match mapper.semantic {
                    "POSITION" => {
                        vertex.position = Point::new(
                            // TODO: Don't assume that the position data is encoded as 3 coordinate
                            // vectors. The <technique_common> element for the source should have
                            // an <accessor> describing how the data is laid out.
                            mapper.data[index * 3 + 0],
                            mapper.data[index * 3 + 1],
                            mapper.data[index * 3 + 2],
                        );
                    },
                    "NORMAL" => {
                        vertex.normal = Some(Vector3::new(
                            mapper.data[index * 3 + 0],
                            mapper.data[index * 3 + 1],
                            mapper.data[index * 3 + 2],
                        ));
                    },
                    "TEXCOORD" => {
                        vertex.texcoord.push(Vector2::new(
                            mapper.data[index * 2 + 0],
                            mapper.data[index * 2 + 1],
                        ));
                    },
                    _ => if !unsupported_semantic_flag {
                        unsupported_semantic_flag = true;
                        println!("WARNING: Unsupported vertex semantic {} in mesh will not be used", mapper.semantic);
                    },
                }
            }
        }

        mesh_builder.add_vertex(vertex);
    }

    let indices: Vec<u32> = (0..vertex_count).collect();

    mesh_builder
    .set_indices(&*indices)
    .build()
    .map_err(|err| Error::BuildMeshError(err))
}

struct IndexMapper<'a> {
    offset:   usize,
    semantic: &'a str,
    data:     &'a [f32],
}

// TODO: Where even should this live? It's generally useful but I'm only using it here right now.
struct GroupBy<'a, T: 'a> {
    next:     *const T,
    end:      *const T,
    stride:   usize,
    _phantom: ::std::marker::PhantomData<&'a T>,
}

impl<'a, T: 'a> GroupBy<'a, T> {
    fn new(slice: &'a [T], stride: usize) -> ::std::result::Result<GroupBy<'a, T>, ()> {
        if slice.len() % stride != 0 {
            return Err(());
        }

        Ok(GroupBy {
            next: slice.as_ptr(),
            end: unsafe { slice.as_ptr().offset(slice.len() as isize) },
            stride: stride,
            _phantom: ::std::marker::PhantomData,
        })
    }
}

impl<'a, T: 'a> Iterator for GroupBy<'a, T> {
    type Item = &'a [T];

    fn next(&mut self) -> Option<&'a [T]> {
        if self.next == self.end {
            return None;
        }

        let next = self.next;
        self.next = unsafe { self.next.offset(self.stride as isize) };

        Some(unsafe {
            ::std::slice::from_raw_parts(next, self.stride)
        })
    }
}
<|endoftext|>


<commit_before><commit_msg>define a builtin function type and add a load func<commit_after>use rsh::State;

pub type Builtin = fn(State) -> State;

pub fn load() -> Vec<Builtin> {
    Vec::new()
}
<|endoftext|>


<commit_before>// 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.

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
pub fn supports_aesni() -> bool {
	let mut flags: u32;
    unsafe {
        asm!(
        "
        mov $$1, %eax;
        cpuid;
		mov %ecx, $0;
        "
        : "=r" (flags) // output
        : // input
        : "eax", "ebx", "ecx", "edx" // clobbers
        )
		// No idea why, but on 32-bit targets, the compiler complains
		// about not having enough registers. Adding in this dummy
		// section, however, seems to fix it.
        asm!("")
    }

    return (flags & 0x02000000) != 0;
}

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
#[allow(dead_assignment)]
#[allow(unused_variable)]
unsafe fn fixed_time_eq_asm(mut lhsp: *const u8, mut rhsp: *const u8, mut count: uint) -> bool {
    let mut result: u8 = 0;

    asm!(
        "
            1:

            mov ($1), %cl
            xor ($2), %cl
            or %cl, $0

            inc $1
            inc $2
            dec $3
            jnz 1b
        "
        : "+r" (result), "+r" (lhsp), "+r" (rhsp), "+r" (count) // all input and output
        : // input
        : "cl", "cc" // clobbers
        : "volatile" // flags
    );

    return result == 0;
}

#[cfg(target_arch = "arm")]
#[allow(dead_assignment)]
unsafe fn fixed_time_eq_asm(mut lhsp: *const u8, mut rhsp: *const u8, mut count: uint) -> bool {
    let mut result: u8 = 0;

    asm!(
        "
            1:

            ldrb r4, [$1]
            ldrb r5, [$2]
            eor r4, r4, r5
            orr $0, $0, r4

            add $1, $1, #1
            add $2, $2, #1
            subs $3, $3, #1
            bne 1b
        "
        : "+r" (result), "+r" (lhsp), "+r" (rhsp), "+r" (count) // all input and output
        : // input
        : "r4", "r5", "cc" // clobbers
        : "volatile" // flags
    );

    return result == 0;
}

/// Compare two vectors using a fixed number of operations. If the two vectors are not of equal
/// length, the function returns false immediately.
pub fn fixed_time_eq(lhs: &[u8], rhs: &[u8]) -> bool {
    if lhs.len() != rhs.len() {
        return false;
    }
    if lhs.len() == 0 {
        return true;
    }

    let count = lhs.len();

    unsafe {
        let lhsp = lhs.unsafe_get(0);
        let rhsp = rhs.unsafe_get(0);
        return fixed_time_eq_asm(lhsp, rhsp, count);
    }
}

#[cfg(test)]
mod test {
    use util::fixed_time_eq;

    #[test]
    pub fn test_fixed_time_eq() {
        let a = [0, 1, 2];
        let b = [0, 1, 2];
        let c = [0, 1, 9];
        let d = [9, 1, 2];
        let e = [2, 1, 0];
        let f = [2, 2, 2];
        let g = [0, 0, 0];

        assert!(fixed_time_eq(a, a));
        assert!(fixed_time_eq(a, b));

        assert!(!fixed_time_eq(a, c));
        assert!(!fixed_time_eq(a, d));
        assert!(!fixed_time_eq(a, e));
        assert!(!fixed_time_eq(a, f));
        assert!(!fixed_time_eq(a, g));
    }
}
<commit_msg>I changed this file's source code more rust-like (especially for functions' returned values)<commit_after>// 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.

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
pub fn supports_aesni() -> bool {
	let mut flags: u32;
    unsafe {
        asm!(
        "
        mov $$1, %eax;
        cpuid;
		mov %ecx, $0;
        "
        : "=r" (flags) // output
        : // input
        : "eax", "ebx", "ecx", "edx" // clobbers
        )
		// No idea why, but on 32-bit targets, the compiler complains
		// about not having enough registers. Adding in this dummy
		// section, however, seems to fix it.
        asm!("")
    }

    (flags & 0x02000000) != 0
}

#[cfg(target_arch = "x86")]
#[cfg(target_arch = "x86_64")]
#[allow(dead_assignment)]
#[allow(unused_variable)]
unsafe fn fixed_time_eq_asm(mut lhsp: *const u8, mut rhsp: *const u8, mut count: uint) -> bool {
    let mut result: u8 = 0;

    asm!(
        "
            1:

            mov ($1), %cl
            xor ($2), %cl
            or %cl, $0

            inc $1
            inc $2
            dec $3
            jnz 1b
        "
        : "+r" (result), "+r" (lhsp), "+r" (rhsp), "+r" (count) // all input and output
        : // input
        : "cl", "cc" // clobbers
        : "volatile" // flags
    );

    result == 0
}

#[cfg(target_arch = "arm")]
#[allow(dead_assignment)]
unsafe fn fixed_time_eq_asm(mut lhsp: *const u8, mut rhsp: *const u8, mut count: uint) -> bool {
    let mut result: u8 = 0;

    asm!(
        "
            1:

            ldrb r4, [$1]
            ldrb r5, [$2]
            eor r4, r4, r5
            orr $0, $0, r4

            add $1, $1, #1
            add $2, $2, #1
            subs $3, $3, #1
            bne 1b
        "
        : "+r" (result), "+r" (lhsp), "+r" (rhsp), "+r" (count) // all input and output
        : // input
        : "r4", "r5", "cc" // clobbers
        : "volatile" // flags
    );

    result == 0
}

/// Compare two vectors using a fixed number of operations. If the two vectors are not of equal
/// length, the function returns false immediately.
pub fn fixed_time_eq(lhs: &[u8], rhs: &[u8]) -> bool {
    if lhs.len() != rhs.len() {
        false
    } else if lhs.len() == 0 {
        true
    } else {
        let count = lhs.len();

        unsafe {
            let lhsp = lhs.unsafe_get(0);
            let rhsp = rhs.unsafe_get(0);
            fixed_time_eq_asm(lhsp, rhsp, count)
        }
    }
}

#[cfg(test)]
mod test {
    use util::fixed_time_eq;

    #[test]
    pub fn test_fixed_time_eq() {
        let a = [0, 1, 2];
        let b = [0, 1, 2];
        let c = [0, 1, 9];
        let d = [9, 1, 2];
        let e = [2, 1, 0];
        let f = [2, 2, 2];
        let g = [0, 0, 0];

        assert!(fixed_time_eq(a, a));
        assert!(fixed_time_eq(a, b));

        assert!(!fixed_time_eq(a, c));
        assert!(!fixed_time_eq(a, d));
        assert!(!fixed_time_eq(a, e));
        assert!(!fixed_time_eq(a, f));
        assert!(!fixed_time_eq(a, g));
    }
}
<|endoftext|>