<commit_before>use hir::HirDisplay;
use syntax::{ast, AstNode, TextRange, TextSize};
use test_utils::mark;

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: infer_function_return_type
//
// Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return
// type specified. This assists is useable in a functions or closures tail expression or return type position.
//
// ```
// fn foo() { 4<|>2i32 }
// ```
// ->
// ```
// fn foo() -> i32 { 42i32 }
// ```
pub(crate) fn infer_function_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let (tail_expr, builder_edit_pos, wrap_expr) = extract_tail(ctx)?;
    let module = ctx.sema.scope(tail_expr.syntax()).module()?;
    let ty = ctx.sema.type_of_expr(&tail_expr)?;
    if ty.is_unit() {
        return None;
    }
    let ty = ty.display_source_code(ctx.db(), module.into()).ok()?;

    acc.add(
        AssistId("infer_function_return_type", AssistKind::RefactorRewrite),
        "Add this function's return type",
        tail_expr.syntax().text_range(),
        |builder| {
            match builder_edit_pos {
                InsertOrReplace::Insert(insert_pos) => {
                    builder.insert(insert_pos, &format!("-> {} ", ty))
                }
                InsertOrReplace::Replace(text_range) => {
                    builder.replace(text_range, &format!("-> {}", ty))
                }
            }
            if wrap_expr {
                mark::hit!(wrap_closure_non_block_expr);
                // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
                builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
            }
        },
    )
}

enum InsertOrReplace {
    Insert(TextSize),
    Replace(TextRange),
}

/// Check the potentially already specified return type and reject it or turn it into a builder command
/// if allowed.
fn ret_ty_to_action(ret_ty: Option<ast::RetType>, insert_pos: TextSize) -> Option<InsertOrReplace> {
    match ret_ty {
        Some(ret_ty) => match ret_ty.ty() {
            Some(ast::Type::InferType(_)) | None => {
                mark::hit!(existing_infer_ret_type);
                mark::hit!(existing_infer_ret_type_closure);
                Some(InsertOrReplace::Replace(ret_ty.syntax().text_range()))
            }
            _ => {
                mark::hit!(existing_ret_type);
                mark::hit!(existing_ret_type_closure);
                None
            }
        },
        None => Some(InsertOrReplace::Insert(insert_pos + TextSize::from(1))),
    }
}

fn extract_tail(ctx: &AssistContext) -> Option<(ast::Expr, InsertOrReplace, bool)> {
    let (tail_expr, return_type_range, action, wrap_expr) =
        if let Some(closure) = ctx.find_node_at_offset::<ast::ClosureExpr>() {
            let rpipe_pos = closure.param_list()?.syntax().last_token()?.text_range().end();
            let action = ret_ty_to_action(closure.ret_type(), rpipe_pos)?;

            let body = closure.body()?;
            let body_start = body.syntax().first_token()?.text_range().start();
            let (tail_expr, wrap_expr) = match body {
                ast::Expr::BlockExpr(block) => (block.expr()?, false),
                body => (body, true),
            };

            let ret_range = TextRange::new(rpipe_pos, body_start);
            (tail_expr, ret_range, action, wrap_expr)
        } else {
            let func = ctx.find_node_at_offset::<ast::Fn>()?;
            let rparen_pos = func.param_list()?.r_paren_token()?.text_range().end();
            let action = ret_ty_to_action(func.ret_type(), rparen_pos)?;

            let body = func.body()?;
            let tail_expr = body.expr()?;

            let ret_range_end = body.l_curly_token()?.text_range().start();
            let ret_range = TextRange::new(rparen_pos, ret_range_end);
            (tail_expr, ret_range, action, false)
        };
    let frange = ctx.frange.range;
    if return_type_range.contains_range(frange) {
        mark::hit!(cursor_in_ret_position);
        mark::hit!(cursor_in_ret_position_closure);
    } else if tail_expr.syntax().text_range().contains_range(frange) {
        mark::hit!(cursor_on_tail);
        mark::hit!(cursor_on_tail_closure);
    } else {
        return None;
    }
    Some((tail_expr, action, wrap_expr))
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn infer_return_type_specified_inferred() {
        mark::check!(existing_infer_ret_type);
        check_assist(
            infer_function_return_type,
            r#"fn foo() -> <|>_ {
                45
            }"#,
            r#"fn foo() -> i32 {
                45
            }"#,
        );
    }

    #[test]
    fn infer_return_type_specified_inferred_closure() {
        mark::check!(existing_infer_ret_type_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                || -> _ {<|>45};
            }"#,
            r#"fn foo() {
                || -> i32 {45};
            }"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos() {
        mark::check!(cursor_in_ret_position);
        check_assist(
            infer_function_return_type,
            r#"fn foo() <|>{
                45
            }"#,
            r#"fn foo() -> i32 {
                45
            }"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos_closure() {
        mark::check!(cursor_in_ret_position_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                || <|>45
            }"#,
            r#"fn foo() {
                || -> i32 {45}
            }"#,
        );
    }

    #[test]
    fn infer_return_type() {
        mark::check!(cursor_on_tail);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                45<|>
            }"#,
            r#"fn foo() -> i32 {
                45
            }"#,
        );
    }

    #[test]
    fn infer_return_type_nested() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                if true {
                    3<|>
                } else {
                    5
                }
            }"#,
            r#"fn foo() -> i32 {
                if true {
                    3
                } else {
                    5
                }
            }"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified() {
        mark::check!(existing_ret_type);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() -> i32 {
                ( 45<|> + 32 ) * 123
            }"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                let x = <|>3;
                ( 45 + 32 ) * 123
            }"#,
        );
    }

    #[test]
    fn not_applicable_unit_return_type() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                (<|>)
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure_block() {
        mark::check!(cursor_on_tail_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| {
                    x<|>
                };
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 {
                    x
                };
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| { x<|> };
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 { x };
            }"#,
        );
    }

    #[test]
    fn infer_return_type_closure_wrap() {
        mark::check!(wrap_closure_non_block_expr);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                |x: i32| x<|>;
            }"#,
            r#"fn foo() {
                |x: i32| -> i32 {x};
            }"#,
        );
    }

    #[test]
    fn infer_return_type_nested_closure() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
                || {
                    if true {
                        3<|>
                    } else {
                        5
                    }
                }
            }"#,
            r#"fn foo() {
                || -> i32 {
                    if true {
                        3
                    } else {
                        5
                    }
                }
            }"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified_closure() {
        mark::check!(existing_ret_type_closure);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                || -> i32 { 3<|> }
            }"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr_closure() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
                || -> i32 {
                    let x = 3<|>;
                    6
                }
            }"#,
        );
    }
}
<commit_msg>Adjust test-texts in infer_function_return_type<commit_after>use hir::HirDisplay;
use syntax::{ast, AstNode, TextRange, TextSize};
use test_utils::mark;

use crate::{AssistContext, AssistId, AssistKind, Assists};

// Assist: infer_function_return_type
//
// Adds the return type to a function or closure inferred from its tail expression if it doesn't have a return
// type specified. This assists is useable in a functions or closures tail expression or return type position.
//
// ```
// fn foo() { 4<|>2i32 }
// ```
// ->
// ```
// fn foo() -> i32 { 42i32 }
// ```
pub(crate) fn infer_function_return_type(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
    let (tail_expr, builder_edit_pos, wrap_expr) = extract_tail(ctx)?;
    let module = ctx.sema.scope(tail_expr.syntax()).module()?;
    let ty = ctx.sema.type_of_expr(&tail_expr)?;
    if ty.is_unit() {
        return None;
    }
    let ty = ty.display_source_code(ctx.db(), module.into()).ok()?;

    acc.add(
        AssistId("infer_function_return_type", AssistKind::RefactorRewrite),
        "Add this function's return type",
        tail_expr.syntax().text_range(),
        |builder| {
            match builder_edit_pos {
                InsertOrReplace::Insert(insert_pos) => {
                    builder.insert(insert_pos, &format!("-> {} ", ty))
                }
                InsertOrReplace::Replace(text_range) => {
                    builder.replace(text_range, &format!("-> {}", ty))
                }
            }
            if wrap_expr {
                mark::hit!(wrap_closure_non_block_expr);
                // `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
                builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
            }
        },
    )
}

enum InsertOrReplace {
    Insert(TextSize),
    Replace(TextRange),
}

/// Check the potentially already specified return type and reject it or turn it into a builder command
/// if allowed.
fn ret_ty_to_action(ret_ty: Option<ast::RetType>, insert_pos: TextSize) -> Option<InsertOrReplace> {
    match ret_ty {
        Some(ret_ty) => match ret_ty.ty() {
            Some(ast::Type::InferType(_)) | None => {
                mark::hit!(existing_infer_ret_type);
                mark::hit!(existing_infer_ret_type_closure);
                Some(InsertOrReplace::Replace(ret_ty.syntax().text_range()))
            }
            _ => {
                mark::hit!(existing_ret_type);
                mark::hit!(existing_ret_type_closure);
                None
            }
        },
        None => Some(InsertOrReplace::Insert(insert_pos + TextSize::from(1))),
    }
}

