<commit_before>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A standard, garbage-collected linked list.

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

pub struct Items<'a, T> {
    priv head: &'a List<T>,
    priv next: Option<&'a @List<T>>
}

impl<'a, T> Iterator<&'a T> for Items<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        match self.next {
            None => match *self.head {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            },
            Some(next) => match **next {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            }
        }
    }
}

impl<T> List<T> {
    /// Returns a forward iterator
    pub fn iter<'a>(&'a self) -> Items<'a, T> {
        Items {
            head: self,
            next: None
        }
    }
}

/**
 * Search for an element that matches a given predicate
 *
 * Apply function `f` to each element of `list`, starting from the first.
 * When function `f` returns true then an option containing the element
 * is returned. If `f` matches no elements then none is returned.
 */
pub fn find<T:Clone>(list: @List<T>, f: |&T| -> bool) -> Option<T> {
    let mut list = list;
    loop {
        list = match *list {
          Cons(ref head, tail) => {
            if f(head) { return Some((*head).clone()); }
            tail
          }
          Nil => return None
        }
    };
}

/**
 * Returns true if a list contains an element that matches a given predicate
 *
 * Apply function `f` to each element of `list`, starting from the first.
 * When function `f` returns true then it also returns true. If `f` matches no
 * elements then false is returned.
 */
pub fn any<T>(list: @List<T>, f: |&T| -> bool) -> bool {
    let mut list = list;
    loop {
        list = match *list {
            Cons(ref head, tail) => {
                if f(head) { return true; }
                tail
            }
            Nil => return false
        }
    };
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(list: @List<T>, element: T) -> bool {
    let mut found = false;
    each(list, |e| {
        if *e == element { found = true; false } else { true }
    });
    return found;
}

/// Returns true if the list is empty
pub fn is_empty<T>(list: @List<T>) -> bool {
    match *list {
        Nil => true,
        _ => false
    }
}

/// Returns the length of a list
pub fn len<T>(list: @List<T>) -> uint {
    let mut count = 0u;
    iter(list, |_e| count += 1u);
    count
}

/// Returns all but the first element of a list
pub fn tail<T>(list: @List<T>) -> @List<T> {
    match *list {
        Cons(_, tail) => return tail,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(list: @List<T>) -> T {
    match *list {
      Cons(ref head, _) => (*head).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(list: @List<T>, other: @List<T>) -> @List<T> {
    match *list {
      Nil => return other,
      Cons(ref head, tail) => {
        let rest = append(tail, other);
        return @Cons((*head).clone(), rest);
      }
    }
}

impl<T:'static + Clone> List<T> {
    /// Create a list from a vector
    pub fn from_vec(v: &[T]) -> List<T> {
        match v.len() {
            0 => Nil,
            _ => v.rev_iter().fold(Nil, |tail, value: &T| Cons(value.clone(), @tail))
        }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

/// Iterate over a list
pub fn iter<T>(list: @List<T>, f: |&T|) {
    let mut cur = list;
    loop {
        cur = match *cur {
          Cons(ref head, tail) => {
            f(head);
            tail
          }
          Nil => break
        }
    }
}

/// Iterate over a list
pub fn each<T>(list: @List<T>, f: |&T| -> bool) -> bool {
    let mut cur = list;
    loop {
        cur = match *cur {
          Cons(ref head, tail) => {
            if !f(head) { return false; }
            tail
          }
          Nil => { return true; }
        }
    }
}

#[cfg(test)]
mod tests {
    use list::{List, Nil, head, is_empty, tail};
    use list;

    use std::option;

    #[test]
    fn test_iter() {
        let list = List::from_vec([0, 1, 2]);
        let mut iter = list.iter();
        assert_eq!(&0, iter.next().unwrap());
        assert_eq!(&1, iter.next().unwrap());
        assert_eq!(&2, iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn test_is_empty() {
        let empty : @list::List<int> = @List::from_vec([]);
        let full1 = @List::from_vec([1]);
        let full2 = @List::from_vec(['r', 'u']);

        assert!(is_empty(empty));
        assert!(!is_empty(full1));
        assert!(!is_empty(full2));
    }

    #[test]
    fn test_from_vec() {
        let list = @List::from_vec([0, 1, 2]);

        assert_eq!(head(list), 0);

        let tail_l = tail(list);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : list::List<int> = List::from_vec([]);
        assert_eq!(empty, Nil::<int>);
    }

    #[test]
    fn test_fold() {
        fn add_(a: uint, b: &uint) -> uint { a + *b }
        fn subtract_(a: uint, b: &uint) -> uint { a - *b }

        let empty = Nil::<uint>;
        assert_eq!(empty.iter().fold(0u, add_), 0u);
        assert_eq!(empty.iter().fold(10u, subtract_), 10u);

        let list = List::from_vec([0u, 1u, 2u, 3u, 4u]);
        assert_eq!(list.iter().fold(0u, add_), 10u);
        assert_eq!(list.iter().fold(10u, subtract_), 0u);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let list = @List::from_vec([0, 1, 2]);
        assert_eq!(list::find(list, match_), option::Some(2));
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: &int) -> bool { return false; }
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::find(list, match_), option::None::<int>);
        assert_eq!(list::find(empty, match_), option::None::<int>);
    }

    #[test]
    fn test_any() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::any(list, match_), true);
        assert_eq!(list::any(empty, match_), false);
    }

    #[test]
    fn test_has() {
        let list = @List::from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(list, 5)));
        assert!((!list::has(list, 7)));
        assert!((list::has(list, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::len(list), 3u);
        assert_eq!(list::len(empty), 0u);
    }

    #[test]
    fn test_append() {
        assert!(@List::from_vec([1,2,3,4])
            == list::append(@List::from_vec([1,2]), @List::from_vec([3,4])));
    }
}
<commit_msg>Removed list::find() in favor of iter().find()<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A standard, garbage-collected linked list.

#[deriving(Clone, Eq)]
#[allow(missing_doc)]
pub enum List<T> {
    Cons(T, @List<T>),
    Nil,
}

pub struct Items<'a, T> {
    priv head: &'a List<T>,
    priv next: Option<&'a @List<T>>
}

impl<'a, T> Iterator<&'a T> for Items<'a, T> {
    fn next(&mut self) -> Option<&'a T> {
        match self.next {
            None => match *self.head {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            },
            Some(next) => match **next {
                Nil => None,
                Cons(ref value, ref tail) => {
                    self.next = Some(tail);
                    Some(value)
                }
            }
        }
    }
}

impl<T> List<T> {
    /// Returns a forward iterator
    pub fn iter<'a>(&'a self) -> Items<'a, T> {
        Items {
            head: self,
            next: None
        }
    }
}

/**
 * Returns true if a list contains an element that matches a given predicate
 *
 * Apply function `f` to each element of `list`, starting from the first.
 * When function `f` returns true then it also returns true. If `f` matches no
 * elements then false is returned.
 */
pub fn any<T>(list: @List<T>, f: |&T| -> bool) -> bool {
    let mut list = list;
    loop {
        list = match *list {
            Cons(ref head, tail) => {
                if f(head) { return true; }
                tail
            }
            Nil => return false
        }
    };
}

/// Returns true if a list contains an element with the given value
pub fn has<T:Eq>(list: @List<T>, element: T) -> bool {
    let mut found = false;
    each(list, |e| {
        if *e == element { found = true; false } else { true }
    });
    return found;
}

/// Returns true if the list is empty
pub fn is_empty<T>(list: @List<T>) -> bool {
    match *list {
        Nil => true,
        _ => false
    }
}

/// Returns the length of a list
pub fn len<T>(list: @List<T>) -> uint {
    let mut count = 0u;
    iter(list, |_e| count += 1u);
    count
}

/// Returns all but the first element of a list
pub fn tail<T>(list: @List<T>) -> @List<T> {
    match *list {
        Cons(_, tail) => return tail,
        Nil => fail!("list empty")
    }
}

/// Returns the first element of a list
pub fn head<T:Clone>(list: @List<T>) -> T {
    match *list {
      Cons(ref head, _) => (*head).clone(),
      // makes me sad
      _ => fail!("head invoked on empty list")
    }
}

/// Appends one list to another
pub fn append<T:Clone + 'static>(list: @List<T>, other: @List<T>) -> @List<T> {
    match *list {
      Nil => return other,
      Cons(ref head, tail) => {
        let rest = append(tail, other);
        return @Cons((*head).clone(), rest);
      }
    }
}

impl<T:'static + Clone> List<T> {
    /// Create a list from a vector
    pub fn from_vec(v: &[T]) -> List<T> {
        match v.len() {
            0 => Nil,
            _ => v.rev_iter().fold(Nil, |tail, value: &T| Cons(value.clone(), @tail))
        }
    }
}

/*
/// Push one element into the front of a list, returning a new list
/// THIS VERSION DOESN'T ACTUALLY WORK
fn push<T:Clone>(ll: &mut @list<T>, vv: T) {
    ll = &mut @cons(vv, *ll)
}
*/

/// Iterate over a list
pub fn iter<T>(list: @List<T>, f: |&T|) {
    let mut cur = list;
    loop {
        cur = match *cur {
          Cons(ref head, tail) => {
            f(head);
            tail
          }
          Nil => break
        }
    }
}

/// Iterate over a list
pub fn each<T>(list: @List<T>, f: |&T| -> bool) -> bool {
    let mut cur = list;
    loop {
        cur = match *cur {
          Cons(ref head, tail) => {
            if !f(head) { return false; }
            tail
          }
          Nil => { return true; }
        }
    }
}

#[cfg(test)]
mod tests {
    use list::{List, Nil, head, is_empty, tail};
    use list;

    #[test]
    fn test_iter() {
        let list = List::from_vec([0, 1, 2]);
        let mut iter = list.iter();
        assert_eq!(&0, iter.next().unwrap());
        assert_eq!(&1, iter.next().unwrap());
        assert_eq!(&2, iter.next().unwrap());
        assert_eq!(None, iter.next());
    }

    #[test]
    fn test_is_empty() {
        let empty : @list::List<int> = @List::from_vec([]);
        let full1 = @List::from_vec([1]);
        let full2 = @List::from_vec(['r', 'u']);

        assert!(is_empty(empty));
        assert!(!is_empty(full1));
        assert!(!is_empty(full2));
    }

    #[test]
    fn test_from_vec() {
        let list = @List::from_vec([0, 1, 2]);

        assert_eq!(head(list), 0);

        let tail_l = tail(list);
        assert_eq!(head(tail_l), 1);

        let tail_tail_l = tail(tail_l);
        assert_eq!(head(tail_tail_l), 2);
    }

    #[test]
    fn test_from_vec_empty() {
        let empty : list::List<int> = List::from_vec([]);
        assert_eq!(empty, Nil::<int>);
    }

    #[test]
    fn test_fold() {
        fn add_(a: uint, b: &uint) -> uint { a + *b }
        fn subtract_(a: uint, b: &uint) -> uint { a - *b }

        let empty = Nil::<uint>;
        assert_eq!(empty.iter().fold(0u, add_), 0u);
        assert_eq!(empty.iter().fold(10u, subtract_), 10u);

        let list = List::from_vec([0u, 1u, 2u, 3u, 4u]);
        assert_eq!(list.iter().fold(0u, add_), 10u);
        assert_eq!(list.iter().fold(10u, subtract_), 0u);
    }

