<commit_before>use super::{super::utils::JoinWithCommasAndAnd, utils::id_to_end_of_line, Hint, HintKind};
use crate::{
    compiler::{
        ast_to_hir::AstToHir,
        hir::{Expression, HirDb, Id, Lambda},
    },
    database::Database,
    fuzzer::{Fuzzer, Status},
    input::Input,
    vm::{tracer::TraceEntry, value::Closure},
};
use itertools::Itertools;
use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap;

#[derive(Default)]
pub struct FuzzerManager {
    fuzzable_closures: HashMap<Input, HashMap<Id, Closure>>,
    fuzzers: HashMap<Closure, Fuzzer>,
}

impl FuzzerManager {
    pub fn update_input(
        &mut self,
        db: &Database,
        input: Input,
        fuzzable_closures: Vec<(Id, Closure)>,
    ) {
        let closures = self
            .fuzzable_closures
            .entry(input.clone())
            .or_insert_with(|| HashMap::new());

        for (id, new_closure) in fuzzable_closures {
            let old_closure = closures.insert(id.clone(), new_closure.clone());
            self.fuzzers
                .entry(new_closure.clone())
                .or_insert_with(|| Fuzzer::new(db, new_closure.clone(), id));
            if let Some(old_closure) = old_closure && old_closure != new_closure {
                self.fuzzers.remove(&old_closure);
            }
        }
    }

    pub fn remove_input(&mut self, input: Input) {
        self.fuzzable_closures.remove(&input).unwrap();
    }

    pub fn run(&mut self, db: &Database) -> Option<Input> {
        let mut running_fuzzers = self
            .fuzzers
            .values_mut()
            .filter(|fuzzer| matches!(fuzzer.status(), Status::StillFuzzing { .. }))
            .collect_vec();
        log::trace!(
            "Fuzzer running. {} fuzzers for relevant closures are running.",
            running_fuzzers.len(),
        );

        let fuzzer = running_fuzzers.choose_mut(&mut thread_rng())?;
        fuzzer.run(db, 100);

        match &fuzzer.status() {
            Status::StillFuzzing { .. } => None,
            Status::PanickedForArguments { .. } => Some(fuzzer.closure_id.input.clone()),
        }
    }

    pub fn get_hints(&self, db: &Database, input: &Input) -> Vec<Vec<Hint>> {
        let relevant_fuzzers = self.fuzzable_closures[input]
            .iter()
            .map(|(_, closure)| &self.fuzzers[closure])
            .collect_vec();
        let mut hints = vec![];

        for fuzzer in &relevant_fuzzers {
            if let Status::PanickedForArguments {
                arguments,
                reason,
                tracer,
            } = fuzzer.status()
            {
                let id = fuzzer.closure_id.clone();
                let first_hint = {
                    let parameter_names = match db.find_expression(id.clone()) {
                        Some(Expression::Lambda(Lambda { parameters, .. })) => parameters
                            .into_iter()
                            .map(|parameter| parameter.keys.last().unwrap().to_string())
                            .collect_vec(),
                        Some(_) => {
                            panic!("Looks like we fuzzed a non-closure. That's weird.")
                        }
                        None => {
                            log::warn!("Using fuzzing, we found an error in a generated closure.");
                            continue;
                        }
                    };
                    Hint {
                        kind: HintKind::Fuzz,
                        text: format!(
                            "If this is called with {},",
                            parameter_names
                                .iter()
                                .zip(arguments.iter())
                                .map(|(name, argument)| format!("`{name} = {argument}`"))
                                .collect_vec()
                                .join_with_commas_and_and(),
                        ),
                        position: id_to_end_of_line(&db, id.clone()).unwrap(),
                    }
                };

                let second_hint = {
                    let panicking_inner_call = tracer
                        .log()
                        .iter()
                        .rev()
                        // Find the innermost panicking call that is in the
                        // function.
                        .filter(|entry| {
                            let innermost_panicking_call_id = match entry {
                                TraceEntry::CallStarted { id, .. } => id,
                                TraceEntry::NeedsStarted { id, .. } => id,
                                _ => return false,
                            };
                            id.is_same_module_and_any_parent_of(innermost_panicking_call_id)
                                && db.hir_to_cst_id(id.clone()).is_some()
                        })
                        .next()
                        .expect(
                            "Fuzzer found a panicking function without an inner panicking needs",
                        );
                    let (call_id, name, arguments) = match panicking_inner_call {
                        TraceEntry::CallStarted { id, closure, args } => {
                            (id.clone(), format!("{closure}"), args.clone())
                        }
                        TraceEntry::NeedsStarted {
                            id,
                            condition,
                            reason,
                        } => (
                            id.clone(),
                            "needs".to_string(),
                            vec![condition.clone(), reason.clone()],
                        ),
                        _ => unreachable!(),
                    };
                    Hint {
                        kind: HintKind::Fuzz,
                        text: format!(
                            "then `{name} {}` panics because {reason}.",
                            arguments.iter().map(|arg| format!("{arg}")).join(" "),
                        ),
                        position: id_to_end_of_line(db, call_id).unwrap(),
                    }
                };

                hints.push(vec![first_hint, second_hint]);
            }
        }

        hints
    }
}
<commit_msg>Handle compiler errors in fuzzer<commit_after>use super::{super::utils::JoinWithCommasAndAnd, utils::id_to_end_of_line, Hint, HintKind};
use crate::{
    compiler::{
        ast_to_hir::AstToHir,
        hir::{Expression, HirDb, Id, Lambda},
    },
    database::Database,
    fuzzer::{Fuzzer, Status},
    input::Input,
    vm::{tracer::TraceEntry, value::Closure},
};
use itertools::Itertools;
use rand::{prelude::SliceRandom, thread_rng};
use std::collections::HashMap;

#[derive(Default)]
pub struct FuzzerManager {
    fuzzable_closures: HashMap<Input, HashMap<Id, Closure>>,
    fuzzers: HashMap<Closure, Fuzzer>,
}

impl FuzzerManager {
    pub fn update_input(
        &mut self,
        db: &Database,
        input: Input,
        fuzzable_closures: Vec<(Id, Closure)>,
    ) {
        let closures = self
            .fuzzable_closures
            .entry(input.clone())
            .or_insert_with(|| HashMap::new());

        for (id, new_closure) in fuzzable_closures {
            let old_closure = closures.insert(id.clone(), new_closure.clone());
            self.fuzzers
                .entry(new_closure.clone())
                .or_insert_with(|| Fuzzer::new(db, new_closure.clone(), id));
            if let Some(old_closure) = old_closure && old_closure != new_closure {
                self.fuzzers.remove(&old_closure);
            }
        }
    }

    pub fn remove_input(&mut self, input: Input) {
        self.fuzzable_closures.remove(&input).unwrap();
    }

    pub fn run(&mut self, db: &Database) -> Option<Input> {
        let mut running_fuzzers = self
            .fuzzers
            .values_mut()
            .filter(|fuzzer| matches!(fuzzer.status(), Status::StillFuzzing { .. }))
            .collect_vec();
        log::trace!(
            "Fuzzer running. {} fuzzers for relevant closures are running.",
            running_fuzzers.len(),
        );

        let fuzzer = running_fuzzers.choose_mut(&mut thread_rng())?;
        fuzzer.run(db, 100);

        match &fuzzer.status() {
            Status::StillFuzzing { .. } => None,
            Status::PanickedForArguments { .. } => Some(fuzzer.closure_id.input.clone()),
        }
    }

    pub fn get_hints(&self, db: &Database, input: &Input) -> Vec<Vec<Hint>> {
        let relevant_fuzzers = self.fuzzable_closures[input]
            .iter()
            .map(|(_, closure)| &self.fuzzers[closure])
            .collect_vec();
        let mut hints = vec![];

        for fuzzer in &relevant_fuzzers {
            if let Status::PanickedForArguments {
                arguments,
                reason,
                tracer,
            } = fuzzer.status()
            {
                let id = fuzzer.closure_id.clone();
                let first_hint = {
                    let parameter_names = match db.find_expression(id.clone()) {
                        Some(Expression::Lambda(Lambda { parameters, .. })) => parameters
                            .into_iter()
                            .map(|parameter| parameter.keys.last().unwrap().to_string())
                            .collect_vec(),
                        Some(_) => panic!("Looks like we fuzzed a non-closure. That's weird."),
                        None => {
                            log::error!("Using fuzzing, we found an error in a generated closure.");
                            continue;
                        }
                    };
                    Hint {
                        kind: HintKind::Fuzz,
                        text: format!(
                            "If this is called with {},",
                            parameter_names
                                .iter()
                                .zip(arguments.iter())
                                .map(|(name, argument)| format!("`{name} = {argument}`"))
                                .collect_vec()
                                .join_with_commas_and_and(),
                        ),
                        position: id_to_end_of_line(&db, id.clone()).unwrap(),
                    }
                };

                let second_hint = {
                    let panicking_inner_call = tracer
                        .log()
                        .iter()
                        .rev()
                        // Find the innermost panicking call that is in the
                        // function.
                        .filter(|entry| {
                            let innermost_panicking_call_id = match entry {
                                TraceEntry::CallStarted { id, .. } => id,
                                TraceEntry::NeedsStarted { id, .. } => id,
                                _ => return false,
                            };
                            id.is_same_module_and_any_parent_of(innermost_panicking_call_id)
                                && db.hir_to_cst_id(id.clone()).is_some()
                        })
                        .next();
                    let panicking_inner_call = match panicking_inner_call {
                        Some(panicking_inner_call) => panicking_inner_call,
                        None => {
                            // We found a panicking function without an inner
                            // panicking needs. This indicates an error during
                            // compilation within a function body.
                            continue;
                        }
                    };
                    let (call_id, name, arguments) = match panicking_inner_call {
                        TraceEntry::CallStarted { id, closure, args } => {
                            (id.clone(), format!("{closure}"), args.clone())
                        }
                        TraceEntry::NeedsStarted {
                            id,
                            condition,
                            reason,
                        } => (
                            id.clone(),
                            "needs".to_string(),
                            vec![condition.clone(), reason.clone()],
                        ),
                        _ => unreachable!(),
                    };
                    Hint {
                        kind: HintKind::Fuzz,
                        text: format!(
                            "then `{name} {}` panics because {reason}.",
                            arguments.iter().map(|arg| format!("{arg}")).join(" "),
                        ),
                        position: id_to_end_of_line(db, call_id).unwrap(),
                    }
                };

                hints.push(vec![first_hint, second_hint]);
            }
        }

        hints
    }
}
<|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 https://mozilla.org/MPL/2.0/. */

//! An event loop implementation that works in headless mode.

use glutin;
use servo::embedder_traits::EventLoopWaker;
use std::sync::Arc;
use std::rc::Rc;
use std::cell::RefCell;
use std::thread;
use std::time;

pub struct EventsLoop(Option<glutin::EventsLoop>);

impl EventsLoop {
    // Ideally, we could use the winit event loop in both modes,
    // but on Linux, the event loop requires a X11 server.
    #[cfg(not(target_os = "linux"))]
    pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> {
        Rc::new(RefCell::new(EventsLoop(Some(glutin::EventsLoop::new()))))
    }
    #[cfg(target_os = "linux")]
    pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> {
        let events_loop = if headless {
            None
        } else {
            Some(glutin::EventsLoop::new())
        };
        Rc::new(RefCell::new(EventsLoop(events_loop)))
    }
}

