<commit_before>extern crate pattern_api_v2 as pattern;

use pattern::Pattern;
use pattern::{Searcher, ReverseSearcher};
use pattern::SearchCursors;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum SearchResult {
    Match(usize, usize),
    Reject(usize, usize),
}

impl SearchResult {
    pub fn begin(&self) -> usize {
        match *self {
            Match(a, _) | Reject(a, _) => a,
        }
    }
    pub fn end(&self) -> usize {
        match *self {
            Match(_, b) | Reject(_, b) => b,
        }
    }
}

use SearchResult::{Match, Reject};

#[macro_export]
macro_rules! searcher_test {
    // For testing if the results of a double ended searcher exactly match what is expected
    ($name:ident, $p:expr, $h:expr, double: [$($e:expr,)*]) => {
        #[allow(unused_imports)]
        mod $name {
            use $crate::SearchResult::{Match, Reject};
            use $crate::{cmp_search_to_vec};
            use super::*;

            #[test]
            fn fwd_exact() {
                cmp_search_to_vec(false, || $p, || $h, Some(vec![$($e),*]));
            }
            #[test]
            fn bwd_exact() {
                cmp_search_to_vec(true, || $p, || $h, Some(vec![$($e),*]));
            }
        }
    };
    // For testing if the results of a forward-reverse searcher exactly match what is expected
    ($name:ident, $p:expr, $h:expr, forward: [$($e:expr,)*], backward: [$($f:expr,)*]) => {
        #[allow(unused_imports)]
        mod $name {
            use $crate::SearchResult::{Match, Reject};
            use $crate::{cmp_search_to_vec};

            #[test]
            fn fwd_exact() {
                cmp_search_to_vec(false, || $p, || $h, Some(vec![$($e),*]));
            }
            #[test]
            fn bwd_exact() {
                cmp_search_to_vec(true, || $p, || $h, Some(vec![$($f),*]));
            }
        }
    };
}

pub fn cmp_search_to_vec<'a, H, P, F, HF>(rev: bool,
                                          mut pat: F,
                                          mut haystack: HF,
                                          right: Option<Vec<SearchResult>>) -> Vec<SearchResult>
where H: SearchCursors,
      P: Pattern<H>,
      P::Searcher: ReverseSearcher<H>,
      F: FnMut() -> P,
      HF: FnMut() -> H,
{

    cmp_search_to_vec2(rev, |f: &mut Callback| {
        let h = haystack();
        let p = pat();
        f.call(h, p);
    }, right)
}

#[macro_export]
macro_rules! searcher_cross_test {
    ($tname:ident {
        double: [$($res:expr,)*];
        for:
        $($cname:ident, $hty:ty: $h:expr, $pty:ty: $p:expr;)*
    }) => {
        #[allow(unused_imports)]
        mod $tname {
            use $crate::SearchResult::{self, Match, Reject};

            fn build() -> Vec<SearchResult> {
                vec![$($res),*]
            }

            $(
                mod $cname {
                    use $crate::SearchResult::{Match, Reject};
                    use $crate::{cmp_search_to_vec2, Callback};
                    use super::build;

                    #[test]
                    fn fwd_exact() {
                        cmp_search_to_vec2(false, |f: &mut Callback| {
                            let h: $hty = $h;
                            let p: $pty = $p;
                            f.call(h, p);
                        }, Some(build()));
                    }
                    #[test]
                    fn bwd_exact() {
                        cmp_search_to_vec2(true, |f: &mut Callback| {
                            let h: $hty = $h;
                            let p: $pty = $p;
                            f.call(h, p);
                        }, Some(build()));
                    }
                }
            )*
        }
    }
}

enum CallbackMode {
    Gather {
        rev: bool,
        matches: bool,
    },
}

pub struct Callback {
    mode: CallbackMode,
    result: Vec<(usize, usize)>,
    hs_len: Option<usize>,
}
impl Callback {
    pub fn call<H, P>(&mut self, haystack: H, pattern: P)
        where H: SearchCursors,
              P: Pattern<H>,
              P::Searcher: ReverseSearcher<H>,
    {
        match self.mode {
            CallbackMode::Gather { rev, matches } => {
                let r = {
                    let mut searcher = pattern.into_searcher(haystack);
                    let mut v = vec![];
                    loop {
                        let next = match (rev, matches) {
                            (false, true) =>  searcher.next_match(),
                            (false, false) =>  searcher.next_reject(),
                            (true, true) =>  searcher.next_match_back(),
                            (true, false) =>  searcher.next_reject_back(),
                        };
                        match next {
                            Some((a, b)) => v.push((a, b)),
                            None => break,
                        }
                    }
                    if rev {
                        v.reverse();
                    }
                    self.hs_len = Some(H::haystack_len(searcher.haystack()));
                    v.into_iter().map(|(a, b)| {
                        let haystack = searcher.haystack();
                        (
                            H::offset_from_front(haystack, a),
                            H::offset_from_front(haystack, b),
                        )
                    }).collect::<Vec<_>>()
                };
                self.result = r;
            }
        }

    }

    fn new(rev: bool, matches: bool) -> Self {
        Callback {
            mode: CallbackMode::Gather {
                rev: rev,
                matches: matches,
            },
            result: vec![],
            hs_len: None,
        }
    }
}

pub fn cmp_search_to_vec2<F>(rev: bool,
                             mut f: F,
                             right: Option<Vec<SearchResult>>)
                             ->  Vec<SearchResult>
where F: FnMut(&mut Callback),
{
    let mut matches = Callback::new(rev, true);
    f(&mut matches);

    let mut rejects = Callback::new(rev, false);
    f(&mut rejects);

    let hs_len = matches.hs_len.unwrap();

    let mut matches = matches.result.into_iter();
    let mut rejects = rejects.result.into_iter();

    let mut v = vec![];

    // Merge the two streams of results
    {
        let mut cur_match = matches.next();
        let mut cur_reject = rejects.next();

        loop {
            if cur_match.is_none() && cur_reject.is_none() {
                break;
            } else if cur_match.is_some() && cur_reject.is_some() {
                let m = cur_match.unwrap();
                let r = cur_reject.unwrap();

                if m.0 <= r.0 {
                    v.push(Match(m.0, m.1));
                    cur_match = matches.next();
                } else {
                    v.push(Reject(r.0, r.1));
                    cur_reject = rejects.next();
                }
            } else if cur_match.is_some() {
                let m = cur_match.unwrap();
                v.push(Match(m.0, m.1));
                cur_match = matches.next();
            } else if cur_reject.is_some() {
                let r = cur_reject.unwrap();
                v.push(Reject(r.0, r.1));
                cur_reject = rejects.next();
            }
        }
    }

    println!("");

    // Validate and emit diagnostics

    if is_malformed(&v, hs_len) {
        panic!("searcher impl outputted invalid search results");
    }

    if let Some(right) = right {
        compare(&v, &right, hs_len);
    }

    v
}

pub fn is_malformed(v: &[SearchResult], haystack_len: usize) -> bool {
    let mut found = false;
    for (i, pair) in v.windows(2).enumerate() {
        if pair[0].end() < pair[1].begin() {
            println!("Gap detected at end of {:?}", &v[..i+2]);
            found = true;
        }
        if pair[0].end() > pair[1].begin() {
            println!("Overlap detected at end of {:?}", &v[..i+2]);
            found = true;
        }
    }

    for (i, &e) in v.iter().enumerate() {
        if let Reject(a, b) = e {
            if a == b {
                println!("Zero-length Reject detected at end of {:?}", &v[..i+1]);
                found = true;
            }
        }
    }

    if v.len() > 0 {
        if v[0].begin() != 0 {
            println!("First interval did not start at begin of haystack: [{:?}, ...]", &v[0]);
            found = true;
        }

        if v[v.len() - 1].end() != haystack_len {
            println!("Last interval did not end at end of haystack: [..., {:?}]", &v[v.len() - 1]);
            found = true;
        }
    }

    found
}

pub fn compare(left: &[SearchResult], right: &[SearchResult], haystack_len: usize) {
    if is_malformed(&right, haystack_len) {
        panic!("should-be search result test input is malformed, check test code for correctness");
    }

    assert!(left == right, "\n  searcher:  {:?}\n  should-be: {:?}\n", left, right);
}
<commit_msg>Reduced test macros more<commit_after>extern crate pattern_api_v2 as pattern;

use pattern::Pattern;
use pattern::{Searcher, ReverseSearcher};
use pattern::SearchCursors;

#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub enum SearchResult {
    Match(usize, usize),
    Reject(usize, usize),
}

impl SearchResult {
    pub fn begin(&self) -> usize {
        match *self {
            Match(a, _) | Reject(a, _) => a,
        }
    }
    pub fn end(&self) -> usize {
        match *self {
            Match(_, b) | Reject(_, b) => b,
        }
    }
}

use SearchResult::{Match, Reject};

pub fn cmp_search_to_vec<'a, H, P, F, HF>(rev: bool,
                                          mut pat: F,
                                          mut haystack: HF,
                                          right: Option<Vec<SearchResult>>) -> Vec<SearchResult>
where H: SearchCursors,
      P: Pattern<H>,
      P::Searcher: ReverseSearcher<H>,
      F: FnMut() -> P,
      HF: FnMut() -> H,
{

    cmp_search_to_vec2(rev, |f: &mut Callback| {
        let h = haystack();
        let p = pat();
        f.call(h, p);
    }, right)
}

#[macro_export]
macro_rules! searcher_cross_test {
    ($tname:ident {
        double: [$($res:expr,)*];
        for:
        $($cname:ident, $hty:ty: $h:expr, $pty:ty: $p:expr;)*
    }) => {
        searcher_cross_test! {
            $tname {
                forward: [$($res,)*];
                backward: [$($res,)*];
                for:
                $($cname, $hty: $h, $pty: $p;)*
            }
        }
    };
    ($tname:ident {
        forward: [$($res:expr,)*];
        backward: [$($rres:expr,)*];
        for:
        $($cname:ident, $hty:ty: $h:expr, $pty:ty: $p:expr;)*
    }) => {
        #[allow(unused_imports)]
        mod $tname {
            use $crate::SearchResult::{self, Match, Reject};

            fn build() -> Vec<SearchResult> {
                vec![$($res),*]
            }

            fn rbuild() -> Vec<SearchResult> {
                vec![$($rres),*]
            }

            $(
                mod $cname {
                    use $crate::SearchResult::{Match, Reject};
                    use $crate::{cmp_search_to_vec2, Callback};
                    use super::{build, rbuild};
                    use super::super::*;

                    #[test]
                    fn fwd() {
                        cmp_search_to_vec2(false, |f: &mut Callback| {
                            let h: $hty = $h;
                            let p: $pty = $p;
                            f.call(h, p);
                        }, Some(build()));
                    }
                    #[test]
                    fn bwd() {
                        cmp_search_to_vec2(true, |f: &mut Callback| {
                            let h: $hty = $h;
                            let p: $pty = $p;
                            f.call(h, p);
                        }, Some(rbuild()));
                    }
                }
            )*
        }
    }
}

#[macro_export]
macro_rules! searcher_test {
    // For testing if the results of a double ended searcher exactly match what is expected
    ($name:ident, $p:expr, $h:expr, double: [$($e:expr,)*]) => {
        searcher_cross_test!{
            $name {
                double: [$($e,)*];
                for:
                test, _: $h, _: $p;
            }
        }
    };
    // For testing if the results of a forward-reverse searcher exactly match what is expected
    ($name:ident, $p:expr, $h:expr, forward: [$($e:expr,)*], backward: [$($f:expr,)*]) => {
        searcher_cross_test!{
            $name {
                forward: [$($e,)*];
                backward: [$($f,)*];
                for:
                test, _: $h, _: $p;
            }
        }
    };
}