fn extract_tail(ctx: &AssistContext) -> Option<(ast::Expr, InsertOrReplace, bool)> {
    let (tail_expr, return_type_range, action, wrap_expr) =
        if let Some(closure) = ctx.find_node_at_offset::<ast::ClosureExpr>() {
            let rpipe_pos = closure.param_list()?.syntax().last_token()?.text_range().end();
            let action = ret_ty_to_action(closure.ret_type(), rpipe_pos)?;

            let body = closure.body()?;
            let body_start = body.syntax().first_token()?.text_range().start();
            let (tail_expr, wrap_expr) = match body {
                ast::Expr::BlockExpr(block) => (block.expr()?, false),
                body => (body, true),
            };

            let ret_range = TextRange::new(rpipe_pos, body_start);
            (tail_expr, ret_range, action, wrap_expr)
        } else {
            let func = ctx.find_node_at_offset::<ast::Fn>()?;
            let rparen_pos = func.param_list()?.r_paren_token()?.text_range().end();
            let action = ret_ty_to_action(func.ret_type(), rparen_pos)?;

            let body = func.body()?;
            let tail_expr = body.expr()?;

            let ret_range_end = body.l_curly_token()?.text_range().start();
            let ret_range = TextRange::new(rparen_pos, ret_range_end);
            (tail_expr, ret_range, action, false)
        };
    let frange = ctx.frange.range;
    if return_type_range.contains_range(frange) {
        mark::hit!(cursor_in_ret_position);
        mark::hit!(cursor_in_ret_position_closure);
    } else if tail_expr.syntax().text_range().contains_range(frange) {
        mark::hit!(cursor_on_tail);
        mark::hit!(cursor_on_tail_closure);
    } else {
        return None;
    }
    Some((tail_expr, action, wrap_expr))
}

#[cfg(test)]
mod tests {
    use crate::tests::{check_assist, check_assist_not_applicable};

    use super::*;

    #[test]
    fn infer_return_type_specified_inferred() {
        mark::check!(existing_infer_ret_type);
        check_assist(
            infer_function_return_type,
            r#"fn foo() -> <|>_ {
    45
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_specified_inferred_closure() {
        mark::check!(existing_infer_ret_type_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
    || -> _ {<|>45};
}"#,
            r#"fn foo() {
    || -> i32 {45};
}"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos() {
        mark::check!(cursor_in_ret_position);
        check_assist(
            infer_function_return_type,
            r#"fn foo() <|>{
    45
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_cursor_at_return_type_pos_closure() {
        mark::check!(cursor_in_ret_position_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
    || <|>45
}"#,
            r#"fn foo() {
    || -> i32 {45}
}"#,
        );
    }

    #[test]
    fn infer_return_type() {
        mark::check!(cursor_on_tail);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
    45<|>
}"#,
            r#"fn foo() -> i32 {
    45
}"#,
        );
    }

    #[test]
    fn infer_return_type_nested() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
    if true {
        3<|>
    } else {
        5
    }
}"#,
            r#"fn foo() -> i32 {
    if true {
        3
    } else {
        5
    }
}"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified() {
        mark::check!(existing_ret_type);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() -> i32 {
    ( 45<|> + 32 ) * 123
}"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
    let x = <|>3;
    ( 45 + 32 ) * 123
}"#,
        );
    }

    #[test]
    fn not_applicable_unit_return_type() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
    (<|>)
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure_block() {
        mark::check!(cursor_on_tail_closure);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
    |x: i32| {
        x<|>
    };
}"#,
            r#"fn foo() {
    |x: i32| -> i32 {
        x
    };
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
    |x: i32| { x<|> };
}"#,
            r#"fn foo() {
    |x: i32| -> i32 { x };
}"#,
        );
    }

    #[test]
    fn infer_return_type_closure_wrap() {
        mark::check!(wrap_closure_non_block_expr);
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
    |x: i32| x<|>;
}"#,
            r#"fn foo() {
    |x: i32| -> i32 {x};
}"#,
        );
    }

    #[test]
    fn infer_return_type_nested_closure() {
        check_assist(
            infer_function_return_type,
            r#"fn foo() {
    || {
        if true {
            3<|>
        } else {
            5
        }
    }
}"#,
            r#"fn foo() {
    || -> i32 {
        if true {
            3
        } else {
            5
        }
    }
}"#,
        );
    }

    #[test]
    fn not_applicable_ret_type_specified_closure() {
        mark::check!(existing_ret_type_closure);
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
    || -> i32 { 3<|> }
}"#,
        );
    }

    #[test]
    fn not_applicable_non_tail_expr_closure() {
        check_assist_not_applicable(
            infer_function_return_type,
            r#"fn foo() {
    || -> i32 {
        let x = 3<|>;
        6
    }
}"#,
        );
    }
}
<|endoftext|>


<commit_before>// TODO:
//
// - Better error reporting

extern crate libc;

use std::collections::HashMap;
use std::ops::BitOr;

pub struct EvLoop {
    fds: HashMap<libc::c_int, Handler>,
}

enum Handler {
    Timer { cb: Box<Fn(&mut EvLoopController) -> ()> },
    Signal { cb: Box<Fn(&mut EvLoopController) -> ()> },
    Fd { evs: FdEv, cb: Box<Fn(FdEv, &mut EvLoopController) -> ()> },
}

/// File descriptor events. Use bitwise or to combine.
pub struct FdEv(libc::c_short);

pub const READ_EV: FdEv = FdEv(libc::POLLIN);
pub const WRITE_EV: FdEv = FdEv(libc::POLLOUT);
pub const ERR_EV: FdEv = FdEv(libc::POLLERR);
pub const HUP_EV: FdEv = FdEv(libc::POLLHUP);

impl BitOr for FdEv {
    type Output = FdEv;

    fn bitor(self, rhs: FdEv) -> FdEv {
        FdEv(self.0 | rhs.0)
    }
}

pub struct TimerRef(libc::c_int);
pub struct SignalRef(libc::c_int);

extern "C" {
    fn timerfd_create(
        clockid: libc::c_int,
        flags: libc::c_int
        ) -> libc::c_int;

    fn timerfd_settime(
        fd: libc::c_int,
        flags: libc::c_int,
        new_value: *const itimerspec,
        old_value: *mut itimerspec
        ) -> libc::c_int;

    // fn timerfd_gettime(
    //     fd: libc::c_int,
    //     curr_value: *mut libc::itimerspec
    //     ) -> libc::c_int;
}

// Can't find itimerspec in libc
#[repr(C)]
pub struct itimerspec {
    it_interval: libc::timespec,
    it_value: libc::timespec,
}

pub struct EvLoopController<'a> {
    stop_ref: &'a mut bool,
    remove_self: &'a mut bool,
}

impl<'a> EvLoopController<'a> {
    pub fn stop(&mut self) {
        *self.stop_ref = true;
    }

    pub fn remove_self(&mut self) {
        *self.remove_self = true;
    }
}

fn mk_timespec(millis: i64) -> libc::timespec {
    let secs: i64 = millis / 1000;
    let nanos: i64 = (millis % 1000) * 1000000;
    libc::timespec { tv_sec: secs, tv_nsec: nanos }
}

impl EvLoop {
    pub fn new() -> EvLoop {
        EvLoop { fds: HashMap::new() }
    }

    /// Register a non-blocking socket. Use the same fd for unregister.
    pub fn add_fd(&mut self, fd: libc::c_int, evs: FdEv, cb: Box<Fn(FdEv, &mut EvLoopController) -> ()>) {
        self.fds.insert(fd, Handler::Fd { evs: evs, cb: cb });
    }

    pub fn remove_fd(&mut self, fd: libc::c_int) {
        self.fds.remove(&fd);
    }

    /// `timeout` and `period` in milliseconds. `timeout` must be non-zero for this to work. If
    /// `period` is non-zero, timer expires repeatedly after the initial timeout.
    pub fn add_timer(&mut self, timeout: i64, period: i64, cb: Box<Fn(&mut EvLoopController) -> ()>) -> TimerRef {
        let fd = unsafe { timerfd_create(libc::CLOCK_MONOTONIC, libc::EFD_NONBLOCK) };
        assert!(fd != -1);

        let timeout_spec = mk_timespec(timeout);
        let period_spec = mk_timespec(period);
        let timerspec = itimerspec { it_interval: period_spec, it_value: timeout_spec };

        assert!(unsafe { timerfd_settime(fd, 0, &timerspec, std::ptr::null_mut()) } != -1);
        self.fds.insert(fd, Handler::Timer { cb: cb });
        TimerRef(fd)
    }

    pub fn remove_timer(&mut self, timer_ref: TimerRef) {
        assert!(unsafe { libc::close(timer_ref.0) } != -1);
        self.fds.remove(&timer_ref.0);
    }

    pub fn add_signal(&mut self, sigs: &libc::sigset_t, cb: Box<Fn(&mut EvLoopController) -> ()>) -> SignalRef {
        // Block the signals we handle using signalfd() so they don't cause signal handlers to run
        assert!(unsafe { libc::sigprocmask(libc::SIG_BLOCK, sigs as *const libc::sigset_t, std::ptr::null_mut()) } != -1);
        let fd = unsafe { libc::signalfd(-1, sigs, libc::EFD_NONBLOCK) };
        assert!(fd != -1);
        self.fds.insert(fd, Handler::Signal { cb: cb });
        SignalRef(fd)
    }

    pub fn remove_signal(&mut self, signal_ref: SignalRef) {
        self.fds.remove(&signal_ref.0);
    }

    pub fn run(&mut self) {
        let mut stop = false;
        while !stop {
            let mut fds: Vec<libc::pollfd> = Vec::with_capacity(self.fds.len());

            for (fd, handler) in self.fds.iter() {
                match handler {
                    &Handler::Timer{ .. } | &Handler::Signal{ .. } => {
                        fds.push(libc::pollfd { fd: *fd, events: libc::POLLIN, revents: 0 });
                    }
                    &Handler::Fd{ ref evs, .. } => {
                        fds.push(libc::pollfd { fd: *fd, events: evs.0, revents: 0 });
                    }
                }
            }

            assert!(unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as u64, -1) } != -1);