impl EventsLoop {
    pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
        if let Some(ref events_loop) = self.0 {
            Box::new(HeadedEventLoopWaker::new(&events_loop))
        } else {
            Box::new(HeadlessEventLoopWaker)
        }
    }
    pub fn as_winit(&self) -> &glutin::EventsLoop {
        &self.0.as_ref().expect("Can't access winit event loop while using the fake headless event loop")
    }
    pub fn take(&mut self) -> Option<glutin::EventsLoop> {
        self.0.take()
    }
    pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(glutin::Event) {
        if let Some(ref mut events_loop) = self.0 {
            events_loop.poll_events(callback);
        } else {
            self.sleep();
        }
    }
    pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(glutin::Event) -> glutin::ControlFlow {
        if let Some(ref mut events_loop) = self.0 {
            events_loop.run_forever(callback);
        } else {
            loop {
                self.sleep();
                if callback(glutin::Event::Awakened) == glutin::ControlFlow::Break {
                    break;
                }
            }
        }
    }
    fn sleep(&self) {
        thread::sleep(time::Duration::from_millis(5));
    }
}

struct HeadedEventLoopWaker {
    proxy: Arc<glutin::EventsLoopProxy>,
}
impl HeadedEventLoopWaker {
    fn new(events_loop: &glutin::EventsLoop) -> HeadedEventLoopWaker {
        let proxy = Arc::new(events_loop.create_proxy());
        HeadedEventLoopWaker { proxy }
    }
}
impl EventLoopWaker for HeadedEventLoopWaker {
    fn wake(&self) {
        // kick the OS event loop awake.
        if let Err(err) = self.proxy.wakeup() {
            warn!("Failed to wake up event loop ({}).", err);
        }
    }
    fn clone_box(&self) -> Box<dyn EventLoopWaker> {
        Box::new(HeadedEventLoopWaker {
            proxy: self.proxy.clone(),
        })
    }
}

struct HeadlessEventLoopWaker;
impl EventLoopWaker for HeadlessEventLoopWaker {
    fn wake(&self) {}
    fn clone_box(&self) -> Box<dyn EventLoopWaker> { Box::new(HeadlessEventLoopWaker) }
}
<commit_msg>Support waking up headless window event loops while they are sleeping.<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 https://mozilla.org/MPL/2.0/. */

//! An event loop implementation that works in headless mode.

use glutin;
use servo::embedder_traits::EventLoopWaker;
use std::sync::{Arc, Condvar, Mutex};
use std::rc::Rc;
use std::cell::RefCell;
use std::time;

#[allow(dead_code)]
enum EventLoop {
    /// A real Glutin windowing event loop.
    Glutin(Option<glutin::EventsLoop>),
    /// A fake event loop which contains a signalling flag used to ensure
    /// that pending events get processed in a timely fashion, and a condition
    /// variable to allow waiting on that flag changing state.
    Headless(Arc<(Mutex<bool>, Condvar)>),
}

pub struct EventsLoop(EventLoop);

impl EventsLoop {
    // Ideally, we could use the winit event loop in both modes,
    // but on Linux, the event loop requires a X11 server.
    #[cfg(not(target_os = "linux"))]
    pub fn new(_headless: bool) -> Rc<RefCell<EventsLoop>> {
        Rc::new(RefCell::new(EventsLoop(EventLoop::Glutin(Some(glutin::EventsLoop::new())))))
    }
    #[cfg(target_os = "linux")]
    pub fn new(headless: bool) -> Rc<RefCell<EventsLoop>> {
        let events_loop = if headless {
            EventLoop::Headless(Arc::new((Mutex::new(false), Condvar::new())))
        } else {
            EventLoop::Glutin(Some(glutin::EventsLoop::new()))
        };
        Rc::new(RefCell::new(EventsLoop(events_loop)))
    }
}

impl EventsLoop {
    pub fn create_event_loop_waker(&self) -> Box<dyn EventLoopWaker> {
        match self.0 {
            EventLoop::Glutin(ref events_loop) => {
                let events_loop = events_loop
                    .as_ref()
                    .expect("Can't create waker for unavailable event loop.");
                Box::new(HeadedEventLoopWaker::new(&events_loop))
            },
            EventLoop::Headless(ref data) =>
                Box::new(HeadlessEventLoopWaker(data.clone())),
        }
    }
    pub fn as_winit(&self) -> &glutin::EventsLoop {
        match self.0 {
            EventLoop::Glutin(Some(ref event_loop)) => event_loop,
            EventLoop::Glutin(None) | EventLoop::Headless(..) =>
                panic!("Can't access winit event loop while using the fake headless event loop"),
        }
    }
    pub fn take(&mut self) -> Option<glutin::EventsLoop> {
        match self.0 {
            EventLoop::Glutin(ref mut event_loop) => event_loop.take(),
            EventLoop::Headless(..) => None,
        }
    }
    pub fn poll_events<F>(&mut self, callback: F) where F: FnMut(glutin::Event) {
        match self.0 {
            EventLoop::Glutin(Some(ref mut events_loop)) => events_loop.poll_events(callback),
            EventLoop::Glutin(None) => (),
            EventLoop::Headless(ref data) => {
                // This is subtle - the use of the event loop in App::run_loop
                // optionally calls run_forever, then always calls poll_events.
                // If our signalling flag is true before we call run_forever,
                // we don't want to reset it before poll_events is called or
                // we'll end up sleeping even though there are events waiting
                // to be handled. We compromise by only resetting the flag here
                // in poll_events, so that both poll_events and run_forever can
                // check it first and avoid sleeping unnecessarily.
                self.sleep(&data.0, &data.1);
                *data.0.lock().unwrap() = false;
            }
        }
    }
    pub fn run_forever<F>(&mut self, mut callback: F) where F: FnMut(glutin::Event) -> glutin::ControlFlow {
        match self.0 {
            EventLoop::Glutin(ref mut events_loop) => {
                let events_loop = events_loop
                    .as_mut()
                    .expect("Can't run an unavailable event loop.");
                events_loop.run_forever(callback);
            }
            EventLoop::Headless(ref data) => {
                let &(ref flag, ref condvar) = &**data;
                while { !*flag.lock().unwrap() } {
                    self.sleep(flag, condvar);
                    if callback(glutin::Event::Awakened) == glutin::ControlFlow::Break {
                        break;
                    }
                }
            }
        }
    }
    fn sleep(&self, lock: &Mutex<bool>, condvar: &Condvar) {
        // To avoid sleeping when we should be processing events, do two things:
        // * before sleeping, check whether our signalling flag has been set
        // * wait on a condition variable with a maximum timeout, to allow
        //   being woken up by any signals that occur while sleeping.
        let guard = lock.lock().unwrap();
        if *guard {
            return;
        }
        let _ = condvar.wait_timeout(
            guard, time::Duration::from_millis(5)
        ).unwrap();
    }
}

struct HeadedEventLoopWaker {
    proxy: Arc<glutin::EventsLoopProxy>,
}
impl HeadedEventLoopWaker {
    fn new(events_loop: &glutin::EventsLoop) -> HeadedEventLoopWaker {
        let proxy = Arc::new(events_loop.create_proxy());
        HeadedEventLoopWaker { proxy }
    }
}
impl EventLoopWaker for HeadedEventLoopWaker {
    fn wake(&self) {
        // kick the OS event loop awake.
        if let Err(err) = self.proxy.wakeup() {
            warn!("Failed to wake up event loop ({}).", err);
        }
    }
    fn clone_box(&self) -> Box<dyn EventLoopWaker> {
        Box::new(HeadedEventLoopWaker {
            proxy: self.proxy.clone(),
        })
    }
}

struct HeadlessEventLoopWaker(Arc<(Mutex<bool>, Condvar)>);
impl EventLoopWaker for HeadlessEventLoopWaker {
    fn wake(&self) {
        // Set the signalling flag and notify the condition variable.
        // This ensures that any sleep operation is interrupted,
        // and any non-sleeping operation will have a change to check
        // the flag before going to sleep.
        let (ref flag, ref condvar) = *self.0;
        let mut flag = flag.lock().unwrap();
        *flag = true;
        condvar.notify_all();
    }
    fn clone_box(&self) -> Box<dyn EventLoopWaker> {
        Box::new(HeadlessEventLoopWaker(self.0.clone()))
    }
}
<|endoftext|>


<commit_before>extern crate compiletest_rs as compiletest;

use std::path::PathBuf;
use std::env::var;

fn run_mode(mode: &'static str) {
    let mut config = compiletest::default_config();

    let cfg_mode = mode.parse().expect("Invalid mode");

    config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());
    if let Ok(name) = var::<&str>("TESTNAME") {
        let s : String = name.to_owned();
        config.filter = Some(s)
    }
    config.mode = cfg_mode;
    config.src_base = PathBuf::from(format!("tests/{}", mode));

    compiletest::run_tests(&config);
}

#[test]
fn compile_fail() {
    run_mode("compile-fail");
}

#[test]
fn run_pass() {
    run_mode("run-pass");
}
<commit_msg>Clean up the compile_tests script<commit_after>extern crate compiletest_rs as compiletest;

use std::env;

fn run_mode(mode: &'static str) {
    let mut config = compiletest::default_config();

    config.mode = mode.parse().expect("invalid mode");
    config.target_rustcflags = Some("-L target/debug/ -L target/debug/deps/".to_owned());
    if let Ok(name) = env::var("TESTNAME") {
        config.filter = Some(name);
    }
    config.src_base = format!("tests/{}", mode).into();

    compiletest::run_tests(&config);
}

#[test]
fn compile_fail() {
    run_mode("compile-fail");
}

#[test]
fn run_pass() {
    run_mode("run-pass");
}
<|endoftext|>


<commit_before>#![cfg(test)]

use std::collections::HashMap;
use rustc_serialize::json;
use rustc_serialize::json::{decode, Json, Object};
use rustc_serialize::{Decoder, Decodable};
use std::io::prelude::*;
use std::fs::File;
use token::{Token, ReservedWord};

pub struct ExpectPass {
    source: String,
    expected: Json,
    options: Option<Json>
}

pub struct ExpectFail {
    source: String,
    error: String,
    options: Option<Json>
}

pub enum TestCase {
    Pass(ExpectPass),
    Fail(ExpectFail)
}

trait JsonExt {
    fn into_array(self) -> json::Array;
    fn into_string(self) -> String;
    fn into_string_opt(self) -> Option<String>;
}

impl JsonExt for Json {
    fn into_array(self) -> json::Array {
        match self {
            Json::Array(array) => array,
            _ => panic!("expected array")
        }
    }
    fn into_string(self) -> String {
        match self {
            Json::String(string) => string,
            _ => panic!("expected string")
        }
    }
    fn into_string_opt(self) -> Option<String> {
        match self {
            Json::Null => None,
            Json::String(string) => Some(string),
            _ => panic!("expected string or null")
        }
    }
}

pub fn read_tests(path: &str) -> Vec<TestCase> {
    let mut f: File = File::open(path).unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s);
    parse_tests(s)
}

pub fn parse_tests(src: &str) -> Vec<TestCase> {
    let data: Json = decode(src).unwrap();
    unimplemented!()
}
<commit_msg>acrichto corrected himself, he said to use s.parse() because Json implements FromStr. that compiles<commit_after>#![cfg(test)]