enum CallbackMode {
    Gather {
        rev: bool,
        matches: bool,
    },
}

pub struct Callback {
    mode: CallbackMode,
    result: Vec<(usize, usize)>,
    hs_len: Option<usize>,
}
impl Callback {
    pub fn call<H, P>(&mut self, haystack: H, pattern: P)
        where H: SearchCursors,
              P: Pattern<H>,
              P::Searcher: ReverseSearcher<H>,
    {
        match self.mode {
            CallbackMode::Gather { rev, matches } => {
                let r = {
                    let mut searcher = pattern.into_searcher(haystack);
                    let mut v = vec![];
                    loop {
                        let next = match (rev, matches) {
                            (false, true) =>  searcher.next_match(),
                            (false, false) =>  searcher.next_reject(),
                            (true, true) =>  searcher.next_match_back(),
                            (true, false) =>  searcher.next_reject_back(),
                        };
                        match next {
                            Some((a, b)) => v.push((a, b)),
                            None => break,
                        }
                    }
                    if rev {
                        v.reverse();
                    }
                    self.hs_len = Some(H::haystack_len(searcher.haystack()));
                    v.into_iter().map(|(a, b)| {
                        let haystack = searcher.haystack();
                        (
                            H::offset_from_front(haystack, a),
                            H::offset_from_front(haystack, b),
                        )
                    }).collect::<Vec<_>>()
                };
                self.result = r;
            }
        }

    }

    fn new(rev: bool, matches: bool) -> Self {
        Callback {
            mode: CallbackMode::Gather {
                rev: rev,
                matches: matches,
            },
            result: vec![],
            hs_len: None,
        }
    }
}

pub fn cmp_search_to_vec2<F>(rev: bool,
                             mut f: F,
                             right: Option<Vec<SearchResult>>)
                             ->  Vec<SearchResult>
where F: FnMut(&mut Callback),
{
    let mut matches = Callback::new(rev, true);
    f(&mut matches);

    let mut rejects = Callback::new(rev, false);
    f(&mut rejects);

    let hs_len = matches.hs_len.unwrap();

    let mut matches = matches.result.into_iter();
    let mut rejects = rejects.result.into_iter();

    let mut v = vec![];

    // Merge the two streams of results
    {
        let mut cur_match = matches.next();
        let mut cur_reject = rejects.next();

        loop {
            if cur_match.is_none() && cur_reject.is_none() {
                break;
            } else if cur_match.is_some() && cur_reject.is_some() {
                let m = cur_match.unwrap();
                let r = cur_reject.unwrap();

                if m.0 <= r.0 {
                    v.push(Match(m.0, m.1));
                    cur_match = matches.next();
                } else {
                    v.push(Reject(r.0, r.1));
                    cur_reject = rejects.next();
                }
            } else if cur_match.is_some() {
                let m = cur_match.unwrap();
                v.push(Match(m.0, m.1));
                cur_match = matches.next();
            } else if cur_reject.is_some() {
                let r = cur_reject.unwrap();
                v.push(Reject(r.0, r.1));
                cur_reject = rejects.next();
            }
        }
    }

    println!("");

    // Validate and emit diagnostics

    if is_malformed(&v, hs_len) {
        panic!("searcher impl outputted invalid search results");
    }

    if let Some(right) = right {
        compare(&v, &right, hs_len);
    }

    v
}

pub fn is_malformed(v: &[SearchResult], haystack_len: usize) -> bool {
    let mut found = false;
    for (i, pair) in v.windows(2).enumerate() {
        if pair[0].end() < pair[1].begin() {
            println!("Gap detected at end of {:?}", &v[..i+2]);
            found = true;
        }
        if pair[0].end() > pair[1].begin() {
            println!("Overlap detected at end of {:?}", &v[..i+2]);
            found = true;
        }
    }

    for (i, &e) in v.iter().enumerate() {
        if let Reject(a, b) = e {
            if a == b {
                println!("Zero-length Reject detected at end of {:?}", &v[..i+1]);
                found = true;
            }
        }
    }

    if v.len() > 0 {
        if v[0].begin() != 0 {
            println!("First interval did not start at begin of haystack: [{:?}, ...]", &v[0]);
            found = true;
        }

        if v[v.len() - 1].end() != haystack_len {
            println!("Last interval did not end at end of haystack: [..., {:?}]", &v[v.len() - 1]);
            found = true;
        }
    }

    found
}

pub fn compare(left: &[SearchResult], right: &[SearchResult], haystack_len: usize) {
    if is_malformed(&right, haystack_len) {
        panic!("should-be search result test input is malformed, check test code for correctness");
    }

    assert!(left == right, "\n  searcher:  {:?}\n  should-be: {:?}\n", left, right);
}
<|endoftext|>


<commit_before>use game::constants::{X_MOVEMENT, Y_MOVEMENT};
use gfx_app::mouse_controls::MouseInputState;
use graphics::can_move;
use graphics::camera::CameraInputState;
use graphics::orientation::Orientation;
use shaders::Position;
use specs;
use specs::{ReadStorage, WriteStorage};
use std::sync::mpsc;

#[derive(Clone, Debug)]
pub struct CharacterInputState {
  pub x_movement: f32,
  pub y_movement: f32,
  pub orientation: Orientation,
  pub is_colliding: bool,
}

impl CharacterInputState {
  pub fn new() -> CharacterInputState {
    CharacterInputState {
      x_movement: 0.0,
      y_movement: 0.0,
      orientation: Orientation::Still,
      is_colliding: false
    }
  }
}

impl specs::Component for CharacterInputState {
  type Storage = specs::DenseVecStorage<CharacterInputState>;
}

#[derive(Debug)]
pub enum CharacterControl {
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CharacterControlSystem {
  queue: mpsc::Receiver<CharacterControl>,
  x_move: Option<f32>,
  y_move: Option<f32>,
}

impl CharacterControlSystem {
  pub fn new() -> (CharacterControlSystem, mpsc::Sender<CharacterControl>) {
    let (tx, rx) = mpsc::channel();
    (CharacterControlSystem {
      queue: rx,
      x_move: None,
      y_move: None,
    }, tx)
  }
}

impl<'a> specs::System<'a> for CharacterControlSystem {
  type SystemData = (WriteStorage<'a, CharacterInputState>, ReadStorage<'a, MouseInputState>, WriteStorage<'a, CameraInputState>);

  fn run(&mut self, (mut character_input, mouse_input, mut camera_input): Self::SystemData) {
    use specs::Join;

    while let Ok(control) = self.queue.try_recv() {
      match control {
        CharacterControl::Up => self.y_move = Some(-Y_MOVEMENT),
        CharacterControl::Down => self.y_move = Some(Y_MOVEMENT),
        CharacterControl::YMoveStop => self.y_move = None,
        CharacterControl::Right => self.x_move = Some(-X_MOVEMENT),
        CharacterControl::Left => self.x_move = Some(X_MOVEMENT),
        CharacterControl::XMoveStop => self.x_move = None,
      }
    }

    if self.y_move.is_none() && self.x_move.is_none() {
      for (ci, mi) in (&mut character_input, &mouse_input).join() {
        if mi.left_click_point.is_none() {
          ci.orientation = Orientation::Still;
        }
      }
    } else if self.x_move.is_none() {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() && !ci.is_colliding || can_move(Position::new([ci.x_movement, ci.y_movement + y])) {
            ci.y_movement += y;
            camera.y_pos -= y;
            ci.orientation =
              if y < 0.0 { Orientation::Up } else if y > 0.0 { Orientation::Down } else { Orientation::Still };
          }
        }
      }
    } else if let Some(x) = self.x_move {
      if let Some(y) = self.y_move {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() && !ci.is_colliding || can_move(Position::new([ci.x_movement + x, ci.y_movement + y])) {
            ci.x_movement += x / 1.5;
            ci.y_movement += y / 1.5;
            camera.x_pos += x / 1.5;
            camera.y_pos -= y / 1.5;

            ci.orientation = match (x, y) {
              (x, y) if x > 0.0 && y > 0.0 => Orientation::DownLeft,
              (x, y) if x > 0.0 && y < 0.0 => Orientation::UpLeft,
              (x, y) if x < 0.0 && y > 0.0 => Orientation::DownRight,
              (x, y) if x < 0.0 && y < 0.0 => Orientation::UpRight,
              _ => Orientation::Still,
            };
          }
        }
      } else if self.y_move.is_none() {
        for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
          if mi.left_click_point.is_none() && !ci.is_colliding || can_move(Position::new([ci.x_movement + x, ci.y_movement])){
            ci.x_movement += x;
            camera.x_pos += x;
            ci.orientation =
              if x < 0.0 { Orientation::Right } else if x > 0.0 { Orientation::Left } else { Orientation::Still };
          }
        }
      }
    }
  }
}
<commit_msg>Throttle input control<commit_after>use game::constants::{X_MOVEMENT, Y_MOVEMENT};
use gfx_app::mouse_controls::MouseInputState;
use graphics::{can_move, DeltaTime};
use graphics::camera::CameraInputState;
use graphics::orientation::Orientation;
use shaders::Position;
use specs;
use specs::{Fetch, ReadStorage, WriteStorage};
use std::sync::mpsc;

#[derive(Clone, Debug)]
pub struct CharacterInputState {
  pub x_movement: f32,
  pub y_movement: f32,
  pub orientation: Orientation,
  pub is_colliding: bool,
}

impl CharacterInputState {
  pub fn new() -> CharacterInputState {
    CharacterInputState {
      x_movement: 0.0,
      y_movement: 0.0,
      orientation: Orientation::Still,
      is_colliding: false
    }
  }
}

impl specs::Component for CharacterInputState {
  type Storage = specs::DenseVecStorage<CharacterInputState>;
}

#[derive(Debug)]
pub enum CharacterControl {
  Left,
  Right,
  Up,
  Down,
  XMoveStop,
  YMoveStop,
}

#[derive(Debug)]
pub struct CharacterControlSystem {
  queue: mpsc::Receiver<CharacterControl>,
  x_move: Option<f32>,
  y_move: Option<f32>,
  cool_down: f64,
}

impl CharacterControlSystem {
  pub fn new() -> (CharacterControlSystem, mpsc::Sender<CharacterControl>) {
    let (tx, rx) = mpsc::channel();
    (CharacterControlSystem {
      queue: rx,
      x_move: None,
      y_move: None,
      cool_down: 1.0,
    }, tx)
  }
}