            for pollfd in fds {
                if pollfd.revents != 0 {

                    let mut remove_fd = false;
                    {
                        let mut controller = EvLoopController { stop_ref: &mut stop, remove_self: &mut remove_fd };

                        match self.fds.get(&pollfd.fd).unwrap() {
                            &Handler::Timer{ ref cb } | &Handler::Signal{ ref cb } => {
                                cb(&mut controller);
                            }
                            &Handler::Fd{ ref cb, .. } => {
                                cb(FdEv(pollfd.revents), &mut controller);
                            }
                        }
                    }

                    if remove_fd {
                        self.fds.remove(&pollfd.fd);
                    }
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::cell::RefCell;
    use std::rc::Rc;

    #[test]
    fn it_works() {
        let it_worked: Rc<RefCell<bool>> = Rc::new(RefCell::new(false));

        let mut ev_loop = EvLoop::new();
        {
            let it_worked_clone = it_worked.clone();
            ev_loop.add_timer(100, 100, Box::new(move |ctrl| {
                *it_worked_clone.borrow_mut() = true;
                ctrl.stop();
            }));
        }
        ev_loop.run();

        assert!(*(*it_worked).borrow());
    }

    #[test]
    fn it_works_2() {
        let cb1: Rc<RefCell<bool>> = Rc::new(RefCell::new(false));
        let cb2: Rc<RefCell<bool>> = Rc::new(RefCell::new(false));
        let cb3: Rc<RefCell<bool>> = Rc::new(RefCell::new(false));

        let mut ev_loop = EvLoop::new();

        {
            let var = cb1.clone();
            ev_loop.add_timer(100, 100, Box::new(move |ctrl| {
                assert!(*(*var).borrow() == false);
                *var.borrow_mut() = true;
                ctrl.remove_self();
            }));
        }

        {
            let var = cb2.clone();
            ev_loop.add_timer(100, 100, Box::new(move |ctrl| {
                assert!(*(*var).borrow() == false);
                *var.borrow_mut() = true;
                ctrl.remove_self();
            }));
        }

        {
            let fd = unsafe { timerfd_create(libc::CLOCK_MONOTONIC, libc::EFD_NONBLOCK) };
            assert!(fd != -1);

            let timeout_spec = mk_timespec(300);
            let period_spec = mk_timespec(300);
            let timerspec = itimerspec { it_interval: period_spec, it_value: timeout_spec };

            assert!(unsafe { timerfd_settime(fd, 0, &timerspec, std::ptr::null_mut()) } != -1);
            let var = cb3.clone();
            ev_loop.add_fd(fd, READ_EV, Box::new(move |_, ctrl| {
                assert!(*(*var).borrow() == false);
                *var.borrow_mut() = true;
                ctrl.remove_self();
                ctrl.stop();
            }));
        }

        ev_loop.run();

        assert!(*(*cb1).borrow());
        assert!(*(*cb2).borrow());
        assert!(*(*cb3).borrow());
    }
}
<commit_msg>ev_loop: Add simple context support<commit_after>// TODO:
//
// - Better error reporting

extern crate libc;

use std::collections::HashMap;
use std::ops::BitOr;

pub struct EvLoop<Ctx> {
    fds: HashMap<libc::c_int, Handler<Ctx>>,
}

enum Handler<Ctx> {
    Timer { cb: Box<Fn(&mut EvLoopController, &mut Ctx) -> ()> },
    Signal { cb: Box<Fn(&mut EvLoopController, &mut Ctx) -> ()> },
    Fd { evs: FdEv, cb: Box<Fn(FdEv, &mut EvLoopController, &mut Ctx) -> ()> },
}

/// File descriptor events. Use bitwise or to combine.
pub struct FdEv(libc::c_short);

pub const READ_EV: FdEv = FdEv(libc::POLLIN);
pub const WRITE_EV: FdEv = FdEv(libc::POLLOUT);
pub const ERR_EV: FdEv = FdEv(libc::POLLERR);
pub const HUP_EV: FdEv = FdEv(libc::POLLHUP);

impl BitOr for FdEv {
    type Output = FdEv;

    fn bitor(self, rhs: FdEv) -> FdEv {
        FdEv(self.0 | rhs.0)
    }
}

pub struct TimerRef(libc::c_int);
pub struct SignalRef(libc::c_int);

extern "C" {
    fn timerfd_create(
        clockid: libc::c_int,
        flags: libc::c_int
        ) -> libc::c_int;

    fn timerfd_settime(
        fd: libc::c_int,
        flags: libc::c_int,
        new_value: *const itimerspec,
        old_value: *mut itimerspec
        ) -> libc::c_int;

    // fn timerfd_gettime(
    //     fd: libc::c_int,
    //     curr_value: *mut libc::itimerspec
    //     ) -> libc::c_int;
}

// Can't find itimerspec in libc
#[repr(C)]
pub struct itimerspec {
    it_interval: libc::timespec,
    it_value: libc::timespec,
}

pub struct EvLoopController<'a> {
    stop_ref: &'a mut bool,
    remove_self: &'a mut bool,
}

impl<'a> EvLoopController<'a> {
    pub fn stop(&mut self) {
        *self.stop_ref = true;
    }

    pub fn remove_self(&mut self) {
        *self.remove_self = true;
    }
}

fn mk_timespec(millis: i64) -> libc::timespec {
    let secs: i64 = millis / 1000;
    let nanos: i64 = (millis % 1000) * 1000000;
    libc::timespec { tv_sec: secs, tv_nsec: nanos }
}

impl<Ctx> EvLoop<Ctx> {
    pub fn new() -> EvLoop<Ctx> {
        EvLoop { fds: HashMap::new() }
    }

    /// Register a non-blocking socket. Use the same fd for unregister.
    pub fn add_fd(&mut self, fd: libc::c_int, evs: FdEv, cb: Box<Fn(FdEv, &mut EvLoopController, &mut Ctx) -> ()>) {
        self.fds.insert(fd, Handler::Fd { evs: evs, cb: cb });
    }

    pub fn remove_fd(&mut self, fd: libc::c_int) {
        self.fds.remove(&fd);
    }

    /// `timeout` and `period` in milliseconds. `timeout` must be non-zero for this to work. If
    /// `period` is non-zero, timer expires repeatedly after the initial timeout.
    pub fn add_timer(&mut self, timeout: i64, period: i64, cb: Box<Fn(&mut EvLoopController, &mut Ctx) -> ()>) -> TimerRef {
        let fd = unsafe { timerfd_create(libc::CLOCK_MONOTONIC, libc::EFD_NONBLOCK) };
        assert!(fd != -1);

        let timeout_spec = mk_timespec(timeout);
        let period_spec = mk_timespec(period);
        let timerspec = itimerspec { it_interval: period_spec, it_value: timeout_spec };

        assert!(unsafe { timerfd_settime(fd, 0, &timerspec, std::ptr::null_mut()) } != -1);
        self.fds.insert(fd, Handler::Timer { cb: cb });
        TimerRef(fd)
    }

    pub fn remove_timer(&mut self, timer_ref: TimerRef) {
        assert!(unsafe { libc::close(timer_ref.0) } != -1);
        self.fds.remove(&timer_ref.0);
    }

    pub fn add_signal(&mut self, sigs: &libc::sigset_t, cb: Box<Fn(&mut EvLoopController, &mut Ctx) -> ()>) -> SignalRef {
        // Block the signals we handle using signalfd() so they don't cause signal handlers to run
        assert!(unsafe { libc::sigprocmask(libc::SIG_BLOCK, sigs as *const libc::sigset_t, std::ptr::null_mut()) } != -1);
        let fd = unsafe { libc::signalfd(-1, sigs, libc::EFD_NONBLOCK) };
        assert!(fd != -1);
        self.fds.insert(fd, Handler::Signal { cb: cb });
        SignalRef(fd)
    }

    pub fn remove_signal(&mut self, signal_ref: SignalRef) {
        self.fds.remove(&signal_ref.0);
    }

    pub fn run(&mut self, mut ctx: Ctx) -> Ctx {
        let mut stop = false;
        while !stop {
            let mut fds: Vec<libc::pollfd> = Vec::with_capacity(self.fds.len());

            for (fd, handler) in self.fds.iter() {
                match handler {
                    &Handler::Timer{ .. } | &Handler::Signal{ .. } => {
                        fds.push(libc::pollfd { fd: *fd, events: libc::POLLIN, revents: 0 });
                    }
                    &Handler::Fd{ ref evs, .. } => {
                        fds.push(libc::pollfd { fd: *fd, events: evs.0, revents: 0 });
                    }
                }
            }

            assert!(unsafe { libc::poll(fds.as_mut_ptr(), fds.len() as u64, -1) } != -1);

            for pollfd in fds {
                if pollfd.revents != 0 {

                    let mut remove_fd = false;
                    {
                        let mut controller = EvLoopController { stop_ref: &mut stop, remove_self: &mut remove_fd };

                        match self.fds.get(&pollfd.fd).unwrap() {
                            &Handler::Timer{ ref cb } | &Handler::Signal{ ref cb } => {
                                cb(&mut controller, &mut ctx);
                            }
                            &Handler::Fd{ ref cb, .. } => {
                                cb(FdEv(pollfd.revents), &mut controller, &mut ctx);
                            }
                        }
                    }

                    if remove_fd {
                        self.fds.remove(&pollfd.fd);
                    }
                }
            }
        }
        ctx
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::cell::RefCell;
    use std::rc::Rc;

    #[test]
    fn it_works() {
        let it_worked: Rc<RefCell<bool>> = Rc::new(RefCell::new(false));

        let mut ev_loop = EvLoop::new();
        {
            let it_worked_clone = it_worked.clone();
            ev_loop.add_timer(100, 100, Box::new(move |ctrl, _| {
                *it_worked_clone.borrow_mut() = true;
                ctrl.stop();
            }));
        }
        ev_loop.run(());

        assert!(*(*it_worked).borrow());
    }

    #[test]
    fn it_works_2() {
        struct Ctx {
            cb1: bool,
            cb2: bool,
            cb3: bool,
        }

        let mut ev_loop: EvLoop<Ctx> = EvLoop::new();

        ev_loop.add_timer(100, 100, Box::new(move |ctrl, ctx| {
            assert!(ctx.cb1 == false);
            ctx.cb1 = true;
            ctrl.remove_self();
        }));

        ev_loop.add_timer(100, 100, Box::new(move |ctrl, ctx| {
            assert!(ctx.cb2 == false);
            ctx.cb2 = true;
            ctrl.remove_self();
        }));

        {
            let fd = unsafe { timerfd_create(libc::CLOCK_MONOTONIC, libc::EFD_NONBLOCK) };
            assert!(fd != -1);

            let timeout_spec = mk_timespec(300);
            let period_spec = mk_timespec(300);
            let timerspec = itimerspec { it_interval: period_spec, it_value: timeout_spec };

            assert!(unsafe { timerfd_settime(fd, 0, &timerspec, std::ptr::null_mut()) } != -1);
            ev_loop.add_fd(fd, READ_EV, Box::new(move |_, ctrl, ctx| {
                assert!(ctx.cb3 == false);
                ctx.cb3 = true;
                ctrl.remove_self();
                ctrl.stop();
            }));
        }

        let ctx = ev_loop.run(Ctx { cb1: false, cb2: false, cb3: false });

        assert!(ctx.cb1);
        assert!(ctx.cb2);
        assert!(ctx.cb3);
    }
}
<|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/. */

pub use servo_util::geometry::Au;

pub type CSSFloat = f64;

pub mod specified {
    use std::ascii::StrAsciiExt;
    use cssparser::*;
    use super::{Au, CSSFloat};
    pub use CSSColor = cssparser::Color;

