<commit_before>#[macro_use]
extern crate enum_map;

use enum_map::{Enum, EnumMap, IntoIter};

use std::cell::RefCell;
use std::collections::HashSet;
use std::convert::Infallible;
use std::marker::PhantomData;

trait From<T>: Sized {
    fn from(_: T) -> Self {
        unreachable!();
    }
}

impl<T, U> From<T> for U {}

#[derive(Copy, Clone, Debug, Enum, PartialEq)]
enum Example {
    A,
    B,
    C,
}

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}

#[test]
fn test_clone() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(map.clone(), map);
}

#[test]
fn test_debug() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(format!("{:?}", map), "{false: 3, true: 5}");
}

#[test]
fn test_hash() {
    let map = enum_map! { false => 3, true => 5 };
    let mut set = HashSet::new();
    set.insert(map);
    assert!(set.contains(&map));
}

#[test]
fn test_clear() {
    let mut map = enum_map! { false => 1, true => 2 };
    map.clear();
    assert_eq!(map[true], 0);
    assert_eq!(map[false], 0);
}

#[test]
fn discriminants() {
    #[derive(Debug, Enum, PartialEq)]
    enum Discriminants {
        A = 2000,
        B = 3000,
        C = 1000,
    }
    let mut map = EnumMap::default();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}

#[test]
fn extend() {
    let mut map = enum_map! { _ => 0 };
    map.extend(vec![(Example::A, 3)]);
    map.extend(vec![(&Example::B, &4)]);
    assert_eq!(
        map,
        enum_map! { Example::A => 3, Example::B => 4, Example::C => 0 }
    );
}

#[test]
fn huge_enum() {
    #[derive(Enum)]
    enum Example {
        A,
        B,
        C,
        D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
        N,
        O,
        P,
        Q,
        R,
        S,
        T,
        U,
        V,
        W,
        X,
        Y,
        Z,
        Aa,
        Bb,
        Cc,
        Dd,
        Ee,
        Ff,
        Gg,
        Hh,
        Ii,
        Jj,
        Kk,
        Ll,
        Mm,
        Nn,
        Oo,
        Pp,
        Qq,
        Rr,
        Ss,
        Tt,
        Uu,
        Vv,
        Ww,
        Xx,
        Yy,
        Zz,
    }

    let map = enum_map! { _ => 2 };
    assert_eq!(map[Example::Xx], 2);
}

#[test]
fn iterator_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter()
            .len(),
        3
    );
}

#[test]
fn iter_mut_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter_mut()
            .len(),
        3
    );
}

#[test]
fn into_iter_len() {
    assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3);
}

#[test]
fn iterator_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter()
            .next_back(),
        Some((Example::C, &3))
    );
}

#[test]
fn iter_mut_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter_mut()
            .next_back(),
        Some((Example::C, &mut 3))
    );
}

#[test]
fn into_iter() {
    let mut iter = enum_map! { true => 5, false => 7 }.into_iter();
    assert_eq!(iter.next(), Some((false, 7)));
    assert_eq!(iter.next(), Some((true, 5)));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None);
}

#[test]
fn into_iter_u8() {
    assert_eq!(
        enum_map! { i => i }.into_iter().collect::<Vec<_>>(),
        (0..256).map(|x| (x as u8, x as u8)).collect::<Vec<_>>()
    );
}

struct DropReporter<'a> {
    into: &'a RefCell<Vec<usize>>,
    value: usize,
}

impl<'a> Drop for DropReporter<'a> {
    fn drop(&mut self) {
        self.into.borrow_mut().push(self.value);
    }
}

#[test]
fn into_iter_drop() {
    let dropped = RefCell::new(Vec::default());
    let mut a: IntoIter<Example, _> = enum_map! {
        k => DropReporter {
            into: &dropped,
            value: k as usize,
        },
    }
    .into_iter();
    assert_eq!(a.next().unwrap().0, Example::A);
    assert_eq!(*dropped.borrow(), &[0]);
    drop(a);
    assert_eq!(*dropped.borrow(), &[0, 1, 2]);
}

#[test]
fn values_rev_collect() {
    assert_eq!(
        vec![3, 2, 1],
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .values()
            .rev()
            .cloned()
            .collect::<Vec<_>>()
    );
}

#[test]
fn values_len() {
    assert_eq!(enum_map! { false => 0, true => 1 }.values().len(), 2);
}

#[test]
fn values_mut_next_back() {
    let mut map = enum_map! { false => 0, true => 1 };
    assert_eq!(map.values_mut().next_back(), Some(&mut 1));
}
#[test]
fn test_u8() {
    let mut map = enum_map! { b'a' => 4, _ => 0 };
    map[b'c'] = 3;
    assert_eq!(map[b'a'], 4);
    assert_eq!(map[b'b'], 0);
    assert_eq!(map[b'c'], 3);
    assert_eq!(map.iter().next(), Some((0, &0)));
}

#[derive(Enum)]
enum Void {}

#[test]
#[allow(deprecated)]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map! {};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}

#[test]
#[allow(deprecated)]
fn empty_infallible_map() {
    let void: EnumMap<Infallible, Infallible> = enum_map! {};
    assert!(void.is_empty());
}

#[derive(Clone, Copy)]
enum X {
    A(PhantomData<*const ()>),
}

impl<V> Enum<V> for X {
    type Array = [V; 1];

    fn from_usize(arg: usize) -> X {
        assert_eq!(arg, 0);
        X::A(PhantomData)
    }

    fn into_usize(self) -> usize {
        0
    }
}

fn assert_sync_send<T: Sync + Send>(_: T) {}

#[test]
fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() {
    let mut map = enum_map! { X::A(PhantomData) => true };
    assert_sync_send(map);
    assert_sync_send(&map);
    assert_sync_send(&mut map);
    assert_sync_send(map.iter());
    assert_sync_send(map.iter_mut());
    assert_sync_send(map.into_iter());
    assert_eq!(map[X::A(PhantomData)], true);
}

#[test]
fn test_sum() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter()
            .map(|(_, v)| v)
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_sum_mut() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter_mut()
            .map(|(_, &mut v)| -> u32 { v })
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_iter_clone() {
    struct S(u8);
    let map = enum_map! {
        Example::A => S(3),
        Example::B => S(4),
        Example::C => S(1),
    };
    let iter = map.iter();
    assert_eq!(iter.clone().map(|(_, S(v))| v).sum::<u8>(), 8);
    assert_eq!(iter.map(|(_, S(v))| v).sum::<u8>(), 8);
    let values = map.values();
    assert_eq!(values.clone().map(|S(v)| v).sum::<u8>(), 8);
    assert_eq!(values.map(|S(v)| v).sum::<u8>(), 8);
}
<commit_msg>Add a test for question mark in enum map<commit_after>#[macro_use]
extern crate enum_map;

use enum_map::{Enum, EnumMap, IntoIter};

use std::cell::RefCell;
use std::collections::HashSet;
use std::convert::Infallible;
use std::marker::PhantomData;
use std::num::ParseIntError;

trait From<T>: Sized {
    fn from(_: T) -> Self {
        unreachable!();
    }
}

impl<T, U> From<T> for U {}

#[derive(Copy, Clone, Debug, Enum, PartialEq)]
enum Example {
    A,
    B,
    C,
}

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}

#[test]
fn test_clone() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(map.clone(), map);
}

#[test]
fn test_debug() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(format!("{:?}", map), "{false: 3, true: 5}");
}

#[test]
fn test_hash() {
    let map = enum_map! { false => 3, true => 5 };
    let mut set = HashSet::new();
    set.insert(map);
    assert!(set.contains(&map));
}

#[test]
fn test_clear() {
    let mut map = enum_map! { false => 1, true => 2 };
    map.clear();
    assert_eq!(map[true], 0);
    assert_eq!(map[false], 0);
}

#[test]
fn discriminants() {
    #[derive(Debug, Enum, PartialEq)]
    enum Discriminants {
        A = 2000,
        B = 3000,
        C = 1000,
    }
    let mut map = EnumMap::default();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}

#[test]
fn extend() {
    let mut map = enum_map! { _ => 0 };
    map.extend(vec![(Example::A, 3)]);
    map.extend(vec![(&Example::B, &4)]);
    assert_eq!(
        map,
        enum_map! { Example::A => 3, Example::B => 4, Example::C => 0 }
    );
}

#[test]
fn huge_enum() {
    #[derive(Enum)]
    enum Example {
        A,
        B,
        C,
        D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
        N,
        O,
        P,
        Q,
        R,
        S,
        T,
        U,
        V,
        W,
        X,
        Y,
        Z,
        Aa,
        Bb,
        Cc,
        Dd,
        Ee,
        Ff,
        Gg,
        Hh,
        Ii,
        Jj,
        Kk,
        Ll,
        Mm,
        Nn,
        Oo,
        Pp,
        Qq,
        Rr,
        Ss,
        Tt,
        Uu,
        Vv,
        Ww,
        Xx,
        Yy,
        Zz,
    }

    let map = enum_map! { _ => 2 };
    assert_eq!(map[Example::Xx], 2);
}

#[test]
fn iterator_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter()
            .len(),
        3
    );
}

#[test]
fn iter_mut_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter_mut()
            .len(),
        3
    );
}

#[test]
fn into_iter_len() {
    assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3);
}

#[test]
fn iterator_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter()
            .next_back(),
        Some((Example::C, &3))
    );
}

#[test]
fn iter_mut_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter_mut()
            .next_back(),
        Some((Example::C, &mut 3))
    );
}

#[test]
fn into_iter() {
    let mut iter = enum_map! { true => 5, false => 7 }.into_iter();
    assert_eq!(iter.next(), Some((false, 7)));
    assert_eq!(iter.next(), Some((true, 5)));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None);
}

#[test]
fn into_iter_u8() {
    assert_eq!(
        enum_map! { i => i }.into_iter().collect::<Vec<_>>(),
        (0..256).map(|x| (x as u8, x as u8)).collect::<Vec<_>>()
    );
}

struct DropReporter<'a> {
    into: &'a RefCell<Vec<usize>>,
    value: usize,
}

impl<'a> Drop for DropReporter<'a> {
    fn drop(&mut self) {
        self.into.borrow_mut().push(self.value);
    }
}

#[test]
fn into_iter_drop() {
    let dropped = RefCell::new(Vec::default());
    let mut a: IntoIter<Example, _> = enum_map! {
        k => DropReporter {
            into: &dropped,
            value: k as usize,
        },
    }
    .into_iter();
    assert_eq!(a.next().unwrap().0, Example::A);
    assert_eq!(*dropped.borrow(), &[0]);
    drop(a);
    assert_eq!(*dropped.borrow(), &[0, 1, 2]);
}