use std::collections::HashMap;
use rustc_serialize::json;
use rustc_serialize::json::{decode, Json, Object};
use rustc_serialize::{Decoder, Decodable};
use std::io::prelude::*;
use std::fs::File;
use token::{Token, ReservedWord};

pub struct ExpectPass {
    source: String,
    expected: Json,
    options: Option<Json>
}

pub struct ExpectFail {
    source: String,
    error: String,
    options: Option<Json>
}

pub enum TestCase {
    Pass(ExpectPass),
    Fail(ExpectFail)
}

trait JsonExt {
    fn into_array(self) -> json::Array;
    fn into_string(self) -> String;
    fn into_string_opt(self) -> Option<String>;
}

impl JsonExt for Json {
    fn into_array(self) -> json::Array {
        match self {
            Json::Array(array) => array,
            _ => panic!("expected array")
        }
    }
    fn into_string(self) -> String {
        match self {
            Json::String(string) => string,
            _ => panic!("expected string")
        }
    }
    fn into_string_opt(self) -> Option<String> {
        match self {
            Json::Null => None,
            Json::String(string) => Some(string),
            _ => panic!("expected string or null")
        }
    }
}

pub fn read_tests(path: &str) -> Vec<TestCase> {
    let mut f: File = File::open(path).unwrap();
    let mut s = String::new();
    f.read_to_string(&mut s);
    parse_tests(&s)
}

pub fn parse_tests(src: &str) -> Vec<TestCase> {
    let data: Json = src.parse().unwrap();
    unimplemented!()
}
<|endoftext|>


<commit_before>
use color::Color;
use frame::{
    Framing,
    Frame,
    NoFrame,
};
use graphics::{
    AddColor,
    AddEllipse,
    AddLine,
    AddRoundBorder,
    Context,
    Draw,
};
use label;
use label::{
    NoLabel,
    Label,
    FontSize,
    Labeling,
};
use mouse_state::{
    MouseState,
    Up,
    Down,
};
use opengl_graphics::Gl;
use piston::{
    RenderArgs,
};
use piston::input::keyboard::{
    Key,
    Backspace,
    Left,
    Right,
    Return,
};
use point::Point;
use rectangle;
use rectangle::{
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
};
use ui_context::{
    UIID,
    UIContext,
};
use utils::{
    clamp,
    map_range,
    val_to_string,
};
use widget::TextBox;

pub type Idx = uint;
pub type CursorX = f64;

/// Represents the state of the text_box widget.
#[deriving(Show, PartialEq)]
pub struct State(WidgetState, Capturing);

/// Represents the next tier of state.
#[deriving(Show, PartialEq)]
pub enum WidgetState {
    Normal,
    Highlighted(Element),
    Clicked(Element),
}

/// Whether the textbox is currently captured or not.
#[deriving(Show, PartialEq)]
pub enum Capturing {
    Uncaptured,
    Captured(Idx, CursorX),
}

/// Represents an element of the TextBox widget.
#[deriving(Show, PartialEq)]
pub enum Element {
    Nill,
    Rect,
    Text(Idx, CursorX),
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State(state, capturing) => match capturing {
                Captured(_, _) => rectangle::Normal,
                Uncaptured => match state {
                    Normal => rectangle::Normal,
                    Highlighted(_) => rectangle::Highlighted,
                    Clicked(_) => rectangle::Clicked,
                },
            }
        }
    }
}

widget_fns!(TextBox, State, TextBox(State(Normal, Uncaptured)))

static TEXT_PADDING: f64 = 5f64;

/// Draw the text_box widget.
pub fn draw(args: &RenderArgs,
            gl: &mut Gl,
            uic: &mut UIContext,
            ui_id: UIID,
            pos: Point<f64>,
            width: f64,
            height: f64,
            font_size: FontSize,
            frame: Framing,
            color: Color,
            text: &mut String,
            callback: |&mut String|) {

    let mouse = uic.get_mouse_state();
    let state = *get_state(uic, ui_id);

    // Rect.
    let frame_w = match frame { Frame(w, _) => w, NoFrame => 0.0 };
    let frame_w2 = frame_w * 2.0;
    let pad_pos = pos + Point::new(frame_w, frame_w, 0.0);
    let pad_w = width - frame_w2;
    let pad_h = height - frame_w2;
    let text_pos = Point::new(pad_pos.x + TEXT_PADDING,
                              pad_pos.y + (pad_h - font_size as f64) / 2.0,
                              0.0);
    let text_w = label::width(uic, font_size, text.as_slice());
    let over_elem = over_elem(uic, pos, mouse.pos, width, height,
                              pad_pos, pad_w, pad_h,
                              text_pos, text_w, font_size, text.as_slice());
    let mut new_state = get_new_state(over_elem, state, mouse);

    rectangle::draw(args, gl, new_state.as_rectangle_state(), pos, width, height, frame, color);
    label::draw(args, gl, uic, text_pos, font_size, color.plain_contrast(), text.as_slice());

    let new_state = match new_state { State(w_state, capturing) => match capturing {
        Uncaptured => new_state,
        Captured(idx, cursor_x) => {
            let context = Context::abs(args.width as f64, args.height as f64);
            let (r, g, b, a) = color.plain_contrast().as_tuple();
            context
                .line(cursor_x, pad_pos.y, cursor_x, pad_pos.y + pad_h)
                .round_border_width(1f64)
                .rgba(r, g, b, a)
                .draw(gl);
            let mut new_idx = idx;
            let mut new_cursor_x = cursor_x;

            // Check for entered text.
            let entered_text = uic.get_entered_text();
            for t in entered_text.iter() {
                let new_text = String::from_str(text.as_slice().slice_to(idx))
                    .append(t.as_slice()).append(text.as_slice().slice_from(idx));
                *text = new_text;
                new_idx += t.len();
                for ch in t.as_slice().chars() {
                    let c = uic.get_character(font_size, ch);
                    new_cursor_x += (c.glyph.advance().x >> 16) as f64;
                }
            }

            // Check for control keys.
            let pressed_keys = uic.get_pressed_keys();
            for key in pressed_keys.iter() {
                match *key {
                    Backspace => {
                        if text.len() > 0u
                        && text.len() >= idx
                        && idx > 0u {
                            let rem_idx = idx - 1u;
                            new_cursor_x -= uic.get_character_w(font_size, text.as_slice().char_at(rem_idx));
                            let new_text = String::from_str(text.as_slice().slice_to(rem_idx))
                                .append(text.as_slice().slice_from(idx));
                            *text = new_text;
                            new_idx = rem_idx;
                        }
                    },
                    Left => {
                        if idx > 0 {
                            new_cursor_x -= uic.get_character_w(font_size, text.as_slice().char_at(idx - 1u));
                            new_idx -= 1u;
                        }
                    },
                    Right => {
                        if text.len() > idx {
                            new_cursor_x += uic.get_character_w(font_size, text.as_slice().char_at(idx));
                            new_idx += 1u;
                        }
                    },
                    Return => if text.len() > 0u { callback(text) },
                    _ => (),
                }
            }

            State(w_state, Captured(new_idx, new_cursor_x))
        },
    }};

    set_state(uic, ui_id, new_state);

}

/// Check if cursor is over the pad and if so, which
fn over_elem(uic: &mut UIContext,
             pos: Point<f64>,
             mouse_pos: Point<f64>,
             rect_w: f64,
             rect_h: f64,
             pad_pos: Point<f64>,
             pad_w: f64,
             pad_h: f64,
             text_pos: Point<f64>,
             text_w: f64,
             font_size: FontSize,
             text: &str) -> Element {
    match rectangle::is_over(pos, mouse_pos, rect_w, rect_h) {
        false => Nill,
        true => match rectangle::is_over(pad_pos, mouse_pos, pad_w, pad_h) {
            false => Rect,
            true => {
                let (idx, cursor_x) = closest_idx(uic, mouse_pos, pad_h, pad_pos.y, text_pos.x, text_w, font_size, text);
                Text(idx, cursor_x)
            },
        },
    }
}

/// Check which character is closest to the mouse cursor.
fn closest_idx(uic: &mut UIContext,
               mouse_pos: Point<f64>,
               pad_h: f64,
               pad_y: f64,
               text_x: f64,
               text_w: f64,
               font_size: FontSize,
               text: &str) -> (Idx, f64) {
    if mouse_pos.x <= text_x { return (0u, text_x) }
    let mut x = text_x;
    let mut prev_x = x;
    let mut left_x = text_x;
    for (i, ch) in text.chars().enumerate() {
        let character = uic.get_character(font_size, ch);
        let char_w = (character.glyph.advance().x >> 16) as f64;
        x += char_w;
        let right_x = prev_x + char_w / 2.0;
        if mouse_pos.x > left_x && mouse_pos.x < right_x { return (i, prev_x) }
        prev_x = x;
        left_x = right_x;
    }
    (text.len(), text_x + text_w)
}

/// Check and return the current state of the TextBox.
fn get_new_state(over_elem: Element,
                 prev_box_state: State,
                 mouse: MouseState) -> State {
    match prev_box_state {
        State(prev, Uncaptured) => {
            match (over_elem, prev, mouse.left) {
                (_, Normal, Down) => State(Normal, Uncaptured),
                (Nill, Normal, Up) | (Nill, Highlighted(_), Up) => State(Normal, Uncaptured),
                (_, Normal, Up) | (_, Highlighted(_), Up) => State(Highlighted(over_elem), Uncaptured),
                (_, Highlighted(p_elem), Down) | (_, Clicked(p_elem), Down) =>
                    State(Clicked(p_elem), Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (Nill, _, _) => State(Normal, Uncaptured),
                _ => prev_box_state,
            }
        },
        State(prev, Captured(p_idx, p_x)) => {
            match (over_elem, prev, mouse.left) {
                (Nill, Clicked(Nill), Up) => State(Normal, Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (_, Normal, Up) | (_, Highlighted(_), Up) | (_, Clicked(_), Up)  =>
                    State(Highlighted(over_elem), Captured(p_idx, p_x)),
                (_, Highlighted(p_elem), Down) | (_, Clicked(p_elem), Down) =>
                    State(Clicked(p_elem), Captured(p_idx, p_x)),
                _ => prev_box_state,
            }
        },
    }
}

<commit_msg>Added condition so that text cannot be longer than the textbox itself<commit_after>
use color::Color;
use frame::{
    Framing,
    Frame,
    NoFrame,
};
use graphics::{
    AddColor,
    AddEllipse,
    AddLine,
    AddRoundBorder,
    Context,
    Draw,
};
use label;
use label::{
    NoLabel,
    Label,
    FontSize,
    Labeling,
};
use mouse_state::{
    MouseState,
    Up,
    Down,
};
use opengl_graphics::Gl;
use piston::{
    RenderArgs,
};
use piston::input::keyboard::{
    Key,
    Backspace,
    Left,
    Right,
    Return,
};
use point::Point;
use rectangle;
use rectangle::{
    TopLeft,
    TopRight,
    BottomLeft,
    BottomRight,
};
use ui_context::{
    UIID,
    UIContext,
};
use utils::{
    clamp,
    map_range,
    val_to_string,
};
use widget::TextBox;

pub type Idx = uint;
pub type CursorX = f64;

/// Represents the state of the text_box widget.
#[deriving(Show, PartialEq)]
pub struct State(WidgetState, Capturing);

/// Represents the next tier of state.
#[deriving(Show, PartialEq)]
pub enum WidgetState {
    Normal,
    Highlighted(Element),
    Clicked(Element),
}

/// Whether the textbox is currently captured or not.
#[deriving(Show, PartialEq)]
pub enum Capturing {
    Uncaptured,
    Captured(Idx, CursorX),
}

/// Represents an element of the TextBox widget.
#[deriving(Show, PartialEq)]
pub enum Element {
    Nill,
    Rect,
    Text(Idx, CursorX),
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State(state, capturing) => match capturing {
                Captured(_, _) => rectangle::Normal,
                Uncaptured => match state {
                    Normal => rectangle::Normal,
                    Highlighted(_) => rectangle::Highlighted,
                    Clicked(_) => rectangle::Clicked,
                },
            }
        }
    }
}