impl<'a> specs::System<'a> for CharacterControlSystem {
  type SystemData = (WriteStorage<'a, CharacterInputState>,
                     ReadStorage<'a, MouseInputState>,
                     WriteStorage<'a, CameraInputState>,
                     Fetch<'a, DeltaTime>);

  fn run(&mut self, (mut character_input, mouse_input, mut camera_input, d): Self::SystemData) {
    use specs::Join;
    let delta = d.0;

    if self.cool_down == 0.0 {
      self.cool_down += 0.01;
    } else {
      self.cool_down = (self.cool_down - delta).max(0.0);
      while let Ok(control) = self.queue.try_recv() {
        match control {
          CharacterControl::Up => self.y_move = Some(-Y_MOVEMENT),
          CharacterControl::Down => self.y_move = Some(Y_MOVEMENT),
          CharacterControl::YMoveStop => self.y_move = None,
          CharacterControl::Right => self.x_move = Some(-X_MOVEMENT),
          CharacterControl::Left => self.x_move = Some(X_MOVEMENT),
          CharacterControl::XMoveStop => self.x_move = None,
        }
      }

      if self.y_move.is_none() && self.x_move.is_none() {
        for (ci, mi) in (&mut character_input, &mouse_input).join() {
          if mi.left_click_point.is_none() {
            ci.orientation = Orientation::Still;
          }
        }
      } else if self.x_move.is_none() {
        if let Some(y) = self.y_move {
          for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
            if mi.left_click_point.is_none() && !ci.is_colliding || can_move(Position::new([ci.x_movement, ci.y_movement + y])) {
              ci.y_movement += y;
              camera.y_pos -= y;
              ci.orientation =
                if y < 0.0 { Orientation::Up } else if y > 0.0 { Orientation::Down } else { Orientation::Still };
            }
          }
        }
      } else if let Some(x) = self.x_move {
        if let Some(y) = self.y_move {
          for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
            if mi.left_click_point.is_none() && !ci.is_colliding || can_move(Position::new([ci.x_movement + x, ci.y_movement + y])) {
              ci.x_movement += x / 1.5;
              ci.y_movement += y / 1.5;
              camera.x_pos += x / 1.5;
              camera.y_pos -= y / 1.5;

              ci.orientation = match (x, y) {
                (x, y) if x > 0.0 && y > 0.0 => Orientation::DownLeft,
                (x, y) if x > 0.0 && y < 0.0 => Orientation::UpLeft,
                (x, y) if x < 0.0 && y > 0.0 => Orientation::DownRight,
                (x, y) if x < 0.0 && y < 0.0 => Orientation::UpRight,
                _ => Orientation::Still,
              };
            }
          }
        } else if self.y_move.is_none() {
          for (ci, mi, camera) in (&mut character_input, &mouse_input, &mut camera_input).join() {
            if mi.left_click_point.is_none() && !ci.is_colliding || can_move(Position::new([ci.x_movement + x, ci.y_movement])) {
              ci.x_movement += x;
              camera.x_pos += x;
              ci.orientation =
                if x < 0.0 { Orientation::Right } else if x > 0.0 { Orientation::Left } else { Orientation::Still };
            }
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>fn main() {
    // This is an example of a line comment
    // Notice how there are two slashes at the beginning of the line
    // And that nothing written inside these will be read by the compiler

    // println!("Hello, world!");

    // Run it. See? Now try deleting the two slashes, and run it again.

    /*
     * This is another type of comment, the block comment. In general,
     * the line comment is the recommended comment style however the
     * block comment is extremely useful for debugging
     */

     /*
     Note, the previous column of `*` was entirely for style. There's
     no actual need for it.
     */

     // Observe how block comments allow easy expression manipulation
     // which line comments do not. Deleting the comment delimiters
     // will change the result:
     let x = 5 + /* 90 + */ 5;
     println!("Is `x` 10 or 100? x = {}", x);
}
<commit_msg>translate comment.rs<commit_after>fn main() {
    // 这是行注释的例子
    // 注意这里有两个斜线在这行的开头
    // 在这里面的所有内容编译器都不会读取

    // println!("Hello, world!");

    // 运行一下，看看得到什么结果？现在将上述语句的两条斜线删掉，并重新运行看看。

    /*
     * 这是另外一种格式的注释——块注释。一般而言，行注释是推荐的注释格式，不过块
     * 注释在调试过程中很以用。
     */

     /*
      注意，上面的例子中纵向都有 `*`，这完全是基于格式考虑，实际上这并不是
      必须的。
      */

     // 观察块注释是如何对简单的表达式进行控制，而行注释不能这样操作。
     // 删除注释分隔符将会改变结果。
     let x = 5 + /* 90 + */ 5;
     println!("Is `x` 10 or 100? x = {}", x);
}
<|endoftext|>


<commit_before>extern crate wrappinghashset;

use self::wrappinghashset::{WrappingHashSet, Iter};

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, Mutex};

use bytes::Bytes;

use ::constants::*;
use ::packet::*;
use job::Job;

#[derive(Debug)]
pub struct WorkerSet {
    inactive: HashSet<usize>,
    active: HashSet<usize>,
}

impl WorkerSet {
    pub fn new() -> WorkerSet {
        WorkerSet {
            inactive: HashSet::new(),
            active: HashSet::new(),
        }
    }
}

pub struct Workers {
    allworkers: HashMap<Bytes, WorkerSet>,
    wakeworkers: HashSet<usize>,
}

pub type SharedWorkers = Arc<Mutex<Workers>>;

pub trait Wake {
    fn new_workers() -> Self;
    fn queue_wake(&mut self, &Bytes);
    fn do_wakes(&mut self) -> Vec<Packet>;
    fn sleep(&mut self, &mut Worker, usize);
    fn wakeup(&mut self, &mut Worker, usize);
    fn count_workers(&mut self, &Bytes) -> (usize, usize);
    fn shutdown(&mut self, remote: usize);
}

impl Wake for SharedWorkers {
    fn new_workers() -> SharedWorkers {
        Arc::new(Mutex::new(Workers::new()))
    }

    fn queue_wake(&mut self, fname: &Bytes) {
        let mut workers = self.lock().unwrap();
        let mut inserts = Vec::new();
        debug!("allworkers({:?}) = {:?}", fname, workers.allworkers);
        match workers.allworkers.get_mut(fname) {
            None => {}
            Some(workerset) => {
                // Copy the contents into active
                workerset.active.extend(workerset.inactive.iter());
                // Empty the contents into inserts
                for worker in workerset.inactive.drain() {
                    inserts.push(worker.clone());
                }
            }
        }
        debug!("Queueing inserts {:?}", inserts);
        workers.wakeworkers.extend(inserts);
    }

    fn do_wakes(&mut self) -> Vec<Packet> {
        let mut workers = self.lock().unwrap();
        let mut packets = Vec::with_capacity(workers.wakeworkers.len());
        for worker in workers.wakeworkers.drain() {
            packets.push(Packet::new_res_remote(NOOP, Box::new(Vec::new()), Some(worker)));
        }
        packets
    }

    fn sleep(&mut self, worker: &mut Worker, remote: usize) {
        debug!("Sleeping with fnames = {:?}", worker.functions);
        let mut workers = self.lock().unwrap();
        for fname in worker.iter() {
            let mut add = false;
            debug!("Looking for {:?} in workers.allworkers, {:?}",
                   &fname,
                   &workers.allworkers);
            match workers.allworkers.get_mut(&fname) {
                None => {
                    debug!("Did not find {:?}", &fname);
                    add = true;
                }
                Some(workerset) => {
                    debug!("Deactivating remote {:?} from fname {:?}", remote, &fname);
                    workerset.active.remove(&remote);
                    workerset.inactive.insert(remote);
                }
            };
            if add {
                debug!("Adding new workerset {:?} from fname {:?}", remote, &fname);
                let mut workerset = WorkerSet::new();
                workerset.inactive.insert(remote);
                workers.allworkers.insert(fname.clone(), workerset);
            }
        }
    }

    fn wakeup(&mut self, worker: &mut Worker, remote: usize) {
        let mut workers = self.lock().unwrap();
        for fname in worker.iter() {
            let mut add = false;
            match workers.allworkers.get_mut(&fname) {
                None => {
                    add = true;
                }
                Some(workerset) => {
                    workerset.inactive.remove(&remote);
                    workerset.active.insert(remote);
                }
            };
            if add {
                let mut workerset = WorkerSet::new();
                workerset.active.insert(remote);
                workers.allworkers.insert(fname.clone(), workerset);
            }
        }
    }

    fn count_workers(&mut self, fname: &Bytes) -> (usize, usize) {
        let workers = self.lock().unwrap();
        match workers.allworkers.get(fname) {
            None => (0, 0),
            Some(workerset) => (workerset.active.len(), workerset.inactive.len()),
        }
    }

    fn shutdown(&mut self, remote: usize) {
        let mut workers = self.lock().unwrap();
        for (_, workerset) in workers.allworkers.iter_mut() {
            workerset.inactive.remove(&remote);
            workerset.active.remove(&remote);
        }
    }
}

impl Workers {
    fn new() -> Workers {
        Workers {
            allworkers: HashMap::new(),
            wakeworkers: HashSet::new(),
        }
    }
}

#[derive(Debug)]
pub struct Worker {
    pub functions: WrappingHashSet<Bytes>,
    job: Option<Arc<Job>>,
}

impl Worker {
    pub fn new() -> Worker {
        Worker {
            functions: WrappingHashSet::new(),
            job: None,
        }
    }

    pub fn can_do(&mut self, fname: Bytes) {
        self.functions.insert(fname);
    }

    pub fn cant_do<'b>(&mut self, fname: &'b Bytes) {
        self.functions.remove(fname);
    }

    pub fn iter<'i>(&'i mut self) -> Iter<'i, Bytes> {
        self.functions.iter()
    }

    pub fn assign_job(&mut self, job: &Arc<Job>) {
        self.job = Some(job.clone());
    }

    pub fn unassign_job(&mut self) {
        match self.job {
            None => {}
            Some(ref j) => {
                match Arc::weak_count(j) {
                    0 => {}
                    a @ _ => {
                        warn!("Unassigning queued {:?} ({}+{} refs)",
                              j,
                              Arc::strong_count(j),
                              a);
                    }
                }
            }
        }
        self.job = None;
    }

    pub fn job(&mut self) -> Option<Arc<Job>> {
        self.job.clone()
    }
}
<commit_msg>replace do_wakes with wakeworkers_drain<commit_after>extern crate wrappinghashset;

use self::wrappinghashset::{WrappingHashSet, Iter};

use std::collections::{HashMap, HashSet};
use std::sync::{Arc, Mutex};

use bytes::Bytes;

use job::Job;

#[derive(Debug)]
pub struct WorkerSet {
    inactive: HashSet<usize>,
    active: HashSet<usize>,
}

impl WorkerSet {
    pub fn new() -> WorkerSet {
        WorkerSet {
            inactive: HashSet::new(),
            active: HashSet::new(),
        }
    }
}

pub struct Workers {
    allworkers: HashMap<Bytes, WorkerSet>,
    wakeworkers: HashSet<usize>,
}

pub type SharedWorkers = Arc<Mutex<Workers>>;

pub trait Wake {
    fn new_workers() -> Self;
    fn queue_wake(&mut self, &Bytes);
    fn wakeworkers_drain(&mut self) -> Vec<usize>;
    fn sleep(&mut self, &mut Worker, usize);
    fn wakeup(&mut self, &mut Worker, usize);
    fn count_workers(&mut self, &Bytes) -> (usize, usize);
    fn shutdown(&mut self, remote: usize);
}

impl Wake for SharedWorkers {
    fn new_workers() -> SharedWorkers {
        Arc::new(Mutex::new(Workers::new()))
    }

    fn queue_wake(&mut self, fname: &Bytes) {
        let mut workers = self.lock().unwrap();
        let mut inserts = Vec::new();
        debug!("allworkers({:?}) = {:?}", fname, workers.allworkers);
        match workers.allworkers.get_mut(fname) {
            None => {}
            Some(workerset) => {
                // Copy the contents into active
                workerset.active.extend(workerset.inactive.iter());
                // Empty the contents into inserts
                for worker in workerset.inactive.drain() {
                    inserts.push(worker.clone());
                }
            }
        }
        debug!("Queueing inserts {:?}", inserts);
        workers.wakeworkers.extend(inserts);
    }

