<commit_before>use std::ptr;

use env::NapiEnv;
use result::NapiResult;
use sys;

mod any;
mod array;
mod boolean;
mod null;
mod number;
mod object;
mod string;
mod undefined;

pub use self::any::NapiAny;
pub use self::array::NapiArray;
pub use self::boolean::NapiBoolean;
pub use self::null::NapiNull;
pub use self::number::NapiNumber;
pub use self::object::NapiObject;
pub use self::string::NapiString;
pub use self::undefined::NapiUndefined;

pub trait NapiValue {
    fn as_sys_value(&self) -> sys::napi_value;
    fn env(&self) -> &NapiEnv;

    fn to_napi_boolean(&self) -> NapiResult<NapiBoolean> {
        coerce(self, sys::napi_coerce_to_bool)
    }

    fn to_napi_number(&self) -> NapiResult<NapiNumber> {
        coerce(self, sys::napi_coerce_to_number)
    }

    fn to_napi_object(&self) -> NapiResult<NapiObject> {
        coerce(self, sys::napi_coerce_to_object)
    }

    fn to_napi_string(&self) -> NapiResult<NapiString> {
        coerce(self, sys::napi_coerce_to_string)
    }

    fn as_any(&self) -> NapiAny {
        NapiAny::with_value(self.env(), self.as_sys_value())
    }

    fn instanceof(&self, constructor: &NapiObject) -> NapiResult<bool> {
        let env = self.env();
        let mut result = false;

        env.handle_status(unsafe {
            sys::napi_instanceof(
                env.as_sys_env(),
                self.as_sys_value(),
                constructor.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }

    fn is_array(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_array)
    }

    fn is_arraybuffer(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_arraybuffer)
    }

    fn is_buffer(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_buffer)
    }

    fn is_error(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_error)
    }

    fn is_typedarray(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_typedarray)
    }

    fn is_dataview(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_dataview)
    }
}

trait NapiValueInternal<'a>: NapiValue + 'a {
    fn construct(env: &'a NapiEnv, value: sys::napi_value) -> Self;
}

fn coerce<'a, T, U>(
    value: &'a T,
    napi_fn: unsafe extern "C" fn(
        sys::napi_env,
        sys::napi_value,
        *mut sys::napi_value,
    ) -> sys::napi_status,
) -> NapiResult<U>
where
    T: NapiValue + ?Sized,
    U: NapiValueInternal<'a>,
{
    let env = value.env();
    let mut coerced_value = ptr::null_mut();

    env.handle_status(unsafe {
        napi_fn(env.as_sys_env(), value.as_sys_value(), &mut coerced_value)
    })?;

    Ok(U::construct(env, coerced_value))
}

fn check_type<'a, T>(
    value: &'a T,
    napi_fn: unsafe extern "C" fn(sys::napi_env, sys::napi_value, *mut bool)
        -> sys::napi_status,
) -> NapiResult<bool>
where
    T: NapiValue + ?Sized,
{
    let env = value.env();
    let mut result = false;

    env.handle_status(unsafe {
        napi_fn(env.as_sys_env(), value.as_sys_value(), &mut result)
    })?;

    Ok(result)
}
<commit_msg>feat(napi): implement NapiValue::strict_equals<commit_after>use std::ptr;

use env::NapiEnv;
use result::NapiResult;
use sys;

mod any;
mod array;
mod boolean;
mod null;
mod number;
mod object;
mod string;
mod undefined;

pub use self::any::NapiAny;
pub use self::array::NapiArray;
pub use self::boolean::NapiBoolean;
pub use self::null::NapiNull;
pub use self::number::NapiNumber;
pub use self::object::NapiObject;
pub use self::string::NapiString;
pub use self::undefined::NapiUndefined;

pub trait NapiValue {
    fn as_sys_value(&self) -> sys::napi_value;
    fn env(&self) -> &NapiEnv;

    fn to_napi_boolean(&self) -> NapiResult<NapiBoolean> {
        coerce(self, sys::napi_coerce_to_bool)
    }

    fn to_napi_number(&self) -> NapiResult<NapiNumber> {
        coerce(self, sys::napi_coerce_to_number)
    }

    fn to_napi_object(&self) -> NapiResult<NapiObject> {
        coerce(self, sys::napi_coerce_to_object)
    }

    fn to_napi_string(&self) -> NapiResult<NapiString> {
        coerce(self, sys::napi_coerce_to_string)
    }

    fn as_any(&self) -> NapiAny {
        NapiAny::with_value(self.env(), self.as_sys_value())
    }

    fn instanceof(&self, constructor: &NapiObject) -> NapiResult<bool> {
        let env = self.env();
        let mut result = false;

        env.handle_status(unsafe {
            sys::napi_instanceof(
                env.as_sys_env(),
                self.as_sys_value(),
                constructor.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }

    fn is_array(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_array)
    }

    fn is_arraybuffer(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_arraybuffer)
    }

    fn is_buffer(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_buffer)
    }