#[test]
fn values_rev_collect() {
    assert_eq!(
        vec![3, 2, 1],
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .values()
            .rev()
            .cloned()
            .collect::<Vec<_>>()
    );
}

#[test]
fn values_len() {
    assert_eq!(enum_map! { false => 0, true => 1 }.values().len(), 2);
}

#[test]
fn values_mut_next_back() {
    let mut map = enum_map! { false => 0, true => 1 };
    assert_eq!(map.values_mut().next_back(), Some(&mut 1));
}
#[test]
fn test_u8() {
    let mut map = enum_map! { b'a' => 4, _ => 0 };
    map[b'c'] = 3;
    assert_eq!(map[b'a'], 4);
    assert_eq!(map[b'b'], 0);
    assert_eq!(map[b'c'], 3);
    assert_eq!(map.iter().next(), Some((0, &0)));
}

#[derive(Enum)]
enum Void {}

#[test]
#[allow(deprecated)]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map! {};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}

#[test]
#[allow(deprecated)]
fn empty_infallible_map() {
    let void: EnumMap<Infallible, Infallible> = enum_map! {};
    assert!(void.is_empty());
}

#[derive(Clone, Copy)]
enum X {
    A(PhantomData<*const ()>),
}

impl<V> Enum<V> for X {
    type Array = [V; 1];

    fn from_usize(arg: usize) -> X {
        assert_eq!(arg, 0);
        X::A(PhantomData)
    }

    fn into_usize(self) -> usize {
        0
    }
}

fn assert_sync_send<T: Sync + Send>(_: T) {}

#[test]
fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() {
    let mut map = enum_map! { X::A(PhantomData) => true };
    assert_sync_send(map);
    assert_sync_send(&map);
    assert_sync_send(&mut map);
    assert_sync_send(map.iter());
    assert_sync_send(map.iter_mut());
    assert_sync_send(map.into_iter());
    assert_eq!(map[X::A(PhantomData)], true);
}

#[test]
fn test_sum() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter()
            .map(|(_, v)| v)
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_sum_mut() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter_mut()
            .map(|(_, &mut v)| -> u32 { v })
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_iter_clone() {
    struct S(u8);
    let map = enum_map! {
        Example::A => S(3),
        Example::B => S(4),
        Example::C => S(1),
    };
    let iter = map.iter();
    assert_eq!(iter.clone().map(|(_, S(v))| v).sum::<u8>(), 8);
    assert_eq!(iter.map(|(_, S(v))| v).sum::<u8>(), 8);
    let values = map.values();
    assert_eq!(values.clone().map(|S(v)| v).sum::<u8>(), 8);
    assert_eq!(values.map(|S(v)| v).sum::<u8>(), 8);
}

#[test]
fn question_mark() -> Result<(), ParseIntError> {
    let map = enum_map! { false => "2".parse()?, true => "5".parse()? };
    assert_eq!(map, enum_map! { false => 2, true => 5 });
    Ok(())
}
<|endoftext|>


<commit_before>//! A module for common example logic, in an attempt to keep the example
//! source files as concise as possible.
extern crate cgmath;
extern crate glium;

use self::cgmath::*;
use self::glium::*;
use self::glium::uniforms::*;
use self::glium::backend::glutin_backend::GlutinFacade;

/// Shared data used in the examples.
pub struct ExampleData<'a> {

    /// The shader program used to render the shapes.
    pub program: glium::Program,

    /// The draw parameter state used to render the shapes.
    pub draw_params: glium::DrawParameters<'a>
}

/// A type to represent the frame-varying uniforms in the examples. At
/// the moment, this just holds the camera (view * projection) matrix.
pub type FrameUniforms<'a> = UniformsStorage<'a, [[f32; 4]; 4], EmptyUniforms>;

/// Setup the glium display and example data and return them both in a tuple.
pub fn setup<'a>() -> (GlutinFacade, ExampleData<'a>) {

    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(600, 600)
        .with_depth_buffer(16)
        .with_title("Example Viewer".into())
        .build_glium()
        .expect("Failed to build glium display");

    let data = ExampleData {
        program: program!(&display,
            140 => {
                vertex: "
                    #version 140

                    in vec3 position;
                    in vec3 normal;
                    in vec2 texcoord;

                    out vec3 v_normal;
                    out vec2 v_texcoord;

                    uniform mat4 matrix;

                    void main() {
                        gl_Position = matrix * vec4(position, 1.0);
                        v_normal = normal;
                    }
                ",
                fragment: "
                    #version 140

                    in vec3 v_normal;
                    in vec2 v_texcoord;

                    out vec4 fragColor;

                    void main() {
                        fragColor = vec4((v_normal + 1) / 2, 1.0);
                    }
                ",
            }
        ).expect("Failed to compile shader program"),
        draw_params: glium::DrawParameters {
            backface_culling: BackfaceCullingMode::CullClockwise,
            depth: glium::Depth {
                test: glium::draw_parameters::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        }
    };
    return (display, data);
}

/// Process any pending events in the glium display. Return true if the
/// display is still open, or false if the user has closed the display.
pub fn process_events(display: &GlutinFacade) -> bool {
    for event in display.poll_events() {
        match event {
            glium::glutin::Event::Closed => return false,
            _ => continue
        }
    }
    return true;
}

/// Called before rendering a frame. Returns the glium frame and the
/// uniforms that should be used for this frame.
pub fn begin_frame<'a>(display: &GlutinFacade) -> (glium::Frame, FrameUniforms<'a>) {
    let mut frame = display.draw();
    frame.clear_color(0.1, 0.1, 0.1, 1.0);
    frame.clear_depth(1.0);
    let uniforms = build_frame_uniforms(&frame);
    return (frame, uniforms);
}

/// Called after rendering a frame. Swaps the display buffers.
pub fn end_frame(frame: glium::Frame) {
    frame.finish().expect("Failed to draw frame");
}

/// Build the frame-varying uniforms. At the moment, this just
/// consists of the camera (view * projection) matrix.
fn build_frame_uniforms<'a>(frame: &glium::Frame) -> FrameUniforms<'a> {
    let (width, height) = frame.get_dimensions();

    let projection = cgmath::PerspectiveFov::<f32> {
        fovy: cgmath::Rad::<f32>::from(cgmath::Deg::<f32>::new(90.0)),
        aspect: width as f32 / height as f32,
        near: 1.0,
        far: 1000.0
    };

    let view = cgmath::Matrix4::<f32>::from_translation(
        cgmath::Vector3::<f32>::new(0.0, 0.0, -10.0)
    );

    let uniforms = uniform! {
        matrix: (cgmath::Matrix4::<f32>::from(projection) * view).into()
    };

    return uniforms;
}
<commit_msg>Cleaning up cgmath usage in common example module.<commit_after>//! A module for common example logic, in an attempt to keep the example
//! source files as concise as possible.
extern crate cgmath;
extern crate glium;

use self::cgmath::*;
use self::glium::*;
use self::glium::uniforms::*;
use self::glium::backend::glutin_backend::GlutinFacade;

/// Shared data used in the examples.
pub struct ExampleData<'a> {

    /// The shader program used to render the shapes.
    pub program: glium::Program,

    /// The draw parameter state used to render the shapes.
    pub draw_params: glium::DrawParameters<'a>
}

/// A type to represent the frame-varying uniforms in the examples. At
/// the moment, this just holds the camera (view * projection) matrix.
pub type FrameUniforms<'a> = UniformsStorage<'a, [[f32; 4]; 4], EmptyUniforms>;

/// Setup the glium display and example data and return them both in a tuple.
pub fn setup<'a>() -> (GlutinFacade, ExampleData<'a>) {

    let display = glium::glutin::WindowBuilder::new()
        .with_dimensions(600, 600)
        .with_depth_buffer(16)
        .with_title("Example Viewer".into())
        .build_glium()
        .expect("Failed to build glium display");

    let data = ExampleData {
        program: program!(&display,
            140 => {
                vertex: "
                    #version 140

                    in vec3 position;
                    in vec3 normal;
                    in vec2 texcoord;

                    out vec3 v_normal;
                    out vec2 v_texcoord;

                    uniform mat4 matrix;

                    void main() {
                        gl_Position = matrix * vec4(position, 1.0);
                        v_normal = normal;
                    }
                ",
                fragment: "
                    #version 140

                    in vec3 v_normal;
                    in vec2 v_texcoord;

                    out vec4 fragColor;

                    void main() {
                        fragColor = vec4((v_normal + 1) / 2, 1.0);
                    }
                ",
            }
        ).expect("Failed to compile shader program"),
        draw_params: glium::DrawParameters {
            backface_culling: BackfaceCullingMode::CullClockwise,
            depth: glium::Depth {
                test: glium::draw_parameters::DepthTest::IfLess,
                write: true,
                .. Default::default()
            },
            .. Default::default()
        }
    };
    return (display, data);
}

/// Process any pending events in the glium display. Return true if the
/// display is still open, or false if the user has closed the display.
pub fn process_events(display: &GlutinFacade) -> bool {
    for event in display.poll_events() {
        match event {
            glium::glutin::Event::Closed => return false,
            _ => continue
        }
    }
    return true;
}

/// Called before rendering a frame. Returns the glium frame and the
/// uniforms that should be used for this frame.
pub fn begin_frame<'a>(display: &GlutinFacade) -> (glium::Frame, FrameUniforms<'a>) {
    let mut frame = display.draw();
    frame.clear_color(0.1, 0.1, 0.1, 1.0);
    frame.clear_depth(1.0);
    let uniforms = build_frame_uniforms(&frame);
    return (frame, uniforms);
}

/// Called after rendering a frame. Swaps the display buffers.
pub fn end_frame(frame: glium::Frame) {
    frame.finish().expect("Failed to draw frame");
}

/// Build the frame-varying uniforms. At the moment, this just
/// consists of the camera (view * projection) matrix.
fn build_frame_uniforms<'a>(frame: &glium::Frame) -> FrameUniforms<'a> {
    let (width, height) = frame.get_dimensions();

    let projection = PerspectiveFov::<f32> {
        fovy: Rad::<f32>::from(Deg::<f32>::new(90.0)),
        aspect: width as f32 / height as f32,
        near: 1.0,
        far: 1000.0
    };

    let view = Matrix4::<f32>::from_translation(
        Vector3::<f32>::new(0.0, 0.0, -10.0)
    );

    let uniforms = uniform! {
        matrix: (Matrix4::<f32>::from(projection) * view).into()
    };

    return uniforms;
}
<|endoftext|>