    #[deriving(Clone)]
    pub enum Length {
        Au_(Au),  // application units
        Em(CSSFloat),
        Ex(CSSFloat),
        // XXX uncomment when supported:
//        Ch(CSSFloat),
//        Rem(CSSFloat),
//        Vw(CSSFloat),
//        Vh(CSSFloat),
//        Vmin(CSSFloat),
//        Vmax(CSSFloat),
    }
    static AU_PER_PX: CSSFloat = 60.;
    static AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
    static AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
    static AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
    static AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
    static AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
    impl Length {
        #[inline]
        fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Option<Length> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()),
                &Number(ref value) if value.value == 0. =>  Some(Au_(Au(0))),
                _ => None
            }
        }
        pub fn parse(input: &ComponentValue) -> Option<Length> {
            Length::parse_internal(input, /* negative_ok = */ true)
        }
        pub fn parse_non_negative(input: &ComponentValue) -> Option<Length> {
            Length::parse_internal(input, /* negative_ok = */ false)
        }
        pub fn parse_dimension(value: CSSFloat, unit: &str) -> Option<Length> {
            match unit.to_ascii_lower().as_slice() {
                "px" => Some(Length::from_px(value)),
                "in" => Some(Au_(Au((value * AU_PER_IN) as i32))),
                "cm" => Some(Au_(Au((value * AU_PER_CM) as i32))),
                "mm" => Some(Au_(Au((value * AU_PER_MM) as i32))),
                "pt" => Some(Au_(Au((value * AU_PER_PT) as i32))),
                "pc" => Some(Au_(Au((value * AU_PER_PC) as i32))),
                "em" => Some(Em(value)),
                "ex" => Some(Ex(value)),
                _ => None
            }
        }
        #[inline]
        pub fn from_px(px_value: CSSFloat) -> Length {
            Au_(Au((px_value * AU_PER_PX) as i32))
        }
    }

    #[deriving(Clone)]
    pub enum LengthOrPercentage {
        LP_Length(Length),
        LP_Percentage(CSSFloat),  // [0 .. 100%] maps to [0.0 .. 1.0]
    }
    impl LengthOrPercentage {
        fn parse_internal(input: &ComponentValue, negative_ok: bool)
                              -> Option<LengthOrPercentage> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()).map(LP_Length),
                &ast::Percentage(ref value) if negative_ok || value.value >= 0.
                => Some(LP_Percentage(value.value / 100.)),
                &Number(ref value) if value.value == 0. =>  Some(LP_Length(Au_(Au(0)))),
                _ => None
            }
        }
        #[inline]
        pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> {
            LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
        }
        #[inline]
        pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentage> {
            LengthOrPercentage::parse_internal(input, /* negative_ok = */ false)
        }
    }

    #[deriving(Clone)]
    pub enum LengthOrPercentageOrAuto {
        LPA_Length(Length),
        LPA_Percentage(CSSFloat),  // [0 .. 100%] maps to [0.0 .. 1.0]
        LPA_Auto,
    }
    impl LengthOrPercentageOrAuto {
        fn parse_internal(input: &ComponentValue, negative_ok: bool)
                     -> Option<LengthOrPercentageOrAuto> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()).map(LPA_Length),
                &ast::Percentage(ref value) if negative_ok || value.value >= 0.
                => Some(LPA_Percentage(value.value / 100.)),
                &Number(ref value) if value.value == 0. => Some(LPA_Length(Au_(Au(0)))),
                &Ident(ref value) if value.eq_ignore_ascii_case("auto") => Some(LPA_Auto),
                _ => None
            }
        }
        #[inline]
        pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> {
            LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true)
        }
        #[inline]
        pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> {
            LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false)
        }
    }
}

pub mod computed {
    use cssparser;
    pub use CSSColor = cssparser::Color;
    pub use compute_CSSColor = super::super::longhands::computed_as_specified;
    use super::*;
    use super::super::longhands;
    pub use servo_util::geometry::Au;

    pub struct Context {
        current_color: cssparser::RGBA,
        font_size: Au,
        font_weight: longhands::font_weight::computed_value::T,
        position: longhands::position::SpecifiedValue,
        float: longhands::float::SpecifiedValue,
        is_root_element: bool,
        has_border_top: bool,
        has_border_right: bool,
        has_border_bottom: bool,
        has_border_left: bool,
        // TODO, as needed: root font size, viewport size, etc.
    }

    #[inline]
    fn mul(a: Au, b: CSSFloat) -> Au { Au(((*a as CSSFloat) * b) as i32) }

    pub fn compute_Au(value: specified::Length, context: &Context) -> Au {
        match value {
            specified::Au_(value) => value,
            specified::Em(value) => mul(context.font_size, value),
            specified::Ex(value) => {
                let x_height = 0.5;  // TODO: find that from the font
                mul(context.font_size, value * x_height)
            },
        }
    }

    #[deriving(Eq, Clone)]
    pub enum LengthOrPercentage {
        LP_Length(Au),
        LP_Percentage(CSSFloat),
    }
    pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
                                   -> LengthOrPercentage {
        match value {
            specified::LP_Length(value) => LP_Length(compute_Au(value, context)),
            specified::LP_Percentage(value) => LP_Percentage(value),
        }
    }

    #[deriving(Eq, Clone)]
    pub enum LengthOrPercentageOrAuto {
        LPA_Length(Au),
        LPA_Percentage(CSSFloat),
        LPA_Auto,
    }
    pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
                                            context: &Context) -> LengthOrPercentageOrAuto {
        match value {
            specified::LPA_Length(value) => LPA_Length(compute_Au(value, context)),
            specified::LPA_Percentage(value) => LPA_Percentage(value),
            specified::LPA_Auto => LPA_Auto,
        }
    }
}
<commit_msg>Use Au::scale_by instead of duplicating it.<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/. */

pub use servo_util::geometry::Au;

pub type CSSFloat = f64;

pub mod specified {
    use std::ascii::StrAsciiExt;
    use cssparser::*;
    use super::{Au, CSSFloat};
    pub use CSSColor = cssparser::Color;

    #[deriving(Clone)]
    pub enum Length {
        Au_(Au),  // application units
        Em(CSSFloat),
        Ex(CSSFloat),
        // XXX uncomment when supported:
//        Ch(CSSFloat),
//        Rem(CSSFloat),
//        Vw(CSSFloat),
//        Vh(CSSFloat),
//        Vmin(CSSFloat),
//        Vmax(CSSFloat),
    }
    static AU_PER_PX: CSSFloat = 60.;
    static AU_PER_IN: CSSFloat = AU_PER_PX * 96.;
    static AU_PER_CM: CSSFloat = AU_PER_IN / 2.54;
    static AU_PER_MM: CSSFloat = AU_PER_IN / 25.4;
    static AU_PER_PT: CSSFloat = AU_PER_IN / 72.;
    static AU_PER_PC: CSSFloat = AU_PER_PT * 12.;
    impl Length {
        #[inline]
        fn parse_internal(input: &ComponentValue, negative_ok: bool) -> Option<Length> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()),
                &Number(ref value) if value.value == 0. =>  Some(Au_(Au(0))),
                _ => None
            }
        }
        pub fn parse(input: &ComponentValue) -> Option<Length> {
            Length::parse_internal(input, /* negative_ok = */ true)
        }
        pub fn parse_non_negative(input: &ComponentValue) -> Option<Length> {
            Length::parse_internal(input, /* negative_ok = */ false)
        }
        pub fn parse_dimension(value: CSSFloat, unit: &str) -> Option<Length> {
            match unit.to_ascii_lower().as_slice() {
                "px" => Some(Length::from_px(value)),
                "in" => Some(Au_(Au((value * AU_PER_IN) as i32))),
                "cm" => Some(Au_(Au((value * AU_PER_CM) as i32))),
                "mm" => Some(Au_(Au((value * AU_PER_MM) as i32))),
                "pt" => Some(Au_(Au((value * AU_PER_PT) as i32))),
                "pc" => Some(Au_(Au((value * AU_PER_PC) as i32))),
                "em" => Some(Em(value)),
                "ex" => Some(Ex(value)),
                _ => None
            }
        }
        #[inline]
        pub fn from_px(px_value: CSSFloat) -> Length {
            Au_(Au((px_value * AU_PER_PX) as i32))
        }
    }

    #[deriving(Clone)]
    pub enum LengthOrPercentage {
        LP_Length(Length),
        LP_Percentage(CSSFloat),  // [0 .. 100%] maps to [0.0 .. 1.0]
    }
    impl LengthOrPercentage {
        fn parse_internal(input: &ComponentValue, negative_ok: bool)
                              -> Option<LengthOrPercentage> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()).map(LP_Length),
                &ast::Percentage(ref value) if negative_ok || value.value >= 0.
                => Some(LP_Percentage(value.value / 100.)),
                &Number(ref value) if value.value == 0. =>  Some(LP_Length(Au_(Au(0)))),
                _ => None
            }
        }
        #[inline]
        pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentage> {
            LengthOrPercentage::parse_internal(input, /* negative_ok = */ true)
        }
        #[inline]
        pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentage> {
            LengthOrPercentage::parse_internal(input, /* negative_ok = */ false)
        }
    }

    #[deriving(Clone)]
    pub enum LengthOrPercentageOrAuto {
        LPA_Length(Length),
        LPA_Percentage(CSSFloat),  // [0 .. 100%] maps to [0.0 .. 1.0]
        LPA_Auto,
    }
    impl LengthOrPercentageOrAuto {
        fn parse_internal(input: &ComponentValue, negative_ok: bool)
                     -> Option<LengthOrPercentageOrAuto> {
            match input {
                &Dimension(ref value, ref unit) if negative_ok || value.value >= 0.
                => Length::parse_dimension(value.value, unit.as_slice()).map(LPA_Length),
                &ast::Percentage(ref value) if negative_ok || value.value >= 0.
                => Some(LPA_Percentage(value.value / 100.)),
                &Number(ref value) if value.value == 0. => Some(LPA_Length(Au_(Au(0)))),
                &Ident(ref value) if value.eq_ignore_ascii_case("auto") => Some(LPA_Auto),
                _ => None
            }
        }
        #[inline]
        pub fn parse(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> {
            LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ true)
        }
        #[inline]
        pub fn parse_non_negative(input: &ComponentValue) -> Option<LengthOrPercentageOrAuto> {
            LengthOrPercentageOrAuto::parse_internal(input, /* negative_ok = */ false)
        }
    }
}