    fn is_error(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_error)
    }

    fn is_typedarray(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_typedarray)
    }

    fn is_dataview(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_dataview)
    }

    fn strict_equals<T>(&self, other: &T) -> NapiResult<bool>
    where
        T: NapiValue + ?Sized,
    {
        let env = self.env();
        let mut result = false;

        env.handle_status(unsafe {
            sys::napi_strict_equals(
                env.as_sys_env(),
                self.as_sys_value(),
                other.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }
}

trait NapiValueInternal<'a>: NapiValue + 'a {
    fn construct(env: &'a NapiEnv, value: sys::napi_value) -> Self;
}

fn coerce<'a, T, U>(
    value: &'a T,
    napi_fn: unsafe extern "C" fn(
        sys::napi_env,
        sys::napi_value,
        *mut sys::napi_value,
    ) -> sys::napi_status,
) -> NapiResult<U>
where
    T: NapiValue + ?Sized,
    U: NapiValueInternal<'a>,
{
    let env = value.env();
    let mut coerced_value = ptr::null_mut();

    env.handle_status(unsafe {
        napi_fn(env.as_sys_env(), value.as_sys_value(), &mut coerced_value)
    })?;

    Ok(U::construct(env, coerced_value))
}

fn check_type<'a, T>(
    value: &'a T,
    napi_fn: unsafe extern "C" fn(sys::napi_env, sys::napi_value, *mut bool)
        -> sys::napi_status,
) -> NapiResult<bool>
where
    T: NapiValue + ?Sized,
{
    let env = value.env();
    let mut result = false;

    env.handle_status(unsafe {
        napi_fn(env.as_sys_env(), value.as_sys_value(), &mut result)
    })?;

    Ok(result)
}
<|endoftext|>


<commit_before>use std::ptr;

use env::NapiEnv;
use result::NapiResult;
use sys;

mod any;
mod array;
mod boolean;
mod null;
mod number;
mod object;
mod string;
mod undefined;

pub use self::any::NapiAny;
pub use self::array::NapiArray;
pub use self::boolean::NapiBoolean;
pub use self::null::NapiNull;
pub use self::number::NapiNumber;
pub use self::object::NapiObject;
pub use self::string::NapiString;
pub use self::undefined::NapiUndefined;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum NapiValueType {
    Undefined,
    Null,
    Boolean,
    Number,
    String,
    Symbol,
    Object,
    Function,
    External,
}

pub trait NapiValue {
    fn as_sys_value(&self) -> sys::napi_value;
    fn env(&self) -> &NapiEnv;

    fn to_napi_boolean(&self) -> NapiResult<NapiBoolean> {
        coerce(self, sys::napi_coerce_to_bool)
    }

    fn to_napi_number(&self) -> NapiResult<NapiNumber> {
        coerce(self, sys::napi_coerce_to_number)
    }

    fn to_napi_object(&self) -> NapiResult<NapiObject> {
        coerce(self, sys::napi_coerce_to_object)
    }

    fn to_napi_string(&self) -> NapiResult<NapiString> {
        coerce(self, sys::napi_coerce_to_string)
    }

    fn as_napi_any(&self) -> NapiAny {
        NapiAny::with_value(self.env(), self.as_sys_value())
    }

    fn value_type(&self) -> NapiResult<NapiValueType> {
        let env = self.env();
        let mut result = sys::napi_valuetype::napi_undefined;

        env.handle_status(unsafe {
            sys::napi_typeof(env.as_sys_env(), self.as_sys_value(), &mut result)
        })?;

        Ok(match result {
            sys::napi_valuetype::napi_undefined => NapiValueType::Undefined,
            sys::napi_valuetype::napi_null => NapiValueType::Null,
            sys::napi_valuetype::napi_boolean => NapiValueType::Boolean,
            sys::napi_valuetype::napi_number => NapiValueType::Number,
            sys::napi_valuetype::napi_string => NapiValueType::String,
            sys::napi_valuetype::napi_symbol => NapiValueType::Symbol,
            sys::napi_valuetype::napi_object => NapiValueType::Object,
            sys::napi_valuetype::napi_function => NapiValueType::Function,
            sys::napi_valuetype::napi_external => NapiValueType::External,
        })
    }

    fn instanceof(&self, constructor: &NapiObject) -> NapiResult<bool> {
        let env = self.env();
        let mut result = false;

        env.handle_status(unsafe {
            sys::napi_instanceof(
                env.as_sys_env(),
                self.as_sys_value(),
                constructor.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }

    fn is_array(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_array)
    }

    fn is_arraybuffer(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_arraybuffer)
    }

    fn is_buffer(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_buffer)
    }

    fn is_error(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_error)
    }

    fn is_typedarray(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_typedarray)
    }

    fn is_dataview(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_dataview)
    }

    fn strict_equals<T>(&self, other: &T) -> NapiResult<bool>
    where
        T: NapiValue + ?Sized,
    {
        let env = self.env();
        let mut result = false;

        env.handle_status(unsafe {
            sys::napi_strict_equals(
                env.as_sys_env(),
                self.as_sys_value(),
                other.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }
}

pub trait AsNapiObject: NapiValue {
    fn as_napi_object(&self) -> NapiObject {
        NapiObject::construct(self.env(), self.as_sys_value())
    }
}

trait NapiValueInternal<'a>: NapiValue + 'a {
    fn construct(env: &'a NapiEnv, value: sys::napi_value) -> Self;
}

fn coerce<'a, T, U>(
    value: &'a T,
    napi_fn: unsafe extern "C" fn(
        sys::napi_env,
        sys::napi_value,
        *mut sys::napi_value,
    ) -> sys::napi_status,
) -> NapiResult<U>
where
    T: NapiValue + ?Sized,
    U: NapiValueInternal<'a>,
{
    let env = value.env();
    let mut coerced_value = ptr::null_mut();

    env.handle_status(unsafe {
        napi_fn(env.as_sys_env(), value.as_sys_value(), &mut coerced_value)
    })?;

    Ok(U::construct(env, coerced_value))
}

fn check_type<'a, T>(
    value: &'a T,
    napi_fn: unsafe extern "C" fn(sys::napi_env, sys::napi_value, *mut bool)
        -> sys::napi_status,
) -> NapiResult<bool>
where
    T: NapiValue + ?Sized,
{
    let env = value.env();
    let mut result = false;

    env.handle_status(unsafe {
        napi_fn(env.as_sys_env(), value.as_sys_value(), &mut result)
    })?;

    Ok(result)
}
<commit_msg>style(napi): remove unnecessary lifetimes<commit_after>use std::ptr;

use env::NapiEnv;
use result::NapiResult;
use sys;

mod any;
mod array;
mod boolean;
mod null;
mod number;
mod object;
mod string;
mod undefined;

pub use self::any::NapiAny;
pub use self::array::NapiArray;
pub use self::boolean::NapiBoolean;
pub use self::null::NapiNull;
pub use self::number::NapiNumber;
pub use self::object::NapiObject;
pub use self::string::NapiString;
pub use self::undefined::NapiUndefined;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum NapiValueType {
    Undefined,
    Null,
    Boolean,
    Number,
    String,
    Symbol,
    Object,
    Function,
    External,
}

pub trait NapiValue {
    fn as_sys_value(&self) -> sys::napi_value;
    fn env(&self) -> &NapiEnv;

    fn to_napi_boolean(&self) -> NapiResult<NapiBoolean> {
        coerce(self, sys::napi_coerce_to_bool)
    }

    fn to_napi_number(&self) -> NapiResult<NapiNumber> {
        coerce(self, sys::napi_coerce_to_number)
    }

    fn to_napi_object(&self) -> NapiResult<NapiObject> {
        coerce(self, sys::napi_coerce_to_object)
    }

    fn to_napi_string(&self) -> NapiResult<NapiString> {
        coerce(self, sys::napi_coerce_to_string)
    }

    fn as_napi_any(&self) -> NapiAny {
        NapiAny::with_value(self.env(), self.as_sys_value())
    }

    fn value_type(&self) -> NapiResult<NapiValueType> {
        let env = self.env();
        let mut result = sys::napi_valuetype::napi_undefined;

        env.handle_status(unsafe {
            sys::napi_typeof(env.as_sys_env(), self.as_sys_value(), &mut result)
        })?;

        Ok(match result {
            sys::napi_valuetype::napi_undefined => NapiValueType::Undefined,
            sys::napi_valuetype::napi_null => NapiValueType::Null,
            sys::napi_valuetype::napi_boolean => NapiValueType::Boolean,
            sys::napi_valuetype::napi_number => NapiValueType::Number,
            sys::napi_valuetype::napi_string => NapiValueType::String,
            sys::napi_valuetype::napi_symbol => NapiValueType::Symbol,
            sys::napi_valuetype::napi_object => NapiValueType::Object,
            sys::napi_valuetype::napi_function => NapiValueType::Function,
            sys::napi_valuetype::napi_external => NapiValueType::External,
        })
    }

    fn instanceof(&self, constructor: &NapiObject) -> NapiResult<bool> {
        let env = self.env();
        let mut result = false;

        env.handle_status(unsafe {
            sys::napi_instanceof(
                env.as_sys_env(),
                self.as_sys_value(),
                constructor.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }

    fn is_array(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_array)
    }

    fn is_arraybuffer(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_arraybuffer)
    }

    fn is_buffer(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_buffer)
    }

    fn is_error(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_error)
    }

    fn is_typedarray(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_typedarray)
    }

    fn is_dataview(&self) -> NapiResult<bool> {
        check_type(self, sys::napi_is_dataview)
    }

    fn strict_equals<T>(&self, other: &T) -> NapiResult<bool>
    where
        T: NapiValue + ?Sized,
    {
        let env = self.env();
        let mut result = false;

        env.handle_status(unsafe {
            sys::napi_strict_equals(
                env.as_sys_env(),
                self.as_sys_value(),
                other.as_sys_value(),
                &mut result,
            )
        })?;

        Ok(result)
    }
}

pub trait AsNapiObject: NapiValue {
    fn as_napi_object(&self) -> NapiObject {
        NapiObject::construct(self.env(), self.as_sys_value())
    }
}

trait NapiValueInternal<'a>: NapiValue + 'a {
    fn construct(env: &'a NapiEnv, value: sys::napi_value) -> Self;
}

fn coerce<'a, T, U>(
    value: &'a T,
    napi_fn: unsafe extern "C" fn(
        sys::napi_env,
        sys::napi_value,
        *mut sys::napi_value,
    ) -> sys::napi_status,
) -> NapiResult<U>
where
    T: NapiValue + ?Sized,
    U: NapiValueInternal<'a>,
{
    let env = value.env();
    let mut coerced_value = ptr::null_mut();

    env.handle_status(unsafe {
        napi_fn(env.as_sys_env(), value.as_sys_value(), &mut coerced_value)
    })?;

    Ok(U::construct(env, coerced_value))
}

fn check_type<T>(
    value: &T,
    napi_fn: unsafe extern "C" fn(sys::napi_env, sys::napi_value, *mut bool)
        -> sys::napi_status,
) -> NapiResult<bool>
where
    T: NapiValue + ?Sized,
{
    let env = value.env();
    let mut result = false;

    env.handle_status(unsafe {
        napi_fn(env.as_sys_env(), value.as_sys_value(), &mut result)
    })?;

    Ok(result)
}
<|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/. */

// Servo, the mighty web browser engine from the future.
//
// This is a very simple library that wires all of Servo's components
// together as type `Browser`, along with a generic client
// implementing the `WindowMethods` trait, to create a working web
// browser.
//
// The `Browser` type is responsible for configuring a
// `Constellation`, which does the heavy lifting of coordinating all
// of Servo's internal subsystems, including the `ScriptTask` and the
// `LayoutTask`, as well maintains the navigation context.
//
// The `Browser` is fed events from a generic type that implements the
// `WindowMethods` trait.

extern crate compositing;
extern crate devtools;
extern crate devtools_traits;
extern crate net;
extern crate net_traits;
extern crate msg;
extern crate profile;
extern crate profile_traits;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate webdriver_server;

use compositing::CompositorEventListener;
use compositing::windowing::WindowEvent;

use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorTask, Constellation};

use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::ConstellationChan;

use script::dom::bindings::codegen::RegisterBindings;

use net::image_cache_task::new_image_cache_task;
use net::storage_task::StorageTaskFactory;
use net::resource_task::new_resource_task;
use net_traits::storage_task::StorageTask;

use gfx::font_cache_task::FontCacheTask;
use profile::mem as profile_mem;
use profile::time as profile_time;
use profile_traits::mem;
use profile_traits::time;
use util::opts;

use std::borrow::Borrow;
use std::rc::Rc;
use std::sync::mpsc::Sender;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
impl Browser {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
                       where Window: WindowMethods + 'static {
        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        script::init();
        // Create the global vtables used by the (generated) DOM
        // bindings to implement JS proxies.
        RegisterBindings::RegisterProxyHandlers();

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let supports_clipboard = match window {
            Some(ref win_rc) => {
                let win: &Window = win_rc.borrow();
                win.supports_clipboard()
            }
            None => false
        };
        let time_profiler_chan = profile_time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      devtools_chan,
                                                      mem_profiler_chan.clone(),
                                                      supports_clipboard);

        if let Some(port) = opts.webdriver_port {
            webdriver_server::start_server(port, constellation_chan.clone());
        };

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan.clone(),
                                                time_profiler_chan,
                                                mem_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
        self.compositor.handle_events(events)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}

fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy+Send>,
                        time_profiler_chan: time::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        mem_profiler_chan: mem::ProfilerChan,
                        supports_clipboard: bool) -> ConstellationChan {
    let resource_task = new_resource_task(opts.user_agent.clone(), devtools_chan.clone());

    let image_cache_task = new_image_cache_task(resource_task.clone());
    let font_cache_task = FontCacheTask::new(resource_task.clone());
    let storage_task: StorageTask = StorageTaskFactory::new();

    let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
    script::script_task::ScriptTask>::start(
        compositor_proxy,
        resource_task,
        image_cache_task,
        font_cache_task,
        time_profiler_chan,
        mem_profiler_chan,
        devtools_chan,
        storage_task,
        supports_clipboard);

    // Send the URL command to the constellation.
    match opts.url {
        Some(url) => {
            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(ConstellationMsg::InitLoadUrl(url.clone())).unwrap();
        },
        None => ()
    };

    constellation_chan
}
<commit_msg>Auto merge of #6444 - Ms2ger:clone, r=saneyuki<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/. */

// Servo, the mighty web browser engine from the future.
//
// This is a very simple library that wires all of Servo's components
// together as type `Browser`, along with a generic client
// implementing the `WindowMethods` trait, to create a working web
// browser.
//
// The `Browser` type is responsible for configuring a
// `Constellation`, which does the heavy lifting of coordinating all
// of Servo's internal subsystems, including the `ScriptTask` and the
// `LayoutTask`, as well maintains the navigation context.
//
// The `Browser` is fed events from a generic type that implements the
// `WindowMethods` trait.

extern crate compositing;
extern crate devtools;
extern crate devtools_traits;
extern crate net;
extern crate net_traits;
extern crate msg;
extern crate profile;
extern crate profile_traits;
#[macro_use]
extern crate util;
extern crate script;
extern crate layout;
extern crate gfx;
extern crate libc;
extern crate webdriver_server;

use compositing::CompositorEventListener;
use compositing::windowing::WindowEvent;

use compositing::windowing::WindowMethods;
use compositing::{CompositorProxy, CompositorTask, Constellation};

use msg::constellation_msg::Msg as ConstellationMsg;
use msg::constellation_msg::ConstellationChan;

use script::dom::bindings::codegen::RegisterBindings;

use net::image_cache_task::new_image_cache_task;
use net::storage_task::StorageTaskFactory;
use net::resource_task::new_resource_task;
use net_traits::storage_task::StorageTask;

use gfx::font_cache_task::FontCacheTask;
use profile::mem as profile_mem;
use profile::time as profile_time;
use profile_traits::mem;
use profile_traits::time;
use util::opts;

use std::borrow::Borrow;
use std::rc::Rc;
use std::sync::mpsc::Sender;

pub struct Browser {
    compositor: Box<CompositorEventListener + 'static>,
}

/// The in-process interface to Servo.
///
/// It does everything necessary to render the web, primarily
/// orchestrating the interaction between JavaScript, CSS layout,
/// rendering, and the client window.
///
/// Clients create a `Browser` for a given reference-counted type
/// implementing `WindowMethods`, which is the bridge to whatever
/// application Servo is embedded in. Clients then create an event
/// loop to pump messages between the embedding application and
/// various browser components.
impl Browser {
    pub fn new<Window>(window: Option<Rc<Window>>) -> Browser
                       where Window: WindowMethods + 'static {
        // Global configuration options, parsed from the command line.
        let opts = opts::get();

        script::init();
        // Create the global vtables used by the (generated) DOM
        // bindings to implement JS proxies.
        RegisterBindings::RegisterProxyHandlers();

        // Get both endpoints of a special channel for communication between
        // the client window and the compositor. This channel is unique because
        // messages to client may need to pump a platform-specific event loop
        // to deliver the message.
        let (compositor_proxy, compositor_receiver) =
            WindowMethods::create_compositor_channel(&window);
        let supports_clipboard = match window {
            Some(ref win_rc) => {
                let win: &Window = win_rc.borrow();
                win.supports_clipboard()
            }
            None => false
        };
        let time_profiler_chan = profile_time::Profiler::create(opts.time_profiler_period);
        let mem_profiler_chan = profile_mem::Profiler::create(opts.mem_profiler_period);
        let devtools_chan = opts.devtools_port.map(|port| {
            devtools::start_server(port)
        });

        // Create the constellation, which maintains the engine
        // pipelines, including the script and layout threads, as well
        // as the navigation context.
        let constellation_chan = create_constellation(opts.clone(),
                                                      compositor_proxy.clone_compositor_proxy(),
                                                      time_profiler_chan.clone(),
                                                      devtools_chan,
                                                      mem_profiler_chan.clone(),
                                                      supports_clipboard);

        if let Some(port) = opts.webdriver_port {
            webdriver_server::start_server(port, constellation_chan.clone());
        };

        // The compositor coordinates with the client window to create the final
        // rendered page and display it somewhere.
        let compositor = CompositorTask::create(window,
                                                compositor_proxy,
                                                compositor_receiver,
                                                constellation_chan,
                                                time_profiler_chan,
                                                mem_profiler_chan);

        Browser {
            compositor: compositor,
        }
    }

    pub fn handle_events(&mut self, events: Vec<WindowEvent>) -> bool {
        self.compositor.handle_events(events)
    }

    pub fn repaint_synchronously(&mut self) {
        self.compositor.repaint_synchronously()
    }

    pub fn pinch_zoom_level(&self) -> f32 {
        self.compositor.pinch_zoom_level()
    }

    pub fn get_title_for_main_frame(&self) {
        self.compositor.get_title_for_main_frame()
    }

    pub fn shutdown(mut self) {
        self.compositor.shutdown();
    }
}

fn create_constellation(opts: opts::Opts,
                        compositor_proxy: Box<CompositorProxy+Send>,
                        time_profiler_chan: time::ProfilerChan,
                        devtools_chan: Option<Sender<devtools_traits::DevtoolsControlMsg>>,
                        mem_profiler_chan: mem::ProfilerChan,
                        supports_clipboard: bool) -> ConstellationChan {
    let resource_task = new_resource_task(opts.user_agent.clone(), devtools_chan.clone());

    let image_cache_task = new_image_cache_task(resource_task.clone());
    let font_cache_task = FontCacheTask::new(resource_task.clone());
    let storage_task: StorageTask = StorageTaskFactory::new();

    let constellation_chan = Constellation::<layout::layout_task::LayoutTask,
    script::script_task::ScriptTask>::start(
        compositor_proxy,
        resource_task,
        image_cache_task,
        font_cache_task,
        time_profiler_chan,
        mem_profiler_chan,
        devtools_chan,
        storage_task,
        supports_clipboard);

    // Send the URL command to the constellation.
    match opts.url {
        Some(url) => {
            let ConstellationChan(ref chan) = constellation_chan;
            chan.send(ConstellationMsg::InitLoadUrl(url)).unwrap();
        },
        None => ()
    };

    constellation_chan
}
<|endoftext|>


<commit_before>extern crate x11;
extern crate libc;

use std::ffi;
use std::process::Command;
use std::boxed::Box;

use x11::xlib;
use x11::xlib::{ Display, Window };
use super::WindowManager;
use super::workspace::Workspaces;
use super::layout;

#[derive(Hash, Eq, PartialEq, Debug)]
pub struct KeyBind {
    pub key: u64,
    pub mask: u32,
}

impl KeyBind {
    pub fn build(mod_key: u32, tokens: &[&str]) -> KeyBind {
        let mut mask = 0;
        let mut sym = 0;
        for key in tokens {
            match *key {
                "$mod" => mask = mask | mod_key,
                "Shift" => mask = mask | xlib::ShiftMask,
                "Ctrl" => mask = mask | xlib::ControlMask,
                "Mod1" => mask = mask | xlib::Mod1Mask,
                "Mod2" => mask = mask | xlib::Mod2Mask,
                "Mod3" => mask = mask | xlib::Mod3Mask,
                "Mod4" => mask = mask | xlib::Mod4Mask,
                "Mod5" => mask = mask | xlib::Mod5Mask,
                _ => {
                    let tmp = ffi::CString::new(*key).unwrap();
                    unsafe{
                        sym = xlib::XStringToKeysym(tmp.as_ptr());
                    }
                }
            }
        }

        println!("bind {} {}", mask, sym);
        KeyBind {
            mask: mask,
            key: sym
        }
    }
}

pub trait Handler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int);
}

pub struct ExecHandler {
    pub cmd: Command
}

pub struct LayoutHandler {
    layout_type: layout::Type,
}

/// switch to another workspace
pub struct WorkspaceHandler {
    pub key: char,
}

impl Handler for WorkspaceHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle workspace");
        workspaces.switch_current(self.key, display);
    }
}

impl Handler for ExecHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle exec");
        self.cmd.spawn();
    }
}

impl Handler for LayoutHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        debug!("handle layout");
        let current = workspaces.current();
        let t = self.layout_type.clone();
        current.change_layout(t);
        current.config(display, screen_num);
    }
}

impl LayoutHandler {
    pub fn new(layout: layout::Type) -> LayoutHandler{
        LayoutHandler {
            layout_type: layout
        }
    }
}

