<commit_before>#[doc ="
Utilities that leverage libuv's `uv_timer_*` API
"];

import uv = uv;
export delayed_send, sleep, recv_timeout;

#[doc = "
Wait for timeout period then send provided value over a channel

This call returns immediately. Useful as the building block for a number
of higher-level timer functions.

Is not guaranteed to wait for exactly the specified time, but will wait
for *at least* that period of time.

# Arguments

* msecs - a timeout period, in milliseconds, to wait
* ch - a channel of type T to send a `val` on
* val - a value of type T to send over the provided `ch`
"]
fn delayed_send<T: send>(msecs: uint, ch: comm::chan<T>, val: T) {
    task::spawn() {||
        unsafe {
            let timer_done_po = comm::port::<()>();
            let timer_done_ch = comm::chan(timer_done_po);
            let timer_done_ch_ptr = ptr::addr_of(timer_done_ch);
            let timer = uv::ll::timer_t();
            let timer_ptr = ptr::addr_of(timer);
            let hl_loop = uv::global_loop::get();
            uv::hl::interact(hl_loop) {|loop_ptr|
                let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
                if (init_result == 0i32) {
                    let start_result = uv::ll::timer_start(
                        timer_ptr, delayed_send_cb, msecs, 0u);
                    if (start_result == 0i32) {
                        uv::ll::set_data_for_uv_handle(
                            timer_ptr,
                            timer_done_ch_ptr as *libc::c_void);
                    }
                    else {
                        let error_msg = uv::ll::get_last_err_info(loop_ptr);
                        fail "timer::delayed_send() start failed: "+error_msg;
                    }
                }
                else {
                    let error_msg = uv::ll::get_last_err_info(loop_ptr);
                    fail "timer::delayed_send() init failed: "+error_msg;
                }
            };
            // delayed_send_cb has been processed by libuv
            comm::recv(timer_done_po);
            // notify the caller immediately
            comm::send(ch, copy(val));
            // uv_close for this timer has been processed
            comm::recv(timer_done_po);
        }
    };
}

#[doc = "
Blocks the current task for (at least) the specified time period.

Is not guaranteed to sleep for exactly the specified time, but will sleep
for *at least* that period of time.

# Arguments

* msecs - an amount of time, in milliseconds, for the current task to block
"]
fn sleep(msecs: uint) {
    let exit_po = comm::port::<()>();
    let exit_ch = comm::chan(exit_po);
    delayed_send(msecs, exit_ch, ());
    comm::recv(exit_po);
}

#[doc = "
Receive on a port for (up to) a specified time, then return an `option<T>`

This call will block to receive on the provided port for up to the specified
timeout. Depending on whether the provided port receives in that time period,
`recv_timeout` will return an `option<T>` representing the result.

# Arguments

* msecs - an mount of time, in milliseconds, to wait to receive
* wait_port - a `comm::port<T>` to receive on

# Returns

An `option<T>` representing the outcome of the call. If the call `recv`'d on
the provided port in the allotted timeout period, then the result will be a
`some(T)`. If not, then `none` will be returned.
"]
fn recv_timeout<T: send>(msecs: uint, wait_po: comm::port<T>) -> option<T> {
    let timeout_po = comm::port::<()>();
    let timeout_ch = comm::chan(timeout_po);
    delayed_send(msecs, timeout_ch, ());
    either::either(
        {|left_val|
            log(debug, #fmt("recv_time .. left_val %?",
                           left_val));
            none
        }, {|right_val|
            some(right_val)
        }, comm::select2(timeout_po, wait_po)
    )
}