pub mod computed {
    use cssparser;
    pub use CSSColor = cssparser::Color;
    pub use compute_CSSColor = super::super::longhands::computed_as_specified;
    use super::*;
    use super::super::longhands;
    pub use servo_util::geometry::Au;

    pub struct Context {
        current_color: cssparser::RGBA,
        font_size: Au,
        font_weight: longhands::font_weight::computed_value::T,
        position: longhands::position::SpecifiedValue,
        float: longhands::float::SpecifiedValue,
        is_root_element: bool,
        has_border_top: bool,
        has_border_right: bool,
        has_border_bottom: bool,
        has_border_left: bool,
        // TODO, as needed: root font size, viewport size, etc.
    }

    pub fn compute_Au(value: specified::Length, context: &Context) -> Au {
        match value {
            specified::Au_(value) => value,
            specified::Em(value) => context.font_size.scale_by(value),
            specified::Ex(value) => {
                let x_height = 0.5;  // TODO: find that from the font
                context.font_size.scale_by(value * x_height)
            },
        }
    }

    #[deriving(Eq, Clone)]
    pub enum LengthOrPercentage {
        LP_Length(Au),
        LP_Percentage(CSSFloat),
    }
    pub fn compute_LengthOrPercentage(value: specified::LengthOrPercentage, context: &Context)
                                   -> LengthOrPercentage {
        match value {
            specified::LP_Length(value) => LP_Length(compute_Au(value, context)),
            specified::LP_Percentage(value) => LP_Percentage(value),
        }
    }

    #[deriving(Eq, Clone)]
    pub enum LengthOrPercentageOrAuto {
        LPA_Length(Au),
        LPA_Percentage(CSSFloat),
        LPA_Auto,
    }
    pub fn compute_LengthOrPercentageOrAuto(value: specified::LengthOrPercentageOrAuto,
                                            context: &Context) -> LengthOrPercentageOrAuto {
        match value {
            specified::LPA_Length(value) => LPA_Length(compute_Au(value, context)),
            specified::LPA_Percentage(value) => LPA_Percentage(value),
            specified::LPA_Auto => LPA_Auto,
        }
    }
}
<|endoftext|>


<commit_before>use std::{env,
          ffi::OsString,
          fs as stdfs,
          path::PathBuf};

use crate::{common::ui::UI,
            hcore::{crypto::CACHE_KEY_PATH_ENV_VAR,
                    env as henv,
                    fs}};

use crate::{config,
            error::Result,
            BLDR_URL_ENVVAR,
            CTL_SECRET_ENVVAR,
            ORIGIN_ENVVAR};

use habitat_core::AUTH_TOKEN_ENVVAR;

pub const ARTIFACT_PATH_ENVVAR: &str = "ARTIFACT_PATH";

const STUDIO_CMD: &str = "hab-studio";
const STUDIO_CMD_ENVVAR: &str = "HAB_STUDIO_BINARY";
const STUDIO_PACKAGE_IDENT: &str = "core/hab-studio";

#[derive(Clone, Copy)]
enum Sensitivity {
    PrintValue,
    NoPrintValue,
}

fn set_env_var_from_config(env_var: &str, config_val: Option<String>, sensitive: Sensitivity) {
    if henv::var(env_var).is_err() {
        if let Some(val) = config_val {
            match sensitive {
                Sensitivity::NoPrintValue => {
                    debug!("Setting {}=REDACTED (sensitive) via config file", env_var)
                }
                Sensitivity::PrintValue => debug!("Setting {}={} via config file", env_var, val),
            }
            env::set_var(env_var, val);
        }
    }
}

pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
    let config = config::load()?;

    set_env_var_from_config(AUTH_TOKEN_ENVVAR,
                            config.auth_token,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(BLDR_URL_ENVVAR, config.bldr_url, Sensitivity::PrintValue);
    set_env_var_from_config(CTL_SECRET_ENVVAR,
                            config.ctl_secret,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(ORIGIN_ENVVAR, config.origin, Sensitivity::PrintValue);

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = fs::cache_key_path(None::<&str>);
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, &path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use crate::{command::studio::docker,
                common::ui::{UIWriter,
                             UI},
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        env as henv,
                        fs::{am_i_root,
                             find_command},
                        os::process,
                        package::{PackageIdent,
                                  PackageInstall},
                        users::linux as group},
                VERSION};
    use std::{env,
              ffi::OsString,
              path::PathBuf,
              str::FromStr};

    const SUDO_CMD: &str = "sudo";

    pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
        rerun_with_sudo_if_needed(ui, &args)?;
        if is_docker_studio(&args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init();
                    let version: Vec<&str> = VERSION.split('/').collect();
                    let ident = PackageIdent::from_str(&format!("{}/{}",
                                                                super::STUDIO_PACKAGE_IDENT,
                                                                version[0]))?;
                    // This is a duplicate of the code in `hab pkg exec` and
                    // should be refactored as part of or after:
                    // https://github.com/habitat-sh/habitat/issues/6633
                    // https://github.com/habitat-sh/habitat/issues/6634
                    let pkg_install = PackageInstall::load(&ident, None)?;
                    let cmd_env = pkg_install.environment_for_command()?;
                    for (key, value) in cmd_env.into_iter() {
                        debug!("Setting: {}='{}'", key, value);
                        env::set_var(key, value);
                    }

                    let mut display_args = super::STUDIO_CMD.to_string();
                    for arg in args {
                        display_args.push(' ');
                        display_args.push_str(arg.to_string_lossy().as_ref());
                    }
                    debug!("Running: {}", display_args);

                    exec::command_from_min_pkg(ui, super::STUDIO_CMD, &ident)?
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                process::become_command(cmd, args)?;
                Ok(())
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "linux")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return true;
            }
        }

        false
    }

    fn has_docker_group() -> bool {
        let current_user = group::get_current_username().unwrap();
        let docker_members = group::get_members_by_groupname("docker");
        docker_members.map_or(false, |d| d.contains(&current_user))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &[OsString]) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() || (is_docker_studio(args) && has_docker_group()) {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec!["-p".into(),
                                                   "[sudo hab-studio] password for %u: ".into(),
                                                   "-E".into(),];
                args.append(&mut env::args_os().collect());
                process::become_command(sudo_prog, &args)?;
                Ok(())
            }
            None => {
                ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                SUDO_CMD))?;
                ui.warn("Running Habitat Studio requires root or administrator privileges. \
                         Please retry this command as a super user or use a privilege-granting \
                         facility such as sudo.")?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use crate::{command::studio::docker,
                common::ui::UI,
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        env as henv,
                        fs::find_command,
                        os::process,
                        package::PackageIdent},
                VERSION};
    use std::{ffi::OsString,
              path::PathBuf,
              str::FromStr};

    pub fn start(_ui: &mut UI, args: &[OsString]) -> Result<()> {
        if is_windows_studio(&args) {
            start_windows_studio(_ui, args)
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub fn start_windows_studio(ui: &mut UI, args: &[OsString]) -> Result<()> {
        let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let version: Vec<&str> = VERSION.split('/').collect();
                let ident = PackageIdent::from_str(&format!("{}/{}",
                                                            super::STUDIO_PACKAGE_IDENT,
                                                            version[0]))?;
                exec::command_from_min_pkg(ui, super::STUDIO_CMD, &ident)?
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            process::become_command(cmd, args)?;
        } else {
            return Err(Error::ExecCommandNotFound(command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return false;
            }
        }

        true
    }
}
<commit_msg>Ensure studio is installed<commit_after>use std::{env,
          ffi::OsString,
          fs as stdfs,
          path::PathBuf};

use crate::{common::ui::UI,
            hcore::{crypto::CACHE_KEY_PATH_ENV_VAR,
                    env as henv,
                    fs}};

use crate::{config,
            error::Result,
            BLDR_URL_ENVVAR,
            CTL_SECRET_ENVVAR,
            ORIGIN_ENVVAR};

use habitat_core::AUTH_TOKEN_ENVVAR;

pub const ARTIFACT_PATH_ENVVAR: &str = "ARTIFACT_PATH";

const STUDIO_CMD: &str = "hab-studio";
const STUDIO_CMD_ENVVAR: &str = "HAB_STUDIO_BINARY";
const STUDIO_PACKAGE_IDENT: &str = "core/hab-studio";

#[derive(Clone, Copy)]
enum Sensitivity {
    PrintValue,
    NoPrintValue,
}

fn set_env_var_from_config(env_var: &str, config_val: Option<String>, sensitive: Sensitivity) {
    if henv::var(env_var).is_err() {
        if let Some(val) = config_val {
            match sensitive {
                Sensitivity::NoPrintValue => {
                    debug!("Setting {}=REDACTED (sensitive) via config file", env_var)
                }
                Sensitivity::PrintValue => debug!("Setting {}={} via config file", env_var, val),
            }
            env::set_var(env_var, val);
        }
    }
}

pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
    let config = config::load()?;

    set_env_var_from_config(AUTH_TOKEN_ENVVAR,
                            config.auth_token,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(BLDR_URL_ENVVAR, config.bldr_url, Sensitivity::PrintValue);
    set_env_var_from_config(CTL_SECRET_ENVVAR,
                            config.ctl_secret,
                            Sensitivity::NoPrintValue);
    set_env_var_from_config(ORIGIN_ENVVAR, config.origin, Sensitivity::PrintValue);

    if henv::var(CACHE_KEY_PATH_ENV_VAR).is_err() {
        let path = fs::cache_key_path(None::<&str>);
        debug!("Setting {}={}", CACHE_KEY_PATH_ENV_VAR, path.display());
        env::set_var(CACHE_KEY_PATH_ENV_VAR, &path);
    };

    let artifact_path = match henv::var(ARTIFACT_PATH_ENVVAR) {
        Ok(p) => PathBuf::from(p),
        Err(_) => {
            let path = fs::cache_artifact_path(None::<&str>);
            debug!("Setting {}={}", ARTIFACT_PATH_ENVVAR, path.display());
            env::set_var(ARTIFACT_PATH_ENVVAR, &path);
            path
        }
    };
    if !artifact_path.is_dir() {
        debug!("Creating artifact_path at: {}", artifact_path.display());
        stdfs::create_dir_all(&artifact_path)?;
    }

    inner::start(ui, args)
}

#[cfg(target_os = "linux")]
mod inner {
    use crate::{command::studio::docker,
                common::ui::{UIWriter,
                             UI},
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        env as henv,
                        fs::{am_i_root,
                             find_command},
                        os::process,
                        package::{PackageIdent,
                                  PackageInstall},
                        users::linux as group},
                VERSION};
    use std::{env,
              ffi::OsString,
              path::PathBuf,
              str::FromStr};

    const SUDO_CMD: &str = "sudo";

    pub fn start(ui: &mut UI, args: &[OsString]) -> Result<()> {
        rerun_with_sudo_if_needed(ui, &args)?;
        if is_docker_studio(&args) {
            docker::start_docker_studio(ui, args)
        } else {
            let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
                Ok(command) => PathBuf::from(command),
                Err(_) => {
                    init();
                    let version: Vec<&str> = VERSION.split('/').collect();
                    let ident = PackageIdent::from_str(&format!("{}/{}",
                                                                super::STUDIO_PACKAGE_IDENT,
                                                                version[0]))?;
                    let command = exec::command_from_min_pkg(ui, super::STUDIO_CMD, &ident)?
                    // This is a duplicate of the code in `hab pkg exec` and
                    // should be refactored as part of or after:
                    // https://github.com/habitat-sh/habitat/issues/6633
                    // https://github.com/habitat-sh/habitat/issues/6634
                    let pkg_install = PackageInstall::load(&ident, None)?;
                    let cmd_env = pkg_install.environment_for_command()?;
                    for (key, value) in cmd_env.into_iter() {
                        debug!("Setting: {}='{}'", key, value);
                        env::set_var(key, value);
                    }

                    let mut display_args = super::STUDIO_CMD.to_string();
                    for arg in args {
                        display_args.push(' ');
                        display_args.push_str(arg.to_string_lossy().as_ref());
                    }
                    debug!("Running: {}", display_args);

                    command
                }
            };

            if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
                process::become_command(cmd, args)?;
                Ok(())
            } else {
                Err(Error::ExecCommandNotFound(command))
            }
        }
    }

    fn is_docker_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "linux")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return true;
            }
        }

        false
    }

    fn has_docker_group() -> bool {
        let current_user = group::get_current_username().unwrap();
        let docker_members = group::get_members_by_groupname("docker");
        docker_members.map_or(false, |d| d.contains(&current_user))
    }

    fn rerun_with_sudo_if_needed(ui: &mut UI, args: &[OsString]) -> Result<()> {
        // If I have root permissions or if I am executing a docker studio
        // and have the appropriate group - early return, we are done.
        if am_i_root() || (is_docker_studio(args) && has_docker_group()) {
            return Ok(());
        }

        // Otherwise we will try to re-run this program using `sudo`
        match find_command(SUDO_CMD) {
            Some(sudo_prog) => {
                let mut args: Vec<OsString> = vec!["-p".into(),
                                                   "[sudo hab-studio] password for %u: ".into(),
                                                   "-E".into(),];
                args.append(&mut env::args_os().collect());
                process::become_command(sudo_prog, &args)?;
                Ok(())
            }
            None => {
                ui.warn(format!("Could not find the `{}' command, is it in your PATH?",
                                SUDO_CMD))?;
                ui.warn("Running Habitat Studio requires root or administrator privileges. \
                         Please retry this command as a super user or use a privilege-granting \
                         facility such as sudo.")?;
                ui.br()?;
                Err(Error::RootRequired)
            }
        }
    }
}

#[cfg(not(target_os = "linux"))]
mod inner {
    use crate::{command::studio::docker,
                common::ui::UI,
                error::{Error,
                        Result},
                exec,
                hcore::{crypto::init,
                        env as henv,
                        fs::find_command,
                        os::process,
                        package::PackageIdent},
                VERSION};
    use std::{ffi::OsString,
              path::PathBuf,
              str::FromStr};

    pub fn start(_ui: &mut UI, args: &[OsString]) -> Result<()> {
        if is_windows_studio(&args) {
            start_windows_studio(_ui, args)
        } else {
            docker::start_docker_studio(_ui, args)
        }
    }

    pub fn start_windows_studio(ui: &mut UI, args: &[OsString]) -> Result<()> {
        let command = match henv::var(super::STUDIO_CMD_ENVVAR) {
            Ok(command) => PathBuf::from(command),
            Err(_) => {
                init();
                let version: Vec<&str> = VERSION.split('/').collect();
                let ident = PackageIdent::from_str(&format!("{}/{}",
                                                            super::STUDIO_PACKAGE_IDENT,
                                                            version[0]))?;
                exec::command_from_min_pkg(ui, super::STUDIO_CMD, &ident)?
            }
        };

        if let Some(cmd) = find_command(command.to_string_lossy().as_ref()) {
            process::become_command(cmd, args)?;
        } else {
            return Err(Error::ExecCommandNotFound(command));
        }
        Ok(())
    }