    #[test]
    fn test_find_success() {
        fn match_(i: & &int) -> bool { **i == 2 }

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.iter().find(match_).unwrap(), &2);
    }

    #[test]
    fn test_find_fail() {
        fn match_(_i: & &int) -> bool { false }

        let empty = Nil::<int>;
        assert_eq!(empty.iter().find(match_), None);

        let list = List::from_vec([0, 1, 2]);
        assert_eq!(list.iter().find(match_), None);
    }

    #[test]
    fn test_any() {
        fn match_(i: &int) -> bool { return *i == 2; }
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::any(list, match_), true);
        assert_eq!(list::any(empty, match_), false);
    }

    #[test]
    fn test_has() {
        let list = @List::from_vec([5, 8, 6]);
        let empty = @list::Nil::<int>;
        assert!((list::has(list, 5)));
        assert!((!list::has(list, 7)));
        assert!((list::has(list, 8)));
        assert!((!list::has(empty, 5)));
    }

    #[test]
    fn test_len() {
        let list = @List::from_vec([0, 1, 2]);
        let empty = @list::Nil::<int>;
        assert_eq!(list::len(list), 3u);
        assert_eq!(list::len(empty), 0u);
    }

    #[test]
    fn test_append() {
        assert!(@List::from_vec([1,2,3,4])
            == list::append(@List::from_vec([1,2]), @List::from_vec([3,4])));
    }
}
<|endoftext|>


<commit_before>/*

The region check is a final pass that runs over the AST after we have
inferred the type constraints but before we have actually finalized
the types.  It's purpose is to embed some final region constraints.
The reason that this is not done earlier is that sometimes we don't
know whether a given type will be a region pointer or not until this
phase.

In particular, we ensure that, if the type of an expression or
variable is `&r.T`, then the expression or variable must occur within
the region scope `r`.

*/

import util::ppaux;
import syntax::print::pprust;

type rcx = @{fcx: @fn_ctxt, mut errors_reported: uint};
type rvt = visit::vt<rcx>;

fn regionck_expr(fcx: @fn_ctxt, e: @ast::expr) {
    let rcx = @{fcx:fcx, mut errors_reported: 0u};
    let v = regionck_visitor();
    v.visit_expr(e, rcx, v);
}

fn regionck_fn(fcx: @fn_ctxt,
               _decl: ast::fn_decl,
               blk: ast::blk) {
    let rcx = @{fcx:fcx, mut errors_reported: 0u};
    let v = regionck_visitor();
    v.visit_block(blk, rcx, v);
}

fn regionck_visitor() -> rvt {
    visit::mk_vt(@{visit_item: visit_item,
                   visit_stmt: visit_stmt,
                   visit_expr: visit_expr,
                   visit_block: visit_block,
                   visit_pat: visit_pat,
                   visit_local: visit_local
                   with *visit::default_visitor()})
}

fn visit_item(_item: @ast::item, &&_rcx: rcx, _v: rvt) {
    // Ignore items
}

fn visit_local(l: @ast::local, &&rcx: rcx, v: rvt) {
    let e = rcx.errors_reported;
    v.visit_pat(l.node.pat, rcx, v);
    if e != rcx.errors_reported {
        ret; // if decl has errors, skip initializer expr
    }

    v.visit_ty(l.node.ty, rcx, v);
    for l.node.init.each { |i|
        v.visit_expr(i.expr, rcx, v);
    }
}

fn visit_pat(p: @ast::pat, &&rcx: rcx, v: rvt) {
    let fcx = rcx.fcx;
    alt p.node {
      ast::pat_ident(path, _)
      if !pat_util::pat_is_variant(fcx.ccx.tcx.def_map, p) {
        #debug["visit_pat binding=%s", path.idents[0]];
        visit_node(p.id, p.span, rcx);
      }
      _ {}
    }

    visit::visit_pat(p, rcx, v);
}

fn visit_block(b: ast::blk, &&rcx: rcx, v: rvt) {
    visit::visit_block(b, rcx, v);
}

fn visit_expr(e: @ast::expr, &&rcx: rcx, v: rvt) {
    #debug["visit_expr(e=%s)", pprust::expr_to_str(e)];

    alt e.node {
      ast::expr_path(*) {
        // Avoid checking the use of local variables, as we already
        // check their definitions.  The def'n always encloses the
        // use.  So if the def'n is enclosed by the region, then the
        // uses will also be enclosed (and otherwise, an error will
        // have been reported at the def'n site).
        alt lookup_def(rcx.fcx, e.span, e.id) {
          ast::def_local(*) | ast::def_arg(*) | ast::def_upvar(*) { ret; }
          _ { }
        }
      }
      _ { }
    }

    if !visit_node(e.id, e.span, rcx) { ret; }
    visit::visit_expr(e, rcx, v);
}

fn visit_stmt(s: @ast::stmt, &&rcx: rcx, v: rvt) {
    visit::visit_stmt(s, rcx, v);
}

// checks the type of the node `id` and reports an error if it
// references a region that is not in scope for that node.  Returns
// false if an error is reported; this is used to cause us to cut off
// region checking for that subtree to avoid reporting tons of errors.
fn visit_node(id: ast::node_id, span: span, rcx: rcx) -> bool {
    let fcx = rcx.fcx;

    // Try to resolve the type.  If we encounter an error, then typeck
    // is going to fail anyway, so just stop here and let typeck
    // report errors later on in the writeback phase.
    let ty0 = fcx.node_ty(id);
    let ty = alt infer::resolve_deep(fcx.infcx, ty0, false) {
      result::err(_) { ret true; }
      result::ok(ty) { ty }
    };

    // find the region where this expr evaluation is taking place
    let tcx = fcx.ccx.tcx;
    let encl_region = ty::encl_region(tcx, id);

    #debug["visit_node(ty=%s, id=%d, encl_region=%s, ty0=%s)",
           ppaux::ty_to_str(tcx, ty),
           id,
           ppaux::region_to_str(tcx, encl_region),
           ppaux::ty_to_str(tcx, ty0)];

    // Otherwise, look at the type and see if it is a region pointer.
    let e = rcx.errors_reported;
    ty::walk_regions_and_ty(
        tcx, ty,
        { |r| constrain_region(rcx, encl_region, span, r); },
        { |t| ty::type_has_regions(t) });
    ret (e == rcx.errors_reported);

    fn constrain_region(rcx: rcx,
                        encl_region: ty::region,
                        span: span,
                        region: ty::region) {
        let tcx = rcx.fcx.ccx.tcx;

        #debug["constrain_region(encl_region=%s, region=%s)",
               ppaux::region_to_str(tcx, encl_region),
               ppaux::region_to_str(tcx, region)];

        alt region {
          ty::re_bound(_) {
            // a bound region is one which appears inside an fn type.
            // (e.g., the `&` in `fn(&T)`).  Such regions need not be
            // constrained by `encl_region` as they are placeholders
            // for regions that are as-yet-unknown.
            ret;
          }
          _ {}
        }

        alt rcx.fcx.mk_subr(encl_region, region) {
          result::err(_) {
            tcx.sess.span_err(
                span,
                #fmt["reference is not valid outside \
                      of its lifetime, %s",
                     ppaux::region_to_str(tcx, region)]);
            rcx.errors_reported += 1u;
          }
          result::ok(()) {
          }
        }
    }
}
<commit_msg>Comment only: fix typo<commit_after>/*

The region check is a final pass that runs over the AST after we have
inferred the type constraints but before we have actually finalized
the types.  Its purpose is to embed some final region constraints.
The reason that this is not done earlier is that sometimes we don't
know whether a given type will be a region pointer or not until this
phase.

In particular, we ensure that, if the type of an expression or
variable is `&r.T`, then the expression or variable must occur within
the region scope `r`.

*/

import util::ppaux;
import syntax::print::pprust;

type rcx = @{fcx: @fn_ctxt, mut errors_reported: uint};
type rvt = visit::vt<rcx>;

fn regionck_expr(fcx: @fn_ctxt, e: @ast::expr) {
    let rcx = @{fcx:fcx, mut errors_reported: 0u};
    let v = regionck_visitor();
    v.visit_expr(e, rcx, v);
}

fn regionck_fn(fcx: @fn_ctxt,
               _decl: ast::fn_decl,
               blk: ast::blk) {
    let rcx = @{fcx:fcx, mut errors_reported: 0u};
    let v = regionck_visitor();
    v.visit_block(blk, rcx, v);
}

fn regionck_visitor() -> rvt {
    visit::mk_vt(@{visit_item: visit_item,
                   visit_stmt: visit_stmt,
                   visit_expr: visit_expr,
                   visit_block: visit_block,
                   visit_pat: visit_pat,
                   visit_local: visit_local
                   with *visit::default_visitor()})
}

fn visit_item(_item: @ast::item, &&_rcx: rcx, _v: rvt) {
    // Ignore items
}

fn visit_local(l: @ast::local, &&rcx: rcx, v: rvt) {
    let e = rcx.errors_reported;
    v.visit_pat(l.node.pat, rcx, v);
    if e != rcx.errors_reported {
        ret; // if decl has errors, skip initializer expr
    }

    v.visit_ty(l.node.ty, rcx, v);
    for l.node.init.each { |i|
        v.visit_expr(i.expr, rcx, v);
    }
}

fn visit_pat(p: @ast::pat, &&rcx: rcx, v: rvt) {
    let fcx = rcx.fcx;
    alt p.node {
      ast::pat_ident(path, _)
      if !pat_util::pat_is_variant(fcx.ccx.tcx.def_map, p) {
        #debug["visit_pat binding=%s", path.idents[0]];
        visit_node(p.id, p.span, rcx);
      }
      _ {}
    }

    visit::visit_pat(p, rcx, v);
}

fn visit_block(b: ast::blk, &&rcx: rcx, v: rvt) {
    visit::visit_block(b, rcx, v);
}

fn visit_expr(e: @ast::expr, &&rcx: rcx, v: rvt) {
    #debug["visit_expr(e=%s)", pprust::expr_to_str(e)];

    alt e.node {
      ast::expr_path(*) {
        // Avoid checking the use of local variables, as we already
        // check their definitions.  The def'n always encloses the
        // use.  So if the def'n is enclosed by the region, then the
        // uses will also be enclosed (and otherwise, an error will
        // have been reported at the def'n site).
        alt lookup_def(rcx.fcx, e.span, e.id) {
          ast::def_local(*) | ast::def_arg(*) | ast::def_upvar(*) { ret; }
          _ { }
        }
      }
      _ { }
    }

    if !visit_node(e.id, e.span, rcx) { ret; }
    visit::visit_expr(e, rcx, v);
}

fn visit_stmt(s: @ast::stmt, &&rcx: rcx, v: rvt) {
    visit::visit_stmt(s, rcx, v);
}