<commit_before>extern crate bincode;

extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate definitions;

mod vm;
mod error;

use clap::{App, Arg};
use definitions::program::Program;
use definitions::typedef::*;
use error::*;
use std::fs::File;
use std::io::Read;
use std::sync::mpsc;
use std::thread;
use vm::VM;

fn main() {
    if let Err(ref e) = run() {
        println!("error: {}", e);

        for e in e.iter().skip(1) {
            println!("caused by: {}", e);
        }

        // The backtrace is not always generated. Try to run this example
        // with `RUST_BACKTRACE=1`.
        if let Some(backtrace) = e.backtrace() {
            println!("backtrace: {:?}", backtrace);
        }

        ::std::process::exit(1);
    }
}

fn run() -> VMResult<()> {
    let matches = App::new("bakerVM")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Julian Laubstein <contact@julianlaubstein.de>")
        .about("A virtual machine for building and running retro games")
        .arg(
            Arg::with_name("input")
                .index(1)
                .help("Sets the image file to use. Uses a standard image if nothing is specified.")
        )
        .get_matches();

    let program: Program = if let Some(input) = matches.value_of("input") {
        let mut file = File::open(input).chain_err(|| "unable to open file")?;
        let mut buf: ImageData = ImageData::new();
        file.read_to_end(&mut buf).chain_err(|| "unable to read from file")?;

        bincode::deserialize(&buf[..]).chain_err(|| "unable to decode image file")?
    } else {
        Program::default()
    };

    let display_resolution = program.config.display_resolution.clone();

    let (vm_sender, outer_receiver) = mpsc::channel::<Frame>();
    let (outer_sender, vm_receiver) = mpsc::channel::<Address>();

    thread::spawn(
        move || {
            VM::default().exec(program, vm_sender, vm_receiver).expect("unable to exec program");
        },
    );

    'main: loop {
        if let Ok(frame) = outer_receiver.recv() {
            for y in 0..display_resolution.height {
                for x in 0..display_resolution.width {
                    print!("{:?}", frame[(y * display_resolution.width) + x]);
                }
                println!();
            }
        } else {
            break 'main;
        }
    }

    Ok(())
}
<commit_msg>Added display scale<commit_after>extern crate bincode;

extern crate clap;
#[macro_use]
extern crate error_chain;
extern crate definitions;

mod vm;
mod error;

use clap::{App, Arg};
use definitions::program::Program;
use definitions::typedef::*;
use error::*;
use std::fs::File;
use std::io::Read;
use std::sync::mpsc;
use std::thread;
use vm::VM;

fn main() {
    if let Err(ref e) = run() {
        println!("error: {}", e);

        for e in e.iter().skip(1) {
            println!("caused by: {}", e);
        }

        // The backtrace is not always generated. Try to run this example
        // with `RUST_BACKTRACE=1`.
        if let Some(backtrace) = e.backtrace() {
            println!("backtrace: {:?}", backtrace);
        }

        ::std::process::exit(1);
    }
}

fn run() -> VMResult<()> {
    let matches = App::new("bakerVM")
        .version(env!("CARGO_PKG_VERSION"))
        .author("Julian Laubstein <contact@julianlaubstein.de>")
        .about("A virtual machine for building and running retro games")
        .arg(
            Arg::with_name("input")
                .index(1)
                .help("Sets the image file to use. Uses a standard image if nothing is specified.")
        )
        .get_matches();

    let program: Program = if let Some(input) = matches.value_of("input") {
        let mut file = File::open(input).chain_err(|| "unable to open file")?;
        let mut buf: ImageData = ImageData::new();
        file.read_to_end(&mut buf).chain_err(|| "unable to read from file")?;

        bincode::deserialize(&buf[..]).chain_err(|| "unable to decode image file")?
    } else {
        Program::default()
    };

    let display_resolution = program.config.display_resolution.clone();
    let display_scale = program.config.display_scale.clone();

    let (vm_sender, outer_receiver) = mpsc::channel::<Frame>();
    let (outer_sender, vm_receiver) = mpsc::channel::<Address>();

    thread::spawn(
        move || {
            VM::default().exec(program, vm_sender, vm_receiver).expect("unable to exec program");
        },
    );

    'main: loop {
        if let Ok(frame) = outer_receiver.recv() {
            for y in 0..display_resolution.height {
                for x in 0..display_resolution.width {
                    print!("{:?}", frame[(y * display_resolution.width) + x]);
                }
                println!();
            }
        } else {
            break 'main;
        }
    }

    Ok(())
}
<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

pub fn start(rt: &Runtime) -> i32 {
    unimplemented!()
}

<commit_msg>Add impl of start()<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::str::FromStr;

use libimagrt::runtime::Runtime;
use libimagerror::trace::trace_error;
use libimagentrytimetrack::tag::TimeTrackingTag;
use libimagentrytimetrack::timetrackingstore::TimeTrackStore;
use libimagerror::trace::MapErrTrace;

pub fn start(rt: &Runtime) -> i32 {
    let (_, cmd) = rt.cli().subcommand();
    let cmd = cmd.unwrap(); // checked in main()

    let start = match cmd.value_of("start-time").map(::chrono::naive::NaiveDateTime::from_str) {
        None          => ::chrono::offset::Local::now().naive_local(),
        Some(Ok(ndt)) => ndt,
        Some(Err(e))  => {
            trace_error(&e);
            error!("Cannot continue, not having start time");
            return 1
        },
    };

    cmd.values_of("tags")
        .unwrap() // enforced by clap
        .map(String::from)
        .map(TimeTrackingTag::from)
        .fold(0, |acc, ttt| {
            rt.store()
              .create_timetracking_at(&start, &ttt)
              .map_err_trace()
              .map(|_| acc)
              .unwrap_or(1)
        })
}

<|endoftext|>


<commit_before>use std::cmp::Ordering;
use std::ops::Deref;
use std::path::PathBuf;
use semver::Version;
use super::section::{Kind, Section};

#[derive(Clone)]
#[derive(Debug)]
#[derive(PartialEq)]
pub struct Slice {
    pub name: String,
    pub path: PathBuf,
    pub version: Version,
    pub sections: Vec<Section>,
}

impl Slice {
    /// # Examples
    /// ```
    /// extern crate semver;
    /// extern crate sb;
    /// use std::path::PathBuf;
    /// use semver::Version;
    /// use sb::helper;
    /// use sb::slice::section::{Section, Kind};
    /// use sb::slice::item::Slice;
    ///
    /// fn main() {
    ///     let section = Section { kind: Kind::Os, items: vec!["debian".to_string()] };
    ///     let sections = vec![section];
    ///     let slice = Slice { name: "".to_string(), path: PathBuf::new(),
    ///                         version: helper::zero_version(),
    ///                         sections: sections };
    ///     assert_eq!(slice.section(Kind::Os), vec!["debian"]);
    ///     assert_eq!(slice.section(Kind::Dep), Vec::<&str>::new());
    /// }
    /// ```
    pub fn section(&self, kind: Kind) -> Vec<&str> {
        let mut iter = self.sections.iter();
        let section = iter.find(|section| section.kind == kind);
        if let Some(section) = section {
            let iter = section.items.iter();
            let items = iter.map(|item| item.deref()).collect::<Vec<&str>>();
            items
        } else {
            Vec::new()
        }
    }

    pub fn dependencies(&self) -> Vec<&str> {
        self.section(Kind::Dep)
    }

    pub fn supports_os(&self, os: &str) -> bool {
        self.oses().contains(&os)
    }

    pub fn oses(&self) -> Vec<&str> {
        let section = self.section(Kind::Os);
        assert!(!section.is_empty(), "Slice has no os section. Slice path = {}",
                self.path.display());
        section
    }

    pub fn run_section(&self) -> Vec<&str> {
        let section = self.section(Kind::Run);
        assert!(!section.is_empty(), "Slice has no run section. Slice path = {}",
                self.path.display());
        section
    }
}

impl PartialOrd for Slice {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.version.partial_cmp(&other.version)
    }
}

impl Eq for Slice {
}

impl Ord for Slice {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[test]
fn slice_get_os_list_works() {
    let mut lines: Vec<String> = Vec::new();
    lines.push("OS".to_string());
    lines.push("debian-8.2".to_string());
    lines.push("".to_string());
    lines.push("FROM".to_string());
    lines.push("debian:jessie".to_string());
    let mut sections: Vec<Section> = Vec::new();
    while !lines.is_empty() {
        let (section, remaining_lines) = Section::load_from_lines(lines);
        let section = section.unwrap();
        sections.push(section);
        lines = remaining_lines;
    }
    assert_eq!(sections.len(), 2);
    let slice = Slice {
        name: "Slice".to_string(),
        path: PathBuf::new(),
        version: Version::parse("0.0.0").unwrap(),
        sections: sections,
    };
    let os_list = slice.section(Kind::Os);
    assert_eq!(os_list.len(), 1);
    let os = *os_list.first().unwrap();
    assert_eq!(os, "debian-8.2");
}
<commit_msg>Test moved into module<commit_after>use std::cmp::Ordering;
use std::ops::Deref;
use std::path::PathBuf;
use semver::Version;
use super::section::{Kind, Section};

#[derive(Clone)]
#[derive(Debug)]
#[derive(PartialEq)]
pub struct Slice {
    pub name: String,
    pub path: PathBuf,
    pub version: Version,
    pub sections: Vec<Section>,
}

impl Slice {
    /// # Examples
    /// ```
    /// extern crate semver;
    /// extern crate sb;
    /// use std::path::PathBuf;
    /// use semver::Version;
    /// use sb::helper;
    /// use sb::slice::section::{Section, Kind};
    /// use sb::slice::item::Slice;
    ///
    /// fn main() {
    ///     let section = Section { kind: Kind::Os, items: vec!["debian".to_string()] };
    ///     let sections = vec![section];
    ///     let slice = Slice { name: "".to_string(), path: PathBuf::new(),
    ///                         version: helper::zero_version(),
    ///                         sections: sections };
    ///     assert_eq!(slice.section(Kind::Os), vec!["debian"]);
    ///     assert_eq!(slice.section(Kind::Dep), Vec::<&str>::new());
    /// }
    /// ```
    pub fn section(&self, kind: Kind) -> Vec<&str> {
        let mut iter = self.sections.iter();
        let section = iter.find(|section| section.kind == kind);
        if let Some(section) = section {
            let iter = section.items.iter();
            let items = iter.map(|item| item.deref()).collect::<Vec<&str>>();
            items
        } else {
            Vec::new()
        }
    }