    fn wakeworkers_drain(&mut self) -> Vec<usize> {
        let mut workers = self.lock().unwrap();
        let to_drain: Vec<usize> = workers.wakeworkers.drain().collect();
        to_drain
    }

    fn sleep(&mut self, worker: &mut Worker, remote: usize) {
        debug!("Sleeping with fnames = {:?}", worker.functions);
        let mut workers = self.lock().unwrap();
        for fname in worker.iter() {
            let mut add = false;
            debug!("Looking for {:?} in workers.allworkers, {:?}",
                   &fname,
                   &workers.allworkers);
            match workers.allworkers.get_mut(&fname) {
                None => {
                    debug!("Did not find {:?}", &fname);
                    add = true;
                }
                Some(workerset) => {
                    debug!("Deactivating remote {:?} from fname {:?}", remote, &fname);
                    workerset.active.remove(&remote);
                    workerset.inactive.insert(remote);
                }
            };
            if add {
                debug!("Adding new workerset {:?} from fname {:?}", remote, &fname);
                let mut workerset = WorkerSet::new();
                workerset.inactive.insert(remote);
                workers.allworkers.insert(fname.clone(), workerset);
            }
        }
    }

    fn wakeup(&mut self, worker: &mut Worker, remote: usize) {
        let mut workers = self.lock().unwrap();
        for fname in worker.iter() {
            let mut add = false;
            match workers.allworkers.get_mut(&fname) {
                None => {
                    add = true;
                }
                Some(workerset) => {
                    workerset.inactive.remove(&remote);
                    workerset.active.insert(remote);
                }
            };
            if add {
                let mut workerset = WorkerSet::new();
                workerset.active.insert(remote);
                workers.allworkers.insert(fname.clone(), workerset);
            }
        }
    }

    fn count_workers(&mut self, fname: &Bytes) -> (usize, usize) {
        let workers = self.lock().unwrap();
        match workers.allworkers.get(fname) {
            None => (0, 0),
            Some(workerset) => (workerset.active.len(), workerset.inactive.len()),
        }
    }

    fn shutdown(&mut self, remote: usize) {
        let mut workers = self.lock().unwrap();
        for (_, workerset) in workers.allworkers.iter_mut() {
            workerset.inactive.remove(&remote);
            workerset.active.remove(&remote);
        }
    }
}

impl Workers {
    fn new() -> Workers {
        Workers {
            allworkers: HashMap::new(),
            wakeworkers: HashSet::new(),
        }
    }
}

#[derive(Debug)]
pub struct Worker {
    pub functions: WrappingHashSet<Bytes>,
    job: Option<Arc<Job>>,
}

impl Worker {
    pub fn new() -> Worker {
        Worker {
            functions: WrappingHashSet::new(),
            job: None,
        }
    }

    pub fn can_do(&mut self, fname: Bytes) {
        self.functions.insert(fname);
    }

    pub fn cant_do<'b>(&mut self, fname: &'b Bytes) {
        self.functions.remove(fname);
    }

    pub fn iter<'i>(&'i mut self) -> Iter<'i, Bytes> {
        self.functions.iter()
    }

    pub fn assign_job(&mut self, job: &Arc<Job>) {
        self.job = Some(job.clone());
    }

    pub fn unassign_job(&mut self) {
        match self.job {
            None => {}
            Some(ref j) => {
                match Arc::weak_count(j) {
                    0 => {}
                    a @ _ => {
                        warn!("Unassigning queued {:?} ({}+{} refs)",
                              j,
                              Arc::strong_count(j),
                              a);
                    }
                }
            }
        }
        self.job = None;
    }

    pub fn job(&mut self) -> Option<Arc<Job>> {
        self.job.clone()
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

#[derive(Clone, Copy, Debug)]
pub enum Orientation {
    Across,
    Down
}

#[derive(Clone, Copy, Debug)]
pub struct WordspanAddress {
    start_row: usize,
    start_col: usize,
    orientation: Orientation,
    length: usize
}

impl WordspanAddress {
    pub fn new(start_row: usize, start_col: usize,
               orientation: Orientation, length: usize) -> Self {
        WordspanAddress {
            start_row: start_row,
            start_col: start_col,
            orientation: orientation,
            length: length
        }
    }
}

pub const BARRIER: char = '█';

#[derive(Clone, Debug)]
pub struct Puzzle {
    rows: usize,
    cols: usize,
    backing: Vec<char>
}

impl Puzzle {
    fn read(&self, row_index: usize, col_index: usize) -> char {
        self.backing[self.cols*row_index + col_index]
    }

    fn write(&mut self, row_index: usize, col_index: usize,
             letter: char) {
        self.backing[self.cols*row_index + col_index] = letter;
    }

    // XXX: returning a Vec<_> implies an allocation, but we can't return a
    // slice because the Down case isn't contiguous. Can we return a
    // Cow<[char]>? Profile and decide later
    pub fn read_wordspan(&self, address: WordspanAddress) -> Vec<char> {
        let start_square = self.cols*address.start_row + address.start_col;
        match address.orientation {
            Orientation::Across => {
                self.backing[start_square..start_square+address.length].to_vec()
            },
            Orientation::Down => {
                (0..address.length).map(|r| {
                    self.backing[start_square + self.cols*r]
                }).collect()
            }
        }
    }

    pub fn write_wordspan(&mut self, address: WordspanAddress, word: Vec<char>) {
        let start_square = self.cols*address.start_row + address.start_col;
        let mut offset = 0;
        for character in word {
            self.backing[start_square + offset] = character;
            offset += match address.orientation {
                Orientation::Across => 1,
                Orientation::Down => self.cols
            }
        }
    }

}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_puzzle() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 5,
            backing: vec![
                'W', 'R', 'I', 'T', 'E',
                'A', 'A', 'R', 'O', 'N',
                'G', 'I', 'A', 'N', 'T',
                'E', 'S', 'T', 'E', 'R',
                'R', 'E', 'E', 'D', 'Y',
            ]
        }
    }

    #[test]
    fn concerning_read_wordspan_across() {
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        assert_eq!(test_puzzle().read_wordspan(write_address),
                   vec!['W', 'R', 'I', 'T', 'E']);
    }

    #[test]
    fn concerning_read_wordspan_down() {
        let raise_address = WordspanAddress::new(0, 1, Orientation::Down, 5);
        assert_eq!(test_puzzle().read_wordspan(raise_address),
                   vec!['R', 'A', 'I', 'S', 'E']);
    }

    #[test]
    fn concerning_write_wordspan_across() {
        let mut puzzle = test_puzzle();
        // in more ways than one
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        puzzle.write_wordspan(write_address, vec!['P', 'L', 'A', 'T', 'E']);
        assert_eq!(puzzle.read_wordspan(write_address),
                   vec!['P', 'L', 'A', 'T', 'E']);
    }

    #[test]
    fn concerning_write_wordspan_down() {
        let mut puzzle = test_puzzle();
        let entry_address = WordspanAddress::new(0, 4, Orientation::Down, 5);
        puzzle.write_wordspan(entry_address, vec!['F', 'A', 'I', 'T', 'H']);
        assert_eq!(puzzle.read_wordspan(entry_address),
                   vec!['F', 'A', 'I', 'T', 'H']);
    }

}
<commit_msg>wordspan addresses across<commit_after>#![allow(dead_code)]

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Orientation {
    Across,
    Down
}

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct WordspanAddress {
    start_row: usize,
    start_col: usize,
    orientation: Orientation,
    length: usize
}

impl WordspanAddress {
    pub fn new(start_row: usize, start_col: usize,
               orientation: Orientation, length: usize) -> Self {
        WordspanAddress {
            start_row: start_row,
            start_col: start_col,
            orientation: orientation,
            length: length
        }
    }
}

pub const BARRIER: char = '█';

#[derive(Clone, Debug)]
pub struct Puzzle {
    rows: usize,
    cols: usize,
    backing: Vec<char>
}

impl Puzzle {
    pub fn read(&self, row_index: usize, col_index: usize) -> char {
        self.backing[self.cols*row_index + col_index]
    }

    pub fn write(&mut self, row_index: usize, col_index: usize,
             letter: char) {
        self.backing[self.cols*row_index + col_index] = letter;
    }

    // XXX: returning a Vec<_> implies an allocation, but we can't return a
    // slice because the Down case isn't contiguous. Can we return a
    // Cow<[char]>? Profile and decide later
    pub fn read_wordspan(&self, address: WordspanAddress) -> Vec<char> {
        let start_square = self.cols*address.start_row + address.start_col;
        match address.orientation {
            Orientation::Across => {
                self.backing[start_square..start_square+address.length].to_vec()
            },
            Orientation::Down => {
                (0..address.length).map(|r| {
                    self.backing[start_square + self.cols*r]
                }).collect()
            }
        }
    }

    pub fn write_wordspan(&mut self, address: WordspanAddress, word: Vec<char>) {
        let start_square = self.cols*address.start_row + address.start_col;
        let mut offset = 0;
        for character in word {
            self.backing[start_square + offset] = character;
            offset += match address.orientation {
                Orientation::Across => 1,
                Orientation::Down => self.cols
            }
        }
    }

    fn wordspan_addresses_across(&self) -> Vec<WordspanAddress> {
        let mut addresses = Vec::new();
        for row in 0..self.rows {
            let mut open_word_from: Option<usize> = None;
            for col in 0..self.cols {
                match open_word_from {
                    None => {
                        if self.read(row, col) == BARRIER {
                            continue;
                        } else {
                            open_word_from = Some(col);
                        }
                    },
                    Some(open_from) => {
                        if self.read(row, col) == BARRIER {
                            let address = WordspanAddress::new(
                                row, open_from, Orientation::Across,
                                col-open_from
                            );
                            addresses.push(address);
                            open_word_from = None;
                        } else {
                            continue;
                        }
                    }
                }
            }
            // close off word closed by edge of puzzle rather than barrier
            if let Some(open_from) = open_word_from {
                let address = WordspanAddress::new(
                    row, open_from, Orientation::Across,
                    self.cols-open_from
                );
                addresses.push(address);
            }
        }
        addresses
    }

}

#[cfg(test)]
mod tests {
    use super::*;

    fn test_puzzle_i() -> Puzzle {
        Puzzle {
            rows: 5,
            cols: 5,
            backing: vec![
                'W', 'R', 'I', 'T', 'E',
                'A', 'A', 'R', 'O', 'N',
                'G', 'I', 'A', 'N', 'T',
                'E', 'S', 'T', 'E', 'R',
                'R', 'E', 'E', 'D', 'Y',
            ]
        }
    }

    fn test_puzzle_ii() -> Puzzle {
        Puzzle {
            rows: 7,
            cols: 11,
            backing: vec![
                'S', 'W', 'I', 'F', 'T', '█', 'S', 'T', 'A', 'C', 'K',
                'L', 'A', 'M', 'A', 'S', '█', 'L', 'A', 'M', 'A', 'R',
                'A', 'L', 'A', 'N', '█', 'L', 'E', 'G', 'A', 'T', 'O',
                'B', 'E', 'G', '█', 'L', 'A', 'D', '█', 'D', 'E', 'C',
                '█', 'S', 'E', 'L', 'I', 'M', '█', 'F', 'E', 'R', '█',
                '█', 'A', 'R', 'E', 'S', '█', 'P', 'I', 'U', 'S', '█',
                '█', '█', 'Y', 'I', 'P', '█', 'L', 'E', 'S', '█', '█',
            ]
        }
    }

    #[test]
    fn concerning_read_wordspan_across() {
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        assert_eq!(test_puzzle_i().read_wordspan(write_address),
                   vec!['W', 'R', 'I', 'T', 'E']);
    }