// checks the type of the node `id` and reports an error if it
// references a region that is not in scope for that node.  Returns
// false if an error is reported; this is used to cause us to cut off
// region checking for that subtree to avoid reporting tons of errors.
fn visit_node(id: ast::node_id, span: span, rcx: rcx) -> bool {
    let fcx = rcx.fcx;

    // Try to resolve the type.  If we encounter an error, then typeck
    // is going to fail anyway, so just stop here and let typeck
    // report errors later on in the writeback phase.
    let ty0 = fcx.node_ty(id);
    let ty = alt infer::resolve_deep(fcx.infcx, ty0, false) {
      result::err(_) { ret true; }
      result::ok(ty) { ty }
    };

    // find the region where this expr evaluation is taking place
    let tcx = fcx.ccx.tcx;
    let encl_region = ty::encl_region(tcx, id);

    #debug["visit_node(ty=%s, id=%d, encl_region=%s, ty0=%s)",
           ppaux::ty_to_str(tcx, ty),
           id,
           ppaux::region_to_str(tcx, encl_region),
           ppaux::ty_to_str(tcx, ty0)];

    // Otherwise, look at the type and see if it is a region pointer.
    let e = rcx.errors_reported;
    ty::walk_regions_and_ty(
        tcx, ty,
        { |r| constrain_region(rcx, encl_region, span, r); },
        { |t| ty::type_has_regions(t) });
    ret (e == rcx.errors_reported);

    fn constrain_region(rcx: rcx,
                        encl_region: ty::region,
                        span: span,
                        region: ty::region) {
        let tcx = rcx.fcx.ccx.tcx;

        #debug["constrain_region(encl_region=%s, region=%s)",
               ppaux::region_to_str(tcx, encl_region),
               ppaux::region_to_str(tcx, region)];

        alt region {
          ty::re_bound(_) {
            // a bound region is one which appears inside an fn type.
            // (e.g., the `&` in `fn(&T)`).  Such regions need not be
            // constrained by `encl_region` as they are placeholders
            // for regions that are as-yet-unknown.
            ret;
          }
          _ {}
        }

        alt rcx.fcx.mk_subr(encl_region, region) {
          result::err(_) {
            tcx.sess.span_err(
                span,
                #fmt["reference is not valid outside \
                      of its lifetime, %s",
                     ppaux::region_to_str(tcx, region)]);
            rcx.errors_reported += 1u;
          }
          result::ok(()) {
          }
        }
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::option::Option;
use std::os::unix::process::CommandExt;
use std::process::Command;

const SYSTEMD_RUN: &'static str = "/usr/bin/systemd-run";
const FIREJAIL: &'static str = "/usr/bin/firejail";

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_PROFILE: &'static str = "/etc/firejail/firefox.profile";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const FIREFOX_MEMORY_HIGH: i32 = 4420;
const FIREFOX_MEMORY_MAX: i32 = 5200;

const KEIRA: &'static str = "/home/kalvin/Downloads/.firefox-nightly/firefox";
const KEIRA_PROFILE: &'static str = "/etc/firejail/firefox-nightly.profile";

const MPV: &'static str = "/usr/bin/mpv";
const MPV_PROFILE: &'static str = "/etc/firejail/mpv.profile";

const TERM: &'static str = "/usr/bin/alacritty";
const TERM_PROFILE: &'static str = "/etc/firejail/x-terminal-emulator.profile";

const THUNDERBIRD: &'static str = "/home/kalvin/Downloads/.thunderbird-beta/thunderbird";
const THUNDERBIRD_PROFILE: &'static str = "/etc/firejail/thunderbird-beta.profile";

const QUODLIBET_FIFO: &'static str = "/home/kalvin/.config/quodlibet/control";

// Partial ordering on enums are ordered by their declaration order:
// https://users.rust-lang.org/t/how-to-sort-enum-variants/52291/2
#[derive(PartialOrd, Ord, PartialEq, Eq)]
enum BuilderWatermark {
    Unset,
    MemoryHigh,
    MemoryMax,
    FirejailProfile,
    BinPath,
    ImplicitExtraArgs,
    RemainingArgs,
}

struct CgroupedFirejailedCommand {
    pub command: std::process::Command,
    watermark: BuilderWatermark,
}

impl CgroupedFirejailedCommand {
    pub fn new() -> Self {
        let mut result = Self {
            command: std::process::Command::new(SYSTEMD_RUN),
            watermark: BuilderWatermark::Unset,
        };
        result
            .command
            .args(&["--user", "--scope", "-p", "MemorySwapMax=0"]);
        result
    }

    pub fn memory_high(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryHigh);
        self.watermark = BuilderWatermark::MemoryHigh;
        self.command.arg("-p");
        self.command.arg(format!("MemoryHigh={}M", param));
        self
    }

    pub fn memory_max(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryMax);
        self.watermark = BuilderWatermark::MemoryMax;
        self.command.arg("-p");
        self.command.arg(format!("MemoryMax={}M", param));
        self
    }

    pub fn firejail_profile(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::FirejailProfile);
        self.watermark = BuilderWatermark::FirejailProfile;
        self.command.args(&[FIREJAIL, "--ignore=seccomp"]);
        self.command.arg(format!("--profile={}", path));
        self
    }

    pub fn bin_path(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::BinPath);
        self.watermark = BuilderWatermark::BinPath;
        self.command.arg(path);
        self
    }

    pub fn implicit_extra_args(mut self, args: &[&str]) -> Self {
        assert!(self.watermark < BuilderWatermark::ImplicitExtraArgs);
        self.watermark = BuilderWatermark::ImplicitExtraArgs;
        self.command.args(args);
        self
    }

    pub fn remaining_args(mut self, args: Vec<String>) -> Self {
        assert!(self.watermark < BuilderWatermark::RemainingArgs);
        self.watermark = BuilderWatermark::RemainingArgs;
        self.command.args(args);
        self
    }
}

fn simple_firejail_command(target: &str, args: Vec<String>) -> Command {
    let mut command = Command::new(FIREJAIL);

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));
    command.args(args);

    command
}

fn quodlibet_command(args: Vec<String>) {
    let mut file = std::fs::OpenOptions::new()
        .append(true)
        .open(QUODLIBET_FIFO)
        .unwrap();
    file.write_all(match args[0].as_str() {
        "pp" => "play-pause".as_bytes(),
        "sa" => "stop-after 1".as_bytes(),
        _ => panic!(
            "bad argument for quodlibet command: ``{}''",
            args[0].as_str()
        ),
    })
    .unwrap();
}

fn init_command() -> Option<Command> {
    let mut args_less_the_first = std::env::args();
    // Pops the name of this executable.
    args_less_the_first.next();

    // Pops the name of the unner target.
    let target = args_less_the_first.next().unwrap();

    // Copies and collects the remaining argv.
    let args: Vec<String> = args_less_the_first.collect();

    match target.as_str() {
        "ef" => {
            // edgy Firefox; Firejail disabled
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "ff" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(FIREFOX_PROFILE)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "keira" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(KEIRA_PROFILE)
                    .bin_path(KEIRA)
                    .implicit_extra_args(&["-P", "nightly"])
                    .remaining_args(args)
                    .command,
            );
        }
        "npv" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(MPV_PROFILE)
                    .bin_path(MPV)
                    .remaining_args(args)
                    .command,
            );
        }
        "q" => {
            quodlibet_command(args);
            return None;
        }
        "read" => {
            let formatted_args: Vec<String> = vec![format!("about:reader?url={}", args[0])];
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile(FIREFOX_PROFILE)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(formatted_args)
                    .command,
            );
        }
        "t" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(TERM_PROFILE)
                    .bin_path(TERM)
                    .remaining_args(args)
                    .command,
            );
        }
        "tbb" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile(THUNDERBIRD_PROFILE)
                    .bin_path(THUNDERBIRD)
                    .remaining_args(args)
                    .command,
            );
        }
        "vlk" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile("/etc/firejail/vlc.profile")
                    .bin_path("/usr/bin/vlc")
                    .implicit_extra_args(&["--play-and-exit"])
                    .remaining_args(args)
                    .command,
            );
        }
        "e" => return Some(simple_firejail_command("evince", args)),
        _ => panic!("no handler for ``{}''", target),
    }
}

fn main() {
    if let Some(mut command) = init_command() {
        println!("{:#?}", command);
        command.exec();
    }
}
<commit_msg>unner: Reduce defined string constants<commit_after>use std::io::Write;
use std::option::Option;
use std::os::unix::process::CommandExt;
use std::process::Command;

const FIREFOX: &'static str = "/usr/bin/firefox";
const FIREFOX_MOZILLA_SFW_PROFILE: &'static str = "default-1473025815439";

const FIREFOX_MEMORY_HIGH: i32 = 6500;
const FIREFOX_MEMORY_MAX: i32 = 7800;

// Partial ordering on enums are ordered by their declaration order:
// https://users.rust-lang.org/t/how-to-sort-enum-variants/52291/2
#[derive(PartialOrd, Ord, PartialEq, Eq)]
enum BuilderWatermark {
    Unset,
    MemoryHigh,
    MemoryMax,
    FirejailProfile,
    BinPath,
    ImplicitExtraArgs,
    RemainingArgs,
}

struct CgroupedFirejailedCommand {
    pub command: std::process::Command,
    watermark: BuilderWatermark,
}

impl CgroupedFirejailedCommand {
    pub fn new() -> Self {
        let mut result = Self {
            command: std::process::Command::new("/usr/bin/systemd-run"),
            watermark: BuilderWatermark::Unset,
        };
        result
            .command
            .args(&["--user", "--scope", "-p", "MemorySwapMax=0"]);
        result
    }

    pub fn memory_high(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryHigh);
        self.watermark = BuilderWatermark::MemoryHigh;
        self.command.arg("-p");
        self.command.arg(format!("MemoryHigh={}M", param));
        self
    }

    pub fn memory_max(mut self, param: i32) -> Self {
        assert!(self.watermark < BuilderWatermark::MemoryMax);
        self.watermark = BuilderWatermark::MemoryMax;
        self.command.arg("-p");
        self.command.arg(format!("MemoryMax={}M", param));
        self
    }

    pub fn firejail_profile(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::FirejailProfile);
        self.watermark = BuilderWatermark::FirejailProfile;
        self.command
            .args(&["/usr/bin/firejail", "--ignore=seccomp"]);
        self.command
            .arg(format!("--profile=/etc/firejail/{}.profile", path));
        self
    }

    pub fn bin_path(mut self, path: &str) -> Self {
        assert!(self.watermark < BuilderWatermark::BinPath);
        self.watermark = BuilderWatermark::BinPath;
        self.command.arg(path);
        self
    }

    pub fn implicit_extra_args(mut self, args: &[&str]) -> Self {
        assert!(self.watermark < BuilderWatermark::ImplicitExtraArgs);
        self.watermark = BuilderWatermark::ImplicitExtraArgs;
        self.command.args(args);
        self
    }

    pub fn remaining_args(mut self, args: Vec<String>) -> Self {
        assert!(self.watermark < BuilderWatermark::RemainingArgs);
        self.watermark = BuilderWatermark::RemainingArgs;
        self.command.args(args);
        self
    }
}

fn simple_firejail_command(target: &str, args: Vec<String>) -> Command {
    let mut command = Command::new("/usr/bin/firejail");

    command.arg(format!("--profile=/etc/firejail/{}.profile", target));
    command.arg(format!("/usr/bin/{}", target));
    command.args(args);

    command
}

fn quodlibet_command(args: Vec<String>) {
    let mut file = std::fs::OpenOptions::new()
        .append(true)
        .open("/home/kalvin/.config/quodlibet/control")
        .unwrap();
    file.write_all(match args[0].as_str() {
        "pp" => "play-pause".as_bytes(),
        "sa" => "stop-after 1".as_bytes(),
        _ => panic!(
            "bad argument for quodlibet command: ``{}''",
            args[0].as_str()
        ),
    })
    .unwrap();
}