widget_fns!(TextBox, State, TextBox(State(Normal, Uncaptured)))

static TEXT_PADDING: f64 = 5f64;

/// Draw the text_box widget.
pub fn draw(args: &RenderArgs,
            gl: &mut Gl,
            uic: &mut UIContext,
            ui_id: UIID,
            pos: Point<f64>,
            width: f64,
            height: f64,
            font_size: FontSize,
            frame: Framing,
            color: Color,
            text: &mut String,
            callback: |&mut String|) {

    let mouse = uic.get_mouse_state();
    let state = *get_state(uic, ui_id);

    // Rect.
    let frame_w = match frame { Frame(w, _) => w, NoFrame => 0.0 };
    let frame_w2 = frame_w * 2.0;
    let pad_pos = pos + Point::new(frame_w, frame_w, 0.0);
    let pad_w = width - frame_w2;
    let pad_h = height - frame_w2;
    let text_pos = Point::new(pad_pos.x + TEXT_PADDING,
                              pad_pos.y + (pad_h - font_size as f64) / 2.0,
                              0.0);
    let text_w = label::width(uic, font_size, text.as_slice());
    let over_elem = over_elem(uic, pos, mouse.pos, width, height,
                              pad_pos, pad_w, pad_h,
                              text_pos, text_w, font_size, text.as_slice());
    let mut new_state = get_new_state(over_elem, state, mouse);

    rectangle::draw(args, gl, new_state.as_rectangle_state(), pos, width, height, frame, color);
    label::draw(args, gl, uic, text_pos, font_size, color.plain_contrast(), text.as_slice());

    let new_state = match new_state { State(w_state, capturing) => match capturing {
        Uncaptured => new_state,
        Captured(idx, cursor_x) => {
            let context = Context::abs(args.width as f64, args.height as f64);
            let (r, g, b, a) = color.plain_contrast().as_tuple();
            context
                .line(cursor_x, pad_pos.y, cursor_x, pad_pos.y + pad_h)
                .round_border_width(1f64)
                .rgba(r, g, b, a)
                .draw(gl);
            let mut new_idx = idx;
            let mut new_cursor_x = cursor_x;

            // Check for entered text.
            let entered_text = uic.get_entered_text();
            for t in entered_text.iter() {
                let mut entered_text_width = 0f64;
                for ch in t.as_slice().chars() {
                    let c = uic.get_character(font_size, ch);
                    entered_text_width += (c.glyph.advance().x >> 16) as f64;
                }
                if new_cursor_x + entered_text_width < pad_pos.x + pad_w - TEXT_PADDING {
                    new_cursor_x += entered_text_width;
                }
                else {
                    break;
                }
                let new_text = String::from_str(text.as_slice().slice_to(idx))
                    .append(t.as_slice()).append(text.as_slice().slice_from(idx));
                *text = new_text;
                new_idx += t.len();
            }

            // Check for control keys.
            let pressed_keys = uic.get_pressed_keys();
            for key in pressed_keys.iter() {
                match *key {
                    Backspace => {
                        if text.len() > 0u
                        && text.len() >= idx
                        && idx > 0u {
                            let rem_idx = idx - 1u;
                            new_cursor_x -= uic.get_character_w(font_size, text.as_slice().char_at(rem_idx));
                            let new_text = String::from_str(text.as_slice().slice_to(rem_idx))
                                .append(text.as_slice().slice_from(idx));
                            *text = new_text;
                            new_idx = rem_idx;
                        }
                    },
                    Left => {
                        if idx > 0 {
                            new_cursor_x -= uic.get_character_w(font_size, text.as_slice().char_at(idx - 1u));
                            new_idx -= 1u;
                        }
                    },
                    Right => {
                        if text.len() > idx {
                            new_cursor_x += uic.get_character_w(font_size, text.as_slice().char_at(idx));
                            new_idx += 1u;
                        }
                    },
                    Return => if text.len() > 0u { callback(text) },
                    _ => (),
                }
            }

            State(w_state, Captured(new_idx, new_cursor_x))
        },
    }};

    set_state(uic, ui_id, new_state);

}

/// Check if cursor is over the pad and if so, which
fn over_elem(uic: &mut UIContext,
             pos: Point<f64>,
             mouse_pos: Point<f64>,
             rect_w: f64,
             rect_h: f64,
             pad_pos: Point<f64>,
             pad_w: f64,
             pad_h: f64,
             text_pos: Point<f64>,
             text_w: f64,
             font_size: FontSize,
             text: &str) -> Element {
    match rectangle::is_over(pos, mouse_pos, rect_w, rect_h) {
        false => Nill,
        true => match rectangle::is_over(pad_pos, mouse_pos, pad_w, pad_h) {
            false => Rect,
            true => {
                let (idx, cursor_x) = closest_idx(uic, mouse_pos, pad_h, pad_pos.y, text_pos.x, text_w, font_size, text);
                Text(idx, cursor_x)
            },
        },
    }
}

/// Check which character is closest to the mouse cursor.
fn closest_idx(uic: &mut UIContext,
               mouse_pos: Point<f64>,
               pad_h: f64,
               pad_y: f64,
               text_x: f64,
               text_w: f64,
               font_size: FontSize,
               text: &str) -> (Idx, f64) {
    if mouse_pos.x <= text_x { return (0u, text_x) }
    let mut x = text_x;
    let mut prev_x = x;
    let mut left_x = text_x;
    for (i, ch) in text.chars().enumerate() {
        let character = uic.get_character(font_size, ch);
        let char_w = (character.glyph.advance().x >> 16) as f64;
        x += char_w;
        let right_x = prev_x + char_w / 2.0;
        if mouse_pos.x > left_x && mouse_pos.x < right_x { return (i, prev_x) }
        prev_x = x;
        left_x = right_x;
    }
    (text.len(), text_x + text_w)
}