    #[test]
    fn concerning_read_wordspan_down() {
        let raise_address = WordspanAddress::new(0, 1, Orientation::Down, 5);
        assert_eq!(test_puzzle_i().read_wordspan(raise_address),
                   vec!['R', 'A', 'I', 'S', 'E']);
    }

    #[test]
    fn concerning_write_wordspan_across() {
        let mut puzzle = test_puzzle_i();
        // in more ways than one
        let write_address = WordspanAddress::new(0, 0, Orientation::Across, 5);
        puzzle.write_wordspan(write_address, vec!['P', 'L', 'A', 'T', 'E']);
        assert_eq!(puzzle.read_wordspan(write_address),
                   vec!['P', 'L', 'A', 'T', 'E']);
    }

    #[test]
    fn concerning_write_wordspan_down() {
        let mut puzzle = test_puzzle_i();
        let entry_address = WordspanAddress::new(0, 4, Orientation::Down, 5);
        puzzle.write_wordspan(entry_address, vec!['F', 'A', 'I', 'T', 'H']);
        assert_eq!(puzzle.read_wordspan(entry_address),
                   vec!['F', 'A', 'I', 'T', 'H']);
    }

    #[test]
    fn concerning_wordspan_addresses_across() {
        let puzzle = test_puzzle_ii();
        assert_eq!(
            &[WordspanAddress::new(0, 0, Orientation::Across, 5),
              WordspanAddress::new(0, 6, Orientation::Across, 5),
              WordspanAddress::new(1, 0, Orientation::Across, 5),
              WordspanAddress::new(1, 6, Orientation::Across, 5),
              WordspanAddress::new(2, 0, Orientation::Across, 4),
              WordspanAddress::new(2, 5, Orientation::Across, 6)],
            &puzzle.wordspan_addresses_across()[..6]
        );
    }
}
<|endoftext|>


<commit_before>extern crate html2text;
extern crate termion;
extern crate argparse;
use std::io::{self, Write};
use html2text::render::text_renderer::{RichAnnotation};
use argparse::{ArgumentParser, Store};
use termion::input::TermRead;
use termion::event::Key;
use termion::raw::IntoRawMode;
use termion::cursor::Goto;

fn to_style(tag: &Vec<RichAnnotation>) -> String {
    let mut style = String::new();

    for ann in tag {
        match *ann {
            RichAnnotation::Default => (),
            RichAnnotation::Link(_) => {
                style.push_str(&format!("{}", termion::style::Underline));
            },
            RichAnnotation::Image => {
                style.push_str(&format!("{}", termion::color::Fg(termion::color::LightBlue)));
            },
        }
    }
    style
}

fn main() {
    let mut filename = String::new();
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut filename)
          .add_argument("filename", Store, "Set HTML filename");
        ap.parse_args_or_exit();
    }

    let (width, height) = termion::terminal_size().unwrap();
    let (width, height) = (width as usize, height as usize);

    let mut file = std::fs::File::open(filename).expect("Tried to open file");
    let annotated = html2text::from_read_rich(&mut file, width as usize);

    let mut keys = io::stdin().keys();
    let mut stdout = io::stdout().into_raw_mode().unwrap();
    let mut pos = 0;
    let mut cursor_x = 1;
    let mut cursor_y = 1;
    loop {
        let maxpos = std::cmp::min(pos+height, annotated.len());
        write!(stdout, "{}", termion::clear::All).unwrap();
        for (i, line) in annotated[pos..maxpos].iter().enumerate() {
            write!(stdout, "{}", Goto(1, i as u16 +1)).unwrap();
            for (s, tag) in line.iter() {
                let style = to_style(tag);
                write!(stdout, "{}{}{}", style, s, termion::style::Reset).unwrap();
            }
        }
        write!(stdout, "{}", Goto(cursor_x, cursor_y)).unwrap();
        stdout.flush().unwrap();
        if let Some(Ok(k)) = keys.next() {
            match k {
                Key::Char('q') => break,
                Key::Char('j') | Key::Down => {
                    if cursor_y < height as u16 {
                        cursor_y += 1;
                    }
                },
                Key::Char('k') | Key::Up => {
                    if cursor_y > 1 {
                        cursor_y -= 1;
                    }
                },
                Key::Char('h') | Key::Left => {
                    if cursor_x > 1 {
                        cursor_x -= 1;
                    }
                },
                Key::Char('l') | Key::Right => {
                    if cursor_x < width as u16 {
                        cursor_x += 1;
                    }
                },
                Key::Char(' ') | Key::PageDown => {
                    if pos + height-1 < annotated.len() {
                        pos += height-1;
                    }
                },
                Key::PageUp => {
                    if pos >= height-1 {
                        pos -= height-1;
                    }
                },
                _ => {},
            }
        }
    }
}<commit_msg>Some work towards doing something with links in the terminal UI. Can now highlight links when the cursor is on them.<commit_after>extern crate html2text;
extern crate termion;
extern crate argparse;
extern crate unicode_width;
use std::io::{self, Write};
use html2text::render::text_renderer::{RichAnnotation,TaggedLine};
use argparse::{ArgumentParser, Store};
use termion::input::TermRead;
use termion::event::Key;
use termion::raw::IntoRawMode;
use termion::cursor::Goto;
use unicode_width::UnicodeWidthStr;

fn to_style(tag: &Vec<RichAnnotation>) -> String {
    let mut style = String::new();

    for ann in tag {
        match *ann {
            RichAnnotation::Default => (),
            RichAnnotation::Link(_) => {
                style.push_str(&format!("{}", termion::style::Underline));
            },
            RichAnnotation::Image => {
                style.push_str(&format!("{}", termion::color::Fg(termion::color::LightBlue)));
            },
        }
    }
    style
}

struct LinkMap {
    lines: Vec<Vec<Option<String>>>,  // lines[y][x] => Some(URL) or None
}

impl LinkMap {
    pub fn link_at(&self, x: usize, y: usize) -> Option<&str> {
        if let Some(ref linevec) = self.lines.get(y) {
            if let Some(&Some(ref text)) = linevec.get(x) {
                return Some(&text)
            }
        }
        None
    }
}

fn link_from_tag(tag: &Vec<RichAnnotation>) -> Option<String> {
    let mut link = None;
    for annotation in tag {
        if let RichAnnotation::Link(ref text) = *annotation {
            link = Some(text.clone());
        }
    }
    link
}

fn find_links(lines: &Vec<TaggedLine<Vec<RichAnnotation>>>) -> LinkMap {
    let mut map = Vec::new();
    for line in lines {
        let mut linevec = Vec::new();

        for (s, tag) in line.iter() {
            let link = link_from_tag(tag);
            for _ in 0..UnicodeWidthStr::width(s) {
                linevec.push(link.clone());
            }
        }

        map.push(linevec);
    }
    LinkMap {
        lines: map,
    }
}

fn main() {
    let mut filename = String::new();
    {
        let mut ap = ArgumentParser::new();
        ap.refer(&mut filename)
          .add_argument("filename", Store, "Set HTML filename");
        ap.parse_args_or_exit();
    }

    let (width, height) = termion::terminal_size().unwrap();
    let (width, height) = (width as usize, height as usize);

    let mut file = std::fs::File::open(filename).expect("Tried to open file");
    let annotated = html2text::from_read_rich(&mut file, width as usize);

    let link_map = find_links(&annotated);

    let mut keys = io::stdin().keys();
    let mut stdout = io::stdout().into_raw_mode().unwrap();
    let mut pos = 0;
    // 1-based screen co-ordinates
    let mut cursor_x = 1;
    let mut cursor_y = 1;
    loop {
        let opt_url = link_map.link_at(cursor_x as usize - 1, cursor_y as usize +pos-1);
        let maxpos = std::cmp::min(pos+height, annotated.len());
        write!(stdout, "{}", termion::clear::All).unwrap();
        for (i, line) in annotated[pos..maxpos].iter().enumerate() {
            let mut x = 0;
            write!(stdout, "{}", Goto(1, i as u16 +1)).unwrap();
            for (s, tag) in line.iter() {
                let style = to_style(tag);
                let link = link_from_tag(tag);
                match (opt_url, link) {
                    (Some(ref t1), Some(ref t2)) if t1 == t2 => {
                        write!(stdout, "{}", termion::style::Invert).unwrap();
                    },
                    _ => (),
                }
                write!(stdout, "{}{}{}", style, s, termion::style::Reset).unwrap();
            }
        }
        write!(stdout, "{}", Goto(cursor_x, cursor_y)).unwrap();
        stdout.flush().unwrap();
        if let Some(Ok(k)) = keys.next() {
            match k {
                Key::Char('q') => break,
                Key::Char('j') | Key::Down => {
                    if cursor_y < height as u16 {
                        cursor_y += 1;
                    }
                },
                Key::Char('k') | Key::Up => {
                    if cursor_y > 1 {
                        cursor_y -= 1;
                    }
                },
                Key::Char('h') | Key::Left => {
                    if cursor_x > 1 {
                        cursor_x -= 1;
                    }
                },
                Key::Char('l') | Key::Right => {
                    if cursor_x < width as u16 {
                        cursor_x += 1;
                    }
                },
                Key::Char(' ') | Key::PageDown => {
                    if pos + height-1 < annotated.len() {
                        pos += height-1;
                    }
                },
                Key::PageUp => {
                    if pos >= height-1 {
                        pos -= height-1;
                    }
                },
                Key::Char('\t') => {
                },
                _ => {},
            }
        }
    }
}<|endoftext|>


<commit_before>use super::gi_docgen;
use crate::{analysis::symbols, Env};
use once_cell::sync::Lazy;
use regex::{Captures, Match, Regex};

const LANGUAGE_SEP_BEGIN: &str = "<!-- language=\"";
const LANGUAGE_SEP_END: &str = "\" -->";
const LANGUAGE_BLOCK_BEGIN: &str = "|[";
const LANGUAGE_BLOCK_END: &str = "\n]|";

pub fn reformat_doc(input: &str, env: &Env, in_type: &str) -> String {
    code_blocks_transformation(input, env, in_type)
}

fn try_split<'a>(src: &'a str, needle: &str) -> (&'a str, Option<&'a str>) {
    match src.find(needle) {
        Some(pos) => (&src[..pos], Some(&src[pos + needle.len()..])),
        None => (src, None),
    }
}

fn code_blocks_transformation(mut input: &str, env: &Env, in_type: &str) -> String {
    let mut out = String::with_capacity(input.len());

    loop {
        input = match try_split(input, LANGUAGE_BLOCK_BEGIN) {
            (before, Some(after)) => {
                out.push_str(&format(before, env, in_type));
                if let (before, Some(after)) =
                    try_split(get_language(after, &mut out), LANGUAGE_BLOCK_END)
                {
                    out.push_str(before);
                    out.push_str("\n```");
                    after
                } else {
                    after
                }
            }
            (before, None) => {
                out.push_str(&format(before, env, in_type));
                return out;
            }
        };
    }
}

fn get_language<'a>(entry: &'a str, out: &mut String) -> &'a str {
    if let (_, Some(after)) = try_split(entry, LANGUAGE_SEP_BEGIN) {
        if let (before, Some(after)) = try_split(after, LANGUAGE_SEP_END) {
            out.push_str(&format!("\n```{}", before));
            return after;
        }
    }
    out.push_str("\n```text");
    entry
}