fn init_command() -> Option<Command> {
    let mut args_less_the_first = std::env::args();
    // Pops the name of this executable.
    args_less_the_first.next();

    // Pops the name of the unner target.
    let target = args_less_the_first.next().unwrap();

    // Copies and collects the remaining argv.
    let args: Vec<String> = args_less_the_first.collect();

    match target.as_str() {
        "ef" => {
            // edgy Firefox; Firejail disabled
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "ff" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile("firefox")
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(args)
                    .command,
            );
        }
        "keira" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile("firefox-nightly")
                    .bin_path("/home/kalvin/Downloads/.firefox-nightly/firefox")
                    .implicit_extra_args(&["-P", "nightly"])
                    .remaining_args(args)
                    .command,
            );
        }
        "npv" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile("mpv")
                    .bin_path("/usr/bin/mpv")
                    .remaining_args(args)
                    .command,
            );
        }
        "q" => {
            quodlibet_command(args);
            return None;
        }
        "read" => {
            let formatted_args: Vec<String> = vec![format!("about:reader?url={}", args[0])];
            return Some(
                CgroupedFirejailedCommand::new()
                    .memory_high(FIREFOX_MEMORY_HIGH)
                    .memory_max(FIREFOX_MEMORY_MAX)
                    .firejail_profile("firefox")
                    .bin_path(FIREFOX)
                    .implicit_extra_args(&["-P", FIREFOX_MOZILLA_SFW_PROFILE])
                    .remaining_args(formatted_args)
                    .command,
            );
        }
        "t" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile("x-terminal-emulator")
                    .bin_path("/usr/bin/alacritty")
                    .remaining_args(args)
                    .command,
            );
        }
        "tbb" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile("thunderbird-beta")
                    .bin_path("/home/kalvin/Downloads/.thunderbird-beta/thunderbird")
                    .remaining_args(args)
                    .command,
            );
        }
        "vlk" => {
            return Some(
                CgroupedFirejailedCommand::new()
                    .firejail_profile("vlc")
                    .bin_path("/usr/bin/vlc")
                    .implicit_extra_args(&["--play-and-exit"])
                    .remaining_args(args)
                    .command,
            );
        }
        "e" => return Some(simple_firejail_command("evince", args)),
        _ => panic!("no handler for ``{}''", target),
    }
}

fn main() {
    if let Some(mut command) = init_command() {
        println!("{:#?}", command);
        command.exec();
    }
}
<|endoftext|>


<commit_before>mod test_event;
mod test_socket;
mod test_sockopt;
mod test_termios;
mod test_ioctl;
mod test_wait;
mod test_select;
mod test_uio;
<commit_msg>Disable sys/event tests on Linux<commit_after>#[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd",
    target_os = "dragonfly", target_os = "openbsd", target_os = "netbsd"))]
mod test_event;
mod test_socket;
mod test_sockopt;
mod test_termios;
mod test_ioctl;
mod test_wait;
mod test_select;
mod test_uio;
<|endoftext|>


<commit_before>extern crate xml;
extern crate clap;

mod polyfill;
mod emitter;

use emitter::Emitter;

use std::fs::File;
use std::io::BufReader;

use xml::reader::{EventReader, XmlEvent};
use clap::{Arg, App};

fn matching_element_id<'a>(ids: &str, attr: &'a Vec<xml::attribute::OwnedAttribute>) -> Option<&'a str> {
    let id_attr = match attr.iter().find(|ref a| a.name.local_name == "id") {
        Some(a) => a,
        None => return None
    };

    if ids.is_empty() || ids.split(',').any(|i| id_attr.value == i) {
        Some(&id_attr.value)
    }
    else { None }
}

fn main() {
    let app: App = App::new("grayfx")
        .version("0.0")
        .author("Nigel Baillie <metreckk@gmail.com>")
        .about("Converts Inkscape SVGs into C++ rendering and/or physics code for Gray")
        .arg(Arg::with_name("input")
            .help("the svg file to parse")
            .short("f")
            .takes_value(true)
            .index(1)
            .required(true))
        .arg(Arg::with_name("ids")
            .short("i")
            .help("comma-separated ids of the elements to process")
            .takes_value(true)
            .required(false))
        .arg(Arg::with_name("color")
            .short("c")
            .help("expression to use for color")
            .takes_value(true)
            .required(false))
         .arg(Arg::with_name("drawvar")
             .short("d")
             .help("generate rendering code with this variable name")
             .takes_value(true)
             .required(false))
         .arg(Arg::with_name("physicsvar")
             .short("p")
             .help("generate physics setup code with this variable name")
             .takes_value(true)
             .required(false));
    let matches = app.get_matches();

    let filename = matches.value_of("input").unwrap();
    let file = File::open(filename).unwrap();
    let file = BufReader::new(file);

    let ids = matches.value_of("ids").unwrap_or("");
    let color = matches.value_of("color");

    let ids_count = if ids.is_empty() {
        0
    } else {
        ids.chars().fold(1, |n, c| if c == ',' { n + 1 } else { n })
    };

    // === Parse XML ===
    let mut emitter = Emitter::new();
    let parser = EventReader::new(file);
    'parse_xml: for xmlevent in parser {
        match xmlevent {
            // elements:
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                if let Some(id) = matching_element_id(ids, &attributes) {
                    emitter.add_shape(id, &name.local_name, &attributes);

                    // Duck out early if possible
                    if ids_count > 0 && emitter.len() >= ids_count {
                        break 'parse_xml;
                    }
                }
            }
            /*
            Ok(XmlEvent::EndElement { name }) => {
                println!("END {}", name);
            }
            */
            Err(e) => {
                println!("// Error: {}", e);
                break;
            }
            _ => {}
        }
    }

    // === Now process elements that matched, in specified order ===
    let draw_var = matches.value_of("drawvar");
    let phys_var = matches.value_of("physicsvar");

    if ids_count > 0 {
        let each_id = ids.split(',');
        for id in each_id {

            let id_str = id.to_owned();
            if !emitter.emit(&id_str, draw_var, phys_var, color) {
                panic!("ID \"{}\" not found in {}", id_str, filename);
            }
        }
    }
    else {
        emitter.emit_all(draw_var, phys_var, color);
    }
}
<commit_msg>reorder takes_value and index<commit_after>extern crate xml;
extern crate clap;

mod polyfill;
mod emitter;

use emitter::Emitter;

use std::fs::File;
use std::io::BufReader;

use xml::reader::{EventReader, XmlEvent};
use clap::{Arg, App};

fn matching_element_id<'a>(ids: &str, attr: &'a Vec<xml::attribute::OwnedAttribute>) -> Option<&'a str> {
    let id_attr = match attr.iter().find(|ref a| a.name.local_name == "id") {
        Some(a) => a,
        None => return None
    };

    if ids.is_empty() || ids.split(',').any(|i| id_attr.value == i) {
        Some(&id_attr.value)
    }
    else { None }
}

fn main() {
    let app: App = App::new("grayfx")
        .version("0.0")
        .author("Nigel Baillie <metreckk@gmail.com>")
        .about("Converts Inkscape SVGs into C++ rendering and/or physics code for Gray")
        .arg(Arg::with_name("input")
            .help("the svg file to parse")
            .short("f")
            .index(1)
            .takes_value(true)
            .required(true))
        .arg(Arg::with_name("ids")
            .short("i")
            .help("comma-separated ids of the elements to process")
            .takes_value(true)
            .required(false))
        .arg(Arg::with_name("color")
            .short("c")
            .help("expression to use for color")
            .takes_value(true)
            .required(false))
         .arg(Arg::with_name("drawvar")
             .short("d")
             .help("generate rendering code with this variable name")
             .takes_value(true)
             .required(false))
         .arg(Arg::with_name("physicsvar")
             .short("p")
             .help("generate physics setup code with this variable name")
             .takes_value(true)
             .required(false));
    let matches = app.get_matches();

    let filename = matches.value_of("input").unwrap();
    let file = File::open(filename).unwrap();
    let file = BufReader::new(file);

    let ids = matches.value_of("ids").unwrap_or("");
    let color = matches.value_of("color");

    let ids_count = if ids.is_empty() {
        0
    } else {
        ids.chars().fold(1, |n, c| if c == ',' { n + 1 } else { n })
    };

    // === Parse XML ===
    let mut emitter = Emitter::new();
    let parser = EventReader::new(file);
    'parse_xml: for xmlevent in parser {
        match xmlevent {
            // elements:
            Ok(XmlEvent::StartElement { name, attributes, .. }) => {
                if let Some(id) = matching_element_id(ids, &attributes) {
                    emitter.add_shape(id, &name.local_name, &attributes);

                    // Duck out early if possible
                    if ids_count > 0 && emitter.len() >= ids_count {
                        break 'parse_xml;
                    }
                }
            }
            /*
            Ok(XmlEvent::EndElement { name }) => {
                println!("END {}", name);
            }
            */
            Err(e) => {
                println!("// Error: {}", e);
                break;
            }
            _ => {}
        }
    }

    // === Now process elements that matched, in specified order ===
    let draw_var = matches.value_of("drawvar");
    let phys_var = matches.value_of("physicsvar");

    if ids_count > 0 {
        let each_id = ids.split(',');
        for id in each_id {

            let id_str = id.to_owned();
            if !emitter.emit(&id_str, draw_var, phys_var, color) {
                panic!("ID \"{}\" not found in {}", id_str, filename);
            }
        }
    }
    else {
        emitter.emit_all(draw_var, phys_var, color);
    }
}
<|endoftext|>


<commit_before>use super::*;

enum PlStage {
    IC,
    RF,
    EX,
    DC,
    WB
}

#[derive(Copy, Clone)]
pub struct Ic {
    pub op: Inst
}

#[derive(Copy, Clone)]
pub struct Rf {
    /* RF stage */
    pub rt: u64,
    pub rs: u64
}

#[derive(Copy, Clone)]
pub struct Ex {
    /* EX stage */
    pub ol: u64,
    pub br: bool,
    pub wlr: bool
}

#[derive(Copy, Clone)]
pub struct Dc {
    pub dc: u64
}

#[derive(Copy, Clone)]
pub struct Wb {

}

#[derive(Copy, Clone)]
pub struct Pls {
    pub ic : Ic,
    pub rf: Rf,
    pub ex: Ex,
    pub dc: Dc,
    pub wb: Wb
}

impl Pls {
    pub fn new() -> Pls {
        Pls {
            /* IC stage */
            ic: Ic {
                op: Inst(0)
            },

            /* RF stage */
            rf: Rf {
                rt: 0,
                rs: 0
            },

            /* EX stage */
            ex: Ex {
                ol: 0,
                br: false,
                wlr: false
            },

            /* DC stage */
            dc: Dc {
                dc: 0
            },

            /* WB stage */
            wb: Wb {

            }
        }
    }
}

pub struct Pl {
    /* pipeline stage */
    st: [Pls; 5]
}

impl Pl {
    pub fn new() -> Pl {
        Pl {
            st: [Pls::new(); 5]
        }
    }
}

/* IC - Instruction Cache Fetch */
pub fn ic(i: usize, cpu: &mut VR4300, mc: &MC) {

    let val = mc.read(cpu.pc as u32);
    cpu.pl.st[i].ic.op = Inst(val);
    println!("IC - {:#x}: ({:#x}) {}", cpu.pc, val, cpu.pl.st[i].ic.op);
}

/* RF - Register Fetch */
pub fn rf(i: usize, cpu: &mut VR4300) {

    cpu.pc += 4;

    match cpu.pl.st[i].ic.op.class() {
        OpC::C => {
            cpu.pl.st[i].rf.rs = cpu.cp0.rgpr(cpu.pl.st[i].ic.op._rd()) as u64
        }, _ => {
            cpu.pl.st[i].rf.rs = cpu.rgpr(cpu.pl.st[i].ic.op._rs());
        }
    }

    cpu.pl.st[i].rf.rt = cpu.rgpr(cpu.pl.st[i].ic.op._rt());

    println!("RF - {}", cpu.pl.st[i].ic.op);
}