    pub fn dependencies(&self) -> Vec<&str> {
        self.section(Kind::Dep)
    }

    pub fn supports_os(&self, os: &str) -> bool {
        self.oses().contains(&os)
    }

    pub fn oses(&self) -> Vec<&str> {
        let section = self.section(Kind::Os);
        assert!(!section.is_empty(), "Slice has no os section. Slice path = {}",
                self.path.display());
        section
    }

    pub fn run_section(&self) -> Vec<&str> {
        let section = self.section(Kind::Run);
        assert!(!section.is_empty(), "Slice has no run section. Slice path = {}",
                self.path.display());
        section
    }
}

impl PartialOrd for Slice {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.version.partial_cmp(&other.version)
    }
}

impl Eq for Slice {
}

impl Ord for Slice {
    fn cmp(&self, other: &Self) -> Ordering {
        self.partial_cmp(other).unwrap()
    }
}

#[cfg(test)]
mod tests {
    use std::path::PathBuf;
    use helper;
    use slice::item::Slice;
    use slice::section::{Kind, Section};

    #[test]
    fn slice_get_os_list_works() {
        let mut lines: Vec<String> = Vec::new();
        lines.push("OS".to_string());
        lines.push("debian-8.2".to_string());
        lines.push("".to_string());
        lines.push("FROM".to_string());
        lines.push("debian:jessie".to_string());
        let mut sections: Vec<Section> = Vec::new();
        while !lines.is_empty() {
            let (section, remaining_lines) = Section::load_from_lines(lines);
            let section = section.unwrap();
            sections.push(section);
            lines = remaining_lines;
        }
        assert_eq!(sections.len(), 2);
        let slice = Slice {
            name: "Slice".to_string(),
            path: PathBuf::new(),
            version: helper::zero_version(),
            sections: sections,
        };
        let os_list = slice.section(Kind::Os);
        assert_eq!(os_list.len(), 1);
        let os = *os_list.first().unwrap();
        assert_eq!(os, "debian-8.2");
    }
}<|endoftext|>


<commit_before>// copyright 2019 Kaz Wesley

//! Pure Rust ChaCha with SIMD optimizations.
//!
//! Stream-cipher usage:
//! ```
//! extern crate c2_chacha;
//!
//! use c2_chacha::stream_cipher::{NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek};
//! use c2_chacha::{ChaCha20, ChaCha12};
//!
//! let key = b"very secret key-the most secret.";
//! let iv = b"my nonce";
//! let plaintext = b"The quick brown fox jumps over the lazy dog.";
//!
//! let mut buffer = plaintext.to_vec();
//! // create cipher instance
//! let mut cipher = ChaCha20::new_var(key, iv).unwrap();
//! // apply keystream (encrypt)
//! cipher.apply_keystream(&mut buffer);
//! // and decrypt it back
//! cipher.seek(0);
//! cipher.apply_keystream(&mut buffer);
//! // stream ciphers can be used with streaming messages
//! let mut cipher = ChaCha12::new_var(key, iv).unwrap();
//! for chunk in buffer.chunks_mut(3) {
//!     cipher.apply_keystream(chunk);
//! }
//! ```

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(test)]
#[macro_use]
extern crate hex_literal;

#[macro_use]
extern crate ppv_lite86;

pub mod guts;

#[cfg(feature = "rustcrypto_api")]
mod rustcrypto_impl;
#[cfg(feature = "rustcrypto_api")]
pub use self::rustcrypto_impl::{stream_cipher, Ietf, ChaCha8, ChaCha12, ChaCha20, XChaCha8, XChaCha12, XChaCha20};
<commit_msg>c2-chacha: fix no-std build<commit_after>// copyright 2019 Kaz Wesley

//! Pure Rust ChaCha with SIMD optimizations.
//!
//! Stream-cipher usage:
//! ```
//! #[cfg(features = "std")]
//! fn demo() {
//! extern crate c2_chacha;
//!
//! use c2_chacha::stream_cipher::{NewStreamCipher, SyncStreamCipher, SyncStreamCipherSeek};
//! use c2_chacha::{ChaCha20, ChaCha12};
//!
//! let key = b"very secret key-the most secret.";
//! let iv = b"my nonce";
//! let plaintext = b"The quick brown fox jumps over the lazy dog.";
//!
//! let mut buffer = plaintext.to_vec();
//! // create cipher instance
//! let mut cipher = ChaCha20::new_var(key, iv).unwrap();
//! // apply keystream (encrypt)
//! cipher.apply_keystream(&mut buffer);
//! // and decrypt it back
//! cipher.seek(0);
//! cipher.apply_keystream(&mut buffer);
//! // stream ciphers can be used with streaming messages
//! let mut cipher = ChaCha12::new_var(key, iv).unwrap();
//! for chunk in buffer.chunks_mut(3) {
//!     cipher.apply_keystream(chunk);
//! }
//! }
//! ```

#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(test)]
#[macro_use]
extern crate hex_literal;

#[macro_use]
extern crate ppv_lite86;

pub mod guts;

#[cfg(feature = "rustcrypto_api")]
mod rustcrypto_impl;
#[cfg(feature = "rustcrypto_api")]
pub use self::rustcrypto_impl::{stream_cipher, Ietf, ChaCha8, ChaCha12, ChaCha20, XChaCha8, XChaCha12, XChaCha20};
<|endoftext|>


<commit_before>#![feature(no_std)]
#![feature(start)]
#![no_std]

#[macro_use]
extern crate uni;

#[start]
fn main(_: isize, _: *const *const u8) -> isize {
    println!("Hello World");

    0
}
<commit_msg>examples: Hello now uses String<commit_after>#![feature(no_std)]
#![feature(start)]
#![no_std]

#[macro_use]
extern crate uni;

use uni::string::String;