fn format(mut input: &str, env: &Env, in_type: &str) -> String {
    let mut ret = String::with_capacity(input.len());
    loop {
        let (before, after) = try_split(input, "`");
        // We run gi_docgen first because it's super picky about the types it replaces
        let no_c_types_re = gi_docgen::replace_c_types(before, env, in_type);
        ret.push_str(&replace_c_types(&no_c_types_re, env, in_type));

        if let Some(after) = after {
            ret.push('`');
            let (before, after) = try_split(after, "`");
            // don't touch anything enclosed in backticks
            ret.push_str(before);
            if let Some(after) = after {
                ret.push('`');
                input = after;
            } else {
                return ret;
            }
        } else {
            return ret;
        }
    }
}

static SYMBOL: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(^|[^\\])([@#%])(\w+\b)([:.]+[\w-]+\b)?").unwrap());
static FUNCTION: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"([@#%])?(\w+\b[:.]+)?(\b[a-z0-9_]+)\(\)").unwrap());
static GDK_GTK: Lazy<Regex> = Lazy::new(|| Regex::new(r"G[dt]k[A-Z]\w+\b").unwrap());
static TAGS: Lazy<Regex> = Lazy::new(|| Regex::new(r"<[\w/-]+>").unwrap());
static SPACES: Lazy<Regex> = Lazy::new(|| Regex::new(r"[ ]{2,}").unwrap());

fn replace_c_types(entry: &str, env: &Env, in_type: &str) -> String {
    let symbols = env.symbols.borrow();
    let lookup = |s: &str| -> String {
        symbols
            .by_c_name(s)
            .map(symbols::Symbol::full_rust_name)
            .unwrap_or_else(|| s.into())
    };

    let out = FUNCTION.replace_all(entry, |caps: &Captures<'_>| {
        let name = &caps[3];
        let sym = symbols.by_c_name(name);

        if let Some(sym) = sym {
            if sym.owner_name() == Some(in_type) {
                // `#` or `%` symbols should probably have been `@` to denote
                // that it is a reference within the current type.
                format!("[`Self::{}()`]", sym.name())
            } else {
                match caps.get(1).as_ref().map(Match::as_str) {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    Some("@") => format!(
                        "[`crate::{}()`] (XXX: @-reference does not belong to {}!)",
                        sym.full_rust_name(),
                        in_type,
                    ),
                    Some("#") | None => {
                        format!("[`crate::{}()`]", sym.full_rust_name())
                    }
                    Some("%") => panic!("% not allowed for {:?}", caps),
                    Some(c) => panic!("Unknown symbol reference {}", c),
                }
            }
        } else if let Some(typ) = caps.get(2) {
            let typ = typ.as_str();
            if typ == in_type {
                format!("[`Self::{}()`]", name)
            } else {
                format!("[`crate::{}{}()`]", typ, name)
            }
        } else {
            format!("`{}()`", name)
        }
    });

    let out = SYMBOL.replace_all(&out, |caps: &Captures<'_>| {
        let member = caps.get(4).map(|m| m.as_str()).unwrap_or("");
        let sym = symbols.by_c_name(&caps[3]);

        if let Some(sym) = sym {
            if sym.owner_name() == Some(in_type) {
                // `#` or `%` symbols should probably have been `@` to denote
                // that it is a reference within the current type.
                format!("{}[`Self::{}{}`]", &caps[1], sym.name(), member)
            } else {
                match &caps[2] {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    "@" => format!(
                        "{}[`crate::{}{}`] (XXX: @-reference does not belong to {}!)",
                        &caps[1],
                        sym.full_rust_name(),
                        member,
                        in_type,
                    ),
                    "%" if sym.is_rust_prelude() => {
                        format!("{}[`{}{}`]", &caps[1], sym.full_rust_name(), member)
                    }
                    "#" | "%" => {
                        format!("{}[`crate::{}{}`]", &caps[1], sym.full_rust_name(), member)
                    }
                    c => panic!("Unknown symbol reference {}", c),
                }
            }
        } else {
            format!("{}`{}{}`", &caps[1], &caps[3], member)
        }
    });
    let out = GDK_GTK.replace_all(&out, |caps: &Captures<'_>| {
        format!("`{}`", lookup(&caps[0]))
    });
    let out = TAGS.replace_all(&out, "`$0`");
    SPACES.replace_all(&out, " ").into_owned()
}
<commit_msg>docs: try to find objects/interface/records<commit_after>use std::any::Any;

use super::gi_docgen;
use crate::{analysis::symbols, Env};
use once_cell::sync::Lazy;
use regex::{Captures, Match, Regex};

const LANGUAGE_SEP_BEGIN: &str = "<!-- language=\"";
const LANGUAGE_SEP_END: &str = "\" -->";
const LANGUAGE_BLOCK_BEGIN: &str = "|[";
const LANGUAGE_BLOCK_END: &str = "\n]|";

pub fn reformat_doc(input: &str, env: &Env, in_type: &str) -> String {
    code_blocks_transformation(input, env, in_type)
}

fn try_split<'a>(src: &'a str, needle: &str) -> (&'a str, Option<&'a str>) {
    match src.find(needle) {
        Some(pos) => (&src[..pos], Some(&src[pos + needle.len()..])),
        None => (src, None),
    }
}

fn code_blocks_transformation(mut input: &str, env: &Env, in_type: &str) -> String {
    let mut out = String::with_capacity(input.len());

    loop {
        input = match try_split(input, LANGUAGE_BLOCK_BEGIN) {
            (before, Some(after)) => {
                out.push_str(&format(before, env, in_type));
                if let (before, Some(after)) =
                    try_split(get_language(after, &mut out), LANGUAGE_BLOCK_END)
                {
                    out.push_str(before);
                    out.push_str("\n```");
                    after
                } else {
                    after
                }
            }
            (before, None) => {
                out.push_str(&format(before, env, in_type));
                return out;
            }
        };
    }
}

fn get_language<'a>(entry: &'a str, out: &mut String) -> &'a str {
    if let (_, Some(after)) = try_split(entry, LANGUAGE_SEP_BEGIN) {
        if let (before, Some(after)) = try_split(after, LANGUAGE_SEP_END) {
            out.push_str(&format!("\n```{}", before));
            return after;
        }
    }
    out.push_str("\n```text");
    entry
}

fn format(mut input: &str, env: &Env, in_type: &str) -> String {
    let mut ret = String::with_capacity(input.len());
    loop {
        let (before, after) = try_split(input, "`");
        // We run gi_docgen first because it's super picky about the types it replaces
        let no_c_types_re = gi_docgen::replace_c_types(before, env, in_type);
        ret.push_str(&replace_c_types(&no_c_types_re, env, in_type));

        if let Some(after) = after {
            ret.push('`');
            let (before, after) = try_split(after, "`");
            // don't touch anything enclosed in backticks
            ret.push_str(before);
            if let Some(after) = after {
                ret.push('`');
                input = after;
            } else {
                return ret;
            }
        } else {
            return ret;
        }
    }
}

static SYMBOL: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"(^|[^\\])([@#%])(\w+\b)([:.]+[\w-]+\b)?").unwrap());
static FUNCTION: Lazy<Regex> =
    Lazy::new(|| Regex::new(r"([@#%])?(\w+\b[:.]+)?(\b[a-z0-9_]+)\(\)").unwrap());
static GDK_GTK: Lazy<Regex> = Lazy::new(|| Regex::new(r"G[dt]k[A-Z]\w+\b").unwrap());
static TAGS: Lazy<Regex> = Lazy::new(|| Regex::new(r"<[\w/-]+>").unwrap());
static SPACES: Lazy<Regex> = Lazy::new(|| Regex::new(r"[ ]{2,}").unwrap());

fn replace_c_types(entry: &str, env: &Env, in_type: &str) -> String {
    let symbols = env.symbols.borrow();
    let lookup = |s: &str| -> String {
        symbols
            .by_c_name(s)
            .map(symbols::Symbol::full_rust_name)
            .unwrap_or_else(|| s.into())
    };

    let out = FUNCTION.replace_all(entry, |caps: &Captures<'_>| {
        let name = &caps[3];
        let sym = symbols.by_c_name(name);

        if let Some(sym) = sym {
            if sym.owner_name() == Some(in_type) {
                // `#` or `%` symbols should probably have been `@` to denote
                // that it is a reference within the current type.
                format!("[`Self::{}()`]", sym.name())
            } else {
                match caps.get(1).as_ref().map(Match::as_str) {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    Some("@") => format!(
                        "[`crate::{}()`] (XXX: @-reference does not belong to {}!)",
                        sym.full_rust_name(),
                        in_type,
                    ),
                    Some("#") | None => {
                        format!("[`crate::{}()`]", sym.full_rust_name())
                    }
                    Some("%") => panic!("% not allowed for {:?}", caps),
                    Some(c) => panic!("Unknown symbol reference {}", c),
                }
            }
        } else if let Some(typ) = caps.get(2) {
            let typ = typ.as_str();
            if typ == in_type {
                format!("[`Self::{}()`]", name)
            } else {
                format!("[`crate::{}{}()`]", typ, name)
            }
        } else {
            format!("`{}()`", name)
        }
    });

    let out = SYMBOL.replace_all(&out, |caps: &Captures<'_>| {
        let member = caps.get(4).map(|m| m.as_str()).unwrap_or("");
        let sym = symbols.by_c_name(&caps[3]);

        if let Some(sym) = sym {
            if sym.owner_name() == Some(in_type) {
                // `#` or `%` symbols should probably have been `@` to denote
                // that it is a reference within the current type.
                format!("{}[`Self::{}{}`]", &caps[1], sym.name(), member)
            } else {
                match &caps[2] {
                    // Catch invalid @ references that have a C symbol available but do not belong
                    // to the current type (and can hence not use `Self::`). For now generate XXX
                    // but with a valid global link so that the can be easily spotted in the code.
                    // assert_eq!(sym.owner_name(), Some(in_type));
                    "@" => format!(
                        "{}[`crate::{}{}`] (XXX: @-reference does not belong to {}!)",
                        &caps[1],
                        sym.full_rust_name(),
                        member,
                        in_type,
                    ),
                    "%" if sym.is_rust_prelude() => {
                        format!("{}[`{}{}`]", &caps[1], sym.full_rust_name(), member)
                    }
                    "#" | "%" => {
                        format!("{}[`crate::{}{}`]", &caps[1], sym.full_rust_name(), member)
                    }
                    c => panic!("Unknown symbol reference {}", c),
                }
            }
        } else {
            format!("{}`{}{}`", &caps[1], &caps[3], member)
        }
    });
    let out = GDK_GTK.replace_all(&out, |caps: &Captures<'_>| find_struct(&caps[0], env));
    let out = TAGS.replace_all(&out, "`$0`");
    SPACES.replace_all(&out, " ").into_owned()
}

fn find_struct(name: &str, env: &Env) -> String {
    let symbols = env.symbols.borrow();
    let symbol = if let Some(obj) = env
        .analysis
        .objects
        .iter()
        .find(|(_, o)| o.full_name == name)
        .map(|(_, o)| o)
    {
        symbols.by_tid(obj.type_id)
    } else if let Some(record) = env
        .analysis
        .records
        .iter()
        .find(|(_, r)| r.full_name == name)
        .map(|(_, r)| r)
    {
        symbols.by_tid(record.type_id)
    } else {
        None
    };
    symbol
        .map(|sym| format!("[{name}](crate::{name})", name = sym.full_rust_name()))
        .unwrap_or_else(|| format!("`{}`", name))
}
<|endoftext|>