/// Check and return the current state of the TextBox.
fn get_new_state(over_elem: Element,
                 prev_box_state: State,
                 mouse: MouseState) -> State {
    match prev_box_state {
        State(prev, Uncaptured) => {
            match (over_elem, prev, mouse.left) {
                (_, Normal, Down) => State(Normal, Uncaptured),
                (Nill, Normal, Up) | (Nill, Highlighted(_), Up) => State(Normal, Uncaptured),
                (_, Normal, Up) | (_, Highlighted(_), Up) => State(Highlighted(over_elem), Uncaptured),
                (_, Highlighted(p_elem), Down) | (_, Clicked(p_elem), Down) =>
                    State(Clicked(p_elem), Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (Nill, _, _) => State(Normal, Uncaptured),
                _ => prev_box_state,
            }
        },
        State(prev, Captured(p_idx, p_x)) => {
            match (over_elem, prev, mouse.left) {
                (Nill, Clicked(Nill), Up) => State(Normal, Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (_, Normal, Up) | (_, Highlighted(_), Up) | (_, Clicked(_), Up)  =>
                    State(Highlighted(over_elem), Captured(p_idx, p_x)),
                (_, Highlighted(p_elem), Down) | (_, Clicked(p_elem), Down) =>
                    State(Clicked(p_elem), Captured(p_idx, p_x)),
                _ => prev_box_state,
            }
        },
    }
}

<|endoftext|>


<commit_before>#![no_std]

#[macro_use]
extern crate static_assertions;

assert_eq_size!(byte; u8, u8, (u8,), [u8; 1]);

#[cfg(feature = "failure")]
const_assert!(byte; u8, u8);

// Placed in separate module so that DropCounter's fields are private
mod dc {
    /// A type that acts somewhat of a reference counter.
    pub struct DropCounter<'a> {
        count: &'a mut i32
    }

    impl<'a> DropCounter<'a> {
        pub fn new(count: &'a mut i32) -> DropCounter<'a> {
            *count += 1;
            DropCounter { count: count }
        }

        pub fn count(&self) -> i32 {
            *self.count
        }
    }

    impl<'a> Drop for DropCounter<'a> {
        fn drop(&mut self) {
            *self.count -= 1
        }
    }
}
use dc::*;

/// A type that panics on drop.
struct PanicDrop<T>(T);

impl<T> Drop for PanicDrop<T> {
    fn drop(&mut self) {
        panic!("Dropped!");
    }
}

#[test]
fn test_eq_size() {
    assert_eq_size!([u8; 2], u16);
    assert_eq_size!([u8; 2], u16, (u8, u8));
    assert_eq_size!([u8; 4], u32, (u16, u8, u8), (u16, u16));

    assert_eq_size_val!([0u8; 2], 0u16);
    assert_eq_size_val!([0u8; 2], 0u16, (0u8, 0u8));
    assert_eq_size_val!([0u8; 4], 0u32, (0u16, 0u8, 0u8), (0u16, 0u16));

    #[deny(unused_unsafe)]
    unsafe {
        assert_eq_size!(u8, u8);
        assert_eq_size_val!(0u8, 0u8);
    }

    // Should fail to compile (un-comment to test manually):
    // assert_eq_size!(u8, u16);
    // assert_eq_size_val!(0u8, 0u16);
}

#[test]
fn test_eq_size_no_drop() {
    assert_eq_size!(u32, PanicDrop<u32>);
    assert_eq_size!(PanicDrop<u32>, u32);
    assert_eq_size!(PanicDrop<u32>, PanicDrop<u32>);
}

#[test]
fn test_eq_size_drop_count() {
    let mut count = 0;
    {
        let dc = DropCounter::new(&mut count);
        assert_eq!(dc.count(), 1);
        assert_eq_size_val!(dc, 0usize);
        assert_eq!(dc.count(), 1);
        assert_eq_size_val!(dc, 0usize, dc);
        assert_eq!(dc.count(), 1);
    }
    assert_eq!(count, 0);

    assert_eq_size_val!(DropCounter::new(&mut count), 0usize);
    assert_eq!(count, 0);
}

// This test is expected to fail at compile-time
#[cfg(feature = "failure")]
#[test]
fn test_fail() {
    assert_eq_size!(u8, u32);
    assert_eq_size!(u8, u32, u64);
    assert_eq_size!([u8; 1], u8, u8, u64);
}
<commit_msg>[Tests] Fix same label failure macro<commit_after>#![no_std]

#[macro_use]
extern crate static_assertions;

assert_eq_size!(byte; u8, u8, (u8,), [u8; 1]);

#[cfg(feature = "failure")]
assert_eq_size!(byte; u8, u8);

// Placed in separate module so that DropCounter's fields are private
mod dc {
    /// A type that acts somewhat of a reference counter.
    pub struct DropCounter<'a> {
        count: &'a mut i32
    }

    impl<'a> DropCounter<'a> {
        pub fn new(count: &'a mut i32) -> DropCounter<'a> {
            *count += 1;
            DropCounter { count: count }
        }

        pub fn count(&self) -> i32 {
            *self.count
        }
    }

    impl<'a> Drop for DropCounter<'a> {
        fn drop(&mut self) {
            *self.count -= 1
        }
    }
}
use dc::*;

/// A type that panics on drop.
struct PanicDrop<T>(T);

impl<T> Drop for PanicDrop<T> {
    fn drop(&mut self) {
        panic!("Dropped!");
    }
}

#[test]
fn test_eq_size() {
    assert_eq_size!([u8; 2], u16);
    assert_eq_size!([u8; 2], u16, (u8, u8));
    assert_eq_size!([u8; 4], u32, (u16, u8, u8), (u16, u16));

    assert_eq_size_val!([0u8; 2], 0u16);
    assert_eq_size_val!([0u8; 2], 0u16, (0u8, 0u8));
    assert_eq_size_val!([0u8; 4], 0u32, (0u16, 0u8, 0u8), (0u16, 0u16));

    #[deny(unused_unsafe)]
    unsafe {
        assert_eq_size!(u8, u8);
        assert_eq_size_val!(0u8, 0u8);
    }

    // Should fail to compile (un-comment to test manually):
    // assert_eq_size!(u8, u16);
    // assert_eq_size_val!(0u8, 0u16);
}

#[test]
fn test_eq_size_no_drop() {
    assert_eq_size!(u32, PanicDrop<u32>);
    assert_eq_size!(PanicDrop<u32>, u32);
    assert_eq_size!(PanicDrop<u32>, PanicDrop<u32>);
}

#[test]
fn test_eq_size_drop_count() {
    let mut count = 0;
    {
        let dc = DropCounter::new(&mut count);
        assert_eq!(dc.count(), 1);
        assert_eq_size_val!(dc, 0usize);
        assert_eq!(dc.count(), 1);
        assert_eq_size_val!(dc, 0usize, dc);
        assert_eq!(dc.count(), 1);
    }
    assert_eq!(count, 0);

    assert_eq_size_val!(DropCounter::new(&mut count), 0usize);
    assert_eq!(count, 0);
}

// This test is expected to fail at compile-time
#[cfg(feature = "failure")]
#[test]
fn test_fail() {
    assert_eq_size!(u8, u32);
    assert_eq_size!(u8, u32, u64);
    assert_eq_size!([u8; 1], u8, u8, u64);
}
<|endoftext|>


<commit_before>use gfx::{self, Factory, Resources};
use gfx::format::{Rgba8, TextureFormat};
use gfx::handle::{Sampler, ShaderResourceView};
use gfx::texture::{AaMode, FilterMethod, Kind, SamplerInfo, WrapMode};
use image;
use std::path::Path;

#[derive(Clone)]
pub struct Texture<R, T>
    where R: Resources,
          T: TextureFormat
{
    pub surface: gfx::handle::Texture<R, T::Surface>,
    pub view: ShaderResourceView<R, T::View>,
    pub sampler: Sampler<R>,
}

impl<R, T> Texture<R, T>
    where R: Resources,
          T: TextureFormat
{
    pub fn from_file<F, P>(factory: &mut F, path: P) -> Self
        where F: Factory<R>,
              P: AsRef<Path>
    {
        // TODO: Return a `Result` and expose any errors from `image::open`.
        let data = image::open(path).unwrap().to_rgba();
        let (width, height) = data.dimensions();
        let (surface, view) = factory.create_texture_immutable_u8::<T>(
            Kind::D2(width as u16, height as u16, AaMode::Single),
            &[data.into_vec().as_slice()]).unwrap();
        Texture {
            surface: surface,
            view: view,
            sampler: factory.create_sampler(
                SamplerInfo::new(FilterMethod::Trilinear, WrapMode::Tile)),
        }
    }
}

impl<R, T> Texture<R, T>
    where R: Resources,
          T: TextureFormat,
          T::View: Clone
{
    pub fn to_pipeline_data(&self) -> (ShaderResourceView<R, T::View>, Sampler<R>) {
        (self.view.clone(), self.sampler.clone())
    }
}

impl<R> Texture<R, Rgba8>
    where R: Resources
{
    pub fn white<F>(factory: &mut F) -> Self
        where F: Factory<R>
    {
        let max = u8::max_value();
        let (surface, view) = factory.create_texture_immutable_u8::<Rgba8>(
            Kind::D2(1, 1, AaMode::Single),
            &[&[max, max, max, max]]).unwrap();
        Texture {
            surface: surface,
            view: view,
            sampler: factory.create_sampler(
                SamplerInfo::new(FilterMethod::Trilinear, WrapMode::Tile)),
        }
    }
}
<commit_msg>Limit `from_file` to 8-bit, normalized, unsigned RGBA formats.<commit_after>use gfx::{self, Factory, Resources};
use gfx::format::{R8_G8_B8_A8, Rgba8, Srgb, TextureChannel, TextureFormat, Unorm};
use gfx::handle::{Sampler, ShaderResourceView};
use gfx::texture::{AaMode, FilterMethod, Kind, SamplerInfo, WrapMode};
use image;
use std::path::Path;

pub trait NormalizedChannel {}
pub trait UnsignedChannel {}

impl NormalizedChannel for Srgb {}
impl NormalizedChannel for Unorm {}

impl UnsignedChannel for Srgb {}
impl UnsignedChannel for Unorm {}

#[derive(Clone)]
pub struct Texture<R, T>
    where R: Resources,
          T: TextureFormat
{
    pub surface: gfx::handle::Texture<R, T::Surface>,
    pub view: ShaderResourceView<R, T::View>,
    pub sampler: Sampler<R>,
}

impl<R, C> Texture<R, (R8_G8_B8_A8, C)>
    where R: Resources,
          C: NormalizedChannel + TextureChannel + UnsignedChannel,
          (R8_G8_B8_A8, C): TextureFormat
{
    pub fn from_file<F, P>(factory: &mut F, path: P) -> Self
        where F: Factory<R>,
              P: AsRef<Path>
    {
        // TODO: Return a `Result` and expose any errors from `image::open`.
        let data = image::open(path).unwrap().to_rgba();
        let (width, height) = data.dimensions();
        let (surface, view) = factory.create_texture_immutable_u8::<(R8_G8_B8_A8, C)>(
            Kind::D2(width as u16, height as u16, AaMode::Single),
            &[data.into_vec().as_slice()]).unwrap();
        Texture {
            surface: surface,
            view: view,
            sampler: factory.create_sampler(
                SamplerInfo::new(FilterMethod::Trilinear, WrapMode::Tile)),
        }
    }
}

impl<R, T> Texture<R, T>
    where R: Resources,
          T: TextureFormat,
          T::View: Clone
{
    pub fn to_pipeline_data(&self) -> (ShaderResourceView<R, T::View>, Sampler<R>) {
        (self.view.clone(), self.sampler.clone())
    }
}

impl<R> Texture<R, Rgba8>
    where R: Resources
{
    pub fn white<F>(factory: &mut F) -> Self
        where F: Factory<R>
    {
        let max = u8::max_value();
        let (surface, view) = factory.create_texture_immutable_u8::<Rgba8>(
            Kind::D2(1, 1, AaMode::Single),
            &[&[max, max, max, max]]).unwrap();
        Texture {
            surface: surface,
            view: view,
            sampler: factory.create_sampler(
                SamplerInfo::new(FilterMethod::Trilinear, WrapMode::Tile)),
        }
    }
}
<|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/. */

extern crate egl;
#[macro_use] extern crate log;
extern crate servo;
extern crate smallvec;

use egl::egl::EGLContext;
use egl::egl::EGLDisplay;
use egl::egl::EGLSurface;
use egl::egl::MakeCurrent;
use egl::egl::SwapBuffers;
use egl::eglext::eglGetProcAddress;
use servo::BrowserId;
use servo::Servo;
use servo::compositing::windowing::AnimationState;
use servo::compositing::windowing::EmbedderCoordinates;
use servo::compositing::windowing::MouseWindowEvent;
use servo::compositing::windowing::WindowEvent;
use servo::compositing::windowing::WindowMethods;
use servo::embedder_traits::EmbedderMsg;
use servo::embedder_traits::EventLoopWaker;
use servo::embedder_traits::resources::Resource;
use servo::embedder_traits::resources::ResourceReaderMethods;
use servo::euclid::TypedPoint2D;
use servo::euclid::TypedRect;
use servo::euclid::TypedScale;
use servo::euclid::TypedSize2D;
use servo::gl;
use servo::gl::Gl;
use servo::gl::GlesFns;
use servo::msg::constellation_msg::TraversalDirection;
use servo::script_traits::MouseButton;
use servo::servo_url::ServoUrl;
use servo::webrender_api::DevicePoint;
use smallvec::SmallVec;
use std::ffi::CStr;
use std::ffi::CString;
use std::io::Write;
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use std::time::Instant;

#[repr(u32)]
pub enum MLLogLevel {
    Fatal = 0,
    Error = 1,
    Warning = 2,
    Info = 3,
    Debug = 4,
    Verbose = 5,
}

#[repr(transparent)]
pub struct MLLogger(extern "C" fn (MLLogLevel, *const c_char));

#[repr(transparent)]
pub struct MLHistoryUpdate(extern "C" fn (MLApp, bool, *const c_char, bool));

#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct MLApp(*mut c_void);

const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;

#[no_mangle]
pub unsafe extern "C" fn init_servo(ctxt: EGLContext,
                                    surf: EGLSurface,
                                    disp: EGLDisplay,
                                    app: MLApp,
                                    logger: MLLogger,
                                    history_update: MLHistoryUpdate,
                                    url: *const c_char,
                                    width: u32,
                                    height: u32,
                                    hidpi: f32) -> *mut ServoInstance
{
    // Servo initialization goes here!
    servo::embedder_traits::resources::set(Box::new(ResourceReaderInstance::new()));
    let _ = log::set_boxed_logger(Box::new(logger));
    log::set_max_level(LOG_LEVEL);
    let gl = GlesFns::load_with(|symbol| {
        let cstr = CString::new(symbol).expect("Failed to convert GL symbol to a char*");
        eglGetProcAddress(cstr.as_ptr() as _) as _
    });

    info!("OpenGL version {}", gl.get_string(gl::VERSION));
    let window = Rc::new(WindowInstance {
        ctxt: ctxt,
        surf: surf,
        disp: disp,
        gl: gl,
        width: width,
        height: height,
        hidpi: hidpi,
    });

    info!("Starting servo");
    let mut servo = Servo::new(window);
    let browser_id = BrowserId::new();

    let blank_url = ServoUrl::parse("about:blank").expect("Failed to parse about:blank!");
    let url = CStr::from_ptr(url).to_str().unwrap_or("about:blank");
    let url = ServoUrl::parse(url).unwrap_or(blank_url);
    servo.handle_events(vec![
        WindowEvent::NewBrowser(url, browser_id),
    ]);

    let result = Box::new(ServoInstance {
        app: app,
        browser_id: browser_id,
        history_update: history_update,
        servo: servo,
    });
    Box::into_raw(result)
}

#[no_mangle]
pub unsafe extern "C" fn heartbeat_servo(servo: *mut ServoInstance) {
    // Servo heartbeat goes here!
    if let Some(servo) = servo.as_mut() {
        servo.servo.handle_events(vec![]);
        for ((_browser_id, event)) in servo.servo.get_events() {
            match event {
                // Respond to any messages with a response channel
                // to avoid deadlocking the constellation
                EmbedderMsg::AllowNavigation(_url, sender) => {
                    let _ = sender.send(true);
                },
                EmbedderMsg::GetSelectedBluetoothDevice(_, sender) => {
                    let _ = sender.send(None);
                },
                EmbedderMsg::AllowUnload(sender) => {
                    let _ = sender.send(true);
                },
                EmbedderMsg::Alert(_, sender) => {
                    let _ = sender.send(());
                },
                EmbedderMsg::AllowOpeningBrowser(sender) => {
                    let _ = sender.send(false);
                },
                // Update the history UI
                EmbedderMsg::HistoryChanged(urls, index) => {
                    if let Some(url) = urls.get(index) {
                        if let Ok(cstr) = CString::new(url.as_str()) {
                            let can_go_back = index > 0;
                            let can_go_fwd = (index + 1) < urls.len();
                            (servo.history_update.0)(servo.app, can_go_back, cstr.as_ptr(), can_go_fwd);
                        }
                    }
                },
                // Ignore most messages for now
                EmbedderMsg::ChangePageTitle(..) |
                EmbedderMsg::BrowserCreated(..) |
                EmbedderMsg::LoadStart |
                EmbedderMsg::LoadComplete |
                EmbedderMsg::CloseBrowser |
                EmbedderMsg::Status(..) |
                EmbedderMsg::SelectFiles(..) |
                EmbedderMsg::MoveTo(..) |
                EmbedderMsg::ResizeTo(..) |
                EmbedderMsg::Keyboard(..) |
                EmbedderMsg::SetCursor(..) |
                EmbedderMsg::NewFavicon(..) |
                EmbedderMsg::HeadParsed |
                EmbedderMsg::SetFullscreenState(..) |
                EmbedderMsg::ShowIME(..) |
                EmbedderMsg::HideIME |
                EmbedderMsg::Shutdown |
                EmbedderMsg::Panic(..) => {},
            }
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn cursor_servo(servo: *mut ServoInstance, x: f32, y: f32, trigger: bool) {
    // Servo was triggered
    if let Some(servo) = servo.as_mut() {
        let point = DevicePoint::new(x, y);
        let window_event = if trigger {
            WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(MouseButton::Left, point))
        } else {
            WindowEvent::MouseWindowMoveEventClass(point)
        };
        servo.servo.handle_events(vec![window_event]);
    }
}

#[no_mangle]
pub unsafe extern "C" fn traverse_servo(servo: *mut ServoInstance, delta: i32) {
    // Traverse the session history
    if let Some(servo) = servo.as_mut() {
        let window_event = if delta == 0 {
            WindowEvent::Reload(servo.browser_id)
        } else if delta < 0 {
            WindowEvent::Navigation(servo.browser_id, TraversalDirection::Back(-delta as usize))
        } else {
            WindowEvent::Navigation(servo.browser_id, TraversalDirection::Forward(delta as usize))
        };
        servo.servo.handle_events(vec![window_event]);
    }
}

#[no_mangle]
pub unsafe extern "C" fn navigate_servo(servo: *mut ServoInstance, text: *const c_char) {
    if let Some(servo) = servo.as_mut() {
        let text = CStr::from_ptr(text).to_str().expect("Failed to convert text to UTF-8");
        let url = ServoUrl::parse(text).unwrap_or_else(|_| {
            let mut search = ServoUrl::parse("http://google.com/search")
               .expect("Failed to parse search URL")
               .into_url();
            search.query_pairs_mut().append_pair("q", text);
            ServoUrl::from_url(search)
        });
        let window_event = WindowEvent::LoadUrl(servo.browser_id, url);
        servo.servo.handle_events(vec![window_event]);
    }
}

// Some magic numbers for shutdown
const SHUTDOWN_DURATION: Duration = Duration::from_secs(10);
const SHUTDOWN_POLL_INTERVAL: Duration = Duration::from_millis(100);

#[no_mangle]
pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) {
    if let Some(servo) = servo.as_mut() {
        let mut servo = Box::from_raw(servo);
        let finish = Instant::now() + SHUTDOWN_DURATION;
        'outer: while Instant::now() < finish {
            servo.servo.handle_events(vec![WindowEvent::Quit]);
            for (_, msg) in servo.servo.get_events() {
                if let EmbedderMsg::Shutdown = msg {
                    break 'outer;
                }
            }
            thread::sleep(SHUTDOWN_POLL_INTERVAL);
        }
        servo.servo.deinit();
    }
}

pub struct ServoInstance {
    app: MLApp,
    browser_id: BrowserId,
    history_update: MLHistoryUpdate,
    servo: Servo<WindowInstance>,
}

struct WindowInstance {
    ctxt: EGLContext,
    surf: EGLSurface,
    disp: EGLDisplay,
    gl: Rc<Gl>,
    width: u32,
    height: u32,
    hidpi: f32,
}

impl WindowMethods for WindowInstance {
    fn present(&self) {
        SwapBuffers(self.disp, self.surf);
    }

    fn prepare_for_composite(&self) -> bool {
        MakeCurrent(self.disp, self.surf, self.surf, self.ctxt);
        self.gl.viewport(0, 0, self.width as i32, self.height as i32);
        true
    }

    fn gl(&self) -> Rc<Gl> {
        self.gl.clone()
    }

    fn create_event_loop_waker(&self) -> Box<EventLoopWaker> {
        Box::new(EventLoopWakerInstance::new())
    }

    fn get_coordinates(&self) -> EmbedderCoordinates {
        EmbedderCoordinates {
            hidpi_factor: TypedScale::new(self.hidpi),
            screen: TypedSize2D::new(self.width, self.height),
            screen_avail: TypedSize2D::new(self.width, self.height),
            window: (TypedSize2D::new(self.width, self.height), TypedPoint2D::new(0, 0)),
            framebuffer: TypedSize2D::new(self.width, self.height),
            viewport: TypedRect::new(TypedPoint2D::new(0, 0), TypedSize2D::new(self.width, self.height)),
        }
    }

    fn set_animation_state(&self, _state: AnimationState) {
    }
}

struct EventLoopWakerInstance;

impl EventLoopWakerInstance {
    fn new() -> EventLoopWakerInstance {
        EventLoopWakerInstance
    }
}

impl EventLoopWaker for EventLoopWakerInstance {
    fn clone(&self) -> Box<EventLoopWaker + Send> {
        Box::new(EventLoopWakerInstance)
    }

    fn wake(&self) {
    }
}

struct ResourceReaderInstance;

impl ResourceReaderInstance {
    fn new() -> ResourceReaderInstance {
        ResourceReaderInstance
    }
}

impl ResourceReaderMethods for ResourceReaderInstance {
    fn read(&self, res: Resource) -> Vec<u8> {
        Vec::from(match res {
            Resource::Preferences => &include_bytes!("../../../resources/prefs.json")[..],
            Resource::HstsPreloadList => &include_bytes!("../../../resources/hsts_preload.json")[..],
            Resource::SSLCertificates => &include_bytes!("../../../resources/certs")[..],
            Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..],
            Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..],
            Resource::UserAgentCSS => &include_bytes!("../../../resources/user-agent.css")[..],
            Resource::ServoCSS => &include_bytes!("../../../resources/servo.css")[..],
            Resource::PresentationalHintsCSS => &include_bytes!("../../../resources/presentational-hints.css")[..],
            Resource::QuirksModeCSS => &include_bytes!("../../../resources/quirks-mode.css")[..],
            Resource::RippyPNG => &include_bytes!("../../../resources/rippy.png")[..],
            Resource::DomainList => &include_bytes!("../../../resources/public_domains.txt")[..],
            Resource::BluetoothBlocklist => &include_bytes!("../../../resources/gatt_blocklist.txt")[..],
        })
    }

    fn sandbox_access_files(&self) -> Vec<PathBuf> {
        vec![]
    }

    fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
        vec![]
    }
}