#[start]
fn main(_: isize, _: *const *const u8) -> isize {
    let mut s = String::new();

    s.push_str("Hello");
    s.push_str(" ");
    s.push_str("World");

    println!("{}", s);

    0
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/// The content task (also called the script task) is the main task that owns the DOM in memory,
/// runs JavaScript, and spawns parsing and layout tasks.

use dom::bindings::utils::GlobalStaticData;
use dom::document::Document;
use dom::event::{Event, ResizeEvent, ReflowEvent};
use dom::node::define_bindings;
use dom::window::Window;
use layout::layout_task::{AddStylesheet, BuildData, BuildMsg, Damage, LayoutTask};
use layout::layout_task::{MatchSelectorsDamage, NoDamage, ReflowDamage};
use layout::layout_task;

use core::cell::Cell;
use core::comm::{Port, SharedChan};
use core::either;
use core::io::read_whole_file;
use core::pipes::select2i;
use core::ptr::null;
use core::task::{SingleThreaded, task};
use core::util::replace;
use dom;
use geom::size::Size2D;
use html;
use js::JSVAL_NULL;
use js::global::{global_class, debug_fns};
use js::glue::bindgen::RUST_JSVAL_TO_OBJECT;
use js::jsapi::JSContext;
use js::jsapi::bindgen::{JS_CallFunctionValue, JS_GetContextPrivate};
use js::rust::{Compartment, Cx};
use jsrt = js::rust::rt;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::tree::TreeNodeRef;
use std::net::url::Url;
use url_to_str = std::net::url::to_str;

pub enum ControlMsg {
    ParseMsg(Url),
    ExecuteMsg(Url),
    Timer(~dom::window::TimerData),
    ExitMsg
}

pub enum PingMsg {
    PongMsg
}

pub type ContentTask = SharedChan<ControlMsg>;

pub fn ContentTask(layout_task: LayoutTask,
                   dom_event_port: Port<Event>,
                   dom_event_chan: SharedChan<Event>,
                   resource_task: ResourceTask,
                   img_cache_task: ImageCacheTask)
                -> ContentTask {
    let (control_port, control_chan) = comm::stream();

    let control_chan = SharedChan::new(control_chan);
    let control_chan_copy = control_chan.clone();
    let control_port = Cell(control_port);
    let dom_event_port = Cell(dom_event_port);
    let dom_event_chan = Cell(dom_event_chan);

    // FIXME: rust#6399
    let mut the_task = task();
    the_task.sched_mode(SingleThreaded);
    do the_task.spawn {
        let content = Content(layout_task.clone(),
                              control_port.take(),
                              control_chan_copy.clone(),
                              resource_task.clone(),
                              img_cache_task.clone(),
                              dom_event_port.take(),
                              dom_event_chan.take());
        content.start();
    }

    return control_chan;
}

pub struct Content {
    layout_task: LayoutTask,
    layout_join_port: Option<comm::Port<()>>,

    image_cache_task: ImageCacheTask,
    control_port: comm::Port<ControlMsg>,
    control_chan: comm::SharedChan<ControlMsg>,
    event_port: comm::Port<Event>,
    event_chan: comm::SharedChan<Event>,

    jsrt: jsrt,
    cx: @Cx,
    dom_static: GlobalStaticData,

    document: Option<@mut Document>,
    window:   Option<@mut Window>,
    doc_url: Option<Url>,
    window_size: Size2D<uint>,

    resource_task: ResourceTask,

    compartment: Option<@mut Compartment>,

    // What parts of layout are dirty.
    damage: Damage,
}

pub fn Content(layout_task: LayoutTask,
               control_port: comm::Port<ControlMsg>,
               control_chan: comm::SharedChan<ControlMsg>,
               resource_task: ResourceTask,
               img_cache_task: ImageCacheTask,
               event_port: comm::Port<Event>,
               event_chan: comm::SharedChan<Event>)
            -> @mut Content {
    let jsrt = jsrt();
    let cx = jsrt.cx();

    cx.set_default_options_and_version();
    cx.set_logging_error_reporter();

    let compartment = match cx.new_compartment(global_class) {
          Ok(c) => Some(c),
          Err(()) => None
    };

    let content = @mut Content {
        layout_task: layout_task,
        layout_join_port: None,
        image_cache_task: img_cache_task,
        control_port: control_port,
        control_chan: control_chan,
        event_port: event_port,
        event_chan: event_chan,

        jsrt : jsrt,
        cx : cx,
        dom_static: GlobalStaticData(),

        document    : None,
        window      : None,
        doc_url     : None,
        window_size : Size2D(800u, 600u),

        resource_task : resource_task,
        compartment : compartment,

        damage : MatchSelectorsDamage,
    };

    cx.set_cx_private(ptr::to_unsafe_ptr(&*content) as *());
    unsafe { task::local_data::local_data_set(global_content_key, cast::transmute(content)); }

    content
}

fn global_content_key(_: @Content) {}

pub fn global_content() -> @Content {
    unsafe {
        return task::local_data::local_data_get(global_content_key).get();
    }
}

pub fn task_from_context(cx: *JSContext) -> *mut Content {
    JS_GetContextPrivate(cx) as *mut Content
}

#[unsafe_destructor]
impl Drop for Content {
    fn finalize(&self) {
        unsafe { task::local_data::local_data_pop(global_content_key) };
    }
}

#[allow(non_implicitly_copyable_typarams)]
pub impl Content {
    fn start(&mut self) {
        while self.handle_msg() {
            // Go on ...
        }
    }

    fn handle_msg(&mut self) -> bool {
        match select2i(&mut self.control_port, &mut self.event_port) {
            either::Left(*) => {
                let msg = self.control_port.recv();
                self.handle_control_msg(msg)
            }
            either::Right(*) => {
                let ev = self.event_port.recv();
                self.handle_event(ev)
            }
        }
    }

    fn handle_control_msg(&mut self, control_msg: ControlMsg) -> bool {
        match control_msg {
          ParseMsg(url) => {
            debug!("content: Received url `%s` to parse", url_to_str(&url));

            define_bindings(self.compartment.get());

            // Note: we can parse the next document in parallel
            // with any previous documents.

            let result = html::hubbub_html_parser::parse_html(copy url,
                                                              self.resource_task.clone(),
                                                              self.image_cache_task.clone());

            let root = result.root;

              // Send stylesheets over to layout
              // FIXME: Need these should be streamed to layout as they are parsed
              // and do not need to stop here in the content task
              loop {
                  match result.style_port.recv() {
                      Some(sheet) => {
                          self.layout_task.send(AddStylesheet(sheet));
                      }
                      None => break
                  }
              }

            let js_scripts = result.js_port.recv();
            debug!("js_scripts: %?", js_scripts);

            let window   = Window(self.control_chan.clone(),
                                  self.event_chan.clone(),
                                  ptr::to_mut_unsafe_ptr(&mut *self)); //FIXME store this safely
            let document = Document(root, Some(window));

            do root.with_mut_node |node| {
                node.add_to_doc(document);
            }

            self.damage.add(MatchSelectorsDamage);
            self.relayout(document, &url);

            self.document = Some(document);
            self.window   = Some(window);
            self.doc_url = Some(url);

            let compartment = self.compartment.expect(~"TODO error checking");
            compartment.define_functions(debug_fns);

            do vec::consume(js_scripts) |_i, bytes| {
                self.cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u);
            }

            return true;
          }

          Timer(timerData) => {
            let compartment = self.compartment.expect(~"TODO error checking");
            let thisValue = if timerData.args.len() > 0 {
                RUST_JSVAL_TO_OBJECT(timerData.args[0])
            } else {
                compartment.global_obj.ptr
            };
            let rval = JSVAL_NULL;
            //TODO: support extra args. requires passing a *JSVal argv
            JS_CallFunctionValue(self.cx.ptr, thisValue, timerData.funval,
                                 0, null(), ptr::to_unsafe_ptr(&rval));
            self.relayout(self.document.get(), &(copy self.doc_url).get());
            return true;
          }

          ExecuteMsg(url) => {
            debug!("content: Received url `%s` to execute", url_to_str(&url));

            match read_whole_file(&Path(url.path)) {
              Err(msg) => {
                println(fmt!("Error opening %s: %s", url_to_str(&url), msg));
              }
              Ok(bytes) => {
                let compartment = self.compartment.expect(~"TODO error checking");
                compartment.define_functions(debug_fns);
                self.cx.evaluate_script(compartment.global_obj, bytes, copy url.path, 1u);
              }
            }
            return true;
          }

          ExitMsg => {
            self.layout_task.send(layout_task::ExitMsg);
            return false;
          }
        }
    }

    /**
       Sends a ping to layout and waits for the response (i.e., it has finished any
       pending layout request messages).
    */
    fn join_layout(&mut self) {
        if self.layout_join_port.is_some() {
            let join_port = replace(&mut self.layout_join_port, None);
            match join_port {
                Some(ref join_port) => {
                    if !join_port.peek() {
                        warn!("content: waiting on layout");
                    }
                    join_port.recv();
                    debug!("content: layout joined");
                }
                None => fail!(~"reader forked but no join port?")
            }
        }
    }

    /// This method will wait until the layout task has completed its current action, join the
    /// layout task, and then request a new layout run. It won't wait for the new layout
    /// computation to finish.
    fn relayout(&mut self, document: &Document, doc_url: &Url) {
        debug!("content: performing relayout");

        // Now, join the layout so that they will see the latest changes we have made.
        self.join_layout();

        // Layout will let us know when it's done.
        let (join_port, join_chan) = comm::stream();
        self.layout_join_port = Some(join_port);

        // Send new document and relevant styles to layout.
        let data = ~BuildData {
            node: document.root,
            url: copy *doc_url,
            dom_event_chan: self.event_chan.clone(),
            window_size: self.window_size,
            content_join_chan: join_chan,
            damage: replace(&mut self.damage, NoDamage),
        };

        self.layout_task.send(BuildMsg(data));

        debug!("content: layout forked");
    }

     fn query_layout(&mut self, query: layout_task::LayoutQuery)
                     -> layout_task::LayoutQueryResponse {
         //self.relayout(self.document.get(), &(copy self.doc_url).get());
         self.join_layout();

         let (response_port, response_chan) = comm::stream();
         self.layout_task.send(layout_task::QueryMsg(query, response_chan));
         return response_port.recv()
    }

    /**
       This is the main entry point for receiving and dispatching DOM events.
    */
    // TODO: actually perform DOM event dispatch.
    fn handle_event(&mut self, event: Event) -> bool {
        match event {
          ResizeEvent(new_width, new_height, response_chan) => {
            debug!("content got resize event: %u, %u", new_width, new_height);
            self.damage.add(ReflowDamage);
            self.window_size = Size2D(new_width, new_height);
            match copy self.document {
                None => {
                    // Nothing to do.
                }
                Some(document) => {
                    assert!(self.doc_url.is_some());
                    self.relayout(document, &(copy self.doc_url).get());
                }
            }
            response_chan.send(());
            return true;
          }
          ReflowEvent => {
            debug!("content got reflow event");
            self.damage.add(MatchSelectorsDamage);
            match /*bad*/ copy self.document {
                None => {
                    // Nothing to do.
                }
                Some(document) => {
                    assert!(self.doc_url.is_some());
                    self.relayout(document, &(copy self.doc_url).get());
                }
            }
            return true;
          }
        }
    }
}
<commit_msg>Change core::task::local_data to core::local_data.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/// The content task (also called the script task) is the main task that owns the DOM in memory,
/// runs JavaScript, and spawns parsing and layout tasks.

use dom::bindings::utils::GlobalStaticData;
use dom::document::Document;
use dom::event::{Event, ResizeEvent, ReflowEvent};
use dom::node::define_bindings;
use dom::window::Window;
use layout::layout_task::{AddStylesheet, BuildData, BuildMsg, Damage, LayoutTask};
use layout::layout_task::{MatchSelectorsDamage, NoDamage, ReflowDamage};
use layout::layout_task;

use core::cell::Cell;
use core::comm::{Port, SharedChan};
use core::either;
use core::io::read_whole_file;
use core::pipes::select2i;
use core::ptr::null;
use core::task::{SingleThreaded, task};
use core::util::replace;
use dom;
use geom::size::Size2D;
use html;
use js::JSVAL_NULL;
use js::global::{global_class, debug_fns};
use js::glue::bindgen::RUST_JSVAL_TO_OBJECT;
use js::jsapi::JSContext;
use js::jsapi::bindgen::{JS_CallFunctionValue, JS_GetContextPrivate};
use js::rust::{Compartment, Cx};
use jsrt = js::rust::rt;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::tree::TreeNodeRef;
use std::net::url::Url;
use url_to_str = std::net::url::to_str;

pub enum ControlMsg {
    ParseMsg(Url),
    ExecuteMsg(Url),
    Timer(~dom::window::TimerData),
    ExitMsg
}

pub enum PingMsg {
    PongMsg
}

pub type ContentTask = SharedChan<ControlMsg>;

pub fn ContentTask(layout_task: LayoutTask,
                   dom_event_port: Port<Event>,
                   dom_event_chan: SharedChan<Event>,
                   resource_task: ResourceTask,
                   img_cache_task: ImageCacheTask)
                -> ContentTask {
    let (control_port, control_chan) = comm::stream();

    let control_chan = SharedChan::new(control_chan);
    let control_chan_copy = control_chan.clone();
    let control_port = Cell(control_port);
    let dom_event_port = Cell(dom_event_port);
    let dom_event_chan = Cell(dom_event_chan);

    // FIXME: rust#6399
    let mut the_task = task();
    the_task.sched_mode(SingleThreaded);
    do the_task.spawn {
        let content = Content(layout_task.clone(),
                              control_port.take(),
                              control_chan_copy.clone(),
                              resource_task.clone(),
                              img_cache_task.clone(),
                              dom_event_port.take(),
                              dom_event_chan.take());
        content.start();
    }

    return control_chan;
}

pub struct Content {
    layout_task: LayoutTask,
    layout_join_port: Option<comm::Port<()>>,

    image_cache_task: ImageCacheTask,
    control_port: comm::Port<ControlMsg>,
    control_chan: comm::SharedChan<ControlMsg>,
    event_port: comm::Port<Event>,
    event_chan: comm::SharedChan<Event>,

    jsrt: jsrt,
    cx: @Cx,
    dom_static: GlobalStaticData,

    document: Option<@mut Document>,
    window:   Option<@mut Window>,
    doc_url: Option<Url>,
    window_size: Size2D<uint>,

    resource_task: ResourceTask,

    compartment: Option<@mut Compartment>,

    // What parts of layout are dirty.
    damage: Damage,
}