    fn is_windows_studio(args: &[OsString]) -> bool {
        if cfg!(not(target_os = "windows")) {
            return false;
        }

        for arg in args.iter() {
            let str_arg = arg.to_string_lossy();
            if str_arg == "-D" {
                return false;
            }
        }

        true
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use common::Word;
use layout::{PointerReader, PointerBuilder, FromStructReader, FromStructBuilder,
             PrimitiveElement};
use list::{PrimitiveList};

pub trait PointerReaderHelpers<'a> {
    fn get(reader : PointerReader<'a>, default_value : *Word) -> Self;
}

// Hmm. I think we need associated types to do this right.
pub trait PointerBuilderHelpers<R> {
    fn get(builder : PointerBuilder, default_value : *Word) -> Self;
    fn set(builder : PointerBuilder, value : R);
    fn init(builder : PointerBuilder) -> Self;
}

impl <'a, T: FromStructReader<'a>> PointerReaderHelpers<'a> for T {
    fn get(reader : PointerReader<'a>, default_value : *Word) -> T {
        FromStructReader::from_struct_reader(reader.get_struct(default_value))
    }
}

/*
Can't do this because of "conflicting implementations"

impl <'a, T: PrimitiveElement> PointerReaderHelpers<'a> for PrimitiveList::Reader<'a, T> {
    fn get(reader : PointerReader<'a>, default_value : *Word) -> PrimitiveList::Reader<'a, T> {
        fail!();
//        reader.get_list(f
    }
}
*/
<commit_msg>remove unused imports<commit_after>/*
 * Copyright (c) 2013, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use common::Word;
use layout::{PointerReader, PointerBuilder, FromStructReader};
//use list::{PrimitiveList};

pub trait PointerReaderHelpers<'a> {
    fn get(reader : PointerReader<'a>, default_value : *Word) -> Self;
}

// Hmm. I think we need associated types to do this right.
pub trait PointerBuilderHelpers<R> {
    fn get(builder : PointerBuilder, default_value : *Word) -> Self;
    fn set(builder : PointerBuilder, value : R);
    fn init(builder : PointerBuilder) -> Self;
}

impl <'a, T: FromStructReader<'a>> PointerReaderHelpers<'a> for T {
    fn get(reader : PointerReader<'a>, default_value : *Word) -> T {
        FromStructReader::from_struct_reader(reader.get_struct(default_value))
    }
}

/*
Can't do this because of "conflicting implementations"

impl <'a, T: PrimitiveElement> PointerReaderHelpers<'a> for PrimitiveList::Reader<'a, T> {
    fn get(reader : PointerReader<'a>, default_value : *Word) -> PrimitiveList::Reader<'a, T> {
        fail!();
//        reader.get_list(f
    }
}
*/
<|endoftext|>


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

extern crate app_units;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate webrender_traits;

use app_units::Au;
use euclid::Point2D;
use gleam::gl;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use webrender_traits::{BlobImageResult, BlobImageError, BlobImageDescriptor};
use webrender_traits::{ColorF, Epoch, GlyphInstance, ClipRegion, ImageRendering};
use webrender_traits::{ImageDescriptor, ImageData, ImageFormat, PipelineId};
use webrender_traits::{ImageKey, BlobImageData, BlobImageRenderer, RasterizedBlobImage};
use webrender_traits::{LayoutSize, LayoutPoint, LayoutRect, LayoutTransform, DeviceUintSize};

fn load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        #[cfg(not(target_os = "android"))]
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        #[cfg(not(target_os = "android"))]
        self.window_proxy.wakeup_event_loop();
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let window = glutin::WindowBuilder::new()
                .with_title("WebRender Sample")
                .with_gl(glutin::GlRequest::GlThenGles {
                    opengl_version: (3, 2),
                    opengles_version: (3, 0)
                })
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
    }
    // Android uses the static generator (as opposed to a global generator) at the moment
    #[cfg(not(target_os = "android"))]
    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

    println!("OpenGL version {}", gl::get_string(gl::VERSION));
    println!("Shader resource path: {:?}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        resource_override_path: res_path,
        debug: true,
        precache_shaders: true,
        blob_image_renderer: Some(Box::new(FakeBlobImageRenderer::new())),
        .. Default::default()
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts).unwrap();
    let api = sender.create_api();

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let vector_img = api.generate_image_key();
    api.add_image(
        vector_img,
        ImageDescriptor::new(100, 100, ImageFormat::RGBA8, true),
        ImageData::new_blob_image(Vec::new()),
        None,
    );

    let pipeline_id = PipelineId(0, 0);
    let mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id);

    let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(width as f32, height as f32));
    let clip_region = {
        let complex = webrender_traits::ComplexClipRegion::new(
            LayoutRect::new(LayoutPoint::new(50.0, 50.0), LayoutSize::new(100.0, 100.0)),
            webrender_traits::BorderRadius::uniform(20.0));

        builder.new_clip_region(&bounds, vec![complex], None)
    };

    builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                  bounds,
                                  clip_region,
                                  0,
                                  LayoutTransform::identity().into(),
                                  LayoutTransform::identity(),
                                  webrender_traits::MixBlendMode::Normal,
                                  Vec::new());
    builder.push_image(
        LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(100.0, 100.0)),
        ClipRegion::simple(&bounds),
        LayoutSize::new(100.0, 100.0),
        LayoutSize::new(0.0, 0.0),
        ImageRendering::Auto,
        vector_img,
    );

    let sub_clip = {
        let mask_image = api.generate_image_key();
        api.add_image(
            mask_image,
            ImageDescriptor::new(2, 2, ImageFormat::A8, true),
            ImageData::new(vec![0, 80, 180, 255]),
            None,
        );
        let mask = webrender_traits::ImageMask {
            image: mask_image,
            rect: LayoutRect::new(LayoutPoint::new(75.0, 75.0), LayoutSize::new(100.0, 100.0)),
            repeat: false,
        };
        let complex = webrender_traits::ComplexClipRegion::new(
            LayoutRect::new(LayoutPoint::new(50.0, 50.0), LayoutSize::new(100.0, 100.0)),
            webrender_traits::BorderRadius::uniform(20.0));

        builder.new_clip_region(&bounds, vec![complex], Some(mask))
    };

    builder.push_rect(LayoutRect::new(LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 100.0)),
                      sub_clip,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));
    builder.push_rect(LayoutRect::new(LayoutPoint::new(250.0, 100.0), LayoutSize::new(100.0, 100.0)),
                      sub_clip,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));
    let border_side = webrender_traits::BorderSide {
        color: ColorF::new(0.0, 0.0, 1.0, 1.0),
        style: webrender_traits::BorderStyle::Groove,
    };
    let border_widths = webrender_traits::BorderWidths {
        top: 10.0,
        left: 10.0,
        bottom: 10.0,
        right: 10.0,
    };
    let border_details = webrender_traits::BorderDetails::Normal(webrender_traits::NormalBorder {
        top: border_side,
        right: border_side,
        bottom: border_side,
        left: border_side,
        radius: webrender_traits::BorderRadius::uniform(20.0),
    });
    builder.push_border(LayoutRect::new(LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 100.0)),
                        sub_clip,
                        border_widths,
                        border_details);

    if false { // draw text?
        let font_key = api.generate_font_key();
        let font_bytes = load_file("res/FreeSans.ttf");
        api.add_raw_font(font_key, font_bytes);

        let text_bounds = LayoutRect::new(LayoutPoint::new(100.0, 200.0), LayoutSize::new(700.0, 300.0));

        let glyphs = vec![
            GlyphInstance {
                index: 48,
                point: Point2D::new(100.0, 100.0),
            },
            GlyphInstance {
                index: 68,
                point: Point2D::new(150.0, 100.0),
            },
            GlyphInstance {
                index: 80,
                point: Point2D::new(200.0, 100.0),
            },
            GlyphInstance {
                index: 82,
                point: Point2D::new(250.0, 100.0),
            },
            GlyphInstance {
                index: 81,
                point: Point2D::new(300.0, 100.0),
            },
            GlyphInstance {
                index: 3,
                point: Point2D::new(350.0, 100.0),
            },
            GlyphInstance {
                index: 86,
                point: Point2D::new(400.0, 100.0),
            },
            GlyphInstance {
                index: 79,
                point: Point2D::new(450.0, 100.0),
            },
            GlyphInstance {
                index: 72,
                point: Point2D::new(500.0, 100.0),
            },
            GlyphInstance {
                index: 83,
                point: Point2D::new(550.0, 100.0),
            },
            GlyphInstance {
                index: 87,
                point: Point2D::new(600.0, 100.0),
            },
            GlyphInstance {
                index: 17,
                point: Point2D::new(650.0, 100.0),
            },
        ];

        builder.push_text(text_bounds,
                          webrender_traits::ClipRegion::simple(&bounds),
                          glyphs,
                          font_key,
                          ColorF::new(1.0, 1.0, 0.0, 1.0),
                          Au::from_px(32),
                          Au::from_px(0),
                          None);
    }

    builder.pop_stacking_context();

    api.set_root_display_list(
        Some(root_background_color),
        epoch,
        LayoutSize::new(width as f32, height as f32),
        builder.finalize(),
        true);
    api.set_root_pipeline(pipeline_id);
    api.generate_frame(None);

    for event in window.wait_events() {
        renderer.update();

        renderer.render(DeviceUintSize::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed |
            glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
            glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break,
            _ => ()
        }
    }
}

struct FakeBlobImageRenderer {
    images: HashMap<ImageKey, BlobImageResult>,
}

impl FakeBlobImageRenderer {
    fn new() -> Self {
        FakeBlobImageRenderer { images: HashMap::new() }
    }
}

impl BlobImageRenderer for FakeBlobImageRenderer {
    fn request_blob_image(&mut self, key: ImageKey, _: Arc<BlobImageData>, descriptor: &BlobImageDescriptor) {
        let mut texels = Vec::with_capacity((descriptor.width * descriptor.height * 4) as usize);
        for y in 0..descriptor.height {
            for x in 0..descriptor.width {
                // render a simple checkerboard pattern
                let a = if (x % 20 >= 10) != (y % 20 >= 10) { 255 } else { 0 };
                match descriptor.format {
                    ImageFormat::RGBA8 => {
                        texels.push(a);
                        texels.push(a);
                        texels.push(a);
                        texels.push(255);
                    }
                    ImageFormat::A8 => {
                        texels.push(a);
                    }
                    _ => {
                        self.images.insert(key,
                            Err(BlobImageError::Other(format!(
                                "Usupported image format {:?}",
                                descriptor.format
                            )))
                        );
                        return;
                    }
                }
            }
        }

        self.images.insert(key, Ok(RasterizedBlobImage {
            data: texels,
            width: descriptor.width,
            height: descriptor.height,
        }));
    }

    fn resolve_blob_image(&mut self, key: ImageKey) -> BlobImageResult {
        self.images.remove(&key).unwrap_or(Err(BlobImageError::InvalidKey))
    }
}
<commit_msg>Pass the hidpi factor through to WR init in sample.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate app_units;
extern crate euclid;
extern crate gleam;
extern crate glutin;
extern crate webrender;
extern crate webrender_traits;

use app_units::Au;
use euclid::Point2D;
use gleam::gl;
use std::collections::HashMap;
use std::env;
use std::fs::File;
use std::io::Read;
use std::path::PathBuf;
use std::sync::Arc;
use webrender_traits::{BlobImageResult, BlobImageError, BlobImageDescriptor};
use webrender_traits::{ColorF, Epoch, GlyphInstance, ClipRegion, ImageRendering};
use webrender_traits::{ImageDescriptor, ImageData, ImageFormat, PipelineId};
use webrender_traits::{ImageKey, BlobImageData, BlobImageRenderer, RasterizedBlobImage};
use webrender_traits::{LayoutSize, LayoutPoint, LayoutRect, LayoutTransform, DeviceUintSize};

fn load_file(name: &str) -> Vec<u8> {
    let mut file = File::open(name).unwrap();
    let mut buffer = vec![];
    file.read_to_end(&mut buffer).unwrap();
    buffer
}

struct Notifier {
    window_proxy: glutin::WindowProxy,
}

impl Notifier {
    fn new(window_proxy: glutin::WindowProxy) -> Notifier {
        Notifier {
            window_proxy: window_proxy,
        }
    }
}

impl webrender_traits::RenderNotifier for Notifier {
    fn new_frame_ready(&mut self) {
        #[cfg(not(target_os = "android"))]
        self.window_proxy.wakeup_event_loop();
    }

    fn new_scroll_frame_ready(&mut self, _composite_needed: bool) {
        #[cfg(not(target_os = "android"))]
        self.window_proxy.wakeup_event_loop();
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    let res_path = if args.len() > 1 {
        Some(PathBuf::from(&args[1]))
    } else {
        None
    };

    let window = glutin::WindowBuilder::new()
                .with_title("WebRender Sample")
                .with_gl(glutin::GlRequest::GlThenGles {
                    opengl_version: (3, 2),
                    opengles_version: (3, 0)
                })
                .build()
                .unwrap();

    unsafe {
        window.make_current().ok();
    }
    // Android uses the static generator (as opposed to a global generator) at the moment
    #[cfg(not(target_os = "android"))]
    gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);