impl log::Log for MLLogger {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= LOG_LEVEL
    }

    fn log(&self, record: &log::Record) {
        let lvl = match record.level() {
            log::Level::Error => MLLogLevel::Error,
            log::Level::Warn => MLLogLevel::Warning,
            log::Level::Info => MLLogLevel::Info,
            log::Level::Debug => MLLogLevel::Debug,
            log::Level::Trace => MLLogLevel::Verbose,
        };
        let mut msg = SmallVec::<[c_char; 128]>::new();
        write!(msg, "{}\0", record.args());
        (self.0)(lvl, &msg[0] as *const _ as *const _);
    }

    fn flush(&self) {}
}
<commit_msg>Responding to review comments<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/. */

extern crate egl;
#[macro_use] extern crate log;
extern crate servo;
extern crate smallvec;

use egl::egl::EGLContext;
use egl::egl::EGLDisplay;
use egl::egl::EGLSurface;
use egl::egl::MakeCurrent;
use egl::egl::SwapBuffers;
use egl::eglext::eglGetProcAddress;
use servo::BrowserId;
use servo::Servo;
use servo::compositing::windowing::AnimationState;
use servo::compositing::windowing::EmbedderCoordinates;
use servo::compositing::windowing::MouseWindowEvent;
use servo::compositing::windowing::WindowEvent;
use servo::compositing::windowing::WindowMethods;
use servo::embedder_traits::EmbedderMsg;
use servo::embedder_traits::EventLoopWaker;
use servo::embedder_traits::resources::Resource;
use servo::embedder_traits::resources::ResourceReaderMethods;
use servo::euclid::TypedPoint2D;
use servo::euclid::TypedRect;
use servo::euclid::TypedScale;
use servo::euclid::TypedSize2D;
use servo::gl;
use servo::gl::Gl;
use servo::gl::GlesFns;
use servo::msg::constellation_msg::TraversalDirection;
use servo::script_traits::MouseButton;
use servo::servo_url::ServoUrl;
use servo::webrender_api::DevicePoint;
use smallvec::SmallVec;
use std::ffi::CStr;
use std::ffi::CString;
use std::io::Write;
use std::os::raw::c_char;
use std::os::raw::c_void;
use std::path::PathBuf;
use std::rc::Rc;
use std::thread;
use std::time::Duration;
use std::time::Instant;

#[repr(u32)]
pub enum MLLogLevel {
    Fatal = 0,
    Error = 1,
    Warning = 2,
    Info = 3,
    Debug = 4,
    Verbose = 5,
}

#[repr(transparent)]
pub struct MLLogger(extern "C" fn (MLLogLevel, *const c_char));

#[repr(transparent)]
pub struct MLHistoryUpdate(extern "C" fn (MLApp, bool, *const c_char, bool));

#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct MLApp(*mut c_void);

const LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;