/* EX - Execution */
pub fn ex(i: usize, cpu: &mut VR4300) {

    match cpu.pl.st[i].ic.op.op() {
        Op::Syscall => {
            if cpu.pl.st[i].ic.op.sa() > 0 {
                let result = if cpu.pl.st[i].ic.op._rt() == 16 { "Pass" }  else { "Fail" };
                println!("Test Result - ISA:{:X}  Set:{:X}  Test:{:X}  Result:{:?}", cpu.pl.st[i].ic.op._rs(), cpu.pl.st[i].ic.op._rd(), cpu.pl.st[i].ic.op.sa(), result);
            }
        }, _ => {
            match cpu.pl.st[i].ic.op.class() {
                OpC::L => {

                }, OpC::C => {

                }, OpC::B => {
                    cpu.pl.st[i].ic.op.ex()(&mut cpu.pl.st[i]);

                    if cpu.pl.st[i].ex.br {
                        let offset = ((cpu.pl.st[i].ic.op.offset() as i16 as i32) << 2) as i64;
                        cpu.pl.st[i].ex.ol = (cpu.pc as i64 + offset) as u64;
                    }

                }, _ => {
                    cpu.pl.st[i].ic.op.ex()(&mut cpu.pl.st[i]);
                }
            }
        }
    }

    println!("EX - {}", cpu.pl.st[i].ic.op);
}

/* DC - Data Cache Fetch */
pub fn dc(i: usize, cpu: &mut VR4300, mc: &MC) {

    match cpu.pl.st[i].ic.op.class() {
        OpC::L => {
            let base = cpu.pl.st[i].rf.rs as i64;
            let offset = cpu.pl.st[i].ic.op.offset() as i16 as i64;
            cpu.pl.st[i].dc.dc = mc.read((base + offset) as u32) as u64;
            /* need to call the ex function as a hack to get ol populated */
            cpu.pl.st[i].ic.op.ex()(&mut cpu.pl.st[i]);
        }, _ => {

        }
    }

    println!("DC - {}", cpu.pl.st[i].ic.op);
}

/* WB - Write Back */
pub fn wb(i: usize, cpu: &mut VR4300, mc: &mut MC) {

    match cpu.pl.st[i].ic.op.class() {
        OpC::S => {
            let base = cpu.pl.st[i].rf.rs as i64;
            let offset = cpu.pl.st[i].ic.op.offset() as i16 as i64;
            mc.write((base + offset) as u64 as u32, cpu.pl.st[i].ex.ol as u32);
        }, OpC::C => {
            /* write back to rt on the coprocessor */
            cpu.cp0.wgpr(cpu.pl.st[i].ex.ol as u32, cpu.pl.st[i].ic.op._rt());
        }, OpC::B => {
            cpu.pc = cpu.pl.st[i].ex.ol;
        }, OpC::J => {
            // nop
        }, OpC::L | OpC::I => {
            /* write back to rt */
            cpu.wgpr(cpu.pl.st[i].ex.ol, cpu.pl.st[i].ic.op._rt());
        }, OpC::R => {
            /* write back to rd */
            cpu.wgpr(cpu.pl.st[i].ex.ol, cpu.pl.st[i].ic.op._rd());
        }
    }

    println!("WB - {}", cpu.pl.st[i].ic.op);
}

pub fn clock(cpu: &mut VR4300, mc: &mut MC) {
    ic(0, cpu, mc);
    rf(1, cpu);
    ex(2, cpu);
    dc(3, cpu, mc);
    wb(4, cpu, mc);

    cpu.pl.st[4] = cpu.pl.st[3];
    cpu.pl.st[3] = cpu.pl.st[2];
    cpu.pl.st[2] = cpu.pl.st[1];
    cpu.pl.st[1] = cpu.pl.st[0];
    cpu.pl.st[0] = Pls::new();
}
<commit_msg>add PlStage<commit_after>use super::*;

#[derive(Copy, Clone)]
pub enum PlStage {
    IC = 0,
    RF = 1,
    EX = 2,
    DC = 3,
    WB = 4
}

#[derive(Copy, Clone)]
pub struct Ic {
    pub op: Inst
}

#[derive(Copy, Clone)]
pub struct Rf {
    /* RF stage */
    pub rt: u64,
    pub rs: u64
}

#[derive(Copy, Clone)]
pub struct Ex {
    /* EX stage */
    pub ol: u64,
    pub br: bool,
    pub wlr: bool
}

#[derive(Copy, Clone)]
pub struct Dc {
    pub dc: u64
}

#[derive(Copy, Clone)]
pub struct Wb {

}

#[derive(Copy, Clone)]
pub struct Pls {
    pub ic : Ic,
    pub rf: Rf,
    pub ex: Ex,
    pub dc: Dc,
    pub wb: Wb
}

impl Pls {
    pub fn new() -> Pls {
        Pls {
            /* IC stage */
            ic: Ic {
                op: Inst(0)
            },

            /* RF stage */
            rf: Rf {
                rt: 0,
                rs: 0
            },

            /* EX stage */
            ex: Ex {
                ol: 0,
                br: false,
                wlr: false
            },

            /* DC stage */
            dc: Dc {
                dc: 0
            },

            /* WB stage */
            wb: Wb {

            }
        }
    }
}

pub struct Pl {
    /* pipeline stage */
    st: [Pls; 5]
}

impl Pl {
    pub fn new() -> Pl {
        Pl {
            st: [Pls::new(); 5]
        }
    }
}

/* IC - Instruction Cache Fetch */
pub fn ic(i: PlStage, cpu: &mut VR4300, mc: &MC) {

    let val = mc.read(cpu.pc as u32);
    cpu.pl.st[i as usize].ic.op = Inst(val);
    println!("IC - {:#x}: ({:#x}) {}", cpu.pc, val, cpu.pl.st[i as usize].ic.op);
}

/* RF - Register Fetch */
pub fn rf(i: PlStage, cpu: &mut VR4300) {

    cpu.pc += 4;

    match cpu.pl.st[i as usize].ic.op.class() {
        OpC::C => {
            cpu.pl.st[i as usize].rf.rs = cpu.cp0.rgpr(cpu.pl.st[i as usize].ic.op._rd()) as u64
        }, _ => {
            cpu.pl.st[i as usize].rf.rs = cpu.rgpr(cpu.pl.st[i as usize].ic.op._rs());
        }
    }

    cpu.pl.st[i as usize].rf.rt = cpu.rgpr(cpu.pl.st[i as usize].ic.op._rt());

    println!("RF - {}", cpu.pl.st[i as usize].ic.op);
}

/* EX - Execution */
pub fn ex(i: PlStage, cpu: &mut VR4300) {

    match cpu.pl.st[i as usize].ic.op.op() {
        Op::Syscall => {
            if cpu.pl.st[i as usize].ic.op.sa() > 0 {
                let result = if cpu.pl.st[i as usize].ic.op._rt() == 16 { "Pass" }  else { "Fail" };
                println!("Test Result - ISA:{:X}  Set:{:X}  Test:{:X}  Result:{:?}", cpu.pl.st[i as usize].ic.op._rs(), cpu.pl.st[i as usize].ic.op._rd(), cpu.pl.st[i as usize].ic.op.sa(), result);
            }
        }, _ => {
            match cpu.pl.st[i as usize].ic.op.class() {
                OpC::L => {

                }, OpC::C => {

                }, OpC::B => {
                    cpu.pl.st[i as usize].ic.op.ex()(&mut cpu.pl.st[i as usize]);

                    if cpu.pl.st[i as usize].ex.br {
                        let offset = ((cpu.pl.st[i as usize].ic.op.offset() as i16 as i32) << 2) as i64;
                        cpu.pl.st[i as usize].ex.ol = (cpu.pc as i64 + offset) as u64;
                    }

                }, _ => {
                    cpu.pl.st[i as usize].ic.op.ex()(&mut cpu.pl.st[i as usize]);
                }
            }
        }
    }

    println!("EX - {}", cpu.pl.st[i as usize].ic.op);
}

/* DC - Data Cache Fetch */
pub fn dc(i: PlStage, cpu: &mut VR4300, mc: &MC) {

    match cpu.pl.st[i as usize].ic.op.class() {
        OpC::L => {
            let base = cpu.pl.st[i as usize].rf.rs as i64;
            let offset = cpu.pl.st[i as usize].ic.op.offset() as i16 as i64;
            cpu.pl.st[i as usize].dc.dc = mc.read((base + offset) as u32) as u64;
            /* need to call the ex function as a hack to get ol populated */
            cpu.pl.st[i as usize].ic.op.ex()(&mut cpu.pl.st[i as usize]);
        }, _ => {

        }
    }

    println!("DC - {}", cpu.pl.st[i as usize].ic.op);
}

/* WB - Write Back */
pub fn wb(i: PlStage, cpu: &mut VR4300, mc: &mut MC) {

    match cpu.pl.st[i as usize].ic.op.class() {
        OpC::S => {
            let base = cpu.pl.st[i as usize].rf.rs as i64;
            let offset = cpu.pl.st[i as usize].ic.op.offset() as i16 as i64;
            mc.write((base + offset) as u64 as u32, cpu.pl.st[i as usize].ex.ol as u32);
        }, OpC::C => {
            /* write back to rt on the coprocessor */
            cpu.cp0.wgpr(cpu.pl.st[i as usize].ex.ol as u32, cpu.pl.st[i as usize].ic.op._rt());
        }, OpC::B => {
            cpu.pc = cpu.pl.st[i as usize].ex.ol;
        }, OpC::J => {
            // nop
        }, OpC::L | OpC::I => {
            /* write back to rt */
            cpu.wgpr(cpu.pl.st[i as usize].ex.ol, cpu.pl.st[i as usize].ic.op._rt());
        }, OpC::R => {
            /* write back to rd */
            cpu.wgpr(cpu.pl.st[i as usize].ex.ol, cpu.pl.st[i as usize].ic.op._rd());
        }
    }

    println!("WB - {}", cpu.pl.st[i as usize].ic.op);
}

pub fn clock(cpu: &mut VR4300, mc: &mut MC) {
    ic(PlStage::IC, cpu, mc);
    rf(PlStage::RF, cpu);
    ex(PlStage::EX, cpu);
    dc(PlStage::DC, cpu, mc);
    wb(PlStage::WB, cpu, mc);

    cpu.pl.st[4] = cpu.pl.st[3];
    cpu.pl.st[3] = cpu.pl.st[2];
    cpu.pl.st[2] = cpu.pl.st[1];
    cpu.pl.st[1] = cpu.pl.st[0];
    cpu.pl.st[0] = Pls::new();
}
<|endoftext|>


<commit_before>
extern crate ndarray;

use ndarray::{arr0, arr1};
use ndarray::{d2, d3};

#[test]
fn formatting()
{
    let a = arr1::<f32>(&[1., 2., 3., 4.]);
    assert_eq!(a.to_string().as_slice(),
               "[   1,    2,    3,    4]");
    let a = a.reshape(d3(4, 1, 1));
    assert_eq!(a.to_string().as_slice(),
               "[[[   1]],\n [[   2]],\n [[   3]],\n [[   4]]]");
    let a = a.reshape(d2(2, 2));
    assert_eq!(a.to_string().as_slice(),
               "[[   1,    2],\n [   3,    4]]");
    assert_eq!(format!("{:#}", a).as_slice(),
               "[[   1,    2], [   3,    4]]");

    let b = arr0::<f32>(3.5);
    assert_eq!(b.to_string().as_slice(),
               "3.5");

    let c = arr1::<f32>(&[1.1, 2.2, 33., 440.]);
    let s = format!("{:.3e}", c);
    assert_eq!(s.as_slice(),
               "[1.100e0, 2.200e0, 3.300e1, 4.400e2]");
}
<commit_msg>Update formatting tests after change in width/padding<commit_after>
extern crate ndarray;