<commit_before>use super::managed_display::ManagedDisplay;
use entities::{ EntitiesState, EntitiesHelper, EntityID, ComponentID, NativeComponentType };
use nalgebra::na::{ Mat4, Vec3, Eye };
use std::collections::{ HashSet, HashMap };
use std::sync::Arc;
use super::sprite_displayer::SpriteDisplayer;
use super::Drawable;

mod custom_display_system;

pub struct DisplaySystem {
	display: Arc<ManagedDisplay>,
	customDisplay: custom_display_system::CustomDisplaySystem,
	sprites: HashMap<ComponentID, SpriteDisplayer>,
	logger: Box<::log::Logger>
}

impl DisplaySystem {
	pub fn new<L: ::log::Logger + 'static>(display: Arc<ManagedDisplay>, state: &EntitiesState, mut logger: L)
		-> DisplaySystem
	{
		declmagic_info!(logger, "created display system");

		DisplaySystem {
			display: display.clone(),
			customDisplay: custom_display_system::CustomDisplaySystem::new(display.clone(), state, logger.clone()),
			sprites: HashMap::new(),
			logger: box logger
		}
	}

	pub fn draw(&mut self, state: &EntitiesState, _: &u64)
	{
		self.update_sprite_displayers(state);

		let camera = DisplaySystem::get_camera(state).unwrap_or_else(|| {
			declmagic_warn!(self.logger, "no active camera on the scene");
			Eye::new_identity(4)
		});

	 	for (cmp, sprite) in self.sprites.iter() {
	 		let pos = DisplaySystem::get_position(state, &state.get_owner(cmp).unwrap());
	 		let translationMatrix = Mat4::new(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, pos.x, pos.y, pos.z, 1.0);
			sprite.draw(&(translationMatrix * camera));
		}

		self.customDisplay.draw(state);
	}

	fn update_sprite_displayers(&mut self, state: &EntitiesState)
	{
		// getting the list of all sprite displayer components
		let listOfComponents = state.get_components_iter()
            .filter(|c| state.is_component_visible(*c).unwrap())
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "spriteDisplay", _ => false })
			.map(|c| c.clone())
			.collect::<HashSet<ComponentID>>();

		// removing from the list the elements that have disappeared
		{	let toRemove = self.sprites.keys().filter(|e| !listOfComponents.contains(e.clone())).map(|e| e.clone()).collect::<Vec<ComponentID>>();
			for c in toRemove.move_iter() {
				self.sprites.remove(&c);
			}
		}

		// adding elements that are not yet created
		{	let toCreate = listOfComponents.iter().filter(|e| !self.sprites.contains_key(e.clone())).map(|e| e.clone()).collect::<Vec<ComponentID>>();
			for spriteDisplayComponent in toCreate.move_iter() {
				// getting the name of the texture
				let textureName = match state.get_as_string(&spriteDisplayComponent, "texture") {
					Some(s) => s,
					_ => {
						declmagic_error!(self.logger, "component {} has no valid \"texture\" element", spriteDisplayComponent)
						continue
					}
				};

				let mut spriteDisplayer = SpriteDisplayer::new(self.display.clone(), textureName.as_slice()).unwrap();

				// getting coordinates
				spriteDisplayer.set_rectangle_coords(
					match state.get(&spriteDisplayComponent, "leftX") { Ok(&::entities::Number(ref nb)) => Some(*nb as f32), _ => None },
					match state.get(&spriteDisplayComponent, "topY") { Ok(&::entities::Number(ref nb)) => Some(*nb as f32), _ => None },
					match state.get(&spriteDisplayComponent, "rightX") { Ok(&::entities::Number(ref nb)) => Some(*nb as f32), _ => None },
					match state.get(&spriteDisplayComponent, "bottomY") { Ok(&::entities::Number(ref nb)) => Some(*nb as f32), _ => None }
				);

				// inserting in sprites list
				self.sprites.insert(spriteDisplayComponent.clone(), spriteDisplayer);
			}
		}
	}

	/// returns the camera matrix of the scene
	fn get_camera(state: &EntitiesState)
		-> Option<Mat4<f32>>
	{
		let cameraInfos = state
			.get_components_iter()
			.filter(|c| state.is_component_visible(*c).unwrap())
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "camera", _ => false })
			.max_by(|c| match state.get(*c, "priority") { Ok(&::entities::Number(ref n)) => (((*n) * 1000f64) as int), _ => 1000 })
			.and_then(|c| match state.get(c, "matrix") { Ok(&::entities::List(ref data)) => Some((c, data)), _ => None })
			.map(|(c, data)| (c, data.iter().filter_map(|elem| match elem { &::entities::Number(ref n) => Some(n.clone() as f32), _ => None }).collect::<Vec<f32>>()) );

		if cameraInfos.is_none() {
			return None;
		}

		let (cameraComponent, matrixData) = cameraInfos.unwrap();
		let matrix = Mat4::new(*matrixData.get(0), *matrixData.get(1), *matrixData.get(2), *matrixData.get(3), *matrixData.get(4), *matrixData.get(5), *matrixData.get(6), *matrixData.get(7), *matrixData.get(8), *matrixData.get(9), *matrixData.get(10), *matrixData.get(11), *matrixData.get(12), *matrixData.get(13), *matrixData.get(14), *matrixData.get(15));

		let position = DisplaySystem::get_position(state, &state.get_owner(cameraComponent).unwrap());
		let positionMatrix = Mat4::new(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -position.x, -position.y, -position.z, 1.0);

		Some(positionMatrix * matrix)
	}

	/// returns the position of an entity
	fn get_position(state: &EntitiesState, id: &EntityID)
		-> Vec3<f32>
	{
		state
			.get_components_iter()

			// filter out non-visible components
			.filter(|c| state.is_component_visible(*c).unwrap())

			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)

			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })

			// build a vector from each of the component
			.filter_map(|cmp| match (state.get(cmp, "x"), state.get(cmp, "y"), state.get(cmp, "z")) {
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), Ok(&::entities::Number(ref z)))
					=> Some(Vec3::new(*x as f32, *y as f32, *z as f32)),
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), _)
					=> Some(Vec3::new(*x as f32, *y as f32, 0.0)),
				_ => None
			})

			// add all the elements together
			.fold(Vec3::new(0.0, 0.0, 0.0), |vec, a| vec + a)
	}
}
<commit_msg>Display system now sees changes in sprites<commit_after>use super::managed_display::ManagedDisplay;
use entities::{ EntitiesState, EntitiesHelper, EntityID, ComponentID, NativeComponentType };
use nalgebra::na::{ Mat4, Vec3, Eye };
use std::collections::{ HashSet, HashMap };
use std::sync::Arc;
use super::sprite_displayer::SpriteDisplayer;
use super::Drawable;

mod custom_display_system;

pub struct DisplaySystem {
	display: Arc<ManagedDisplay>,
	customDisplay: custom_display_system::CustomDisplaySystem,
	sprites: HashMap<ComponentID, (Option<SpriteDisplayer>, String)>,
	logger: Box<::log::Logger>
}

impl DisplaySystem {
	pub fn new<L: ::log::Logger + 'static>(display: Arc<ManagedDisplay>, state: &EntitiesState, mut logger: L)
		-> DisplaySystem
	{
		declmagic_info!(logger, "created display system");

		DisplaySystem {
			display: display.clone(),
			customDisplay: custom_display_system::CustomDisplaySystem::new(display.clone(), state, logger.clone()),
			sprites: HashMap::new(),
			logger: box logger
		}
	}

	pub fn draw(&mut self, state: &EntitiesState, _: &u64)
	{
		self.update_sprite_displayers(state);

		let camera = DisplaySystem::get_camera(state).unwrap_or_else(|| {
			declmagic_warn!(self.logger, "no active camera on the scene");
			Eye::new_identity(4)
		});

	 	for (cmp, &(ref sprite, _)) in self.sprites.iter() {
	 		let pos = DisplaySystem::get_position(state, &state.get_owner(cmp).unwrap());
	 		let translationMatrix = Mat4::new(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, pos.x, pos.y, pos.z, 1.0);
			sprite.as_ref().map(|e| e.draw(&(translationMatrix * camera)));
		}

		self.customDisplay.draw(state);
	}

	fn update_sprite_displayers(&mut self, state: &EntitiesState)
	{
		// getting the list of all sprite displayer components
		let listOfComponents = state.get_components_iter()
            .filter(|c| state.is_component_visible(*c).unwrap())
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "spriteDisplay", _ => false })
			.map(|c| c.clone())
			.collect::<HashSet<ComponentID>>();

		// removing from the list the elements that have disappeared
		{	let toRemove = self.sprites.keys().filter(|e| !listOfComponents.contains(e.clone())).map(|e| e.clone()).collect::<Vec<ComponentID>>();
			for c in toRemove.move_iter() {
				self.sprites.remove(&c);
			}
		}

		// adding elements that are not yet created
		{	let toCreate = listOfComponents.iter().filter(|e| !self.sprites.contains_key(e.clone())).map(|e| e.clone()).collect::<Vec<ComponentID>>();
			for spriteDisplayComponent in toCreate.move_iter() {
				// inserting in sprites list
				self.sprites.insert(spriteDisplayComponent.clone(), (None, format!("")));
			}
		}

		// updating everything
		for (component, &(ref mut sprite, ref mut currTexName)) in self.sprites.mut_iter() {
			// getting the name of the texture
			let textureName = match state.get_as_string(component, "texture") {
				Some(s) => s,
				_ => {
					// TODO:
					//declmagic_error!(self.logger, "component {} has no valid \"texture\" element", component)
					continue
				}
			};

			if sprite.is_none() || currTexName.as_slice() != textureName.as_slice() {
				(*sprite) = Some(SpriteDisplayer::new(self.display.clone(), textureName.as_slice()).unwrap());
			}

			// getting coordinates
			match sprite {
				&Some(ref mut s) =>
					s.set_rectangle_coords(
						match state.get(component, "leftX") { Ok(&::entities::Number(ref nb)) => Some(*nb as f32), _ => None },
						match state.get(component, "topY") { Ok(&::entities::Number(ref nb)) => Some(*nb as f32), _ => None },
						match state.get(component, "rightX") { Ok(&::entities::Number(ref nb)) => Some(*nb as f32), _ => None },
						match state.get(component, "bottomY") { Ok(&::entities::Number(ref nb)) => Some(*nb as f32), _ => None }
					),
				_ => fail!()
			}
		}
	}

	/// returns the camera matrix of the scene
	fn get_camera(state: &EntitiesState)
		-> Option<Mat4<f32>>
	{
		let cameraInfos = state
			.get_components_iter()
			.filter(|c| state.is_component_visible(*c).unwrap())
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "camera", _ => false })
			.max_by(|c| match state.get(*c, "priority") { Ok(&::entities::Number(ref n)) => (((*n) * 1000f64) as int), _ => 1000 })
			.and_then(|c| match state.get(c, "matrix") { Ok(&::entities::List(ref data)) => Some((c, data)), _ => None })
			.map(|(c, data)| (c, data.iter().filter_map(|elem| match elem { &::entities::Number(ref n) => Some(n.clone() as f32), _ => None }).collect::<Vec<f32>>()) );

		if cameraInfos.is_none() {
			return None;
		}

		let (cameraComponent, matrixData) = cameraInfos.unwrap();
		let matrix = Mat4::new(*matrixData.get(0), *matrixData.get(1), *matrixData.get(2), *matrixData.get(3), *matrixData.get(4), *matrixData.get(5), *matrixData.get(6), *matrixData.get(7), *matrixData.get(8), *matrixData.get(9), *matrixData.get(10), *matrixData.get(11), *matrixData.get(12), *matrixData.get(13), *matrixData.get(14), *matrixData.get(15));

		let position = DisplaySystem::get_position(state, &state.get_owner(cameraComponent).unwrap());
		let positionMatrix = Mat4::new(1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -position.x, -position.y, -position.z, 1.0);

		Some(positionMatrix * matrix)
	}

	/// returns the position of an entity
	fn get_position(state: &EntitiesState, id: &EntityID)
		-> Vec3<f32>
	{
		state
			.get_components_iter()

			// filter out non-visible components
			.filter(|c| state.is_component_visible(*c).unwrap())

			// take only the components owned by the entity
			.filter(|c| state.get_owner(*c).unwrap() == *id)

			// take only the "position" components
			.filter(|c| match state.get_type(*c) { Ok(NativeComponentType(t)) => t.as_slice() == "position", _ => false })

			// build a vector from each of the component
			.filter_map(|cmp| match (state.get(cmp, "x"), state.get(cmp, "y"), state.get(cmp, "z")) {
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), Ok(&::entities::Number(ref z)))
					=> Some(Vec3::new(*x as f32, *y as f32, *z as f32)),
				(Ok(&::entities::Number(ref x)), Ok(&::entities::Number(ref y)), _)
					=> Some(Vec3::new(*x as f32, *y as f32, 0.0)),
				_ => None
			})

			// add all the elements together
			.fold(Vec3::new(0.0, 0.0, 0.0), |vec, a| vec + a)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// gpio_status.rs