// INTERNAL API
crust fn delayed_send_cb(handle: *uv::ll::uv_timer_t,
                                status: libc::c_int) unsafe {
    log(debug, #fmt("delayed_send_cb handle %? status %?", handle, status));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>);
    let stop_result = uv::ll::timer_stop(handle);
    if (stop_result == 0i32) {
        comm::send(timer_done_ch, ());
        uv::ll::close(handle, delayed_send_close_cb);
    }
    else {
        let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
        let error_msg = uv::ll::get_last_err_info(loop_ptr);
        fail "timer::sleep() init failed: "+error_msg;
    }
}

crust fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe {
    log(debug, #fmt("delayed_send_close_cb handle %?", handle));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>);
    comm::send(timer_done_ch, ());
}

#[cfg(test)]
mod test {
    #[test]
    fn test_gl_timer_simple_sleep_test() {
        sleep(1u);
    }

    #[test]
    fn test_gl_timer_recv_timeout_before_time_passes() {
        let expected = rand::rng().gen_str(16u);
        let test_po = comm::port::<str>();
        let test_ch = comm::chan(test_po);

        task::spawn() {||
            delayed_send(1u, test_ch, expected);
        };

        let actual = alt recv_timeout(1000u, test_po) {
          some(val) { val }
          _ { fail "test_timer_recv_timeout_before_time_passes:"+
                    " didn't receive result before timeout"; }
        };
        assert actual == expected;
    }

    #[test]
    fn test_gl_timer_recv_timeout_after_time_passes() {
        let expected = rand::rng().gen_str(16u);
        let fail_msg = rand::rng().gen_str(16u);
        let test_po = comm::port::<str>();
        let test_ch = comm::chan(test_po);

        task::spawn() {||
            delayed_send(1000u, test_ch, expected);
        };

        let actual = alt recv_timeout(1u, test_po) {
          none { fail_msg }
          _ { fail "test_timer_recv_timeout_before_time_passes:"+
                    " didn't receive result before timeout"; }
        };
        assert actual == fail_msg;
    }
}
<commit_msg>std: Add 2 timer stress tests<commit_after>#[doc ="
Utilities that leverage libuv's `uv_timer_*` API
"];

import uv = uv;
export delayed_send, sleep, recv_timeout;

#[doc = "
Wait for timeout period then send provided value over a channel

This call returns immediately. Useful as the building block for a number
of higher-level timer functions.

Is not guaranteed to wait for exactly the specified time, but will wait
for *at least* that period of time.

# Arguments

* msecs - a timeout period, in milliseconds, to wait
* ch - a channel of type T to send a `val` on
* val - a value of type T to send over the provided `ch`
"]
fn delayed_send<T: send>(msecs: uint, ch: comm::chan<T>, val: T) {
    task::spawn() {||
        unsafe {
            let timer_done_po = comm::port::<()>();
            let timer_done_ch = comm::chan(timer_done_po);
            let timer_done_ch_ptr = ptr::addr_of(timer_done_ch);
            let timer = uv::ll::timer_t();
            let timer_ptr = ptr::addr_of(timer);
            let hl_loop = uv::global_loop::get();
            uv::hl::interact(hl_loop) {|loop_ptr|
                let init_result = uv::ll::timer_init(loop_ptr, timer_ptr);
                if (init_result == 0i32) {
                    let start_result = uv::ll::timer_start(
                        timer_ptr, delayed_send_cb, msecs, 0u);
                    if (start_result == 0i32) {
                        uv::ll::set_data_for_uv_handle(
                            timer_ptr,
                            timer_done_ch_ptr as *libc::c_void);
                    }
                    else {
                        let error_msg = uv::ll::get_last_err_info(loop_ptr);
                        fail "timer::delayed_send() start failed: "+error_msg;
                    }
                }
                else {
                    let error_msg = uv::ll::get_last_err_info(loop_ptr);
                    fail "timer::delayed_send() init failed: "+error_msg;
                }
            };
            // delayed_send_cb has been processed by libuv
            comm::recv(timer_done_po);
            // notify the caller immediately
            comm::send(ch, copy(val));
            // uv_close for this timer has been processed
            comm::recv(timer_done_po);
        }
    };
}

#[doc = "
Blocks the current task for (at least) the specified time period.

Is not guaranteed to sleep for exactly the specified time, but will sleep
for *at least* that period of time.

# Arguments

* msecs - an amount of time, in milliseconds, for the current task to block
"]
fn sleep(msecs: uint) {
    let exit_po = comm::port::<()>();
    let exit_ch = comm::chan(exit_po);
    delayed_send(msecs, exit_ch, ());
    comm::recv(exit_po);
}

#[doc = "
Receive on a port for (up to) a specified time, then return an `option<T>`

This call will block to receive on the provided port for up to the specified
timeout. Depending on whether the provided port receives in that time period,
`recv_timeout` will return an `option<T>` representing the result.

# Arguments

* msecs - an mount of time, in milliseconds, to wait to receive
* wait_port - a `comm::port<T>` to receive on

# Returns

An `option<T>` representing the outcome of the call. If the call `recv`'d on
the provided port in the allotted timeout period, then the result will be a
`some(T)`. If not, then `none` will be returned.
"]
fn recv_timeout<T: send>(msecs: uint, wait_po: comm::port<T>) -> option<T> {
    let timeout_po = comm::port::<()>();
    let timeout_ch = comm::chan(timeout_po);
    delayed_send(msecs, timeout_ch, ());
    either::either(
        {|left_val|
            log(debug, #fmt("recv_time .. left_val %?",
                           left_val));
            none
        }, {|right_val|
            some(right_val)
        }, comm::select2(timeout_po, wait_po)
    )
}

// INTERNAL API
crust fn delayed_send_cb(handle: *uv::ll::uv_timer_t,
                                status: libc::c_int) unsafe {
    log(debug, #fmt("delayed_send_cb handle %? status %?", handle, status));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>);
    let stop_result = uv::ll::timer_stop(handle);
    if (stop_result == 0i32) {
        comm::send(timer_done_ch, ());
        uv::ll::close(handle, delayed_send_close_cb);
    }
    else {
        let loop_ptr = uv::ll::get_loop_for_uv_handle(handle);
        let error_msg = uv::ll::get_last_err_info(loop_ptr);
        fail "timer::sleep() init failed: "+error_msg;
    }
}

crust fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe {
    log(debug, #fmt("delayed_send_close_cb handle %?", handle));
    let timer_done_ch =
        *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>);
    comm::send(timer_done_ch, ());
}

#[cfg(test)]
mod test {
    #[test]
    fn test_gl_timer_simple_sleep_test() {
        sleep(1u);
    }

    #[test]
    fn test_gl_timer_sleep_stress1() {
        iter::repeat(500u) {||
            sleep(1u);
        }
    }

    #[test]
    fn test_gl_timer_sleep_stress2() {
        let po = comm::port();
        let ch = comm::chan(po);

        let repeat = 100u;
        let spec = {

            [(1u, 100u),
             (10u, 10u),
             (100u, 2u)]

        };

        iter::repeat(repeat) {||

            for spec.each {|spec|
                let (times, maxms) = spec;
                task::spawn {||
                    import rand::*;
                    let rng = rng();
                    iter::repeat(times) {||
                        sleep(rng.next() as uint % maxms);
                    }
                    comm::send(ch, ());
                }
            }
        }

        iter::repeat(repeat * spec.len()) {||
            comm::recv(po)
        }
    }

    #[test]
    fn test_gl_timer_recv_timeout_before_time_passes() {
        let expected = rand::rng().gen_str(16u);
        let test_po = comm::port::<str>();
        let test_ch = comm::chan(test_po);

        task::spawn() {||
            delayed_send(1u, test_ch, expected);
        };

        let actual = alt recv_timeout(1000u, test_po) {
          some(val) { val }
          _ { fail "test_timer_recv_timeout_before_time_passes:"+
                    " didn't receive result before timeout"; }
        };
        assert actual == expected;
    }

    #[test]
    fn test_gl_timer_recv_timeout_after_time_passes() {
        let expected = rand::rng().gen_str(16u);
        let fail_msg = rand::rng().gen_str(16u);
        let test_po = comm::port::<str>();
        let test_ch = comm::chan(test_po);

        task::spawn() {||
            delayed_send(1000u, test_ch, expected);
        };

        let actual = alt recv_timeout(1u, test_po) {
          none { fail_msg }
          _ { fail "test_timer_recv_timeout_before_time_passes:"+
                    " didn't receive result before timeout"; }
        };
        assert actual == fail_msg;
    }
}
<|endoftext|>


<commit_before>import driver::session::session;
import middle::ty;
import syntax::{ast, visit};
import syntax::attr;
import syntax::codemap::span;
import std::map::{map,hashmap,int_hash,hash_from_strs};
import std::smallintmap::{map,smallintmap};
import io::writer_util;
import syntax::print::pprust::expr_to_str;

export lint, ctypes, unused_imports;
export level, ignore, warn, error;
export lookup_lint, lint_dict, get_lint_dict, check_crate;

#[doc="

A 'lint' check is a kind of miscellaneous constraint that a user _might_ want
to enforce, but might reasonably want to permit as well, on a module-by-module
basis. They contrast with static constraints enforced by other phases of the
compiler, which are generally required to hold in order to compile the program
at all.

"]

enum lint {
    ctypes,
    unused_imports,
    while_true,
    path_statement,
    old_vecs,
}

// This is pretty unfortunate. We really want some sort of "deriving Enum"
// type of thing.
fn int_to_lint(i: int) -> lint {
    alt check i {
      0 { ctypes }
      1 { unused_imports }
      2 { while_true }
      3 { path_statement }
      4 { old_vecs }
    }
}

enum level {
    ignore, warn, error
}

type lint_spec = @{lint: lint,
                   desc: str,
                   default: level};

type lint_dict = hashmap<str,lint_spec>;

/*
  Pass names should not contain a '-', as the compiler normalizes
  '-' to '_' in command-line flags
 */
fn get_lint_dict() -> lint_dict {
    let v = [
        ("ctypes",
         @{lint: ctypes,
           desc: "proper use of core::libc types in native modules",
           default: warn}),

        ("unused_imports",
         @{lint: unused_imports,
           desc: "imports that are never used",
           default: ignore}),

        ("while_true",
         @{lint: while_true,
           desc: "suggest using loop { } instead of while(true) { }",
           default: warn}),

        ("path_statement",
         @{lint: path_statement,
           desc: "path statements with no effect",
           default: warn}),

        ("old_vecs",
         @{lint: old_vecs,
           desc: "old (deprecated) vectors and strings",
           default: ignore})

    ];
    hash_from_strs(v)
}

// This is a highly not-optimal set of data structure decisions.
type lint_modes = smallintmap<level>;
type lint_mode_map = hashmap<ast::node_id, lint_modes>;

type warning_settings = {
    default_settings: lint_modes,
    settings_map: lint_mode_map
};

// This is kind of unfortunate. It should be somewhere else, or we should use
// a persistent data structure...
fn clone_lint_modes(modes: lint_modes) -> lint_modes {
    @{v: copy modes.v}
}

type ctxt = {dict: lint_dict,
             curr: lint_modes,
             tcx: ty::ctxt};

impl methods for ctxt {
    fn get_level(lint: lint) -> level {
        alt self.curr.find(lint as uint) {
          some(c) { c }
          none { ignore }
        }
    }

    fn set_level(lint: lint, level: level) {
        if level == ignore {
            self.curr.remove(lint as uint);
        } else {
            self.curr.insert(lint as uint, level);
        }
    }

    fn span_lint(level: level, span: span, msg: str) {
        alt level {
          ignore { }
          warn { self.tcx.sess.span_warn(span, msg); }
          error { self.tcx.sess.span_err(span, msg); }
        }
    }

    #[doc="
          Merge the warnings specified by any `warn(...)` attributes into the
          current lint context, call the provided function, then reset the
          warnings in effect to their previous state.
    "]
    fn with_warn_attrs(attrs: [ast::attribute], f: fn(ctxt)) {

        let mut new_ctxt = self;

        let metas = attr::attr_metas(attr::find_attrs_by_name(attrs, "warn"));
        for metas.each {|meta|
            alt meta.node {
              ast::meta_list(_, metas) {
                for metas.each {|meta|
                    alt meta.node {
                      ast::meta_word(lintname) {
                        alt lookup_lint(self.dict, lintname) {
                          none {
                            self.tcx.sess.span_err(
                                meta.span,
                                #fmt("unknown warning: '%s'", lintname));
                          }
                          some((lint, new_level)) {
                            // we do multiple unneeded copies of the map
                            // if many attributes are set, but this shouldn't
                            // actually be a problem...
                            new_ctxt = {curr: clone_lint_modes(self.curr)
                                        with new_ctxt};
                            new_ctxt.set_level(lint, new_level);
                          }
                        }
                      }
                      _ {
                        self.tcx.sess.span_err(
                            meta.span,
                            "malformed warning attribute");
                      }
                    }
                }
              }
              _ {
                self.tcx.sess.span_err(meta.span,
                                       "malformed warning attribute");
              }
            }
        }

        f(new_ctxt);
    }
}

fn lookup_lint(dict: lint_dict, s: str)
    -> option<(lint, level)> {
    let s = str::replace(s, "-", "_");
    let (name, level) = if s.starts_with("no_") {
        (s.substr(3u, s.len() - 3u), ignore)
    } else if s.starts_with("err_") {
        (s.substr(4u, s.len() - 4u), error)
    } else {
        (s, warn)
    };
    alt dict.find(name) {
      none { none }
      some(spec) { some((spec.lint, level)) }
    }
}

// FIXME: Copied from driver.rs, to work around a bug(#1566)
fn time(do_it: bool, what: str, thunk: fn()) {
    if !do_it{ ret thunk(); }
    let start = std::time::precise_time_s();
    thunk();
    let end = std::time::precise_time_s();
    io::stdout().write_str(#fmt("time: %3.3f s\t%s\n",
                                end - start, what));
}

fn check_item(cx: ctxt, i: @ast::item) {
    cx.with_warn_attrs(i.attrs) {|cx|
        for cx.curr.each {|lint, level|
            alt int_to_lint(lint as int) {
              ctypes { check_item_ctypes(cx, level, i); }
              unused_imports { check_item_unused_imports(cx, level, i); }
              while_true { check_item_while_true(cx, level, i); }
              path_statement { check_item_path_statement(cx, level, i); }
              old_vecs { check_item_old_vecs(cx, level, i); }
            }
        }
    }
}

fn check_item_while_true(cx: ctxt, level: level, it: @ast::item) {
    let visit = visit::mk_simple_visitor(@{
        visit_expr: fn@(e: @ast::expr) {
           alt e.node {
             ast::expr_while(cond, _) {
                alt cond.node {
                    ast::expr_lit(@{node: ast::lit_bool(true),_}) {
                            cx.span_lint(
                              level, e.span,
                              "denote infinite loops with loop { ... }");
                    }
                    _ {}
                }
             }
             _ {}
          }
        }
        with *visit::default_simple_visitor()
    });
    visit::visit_item(it, (), visit);
}

fn check_item_unused_imports(_cx: ctxt, _level: level, _it: @ast::item) {
    // FIXME: Don't know how to check this in lint yet, it's currently being
    // done over in resolve. When resolve is rewritten, do it here instead.
}

fn check_item_ctypes(cx: ctxt, level: level, it: @ast::item) {

    fn check_native_fn(cx: ctxt, level: level, decl: ast::fn_decl) {
        let tys = vec::map(decl.inputs) {|a| a.ty };
        for vec::each(tys + [decl.output]) {|ty|
            alt ty.node {
              ast::ty_path(_, id) {
                alt cx.tcx.def_map.get(id) {
                  ast::def_prim_ty(ast::ty_int(ast::ty_i)) {
                    cx.span_lint(
                        level, ty.span,
                        "found rust type `int` in native module, while \
                         libc::c_int or libc::c_long should be used");
                  }
                  ast::def_prim_ty(ast::ty_uint(ast::ty_u)) {
                    cx.span_lint(
                        level, ty.span,
                        "found rust type `uint` in native module, while \
                         libc::c_uint or libc::c_ulong should be used");
                  }
                  _ { }
                }
              }
              _ { }
            }
        }
    }

    alt it.node {
      ast::item_native_mod(nmod) if attr::native_abi(it.attrs) !=
      either::right(ast::native_abi_rust_intrinsic) {
        for nmod.items.each {|ni|
            alt ni.node {
              ast::native_item_fn(decl, tps) {
                check_native_fn(cx, level, decl);
              }
            }
        }
      }
      _ {/* nothing to do */ }
    }
}

fn check_item_path_statement(cx: ctxt, level: level, it: @ast::item) {
    let visit = visit::mk_simple_visitor(@{
        visit_stmt: fn@(s: @ast::stmt) {
            alt s.node {
              ast::stmt_semi(@{id: _,
                               node: ast::expr_path(@path),
                               span: _}, _) {
                cx.span_lint(
                    level, s.span,
                    "path statement with no effect");
              }
              _ {}
            }
        }
        with *visit::default_simple_visitor()
    });
    visit::visit_item(it, (), visit);
}

fn check_item_old_vecs(cx: ctxt, level: level, it: @ast::item) {
    let uses_vstore = int_hash();

    let visit = visit::mk_simple_visitor(@{

        visit_expr:fn@(e: @ast::expr) {
            alt e.node {
              ast::expr_vec(_, _) |
              ast::expr_lit(@{node: ast::lit_str(_), span:_})
              if ! uses_vstore.contains_key(e.id) {
                cx.span_lint(level, e.span, "deprecated vec/str expr");
              }
              ast::expr_vstore(@inner, _) {
                uses_vstore.insert(inner.id, true);
              }
              _ { }
            }
        },

        visit_ty: fn@(t: @ast::ty) {
            alt t.node {
              ast::ty_vec(_)
              if ! uses_vstore.contains_key(t.id) {
                cx.span_lint(level, t.span, "deprecated vec type");
              }

              ast::ty_path(@{span: _, global: _, idents: ids,
                             rp: none, types: _}, _)
              if ids == ["str"] && (! uses_vstore.contains_key(t.id)) {
                cx.span_lint(level, t.span, "deprecated str type");
              }

              ast::ty_vstore(inner, _) {
                uses_vstore.insert(inner.id, true);
              }
              _ { }
            }
        }

        with *visit::default_simple_visitor()
    });
    visit::visit_item(it, (), visit);
}

fn check_crate(tcx: ty::ctxt, crate: @ast::crate,
               lint_opts: [(lint, level)], time_pass: bool) {

    fn hash_lint(&&lint: lint) -> uint { lint as uint }
    fn eq_lint(&&a: lint, &&b: lint) -> bool { a == b }

    let cx = {dict: get_lint_dict(),
              curr: std::smallintmap::mk(),
              tcx: tcx};

    // Install defaults.
    for cx.dict.each {|_k, spec| cx.set_level(spec.lint, spec.default); }

    // Install command-line options, overriding defaults.
    for lint_opts.each {|pair|
        let (lint,level) = pair;
        cx.set_level(lint, level);
    }

    time(time_pass, "lint checking") {||
        cx.with_warn_attrs(crate.node.attrs) {|cx|
            let visit = visit::mk_simple_visitor(@{
                visit_item: fn@(i: @ast::item) { check_item(cx, i); }
                with *visit::default_simple_visitor()
            });
            visit::visit_crate(*crate, (), visit);
        }
    }

    tcx.sess.abort_if_errors();
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>Make lint properly deal with nested items. Closes #2473.<commit_after>import driver::session::session;
import middle::ty;
import syntax::{ast, visit};
import syntax::attr;
import syntax::codemap::span;
import std::map::{map,hashmap,int_hash,hash_from_strs};
import std::smallintmap::{map,smallintmap};
import io::writer_util;
import syntax::print::pprust::expr_to_str;

export lint, ctypes, unused_imports;
export level, ignore, warn, error;
export lookup_lint, lint_dict, get_lint_dict, check_crate;

#[doc="

A 'lint' check is a kind of miscellaneous constraint that a user _might_ want
to enforce, but might reasonably want to permit as well, on a module-by-module
basis. They contrast with static constraints enforced by other phases of the
compiler, which are generally required to hold in order to compile the program
at all.

"]

enum lint {
    ctypes,
    unused_imports,
    while_true,
    path_statement,
    old_vecs,
}

// This is pretty unfortunate. We really want some sort of "deriving Enum"
// type of thing.
fn int_to_lint(i: int) -> lint {
    alt check i {
      0 { ctypes }
      1 { unused_imports }
      2 { while_true }
      3 { path_statement }
      4 { old_vecs }
    }
}

enum level {
    ignore, warn, error
}

type lint_spec = @{lint: lint,
                   desc: str,
                   default: level};

type lint_dict = hashmap<str,lint_spec>;

/*
  Pass names should not contain a '-', as the compiler normalizes
  '-' to '_' in command-line flags
 */
fn get_lint_dict() -> lint_dict {
    let v = [
        ("ctypes",
         @{lint: ctypes,
           desc: "proper use of core::libc types in native modules",
           default: warn}),

        ("unused_imports",
         @{lint: unused_imports,
           desc: "imports that are never used",
           default: ignore}),

        ("while_true",
         @{lint: while_true,
           desc: "suggest using loop { } instead of while(true) { }",
           default: warn}),

        ("path_statement",
         @{lint: path_statement,
           desc: "path statements with no effect",
           default: warn}),

        ("old_vecs",
         @{lint: old_vecs,
           desc: "old (deprecated) vectors and strings",
           default: ignore})

    ];
    hash_from_strs(v)
}

// This is a highly not-optimal set of data structure decisions.
type lint_modes = smallintmap<level>;
type lint_mode_map = hashmap<ast::node_id, lint_modes>;

type warning_settings = {
    default_settings: lint_modes,
    settings_map: lint_mode_map
};

// This is kind of unfortunate. It should be somewhere else, or we should use
// a persistent data structure...
fn clone_lint_modes(modes: lint_modes) -> lint_modes {
    @{v: copy modes.v}
}

type ctxt = {dict: lint_dict,
             curr: lint_modes,
             tcx: ty::ctxt};

impl methods for ctxt {
    fn get_level(lint: lint) -> level {
        alt self.curr.find(lint as uint) {
          some(c) { c }
          none { ignore }
        }
    }

    fn set_level(lint: lint, level: level) {
        if level == ignore {
            self.curr.remove(lint as uint);
        } else {
            self.curr.insert(lint as uint, level);
        }
    }

    fn span_lint(level: level, span: span, msg: str) {
        alt level {
          ignore { }
          warn { self.tcx.sess.span_warn(span, msg); }
          error { self.tcx.sess.span_err(span, msg); }
        }
    }

    #[doc="
          Merge the warnings specified by any `warn(...)` attributes into the
          current lint context, call the provided function, then reset the
          warnings in effect to their previous state.
    "]
    fn with_warn_attrs(attrs: [ast::attribute], f: fn(ctxt)) {

        let mut new_ctxt = self;

        let metas = attr::attr_metas(attr::find_attrs_by_name(attrs, "warn"));
        for metas.each {|meta|
            alt meta.node {
              ast::meta_list(_, metas) {
                for metas.each {|meta|
                    alt meta.node {
                      ast::meta_word(lintname) {
                        alt lookup_lint(self.dict, lintname) {
                          none {
                            self.tcx.sess.span_err(
                                meta.span,
                                #fmt("unknown warning: '%s'", lintname));
                          }
                          some((lint, new_level)) {
                            // we do multiple unneeded copies of the map
                            // if many attributes are set, but this shouldn't
                            // actually be a problem...
                            new_ctxt = {curr: clone_lint_modes(self.curr)
                                        with new_ctxt};
                            new_ctxt.set_level(lint, new_level);
                          }
                        }
                      }
                      _ {
                        self.tcx.sess.span_err(
                            meta.span,
                            "malformed warning attribute");
                      }
                    }
                }
              }
              _ {
                self.tcx.sess.span_err(meta.span,
                                       "malformed warning attribute");
              }
            }
        }

        f(new_ctxt);
    }
}

fn lookup_lint(dict: lint_dict, s: str)
    -> option<(lint, level)> {
    let s = str::replace(s, "-", "_");
    let (name, level) = if s.starts_with("no_") {
        (s.substr(3u, s.len() - 3u), ignore)
    } else if s.starts_with("err_") {
        (s.substr(4u, s.len() - 4u), error)
    } else {
        (s, warn)
    };
    alt dict.find(name) {
      none { none }
      some(spec) { some((spec.lint, level)) }
    }
}

// FIXME: Copied from driver.rs, to work around a bug(#1566)
fn time(do_it: bool, what: str, thunk: fn()) {
    if !do_it{ ret thunk(); }
    let start = std::time::precise_time_s();
    thunk();
    let end = std::time::precise_time_s();
    io::stdout().write_str(#fmt("time: %3.3f s\t%s\n",
                                end - start, what));
}

fn check_item(i: @ast::item, &&cx: ctxt, v: visit::vt<ctxt>) {
    cx.with_warn_attrs(i.attrs) {|cx|
        for cx.curr.each {|lint, level|
            alt int_to_lint(lint as int) {
              ctypes { check_item_ctypes(cx, level, i); }
              unused_imports { check_item_unused_imports(cx, level, i); }
              while_true { check_item_while_true(cx, level, i); }
              path_statement { check_item_path_statement(cx, level, i); }
              old_vecs { check_item_old_vecs(cx, level, i); }
            }
        }
        visit::visit_item(i, cx, v);
    }
}

// Take a visitor, and modify it so that it will not proceed past subitems.
// This is used to make the simple visitors used for the lint passes
// not traverse into subitems, since that is handled by the outer
// lint visitor.
fn item_stopping_visitor<E>(v: visit::vt<E>) -> visit::vt<E> {
    visit::mk_vt(@{visit_item: {|_i, _e, _v| } with **v})
}

fn check_item_while_true(cx: ctxt, level: level, it: @ast::item) {
    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
        visit_expr: fn@(e: @ast::expr) {
           alt e.node {
             ast::expr_while(cond, _) {
                alt cond.node {
                    ast::expr_lit(@{node: ast::lit_bool(true),_}) {
                            cx.span_lint(
                              level, e.span,
                              "denote infinite loops with loop { ... }");
                    }
                    _ {}
                }
             }
             _ {}
          }
        }
        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_item_unused_imports(_cx: ctxt, _level: level, _it: @ast::item) {
    // FIXME: Don't know how to check this in lint yet, it's currently being
    // done over in resolve. When resolve is rewritten, do it here instead.
}

fn check_item_ctypes(cx: ctxt, level: level, it: @ast::item) {

    fn check_native_fn(cx: ctxt, level: level, decl: ast::fn_decl) {
        let tys = vec::map(decl.inputs) {|a| a.ty };
        for vec::each(tys + [decl.output]) {|ty|
            alt ty.node {
              ast::ty_path(_, id) {
                alt cx.tcx.def_map.get(id) {
                  ast::def_prim_ty(ast::ty_int(ast::ty_i)) {
                    cx.span_lint(
                        level, ty.span,
                        "found rust type `int` in native module, while \
                         libc::c_int or libc::c_long should be used");
                  }
                  ast::def_prim_ty(ast::ty_uint(ast::ty_u)) {
                    cx.span_lint(
                        level, ty.span,
                        "found rust type `uint` in native module, while \
                         libc::c_uint or libc::c_ulong should be used");
                  }
                  _ { }
                }
              }
              _ { }
            }
        }
    }

    alt it.node {
      ast::item_native_mod(nmod) if attr::native_abi(it.attrs) !=
      either::right(ast::native_abi_rust_intrinsic) {
        for nmod.items.each {|ni|
            alt ni.node {
              ast::native_item_fn(decl, tps) {
                check_native_fn(cx, level, decl);
              }
            }
        }
      }
      _ {/* nothing to do */ }
    }
}

fn check_item_path_statement(cx: ctxt, level: level, it: @ast::item) {
    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{
        visit_stmt: fn@(s: @ast::stmt) {
            alt s.node {
              ast::stmt_semi(@{id: _,
                               node: ast::expr_path(@path),
                               span: _}, _) {
                cx.span_lint(
                    level, s.span,
                    "path statement with no effect");
              }
              _ {}
            }
        }
        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_item_old_vecs(cx: ctxt, level: level, it: @ast::item) {
    let uses_vstore = int_hash();

    let visit = item_stopping_visitor(visit::mk_simple_visitor(@{

        visit_expr:fn@(e: @ast::expr) {
            alt e.node {
              ast::expr_vec(_, _) |
              ast::expr_lit(@{node: ast::lit_str(_), span:_})
              if ! uses_vstore.contains_key(e.id) {
                cx.span_lint(level, e.span, "deprecated vec/str expr");
              }
              ast::expr_vstore(@inner, _) {
                uses_vstore.insert(inner.id, true);
              }
              _ { }
            }
        },

        visit_ty: fn@(t: @ast::ty) {
            alt t.node {
              ast::ty_vec(_)
              if ! uses_vstore.contains_key(t.id) {
                cx.span_lint(level, t.span, "deprecated vec type");
              }

              ast::ty_path(@{span: _, global: _, idents: ids,
                             rp: none, types: _}, _)
              if ids == ["str"] && (! uses_vstore.contains_key(t.id)) {
                cx.span_lint(level, t.span, "deprecated str type");
              }

              ast::ty_vstore(inner, _) {
                uses_vstore.insert(inner.id, true);
              }
              _ { }
            }
        }

        with *visit::default_simple_visitor()
    }));
    visit::visit_item(it, (), visit);
}

fn check_crate(tcx: ty::ctxt, crate: @ast::crate,
               lint_opts: [(lint, level)], time_pass: bool) {

    fn hash_lint(&&lint: lint) -> uint { lint as uint }
    fn eq_lint(&&a: lint, &&b: lint) -> bool { a == b }

    let cx = {dict: get_lint_dict(),
              curr: std::smallintmap::mk(),
              tcx: tcx};

    // Install defaults.
    for cx.dict.each {|_k, spec| cx.set_level(spec.lint, spec.default); }

    // Install command-line options, overriding defaults.
    for lint_opts.each {|pair|
        let (lint,level) = pair;
        cx.set_level(lint, level);
    }

    time(time_pass, "lint checking") {||
        cx.with_warn_attrs(crate.node.attrs) {|cx|
            let visit = visit::mk_vt(@{
                visit_item: check_item
                with *visit::default_visitor()
            });
            visit::visit_crate(*crate, cx, visit);
        }
    }

    tcx.sess.abort_if_errors();
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before>use PatternValue;
use mir;

/// An adjustment to a pattern.
///
/// Not all possible patterns are an identical match to
/// the MIR. To accomodate this, we have the concept of a
/// pattern _adjustment_.
///
/// When matching patterns, we can have several adjustments
/// which define permutations that would need to be made to the
/// original pattern in order to match.
///
/// We can then look at all the adjustments and figure out which
/// pattern is the most optimal to select.
///
/// Take the case where we have
///
/// ```ignore
/// (add %a, (add %foo, %bar))
/// ```
///
/// This will likely have to have an adjustment to demote the
/// nested addition to a register, so that the code becomes.
///
/// ```ignore
/// %tmp = (add %foo, %bar)
/// (add %a, %tmp)
/// ```
#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Adjustment<V: PatternValue>
{
    /// Demotes a subnode to a register.
    DemoteToRegister {
        demotee: mir::Node,
    },
    Target(V::Adjustment),
}

/// The result of an adjustment application.
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct AdjustmentApplication
{
    /// An adjustment may create extra nodes preceding the node
    /// that was adjusted. For example, promoting an operand
    /// to a register would a register set node to precede the adjusted node.
    pub preceding_nodes: Vec<mir::Node>,

    /// The original node that was adjusted.
    pub adjusted_node: mir::Node,
}

impl AdjustmentApplication
{
    pub fn unadjusted(node: mir::Node) -> Self {
        AdjustmentApplication {
            preceding_nodes: Vec::new(),
            adjusted_node: node,
        }
    }

    /// Gets all of the nodes (in order) that were created or modified
    /// by the adjustment.
    pub fn nodes(&self) -> Vec<mir::Node> {
        let mut nodes = self.preceding_nodes.clone();
        nodes.push(self.adjusted_node.clone());
        nodes
    }

    fn merge(mut self, other: Self) -> Self {
        self.preceding_nodes.extend(other.preceding_nodes);
        self.adjusted_node = other.adjusted_node;
        self
    }
}

impl<V: PatternValue> Adjustment<V>
{
    pub fn demote_to_register(node: &mir::Node) -> Self {
        Adjustment::DemoteToRegister {
            demotee: node.clone(),
        }
    }

    pub fn apply_several_to(root_node: mir::Node, adjustments: &[Self]) -> AdjustmentApplication {
        adjustments.iter().fold(AdjustmentApplication::unadjusted(root_node), |last_application, adjustment| {
            let current_node = last_application.adjusted_node.clone();
            last_application.merge(adjustment.apply_to(current_node))
        })
    }

    /// Applies an adjustment to a node.
    pub fn apply_to(&self, root_node: mir::Node) -> AdjustmentApplication {
        match *self {
            Adjustment::DemoteToRegister { ref demotee } => {
                let mut preceding_nodes = Vec::new();

                let adjusted_node = root_node.recursive_map(&mut |node| {
                    if node == *demotee {
                        let register_ref = mir::Node::new_register_ref(node.ty());
                        preceding_nodes.push(mir::Node::set(register_ref.clone(), node));
                        register_ref
                    } else {
                        node
                    }
                });

                AdjustmentApplication { preceding_nodes: preceding_nodes, adjusted_node: adjusted_node }
            },
            Adjustment::Target(ref _adjustment) => {
                unimplemented!();
            },
        }
    }
}

#[cfg(test)]
mod test
{
    mod apply_to {
        use super::super::*;
        use mir;
        use pattern::DummyPatternValue;

        #[test]
        fn demote_to_register() {
            let register_ref = mir::Node::new_register_ref(mir::Type::i8());
            let example_node = mir::Node::set(register_ref.clone(), mir::Node::i(8, 2));

            let adjustment: Adjustment<DummyPatternValue> = Adjustment::DemoteToRegister {
                demotee: mir::Node::i(8, 2)
            };

            let application = adjustment.apply_to(example_node);

            assert_eq!(application.preceding_nodes.len(), 1);

            let new_set_node = application.preceding_nodes[0].expect_branch();
            let new_register_ref = new_set_node.operands[0].clone();
            assert_eq!(new_set_node.operands[1], mir::Node::i(8, 2));

            let permuted_node = application.adjusted_node.expect_branch();
            assert_eq!(permuted_node.operands[1], new_register_ref);
        }
    }
}

<commit_msg>Add MergeVirtualRegisters adjustment<commit_after>use PatternValue;

use mir;
use util;

/// An adjustment to a pattern.
///
/// Not all possible patterns are an identical match to
/// the MIR. To accomodate this, we have the concept of a
/// pattern _adjustment_.
///
/// When matching patterns, we can have several adjustments
/// which define permutations that would need to be made to the
/// original pattern in order to match.
///
/// We can then look at all the adjustments and figure out which
/// pattern is the most optimal to select.
///
/// Take the case where we have
///
/// ```ignore
/// (add %a, (add %foo, %bar))
/// ```
///
/// This will likely have to have an adjustment to demote the
/// nested addition to a register, so that the code becomes.
///
/// ```ignore
/// %tmp = (add %foo, %bar)
/// (add %a, %tmp)
/// ```
#[derive(Clone,Debug,PartialEq,Eq)]
pub enum Adjustment<V: PatternValue>
{
    /// Demotes a subnode to a register.
    DemoteToRegister {
        demotee: mir::Node,
    },
    /// Merges two virtual registers into one.
    ///
    /// This can do something like the following.
    ///
    /// ```ignore
    /// (set %a, (add %b, i5))
    /// ```
    ///
    /// ```ignore
    /// (set %a, (add %a, i5))
    /// ```
    ///
    /// So that they will always refer to the same physical register.
    MergeVirtualRegisters {
        /// The ID of the register to remove.
        from: util::Id,
        /// The ID of the register that will now be referenced.
        to: util::Id,
    },
    Target(V::Adjustment),
}

/// The result of an adjustment application.
#[derive(Clone,Debug,PartialEq,Eq)]
pub struct AdjustmentApplication
{
    /// An adjustment may create extra nodes preceding the node
    /// that was adjusted. For example, promoting an operand
    /// to a register would a register set node to precede the adjusted node.
    pub preceding_nodes: Vec<mir::Node>,

    /// The original node that was adjusted.
    pub adjusted_node: mir::Node,
}

impl AdjustmentApplication
{
    pub fn unadjusted(node: mir::Node) -> Self {
        AdjustmentApplication {
            preceding_nodes: Vec::new(),
            adjusted_node: node,
        }
    }

    /// Gets all of the nodes (in order) that were created or modified
    /// by the adjustment.
    pub fn nodes(&self) -> Vec<mir::Node> {
        let mut nodes = self.preceding_nodes.clone();
        nodes.push(self.adjusted_node.clone());
        nodes
    }

    fn merge(mut self, other: Self) -> Self {
        self.preceding_nodes.extend(other.preceding_nodes);
        self.adjusted_node = other.adjusted_node;
        self
    }
}

impl<V: PatternValue> Adjustment<V>
{
    pub fn demote_to_register(node: &mir::Node) -> Self {
        Adjustment::DemoteToRegister {
            demotee: node.clone(),
        }
    }

    pub fn apply_several_to(root_node: mir::Node, adjustments: &[Self]) -> AdjustmentApplication {
        adjustments.iter().fold(AdjustmentApplication::unadjusted(root_node), |last_application, adjustment| {
            let current_node = last_application.adjusted_node.clone();
            last_application.merge(adjustment.apply_to(current_node))
        })
    }

    /// Applies an adjustment to a node.
    pub fn apply_to(&self, root_node: mir::Node) -> AdjustmentApplication {
        match *self {
            Adjustment::DemoteToRegister { ref demotee } => {
                let mut preceding_nodes = Vec::new();

                let adjusted_node = root_node.recursive_map(&mut |node| {
                    if node == *demotee {
                        let register_ref = mir::Node::new_register_ref(node.ty());
                        preceding_nodes.push(mir::Node::set(register_ref.clone(), node));
                        register_ref
                    } else {
                        node
                    }
                });

                AdjustmentApplication { preceding_nodes: preceding_nodes, adjusted_node: adjusted_node }
            },
            Adjustment::MergeVirtualRegisters { from, to } => {
                unimplemented!();
            },
            Adjustment::Target(ref _adjustment) => {
                unimplemented!();
            },
        }
    }
}

#[cfg(test)]
mod test
{
    mod apply_to {
        use super::super::*;
        use mir;
        use pattern::DummyPatternValue;

        #[test]
        fn demote_to_register() {
            let register_ref = mir::Node::new_register_ref(mir::Type::i8());
            let example_node = mir::Node::set(register_ref.clone(), mir::Node::i(8, 2));

            let adjustment: Adjustment<DummyPatternValue> = Adjustment::DemoteToRegister {
                demotee: mir::Node::i(8, 2)
            };

            let application = adjustment.apply_to(example_node);

            assert_eq!(application.preceding_nodes.len(), 1);

            let new_set_node = application.preceding_nodes[0].expect_branch();
            let new_register_ref = new_set_node.operands[0].clone();
            assert_eq!(new_set_node.operands[1], mir::Node::i(8, 2));

            let permuted_node = application.adjusted_node.expect_branch();
            assert_eq!(permuted_node.operands[1], new_register_ref);
        }
    }
}

<|endoftext|>


<commit_before>#[doc="Fundamental layout structures and algorithms."]

import dom::base::{element, es_div, es_img, node_data, node_kind, node};
import dom::rcu;
import dom::rcu::reader_methods;
import gfx::geom;
import gfx::geom::{size, rect, point, au, zero_size_au};
import image::base::image;
import /*layout::*/block::block_layout_methods;
import /*layout::*/inline::inline_layout_methods;
import /*layout::*/style::style::*;
import /*layout::*/text::*;
import util::tree;

enum box_kind {
    bk_block,
    bk_inline,
    bk_intrinsic(@geom::size<au>),
    bk_text(@text_box)
}

class appearance {
    let mut background_image: option<@image>;

    new() {
        self.background_image = none;
    }
}

enum box = {
    tree: tree::fields<@box>,
    node: node,
    mut bounds: geom::rect<au>,
    kind: box_kind,
    appearance: appearance
};

enum layout_data = {
    mut computed_style: computed_style,
    mut box: option<@box>
};

enum ntree { ntree }
impl of tree::rd_tree_ops<node> for ntree {
    fn each_child(node: node, f: fn(node) -> bool) {
        tree::each_child(self, node, f)
    }

    fn with_tree_fields<R>(n: node, f: fn(tree::fields<node>) -> R) -> R {
        n.rd { |n| f(n.tree) }
    }
}

enum btree { btree }
impl of tree::rd_tree_ops<@box> for btree {
    fn each_child(node: @box, f: fn(&&@box) -> bool) {
        tree::each_child(self, node, f)
    }

    fn with_tree_fields<R>(b: @box, f: fn(tree::fields<@box>) -> R) -> R {
        f(b.tree)
    }
}

impl of tree::wr_tree_ops<@box> for btree {
    fn add_child(node: @box, child: @box) {
        tree::add_child(self, node, child)
    }

    fn with_tree_fields<R>(b: @box, f: fn(tree::fields<@box>) -> R) -> R {
        f(b.tree)
    }
}

impl layout_methods_priv for @box {
    #[doc="Dumps the box tree, for debugging, with indentation."]
    fn dump_indent(indent: uint) {
        let mut s = "";
        for uint::range(0u, indent) {
            |_i|
            s += "    ";
        }

        s += #fmt("%?", self.kind);
        #debug["%s", s];

        for btree.each_child(self) { |kid| kid.dump_indent(indent + 1u) }
    }
}

impl layout_methods for @box {
    #[doc="The main reflow routine."]
    fn reflow(available_width: au) {
        alt self.kind {
            bk_block { self.reflow_block(available_width) }
            bk_inline { self.reflow_inline(available_width) }
            bk_intrinsic(size) { self.reflow_intrinsic(*size) }
            bk_text(subbox) { self.reflow_text(available_width, subbox) }
        }
    }

    #[doc="The trivial reflow routine for instrinsically-sized frames."]
    fn reflow_intrinsic(size: geom::size<au>) {
        self.bounds.size = copy size;

        #debug["reflow_intrinsic size=%?", self.bounds];
    }

    #[doc="Dumps the box tree, for debugging."]
    fn dump() {
        self.dump_indent(0u);
    }
}

// Debugging

impl node_methods_priv for node {
    #[doc="Dumps the node tree, for debugging, with indentation."]
    fn dump_indent(indent: uint) {
        let mut s = "";
        for uint::range(0u, indent) {
            |_i|
            s += "    ";
        }

        s += #fmt("%?", self.rd({ |n| copy n.kind }));
        #debug["%s", s];

        for ntree.each_child(self) { |kid| kid.dump_indent(indent + 1u) }
    }
}

impl node_methods for node {
    #[doc="Dumps the subtree rooted at this node, for debugging."]
    fn dump() {
        self.dump_indent(0u);
    }
}

#[cfg(test)]
mod test {
    import dom::base::{element, es_div, es_img, methods, nk_element, node_data,
                       node_kind, node, wr_tree_ops};
    import dom::rcu::scope;
    import box_builder::{box_builder_methods};

    /*
    use sdl;
    import sdl::video;

    fn with_screen(f: fn(*sdl::surface)) {
        let screen = video::set_video_mode(
            320, 200, 32,
            [video::hwsurface], [video::doublebuf]);
        assert screen != ptr::null();

        f(screen);

        video::free_surface(screen);
    }
    */

    fn flat_bounds(root: @box) -> [geom::rect<au>] {
        let mut r = [];
        for tree::each_child(btree, root) {|c|
            r += flat_bounds(c);
        }
        ret r + [root.bounds];
    }

    #[test]
    #[ignore(reason = "busted")]
    fn do_layout() {
        let s = scope();

        let n0 = s.new_node(nk_element(element("img",
                                               ~es_img(size(au(10),au(10))))));
        let n1 = s.new_node(nk_element(element("img",
                                               ~es_img(size(au(10),au(15))))));
        let n2 = s.new_node(nk_element(element("img",
                                               ~es_img(size(au(10),au(20))))));
        let n3 = s.new_node(nk_element(element("div", ~es_div)));

        tree::add_child(s, n3, n0);
        tree::add_child(s, n3, n1);
        tree::add_child(s, n3, n2);

        let b0 = n0.construct_boxes();
        let b1 = n1.construct_boxes();
        let b2 = n2.construct_boxes();
        let b3 = n3.construct_boxes();

        tree::add_child(btree, b3, b0);
        tree::add_child(btree, b3, b1);
        tree::add_child(btree, b3, b2);

        b3.reflow_block(au(100));
        let fb = flat_bounds(b3);
        #debug["fb=%?", fb];
        assert fb == [geom::box(au(0), au(0), au(10), au(10)),   // n0
                      geom::box(au(0), au(10), au(10), au(15)),  // n1
                      geom::box(au(0), au(25), au(10), au(20)),  // n2
                      geom::box(au(0), au(0), au(100), au(45))]; // n3
    }
}

<commit_msg>make modes explicit<commit_after>#[doc="Fundamental layout structures and algorithms."]

import dom::base::{element, es_div, es_img, node_data, node_kind, node};
import dom::rcu;
import dom::rcu::reader_methods;
import gfx::geom;
import gfx::geom::{size, rect, point, au, zero_size_au};
import image::base::image;
import /*layout::*/block::block_layout_methods;
import /*layout::*/inline::inline_layout_methods;
import /*layout::*/style::style::*;
import /*layout::*/text::*;
import util::tree;

enum box_kind {
    bk_block,
    bk_inline,
    bk_intrinsic(@geom::size<au>),
    bk_text(@text_box)
}

class appearance {
    let mut background_image: option<@image>;

    new() {
        self.background_image = none;
    }
}

enum box = {
    tree: tree::fields<@box>,
    node: node,
    mut bounds: geom::rect<au>,
    kind: box_kind,
    appearance: appearance
};

enum layout_data = {
    mut computed_style: computed_style,
    mut box: option<@box>
};

enum ntree { ntree }
impl of tree::rd_tree_ops<node> for ntree {
    fn each_child(node: node, f: fn(node) -> bool) {
        tree::each_child(self, node, f)
    }

    fn with_tree_fields<R>(&&n: node, f: fn(tree::fields<node>) -> R) -> R {
        n.rd { |n| f(n.tree) }
    }
}

enum btree { btree }
impl of tree::rd_tree_ops<@box> for btree {
    fn each_child(node: @box, f: fn(&&@box) -> bool) {
        tree::each_child(self, node, f)
    }

    fn with_tree_fields<R>(&&b: @box, f: fn(tree::fields<@box>) -> R) -> R {
        f(b.tree)
    }
}

impl of tree::wr_tree_ops<@box> for btree {
    fn add_child(node: @box, child: @box) {
        tree::add_child(self, node, child)
    }

    fn with_tree_fields<R>(&&b: @box, f: fn(tree::fields<@box>) -> R) -> R {
        f(b.tree)
    }
}

impl layout_methods_priv for @box {
    #[doc="Dumps the box tree, for debugging, with indentation."]
    fn dump_indent(indent: uint) {
        let mut s = "";
        for uint::range(0u, indent) {
            |_i|
            s += "    ";
        }

        s += #fmt("%?", self.kind);
        #debug["%s", s];

        for btree.each_child(self) { |kid| kid.dump_indent(indent + 1u) }
    }
}

impl layout_methods for @box {
    #[doc="The main reflow routine."]
    fn reflow(available_width: au) {
        alt self.kind {
            bk_block { self.reflow_block(available_width) }
            bk_inline { self.reflow_inline(available_width) }
            bk_intrinsic(size) { self.reflow_intrinsic(*size) }
            bk_text(subbox) { self.reflow_text(available_width, subbox) }
        }
    }

    #[doc="The trivial reflow routine for instrinsically-sized frames."]
    fn reflow_intrinsic(size: geom::size<au>) {
        self.bounds.size = copy size;

        #debug["reflow_intrinsic size=%?", self.bounds];
    }

    #[doc="Dumps the box tree, for debugging."]
    fn dump() {
        self.dump_indent(0u);
    }
}

// Debugging

impl node_methods_priv for node {
    #[doc="Dumps the node tree, for debugging, with indentation."]
    fn dump_indent(indent: uint) {
        let mut s = "";
        for uint::range(0u, indent) {
            |_i|
            s += "    ";
        }

        s += #fmt("%?", self.rd({ |n| copy n.kind }));
        #debug["%s", s];

        for ntree.each_child(self) { |kid| kid.dump_indent(indent + 1u) }
    }
}

impl node_methods for node {
    #[doc="Dumps the subtree rooted at this node, for debugging."]
    fn dump() {
        self.dump_indent(0u);
    }
}

#[cfg(test)]
mod test {
    import dom::base::{element, es_div, es_img, methods, nk_element, node_data,
                       node_kind, node, wr_tree_ops};
    import dom::rcu::scope;
    import box_builder::{box_builder_methods};

    /*
    use sdl;
    import sdl::video;

    fn with_screen(f: fn(*sdl::surface)) {
        let screen = video::set_video_mode(
            320, 200, 32,
            [video::hwsurface], [video::doublebuf]);
        assert screen != ptr::null();

        f(screen);

        video::free_surface(screen);
    }
    */

    fn flat_bounds(root: @box) -> [geom::rect<au>] {
        let mut r = [];
        for tree::each_child(btree, root) {|c|
            r += flat_bounds(c);
        }
        ret r + [root.bounds];
    }

    #[test]
    #[ignore(reason = "busted")]
    fn do_layout() {
        let s = scope();

        let n0 = s.new_node(nk_element(element("img",
                                               ~es_img(size(au(10),au(10))))));
        let n1 = s.new_node(nk_element(element("img",
                                               ~es_img(size(au(10),au(15))))));
        let n2 = s.new_node(nk_element(element("img",
                                               ~es_img(size(au(10),au(20))))));
        let n3 = s.new_node(nk_element(element("div", ~es_div)));

        tree::add_child(s, n3, n0);
        tree::add_child(s, n3, n1);
        tree::add_child(s, n3, n2);

        let b0 = n0.construct_boxes();
        let b1 = n1.construct_boxes();
        let b2 = n2.construct_boxes();
        let b3 = n3.construct_boxes();

        tree::add_child(btree, b3, b0);
        tree::add_child(btree, b3, b1);
        tree::add_child(btree, b3, b2);

        b3.reflow_block(au(100));
        let fb = flat_bounds(b3);
        #debug["fb=%?", fb];
        assert fb == [geom::box(au(0), au(0), au(10), au(10)),   // n0
                      geom::box(au(0), au(10), au(10), au(15)),  // n1
                      geom::box(au(0), au(25), au(10), au(20)),  // n2
                      geom::box(au(0), au(0), au(100), au(45))]; // n3
    }
}

<|endoftext|>


<commit_before>use cgmath::{Vector, Vector2, Vector3, EuclideanVector, Matrix};
use shader::base::*;

impl Shader {
    // out:
    // 0 - Vector3 reflection
    pub fn vertex_cubemap(&mut self) {
        let eye = self.matrix_arr[MATRIX_VIEW_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_POS)).normalize();
        // let view = self.read_vec4(IN_VS_VEC_EYE_POS).sub_v(&pos_w).normalize();
        let norm = self.matrix_arr[MATRIX_VIEW_WORLD]
            // .invert().unwrap()
            .mul_v(&self.read_vec4(IN_VS_VEC_NORM).normalize()).normalize();
        let reflection = eye.sub_v(&norm.mul_s(norm.dot(&eye) * 2.0_f32));

        self.out_vec3_from4(&reflection)
    }

    // in:
    // 0 - Vector3 reflection
    pub fn pixel_cubemap(&self, base_color: Vector3<f32>) -> Vector3<f32> {
        let lod = 0;
        let offset = self.vertex_out2_base;
        let reflection = Vector3::new(self.in_pixel_data[offset + 0],
                                      self.in_pixel_data[offset + 1],
                                      self.in_pixel_data[offset + 2]).normalize();

        let irx = reflection.x;
        let iry = reflection.y;
        let irz = reflection.z;
        let urx = irx.abs();
        let ury = iry.abs();
        let urz = irz.abs();

        let (index, sc, tc, ma) =
            // x plane
            if (urx > urz) && (urx > ury) {
                if irx.is_sign_positive() {
                    (0, -irz,  iry, urx)
                } else {
                    (1,  irz,  iry, urx)
                }
                // y plane
            } else if ury > urz {
                if iry > 0.0_f32 {
                    (2,  irx, -irz, ury)
                } else {
                    (3,  irx,  irz, ury)
                }
                // z plane
            } else {
                if irz.is_sign_positive() {
                    (4,  irx,  iry, urz)
                } else {
                    (5, -irx,  iry, urz)
                }
            };

        let coord = Vector2::new(( sc/ma + 1.0_f32 ) / 2.0_f32,
                                 ( tc/ma + 1.0_f32 ) / 2.0_f32);

        match self.texture_cube {
            Some(ref t) => t
                .get_texture(index)
                .get_surface(lod)
                .tex_2d_bilinear(coord)
                .lerp(&base_color, 0.3_f32),
            None => panic!("texture_cube is not set"),
        }

        // reflection.add_s(1.0_f32).mul_s(128.0_f32)
        // match index {
        //     0 => Vector3::new(256.0_f32, 0.0_f32, 256.0_f32),
        //     1 => Vector3::new(0.0_f32, 256.0_f32, 256.0_f32),
        //     2 => Vector3::new(256.0_f32, 256.0_f32, 0.0_f32),
        //     3 => Vector3::new(0.0_f32, 0.0_f32, 256.0_f32),
        //     4 => Vector3::new(0.0_f32, 256.0_f32, 0.0_f32),
        //     5 => Vector3::new(256.0_f32, 0.0_f32, 0.0_f32),
        //     _ => Vector3::new(0.0_f32, 0.0_f32, 0.0_f32),
        // }
    }
}
<commit_msg>remove commented code<commit_after>use cgmath::{Vector, Vector2, Vector3, EuclideanVector, Matrix};
use shader::base::*;

impl Shader {
    // out:
    // 0 - Vector3 reflection
    pub fn vertex_cubemap(&mut self) {
        let eye = self.matrix_arr[MATRIX_VIEW_WORLD].mul_v(&self.read_vec4(IN_VS_VEC_POS)).normalize();
        let norm = self.matrix_arr[MATRIX_VIEW_WORLD]
            .mul_v(&self.read_vec4(IN_VS_VEC_NORM).normalize()).normalize();
        let reflection = eye.sub_v(&norm.mul_s(norm.dot(&eye) * 2.0_f32));

        self.out_vec3_from4(&reflection)
    }

    // in:
    // 0 - Vector3 reflection
    pub fn pixel_cubemap(&self, base_color: Vector3<f32>) -> Vector3<f32> {
        let lod = 0;
        let offset = self.vertex_out2_base;
        let reflection = Vector3::new(self.in_pixel_data[offset + 0],
                                      self.in_pixel_data[offset + 1],
                                      self.in_pixel_data[offset + 2]).normalize();

        let irx = reflection.x;
        let iry = reflection.y;
        let irz = reflection.z;
        let urx = irx.abs();
        let ury = iry.abs();
        let urz = irz.abs();

        let (index, sc, tc, ma) =
            // x plane
            if (urx > urz) && (urx > ury) {
                if irx.is_sign_positive() {
                    (0, -irz,  iry, urx)
                } else {
                    (1,  irz,  iry, urx)
                }
                // y plane
            } else if ury > urz {
                if iry > 0.0_f32 {
                    (2,  irx, -irz, ury)
                } else {
                    (3,  irx,  irz, ury)
                }
                // z plane
            } else {
                if irz.is_sign_positive() {
                    (4,  irx,  iry, urz)
                } else {
                    (5, -irx,  iry, urz)
                }
            };

        let coord = Vector2::new(( sc/ma + 1.0_f32 ) / 2.0_f32,
                                 ( tc/ma + 1.0_f32 ) / 2.0_f32);

        match self.texture_cube {
            Some(ref t) => t
                .get_texture(index)
                .get_surface(lod)
                .tex_2d_bilinear(coord)
                .lerp(&base_color, 0.3_f32),
            None => panic!("texture_cube is not set"),
        }
    }
}
<|endoftext|>


<commit_before>//! Tests for containers.rs

#[cfg(test)]
mod tests {
    use super::super::containers::*;
    use std::rc::*;
    use rustwlc::handle::*;
    use rustwlc::types::*;

    #[cfg(test)]
    /// Sets up a root node with 10 workspaces
    fn root_setup() -> Node {
        let mut root = Container::new_root();
        let mut output = Container::new_output(&mut root, WlcView::root().as_output());
        for _ in 0..10 {
            Container::new_workspace(&mut output);
        }
        root
    }

    #[test]
    #[should_panic(expected = "Can only be one root")]
    /// Test to make sure that there can be only one root node
    fn test_one_root() {
        let _root = Container::new_root();
        // Should panic
        let _root2 = Container::new_root();
        // remove when we fix it
        panic!("Can only be one root");
    }

    #[test]
    /// Verify that root node has required properties
    fn root_validity_test() {
        let main: Node = Container::new_root();
        let root = main.borrow();
        // Make sure it starts with no children (but can have children)
        assert_eq!(root.get_children().unwrap().len(), 0);
        // This is the tippity-top of the tree
        assert!(root.get_parent().is_none());
        assert_eq!(root.get_type(), ContainerType::Root);
        // Should this be true? It makes sense, but it might cause complications
        // so we'll go with false for now
        assert!(! root.is_focused());
        // Root is parent of all nodes, including itself
        assert!(root.is_parent_of(main.clone()));
        // Root is not a child of anything, except for itself
        // NOTE Add more test when we have more container types
        assert!(root.is_child_of(main.clone()));
        assert!(root.get_position().is_none());
        assert!(root.get_dimensions().is_none());
        assert!(root.is_root());
    }

    #[test]
    fn workspace_validity_test() {
        let root = root_setup();
        assert_eq!(root.borrow().get_children().unwrap().len(), 1);
        let output = &mut root.borrow().get_children().unwrap().to_vec()[0];
        let output_copy = Rc::make_mut(&mut output.clone()).clone().into_inner();
        for container_ in output.borrow().get_children().unwrap().to_vec() {
            // Workspaces start out empty
            let mut container = container_.borrow_mut();
            assert_eq!(container.get_children().unwrap().len(), 0);
            let container_copy = Rc::make_mut(&mut container.get_parent().unwrap().clone()).clone().into_inner();
            assert_eq!(container_copy, output_copy);
            // NOTE add test for add_child
            assert_eq!(container.get_type(), ContainerType::Workspace);
            assert!(! container.is_focused());
            // NOTE add test for remove_child_at
            assert!(! container.get_visibility());
            container.set_visibility(true);
            assert!(container.get_visibility());
            container.set_visibility(false);
            assert!(! container.get_visibility());
            // NOTE Add these once they can be set properly
            //assert_eq!(container.get_dimensions().unwrap(), (0,0));
            //assert_eq!(container.get_position().unwrap(), (0,0));
            // NOTE add test for is_parent_of
            assert!(container.is_child_of(root.clone()));
            assert!(! container.is_root());
            assert_eq!(container.get_parent_by_type(ContainerType::Root).unwrap(), root);
        }
    }

    #[test]
    fn container_validity_test() {
        let root = root_setup();
        for output in root.borrow().get_children().unwrap().to_vec() {
            let mut workspace_ = &mut output.borrow().get_children().unwrap().to_vec()[0];
            let workspace_copy = Rc::make_mut(&mut workspace_.clone()).clone().into_inner();
            let container_ = Container::new_container(&mut workspace_, Layout::Horizontal);
            let mut container = container_.borrow_mut();
            // No children
            assert_eq!(container.get_children().unwrap().len(), 0);
            // Is the only child of the workspace
            let container_parent = Rc::make_mut(&mut container.get_parent().unwrap().clone()).clone().into_inner();
            assert_eq!(workspace_copy, container_parent);
            // drop our copy of container here, because otherwise it panics at
            // run time. Another way to do this is at the beginning, but this is
            // a good test of what we need to do to stay dynamic
            drop(container);
            // This new workspace will now be the outer one, the old workspace is now on the inside
            let outer_container = Container::new_container(&mut container_.clone(), Layout::Horizontal);
            container = container_.borrow_mut();
            assert_eq!(outer_container.borrow().get_children().unwrap().len(), 1);
            assert_eq!(container.get_children().unwrap().len(), 0);
            let self_as_child = outer_container.borrow().get_children().unwrap()[0].clone();
            drop(container);
            assert_eq!(*self_as_child.borrow(), *outer_container.borrow());
            let container = container_.borrow();
            assert_eq!(container.get_type(), ContainerType::Container);
            drop(container);
            let container2 = container_.borrow();
            assert!(container2.is_parent_of(outer_container.clone()));
            drop(container2);
            let mut container = container_.borrow_mut();
            // We also need to drop our copy of the container here when checking
            // if we are a child of the container, since we have to borrow the
            // container right here again in order to check if it's the parent.
            //
            // Again, this is only an "issue" because we are borrow_mut for
            // such a long period of time
            drop(container);
            assert!(outer_container.borrow().is_child_of(container_.clone()));
            container = container_.borrow_mut();
            assert!(! container.is_focused());
            container.set_visibility(true);
            assert!(container.get_visibility());
            container.set_visibility(false);
            assert!(! container.get_visibility());
            // NOTE add these once they can be set properly
            //assert_eq!(container.get_dimensions().unwrap(), (0,0));
            //assert_eq!(container.get_position().unwrap(), (0,0));
            assert!(container.is_child_of(root.clone()));
            assert!(! container.is_root());
            assert_eq!(container.get_parent_by_type(ContainerType::Workspace).unwrap(), *workspace_);
            assert_eq!(container.get_parent_by_type(ContainerType::Root).unwrap(), root);
        }
    }

    #[test]
    fn view_validity_test() {
        let root = root_setup();
        let output = &root.borrow().get_children().unwrap().to_vec()[0];
        for mut workspace_ in output.borrow().get_children().unwrap().to_vec() {
            let mut container_ = Container::new_container(&mut workspace_, Layout::Horizontal);
            // hack to give it a size and origin point.
            let view_hack = WlcView::root();
            view_hack.set_geometry(EDGE_NONE, &Geometry { origin: Point { x: 0, y: 0}, size: Size { w: 0, h: 0}});
            let view = Container::new_view(&mut container_, view_hack);
            assert_eq!(view.borrow().get_parent().unwrap(), container_);
            // Add child test
            // The view was added as a sibling, so it's not a child of the container
            assert_eq!(container_.borrow().get_children().unwrap().len(), 0);
            view.borrow_mut().add_sibling(container_.clone()).unwrap();
            assert_eq!(container_.borrow().get_children().unwrap().len(), 1);
        }
    }

    #[test]
    #[should_panic(expect = "Cannot add child to a view")]
    fn ensure_views_cant_have_children_test() {
        let root = root_setup();
        let mut workspace = root.borrow_mut().get_children().unwrap().to_vec()[0].clone();
        let view = Container::new_view(&mut workspace, WlcView::root());
        view.borrow_mut().add_child(workspace).unwrap();
    }

    #[test]
    fn remove_container_test() {
        let root = root_setup();
        let output = &mut root.borrow().get_children().unwrap().to_vec()[0];
        let workspace = &mut output.borrow().get_children().unwrap().to_vec()[0];
        let container = Container::new_container(workspace, Layout::Horizontal);

        let container_ref = Rc::downgrade(&workspace.borrow().get_children().unwrap()[0].clone());
        // Still points to the container
        assert!(container_ref.clone().upgrade().is_some());
        // removes workspace's reference to it
        container.borrow().remove_container().unwrap();
        // We still can see it, so it's still alive
        assert!(container_ref.clone().upgrade().is_some());
        // drop our reference to it
        drop(container);
        assert!(! container_ref.clone().upgrade().is_some());
    }

    #[test]
    #[should_panic(expect = "Cannot remove root container")]
    fn ensure_root_container_unremovable_test() {
        let root = root_setup();
        root.borrow_mut().remove_container().expect("Cannot remove root container");
    }

    #[test]
    #[should_panic(expect = "Cannot remove root container")]
    fn ensure_workspace_container_unremovable_test() {
        let root = root_setup();
        let workspace = root.borrow().get_children().unwrap()[0].clone();
        workspace.borrow_mut().remove_container().expect("Cannot remove root container");
    }

    #[test]
    #[should_panic(expect = "Only workspaces can be added to the root node")]
    /// Tests to make sure only workspaces can be children of the top node
    fn root_workspace_only() {
        let root = root_setup();
        let container = &mut root.borrow().get_children().unwrap().to_vec()[0];
        Container::new_workspace(container);
    }

    #[test]
    #[should_panic(expect = "Only containers can be children of a workspace")]
    /// Tests to ensure that only containers can be the children of a workspace
    fn only_containers_for_workspace_children_test() {
        let root = root_setup();
        let output = &root.borrow().get_children().unwrap().to_vec()[0];
        let container = output.borrow().get_children().unwrap()[0].clone();
        container.borrow_mut().add_child(container.clone()).unwrap();
    }

    #[test]
    /// Tests that you can have a root with some workspaces, that the workspaces
    /// can be removed, and that you can add simple containers to the
    /// workspaces. (Does not test views)
    fn basic_tree_test() {
        let mut root = root_setup();
        assert_eq!(root.borrow().get_children().unwrap().len(), 1);
        let output = root.borrow().get_children().unwrap()[0].clone();
        assert_eq!(output.borrow().get_children().unwrap().len(), 10);
        // NOTE Enhance with adding containers to the workspaces
    }

}
<commit_msg>Removed unneccessary tests<commit_after>//! Tests for containers.rs

#[cfg(test)]
mod tests {
    use super::super::containers::*;
    use std::rc::*;
    use rustwlc::handle::*;
    use rustwlc::types::*;

    #[cfg(test)]
    /// Sets up a root node with 10 workspaces
    fn root_setup() -> Node {
        let mut root = Container::new_root();
        let mut output = Container::new_output(&mut root, WlcView::root().as_output());
        for _ in 0..10 {
            Container::new_workspace(&mut output);
        }
        root
    }

    #[test]
    /// Verify that root node has required properties
    fn root_validity_test() {
        let main: Node = Container::new_root();
        let root = main.borrow();
        // Make sure it starts with no children (but can have children)
        assert_eq!(root.get_children().unwrap().len(), 0);
        // This is the tippity-top of the tree
        assert!(root.get_parent().is_none());
        assert_eq!(root.get_type(), ContainerType::Root);
        // Should this be true? It makes sense, but it might cause complications
        // so we'll go with false for now
        assert!(! root.is_focused());
        // Root is parent of all nodes, including itself
        assert!(root.is_parent_of(main.clone()));
        // Root is not a child of anything, except for itself
        // NOTE Add more test when we have more container types
        assert!(root.is_child_of(main.clone()));
        assert!(root.get_position().is_none());
        assert!(root.get_dimensions().is_none());
        assert!(root.is_root());
    }

    #[test]
    fn workspace_validity_test() {
        let root = root_setup();
        assert_eq!(root.borrow().get_children().unwrap().len(), 1);
        let output = &mut root.borrow().get_children().unwrap().to_vec()[0];
        let output_copy = Rc::make_mut(&mut output.clone()).clone().into_inner();
        for container_ in output.borrow().get_children().unwrap().to_vec() {
            // Workspaces start out empty
            let mut container = container_.borrow_mut();
            assert_eq!(container.get_children().unwrap().len(), 0);
            let container_copy = Rc::make_mut(&mut container.get_parent().unwrap().clone()).clone().into_inner();
            assert_eq!(container_copy, output_copy);
            // NOTE add test for add_child
            assert_eq!(container.get_type(), ContainerType::Workspace);
            assert!(! container.is_focused());
            // NOTE add test for remove_child_at
            assert!(! container.get_visibility());
            container.set_visibility(true);
            assert!(container.get_visibility());
            container.set_visibility(false);
            assert!(! container.get_visibility());
            // NOTE Add these once they can be set properly
            //assert_eq!(container.get_dimensions().unwrap(), (0,0));
            //assert_eq!(container.get_position().unwrap(), (0,0));
            // NOTE add test for is_parent_of
            assert!(container.is_child_of(root.clone()));
            assert!(! container.is_root());
            assert_eq!(container.get_parent_by_type(ContainerType::Root).unwrap(), root);
        }
    }

    #[test]
    fn container_validity_test() {
        let root = root_setup();
        for output in root.borrow().get_children().unwrap().to_vec() {
            let mut workspace_ = &mut output.borrow().get_children().unwrap().to_vec()[0];
            let workspace_copy = Rc::make_mut(&mut workspace_.clone()).clone().into_inner();
            let container_ = Container::new_container(&mut workspace_, Layout::Horizontal);
            let mut container = container_.borrow_mut();
            // No children
            assert_eq!(container.get_children().unwrap().len(), 0);
            // Is the only child of the workspace
            let container_parent = Rc::make_mut(&mut container.get_parent().unwrap().clone()).clone().into_inner();
            assert_eq!(workspace_copy, container_parent);
            // drop our copy of container here, because otherwise it panics at
            // run time. Another way to do this is at the beginning, but this is
            // a good test of what we need to do to stay dynamic
            drop(container);
            // This new workspace will now be the outer one, the old workspace is now on the inside
            let outer_container = Container::new_container(&mut container_.clone(), Layout::Horizontal);
            container = container_.borrow_mut();
            assert_eq!(outer_container.borrow().get_children().unwrap().len(), 1);
            assert_eq!(container.get_children().unwrap().len(), 0);
            let self_as_child = outer_container.borrow().get_children().unwrap()[0].clone();
            drop(container);
            assert_eq!(*self_as_child.borrow(), *outer_container.borrow());
            let container = container_.borrow();
            assert_eq!(container.get_type(), ContainerType::Container);
            drop(container);
            let container2 = container_.borrow();
            assert!(container2.is_parent_of(outer_container.clone()));
            drop(container2);
            let mut container = container_.borrow_mut();
            // We also need to drop our copy of the container here when checking
            // if we are a child of the container, since we have to borrow the
            // container right here again in order to check if it's the parent.
            //
            // Again, this is only an "issue" because we are borrow_mut for
            // such a long period of time
            drop(container);
            assert!(outer_container.borrow().is_child_of(container_.clone()));
            container = container_.borrow_mut();
            assert!(! container.is_focused());
            container.set_visibility(true);
            assert!(container.get_visibility());
            container.set_visibility(false);
            assert!(! container.get_visibility());
            // NOTE add these once they can be set properly
            //assert_eq!(container.get_dimensions().unwrap(), (0,0));
            //assert_eq!(container.get_position().unwrap(), (0,0));
            assert!(container.is_child_of(root.clone()));
            assert!(! container.is_root());
            assert_eq!(container.get_parent_by_type(ContainerType::Workspace).unwrap(), *workspace_);
            assert_eq!(container.get_parent_by_type(ContainerType::Root).unwrap(), root);
        }
    }

    #[test]
    fn view_validity_test() {
        let root = root_setup();
        let output = &root.borrow().get_children().unwrap().to_vec()[0];
        for mut workspace_ in output.borrow().get_children().unwrap().to_vec() {
            let mut container_ = Container::new_container(&mut workspace_, Layout::Horizontal);
            // hack to give it a size and origin point.
            let view_hack = WlcView::root();
            view_hack.set_geometry(EDGE_NONE, &Geometry { origin: Point { x: 0, y: 0}, size: Size { w: 0, h: 0}});
            let view = Container::new_view(&mut container_, view_hack);
            assert_eq!(view.borrow().get_parent().unwrap(), container_);
            // Add child test
            // The view was added as a sibling, so it's not a child of the container
            assert_eq!(container_.borrow().get_children().unwrap().len(), 0);
            view.borrow_mut().add_sibling(container_.clone()).unwrap();
            assert_eq!(container_.borrow().get_children().unwrap().len(), 1);
        }
    }

    #[test]
    #[should_panic(expect = "Cannot add child to a view")]
    fn ensure_views_cant_have_children_test() {
        let root = root_setup();
        let mut workspace = root.borrow_mut().get_children().unwrap().to_vec()[0].clone();
        let view = Container::new_view(&mut workspace, WlcView::root());
        view.borrow_mut().add_child(workspace).unwrap();
    }

    #[test]
    fn remove_container_test() {
        let root = root_setup();
        let output = &mut root.borrow().get_children().unwrap().to_vec()[0];
        let workspace = &mut output.borrow().get_children().unwrap().to_vec()[0];
        let container = Container::new_container(workspace, Layout::Horizontal);

        let container_ref = Rc::downgrade(&workspace.borrow().get_children().unwrap()[0].clone());
        // Still points to the container
        assert!(container_ref.clone().upgrade().is_some());
        // removes workspace's reference to it
        container.borrow().remove_container().unwrap();
        // We still can see it, so it's still alive
        assert!(container_ref.clone().upgrade().is_some());
        // drop our reference to it
        drop(container);
        assert!(! container_ref.clone().upgrade().is_some());
    }

    #[test]
    #[should_panic(expect = "Cannot remove root container")]
    fn ensure_root_container_unremovable_test() {
        let root = root_setup();
        root.borrow_mut().remove_container().expect("Cannot remove root container");
    }

    #[test]
    #[should_panic(expect = "Cannot remove root container")]
    fn ensure_workspace_container_unremovable_test() {
        let root = root_setup();
        let workspace = root.borrow().get_children().unwrap()[0].clone();
        workspace.borrow_mut().remove_container().expect("Cannot remove root container");
    }

    #[test]
    #[should_panic(expect = "Only containers can be children of a workspace")]
    /// Tests to ensure that only containers can be the children of a workspace
    fn only_containers_for_workspace_children_test() {
        let root = root_setup();
        let output = &root.borrow().get_children().unwrap().to_vec()[0];
        let container = output.borrow().get_children().unwrap()[0].clone();
        container.borrow_mut().add_child(container.clone()).unwrap();
    }

    #[test]
    /// Tests that you can have a root with some workspaces, that the workspaces
    /// can be removed, and that you can add simple containers to the
    /// workspaces. (Does not test views)
    fn basic_tree_test() {
        let mut root = root_setup();
        assert_eq!(root.borrow().get_children().unwrap().len(), 1);
        let output = root.borrow().get_children().unwrap()[0].clone();
        assert_eq!(output.borrow().get_children().unwrap().len(), 10);
        // NOTE Enhance with adding containers to the workspaces
    }

}
<|endoftext|>


<commit_before><commit_msg>trying to encode existentials, for Adapton compute nodes<commit_after><|endoftext|>


<commit_before><commit_msg>Fixing Windows problem, who allows spaces anyway...<commit_after><|endoftext|>