use ndarray::{arr0, arr1};
use ndarray::{d2, d3};

#[test]
fn formatting()
{
    let a = arr1::<f32>(&[1., 2., 3., 4.]);
    assert_eq!(a.to_string().as_slice(),
               //"[   1,    2,    3,    4]");
               "[1, 2, 3, 4]");
    let a = a.reshape(d3(4, 1, 1));
    assert_eq!(a.to_string().as_slice(),
               //"[[[   1]],\n [[   2]],\n [[   3]],\n [[   4]]]");
               "[[[1]],\n [[2]],\n [[3]],\n [[4]]]");
    let a = a.reshape(d2(2, 2));
    assert_eq!(a.to_string().as_slice(),
               //"[[   1,    2],\n [   3,    4]]");
               "[[1, 2],\n [3, 4]]");
    assert_eq!(format!("{:#4}", a).as_slice(),
               "[[   1,    2], [   3,    4]]");

    let b = arr0::<f32>(3.5);
    assert_eq!(b.to_string().as_slice(),
               "3.5");

    let c = arr1::<f32>(&[1.1, 2.2, 33., 440.]);
    let s = format!("{:.3e}", c);
    assert_eq!(s.as_slice(),
               "[1.100e0, 2.200e0, 3.300e1, 4.400e2]");
}
<|endoftext|>


<commit_before>extern crate rsoundio;
extern crate rci;

use rci::Ci;

use std::thread;
use std::time::Duration;

#[test]
fn test_outstream() {
    if Ci::new().is_some() {
        return
    }
    let sio = rsoundio::SoundIo::new();
    sio.connect_backend(rsoundio::SioBackend::Dummy).unwrap();
    let current_backend = sio.current_backend().unwrap();
    assert_eq!(current_backend, rsoundio::SioBackend::Dummy);
    sio.flush_events();
    let dev_idx = sio.default_output_device_index().unwrap();
    let dev = sio.output_device(dev_idx).unwrap();
    let mut stream = dev.create_outstream().unwrap();
    stream.open().unwrap();
    assert!(stream.sample_rate() > 0);
    let layout = stream.layout();
    assert_eq!(layout.channel_count(), 2);
    let cb = |out: rsoundio::OutStream, min_frame_count: u32, max_frame_count: u32| {
        let l: Vec<f32> = (0..max_frame_count as usize)
                              .map(|i| {
                                  match i % 2 == 0 {
                                      true => -1.0,
                                      false => 1.0,
                                  }
                              })
                              .collect();
        let r = l.clone();
        let frames = vec![l, r];
        let frames_written = out.write_stream_f32(min_frame_count, &frames).unwrap();
        assert!(frames_written > 0);
        assert!(out.latency().is_ok());
    };
    stream.register_write_callback(cb);
    let ucb = |_: rsoundio::OutStream| println!("Underflow!");
    stream.register_underflow_callback(ucb);
    let ecb = |_: rsoundio::OutStream, err: rsoundio::SioError| println!("Error: {}", err);
    stream.register_error_callback(ecb);
    stream.start().unwrap();
    thread::sleep(Duration::new(1, 0));
    assert!(stream.pause().is_none());
    thread::sleep(Duration::new(1, 0));
    assert!(stream.unpause().is_none());
    assert!(stream.clear_buffer().is_none());
    thread::sleep(Duration::new(1, 0));
}
<commit_msg>Check latency from outside the callback<commit_after>extern crate rsoundio;
extern crate rci;

use rci::Ci;

use std::thread;
use std::time::Duration;

#[test]
fn test_outstream() {
    if Ci::new().is_some() {
        return
    }
    let sio = rsoundio::SoundIo::new();
    sio.connect_backend(rsoundio::SioBackend::Dummy).unwrap();
    let current_backend = sio.current_backend().unwrap();
    assert_eq!(current_backend, rsoundio::SioBackend::Dummy);
    sio.flush_events();
    let dev_idx = sio.default_output_device_index().unwrap();
    let dev = sio.output_device(dev_idx).unwrap();
    let mut stream = dev.create_outstream().unwrap();
    stream.open().unwrap();
    assert!(stream.sample_rate() > 0);
    let layout = stream.layout();
    assert_eq!(layout.channel_count(), 2);
    let cb = |out: rsoundio::OutStream, min_frame_count: u32, max_frame_count: u32| {
        let l: Vec<f32> = (0..max_frame_count as usize)
                              .map(|i| {
                                  match i % 2 == 0 {
                                      true => -1.0,
                                      false => 1.0,
                                  }
                              })
                              .collect();
        let r = l.clone();
        let frames = vec![l, r];
        let frames_written = out.write_stream_f32(min_frame_count, &frames).unwrap();
        assert!(frames_written > 0);
    };
    stream.register_write_callback(cb);
    let ucb = |_: rsoundio::OutStream| println!("Underflow!");
    stream.register_underflow_callback(ucb);
    let ecb = |_: rsoundio::OutStream, err: rsoundio::SioError| println!("Error: {}", err);
    stream.register_error_callback(ecb);
    stream.start().unwrap();
    thread::sleep(Duration::new(1, 0));
    assert!(stream.pause().is_none());
    thread::sleep(Duration::new(1, 0));
    assert!(stream.unpause().is_none());
    assert!(stream.latency().is_ok());
    assert!(stream.clear_buffer().is_none());
    thread::sleep(Duration::new(1, 0));
}
<|endoftext|>


<commit_before>pub mod application_command;
pub mod autocomplete;
pub mod message_component;
pub mod modal;
pub mod ping;

use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::ser::{Serialize, Serializer};

use self::application_command::ApplicationCommandInteraction;
use self::autocomplete::AutocompleteInteraction;
use self::message_component::MessageComponentInteraction;
use self::modal::ModalSubmitInteraction;
use self::ping::PingInteraction;
use crate::json::{from_value, JsonMap, Value};
use crate::model::id::{ApplicationId, InteractionId};
use crate::model::user::User;
use crate::model::Permissions;

/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object)
#[derive(Clone, Debug)]
pub enum Interaction {
    Ping(PingInteraction),
    ApplicationCommand(ApplicationCommandInteraction),
    MessageComponent(MessageComponentInteraction),
    Autocomplete(AutocompleteInteraction),
    ModalSubmit(ModalSubmitInteraction),
}

impl Interaction {
    /// Gets the interaction Id.
    #[must_use]
    pub fn id(&self) -> InteractionId {
        match self {
            Self::Ping(i) => i.id,
            Self::ApplicationCommand(i) => i.id,
            Self::MessageComponent(i) => i.id,
            Self::Autocomplete(i) => i.id,
            Self::ModalSubmit(i) => i.id,
        }
    }

    /// Gets the interaction type
    #[must_use]
    pub fn kind(&self) -> InteractionType {
        match self {
            Self::Ping(_) => InteractionType::Ping,
            Self::ApplicationCommand(_) => InteractionType::ApplicationCommand,
            Self::MessageComponent(_) => InteractionType::MessageComponent,
            Self::Autocomplete(_) => InteractionType::Autocomplete,
            Self::ModalSubmit(_) => InteractionType::ModalSubmit,
        }
    }

    /// Permissions the app or bot has within the channel the interaction was sent from.
    #[must_use]
    pub fn app_permissions(&self) -> Option<Permissions> {
        match self {
            Self::Ping(_) => None,
            Self::ApplicationCommand(i) => i.app_permissions,
            Self::MessageComponent(i) => i.app_permissions,
            Self::Autocomplete(i) => i.app_permissions,
            Self::ModalSubmit(i) => i.app_permissions,
        }
    }

    /// Gets the interaction application Id
    #[must_use]
    pub fn application_id(&self) -> ApplicationId {
        match self {
            Self::Ping(i) => i.application_id,
            Self::ApplicationCommand(i) => i.application_id,
            Self::MessageComponent(i) => i.application_id,
            Self::Autocomplete(i) => i.application_id,
            Self::ModalSubmit(i) => i.application_id,
        }
    }

    /// Gets the interaction token.
    #[must_use]
    pub fn token(&self) -> &str {
        match self {
            Self::Ping(ref i) => i.token.as_str(),
            Self::ApplicationCommand(i) => i.token.as_str(),
            Self::MessageComponent(i) => i.token.as_str(),
            Self::Autocomplete(i) => i.token.as_str(),
            Self::ModalSubmit(i) => i.token.as_str(),
        }
    }

    /// Gets the invoked guild locale.
    #[must_use]
    pub fn guild_locale(&self) -> Option<&str> {
        match self {
            Self::Ping(i) => i.guild_locale.as_deref(),
            Self::ApplicationCommand(i) => i.guild_locale.as_deref(),
            Self::MessageComponent(i) => i.guild_locale.as_deref(),
            Self::Autocomplete(i) => i.guild_locale.as_deref(),
            Self::ModalSubmit(i) => i.guild_locale.as_deref(),
        }
    }