pub fn Content(layout_task: LayoutTask,
               control_port: comm::Port<ControlMsg>,
               control_chan: comm::SharedChan<ControlMsg>,
               resource_task: ResourceTask,
               img_cache_task: ImageCacheTask,
               event_port: comm::Port<Event>,
               event_chan: comm::SharedChan<Event>)
            -> @mut Content {
    let jsrt = jsrt();
    let cx = jsrt.cx();

    cx.set_default_options_and_version();
    cx.set_logging_error_reporter();

    let compartment = match cx.new_compartment(global_class) {
          Ok(c) => Some(c),
          Err(()) => None
    };

    let content = @mut Content {
        layout_task: layout_task,
        layout_join_port: None,
        image_cache_task: img_cache_task,
        control_port: control_port,
        control_chan: control_chan,
        event_port: event_port,
        event_chan: event_chan,

        jsrt : jsrt,
        cx : cx,
        dom_static: GlobalStaticData(),

        document    : None,
        window      : None,
        doc_url     : None,
        window_size : Size2D(800u, 600u),

        resource_task : resource_task,
        compartment : compartment,

        damage : MatchSelectorsDamage,
    };

    cx.set_cx_private(ptr::to_unsafe_ptr(&*content) as *());
    unsafe { local_data::local_data_set(global_content_key, cast::transmute(content)); }

    content
}

fn global_content_key(_: @Content) {}

pub fn global_content() -> @Content {
    unsafe {
        return local_data::local_data_get(global_content_key).get();
    }
}

pub fn task_from_context(cx: *JSContext) -> *mut Content {
    JS_GetContextPrivate(cx) as *mut Content
}

#[unsafe_destructor]
impl Drop for Content {
    fn finalize(&self) {
        unsafe { local_data::local_data_pop(global_content_key) };
    }
}

#[allow(non_implicitly_copyable_typarams)]
pub impl Content {
    fn start(&mut self) {
        while self.handle_msg() {
            // Go on ...
        }
    }

    fn handle_msg(&mut self) -> bool {
        match select2i(&mut self.control_port, &mut self.event_port) {
            either::Left(*) => {
                let msg = self.control_port.recv();
                self.handle_control_msg(msg)
            }
            either::Right(*) => {
                let ev = self.event_port.recv();
                self.handle_event(ev)
            }
        }
    }

    fn handle_control_msg(&mut self, control_msg: ControlMsg) -> bool {
        match control_msg {
          ParseMsg(url) => {
            debug!("content: Received url `%s` to parse", url_to_str(&url));

            define_bindings(self.compartment.get());

            // Note: we can parse the next document in parallel
            // with any previous documents.

            let result = html::hubbub_html_parser::parse_html(copy url,
                                                              self.resource_task.clone(),
                                                              self.image_cache_task.clone());

            let root = result.root;

              // Send stylesheets over to layout
              // FIXME: Need these should be streamed to layout as they are parsed
              // and do not need to stop here in the content task
              loop {
                  match result.style_port.recv() {
                      Some(sheet) => {
                          self.layout_task.send(AddStylesheet(sheet));
                      }
                      None => break
                  }
              }

            let js_scripts = result.js_port.recv();
            debug!("js_scripts: %?", js_scripts);

            let window   = Window(self.control_chan.clone(),
                                  self.event_chan.clone(),
                                  ptr::to_mut_unsafe_ptr(&mut *self)); //FIXME store this safely
            let document = Document(root, Some(window));

            do root.with_mut_node |node| {
                node.add_to_doc(document);
            }

            self.damage.add(MatchSelectorsDamage);
            self.relayout(document, &url);

            self.document = Some(document);
            self.window   = Some(window);
            self.doc_url = Some(url);

            let compartment = self.compartment.expect(~"TODO error checking");
            compartment.define_functions(debug_fns);

            do vec::consume(js_scripts) |_i, bytes| {
                self.cx.evaluate_script(compartment.global_obj, bytes, ~"???", 1u);
            }

            return true;
          }

          Timer(timerData) => {
            let compartment = self.compartment.expect(~"TODO error checking");
            let thisValue = if timerData.args.len() > 0 {
                RUST_JSVAL_TO_OBJECT(timerData.args[0])
            } else {
                compartment.global_obj.ptr
            };
            let rval = JSVAL_NULL;
            //TODO: support extra args. requires passing a *JSVal argv
            JS_CallFunctionValue(self.cx.ptr, thisValue, timerData.funval,
                                 0, null(), ptr::to_unsafe_ptr(&rval));
            self.relayout(self.document.get(), &(copy self.doc_url).get());
            return true;
          }

          ExecuteMsg(url) => {
            debug!("content: Received url `%s` to execute", url_to_str(&url));

            match read_whole_file(&Path(url.path)) {
              Err(msg) => {
                println(fmt!("Error opening %s: %s", url_to_str(&url), msg));
              }
              Ok(bytes) => {
                let compartment = self.compartment.expect(~"TODO error checking");
                compartment.define_functions(debug_fns);
                self.cx.evaluate_script(compartment.global_obj, bytes, copy url.path, 1u);
              }
            }
            return true;
          }

          ExitMsg => {
            self.layout_task.send(layout_task::ExitMsg);
            return false;
          }
        }
    }

    /**
       Sends a ping to layout and waits for the response (i.e., it has finished any
       pending layout request messages).
    */
    fn join_layout(&mut self) {
        if self.layout_join_port.is_some() {
            let join_port = replace(&mut self.layout_join_port, None);
            match join_port {
                Some(ref join_port) => {
                    if !join_port.peek() {
                        warn!("content: waiting on layout");
                    }
                    join_port.recv();
                    debug!("content: layout joined");
                }
                None => fail!(~"reader forked but no join port?")
            }
        }
    }

    /// This method will wait until the layout task has completed its current action, join the
    /// layout task, and then request a new layout run. It won't wait for the new layout
    /// computation to finish.
    fn relayout(&mut self, document: &Document, doc_url: &Url) {
        debug!("content: performing relayout");

        // Now, join the layout so that they will see the latest changes we have made.
        self.join_layout();

        // Layout will let us know when it's done.
        let (join_port, join_chan) = comm::stream();
        self.layout_join_port = Some(join_port);

        // Send new document and relevant styles to layout.
        let data = ~BuildData {
            node: document.root,
            url: copy *doc_url,
            dom_event_chan: self.event_chan.clone(),
            window_size: self.window_size,
            content_join_chan: join_chan,
            damage: replace(&mut self.damage, NoDamage),
        };

        self.layout_task.send(BuildMsg(data));

        debug!("content: layout forked");
    }

     fn query_layout(&mut self, query: layout_task::LayoutQuery)
                     -> layout_task::LayoutQueryResponse {
         //self.relayout(self.document.get(), &(copy self.doc_url).get());
         self.join_layout();

         let (response_port, response_chan) = comm::stream();
         self.layout_task.send(layout_task::QueryMsg(query, response_chan));
         return response_port.recv()
    }

    /**
       This is the main entry point for receiving and dispatching DOM events.
    */
    // TODO: actually perform DOM event dispatch.
    fn handle_event(&mut self, event: Event) -> bool {
        match event {
          ResizeEvent(new_width, new_height, response_chan) => {
            debug!("content got resize event: %u, %u", new_width, new_height);
            self.damage.add(ReflowDamage);
            self.window_size = Size2D(new_width, new_height);
            match copy self.document {
                None => {
                    // Nothing to do.
                }
                Some(document) => {
                    assert!(self.doc_url.is_some());
                    self.relayout(document, &(copy self.doc_url).get());
                }
            }
            response_chan.send(());
            return true;
          }
          ReflowEvent => {
            debug!("content got reflow event");
            self.damage.add(MatchSelectorsDamage);
            match /*bad*/ copy self.document {
                None => {
                    // Nothing to do.
                }
                Some(document) => {
                    assert!(self.doc_url.is_some());
                    self.relayout(document, &(copy self.doc_url).get());
                }
            }
            return true;
          }
        }
    }
}
<|endoftext|>


<commit_before>extern mod harfbuzz;

use font::Font;
use font_cache::FontCache;

use au = gfx::geometry;
use au::Au;
use geom::point::Point2D;
use glyph::{GlyphStore, GlyphIndex, GlyphData};
use libc::types::common::c99::int32_t;
use libc::{c_uint, c_int, c_void, c_char};
use ptr::{null, to_unsafe_ptr, offset};
use std::arc;
use text_run::TextRun;
use util::*;

use harfbuzz::{HB_MEMORY_MODE_READONLY,
                  HB_DIRECTION_LTR};
use harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_font_funcs_t, hb_buffer_t,
                  hb_codepoint_t, hb_bool_t, hb_glyph_position_t,
		  hb_glyph_info_t, hb_var_int_t, hb_position_t};
use harfbuzz::bindgen::{hb_blob_create, hb_blob_destroy,
                           hb_face_create, hb_face_destroy,
                           hb_font_create, hb_font_destroy,
                           hb_buffer_create, hb_buffer_destroy,
                           hb_buffer_add_utf8, hb_shape,
                           hb_buffer_get_glyph_infos,
                           hb_buffer_get_glyph_positions,
                           hb_font_set_ppem, hb_font_set_scale,
                           hb_buffer_set_direction,
                           hb_font_funcs_create, hb_font_funcs_destroy,
                           hb_font_set_funcs,
                           hb_font_funcs_set_glyph_h_advance_func,
                           hb_font_funcs_set_glyph_func,
                           hb_font_funcs_set_glyph_h_kerning_func};

fn float_to_fixed_hb(f: float) -> i32 {
    util::float_to_fixed(16, f)
}

fn fixed_to_float_hb(i: hb_position_t) -> float {
    util::fixed_to_float(16, i)
}

fn fixed_to_rounded_int_hb(f: hb_position_t) -> int {
    util::fixed_to_rounded_int(16, f)
}

pub struct HarfbuzzShaper {
    dummy: int
}

pub impl HarfbuzzShaper {
    static pub fn new() -> HarfbuzzShaper {
        HarfbuzzShaper { dummy: 42 }
    }

    /**
    Calculate the layout metrics associated with a some given text
    when rendered in a specific font.
    */
    pub fn shape_textrun(run: &TextRun) {
        debug!("shaping text '%s'", run.text);

        // TODO: harfbuzz fonts and faces should be cached on the Font object.
        // TODO: font tables should be stored in Font object and cached by FontCache (Issue #92)
        let face_blob: *hb_blob_t = vec::as_imm_buf(*(run.font).fontbuf, |buf: *u8, len: uint| {
            hb_blob_create(buf as *c_char,
                           len as c_uint,
                           HB_MEMORY_MODE_READONLY,
                           null(),
                           null())
        });

        let hb_face: *hb_face_t = hb_face_create(face_blob, 0 as c_uint);
        let hb_font: *hb_font_t = hb_font_create(hb_face);

        // TODO: set font size here, based on Font's size
        // Set points-per-em. if zero, performs no hinting in that direction.
        hb_font_set_ppem(hb_font, 21 as c_uint, 21 as c_uint);
        // Set scaling. Note that this takes 16.16 fixed point.
        hb_font_set_scale(hb_font, float_to_fixed_hb(21f) as c_int, float_to_fixed_hb(21f) as c_int);

        let funcs: *hb_font_funcs_t = hb_font_funcs_create();
        hb_font_funcs_set_glyph_func(funcs, glyph_func, null(), null());
        hb_font_funcs_set_glyph_h_advance_func(funcs, glyph_h_advance_func, null(), null());

        unsafe {
            let font_data: *c_void = core::ptr::addr_of(run.font) as *c_void;
            hb_font_set_funcs(hb_font, funcs, font_data, null());
        };

        let hb_buffer: *hb_buffer_t = hb_buffer_create();
        hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);