    println!("OpenGL version {}", gl::get_string(gl::VERSION));
    println!("Shader resource path: {:?}", res_path);

    let (width, height) = window.get_inner_size().unwrap();

    let opts = webrender::RendererOptions {
        resource_override_path: res_path,
        debug: true,
        precache_shaders: true,
        blob_image_renderer: Some(Box::new(FakeBlobImageRenderer::new())),
        device_pixel_ratio: window.hidpi_factor(),
        .. Default::default()
    };

    let (mut renderer, sender) = webrender::renderer::Renderer::new(opts).unwrap();
    let api = sender.create_api();

    let notifier = Box::new(Notifier::new(window.create_window_proxy()));
    renderer.set_render_notifier(notifier);

    let epoch = Epoch(0);
    let root_background_color = ColorF::new(0.3, 0.0, 0.0, 1.0);

    let vector_img = api.generate_image_key();
    api.add_image(
        vector_img,
        ImageDescriptor::new(100, 100, ImageFormat::RGBA8, true),
        ImageData::new_blob_image(Vec::new()),
        None,
    );

    let pipeline_id = PipelineId(0, 0);
    let mut builder = webrender_traits::DisplayListBuilder::new(pipeline_id);

    let bounds = LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(width as f32, height as f32));
    let clip_region = {
        let complex = webrender_traits::ComplexClipRegion::new(
            LayoutRect::new(LayoutPoint::new(50.0, 50.0), LayoutSize::new(100.0, 100.0)),
            webrender_traits::BorderRadius::uniform(20.0));

        builder.new_clip_region(&bounds, vec![complex], None)
    };

    builder.push_stacking_context(webrender_traits::ScrollPolicy::Scrollable,
                                  bounds,
                                  clip_region,
                                  0,
                                  LayoutTransform::identity().into(),
                                  LayoutTransform::identity(),
                                  webrender_traits::MixBlendMode::Normal,
                                  Vec::new());
    builder.push_image(
        LayoutRect::new(LayoutPoint::new(0.0, 0.0), LayoutSize::new(100.0, 100.0)),
        ClipRegion::simple(&bounds),
        LayoutSize::new(100.0, 100.0),
        LayoutSize::new(0.0, 0.0),
        ImageRendering::Auto,
        vector_img,
    );

    let sub_clip = {
        let mask_image = api.generate_image_key();
        api.add_image(
            mask_image,
            ImageDescriptor::new(2, 2, ImageFormat::A8, true),
            ImageData::new(vec![0, 80, 180, 255]),
            None,
        );
        let mask = webrender_traits::ImageMask {
            image: mask_image,
            rect: LayoutRect::new(LayoutPoint::new(75.0, 75.0), LayoutSize::new(100.0, 100.0)),
            repeat: false,
        };
        let complex = webrender_traits::ComplexClipRegion::new(
            LayoutRect::new(LayoutPoint::new(50.0, 50.0), LayoutSize::new(100.0, 100.0)),
            webrender_traits::BorderRadius::uniform(20.0));

        builder.new_clip_region(&bounds, vec![complex], Some(mask))
    };

    builder.push_rect(LayoutRect::new(LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 100.0)),
                      sub_clip,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));
    builder.push_rect(LayoutRect::new(LayoutPoint::new(250.0, 100.0), LayoutSize::new(100.0, 100.0)),
                      sub_clip,
                      ColorF::new(0.0, 1.0, 0.0, 1.0));
    let border_side = webrender_traits::BorderSide {
        color: ColorF::new(0.0, 0.0, 1.0, 1.0),
        style: webrender_traits::BorderStyle::Groove,
    };
    let border_widths = webrender_traits::BorderWidths {
        top: 10.0,
        left: 10.0,
        bottom: 10.0,
        right: 10.0,
    };
    let border_details = webrender_traits::BorderDetails::Normal(webrender_traits::NormalBorder {
        top: border_side,
        right: border_side,
        bottom: border_side,
        left: border_side,
        radius: webrender_traits::BorderRadius::uniform(20.0),
    });
    builder.push_border(LayoutRect::new(LayoutPoint::new(100.0, 100.0), LayoutSize::new(100.0, 100.0)),
                        sub_clip,
                        border_widths,
                        border_details);

    if false { // draw text?
        let font_key = api.generate_font_key();
        let font_bytes = load_file("res/FreeSans.ttf");
        api.add_raw_font(font_key, font_bytes);

        let text_bounds = LayoutRect::new(LayoutPoint::new(100.0, 200.0), LayoutSize::new(700.0, 300.0));

        let glyphs = vec![
            GlyphInstance {
                index: 48,
                point: Point2D::new(100.0, 100.0),
            },
            GlyphInstance {
                index: 68,
                point: Point2D::new(150.0, 100.0),
            },
            GlyphInstance {
                index: 80,
                point: Point2D::new(200.0, 100.0),
            },
            GlyphInstance {
                index: 82,
                point: Point2D::new(250.0, 100.0),
            },
            GlyphInstance {
                index: 81,
                point: Point2D::new(300.0, 100.0),
            },
            GlyphInstance {
                index: 3,
                point: Point2D::new(350.0, 100.0),
            },
            GlyphInstance {
                index: 86,
                point: Point2D::new(400.0, 100.0),
            },
            GlyphInstance {
                index: 79,
                point: Point2D::new(450.0, 100.0),
            },
            GlyphInstance {
                index: 72,
                point: Point2D::new(500.0, 100.0),
            },
            GlyphInstance {
                index: 83,
                point: Point2D::new(550.0, 100.0),
            },
            GlyphInstance {
                index: 87,
                point: Point2D::new(600.0, 100.0),
            },
            GlyphInstance {
                index: 17,
                point: Point2D::new(650.0, 100.0),
            },
        ];

        builder.push_text(text_bounds,
                          webrender_traits::ClipRegion::simple(&bounds),
                          glyphs,
                          font_key,
                          ColorF::new(1.0, 1.0, 0.0, 1.0),
                          Au::from_px(32),
                          Au::from_px(0),
                          None);
    }

    builder.pop_stacking_context();

    api.set_root_display_list(
        Some(root_background_color),
        epoch,
        LayoutSize::new(width as f32, height as f32),
        builder.finalize(),
        true);
    api.set_root_pipeline(pipeline_id);
    api.generate_frame(None);

    for event in window.wait_events() {
        renderer.update();

        renderer.render(DeviceUintSize::new(width, height));

        window.swap_buffers().ok();

        match event {
            glutin::Event::Closed |
            glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Escape)) |
            glutin::Event::KeyboardInput(_, _, Some(glutin::VirtualKeyCode::Q)) => break,
            _ => ()
        }
    }
}

struct FakeBlobImageRenderer {
    images: HashMap<ImageKey, BlobImageResult>,
}

impl FakeBlobImageRenderer {
    fn new() -> Self {
        FakeBlobImageRenderer { images: HashMap::new() }
    }
}

impl BlobImageRenderer for FakeBlobImageRenderer {
    fn request_blob_image(&mut self, key: ImageKey, _: Arc<BlobImageData>, descriptor: &BlobImageDescriptor) {
        let mut texels = Vec::with_capacity((descriptor.width * descriptor.height * 4) as usize);
        for y in 0..descriptor.height {
            for x in 0..descriptor.width {
                // render a simple checkerboard pattern
                let a = if (x % 20 >= 10) != (y % 20 >= 10) { 255 } else { 0 };
                match descriptor.format {
                    ImageFormat::RGBA8 => {
                        texels.push(a);
                        texels.push(a);
                        texels.push(a);
                        texels.push(255);
                    }
                    ImageFormat::A8 => {
                        texels.push(a);
                    }
                    _ => {
                        self.images.insert(key,
                            Err(BlobImageError::Other(format!(
                                "Usupported image format {:?}",
                                descriptor.format
                            )))
                        );
                        return;
                    }
                }
            }
        }

        self.images.insert(key, Ok(RasterizedBlobImage {
            data: texels,
            width: descriptor.width,
            height: descriptor.height,
        }));
    }

    fn resolve_blob_image(&mut self, key: ImageKey) -> BlobImageResult {
        self.images.remove(&key).unwrap_or(Err(BlobImageError::InvalidKey))
    }
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate http;
extern crate router;

use std::io::net::ip::Ipv4Addr;
use iron::{Server, Iron, Alloy, Request, Response, Chain, Status, Unwind, FromFn};
use http::method::Get;
use http::status;
use router::{Router, Params};

fn main() {
    let mut server: Server = Iron::new();
    let mut router = Router::new();

    fn handler(req: &mut Request, res: &mut Response) -> Status {
        let query = req.alloy.find::<Params>().unwrap().get("query").unwrap();
        let _ = res.serve(status::Ok, query);
        Unwind
    }

    // Setup our route.
    router.route(
        Get,
        "/:query".to_string(),
        vec!["query".to_string()],
        FromFn::new(handler));

    server.chain.link(router);
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}

<commit_msg>(fix) unused import<commit_after>extern crate iron;
extern crate http;
extern crate router;

use std::io::net::ip::Ipv4Addr;
use iron::{Server, Iron, Request, Response, Chain, Status, Unwind, FromFn};
use http::method::Get;
use http::status;
use router::{Router, Params};

fn main() {
    let mut server: Server = Iron::new();
    let mut router = Router::new();

    fn handler(req: &mut Request, res: &mut Response) -> Status {
        let query = req.alloy.find::<Params>().unwrap().get("query").unwrap();
        let _ = res.serve(status::Ok, query);
        Unwind
    }

    // Setup our route.
    router.route(
        Get,
        "/:query".to_string(),
        vec!["query".to_string()],
        FromFn::new(handler));

    server.chain.link(router);
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}

<|endoftext|>