impl ExecHandler {
    pub fn new(tokens: &[&str]) -> ExecHandler {
        let (name, args) = tokens.split_at(1);
        let mut cmd = Command::new(name[0]);

        for arg in args {
            println!("{}", arg);
            cmd.arg(arg);
        }

        let handler = ExecHandler {
            cmd: cmd,
        };
        handler
    }
}
<commit_msg>add WindowToWorkspaceHandler<commit_after>extern crate x11;
extern crate libc;

use std::ffi;
use std::process::Command;
use std::boxed::Box;
use std::ptr;

use x11::xlib;
use x11::xlib::{ Display, Window };
use super::WindowManager;
use super::workspace::Workspaces;
use super::layout;

#[derive(Hash, Eq, PartialEq, Debug)]
pub struct KeyBind {
    pub key: u64,
    pub mask: u32,
}

impl KeyBind {
    pub fn build(mod_key: u32, tokens: &[&str]) -> KeyBind {
        let mut mask = 0;
        let mut sym = 0;
        for key in tokens {
            match *key {
                "$mod" => mask = mask | mod_key,
                "Shift" => mask = mask | xlib::ShiftMask,
                "Ctrl" => mask = mask | xlib::ControlMask,
                "Mod1" => mask = mask | xlib::Mod1Mask,
                "Mod2" => mask = mask | xlib::Mod2Mask,
                "Mod3" => mask = mask | xlib::Mod3Mask,
                "Mod4" => mask = mask | xlib::Mod4Mask,
                "Mod5" => mask = mask | xlib::Mod5Mask,
                _ => {
                    let tmp = ffi::CString::new(*key).unwrap();
                    unsafe{
                        sym = xlib::XStringToKeysym(tmp.as_ptr());
                    }
                }
            }
        }

        println!("bind {} {}", mask, sym);
        KeyBind {
            mask: mask,
            key: sym
        }
    }
}

pub trait Handler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int);
}

pub struct ExecHandler {
    pub cmd: Command
}

pub struct LayoutHandler {
    layout_type: layout::Type,
}

/// switch to another workspace
pub struct WorkspaceHandler {
    pub key: char,
}

/// move window to target workspace
pub struct WindowToWorkspaceHandler {
    pub key: char,
}

impl Handler for WindowToWorkspaceHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle window move form {} to {}", workspaces.current_name(), self.key);
        let mut window: Window = 0;
        let mut revert_to: libc::c_int = 0;
        unsafe{
            let s = xlib::XGetInputFocus(display, &mut window, &mut revert_to);
            println!("window {}", window);
        }

        let mut root: Window = 0;
        let mut parent: Window = window;
        let mut children: *mut Window = ptr::null_mut();
        let mut nchildren: libc::c_uint = 0;

        // while parent != root {
            window = parent;
            unsafe{
                let s = xlib::XQueryTree(display, window, &mut root, &mut parent, &mut children, &mut nchildren);
                if s > 0 {
                    println!("parent {} root {}", parent, root);
                    xlib::XFree(children as *mut libc::c_void);
                }
                else{
                    println!("error");
                }
            }
        // }

        println!("focused window {}", window);
        workspaces.current().p();
        let from = workspaces.current_name();
        workspaces.move_window(window, from, self.key);
        workspaces.current().config(display, screen_num);

        match workspaces.get(self.key) {
            Some(w) => {
                w.config(display, screen_num);
            }
            None => {}
        }

    }
}

impl Handler for WorkspaceHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle workspace");
        workspaces.switch_current(self.key, display);
    }
}

impl Handler for ExecHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut Display, screen_num: libc::c_int) {
        debug!("handle exec");
        self.cmd.spawn();
    }
}

impl Handler for LayoutHandler {
    fn handle(&mut self, workspaces: &mut Workspaces, display: *mut xlib::Display, screen_num: libc::c_int) {
        debug!("handle layout");
        let current = workspaces.current();
        let t = self.layout_type.clone();
        current.change_layout(t);
        current.config(display, screen_num);
    }
}

impl LayoutHandler {
    pub fn new(layout: layout::Type) -> LayoutHandler{
        LayoutHandler {
            layout_type: layout
        }
    }
}

impl ExecHandler {
    pub fn new(tokens: &[&str]) -> ExecHandler {
        let (name, args) = tokens.split_at(1);
        let mut cmd = Command::new(name[0]);

        for arg in args {
            println!("{}", arg);
            cmd.arg(arg);
        }

        let handler = ExecHandler {
            cmd: cmd,
        };
        handler
    }
}
<|endoftext|>


<commit_before>extern crate crowbook;
use self::crowbook::{Parser, HtmlRenderer, Book, Token};
mod test_helper;
use test_helper::test_eq;

fn ast_to_html(v: &[Token]) -> String {
    let mut book = Book::new();
    book.set_option("numbering", "false").unwrap();
    let mut html = HtmlRenderer::new(&book);
    html.render_vec(v)
}