//
// Retrieves the mode and logic level for each of the pins on the standard
// 40-pin GPIO header, and displays the results in an ASCII table.

use std::fmt;
use std::process::exit;

use rppal::gpio::Gpio;
use rppal::system::{DeviceInfo, Model};

enum PinType {
    Gpio(u8),
    Ground,
    Power3v3,
    Power5v,
}

impl fmt::Display for PinType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            PinType::Gpio(pin) => write!(f, "GPIO{}", pin),
            PinType::Ground => write!(f, "{:<5}", "GND"),
            PinType::Power3v3 => write!(f, "{:<5}", "3.3 V"),
            PinType::Power5v => write!(f, "{:<5}", "5 V"),
        }
    }
}

const HEADER_40: [PinType; 40] = [
    PinType::Power3v3, // Physical pin 1
    PinType::Power5v,  // Physical pin 2
    PinType::Gpio(2),  // Physical pin 3
    PinType::Power5v,  // Physical pin 4
    PinType::Gpio(3),  // Physical pin 5
    PinType::Ground,   // Physical pin 6
    PinType::Gpio(4),  // Physical pin 7
    PinType::Gpio(14), // Physical pin 8
    PinType::Ground,   // Physical pin 9
    PinType::Gpio(15), // Physical pin 10
    PinType::Gpio(17), // Physical pin 11
    PinType::Gpio(18), // Physical pin 12
    PinType::Gpio(27), // Physical pin 13
    PinType::Ground,   // Physical pin 14
    PinType::Gpio(22), // Physical pin 15
    PinType::Gpio(23), // Physical pin 16
    PinType::Power3v3, // Physical pin 17
    PinType::Gpio(24), // Physical pin 18
    PinType::Gpio(10), // Physical pin 19
    PinType::Ground,   // Physical pin 20
    PinType::Gpio(9),  // Physical pin 21
    PinType::Gpio(25), // Physical pin 22
    PinType::Gpio(11), // Physical pin 23
    PinType::Gpio(8),  // Physical pin 24
    PinType::Ground,   // Physical pin 25
    PinType::Gpio(7),  // Physical pin 26
    PinType::Gpio(0),  // Physical pin 27
    PinType::Gpio(1),  // Physical pin 28
    PinType::Gpio(5),  // Physical pin 29
    PinType::Ground,   // Physical pin 30
    PinType::Gpio(6),  // Physical pin 31
    PinType::Gpio(12), // Physical pin 32
    PinType::Gpio(13), // Physical pin 33
    PinType::Ground,   // Physical pin 34
    PinType::Gpio(19), // Physical pin 35
    PinType::Gpio(16), // Physical pin 36
    PinType::Gpio(26), // Physical pin 37
    PinType::Gpio(20), // Physical pin 38
    PinType::Ground,   // Physical pin 39
    PinType::Gpio(21), // Physical pin 40
];

fn print_gpio_status() {
    let gpio = Gpio::new().unwrap_or_else(|e| {
        println!("Error: Can't access GPIO peripheral ({})", e);
        exit(1);
    });

    println!("+------+-------+-------+-----------+-------+-------+------+");
    println!("| GPIO | Mode  | Level |    Pin    | Level | Mode  | GPIO |");
    println!("+------+-------+-------+-----+-----+-------+-------+------+");

    for (idx, pin_type) in HEADER_40.iter().enumerate() {
        match pin_type {
            PinType::Gpio(bcm) => {
                let pin = gpio.get(*bcm).unwrap_or_else(|| {
                    println!("\nError: Can't access GPIO pin {}", *bcm);;
                    exit(1);
                });

                if idx % 2 == 0 {
                    print!(
                        "| {:>4} | {:<5} | {:<5} | {:>3} |",
                        bcm,
                        format!("{}", pin.mode()).to_uppercase(),
                        format!("{}", pin.read()),
                        idx + 1
                    );
                } else {
                    println!(
                        " {:>3} | {:<5} | {:<5} | {:>4} |",
                        idx + 1,
                        format!("{}", pin.read()),
                        format!("{}", pin.mode()).to_uppercase(),
                        bcm,
                    );
                }
            }
            _ => {
                if idx % 2 == 0 {
                    print!("|      | {} |       | {:>3} |", pin_type, idx + 1);
                } else {
                    println!(" {:>3} |       | {} |      |", idx + 1, pin_type);
                }
            }
        };
    }

    println!("+------+-------+-------+-----+-----+-------+-------+------+");
}

fn main() {
    match DeviceInfo::new()
        .unwrap_or_else(|e| {
            println!("Error: Can't identify Raspberry Pi model ({})", e);
            exit(1);
        })
        .model()
    {
        Model::RaspberryPiAPlus
        | Model::RaspberryPiBPlus
        | Model::RaspberryPi2B
        | Model::RaspberryPi3APlus
        | Model::RaspberryPi3B
        | Model::RaspberryPi3BPlus
        | Model::RaspberryPiZero
        | Model::RaspberryPiZeroW => print_gpio_status(),
        model => {
            println!("No GPIO header information available for the {}.", model);
        }
    }
}
<commit_msg>Refactor print functions<commit_after>// Copyright (c) 2017-2018 Rene van der Meer
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

// gpio_status.rs
//
// Retrieves the mode and logic level for each of the pins on the standard
// 40-pin GPIO header, and displays the results in an ASCII table.

use std::fmt;
use std::process::exit;

use rppal::gpio::Gpio;
use rppal::system::{DeviceInfo, Model};

enum PinType {
    Gpio(u8),
    Ground,
    Power3v3,
    Power5v,
}

impl fmt::Display for PinType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            PinType::Gpio(pin) => write!(f, "GPIO{}", pin),
            PinType::Ground => write!(f, "{:<5}", "GND"),
            PinType::Power3v3 => write!(f, "{:<5}", "3.3 V"),
            PinType::Power5v => write!(f, "{:<5}", "5 V"),
        }
    }
}

const HEADER_40: [PinType; 40] = [
    PinType::Power3v3, // Physical pin 1
    PinType::Power5v,  // Physical pin 2
    PinType::Gpio(2),  // Physical pin 3
    PinType::Power5v,  // Physical pin 4
    PinType::Gpio(3),  // Physical pin 5
    PinType::Ground,   // Physical pin 6
    PinType::Gpio(4),  // Physical pin 7
    PinType::Gpio(14), // Physical pin 8
    PinType::Ground,   // Physical pin 9
    PinType::Gpio(15), // Physical pin 10
    PinType::Gpio(17), // Physical pin 11
    PinType::Gpio(18), // Physical pin 12
    PinType::Gpio(27), // Physical pin 13
    PinType::Ground,   // Physical pin 14
    PinType::Gpio(22), // Physical pin 15
    PinType::Gpio(23), // Physical pin 16
    PinType::Power3v3, // Physical pin 17
    PinType::Gpio(24), // Physical pin 18
    PinType::Gpio(10), // Physical pin 19
    PinType::Ground,   // Physical pin 20
    PinType::Gpio(9),  // Physical pin 21
    PinType::Gpio(25), // Physical pin 22
    PinType::Gpio(11), // Physical pin 23
    PinType::Gpio(8),  // Physical pin 24
    PinType::Ground,   // Physical pin 25
    PinType::Gpio(7),  // Physical pin 26
    PinType::Gpio(0),  // Physical pin 27
    PinType::Gpio(1),  // Physical pin 28
    PinType::Gpio(5),  // Physical pin 29
    PinType::Ground,   // Physical pin 30
    PinType::Gpio(6),  // Physical pin 31
    PinType::Gpio(12), // Physical pin 32
    PinType::Gpio(13), // Physical pin 33
    PinType::Ground,   // Physical pin 34
    PinType::Gpio(19), // Physical pin 35
    PinType::Gpio(16), // Physical pin 36
    PinType::Gpio(26), // Physical pin 37
    PinType::Gpio(20), // Physical pin 38
    PinType::Ground,   // Physical pin 39
    PinType::Gpio(21), // Physical pin 40
];

fn print_pin(
    pin: usize,
    gpio: impl fmt::Display,
    name: impl fmt::Display,
    level: impl fmt::Display,
) {
    if pin % 2 != 0 {
        print!("| {:>4} | {:<5} | {:<5} | {:>3} |", gpio, name, level, pin);
    } else {
        println!(" {:>3} | {:<5} | {:<5} | {:>4} |", pin, level, name, gpio);
    }
}

fn print_gpio_status() {
    let gpio = Gpio::new().unwrap_or_else(|e| {
        println!("Error: Can't access GPIO peripheral ({})", e);
        exit(1);
    });

    println!("+------+-------+-------+-----------+-------+-------+------+");
    println!("| GPIO | Mode  | Level |    Pin    | Level | Mode  | GPIO |");
    println!("+------+-------+-------+-----+-----+-------+-------+------+");

    for (idx, pin_type) in HEADER_40.iter().enumerate() {
        match pin_type {
            PinType::Gpio(bcm_gpio) => {
                let pin = gpio.get(*bcm_gpio).unwrap_or_else(|| {
                    println!("\nError: Can't access GPIO pin {}", *bcm_gpio);
                    exit(1);
                });

                print_pin(
                    idx + 1,
                    bcm_gpio,
                    format!("{}", pin.mode()).to_uppercase(),
                    format!("{}", pin.read()),
                );
            }
            _ => print_pin(idx + 1, "", pin_type, ""),
        };
    }

    println!("+------+-------+-------+-----+-----+-------+-------+------+");
}

fn main() {
    match DeviceInfo::new()
        .unwrap_or_else(|e| {
            println!("Error: Can't identify Raspberry Pi model ({})", e);
            exit(1);
        })
        .model()
    {
        Model::RaspberryPiAPlus
        | Model::RaspberryPiBPlus
        | Model::RaspberryPi2B
        | Model::RaspberryPi3APlus
        | Model::RaspberryPi3B
        | Model::RaspberryPi3BPlus
        | Model::RaspberryPiZero
        | Model::RaspberryPiZeroW => print_gpio_status(),
        model => {
            println!("No GPIO header information available for the {}.", model);
        }
    }
}
<|endoftext|>