    /// Converts this to a [`PingInteraction`]
    #[must_use]
    pub fn ping(self) -> Option<PingInteraction> {
        match self {
            Self::Ping(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to an [`ApplicationCommandInteraction`]
    #[must_use]
    pub fn application_command(self) -> Option<ApplicationCommandInteraction> {
        match self {
            Self::ApplicationCommand(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`MessageComponentInteraction`]
    #[must_use]
    pub fn message_component(self) -> Option<MessageComponentInteraction> {
        match self {
            Self::MessageComponent(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`AutocompleteInteraction`]
    #[must_use]
    pub fn autocomplete(self) -> Option<AutocompleteInteraction> {
        match self {
            Self::Autocomplete(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`ModalSubmitInteraction`]
    #[must_use]
    pub fn modal_submit(self) -> Option<ModalSubmitInteraction> {
        match self {
            Self::ModalSubmit(i) => Some(i),
            _ => None,
        }
    }
}

impl<'de> Deserialize<'de> for Interaction {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let map = JsonMap::deserialize(deserializer)?;

        let kind = map
            .get("type")
            .ok_or_else(|| DeError::custom("expected type"))
            .and_then(InteractionType::deserialize)
            .map_err(DeError::custom)?;

        match kind {
            InteractionType::Ping => from_value::<PingInteraction>(Value::from(map))
                .map(Interaction::Ping)
                .map_err(DeError::custom),
            InteractionType::ApplicationCommand => {
                from_value::<ApplicationCommandInteraction>(Value::from(map))
                    .map(Interaction::ApplicationCommand)
                    .map_err(DeError::custom)
            },
            InteractionType::MessageComponent => {
                from_value::<MessageComponentInteraction>(Value::from(map))
                    .map(Interaction::MessageComponent)
                    .map_err(DeError::custom)
            },
            InteractionType::Autocomplete => {
                from_value::<AutocompleteInteraction>(Value::from(map))
                    .map(Interaction::Autocomplete)
                    .map_err(DeError::custom)
            },
            InteractionType::ModalSubmit => from_value::<ModalSubmitInteraction>(Value::from(map))
                .map(Interaction::ModalSubmit)
                .map_err(DeError::custom),
            InteractionType::Unknown => Err(DeError::custom("Unknown interaction type")),
        }
    }
}

impl Serialize for Interaction {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        match self {
            Self::Ping(i) => PingInteraction::serialize(i, serializer),
            Self::ApplicationCommand(i) => ApplicationCommandInteraction::serialize(i, serializer),
            Self::MessageComponent(i) => MessageComponentInteraction::serialize(i, serializer),
            Self::Autocomplete(i) => AutocompleteInteraction::serialize(i, serializer),
            Self::ModalSubmit(i) => ModalSubmitInteraction::serialize(i, serializer),
        }
    }
}

/// The type of an Interaction.
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type).
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InteractionType {
    Ping = 1,
    ApplicationCommand = 2,
    MessageComponent = 3,
    Autocomplete = 4,
    ModalSubmit = 5,
    Unknown = !0,
}

enum_number!(InteractionType {
    Ping,
    MessageComponent,
    ApplicationCommand,
    Autocomplete,
    ModalSubmit
});

bitflags! {
    /// The flags for an interaction response message.
    ///
    /// [Discord docs](https://discord.com/developers/docs/resources/channel#message-object-message-flags)
    /// ([only some are valid in this context](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-messages))
    #[derive(Default)]
    pub struct MessageFlags: u64 {
        /// Do not include any embeds when serializing this message.
        const SUPPRESS_EMBEDS = 1 << 2;
        /// Interaction message will only be visible to sender and will
        /// be quickly deleted.
        const EPHEMERAL = 1 << 6;
    }
}

/// Sent when a [`Message`] is a response to an [`Interaction`].
///
/// [`Message`]: crate::model::channel::Message
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#message-interaction-object).
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MessageInteraction {
    /// The id of the interaction.
    pub id: InteractionId,
    /// The type of the interaction.
    #[serde(rename = "type")]
    pub kind: InteractionType,
    /// The name of the [`Command`].
    ///
    /// [`Command`]: crate::model::application::command::Command
    pub name: String,
    /// The user who invoked the interaction.
    pub user: User,
}

/// The available responses types for an interaction response.
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type).
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InteractionResponseType {
    Pong = 1,
    ChannelMessageWithSource = 4,
    DeferredChannelMessageWithSource = 5,
    DeferredUpdateMessage = 6,
    UpdateMessage = 7,
    Autocomplete = 8,
    Modal = 9,
}
<commit_msg>Add ergonomic view helpers to `Interaction` (#2265)<commit_after>pub mod application_command;
pub mod autocomplete;
pub mod message_component;
pub mod modal;
pub mod ping;

use serde::de::{Deserialize, Deserializer, Error as DeError};
use serde::ser::{Serialize, Serializer};

use self::application_command::ApplicationCommandInteraction;
use self::autocomplete::AutocompleteInteraction;
use self::message_component::MessageComponentInteraction;
use self::modal::ModalSubmitInteraction;
use self::ping::PingInteraction;
use crate::json::{from_value, JsonMap, Value};
use crate::model::id::{ApplicationId, InteractionId};
use crate::model::user::User;
use crate::model::Permissions;

/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object)
#[derive(Clone, Debug)]
pub enum Interaction {
    Ping(PingInteraction),
    ApplicationCommand(ApplicationCommandInteraction),
    MessageComponent(MessageComponentInteraction),
    Autocomplete(AutocompleteInteraction),
    ModalSubmit(ModalSubmitInteraction),
}

impl Interaction {
    /// Gets the interaction Id.
    #[must_use]
    pub fn id(&self) -> InteractionId {
        match self {
            Self::Ping(i) => i.id,
            Self::ApplicationCommand(i) => i.id,
            Self::MessageComponent(i) => i.id,
            Self::Autocomplete(i) => i.id,
            Self::ModalSubmit(i) => i.id,
        }
    }

    /// Gets the interaction type
    #[must_use]
    pub fn kind(&self) -> InteractionType {
        match self {
            Self::Ping(_) => InteractionType::Ping,
            Self::ApplicationCommand(_) => InteractionType::ApplicationCommand,
            Self::MessageComponent(_) => InteractionType::MessageComponent,
            Self::Autocomplete(_) => InteractionType::Autocomplete,
            Self::ModalSubmit(_) => InteractionType::ModalSubmit,
        }
    }

    /// Permissions the app or bot has within the channel the interaction was sent from.
    #[must_use]
    pub fn app_permissions(&self) -> Option<Permissions> {
        match self {
            Self::Ping(_) => None,
            Self::ApplicationCommand(i) => i.app_permissions,
            Self::MessageComponent(i) => i.app_permissions,
            Self::Autocomplete(i) => i.app_permissions,
            Self::ModalSubmit(i) => i.app_permissions,
        }
    }

    /// Gets the interaction application Id
    #[must_use]
    pub fn application_id(&self) -> ApplicationId {
        match self {
            Self::Ping(i) => i.application_id,
            Self::ApplicationCommand(i) => i.application_id,
            Self::MessageComponent(i) => i.application_id,
            Self::Autocomplete(i) => i.application_id,
            Self::ModalSubmit(i) => i.application_id,
        }
    }

    /// Gets the interaction token.
    #[must_use]
    pub fn token(&self) -> &str {
        match self {
            Self::Ping(ref i) => i.token.as_str(),
            Self::ApplicationCommand(i) => i.token.as_str(),
            Self::MessageComponent(i) => i.token.as_str(),
            Self::Autocomplete(i) => i.token.as_str(),
            Self::ModalSubmit(i) => i.token.as_str(),
        }
    }

    /// Gets the invoked guild locale.
    #[must_use]
    pub fn guild_locale(&self) -> Option<&str> {
        match self {
            Self::Ping(i) => i.guild_locale.as_deref(),
            Self::ApplicationCommand(i) => i.guild_locale.as_deref(),
            Self::MessageComponent(i) => i.guild_locale.as_deref(),
            Self::Autocomplete(i) => i.guild_locale.as_deref(),
            Self::ModalSubmit(i) => i.guild_locale.as_deref(),
        }
    }

    /// Converts this to a [`PingInteraction`]
    #[must_use]
    pub fn ping(self) -> Option<PingInteraction> {
        match self {
            Self::Ping(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`PingInteraction`]
    #[must_use]
    pub fn as_ping(&self) -> Option<&PingInteraction> {
        match self {
            Self::Ping(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`PingInteraction`]
    #[must_use]
    pub fn into_ping(self) -> Option<PingInteraction> {
        self.ping()
    }

    /// Converts this to an [`ApplicationCommandInteraction`]
    #[must_use]
    pub fn application_command(self) -> Option<ApplicationCommandInteraction> {
        match self {
            Self::ApplicationCommand(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to an [`ApplicationCommandInteraction`]
    #[must_use]
    pub fn as_application_command(&self) -> Option<&ApplicationCommandInteraction> {
        match self {
            Self::ApplicationCommand(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to an [`ApplicationCommandInteraction`]
    #[must_use]
    pub fn into_application_command(self) -> Option<ApplicationCommandInteraction> {
        self.application_command()
    }

    /// Converts this to a [`MessageComponentInteraction`]
    #[must_use]
    pub fn message_component(self) -> Option<MessageComponentInteraction> {
        match self {
            Self::MessageComponent(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`MessageComponentInteraction`]
    #[must_use]
    pub fn as_message_component(&self) -> Option<&MessageComponentInteraction> {
        match self {
            Self::MessageComponent(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`MessageComponentInteraction`]
    #[must_use]
    pub fn into_message_component(self) -> Option<MessageComponentInteraction> {
        self.message_component()
    }

    /// Converts this to a [`AutocompleteInteraction`]
    #[must_use]
    pub fn autocomplete(self) -> Option<AutocompleteInteraction> {
        match self {
            Self::Autocomplete(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`AutocompleteInteraction`]
    #[must_use]
    pub fn as_autocomplete(&self) -> Option<&AutocompleteInteraction> {
        match self {
            Self::Autocomplete(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`AutocompleteInteraction`]
    #[must_use]
    pub fn into_autocomplete(self) -> Option<AutocompleteInteraction> {
        self.autocomplete()
    }

    /// Converts this to a [`ModalSubmitInteraction`]
    #[must_use]
    pub fn modal_submit(self) -> Option<ModalSubmitInteraction> {
        match self {
            Self::ModalSubmit(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`ModalSubmitInteraction`]
    #[must_use]
    pub fn as_modal_submit(&self) -> Option<&ModalSubmitInteraction> {
        match self {
            Self::ModalSubmit(i) => Some(i),
            _ => None,
        }
    }

    /// Converts this to a [`ModalSubmitInteraction`]
    #[must_use]
    pub fn into_modal_submit(self) -> Option<ModalSubmitInteraction> {
        self.modal_submit()
    }
}

impl<'de> Deserialize<'de> for Interaction {
    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
        let map = JsonMap::deserialize(deserializer)?;

        let kind = map
            .get("type")
            .ok_or_else(|| DeError::custom("expected type"))
            .and_then(InteractionType::deserialize)
            .map_err(DeError::custom)?;

        match kind {
            InteractionType::Ping => from_value::<PingInteraction>(Value::from(map))
                .map(Interaction::Ping)
                .map_err(DeError::custom),
            InteractionType::ApplicationCommand => {
                from_value::<ApplicationCommandInteraction>(Value::from(map))
                    .map(Interaction::ApplicationCommand)
                    .map_err(DeError::custom)
            },
            InteractionType::MessageComponent => {
                from_value::<MessageComponentInteraction>(Value::from(map))
                    .map(Interaction::MessageComponent)
                    .map_err(DeError::custom)
            },
            InteractionType::Autocomplete => {
                from_value::<AutocompleteInteraction>(Value::from(map))
                    .map(Interaction::Autocomplete)
                    .map_err(DeError::custom)
            },
            InteractionType::ModalSubmit => from_value::<ModalSubmitInteraction>(Value::from(map))
                .map(Interaction::ModalSubmit)
                .map_err(DeError::custom),
            InteractionType::Unknown => Err(DeError::custom("Unknown interaction type")),
        }
    }
}

impl Serialize for Interaction {
    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
        match self {
            Self::Ping(i) => PingInteraction::serialize(i, serializer),
            Self::ApplicationCommand(i) => ApplicationCommandInteraction::serialize(i, serializer),
            Self::MessageComponent(i) => MessageComponentInteraction::serialize(i, serializer),
            Self::Autocomplete(i) => AutocompleteInteraction::serialize(i, serializer),
            Self::ModalSubmit(i) => ModalSubmitInteraction::serialize(i, serializer),
        }
    }
}

/// The type of an Interaction.
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-object-interaction-type).
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InteractionType {
    Ping = 1,
    ApplicationCommand = 2,
    MessageComponent = 3,
    Autocomplete = 4,
    ModalSubmit = 5,
    Unknown = !0,
}

enum_number!(InteractionType {
    Ping,
    MessageComponent,
    ApplicationCommand,
    Autocomplete,
    ModalSubmit
});

bitflags! {
    /// The flags for an interaction response message.
    ///
    /// [Discord docs](https://discord.com/developers/docs/resources/channel#message-object-message-flags)
    /// ([only some are valid in this context](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-messages))
    #[derive(Default)]
    pub struct MessageFlags: u64 {
        /// Do not include any embeds when serializing this message.
        const SUPPRESS_EMBEDS = 1 << 2;
        /// Interaction message will only be visible to sender and will
        /// be quickly deleted.
        const EPHEMERAL = 1 << 6;
    }
}

/// Sent when a [`Message`] is a response to an [`Interaction`].
///
/// [`Message`]: crate::model::channel::Message
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#message-interaction-object).
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct MessageInteraction {
    /// The id of the interaction.
    pub id: InteractionId,
    /// The type of the interaction.
    #[serde(rename = "type")]
    pub kind: InteractionType,
    /// The name of the [`Command`].
    ///
    /// [`Command`]: crate::model::application::command::Command
    pub name: String,
    /// The user who invoked the interaction.
    pub user: User,
}

/// The available responses types for an interaction response.
///
/// [Discord docs](https://discord.com/developers/docs/interactions/receiving-and-responding#interaction-response-object-interaction-callback-type).
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
#[non_exhaustive]
#[repr(u8)]
pub enum InteractionResponseType {
    Pong = 1,
    ChannelMessageWithSource = 4,
    DeferredChannelMessageWithSource = 5,
    DeferredUpdateMessage = 6,
    UpdateMessage = 7,
    Autocomplete = 8,
    Modal = 9,
}
<|endoftext|>


<commit_before>use std::collections::{HashMap, HashSet};
use plank_syntax::position::{Span, Spanned};
use ast::cfg::{Program, Function, Block, Reg, Instruction, Value, BlockId, BlockEnd};
use CompileCtx;

struct Context<'a> {
    ctx: &'a mut CompileCtx,
    function: &'a Function,
    reported_regs: HashSet<Reg>,
    live_starts: HashMap<Reg, HashSet<BlockId>>,
}

impl<'a> Context<'a> {
    fn new(function: &'a Function, ctx: &'a mut CompileCtx) -> Self {
        Context {
            ctx,
            function,
            reported_regs: HashSet::new(),
            live_starts: HashMap::new(),
        }
    }

    fn collect_assigned(&self, block: &Block) -> HashSet<Reg> {
        let mut assigned = HashSet::new();
        for op in &block.ops {
            match **op {
                Instruction::Assign(reg, _) |
                Instruction::BinaryOp(reg, _, _, _) |
                Instruction::Call(reg, _, _) |
                Instruction::UnaryOp(reg, _, _) |
                Instruction::TakeAddress(reg, _, _) |
                Instruction::CastAssign(reg, _) => {
                    assigned.insert(reg);
                }
                Instruction::Error |
                Instruction::Drop(_) |
                Instruction::DerefStore(_, _, _, _) |
                Instruction::FieldStore(_, _, _) |
                Instruction::StartStatement => {}
            }
        }
        assigned
    }

    fn check_block(&mut self, id: BlockId, block: &Block) {
        let mut assigned = HashSet::new();
        for op in &block.ops {
            let span = Spanned::span(op);
            match **op {
                Instruction::Assign(_, ref val) |
                Instruction::UnaryOp(_, _, ref val) |
                Instruction::FieldStore(_, _, ref val) |
                Instruction::CastAssign(_, ref val) => {
                    self.check_value(val, span, id, &assigned);
                }
                Instruction::DerefStore(ref a, _, _, ref b) |
                Instruction::BinaryOp(_, _, ref a, ref b) => {
                    self.check_value(a, span, id, &assigned);
                    self.check_value(b, span, id, &assigned);
                }
                Instruction::Call(_, ref value, ref params) => {
                    self.check_value(value, span, id, &assigned);
                    for param in params {
                        self.check_value(param, span, id, &assigned);
                    }
                }
                Instruction::Error |
                Instruction::StartStatement |
                Instruction::Drop(_) => {}
                Instruction::TakeAddress(_, reg, _) => {
                    let val = Value::Reg(reg);
                    self.check_value(&val, span, id, &assigned);
                }
            }
            match **op {
                Instruction::Assign(reg, _) |
                Instruction::BinaryOp(reg, _, _, _) |
                Instruction::Call(reg, _, _) |
                Instruction::UnaryOp(reg, _, _) |
                Instruction::TakeAddress(reg, _, _) |
                Instruction::CastAssign(reg, _) => {
                    assigned.insert(reg);
                }
                Instruction::Error |
                Instruction::Drop(_) |
                Instruction::DerefStore(_, _, _, _) |
                Instruction::FieldStore(_, _, _) |
                Instruction::StartStatement => {}
            }
        }
    }

    fn check_value(&mut self, value: &Value, span: Span, block: BlockId, block_assigned: &HashSet<Reg>) {
        match *value {
            Value::Int(_, _) |
            Value::Symbol(_, _) |
            Value::Bytes(_) |
            Value::Unit |
            Value::Error => {}
            Value::Reg(reg) if self.reported_regs.contains(&reg) => {}
            Value::Reg(reg) if block_assigned.contains(&reg) => {}
            Value::Reg(reg) => {
                let live_start = self.live_starts
                    .get(&reg)
                    .map(|set| set.contains(&block))
                    .unwrap_or(false);
                if !live_start {
                    let msg = format!(
                        "variable used before being assigned (register %{})",
                        reg.0,
                    );
                    self.ctx
                        .reporter
                        .warning(msg, span)
                        .span(span)
                        .build();
                    self.reported_regs.insert(reg);
                }
            }
        }
    }

    fn add_start(&mut self, block: BlockId, reg: Reg) {
        {
            let starts = self.live_starts.entry(reg).or_insert_with(HashSet::new);
            if starts.contains(&block) {
                return;
            }
            starts.insert(block);
        }
        match self.function.blocks[&block].end {
            BlockEnd::Jump(to) => {
                self.add_start(to, reg);
            }
            BlockEnd::Branch(_, a, b) => {
                self.add_start(a, reg);
                self.add_start(b, reg);
            }
            BlockEnd::Return(_) | BlockEnd::Error => {}
        }
    }

    fn check_function(&mut self) {
        if let Some(block) = self.function.start_block {
            for &param in &self.function.parameters {
                self.add_start(block, param);
            }
        }
        for (&id, block) in &self.function.blocks {
            for reg in self.collect_assigned(block) {
                match block.end {
                    BlockEnd::Jump(to) => {
                        self.add_start(to, reg);
                    }
                    BlockEnd::Branch(_, a, b) => {
                        self.add_start(a, reg);
                        self.add_start(b, reg);
                    }
                    BlockEnd::Return(_) | BlockEnd::Error => {}
                }
            }
            self.check_block(id, block);
        }
    }
}

pub(crate) fn check_program(program: &Program, ctx: &mut CompileCtx) {
    for f in program.functions.values() {
        let mut ctx = Context::new(f, ctx);
        ctx.check_function();
    }
}
<commit_msg>fix assignment check<commit_after>use std::collections::{HashMap, HashSet};
use plank_syntax::position::{Span, Spanned};
use ast::cfg::{Program, Function, Block, Reg, Instruction, Value, BlockId, BlockEnd};
use CompileCtx;

struct Context<'a> {
    ctx: &'a mut CompileCtx,
    function: &'a Function,
    reported_regs: HashSet<Reg>,
    live_starts: HashMap<Reg, HashSet<BlockId>>,
}

impl<'a> Context<'a> {
    fn new(function: &'a Function, ctx: &'a mut CompileCtx) -> Self {
        Context {
            ctx,
            function,
            reported_regs: HashSet::new(),
            live_starts: HashMap::new(),
        }
    }

    fn collect_assigned(&self, block: &Block) -> HashSet<Reg> {
        let mut assigned = HashSet::new();
        for op in &block.ops {
            match **op {
                Instruction::Assign(reg, _) |
                Instruction::BinaryOp(reg, _, _, _) |
                Instruction::Call(reg, _, _) |
                Instruction::UnaryOp(reg, _, _) |
                Instruction::TakeAddress(reg, _, _) |
                Instruction::CastAssign(reg, _) => {
                    assigned.insert(reg);
                }
                Instruction::Error |
                Instruction::Drop(_) |
                Instruction::DerefStore(_, _, _, _) |
                Instruction::FieldStore(_, _, _) |
                Instruction::StartStatement => {}
            }
        }
        assigned
    }

    fn check_block(&mut self, id: BlockId, block: &Block) {
        let mut assigned = HashSet::new();
        for op in &block.ops {
            let span = Spanned::span(op);
            match **op {
                Instruction::Assign(_, ref val) |
                Instruction::UnaryOp(_, _, ref val) |
                Instruction::FieldStore(_, _, ref val) |
                Instruction::CastAssign(_, ref val) => {
                    self.check_value(val, span, id, &assigned);
                }
                Instruction::DerefStore(ref a, _, _, ref b) |
                Instruction::BinaryOp(_, _, ref a, ref b) => {
                    self.check_value(a, span, id, &assigned);
                    self.check_value(b, span, id, &assigned);
                }
                Instruction::Call(_, ref value, ref params) => {
                    self.check_value(value, span, id, &assigned);
                    for param in params {
                        self.check_value(param, span, id, &assigned);
                    }
                }
                Instruction::Error |
                Instruction::StartStatement |
                Instruction::Drop(_) => {}
                Instruction::TakeAddress(_, reg, _) => {
                    let val = Value::Reg(reg);
                    self.check_value(&val, span, id, &assigned);
                }
            }
            match **op {
                Instruction::Assign(reg, _) |
                Instruction::BinaryOp(reg, _, _, _) |
                Instruction::Call(reg, _, _) |
                Instruction::UnaryOp(reg, _, _) |
                Instruction::TakeAddress(reg, _, _) |
                Instruction::CastAssign(reg, _) => {
                    assigned.insert(reg);
                }
                Instruction::Error |
                Instruction::Drop(_) |
                Instruction::DerefStore(_, _, _, _) |
                Instruction::FieldStore(_, _, _) |
                Instruction::StartStatement => {}
            }
        }
    }

    fn check_value(&mut self, value: &Value, span: Span, block: BlockId, block_assigned: &HashSet<Reg>) {
        match *value {
            Value::Int(_, _) |
            Value::Symbol(_, _) |
            Value::Bytes(_) |
            Value::Unit |
            Value::Error => {}
            Value::Reg(reg) if self.reported_regs.contains(&reg) => {}
            Value::Reg(reg) if block_assigned.contains(&reg) => {}
            Value::Reg(reg) => {
                let live_start = self.live_starts
                    .get(&reg)
                    .map(|set| set.contains(&block))
                    .unwrap_or(false);
                if !live_start {
                    self.ctx
                        .reporter
                        .error("variable used before being assigned", span)
                        .span(span)
                        .build();
                    self.reported_regs.insert(reg);
                }
            }
        }
    }

    fn add_start(&mut self, block: BlockId, reg: Reg) {
        {
            let starts = self.live_starts.entry(reg).or_insert_with(HashSet::new);
            if starts.contains(&block) {
                return;
            }
            starts.insert(block);
        }
        match self.function.blocks[&block].end {
            BlockEnd::Jump(to) => {
                self.add_start(to, reg);
            }
            BlockEnd::Branch(_, a, b) => {
                self.add_start(a, reg);
                self.add_start(b, reg);
            }
            BlockEnd::Return(_) | BlockEnd::Error => {}
        }
    }

    fn check_function(&mut self) {
        if let Some(block) = self.function.start_block {
            for &param in &self.function.parameters {
                self.add_start(block, param);
            }
        }
        for block in self.function.blocks.values() {
            for reg in self.collect_assigned(block) {
                match block.end {
                    BlockEnd::Jump(to) => {
                        self.add_start(to, reg);
                    }
                    BlockEnd::Branch(_, a, b) => {
                        self.add_start(a, reg);
                        self.add_start(b, reg);
                    }
                    BlockEnd::Return(_) | BlockEnd::Error => {}
                }
            }
        }
        for (&id, block) in &self.function.blocks {
            self.check_block(id, block);
        }
    }
}

pub(crate) fn check_program(program: &Program, ctx: &mut CompileCtx) {
    for f in program.functions.values() {
        let mut ctx = Context::new(f, ctx);
        ctx.check_function();
    }
}
<|endoftext|>