#[no_mangle]
pub unsafe extern "C" fn init_servo(ctxt: EGLContext,
                                    surf: EGLSurface,
                                    disp: EGLDisplay,
                                    app: MLApp,
                                    logger: MLLogger,
                                    history_update: MLHistoryUpdate,
                                    url: *const c_char,
                                    width: u32,
                                    height: u32,
                                    hidpi: f32) -> *mut ServoInstance
{
    // Servo initialization goes here!
    servo::embedder_traits::resources::set(Box::new(ResourceReaderInstance::new()));
    let _ = log::set_boxed_logger(Box::new(logger));
    log::set_max_level(LOG_LEVEL);
    let gl = GlesFns::load_with(|symbol| {
        let cstr = CString::new(symbol).expect("Failed to convert GL symbol to a char*");
        eglGetProcAddress(cstr.as_ptr() as _) as _
    });

    info!("OpenGL version {}", gl.get_string(gl::VERSION));
    let window = Rc::new(WindowInstance {
        ctxt: ctxt,
        surf: surf,
        disp: disp,
        gl: gl,
        width: width,
        height: height,
        hidpi: hidpi,
    });

    info!("Starting servo");
    let mut servo = Servo::new(window);
    let browser_id = BrowserId::new();

    let blank_url = ServoUrl::parse("about:blank").expect("Failed to parse about:blank!");
    let url = CStr::from_ptr(url).to_str().unwrap_or("about:blank");
    let url = ServoUrl::parse(url).unwrap_or(blank_url);
    servo.handle_events(vec![
        WindowEvent::NewBrowser(url, browser_id),
    ]);

    let result = Box::new(ServoInstance {
        app: app,
        browser_id: browser_id,
        history_update: history_update,
        servo: servo,
    });
    Box::into_raw(result)
}

#[no_mangle]
pub unsafe extern "C" fn heartbeat_servo(servo: *mut ServoInstance) {
    // Servo heartbeat goes here!
    if let Some(servo) = servo.as_mut() {
        servo.servo.handle_events(vec![]);
        for ((_browser_id, event)) in servo.servo.get_events() {
            match event {
                // Respond to any messages with a response channel
                // to avoid deadlocking the constellation
                EmbedderMsg::AllowNavigation(_url, sender) => {
                    let _ = sender.send(true);
                },
                EmbedderMsg::GetSelectedBluetoothDevice(_, sender) => {
                    let _ = sender.send(None);
                },
                EmbedderMsg::AllowUnload(sender) => {
                    let _ = sender.send(true);
                },
                EmbedderMsg::Alert(_, sender) => {
                    let _ = sender.send(());
                },
                EmbedderMsg::AllowOpeningBrowser(sender) => {
                    let _ = sender.send(false);
                },
                // Update the history UI
                EmbedderMsg::HistoryChanged(urls, index) => {
                    if let Some(url) = urls.get(index) {
                        if let Ok(cstr) = CString::new(url.as_str()) {
                            let can_go_back = index > 0;
                            let can_go_fwd = (index + 1) < urls.len();
                            (servo.history_update.0)(servo.app, can_go_back, cstr.as_ptr(), can_go_fwd);
                        }
                    }
                },
                // Ignore most messages for now
                EmbedderMsg::ChangePageTitle(..) |
                EmbedderMsg::BrowserCreated(..) |
                EmbedderMsg::LoadStart |
                EmbedderMsg::LoadComplete |
                EmbedderMsg::CloseBrowser |
                EmbedderMsg::Status(..) |
                EmbedderMsg::SelectFiles(..) |
                EmbedderMsg::MoveTo(..) |
                EmbedderMsg::ResizeTo(..) |
                EmbedderMsg::Keyboard(..) |
                EmbedderMsg::SetCursor(..) |
                EmbedderMsg::NewFavicon(..) |
                EmbedderMsg::HeadParsed |
                EmbedderMsg::SetFullscreenState(..) |
                EmbedderMsg::ShowIME(..) |
                EmbedderMsg::HideIME |
                EmbedderMsg::Shutdown |
                EmbedderMsg::Panic(..) => {},
            }
        }
    }
}

#[no_mangle]
pub unsafe extern "C" fn cursor_servo(servo: *mut ServoInstance, x: f32, y: f32, trigger: bool) {
    // Servo was triggered
    if let Some(servo) = servo.as_mut() {
        let point = DevicePoint::new(x, y);
        let window_event = if trigger {
            WindowEvent::MouseWindowEventClass(MouseWindowEvent::Click(MouseButton::Left, point))
        } else {
            WindowEvent::MouseWindowMoveEventClass(point)
        };
        servo.servo.handle_events(vec![window_event]);
    }
}

#[no_mangle]
pub unsafe extern "C" fn traverse_servo(servo: *mut ServoInstance, delta: i32) {
    // Traverse the session history
    if let Some(servo) = servo.as_mut() {
        let window_event = if delta == 0 {
            WindowEvent::Reload(servo.browser_id)
        } else if delta < 0 {
            WindowEvent::Navigation(servo.browser_id, TraversalDirection::Back(-delta as usize))
        } else {
            WindowEvent::Navigation(servo.browser_id, TraversalDirection::Forward(delta as usize))
        };
        servo.servo.handle_events(vec![window_event]);
    }
}

#[no_mangle]
pub unsafe extern "C" fn navigate_servo(servo: *mut ServoInstance, text: *const c_char) {
    if let Some(servo) = servo.as_mut() {
        let text = CStr::from_ptr(text).to_str().expect("Failed to convert text to UTF-8");
        let url = ServoUrl::parse(text).unwrap_or_else(|_| {
            let mut search = ServoUrl::parse("http://google.com/search")
               .expect("Failed to parse search URL")
               .into_url();
            search.query_pairs_mut().append_pair("q", text);
            ServoUrl::from_url(search)
        });
        let window_event = WindowEvent::LoadUrl(servo.browser_id, url);
        servo.servo.handle_events(vec![window_event]);
    }
}

// Some magic numbers for shutdown
const SHUTDOWN_DURATION: Duration = Duration::from_secs(10);
const SHUTDOWN_POLL_INTERVAL: Duration = Duration::from_millis(100);

#[no_mangle]
pub unsafe extern "C" fn discard_servo(servo: *mut ServoInstance) {
    if let Some(servo) = servo.as_mut() {
        let mut servo = Box::from_raw(servo);
        let finish = Instant::now() + SHUTDOWN_DURATION;
        servo.servo.handle_events(vec![WindowEvent::Quit]);
        'outer: loop {
            for (_, msg) in servo.servo.get_events() {
                if let EmbedderMsg::Shutdown = msg {
                    break 'outer;
                }
            }
            if Instant::now() > finish {
	       warn!("Incomplete shutdown.");
               break 'outer;
	    }
            thread::sleep(SHUTDOWN_POLL_INTERVAL);
            servo.servo.handle_events(vec![]);
        }
        servo.servo.deinit();
    }
}

pub struct ServoInstance {
    app: MLApp,
    browser_id: BrowserId,
    history_update: MLHistoryUpdate,
    servo: Servo<WindowInstance>,
}

struct WindowInstance {
    ctxt: EGLContext,
    surf: EGLSurface,
    disp: EGLDisplay,
    gl: Rc<Gl>,
    width: u32,
    height: u32,
    hidpi: f32,
}

impl WindowMethods for WindowInstance {
    fn present(&self) {
        SwapBuffers(self.disp, self.surf);
    }

    fn prepare_for_composite(&self) -> bool {
        MakeCurrent(self.disp, self.surf, self.surf, self.ctxt);
        self.gl.viewport(0, 0, self.width as i32, self.height as i32);
        true
    }

    fn gl(&self) -> Rc<Gl> {
        self.gl.clone()
    }

    fn create_event_loop_waker(&self) -> Box<EventLoopWaker> {
        Box::new(EventLoopWakerInstance::new())
    }

    fn get_coordinates(&self) -> EmbedderCoordinates {
        EmbedderCoordinates {
            hidpi_factor: TypedScale::new(self.hidpi),
            screen: TypedSize2D::new(self.width, self.height),
            screen_avail: TypedSize2D::new(self.width, self.height),
            window: (TypedSize2D::new(self.width, self.height), TypedPoint2D::new(0, 0)),
            framebuffer: TypedSize2D::new(self.width, self.height),
            viewport: TypedRect::new(TypedPoint2D::new(0, 0), TypedSize2D::new(self.width, self.height)),
        }
    }

    fn set_animation_state(&self, _state: AnimationState) {
    }
}

struct EventLoopWakerInstance;

impl EventLoopWakerInstance {
    fn new() -> EventLoopWakerInstance {
        EventLoopWakerInstance
    }
}

impl EventLoopWaker for EventLoopWakerInstance {
    fn clone(&self) -> Box<EventLoopWaker + Send> {
        Box::new(EventLoopWakerInstance)
    }

    fn wake(&self) {
    }
}

struct ResourceReaderInstance;

impl ResourceReaderInstance {
    fn new() -> ResourceReaderInstance {
        ResourceReaderInstance
    }
}

impl ResourceReaderMethods for ResourceReaderInstance {
    fn read(&self, res: Resource) -> Vec<u8> {
        Vec::from(match res {
            Resource::Preferences => &include_bytes!("../../../resources/prefs.json")[..],
            Resource::HstsPreloadList => &include_bytes!("../../../resources/hsts_preload.json")[..],
            Resource::SSLCertificates => &include_bytes!("../../../resources/certs")[..],
            Resource::BadCertHTML => &include_bytes!("../../../resources/badcert.html")[..],
            Resource::NetErrorHTML => &include_bytes!("../../../resources/neterror.html")[..],
            Resource::UserAgentCSS => &include_bytes!("../../../resources/user-agent.css")[..],
            Resource::ServoCSS => &include_bytes!("../../../resources/servo.css")[..],
            Resource::PresentationalHintsCSS => &include_bytes!("../../../resources/presentational-hints.css")[..],
            Resource::QuirksModeCSS => &include_bytes!("../../../resources/quirks-mode.css")[..],
            Resource::RippyPNG => &include_bytes!("../../../resources/rippy.png")[..],
            Resource::DomainList => &include_bytes!("../../../resources/public_domains.txt")[..],
            Resource::BluetoothBlocklist => &include_bytes!("../../../resources/gatt_blocklist.txt")[..],
        })
    }

    fn sandbox_access_files(&self) -> Vec<PathBuf> {
        vec![]
    }

    fn sandbox_access_files_dirs(&self) -> Vec<PathBuf> {
        vec![]
    }
}

impl log::Log for MLLogger {
    fn enabled(&self, metadata: &log::Metadata) -> bool {
        metadata.level() <= LOG_LEVEL
    }

    fn log(&self, record: &log::Record) {
        let lvl = match record.level() {
            log::Level::Error => MLLogLevel::Error,
            log::Level::Warn => MLLogLevel::Warning,
            log::Level::Info => MLLogLevel::Info,
            log::Level::Debug => MLLogLevel::Debug,
            log::Level::Trace => MLLogLevel::Verbose,
        };
        let mut msg = SmallVec::<[c_char; 128]>::new();
        write!(msg, "{}\0", record.args());
        (self.0)(lvl, &msg[0] as *const _ as *const _);
    }

    fn flush(&self) {}
}
<|endoftext|>


<commit_before>extern crate httpd = "tiny-http";

use std::io::timer;

#[allow(dead_code)]
mod support;

#[test]
fn connection_close_header() {
    let mut client = support::new_client_to_hello_world_server(2);

    (write!(client, "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n")).unwrap();
    timer::sleep(1000);

    (write!(client, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n")).unwrap();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn http_1_0_connection_close() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n")).unwrap();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn poor_network_test() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "G")).unwrap();
    timer::sleep(100);
    (write!(client, "ET /he")).unwrap();
    timer::sleep(100);
    (write!(client, "llo HT")).unwrap();
    timer::sleep(100);
    (write!(client, "TP/1.")).unwrap();
    timer::sleep(100);
    (write!(client, "1\r\nHo")).unwrap();
    timer::sleep(100);
    (write!(client, "st: localho")).unwrap();
    timer::sleep(100);
    (write!(client, "st\r\nConnec")).unwrap();
    timer::sleep(100);
    (write!(client, "tion: close\r")).unwrap();
    timer::sleep(100);
    (write!(client, "\n\r")).unwrap();
    timer::sleep(100);
    (write!(client, "\n")).unwrap();

    client.set_timeout(Some(200));
    let data = client.read_to_string().unwrap();
    assert!(data.as_slice().ends_with("hello world"));
}