        // Using as_buf because it never does a copy - we don't need the trailing null
        str::as_buf(run.text, |ctext: *u8, _l: uint| {
            hb_buffer_add_utf8(hb_buffer,
                               ctext as *c_char,
                               run.text.len() as c_int,
                               0 as c_uint,
                               run.text.len() as c_int);
        });

        hb_shape(hb_font, hb_buffer, null(), 0 as c_uint);

        let info_buf_len = 0 as c_uint;
        let info_buf = hb_buffer_get_glyph_infos(hb_buffer, to_unsafe_ptr(&info_buf_len));
        assert info_buf.is_not_null();
        let pos_buf_len = 0 as c_uint;
        let pos_buf = hb_buffer_get_glyph_positions(hb_buffer, to_unsafe_ptr(&pos_buf_len));
        assert pos_buf.is_not_null();

        assert info_buf_len == pos_buf_len;

        for uint::range(0u, info_buf_len as uint) |i| { unsafe {
            let hb_info: hb_glyph_info_t = *offset(info_buf, i);
            let hb_pos: hb_glyph_position_t = *offset(pos_buf, i);
            let codepoint = hb_info.codepoint as GlyphIndex;
            let advance: Au = au::from_frac_px(fixed_to_float_hb(hb_pos.x_advance));
            let offset = match (hb_pos.x_offset, hb_pos.y_offset) {
                (0, 0) => None,
                (x, y) => Some(Point2D(au::from_frac_px(fixed_to_float_hb(x)),
                                       au::from_frac_px(fixed_to_float_hb(y))))
            };
            // TODO: convert pos.y_advance into offset adjustment
            // TODO: handle multiple glyphs per char, ligatures, etc.
            // See Issue #
            debug!("glyph %?: index %?, advance %?, offset %?",
                   i, codepoint, advance, offset);

            let data = GlyphData(codepoint, advance, offset, false, false, false);
            run.glyphs.add_glyph_for_index(i, &data);
        } /* unsafe */ }

        hb_buffer_destroy(hb_buffer);
        hb_font_funcs_destroy(funcs);
        hb_font_destroy(hb_font);
        hb_face_destroy(hb_face);
        hb_blob_destroy(face_blob);
    }
}

extern fn glyph_func(_font: *hb_font_t,
                     font_data: *c_void,
                     unicode: hb_codepoint_t,
                     _variant_selector: hb_codepoint_t,
                     glyph: *mut hb_codepoint_t,
                     _user_data: *c_void) -> hb_bool_t unsafe {

    let font: *Font = font_data as *Font;
    assert font.is_not_null();
    return match (*font).glyph_index(unicode as char) {
        Some(g) => { *glyph = g as hb_codepoint_t; true },
        None => false
    } as hb_bool_t;
}

extern fn glyph_h_advance_func(_font: *hb_font_t,
                               font_data: *c_void,
                               glyph: hb_codepoint_t,
                               _user_data: *c_void) -> hb_position_t unsafe {
    let font: *Font = font_data as *Font;
    assert font.is_not_null();

    let advance = (*font).glyph_h_advance(glyph as GlyphIndex);
    float_to_fixed_hb(advance)
}
<commit_msg>Shaper now uses actual font point size. Closes #162.<commit_after>extern mod harfbuzz;

use font::Font;
use font_cache::FontCache;

use au = gfx::geometry;
use au::Au;
use geom::point::Point2D;
use glyph::{GlyphStore, GlyphIndex, GlyphData};
use libc::types::common::c99::int32_t;
use libc::{c_uint, c_int, c_void, c_char};
use ptr::{null, to_unsafe_ptr, offset};
use std::arc;
use text_run::TextRun;
use util::*;

use harfbuzz::{HB_MEMORY_MODE_READONLY,
                  HB_DIRECTION_LTR};
use harfbuzz::{hb_blob_t, hb_face_t, hb_font_t, hb_font_funcs_t, hb_buffer_t,
                  hb_codepoint_t, hb_bool_t, hb_glyph_position_t,
		  hb_glyph_info_t, hb_var_int_t, hb_position_t};
use harfbuzz::bindgen::{hb_blob_create, hb_blob_destroy,
                           hb_face_create, hb_face_destroy,
                           hb_font_create, hb_font_destroy,
                           hb_buffer_create, hb_buffer_destroy,
                           hb_buffer_add_utf8, hb_shape,
                           hb_buffer_get_glyph_infos,
                           hb_buffer_get_glyph_positions,
                           hb_font_set_ppem, hb_font_set_scale,
                           hb_buffer_set_direction,
                           hb_font_funcs_create, hb_font_funcs_destroy,
                           hb_font_set_funcs,
                           hb_font_funcs_set_glyph_h_advance_func,
                           hb_font_funcs_set_glyph_func,
                           hb_font_funcs_set_glyph_h_kerning_func};

fn float_to_fixed_hb(f: float) -> i32 {
    util::float_to_fixed(16, f)
}

fn fixed_to_float_hb(i: hb_position_t) -> float {
    util::fixed_to_float(16, i)
}

fn fixed_to_rounded_int_hb(f: hb_position_t) -> int {
    util::fixed_to_rounded_int(16, f)
}

pub struct HarfbuzzShaper {
    dummy: int
}

pub impl HarfbuzzShaper {
    static pub fn new() -> HarfbuzzShaper {
        HarfbuzzShaper { dummy: 42 }
    }

    /**
    Calculate the layout metrics associated with a some given text
    when rendered in a specific font.
    */
    pub fn shape_textrun(run: &TextRun) {
        debug!("shaping text '%s'", run.text);

        // TODO(Issue #94): harfbuzz fonts and faces should be cached on the
        // Shaper object, which is owned by the Font instance.
        // TODO(Issue #92): font tables should be stored in Font object and cached per-task
        let face_blob: *hb_blob_t = vec::as_imm_buf(*(run.font).fontbuf, |buf: *u8, len: uint| {
            hb_blob_create(buf as *c_char,
                           len as c_uint,
                           HB_MEMORY_MODE_READONLY,
                           null(),
                           null())
        });

        let hb_face: *hb_face_t = hb_face_create(face_blob, 0 as c_uint);
        let hb_font: *hb_font_t = hb_font_create(hb_face);

        // Set points-per-em. if zero, performs no hinting in that direction.
        let pt_size = run.font.style.pt_size;
        hb_font_set_ppem(hb_font, pt_size as c_uint, pt_size as c_uint);
        // Set scaling. Note that this takes 16.16 fixed point.
        hb_font_set_scale(hb_font, float_to_fixed_hb(pt_size) as c_int, float_to_fixed_hb(pt_size) as c_int);

        let funcs: *hb_font_funcs_t = hb_font_funcs_create();
        hb_font_funcs_set_glyph_func(funcs, glyph_func, null(), null());
        hb_font_funcs_set_glyph_h_advance_func(funcs, glyph_h_advance_func, null(), null());

        unsafe {
            let font_data: *c_void = core::ptr::addr_of(run.font) as *c_void;
            hb_font_set_funcs(hb_font, funcs, font_data, null());
        };

        let hb_buffer: *hb_buffer_t = hb_buffer_create();
        hb_buffer_set_direction(hb_buffer, HB_DIRECTION_LTR);

        // Using as_buf because it never does a copy - we don't need the trailing null
        str::as_buf(run.text, |ctext: *u8, _l: uint| {
            hb_buffer_add_utf8(hb_buffer,
                               ctext as *c_char,
                               run.text.len() as c_int,
                               0 as c_uint,
                               run.text.len() as c_int);
        });

        hb_shape(hb_font, hb_buffer, null(), 0 as c_uint);

        let info_buf_len = 0 as c_uint;
        let info_buf = hb_buffer_get_glyph_infos(hb_buffer, to_unsafe_ptr(&info_buf_len));
        assert info_buf.is_not_null();
        let pos_buf_len = 0 as c_uint;
        let pos_buf = hb_buffer_get_glyph_positions(hb_buffer, to_unsafe_ptr(&pos_buf_len));
        assert pos_buf.is_not_null();

        assert info_buf_len == pos_buf_len;

        for uint::range(0u, info_buf_len as uint) |i| { unsafe {
            let hb_info: hb_glyph_info_t = *offset(info_buf, i);
            let hb_pos: hb_glyph_position_t = *offset(pos_buf, i);
            let codepoint = hb_info.codepoint as GlyphIndex;
            let advance: Au = au::from_frac_px(fixed_to_float_hb(hb_pos.x_advance));
            let offset = match (hb_pos.x_offset, hb_pos.y_offset) {
                (0, 0) => None,
                (x, y) => Some(Point2D(au::from_frac_px(fixed_to_float_hb(x)),
                                       au::from_frac_px(fixed_to_float_hb(y))))
            };
            // TODO: convert pos.y_advance into offset adjustment
            // TODO: handle multiple glyphs per char, ligatures, etc.
            // See Issue #
            debug!("glyph %?: index %?, advance %?, offset %?",
                   i, codepoint, advance, offset);

            let data = GlyphData(codepoint, advance, offset, false, false, false);
            run.glyphs.add_glyph_for_index(i, &data);
        } /* unsafe */ }

        hb_buffer_destroy(hb_buffer);
        hb_font_funcs_destroy(funcs);
        hb_font_destroy(hb_font);
        hb_face_destroy(hb_face);
        hb_blob_destroy(face_blob);
    }
}

extern fn glyph_func(_font: *hb_font_t,
                     font_data: *c_void,
                     unicode: hb_codepoint_t,
                     _variant_selector: hb_codepoint_t,
                     glyph: *mut hb_codepoint_t,
                     _user_data: *c_void) -> hb_bool_t unsafe {

    let font: *Font = font_data as *Font;
    assert font.is_not_null();
    return match (*font).glyph_index(unicode as char) {
        Some(g) => { *glyph = g as hb_codepoint_t; true },
        None => false
    } as hb_bool_t;
}