#[test]
fn html_combination() {
    let doc = "
Foo
===

```rust
fn min(x: &u32, y: u32) -> &u32 {
    if x < y { x } else { y }
}
```

Bar
---

Some paragraph

* a list
    * inside a list
* another item

3. three
4. four
5. five

[& some link](http://foo/bar?baz=42&coin=plop)
";
    let expected = "
Foo

fn min(x: &u32, y: u32) -> &u32 {
    if x < y { x } else { y }
}

Bar

Some paragraph

a list

inside a list

another item

three

four

five

& some link

";
    let actual = ast_to_html(&Parser::new().parse(doc).unwrap());
    println!("ecpected:\n {}", expected);
    println!("actual:\n {}", actual);
    test_eq(&actual, &expected);
}
<commit_msg>tests/html.rs: fixed to new interface<commit_after>extern crate crowbook;
use self::crowbook::{Parser, HtmlRenderer, Book, Token};
mod test_helper;
use test_helper::test_eq;

fn ast_to_html(v: &[Token]) -> String {
    let mut book = Book::new();
    book.set_option("numbering", "0").unwrap();
    let mut html = HtmlRenderer::new(&book);
    html.render_vec(v)
}

#[test]
fn html_combination() {
    let doc = "
Foo
===

```rust
fn min(x: &u32, y: u32) -> &u32 {
    if x < y { x } else { y }
}
```

Bar
---

Some paragraph

* a list
    * inside a list
* another item

3. three
4. four
5. five

[& some link](http://foo/bar?baz=42&coin=plop)
";
    let expected = "
Foo

fn min(x: &u32, y: u32) -> &u32 {
    if x < y { x } else { y }
}

Bar

Some paragraph

a list

inside a list

another item

three

four

five

& some link

";
    let actual = ast_to_html(&Parser::new().parse(doc).unwrap());
    println!("ecpected:\n {}", expected);
    println!("actual:\n {}", actual);
    test_eq(&actual, &expected);
}
<|endoftext|>


<commit_before>extern crate office;

use office::Excel;
use office::DataType::{self, Int, String, Float, Bool, Error};
use office::CellErrorType::*;

#[test]
fn issue_2() {
    let path = format!("{}/tests/issues.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("issue2").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Int(1), String("a".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[Int(2), String("b".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[Int(3), String("c".to_string())] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn issue_3() {
    // test if sheet is resolved with only one row
    let path = format!("{}/tests/issue3.xlsm", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("Sheet1").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Int(1), String("a".to_string())] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn issue_4() {
    // test if sheet is resolved with only one row
    let path = format!("{}/tests/issues.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("issue5").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Float(0.5)] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn issue_6() {
    // test if sheet is resolved with only one row
    let path = format!("{}/tests/issues.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("issue6").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Int(1)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Int(2)] as &[DataType]));
    assert_eq!(r.next(), Some(&[String("ab".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[Bool(false)] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn error_file() {
    let path = format!("{}/tests/errors.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("Feuil1").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Error(Div0)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Name)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Value)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Null)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Ref)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Num)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(NA)] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn issue_9() {
    let path = format!("{}/tests/issue9.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("Feuil1").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[String("test1".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[String("test2 other".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[String("test3 aaa".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[String("test4".to_string())] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn vba() {
    let path = format!("{}/tests/vba.xlsm", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let vba = excel.vba_project().unwrap();
    let modules = vba.read_vba().unwrap().1;
    let testVBA = modules.into_iter().find(|m| &*m.name == "testVBA").unwrap();
    assert_eq!(vba.read_module(&testVBA).unwrap(), "Attribute VB_Name = \"testVBA\"\
    \r\nPublic Sub test()\
    \r\n    MsgBox \"Hello from vba!\"\
    \r\nEnd Sub\
    \r\n");

}
<commit_msg>use snake case for test_vba<commit_after>extern crate office;

use office::Excel;
use office::DataType::{self, Int, String, Float, Bool, Error};
use office::CellErrorType::*;

#[test]
fn issue_2() {
    let path = format!("{}/tests/issues.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("issue2").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Int(1), String("a".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[Int(2), String("b".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[Int(3), String("c".to_string())] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn issue_3() {
    // test if sheet is resolved with only one row
    let path = format!("{}/tests/issue3.xlsm", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("Sheet1").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Int(1), String("a".to_string())] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn issue_4() {
    // test if sheet is resolved with only one row
    let path = format!("{}/tests/issues.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("issue5").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Float(0.5)] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn issue_6() {
    // test if sheet is resolved with only one row
    let path = format!("{}/tests/issues.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("issue6").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Int(1)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Int(2)] as &[DataType]));
    assert_eq!(r.next(), Some(&[String("ab".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[Bool(false)] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn error_file() {
    let path = format!("{}/tests/errors.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("Feuil1").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[Error(Div0)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Name)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Value)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Null)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Ref)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(Num)] as &[DataType]));
    assert_eq!(r.next(), Some(&[Error(NA)] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn issue_9() {
    let path = format!("{}/tests/issue9.xlsx", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let range = excel.worksheet_range("Feuil1").unwrap();
    let mut r = range.rows();
    assert_eq!(r.next(), Some(&[String("test1".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[String("test2 other".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[String("test3 aaa".to_string())] as &[DataType]));
    assert_eq!(r.next(), Some(&[String("test4".to_string())] as &[DataType]));
    assert_eq!(r.next(), None);
}

#[test]
fn vba() {
    let path = format!("{}/tests/vba.xlsm", env!("CARGO_MANIFEST_DIR"));
    let mut excel = Excel::open(&path).expect("cannot open excel file");

    let vba = excel.vba_project().unwrap();
    let modules = vba.read_vba().unwrap().1;
    let test_vba = modules.into_iter().find(|m| &*m.name == "testVBA").unwrap();
    assert_eq!(vba.read_module(&test_vba).unwrap(), "Attribute VB_Name = \"testVBA\"\
    \r\nPublic Sub test()\
    \r\n    MsgBox \"Hello from vba!\"\
    \r\nEnd Sub\
    \r\n");
}
<|endoftext|>


<commit_before>#![feature(core)]

#[macro_use] extern crate libeuler;
use std::iter::AdditiveIterator;

// Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over
// five-thousand first names, begin by sorting it into alphabetical order. Then working out the
// alphabetical value for each name, multiply this value by its alphabetical position in the list
// to obtain a name score.
//
// For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12
// + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 =
// 49714.
//
// What is the total of all the name scores in the file?

fn main() {
    let mut names: Vec<&str> = include_str!("names.txt")
        .split(",")
        .map(|a| a.trim_matches(&['"'] as &[char]))
        .collect();
    names.sort();

    solutions! {
        sol naive {
            names.iter().zip(0..names.len()).map(|(&name, index)| {
                name.chars()
                    .map(|c| c as u8 - 'A' as u8 + 1)
                    .map(|v| v as u64)
                    .sum() * (index as u64 + 1)
            }).sum()
        }
    }
}
<commit_msg>Slight simplification of solution 22<commit_after>#![feature(core)]

#[macro_use] extern crate libeuler;
use std::iter::AdditiveIterator;

// Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over
// five-thousand first names, begin by sorting it into alphabetical order. Then working out the
// alphabetical value for each name, multiply this value by its alphabetical position in the list
// to obtain a name score.
//
// For example, when the list is sorted into alphabetical order, COLIN, which is worth 3 + 15 + 12
// + 9 + 14 = 53, is the 938th name in the list. So, COLIN would obtain a score of 938 × 53 =
// 49714.
//
// What is the total of all the name scores in the file?

fn main() {
    let mut names: Vec<&str> = include_str!("names.txt")
        .split(",")
        .map(|a| a.trim_matches(&['"'] as &[char]))
        .collect();
    names.sort();

    solutions! {
        sol naive {
            names.iter().zip(0..names.len()).map(|(&name, index)| {
                name.chars()
                    .map(|c| c as u64 - 'A' as u64 + 1)
                    .sum() * (index as u64 + 1)
            }).sum()
        }
    }
}
<|endoftext|>


<commit_before>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().unwrap());
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

// CIs usually do it automatically but for normal users libsass would be missing
fn init_submodule() {
    Command::new("git")
        .arg("submodule")
        .arg("init")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success();
    Command::new("git")
        .arg("submodule")
        .arg("update")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success();
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().unwrap().join("libsass")
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let libprobe = | lib: &str | -> bool {
      Command::new("cc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success()
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("error running make");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    }
    else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    }
    else if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    }
    else {
        panic!("no c++ library found");
    }

}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("error running devenv");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let search = Command::new("which")
        .args(&["msbuild.exe"])
        .output()
        .expect("Could not search for msbuild.exe on path");
    let mut msbuild = if search.status.success() {
        Command::new("msbuild.exe")
    } else {
        cc::windows_registry::find(target.as_str(), "msbuild.exe")
            .expect("Could not find msbuild.exe on the registry")
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());

    let r = msbuild
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/m:{}", jobs).as_str(),
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("error running msbuild");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    init_submodule();
    compile();
}
<commit_msg>Move std++ at the top when building<commit_after>// extern crate bindgen;
#[cfg(target_env = "msvc")]
extern crate cc;
extern crate pkg_config;
extern crate num_cpus;

use std::env;
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

// Automatically write bindings to libsass
//#[allow(dead_code)]
//fn write_bindings() {
//    let bindings = bindgen::Builder::default()
//        .header("libsass/include/sass.h")
//        .clang_arg("-Ilibsass/include")
//        // To avoid a test failing
//        .blacklist_type("max_align_t")
//        // we do static linking so it should be fine
//        // https://github.com/rust-lang/rust/issues/36927
//        .rustified_enum(".*")
//        .generate()
//        .expect("Unable to generate bindings");
//
//    // Write the bindings to the $OUT_DIR/bindings.rs file.
//    let out_path = PathBuf::from("src");
//    bindings
//        .write_to_file(out_path.join("bindings.rs"))
//        .expect("Couldn't write bindings!");
//}

macro_rules! t {
    ($e:expr) => (match $e {
        Ok(n) => n,
        Err(e) => panic!("\n{} failed with {}\n", stringify!($e), e),
    })
}

fn cp_r(dir: &Path, dest: &Path) {
    for entry in t!(fs::read_dir(dir)) {
        let entry = t!(entry);
        let path = entry.path();
        let dst = dest.join(path.file_name().unwrap());
        if t!(fs::metadata(&path)).is_file() {
            t!(fs::copy(path, dst));
        } else {
            t!(fs::create_dir_all(&dst));
            cp_r(&path, &dst);
        }
    }
}

// CIs usually do it automatically but for normal users libsass would be missing
fn init_submodule() {
    Command::new("git")
        .arg("submodule")
        .arg("init")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success();
    Command::new("git")
        .arg("submodule")
        .arg("update")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success();
}

fn get_libsass_folder() -> PathBuf {
    env::current_dir().unwrap().join("libsass")
}

// linux/unix
#[cfg(not(target_env = "msvc"))]
fn compile() {
    let target = env::var("TARGET").expect("TARGET not found");
    let src = get_libsass_folder();
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);
    let is_bsd = target.contains("dragonfly")
        || target.contains("freebsd")
        || target.contains("netbsd")
        || target.contains("openbsd");
    let libprobe = | lib: &str | -> bool {
      Command::new("cc")
        .arg("-xc++")
        .arg("-o/dev/null")
        .arg(format!("-l{}",lib))
        .arg("-shared")
        .stderr(Stdio::null())
        .status()
        .expect("")
        .success()
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());
    let r = Command::new(if is_bsd { "gmake" } else { "make" })
        .current_dir(&build)
        .args(&["--jobs", &jobs])
        .output()
        .expect("error running make");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("lib").display()
    );
    println!("cargo:rustc-link-lib=static=sass");

    if libprobe("stdc++") {
        println!("cargo:rustc-link-lib=dylib=stdc++");
    } else if libprobe("c++_shared") {
        println!("cargo:rustc-link-lib=dylib=c++_shared");
    }
    else if libprobe("c++") {
        println!("cargo:rustc-link-lib=dylib=c++");
    }
    else {
        panic!("no c++ library found");
    }

}

// windows
#[cfg(target_env = "msvc")]
fn compile() {
    let src = get_libsass_folder();
    let target = env::var("TARGET").expect("TARGET not found in environment");
    let msvc_platform = if target.contains("x86_64") {
        "Win64"
    } else {
        "Win32"
    };
    let dest = PathBuf::from(env::var_os("OUT_DIR").unwrap());
    let build = dest.join("build");
    t!(fs::create_dir_all(&build));
    cp_r(&src, &build);

    // Find an instance of devenv.exe from Visual Studio IDE in order to upgrade
    // libsass.sln to the current available IDE. Do nothing if no devenv.exe found
    let d = cc::windows_registry::find(target.as_str(), "devenv.exe");
    if let Some(mut d) = d {
        let d = d
            .args(&["/upgrade", "win\\libsass.sln"])
            .current_dir(&build)
            .output()
            .expect("error running devenv");
        if !d.status.success() {
            let err = String::from_utf8_lossy(&d.stderr);
            let out = String::from_utf8_lossy(&d.stdout);
            println!("Upgrade error:\nSTDERR:{}\nSTDOUT:{}", err, out);
        }
    }

    let search = Command::new("which")
        .args(&["msbuild.exe"])
        .output()
        .expect("Could not search for msbuild.exe on path");
    let mut msbuild = if search.status.success() {
        Command::new("msbuild.exe")
    } else {
        cc::windows_registry::find(target.as_str(), "msbuild.exe")
            .expect("Could not find msbuild.exe on the registry")
    };

    let jobs = env::var("MAKE_LIBSASS_JOBS").unwrap_or(num_cpus::get().to_string());

    let r = msbuild
        .args(&[
            "win\\libsass.sln",
            "/p:LIBSASS_STATIC_LIB=1",
            "/p:Configuration=Release",
            "/p:WholeProgramOptimization=false",
            format!("/m:{}", jobs).as_str(),
            format!("/p:Platform={}", msvc_platform).as_str(),
        ])
        .current_dir(&build)
        .output()
        .expect("error running msbuild");

    if !r.status.success() {
        let err = String::from_utf8_lossy(&r.stderr);
        let out = String::from_utf8_lossy(&r.stdout);
        panic!("Build error:\nSTDERR:{}\nSTDOUT:{}", err, out);
    }

    println!(
        "cargo:rustc-link-search=native={}",
        build.join("win").join("bin").display()
    );
    println!("cargo:rustc-link-lib=static=libsass");
}

fn main() {
    // Uncomment the line below to generate bindings. Doesn't work on CI as it
    // requires additional tooling
    // write_bindings();

    // Is it already built?
    if let Ok(_) = pkg_config::find_library("libsass") {
        return;
    }

    init_submodule();
    compile();
}
<|endoftext|>


<commit_before>use arch::x86_64::pti;
use syscall;

#[naked]
pub unsafe extern fn syscall() {
    #[inline(never)]
    unsafe fn inner(stack: &mut SyscallStack) -> usize {
        let rbp;
        asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");

        println!("{:X}, {:X}", stack.rax, stack.rbx);

        syscall::syscall(stack.rax, stack.rbx, stack.rcx, stack.rdx, stack.rsi, stack.rdi, rbp, stack)
    }

    // Push scratch registers
    asm!("push rax
         push rbx
         push rcx
         push rdx
         push rdi
         push rsi
         push r8
         push r9
         push r10
         push r11
         push fs
         mov r11, 0x18
         mov fs, r11"
         : : : : "intel", "volatile");

    // Get reference to stack variables
    let rsp: usize;
    asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");

    // Map kernel
    pti::map();

    let a = inner(&mut *(rsp as *mut SyscallStack));

    // Unmap kernel
    pti::unmap();

    asm!("" : : "{rax}"(a) : : "intel", "volatile");

    // Interrupt return
    asm!("pop fs
          pop r11
          pop r10
          pop r9
          pop r8
          pop rsi
          pop rdi
          pop rdx
          pop rcx
          pop rbx
          add rsp, 8
          iretq"
          : : : : "intel", "volatile");
}

#[allow(dead_code)]
#[repr(packed)]
pub struct SyscallStack {
    pub fs: usize,
    pub r11: usize,
    pub r10: usize,
    pub r9: usize,
    pub r8: usize,
    pub rsi: usize,
    pub rdi: usize,
    pub rdx: usize,
    pub rcx: usize,
    pub rbx: usize,
    pub rax: usize,
    pub rip: usize,
    pub cs: usize,
    pub rflags: usize,
}

#[naked]
pub unsafe extern fn clone_ret() {
    asm!("pop rbp" : : : : "intel", "volatile");
    asm!("" : : "{rax}"(0) : : "intel", "volatile");
}
<commit_msg>Remove debugging print<commit_after>use arch::x86_64::pti;
use syscall;

#[naked]
pub unsafe extern fn syscall() {
    #[inline(never)]
    unsafe fn inner(stack: &mut SyscallStack) -> usize {
        let rbp;
        asm!("" : "={rbp}"(rbp) : : : "intel", "volatile");

        syscall::syscall(stack.rax, stack.rbx, stack.rcx, stack.rdx, stack.rsi, stack.rdi, rbp, stack)
    }

    // Push scratch registers
    asm!("push rax
         push rbx
         push rcx
         push rdx
         push rdi
         push rsi
         push r8
         push r9
         push r10
         push r11
         push fs
         mov r11, 0x18
         mov fs, r11"
         : : : : "intel", "volatile");

    // Get reference to stack variables
    let rsp: usize;
    asm!("" : "={rsp}"(rsp) : : : "intel", "volatile");

    // Map kernel
    pti::map();

    let a = inner(&mut *(rsp as *mut SyscallStack));

    // Unmap kernel
    pti::unmap();

    asm!("" : : "{rax}"(a) : : "intel", "volatile");

    // Interrupt return
    asm!("pop fs
          pop r11
          pop r10
          pop r9
          pop r8
          pop rsi
          pop rdi
          pop rdx
          pop rcx
          pop rbx
          add rsp, 8
          iretq"
          : : : : "intel", "volatile");
}

#[allow(dead_code)]
#[repr(packed)]
pub struct SyscallStack {
    pub fs: usize,
    pub r11: usize,
    pub r10: usize,
    pub r9: usize,
    pub r8: usize,
    pub rsi: usize,
    pub rdi: usize,
    pub rdx: usize,
    pub rcx: usize,
    pub rbx: usize,
    pub rax: usize,
    pub rip: usize,
    pub cs: usize,
    pub rflags: usize,
}

#[naked]
pub unsafe extern fn clone_ret() {
    asm!("pop rbp" : : : : "intel", "volatile");
    asm!("" : : "{rax}"(0) : : "intel", "volatile");
}
<|endoftext|>


<commit_before>// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

use engine_rocks::RocksSnapshot;
use kvproto::raft_cmdpb::{RaftCmdRequest, RaftCmdResponse};
use raft::eraftpb::MessageType;
use raftstore::store::msg::*;
use test_raftstore::*;
use tikv_util::HandyRwLock;

use std::sync::mpsc::{self, TryRecvError};
use std::time::Duration;

struct CbReceivers {
    proposed: mpsc::Receiver<()>,
    committed: mpsc::Receiver<()>,
    applied: mpsc::Receiver<RaftCmdResponse>,
}

impl CbReceivers {
    fn assert_not_ready(&self) {
        sleep_ms(100);
        assert_eq!(self.proposed.try_recv().unwrap_err(), TryRecvError::Empty);
        assert_eq!(self.committed.try_recv().unwrap_err(), TryRecvError::Empty);
        assert_eq!(self.applied.try_recv().unwrap_err(), TryRecvError::Empty);
    }

    fn assert_ok(&self) {
        let resp = self.applied.recv_timeout(Duration::from_secs(1)).unwrap();
        assert!(
            !resp.get_header().has_error(),
            "{:?}",
            resp.get_header().get_error()
        );
        // proposed and committed should be invoked before applied
        self.proposed.try_recv().unwrap();
        self.committed.try_recv().unwrap();
    }

    // When fails to propose, only applied callback will be invoked.
    fn assert_err(&self) {
        assert!(self
            .applied
            .recv_timeout(Duration::from_secs(1))
            .unwrap()
            .get_header()
            .has_error());
        self.proposed.try_recv().unwrap_err();
        self.committed.try_recv().unwrap_err();
    }
}

fn make_cb(cmd: &RaftCmdRequest) -> (Callback<RocksSnapshot>, CbReceivers) {
    let (proposed_tx, proposed_rx) = mpsc::channel();
    let (committed_tx, committed_rx) = mpsc::channel();
    let (cb, applied_rx) = make_cb_ext(
        cmd,
        Some(Box::new(move || proposed_tx.send(()).unwrap())),
        Some(Box::new(move || committed_tx.send(()).unwrap())),
    );
    (
        cb,
        CbReceivers {
            proposed: proposed_rx,
            committed: committed_rx,
            applied: applied_rx,
        },
    )
}

fn make_write_req(cluster: &mut Cluster<NodeCluster>, k: &[u8]) -> RaftCmdRequest {
    let r = cluster.get_region(k);
    let mut req = new_request(
        r.get_id(),
        r.get_region_epoch().clone(),
        vec![new_put_cmd(k, b"v")],
        false,
    );
    let leader = cluster.leader_of_region(r.get_id()).unwrap();
    req.mut_header().set_peer(leader);
    req
}

#[test]
fn test_reject_proposal_during_region_split() {
    let mut cluster = new_node_cluster(0, 3);
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_operator();
    cluster.run();
    cluster.must_transfer_leader(1, new_peer(1, 1));
    cluster.must_put(b"k", b"v");

    // Pause on applying so that region split is not finished.
    let fp = "apply_before_split";
    fail::cfg(fp, "pause").unwrap();

    // Try to split region.
    let (split_tx, split_rx) = mpsc::channel();
    let cb = Callback::Read(Box::new(move |resp: ReadResponse<RocksSnapshot>| {
        split_tx.send(resp.response).unwrap()
    }));
    let r = cluster.get_region(b"");
    cluster.split_region(&r, b"k", cb);
    split_rx
        .recv_timeout(Duration::from_millis(100))
        .unwrap_err();

    // Try to put a key.
    let write_req = make_write_req(&mut cluster, b"k1");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    // The write request should be blocked until split is finished.
    cb_receivers.assert_not_ready();

    fail::remove(fp);
    // Split is finished.
    assert!(!split_rx
        .recv_timeout(Duration::from_secs(1))
        .unwrap()
        .get_header()
        .has_error());

    // The write request fails due to epoch not match.
    cb_receivers.assert_err();

    // New write request can succeed.
    let write_req = make_write_req(&mut cluster, b"k1");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_ok();
}

#[test]
fn test_reject_proposal_during_region_merge() {
    let mut cluster = new_node_cluster(0, 3);
    configure_for_merge(&mut cluster);
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_operator();
    cluster.run();
    cluster.must_transfer_leader(1, new_peer(1, 1));
    cluster.must_put(b"k", b"v");

    let r = cluster.get_region(b"");
    cluster.must_split(&r, b"k");
    // Let the new region catch up.
    cluster.must_put(b"a", b"v");
    cluster.must_put(b"k", b"v");

    let prepare_merge_fp = "apply_before_prepare_merge";
    let commit_merge_fp = "apply_before_commit_merge";

    // Pause on applying so that prepare-merge is not finished.
    fail::cfg(prepare_merge_fp, "pause").unwrap();
    // Try to merge region.
    let (merge_tx, merge_rx) = mpsc::channel();
    let cb = Callback::Read(Box::new(move |resp: ReadResponse<RocksSnapshot>| {
        merge_tx.send(resp.response).unwrap()
    }));
    let source = cluster.get_region(b"");
    let target = cluster.get_region(b"k");
    cluster.merge_region(source.get_id(), target.get_id(), cb);
    merge_rx
        .recv_timeout(Duration::from_millis(100))
        .unwrap_err();

    // Try to put a key on the source region.
    let write_req = make_write_req(&mut cluster, b"a");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    // The write request should be blocked until prepare-merge is finished.
    cb_receivers.assert_not_ready();

    // Pause on the second phase of region merge.
    fail::cfg(commit_merge_fp, "pause").unwrap();

    // prepare-merge is finished.
    fail::remove(prepare_merge_fp);
    assert!(!merge_rx
        .recv_timeout(Duration::from_secs(1))
        .unwrap()
        .get_header()
        .has_error());
    // The write request fails due to epoch not match.
    cb_receivers.assert_err();

    // Write request is rejected because the source region is merging.
    // It's not handled by epoch checker now.
    let write_req = make_write_req(&mut cluster, b"a");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_err();

    // Try to put a key on the target region.
    let write_req = make_write_req(&mut cluster, b"k");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    // The write request should be blocked until commit-merge is finished.
    cb_receivers.assert_not_ready();

    // Wait for region merge done.
    fail::remove(commit_merge_fp);
    pd_client.check_merged_timeout(source.get_id(), Duration::from_secs(1));
    // The write request fails due to epoch not match.
    cb_receivers.assert_err();

    // New write request can succeed.
    let write_req = make_write_req(&mut cluster, b"k");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_ok();
}

#[test]
fn test_reject_proposal_during_rollback_region_merge() {
    let mut cluster = new_node_cluster(0, 2);
    configure_for_merge(&mut cluster);
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_operator();
    cluster.run_conf_change();

    let r = cluster.get_region(b"");
    cluster.must_split(&r, b"k");

    // Don't enter the second phase of region merge.
    let schedule_merge_fp = "on_schedule_merge";
    fail::cfg(schedule_merge_fp, "return()").unwrap();

    let source = cluster.get_region(b"");
    let target = cluster.get_region(b"k");
    // The call is finished when prepare_merge is applied.
    cluster.must_try_merge(source.get_id(), target.get_id());

    // Add a peer to trigger rollback.
    pd_client.must_add_peer(target.get_id(), new_peer(2, 4));
    cluster.must_put(b"k", b"v");
    must_get_equal(&cluster.get_engine(1), b"k", b"v");

    // Pause on applying so that rolling back merge is not finished.
    let rollback_merge_fp = "apply_before_rollback_merge";
    fail::cfg(rollback_merge_fp, "pause").unwrap();
    fail::remove(schedule_merge_fp);
    sleep_ms(200);

    // Write request is rejected because the source region is merging.
    // It's not handled by epoch checker now.
    let write_req = make_write_req(&mut cluster, b"a");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_err();

    fail::remove(rollback_merge_fp);
    // Make sure the rollback is done.
    cluster.must_put(b"a", b"v");

    // New write request can succeed.
    let write_req = make_write_req(&mut cluster, b"a");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_ok();
}

#[test]
fn test_reject_proposal_during_leader_transfer() {
    let mut cluster = new_node_cluster(0, 2);
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_operator();
    let r = cluster.run_conf_change();
    pd_client.must_add_peer(r, new_peer(2, 2));

    // Don't allow leader transfer succeed if it is actually triggered.
    cluster.add_send_filter(CloneFilterFactory(
        RegionPacketFilter::new(1, 2)
            .msg_type(MessageType::MsgTimeoutNow)
            .direction(Direction::Recv),
    ));

    cluster.must_put(b"k", b"v");
    cluster.transfer_leader(r, new_peer(2, 2));
    // The leader can't change to transferring state immediately due to pre-transfer-leader
    // feature, so wait for a while.
    sleep_ms(100);
    assert_ne!(cluster.leader_of_region(r).unwrap(), new_peer(2, 2));

    let write_req = make_write_req(&mut cluster, b"k");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_err();
    cluster.clear_send_filters();
}

#[test]
fn test_accept_proposal_during_conf_change() {
    let mut cluster = new_node_cluster(0, 2);
    cluster.pd_client.disable_default_operator();
    let r = cluster.run_conf_change();
    cluster.must_put(b"a", b"v");

    let conf_change_fp = "apply_on_conf_change_all_1";
    fail::cfg(conf_change_fp, "pause").unwrap();
    let add_peer_rx = cluster.async_add_peer(r, new_peer(2, 2)).unwrap();
    add_peer_rx
        .recv_timeout(Duration::from_millis(100))
        .unwrap_err();

    // Conf change doesn't affect proposals.
    let write_req = make_write_req(&mut cluster, b"k");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers
        .committed
        .recv_timeout(Duration::from_millis(300))
        .unwrap();
    cb_receivers.proposed.try_recv().unwrap();

    fail::remove(conf_change_fp);
    assert!(!add_peer_rx
        .recv_timeout(Duration::from_secs(1))
        .unwrap()
        .get_header()
        .has_error());
    assert!(!cb_receivers
        .applied
        .recv_timeout(Duration::from_secs(1))
        .unwrap()
        .get_header()
        .has_error());
    must_get_equal(&cluster.get_engine(2), b"k", b"v");
}
<commit_msg>test: shouldn't invoke committed callbacks when failing to commit (#9490)<commit_after>// Copyright 2020 TiKV Project Authors. Licensed under Apache-2.0.

use engine_rocks::RocksSnapshot;
use kvproto::raft_cmdpb::{RaftCmdRequest, RaftCmdResponse};
use raft::eraftpb::MessageType;
use raftstore::store::msg::*;
use test_raftstore::*;
use tikv_util::HandyRwLock;

use std::sync::mpsc::{self, TryRecvError};
use std::time::Duration;

struct CbReceivers {
    proposed: mpsc::Receiver<()>,
    committed: mpsc::Receiver<()>,
    applied: mpsc::Receiver<RaftCmdResponse>,
}

impl CbReceivers {
    fn assert_not_ready(&self) {
        sleep_ms(100);
        assert_eq!(self.proposed.try_recv().unwrap_err(), TryRecvError::Empty);
        assert_eq!(self.committed.try_recv().unwrap_err(), TryRecvError::Empty);
        assert_eq!(self.applied.try_recv().unwrap_err(), TryRecvError::Empty);
    }

    fn assert_ok(&self) {
        let resp = self.applied.recv_timeout(Duration::from_secs(1)).unwrap();
        assert!(
            !resp.get_header().has_error(),
            "{:?}",
            resp.get_header().get_error()
        );
        // proposed and committed should be invoked before applied
        self.proposed.try_recv().unwrap();
        self.committed.try_recv().unwrap();
    }

    // When fails to propose, only applied callback will be invoked.
    fn assert_err(&self) {
        let resp = self.applied.recv_timeout(Duration::from_secs(1)).unwrap();
        assert!(resp.get_header().has_error(), "{:?}", resp);
        self.proposed.try_recv().unwrap_err();
        self.committed.try_recv().unwrap_err();
    }
}

fn make_cb(cmd: &RaftCmdRequest) -> (Callback<RocksSnapshot>, CbReceivers) {
    let (proposed_tx, proposed_rx) = mpsc::channel();
    let (committed_tx, committed_rx) = mpsc::channel();
    let (cb, applied_rx) = make_cb_ext(
        cmd,
        Some(Box::new(move || proposed_tx.send(()).unwrap())),
        Some(Box::new(move || committed_tx.send(()).unwrap())),
    );
    (
        cb,
        CbReceivers {
            proposed: proposed_rx,
            committed: committed_rx,
            applied: applied_rx,
        },
    )
}

fn make_write_req(cluster: &mut Cluster<NodeCluster>, k: &[u8]) -> RaftCmdRequest {
    let r = cluster.get_region(k);
    let mut req = new_request(
        r.get_id(),
        r.get_region_epoch().clone(),
        vec![new_put_cmd(k, b"v")],
        false,
    );
    let leader = cluster.leader_of_region(r.get_id()).unwrap();
    req.mut_header().set_peer(leader);
    req
}

#[test]
fn test_reject_proposal_during_region_split() {
    let mut cluster = new_node_cluster(0, 3);
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_operator();
    cluster.run();
    cluster.must_transfer_leader(1, new_peer(1, 1));
    cluster.must_put(b"k", b"v");

    // Pause on applying so that region split is not finished.
    let fp = "apply_before_split";
    fail::cfg(fp, "pause").unwrap();

    // Try to split region.
    let (split_tx, split_rx) = mpsc::channel();
    let cb = Callback::Read(Box::new(move |resp: ReadResponse<RocksSnapshot>| {
        split_tx.send(resp.response).unwrap()
    }));
    let r = cluster.get_region(b"");
    cluster.split_region(&r, b"k", cb);
    split_rx
        .recv_timeout(Duration::from_millis(100))
        .unwrap_err();

    // Try to put a key.
    let write_req = make_write_req(&mut cluster, b"k1");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    // The write request should be blocked until split is finished.
    cb_receivers.assert_not_ready();

    fail::remove(fp);
    // Split is finished.
    assert!(!split_rx
        .recv_timeout(Duration::from_secs(1))
        .unwrap()
        .get_header()
        .has_error());

    // The write request fails due to epoch not match.
    cb_receivers.assert_err();

    // New write request can succeed.
    let write_req = make_write_req(&mut cluster, b"k1");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_ok();
}

#[test]
fn test_reject_proposal_during_region_merge() {
    let mut cluster = new_node_cluster(0, 3);
    configure_for_merge(&mut cluster);
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_operator();
    cluster.run();
    cluster.must_transfer_leader(1, new_peer(1, 1));
    cluster.must_put(b"k", b"v");

    let r = cluster.get_region(b"");
    cluster.must_split(&r, b"k");
    // Let the new region catch up.
    cluster.must_put(b"a", b"v");
    cluster.must_put(b"k", b"v");

    let prepare_merge_fp = "apply_before_prepare_merge";
    let commit_merge_fp = "apply_before_commit_merge";

    // Pause on applying so that prepare-merge is not finished.
    fail::cfg(prepare_merge_fp, "pause").unwrap();
    // Try to merge region.
    let (merge_tx, merge_rx) = mpsc::channel();
    let cb = Callback::Read(Box::new(move |resp: ReadResponse<RocksSnapshot>| {
        merge_tx.send(resp.response).unwrap()
    }));
    let source = cluster.get_region(b"");
    let target = cluster.get_region(b"k");
    cluster.merge_region(source.get_id(), target.get_id(), cb);
    merge_rx
        .recv_timeout(Duration::from_millis(100))
        .unwrap_err();

    // Try to put a key on the source region.
    let write_req = make_write_req(&mut cluster, b"a");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    // The write request should be blocked until prepare-merge is finished.
    cb_receivers.assert_not_ready();

    // Pause on the second phase of region merge.
    fail::cfg(commit_merge_fp, "pause").unwrap();

    // prepare-merge is finished.
    fail::remove(prepare_merge_fp);
    assert!(!merge_rx
        .recv_timeout(Duration::from_secs(1))
        .unwrap()
        .get_header()
        .has_error());
    // The write request fails due to epoch not match.
    cb_receivers.assert_err();

    // Write request is rejected because the source region is merging.
    // It's not handled by epoch checker now.
    let write_req = make_write_req(&mut cluster, b"a");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_err();

    // Try to put a key on the target region.
    let write_req = make_write_req(&mut cluster, b"k");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    // The write request should be blocked until commit-merge is finished.
    cb_receivers.assert_not_ready();

    // Wait for region merge done.
    fail::remove(commit_merge_fp);
    pd_client.check_merged_timeout(source.get_id(), Duration::from_secs(1));
    // The write request fails due to epoch not match.
    cb_receivers.assert_err();

    // New write request can succeed.
    let write_req = make_write_req(&mut cluster, b"k");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_ok();
}

#[test]
fn test_reject_proposal_during_rollback_region_merge() {
    let mut cluster = new_node_cluster(0, 2);
    configure_for_merge(&mut cluster);
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_operator();
    cluster.run_conf_change();

    let r = cluster.get_region(b"");
    cluster.must_split(&r, b"k");

    // Don't enter the second phase of region merge.
    let schedule_merge_fp = "on_schedule_merge";
    fail::cfg(schedule_merge_fp, "return()").unwrap();

    let source = cluster.get_region(b"");
    let target = cluster.get_region(b"k");
    // The call is finished when prepare_merge is applied.
    cluster.must_try_merge(source.get_id(), target.get_id());

    // Add a peer to trigger rollback.
    pd_client.must_add_peer(target.get_id(), new_peer(2, 4));
    cluster.must_put(b"k", b"v");
    must_get_equal(&cluster.get_engine(1), b"k", b"v");

    // Pause on applying so that rolling back merge is not finished.
    let rollback_merge_fp = "apply_before_rollback_merge";
    fail::cfg(rollback_merge_fp, "pause").unwrap();
    fail::remove(schedule_merge_fp);
    sleep_ms(200);

    // Write request is rejected because the source region is merging.
    // It's not handled by epoch checker now.
    let write_req = make_write_req(&mut cluster, b"a");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_err();

    fail::remove(rollback_merge_fp);
    // Make sure the rollback is done.
    cluster.must_put(b"a", b"v");

    // New write request can succeed.
    let write_req = make_write_req(&mut cluster, b"a");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_ok();
}

#[test]
fn test_reject_proposal_during_leader_transfer() {
    let mut cluster = new_node_cluster(0, 2);
    let pd_client = cluster.pd_client.clone();
    pd_client.disable_default_operator();
    let r = cluster.run_conf_change();
    pd_client.must_add_peer(r, new_peer(2, 2));

    // Don't allow leader transfer succeed if it is actually triggered.
    cluster.add_send_filter(CloneFilterFactory(
        RegionPacketFilter::new(r, 2)
            .msg_type(MessageType::MsgTimeoutNow)
            .direction(Direction::Recv),
    ));

    cluster.must_put(b"k", b"v");
    cluster.transfer_leader(r, new_peer(2, 2));
    // The leader can't change to transferring state immediately due to pre-transfer-leader
    // feature, so wait for a while.
    sleep_ms(100);
    assert_ne!(cluster.leader_of_region(r).unwrap(), new_peer(2, 2));

    let write_req = make_write_req(&mut cluster, b"k");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers.assert_err();
    cluster.clear_send_filters();
}

#[test]
fn test_accept_proposal_during_conf_change() {
    let mut cluster = new_node_cluster(0, 2);
    cluster.pd_client.disable_default_operator();
    let r = cluster.run_conf_change();
    cluster.must_put(b"a", b"v");

    let conf_change_fp = "apply_on_conf_change_all_1";
    fail::cfg(conf_change_fp, "pause").unwrap();
    let add_peer_rx = cluster.async_add_peer(r, new_peer(2, 2)).unwrap();
    add_peer_rx
        .recv_timeout(Duration::from_millis(100))
        .unwrap_err();

    // Conf change doesn't affect proposals.
    let write_req = make_write_req(&mut cluster, b"k");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    cb_receivers
        .committed
        .recv_timeout(Duration::from_millis(300))
        .unwrap();
    cb_receivers.proposed.try_recv().unwrap();

    fail::remove(conf_change_fp);
    assert!(!add_peer_rx
        .recv_timeout(Duration::from_secs(1))
        .unwrap()
        .get_header()
        .has_error());
    assert!(!cb_receivers
        .applied
        .recv_timeout(Duration::from_secs(1))
        .unwrap()
        .get_header()
        .has_error());
    must_get_equal(&cluster.get_engine(2), b"k", b"v");
}

#[test]
fn test_not_invoke_committed_cb_when_fail_to_commit() {
    let mut cluster = new_node_cluster(0, 3);
    cluster.pd_client.disable_default_operator();
    cluster.run();
    cluster.must_transfer_leader(1, new_peer(1, 1));
    cluster.must_put(b"k", b"v");

    // Partiton the leader and followers to let the leader fails to commit the proposal.
    cluster.partition(vec![1], vec![2, 3]);
    let write_req = make_write_req(&mut cluster, b"k1");
    let (cb, cb_receivers) = make_cb(&write_req);
    cluster
        .sim
        .rl()
        .async_command_on_node(1, write_req, cb)
        .unwrap();
    // Check the request is proposed but not committed.
    cb_receivers
        .committed
        .recv_timeout(Duration::from_millis(200))
        .unwrap_err();
    cb_receivers.proposed.try_recv().unwrap();

    // The election timeout is 250ms by default.
    let election_timeout = cluster.cfg.raft_store.raft_base_tick_interval.0
        * cluster.cfg.raft_store.raft_election_timeout_ticks as u32;
    std::thread::sleep(2 * election_timeout);

    // Make sure a new leader is elected and will discard the previous proposal when partition is
    // recovered.
    cluster.must_put(b"k2", b"v");
    cluster.clear_send_filters();

    let resp = cb_receivers
        .applied
        .recv_timeout(Duration::from_secs(1))
        .unwrap();
    assert!(resp.get_header().has_error(), "{:?}", resp);
    // The committed callback shouldn't be invoked.
    cb_receivers.committed.try_recv().unwrap_err();
}
<|endoftext|>