#[test]
fn pipelining_test() {
    let mut client = support::new_client_to_hello_world_server(3);

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET /hello HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET /world HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")).unwrap();

    client.set_timeout(Some(200));
    let data = client.read_to_string().unwrap();
    assert_eq!(data.as_slice().split_str("hello world").count(), 4);
}

#[test]
fn server_crash_results_in_response() {
    use std::io::net::tcp::TcpStream;

    let (server, port) = httpd::Server::new_with_random_port().unwrap();
    let mut client = TcpStream::connect("127.0.0.1", port).unwrap();

    spawn(proc() {
        server.recv().unwrap();
        // oops, server crash
    });

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")).unwrap();

    client.set_timeout(Some(200));
    let content = client.read_to_string().unwrap();
    assert!(content.as_slice().slice_from(9).starts_with("5"));   // 5xx status code
}

#[test]
fn responses_reordered() {
    use std::io::timer;

    let (server, mut client) = support::new_one_server_one_client();

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")).unwrap();

    spawn(proc() {
        let rq1 = server.recv().unwrap();
        let rq2 = server.recv().unwrap();

        spawn(proc() {
            rq2.respond(httpd::Response::from_string(format!("second request")));
        });

        timer::sleep(100);

        spawn(proc() {
            rq1.respond(httpd::Response::from_string(format!("first request")));
        });
    });

    client.set_timeout(Some(200));
    let content = client.read_to_string().unwrap();
    assert!(content.as_slice().ends_with("second request"));
}
<commit_msg>Add detect_connection_closed test<commit_after>extern crate httpd = "tiny-http";

use std::io::timer;

#[allow(dead_code)]
mod support;

#[test]
fn connection_close_header() {
    let mut client = support::new_client_to_hello_world_server(2);

    (write!(client, "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n")).unwrap();
    timer::sleep(1000);

    (write!(client, "GET / HTTP/1.1\r\nConnection: close\r\n\r\n")).unwrap();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn http_1_0_connection_close() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "GET / HTTP/1.0\r\nHost: localhost\r\n\r\n")).unwrap();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn detect_connection_closed() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "GET / HTTP/1.1\r\nConnection: keep-alive\r\n\r\n")).unwrap();
    timer::sleep(1000);

    client.close_write();

    // if the connection was not closed, this will err with timeout
    client.set_timeout(Some(100));
    client.read_to_end().unwrap();
}

#[test]
fn poor_network_test() {
    let mut client = support::new_client_to_hello_world_server(1);

    (write!(client, "G")).unwrap();
    timer::sleep(100);
    (write!(client, "ET /he")).unwrap();
    timer::sleep(100);
    (write!(client, "llo HT")).unwrap();
    timer::sleep(100);
    (write!(client, "TP/1.")).unwrap();
    timer::sleep(100);
    (write!(client, "1\r\nHo")).unwrap();
    timer::sleep(100);
    (write!(client, "st: localho")).unwrap();
    timer::sleep(100);
    (write!(client, "st\r\nConnec")).unwrap();
    timer::sleep(100);
    (write!(client, "tion: close\r")).unwrap();
    timer::sleep(100);
    (write!(client, "\n\r")).unwrap();
    timer::sleep(100);
    (write!(client, "\n")).unwrap();

    client.set_timeout(Some(200));
    let data = client.read_to_string().unwrap();
    assert!(data.as_slice().ends_with("hello world"));
}

#[test]
fn pipelining_test() {
    let mut client = support::new_client_to_hello_world_server(3);

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET /hello HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET /world HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")).unwrap();

    client.set_timeout(Some(200));
    let data = client.read_to_string().unwrap();
    assert_eq!(data.as_slice().split_str("hello world").count(), 4);
}

#[test]
fn server_crash_results_in_response() {
    use std::io::net::tcp::TcpStream;

    let (server, port) = httpd::Server::new_with_random_port().unwrap();
    let mut client = TcpStream::connect("127.0.0.1", port).unwrap();

    spawn(proc() {
        server.recv().unwrap();
        // oops, server crash
    });

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")).unwrap();

    client.set_timeout(Some(200));
    let content = client.read_to_string().unwrap();
    assert!(content.as_slice().slice_from(9).starts_with("5"));   // 5xx status code
}

#[test]
fn responses_reordered() {
    use std::io::timer;

    let (server, mut client) = support::new_one_server_one_client();

    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")).unwrap();
    (write!(client, "GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n")).unwrap();

    spawn(proc() {
        let rq1 = server.recv().unwrap();
        let rq2 = server.recv().unwrap();

        spawn(proc() {
            rq2.respond(httpd::Response::from_string(format!("second request")));
        });

        timer::sleep(100);

        spawn(proc() {
            rq1.respond(httpd::Response::from_string(format!("first request")));
        });
    });

    client.set_timeout(Some(200));
    let content = client.read_to_string().unwrap();
    assert!(content.as_slice().ends_with("second request"));
}
<|endoftext|>


<commit_before>//! NVPTX intrinsics (experimental)
//!
//! These intrinsics form the foundation of the CUDA
//! programming model.
//!
//! The reference is the [CUDA C Programming Guide][cuda_c]. Relevant is also
//! the [LLVM NVPTX Backend documentation][llvm_docs].
//!
//! [cuda_c]:
//! http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html
//! [llvm_docs]:
//! https://llvm.org/docs/NVPTXUsage.html

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

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.nvvm.barrier0"]
    fn syncthreads() -> ();
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.x"]
    fn block_dim_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.y"]
    fn block_dim_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.z"]
    fn block_dim_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.x"]
    fn block_idx_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.y"]
    fn block_idx_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.z"]
    fn block_idx_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.x"]
    fn grid_dim_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.y"]
    fn grid_dim_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.z"]
    fn grid_dim_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.x"]
    fn thread_idx_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.y"]
    fn thread_idx_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.z"]
    fn thread_idx_z() -> i32;
}

/// Synchronizes all threads in the block.
#[inline]
pub unsafe fn _syncthreads() -> () {
    syncthreads()
}

/// x-th thread-block dimension.
#[inline]
pub unsafe fn _block_dim_x() -> i32 {
    block_dim_x()
}

/// y-th thread-block dimension.
#[inline]
pub unsafe fn _block_dim_y() -> i32 {
    block_dim_y()
}

/// z-th thread-block dimension.
#[inline]
pub unsafe fn _block_dim_z() -> i32 {
    block_dim_z()
}

/// x-th thread-block index.
#[inline]
pub unsafe fn _block_idx_x() -> i32 {
    block_idx_x()
}

/// y-th thread-block index.
#[inline]
pub unsafe fn _block_idx_y() -> i32 {
    block_idx_y()
}

/// z-th thread-block index.
#[inline]
pub unsafe fn _block_idx_z() -> i32 {
    block_idx_z()
}

/// x-th block-grid dimension.
#[inline]
pub unsafe fn _grid_dim_x() -> i32 {
    grid_dim_x()
}

/// y-th block-grid dimension.
#[inline]
pub unsafe fn _grid_dim_y() -> i32 {
    grid_dim_y()
}

/// z-th block-grid dimension.
#[inline]
pub unsafe fn _grid_dim_z() -> i32 {
    grid_dim_z()
}

/// x-th thread index.
#[inline]
pub unsafe fn _thread_idx_x() -> i32 {
    thread_idx_x()
}

/// y-th thread index.
#[inline]
pub unsafe fn _thread_idx_y() -> i32 {
    thread_idx_y()
}

/// z-th thread index.
#[inline]
pub unsafe fn _thread_idx_z() -> i32 {
    thread_idx_z()
}

/// Generates the trap instruction `TRAP`
#[cfg_attr(test, assert_instr(trap))]
#[inline]
pub unsafe fn trap() -> ! {
    ::_core::intrinsics::abort()
}
<commit_msg>remove assert_instr from nvptx<commit_after>//! NVPTX intrinsics (experimental)
//!
//! These intrinsics form the foundation of the CUDA
//! programming model.
//!
//! The reference is the [CUDA C Programming Guide][cuda_c]. Relevant is also
//! the [LLVM NVPTX Backend documentation][llvm_docs].
//!
//! [cuda_c]:
//! http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html
//! [llvm_docs]:
//! https://llvm.org/docs/NVPTXUsage.html

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

#[allow(improper_ctypes)]
extern "C" {
    #[link_name = "llvm.nvvm.barrier0"]
    fn syncthreads() -> ();
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.x"]
    fn block_dim_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.y"]
    fn block_dim_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ntid.z"]
    fn block_dim_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.x"]
    fn block_idx_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.y"]
    fn block_idx_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.ctaid.z"]
    fn block_idx_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.x"]
    fn grid_dim_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.y"]
    fn grid_dim_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.nctaid.z"]
    fn grid_dim_z() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.x"]
    fn thread_idx_x() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.y"]
    fn thread_idx_y() -> i32;
    #[link_name = "llvm.nvvm.read.ptx.sreg.tid.z"]
    fn thread_idx_z() -> i32;
}

/// Synchronizes all threads in the block.
#[inline]
pub unsafe fn _syncthreads() -> () {
    syncthreads()
}

/// x-th thread-block dimension.
#[inline]
pub unsafe fn _block_dim_x() -> i32 {
    block_dim_x()
}

/// y-th thread-block dimension.
#[inline]
pub unsafe fn _block_dim_y() -> i32 {
    block_dim_y()
}

/// z-th thread-block dimension.
#[inline]
pub unsafe fn _block_dim_z() -> i32 {
    block_dim_z()
}

/// x-th thread-block index.
#[inline]
pub unsafe fn _block_idx_x() -> i32 {
    block_idx_x()
}

/// y-th thread-block index.
#[inline]
pub unsafe fn _block_idx_y() -> i32 {
    block_idx_y()
}

/// z-th thread-block index.
#[inline]
pub unsafe fn _block_idx_z() -> i32 {
    block_idx_z()
}

/// x-th block-grid dimension.
#[inline]
pub unsafe fn _grid_dim_x() -> i32 {
    grid_dim_x()
}

/// y-th block-grid dimension.
#[inline]
pub unsafe fn _grid_dim_y() -> i32 {
    grid_dim_y()
}

/// z-th block-grid dimension.
#[inline]
pub unsafe fn _grid_dim_z() -> i32 {
    grid_dim_z()
}

/// x-th thread index.
#[inline]
pub unsafe fn _thread_idx_x() -> i32 {
    thread_idx_x()
}

/// y-th thread index.
#[inline]
pub unsafe fn _thread_idx_y() -> i32 {
    thread_idx_y()
}

/// z-th thread index.
#[inline]
pub unsafe fn _thread_idx_z() -> i32 {
    thread_idx_z()
}

/// Generates the trap instruction `TRAP`
#[inline]
pub unsafe fn trap() -> ! {
    ::_core::intrinsics::abort()
}
<|endoftext|>