extern fn glyph_h_advance_func(_font: *hb_font_t,
                               font_data: *c_void,
                               glyph: hb_codepoint_t,
                               _user_data: *c_void) -> hb_position_t unsafe {
    let font: *Font = font_data as *Font;
    assert font.is_not_null();

    let advance = (*font).glyph_h_advance(glyph as GlyphIndex);
    float_to_fixed_hb(advance)
}
<|endoftext|>


<commit_before>//! `cpuid` intrinsics

#![cfg_attr(feature = "cargo-clippy", allow(stutter))]

use mem;

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Result of the `cpuid` instruction.
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub struct CpuidResult {
    /// EAX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub eax: u32,
    /// EBX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub ebx: u32,
    /// ECX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub ecx: u32,
    /// EDX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub edx: u32,
}

/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
/// and
/// `sub_leaf` (`ECX`).
///
/// The highest-supported leaf value is returned by the first tuple argument of
/// [`__get_cpuid_max(0)`](fn.__get_cpuid_max.html). For leaves containung
/// sub-leaves, the second tuple argument returns the highest-supported
/// sub-leaf
/// value.
///
/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
/// information using the `EAX` and `ECX` registers, and the interpretation of
/// the results returned in `EAX`, `EBX`, `ECX`, and `EDX`.
///
/// The references are:
/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2:
///   Instruction Set Reference, A-Z][intel64_ref].
/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and
///   System Instructions][amd64_ref].
///
/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID
/// [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
    let mut r = mem::uninitialized::<CpuidResult>();
    if cfg!(target_arch = "x86") {
        asm!("cpuid"
             : "={eax}"(r.eax), "={ebx}"(r.ebx), "={ecx}"(r.ecx), "={edx}"(r.edx)
             : "{eax}"(leaf), "{ecx}"(sub_leaf)
             : :);
    } else {
        // x86-64 uses %rbx as the base register, so preserve it.
        asm!("cpuid\n"
             : "={eax}"(r.eax), "={ebx}"(r.ebx), "={ecx}"(r.ecx), "={edx}"(r.edx)
             : "{eax}"(leaf), "{ecx}"(sub_leaf)
             : "rbx" :);
    }
    r
}

/// See [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
    __cpuid_count(leaf, 0)
}

/// Does the host support the `cpuid` instruction?
#[inline]
pub fn has_cpuid() -> bool {
    #[cfg(target_arch = "x86_64")]
    {
        true
    }
    #[cfg(target_arch = "x86")]
    {
        unsafe {
            // On `x86` the `cpuid` instruction is not always available.
            // This follows the approach indicated in:
            // http://wiki.osdev.org/CPUID#Checking_CPUID_availability
            // https://software.intel.com/en-us/articles/using-cpuid-to-detect-the-presence-of-sse-41-and-sse-42-instruction-sets/
            // which detects whether `cpuid` is available by checking whether the 21st bit of the EFLAGS register is modifiable or not.
            // If it is, then `cpuid` is available.
            let eax: i32;
            asm!(r#"
                # Save ecx (__fastcall needs it preserved) and save a
                # copy of the original eflags that we will restore later:
                push %ecx
                pushfd
                # Copy eflags to ecx and eax:
                pushfd
                pop %eax
                mov %ecx, %eax
                # Flip 21st bit and write back to eflags register:
                xor %eax, 0x200000
                push %eax
                popfd
                # Read eflags register again:
                pushfd
                pop %eax
                # If cpuid is available, the bit will still be flipped
                # and it will be the only bit modified.
                #
                # xor with the original eflags should produce a 1 in
                # the 21st bit in this case, and zeros for all other bits:
                xor %eax, %ecx
                # So if the value of the 21st bit is 1, cpuid is available,
                # and if it is zero, it isn't because we didn't manage to
                # modify it:
                shrd %eax, 21
                # Restore original eflags and ecx:
                popfd
                pop %ecx
            "#
                 : "={eax}"(eax)  // output operands
                 : // input operands
                 : "memory", "ecx" // clobbers all memory
                 : "volatile"  // has side-effects
            );
            debug_assert!(eax == 0 || eax == 1);
            eax == 1
        }
    }
}

/// Returns the highest-supported `leaf` (`EAX`) and sub-leaf (`ECX`) `cpuid`
/// values.
///
/// If `cpuid` is supported, and `leaf` is zero, then the first tuple argument
/// contains the highest `leaf` value that `cpuid` supports. For `leaf`s
/// containing sub-leafs, the second tuple argument contains the
/// highest-supported sub-leaf value.
///
/// See also [`__cpuid`](fn.__cpuid.html) and
/// [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
    let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
    (eax, ebx)
}

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

    #[test]
    fn test_always_has_cpuid() {
        // all currently-tested targets have the instruction
        // FIXME: add targets without `cpuid` to CI
        assert!(cpuid::has_cpuid());
    }

    #[test]
    fn test_has_cpuid_idempotent() {
        assert_eq!(cpuid::has_cpuid(), cpuid::has_cpuid());
    }
}
<commit_msg>no need to save/restore ecx in the inline assembly because its already clobbered<commit_after>//! `cpuid` intrinsics

#![cfg_attr(feature = "cargo-clippy", allow(stutter))]

use mem;

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Result of the `cpuid` instruction.
#[derive(Copy, Clone, Eq, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "cargo-clippy", allow(stutter))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub struct CpuidResult {
    /// EAX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub eax: u32,
    /// EBX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub ebx: u32,
    /// ECX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub ecx: u32,
    /// EDX register.
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub edx: u32,
}

/// Returns the result of the `cpuid` instruction for a given `leaf` (`EAX`)
/// and
/// `sub_leaf` (`ECX`).
///
/// The highest-supported leaf value is returned by the first tuple argument of
/// [`__get_cpuid_max(0)`](fn.__get_cpuid_max.html). For leaves containung
/// sub-leaves, the second tuple argument returns the highest-supported
/// sub-leaf
/// value.
///
/// The [CPUID Wikipedia page][wiki_cpuid] contains how to query which
/// information using the `EAX` and `ECX` registers, and the interpretation of
/// the results returned in `EAX`, `EBX`, `ECX`, and `EDX`.
///
/// The references are:
/// - [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2:
///   Instruction Set Reference, A-Z][intel64_ref].
/// - [AMD64 Architecture Programmer's Manual, Volume 3: General-Purpose and
///   System Instructions][amd64_ref].
///
/// [wiki_cpuid]: https://en.wikipedia.org/wiki/CPUID
/// [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
/// [amd64_ref]: http://support.amd.com/TechDocs/24594.pdf
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid_count(leaf: u32, sub_leaf: u32) -> CpuidResult {
    let mut r = mem::uninitialized::<CpuidResult>();
    if cfg!(target_arch = "x86") {
        asm!("cpuid"
             : "={eax}"(r.eax), "={ebx}"(r.ebx), "={ecx}"(r.ecx), "={edx}"(r.edx)
             : "{eax}"(leaf), "{ecx}"(sub_leaf)
             : :);
    } else {
        // x86-64 uses %rbx as the base register, so preserve it.
        asm!("cpuid\n"
             : "={eax}"(r.eax), "={ebx}"(r.ebx), "={ecx}"(r.ecx), "={edx}"(r.edx)
             : "{eax}"(leaf), "{ecx}"(sub_leaf)
             : "rbx" :);
    }
    r
}

/// See [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[cfg_attr(test, assert_instr(cpuid))]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __cpuid(leaf: u32) -> CpuidResult {
    __cpuid_count(leaf, 0)
}

/// Does the host support the `cpuid` instruction?
#[inline]
pub fn has_cpuid() -> bool {
    #[cfg(target_arch = "x86_64")]
    {
        true
    }
    #[cfg(target_arch = "x86")]
    {
        unsafe {
            // On `x86` the `cpuid` instruction is not always available.
            // This follows the approach indicated in:
            // http://wiki.osdev.org/CPUID#Checking_CPUID_availability
            // https://software.intel.com/en-us/articles/using-cpuid-to-detect-the-presence-of-sse-41-and-sse-42-instruction-sets/
            // which detects whether `cpuid` is available by checking whether the 21st bit of the EFLAGS register is modifiable or not.
            // If it is, then `cpuid` is available.
            let eax: i32;
            asm!(r#"
                # Save a copy of the original eflags that we will restore later:
                pushfd
                # Copy eflags to ecx and eax:
                pushfd
                pop %eax
                mov %ecx, %eax
                # Flip 21st bit and write back to eflags register:
                xor %eax, 0x200000
                push %eax
                popfd
                # Read eflags register again:
                pushfd
                pop %eax
                # If cpuid is available, the bit will still be flipped
                # and it will be the only bit modified.
                #
                # xor with the original eflags should produce a 1 in
                # the 21st bit in this case, and zeros for all other bits:
                xor %eax, %ecx
                # So if the value of the 21st bit is 1, cpuid is available,
                # and if it is zero, it isn't because we didn't manage to
                # modify it:
                shrd %eax, 21
                # Restore original eflags
                popfd
            "#
                 : "={eax}"(eax)  // output operands
                 : // input operands
                 : "memory", "ecx" // clobbers all memory and ecx
                 : "volatile"  // has side-effects
            );
            debug_assert!(eax == 0 || eax == 1);
            eax == 1
        }
    }
}

/// Returns the highest-supported `leaf` (`EAX`) and sub-leaf (`ECX`) `cpuid`
/// values.
///
/// If `cpuid` is supported, and `leaf` is zero, then the first tuple argument
/// contains the highest `leaf` value that `cpuid` supports. For `leaf`s
/// containing sub-leafs, the second tuple argument contains the
/// highest-supported sub-leaf value.
///
/// See also [`__cpuid`](fn.__cpuid.html) and
/// [`__cpuid_count`](fn.__cpuid_count.html).
#[inline]
#[stable(feature = "simd_x86", since = "1.27.0")]
pub unsafe fn __get_cpuid_max(leaf: u32) -> (u32, u32) {
    let CpuidResult { eax, ebx, .. } = __cpuid(leaf);
    (eax, ebx)
}

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

    #[test]
    fn test_always_has_cpuid() {
        // all currently-tested targets have the instruction
        // FIXME: add targets without `cpuid` to CI
        assert!(cpuid::has_cpuid());
    }

    #[test]
    fn test_has_cpuid_idempotent() {
        assert_eq!(cpuid::has_cpuid(), cpuid::has_cpuid());
    }
}
<|endoftext|>