<commit_before>// A parser combinator that scans for zeros in a number of bytes. When the
// current byte is all zeros, the parser fails. The last argument is the bit
// offset relative the first byte being parsed.
macro_rules! skip_bytes (
  ($input: expr, $length: expr, $offset: expr) => (
    {
      match take!($input, $length) {
        $crate::nom::IResult::Done(i, bytes)   => {
          let head        = bytes[0] << $offset;
          let tail        = &bytes[1..];
          let is_all_zero = tail.iter().all(|byte| *byte == 0);

          if head == 0 && is_all_zero {
            $crate::nom::IResult::Done(i, bytes)
          } else {
            $crate::nom::IResult::Error($crate::nom::Err::Position(
              $crate::nom::ErrorKind::Digit, $input))
          }
        }
        $crate::nom::IResult::Error(error)     =>
          $crate::nom::IResult::Error(error),
        $crate::nom::IResult::Incomplete(need) =>
          $crate::nom::IResult::Incomplete(need),
      }
    }
  );
  ($input: expr, $length: expr) => (
    skip_bytes!($input, $length, 0);
  );
);

// A parser combiner for previously allocated buffers that can be passed
// in as mutable slices. The macro will parse and fill the total length of
// the passed in slice.
macro_rules! count_slice (
  ($input: expr, $submac: ident!( $($args:tt)* ), $result: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;

      for result in $result {
        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            *result = o;

            input   = i;
            count  += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorKind::Count, $input))
      } else if count == $result.len() {
        $crate::nom::IResult::Done(input, ())
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_slice!($i, call!($f), $count);
  );
);

// A parser combinator for converting parsed unsigned numbers into signed
// two's complement based numbers. Without an explicit type passed in, the
// default return type is `i32`.
macro_rules! take_signed_bits (
  ($input: expr, $signed_type: ty, $count: expr) => (
    map!($input, take_bits!(u32, $count), |value| {
      ::utility::extend_sign(value, $count) as $signed_type
    });
  );
  ($input: expr, $count: expr) => (
    take_signed_bits!($input, i32, $count);
  );
);

macro_rules! to_custom_error (
  ($error_type: ident) => (
    |_| $crate::nom::Err::Code($crate::nom::ErrorKind::Custom(
          ::utility::ErrorKind::$error_type))
  );
);
<commit_msg>Add `try_parser!` macro<commit_after>// A parser combinator that scans for zeros in a number of bytes. When the
// current byte is all zeros, the parser fails. The last argument is the bit
// offset relative the first byte being parsed.
macro_rules! skip_bytes (
  ($input: expr, $length: expr, $offset: expr) => (
    {
      match take!($input, $length) {
        $crate::nom::IResult::Done(i, bytes)   => {
          let head        = bytes[0] << $offset;
          let tail        = &bytes[1..];
          let is_all_zero = tail.iter().all(|byte| *byte == 0);

          if head == 0 && is_all_zero {
            $crate::nom::IResult::Done(i, bytes)
          } else {
            $crate::nom::IResult::Error($crate::nom::Err::Position(
              $crate::nom::ErrorKind::Digit, $input))
          }
        }
        $crate::nom::IResult::Error(error)     =>
          $crate::nom::IResult::Error(error),
        $crate::nom::IResult::Incomplete(need) =>
          $crate::nom::IResult::Incomplete(need),
      }
    }
  );
  ($input: expr, $length: expr) => (
    skip_bytes!($input, $length, 0);
  );
);

// A parser combiner for previously allocated buffers that can be passed
// in as mutable slices. The macro will parse and fill the total length of
// the passed in slice.
macro_rules! count_slice (
  ($input: expr, $submac: ident!( $($args:tt)* ), $result: expr) => (
    {
      let mut input    = $input;
      let mut count    = 0;
      let mut is_error = false;

      for result in $result {
        match $submac!(input, $($args)*) {
          $crate::nom::IResult::Done(i, o)    => {
            *result = o;

            input   = i;
            count  += 1;
          }
          $crate::nom::IResult::Error(_)      => {
            is_error = true;
            break;
          }
          $crate::nom::IResult::Incomplete(_) => break,
        }
      }

      if is_error {
        $crate::nom::IResult::Error($crate::nom::Err::Position(
          $crate::nom::ErrorKind::Count, $input))
      } else if count == $result.len() {
        $crate::nom::IResult::Done(input, ())
      } else {
        $crate::nom::IResult::Incomplete($crate::nom::Needed::Unknown)
      }
    }
  );
  ($i: expr, $f: expr, $count: expr) => (
    count_slice!($i, call!($f), $count);
  );
);

// A parser combinator for converting parsed unsigned numbers into signed
// two's complement based numbers. Without an explicit type passed in, the
// default return type is `i32`.
macro_rules! take_signed_bits (
  ($input: expr, $signed_type: ty, $count: expr) => (
    map!($input, take_bits!(u32, $count), |value| {
      ::utility::extend_sign(value, $count) as $signed_type
    });
  );
  ($input: expr, $count: expr) => (
    take_signed_bits!($input, i32, $count);
  );
);

macro_rules! to_custom_error (
  ($error_type: ident) => (
    |_| $crate::nom::Err::Code($crate::nom::ErrorKind::Custom(
          ::utility::ErrorKind::$error_type))
  );
);

macro_rules! try_parser (
  ($iresult: expr) => (
    match $iresult {
      $crate::nom::IResult::Done(i, o)    => (i, o),
      $crate::nom::IResult::Error(e)      =>
        return $crate::nom::IResult::Error(e),
      $crate::nom::IResult::Incomplete(i) =>
        return $crate::nom::IResult::Incomplete(i),
    }
  )
);
<|endoftext|>


<commit_before>use super::super::{Grid, Coord};
use super::*;

#[derive(Debug, Clone, Copy, PartialEq)]
enum EvCand {
    Ok,
    Elim(f64),
}

#[derive(Debug)]
enum Move {
    Decide(f64, usize, i32),
    Elim(f64, Vec<(usize, i32)>),
}

pub struct Evaluator {
    n_cells: usize,
    shape: FieldShape,
    val: Vec<i32>,
    clue: Vec<i32>,
    cand_score: Vec<[EvCand; (MAX_VAL + 1) as usize]>, // 1-origin for simplicity
    total_score: f64,
    inconsistent: bool,
    move_cand: Vec<Move>,
}

const UNIQUE_ELIMINATION: f64 = 0.8f64;
const SMALL_LARGE_ELIMINATION: f64 = 1.0f64;

impl Evaluator {
    pub fn new(problem: &Grid<Clue>) -> Evaluator {
        let n_cells = (problem.height() * problem.width()) as usize;

        let mut has_clue = Grid::new(problem.height(), problem.width(), false);
        for i in 0..n_cells {
            if let Clue::Clue { vertical: _, horizontal: _ } = problem[i] {
                has_clue[i] = true;
            }
        }
        let shape = FieldShape::new(&has_clue);
        let mut clue = vec![0; shape.group_to_cells.len()];
        for i in 0..shape.group_to_cells.len() {
            let clue_loc = shape.clue_locations[i];
            clue[i] = match clue_loc {
                ClueLocation::Horizontal(h) => match problem[h] {
                    Clue::Clue { horizontal: h, vertical: _ } => h,
                    _ => unreachable!(),
                },
                ClueLocation::Vertical(v) => match problem[v] {
                    Clue::Clue { horizontal: _, vertical: v } => v,
                    _ => unreachable!(),
                },
            }
        }
        Evaluator {
            n_cells: n_cells,
            shape: shape,
            val: vec![UNDECIDED; n_cells],
            clue: clue,
            cand_score: vec![[EvCand::Ok; (MAX_VAL + 1) as usize]; n_cells],
            total_score: 0.0f64,
            inconsistent: false,
            move_cand: vec![],
        }
    }
    pub fn evaluate(&mut self) -> Option<f64> {
        let mut n_undecided = 0;
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] {
                n_undecided += 1;
            }
        }
        loop {
            self.move_cand.clear();

            // apply possible eliminations
            self.simple_elimination();
            self.unique_decision();
            self.unique_decision();

            self.remove_unnecessary_move();

            if self.move_cand.len() == 0 {
                break;
            }

            let mut lowest_decision = (1e20f64, 0, 0);
            let mut lowest_elim = (1e20f64, vec![]);
            for mv in &self.move_cand {
                match mv {
                    &Move::Decide(score, loc, v) => if score < lowest_decision.0 {
                        lowest_decision = (score, loc, v);
                    },
                    &Move::Elim(score, ref elims) => if score < lowest_elim.0 {
                        lowest_elim = (score, elims.clone());
                    }
                }
            }
            if lowest_elim.0 < lowest_decision.0 * 11.0f64 {
                // use elim
                for (loc, v) in lowest_elim.1 {
                    self.cand_score[loc][v as usize] = EvCand::Elim(lowest_elim.0);
                }
            } else {
                // use lowest_decision
                let mut move_score = 0.0f64;
                for mv in &self.move_cand {
                    if let &Move::Decide(score, _, _) = mv {
                        move_score += score.powf(-2.0f64);
                    }
                }
                move_score = move_score.powf(-1.0 / 2.0f64);
                move_score *= (n_undecided as f64).powf(0.3);

                self.total_score += move_score;
                self.val[lowest_decision.1] = lowest_decision.2;
                n_undecided -= 1;
            }
        }
        if n_undecided == 0 {
            Some(self.total_score)
        } else {
            None
        }
    }
    fn remove_unnecessary_move(&mut self) {
        let mut new_cand = vec![];
        for m in &self.move_cand {
            match m {
                &Move::Decide(score, loc, v) =>
                    if self.val[loc] == UNDECIDED {
                        new_cand.push(Move::Decide(score, loc, v))
                    },
                &Move::Elim(score, ref elims) => {
                    let mut new_elims = vec![];
                    for &(loc, v) in elims {
                        let isok = match self.cand_score[loc][v as usize] {
                            EvCand::Ok => true,
                            EvCand::Elim(sc) => score < sc,
                        };
                        if isok {
                            new_elims.push((loc, v));
                        }
                    }
                    if new_elims.len() > 0 {
                        new_cand.push(Move::Elim(score, new_elims));
                    }
                },
            }
        }
        self.move_cand = new_cand;
    }
    fn simple_elimination(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut used_mask = 0u32; // bit indices are 1-origin
            let mut rem_sum = self.clue[gi];
            for c in self.shape.group_to_cells[gi] {
                if self.val[c] != UNDECIDED {
                    used_mask |= 1u32 << self.val[c];
                    rem_sum -= self.val[c];
                }
            }
            let rem_cells = self.shape.group_to_cells[gi].size() as i32 - used_mask.count_ones() as i32;
            if rem_cells == 0 {
                continue;
            }
            if rem_cells == 1 {
                let mut ep = 0;
                for c in self.shape.group_to_cells[gi] {
                    if self.val[c] == UNDECIDED {
                        ep = c;
                    }
                }
                self.move_cand.push(Move::Decide(4.0, ep, rem_sum));
                continue;
            }

            let mut allowed_cand = ((2u32 << MAX_VAL) - 2u32) ^ used_mask;
            let mut required = 0u32;
            // eliminate too large candidates
            {
                let mut sum_small = 0;
                let mut n_cand_checked = 0;
                let mut max_cand_checked = 0;
                let mut low_bits = 0;
                for i in 1..(MAX_VAL + 1) {
                    if n_cand_checked == rem_cells - 1 {
                        break;
                    }
                    if (allowed_cand & (1u32 << i)) != 0 {
                        sum_small += i;
                        n_cand_checked += 1;
                        max_cand_checked = i;
                        low_bits |= 1u32 << i;
                    }
                }
                let mut max_allowed = rem_sum - sum_small;

                if max_allowed <= max_cand_checked {
                    self.inconsistent = true;
                    return;
                }
                if max_allowed < MAX_VAL {
                    if max_allowed == max_cand_checked + 2 {
                        allowed_cand &= !(1u32 << (max_cand_checked + 1));
                    }
                    allowed_cand &= (2u32 << max_allowed) - 2u32;
                }
                if max_allowed == max_cand_checked + 1 {
                    required |= low_bits | (1u32 << (max_cand_checked + 1));
                } else if max_allowed == max_cand_checked + 2 {
                    required |= low_bits | (1u32 << (max_cand_checked + 2));
                }
            }
            {
                let mut sum_large = 0;
                let mut n_cand_checked = 0;
                let mut min_cand_checked = 0;
                let mut high_bits = 0u32;
                for i in 1..(MAX_VAL + 1) {
                    let i = MAX_VAL + 1 - i;
                    if n_cand_checked == rem_cells - 1 {
                        break;
                    }
                    if (allowed_cand & (1u32 << i)) != 0 {
                        sum_large += i;
                        n_cand_checked += 1;
                        min_cand_checked = i;
                        high_bits |= 1u32 << i;
                    }
                }
                let mut min_allowed = rem_sum - sum_large;

                if min_allowed >= min_cand_checked {
                    self.inconsistent = true;
                    return;
                }
                if min_allowed > 1 {
                    if min_allowed == min_cand_checked - 2 {
                        allowed_cand &= !(1u32 << (min_cand_checked - 1));
                    }
                    allowed_cand &= !((2u32 << (min_allowed - 1)) - 2u32);
                }
                if min_allowed == min_cand_checked - 1 {
                    required |= high_bits | (1u32 << (min_cand_checked - 1));
                } else if min_allowed == min_cand_checked - 2 {
                    required |= high_bits | (1u32 << (min_cand_checked - 2));
                }
            }

            let mut elims = vec![];
            for n in 1..(MAX_VAL + 1) {
                if (allowed_cand & (1u32 << n)) == 0 {
                    for c in self.shape.group_to_cells[gi] {
                        if self.val[c] == UNDECIDED {
                            elims.push((c, n));
                        }
                    }
                }
            }
            self.move_cand.push(Move::Elim(SMALL_LARGE_ELIMINATION, elims));

            for n in 1..(MAX_VAL + 1) {
                if (required & (1u32 << n)) != 0 {
                    let mut cost = 0.0f64;
                    let mut pos = None;
                    let mut twice = false;
                    for c in self.shape.group_to_cells[gi] {
                        if self.val[c] == UNDECIDED {
                            if let EvCand::Elim(s) = self.cand_score[c][n as usize] {
                                cost += s;
                            } else {
                                if pos == None {
                                    pos = Some(c);
                                } else {
                                    twice = true;
                                    break;
                                }
                            }
                        } else if self.val[c] == n {
                            twice = true;
                            break;
                        }
                    }
                    if !twice {
                        if let Some(c) = pos {
                            self.move_cand.push(Move::Decide(cost + 4.0, c, n));
                        } else {
                            self.inconsistent = true;
                            return;
                        }
                    }
                }
            }
        }
    }
    fn unique_elimination(&mut self) {
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] && self.val[i] != UNDECIDED {
                let (g1, g2) = self.shape.cell_to_groups[i];
                let mut mv = vec![];
                for c in self.shape.group_to_cells[g1] {
                    if c != i {
                        mv.push((c, self.val[i]));
                    }
                }
                for c in self.shape.group_to_cells[g2] {
                    if c != i {
                        mv.push((c, self.val[i]));
                    }
                }
                self.move_cand.push(Move::Elim(UNIQUE_ELIMINATION, mv));
            }
        }
    }
    fn unique_decision(&mut self) {
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] {
                let mut cost = 0.0f64;
                let mut cand = -1;
                for v in 1..(MAX_VAL + 1) {
                    match self.cand_score[i][v as usize] {
                        EvCand::Ok => if cand == -1 {
                            cand = v;
                        } else {
                            cand = -2;
                        },
                        EvCand::Elim(c) => cost += c,
                    }
                }
                if cand == -1 {
                    self.inconsistent = true;
                    return;
                } else if cand != -2 {
                    self.move_cand.push(Move::Decide(cost, i, cand));
                }
            }
        }
    }
}
<commit_msg>Kakuro: add two_cells_propagation in Evaluator<commit_after>use super::super::{Grid, Coord};
use super::*;

#[derive(Debug, Clone, Copy, PartialEq)]
enum EvCand {
    Ok,
    Elim(f64),
}

#[derive(Debug)]
enum Move {
    Decide(f64, usize, i32),
    Elim(f64, Vec<(usize, i32)>),
}

pub struct Evaluator {
    n_cells: usize,
    shape: FieldShape,
    val: Vec<i32>,
    clue: Vec<i32>,
    cand_score: Vec<[EvCand; (MAX_VAL + 1) as usize]>, // 1-origin for simplicity
    total_score: f64,
    inconsistent: bool,
    move_cand: Vec<Move>,
}

const UNIQUE_ELIMINATION: f64 = 0.8f64;
const SMALL_LARGE_ELIMINATION: f64 = 1.0f64;

impl Evaluator {
    pub fn new(problem: &Grid<Clue>) -> Evaluator {
        let n_cells = (problem.height() * problem.width()) as usize;

        let mut has_clue = Grid::new(problem.height(), problem.width(), false);
        for i in 0..n_cells {
            if let Clue::Clue { vertical: _, horizontal: _ } = problem[i] {
                has_clue[i] = true;
            }
        }
        let shape = FieldShape::new(&has_clue);
        let mut clue = vec![0; shape.group_to_cells.len()];
        for i in 0..shape.group_to_cells.len() {
            let clue_loc = shape.clue_locations[i];
            clue[i] = match clue_loc {
                ClueLocation::Horizontal(h) => match problem[h] {
                    Clue::Clue { horizontal: h, vertical: _ } => h,
                    _ => unreachable!(),
                },
                ClueLocation::Vertical(v) => match problem[v] {
                    Clue::Clue { horizontal: _, vertical: v } => v,
                    _ => unreachable!(),
                },
            }
        }
        Evaluator {
            n_cells: n_cells,
            shape: shape,
            val: vec![UNDECIDED; n_cells],
            clue: clue,
            cand_score: vec![[EvCand::Ok; (MAX_VAL + 1) as usize]; n_cells],
            total_score: 0.0f64,
            inconsistent: false,
            move_cand: vec![],
        }
    }
    pub fn evaluate(&mut self) -> Option<f64> {
        let mut n_undecided = 0;
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] {
                n_undecided += 1;
            }
        }
        loop {
            self.move_cand.clear();

            // apply possible eliminations
            self.simple_elimination();
            self.unique_decision();
            self.unique_decision();
            self.two_cells_propagation();

            self.remove_unnecessary_move();

            if self.move_cand.len() == 0 {
                break;
            }

            let mut lowest_decision = (1e20f64, 0, 0);
            let mut lowest_elim = (1e20f64, vec![]);
            for mv in &self.move_cand {
                match mv {
                    &Move::Decide(score, loc, v) => if score < lowest_decision.0 {
                        lowest_decision = (score, loc, v);
                    },
                    &Move::Elim(score, ref elims) => if score < lowest_elim.0 {
                        lowest_elim = (score, elims.clone());
                    }
                }
            }
            if lowest_elim.0 < lowest_decision.0 * 11.0f64 {
                // use elim
                for (loc, v) in lowest_elim.1 {
                    self.cand_score[loc][v as usize] = EvCand::Elim(lowest_elim.0);
                }
            } else {
                // use lowest_decision
                let mut move_score = 0.0f64;
                for mv in &self.move_cand {
                    if let &Move::Decide(score, _, _) = mv {
                        move_score += score.powf(-2.0f64);
                    }
                }
                move_score = move_score.powf(-1.0 / 2.0f64);
                move_score *= (n_undecided as f64).powf(0.3);

                self.total_score += move_score;
                self.val[lowest_decision.1] = lowest_decision.2;
                n_undecided -= 1;
            }
        }
        if n_undecided == 0 {
            Some(self.total_score)
        } else {
            None
        }
    }
    fn remove_unnecessary_move(&mut self) {
        let mut new_cand = vec![];
        for m in &self.move_cand {
            match m {
                &Move::Decide(score, loc, v) =>
                    if self.val[loc] == UNDECIDED {
                        new_cand.push(Move::Decide(score, loc, v))
                    },
                &Move::Elim(score, ref elims) => {
                    let mut new_elims = vec![];
                    for &(loc, v) in elims {
                        let isok = match self.cand_score[loc][v as usize] {
                            EvCand::Ok => true,
                            EvCand::Elim(sc) => score < sc,
                        };
                        if isok {
                            new_elims.push((loc, v));
                        }
                    }
                    if new_elims.len() > 0 {
                        new_cand.push(Move::Elim(score, new_elims));
                    }
                },
            }
        }
        self.move_cand = new_cand;
    }
    fn simple_elimination(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut used_mask = 0u32; // bit indices are 1-origin
            let mut rem_sum = self.clue[gi];
            for c in self.shape.group_to_cells[gi] {
                if self.val[c] != UNDECIDED {
                    used_mask |= 1u32 << self.val[c];
                    rem_sum -= self.val[c];
                }
            }
            let rem_cells = self.shape.group_to_cells[gi].size() as i32 - used_mask.count_ones() as i32;
            if rem_cells == 0 {
                continue;
            }
            if rem_cells == 1 {
                let mut ep = 0;
                for c in self.shape.group_to_cells[gi] {
                    if self.val[c] == UNDECIDED {
                        ep = c;
                    }
                }
                self.move_cand.push(Move::Decide(4.0, ep, rem_sum));
                continue;
            }

            let mut allowed_cand = ((2u32 << MAX_VAL) - 2u32) ^ used_mask;
            let mut required = 0u32;
            // eliminate too large candidates
            {
                let mut sum_small = 0;
                let mut n_cand_checked = 0;
                let mut max_cand_checked = 0;
                let mut low_bits = 0;
                for i in 1..(MAX_VAL + 1) {
                    if n_cand_checked == rem_cells - 1 {
                        break;
                    }
                    if (allowed_cand & (1u32 << i)) != 0 {
                        sum_small += i;
                        n_cand_checked += 1;
                        max_cand_checked = i;
                        low_bits |= 1u32 << i;
                    }
                }
                let mut max_allowed = rem_sum - sum_small;

                if max_allowed <= max_cand_checked {
                    self.inconsistent = true;
                    return;
                }
                if max_allowed < MAX_VAL {
                    if max_allowed == max_cand_checked + 2 {
                        allowed_cand &= !(1u32 << (max_cand_checked + 1));
                    }
                    allowed_cand &= (2u32 << max_allowed) - 2u32;
                }
                if max_allowed == max_cand_checked + 1 {
                    required |= low_bits | (1u32 << (max_cand_checked + 1));
                } else if max_allowed == max_cand_checked + 2 {
                    required |= low_bits | (1u32 << (max_cand_checked + 2));
                }
            }
            {
                let mut sum_large = 0;
                let mut n_cand_checked = 0;
                let mut min_cand_checked = 0;
                let mut high_bits = 0u32;
                for i in 1..(MAX_VAL + 1) {
                    let i = MAX_VAL + 1 - i;
                    if n_cand_checked == rem_cells - 1 {
                        break;
                    }
                    if (allowed_cand & (1u32 << i)) != 0 {
                        sum_large += i;
                        n_cand_checked += 1;
                        min_cand_checked = i;
                        high_bits |= 1u32 << i;
                    }
                }
                let mut min_allowed = rem_sum - sum_large;

                if min_allowed >= min_cand_checked {
                    self.inconsistent = true;
                    return;
                }
                if min_allowed > 1 {
                    if min_allowed == min_cand_checked - 2 {
                        allowed_cand &= !(1u32 << (min_cand_checked - 1));
                    }
                    allowed_cand &= !((2u32 << (min_allowed - 1)) - 2u32);
                }
                if min_allowed == min_cand_checked - 1 {
                    required |= high_bits | (1u32 << (min_cand_checked - 1));
                } else if min_allowed == min_cand_checked - 2 {
                    required |= high_bits | (1u32 << (min_cand_checked - 2));
                }
            }

            let mut elims = vec![];
            for n in 1..(MAX_VAL + 1) {
                if (allowed_cand & (1u32 << n)) == 0 {
                    for c in self.shape.group_to_cells[gi] {
                        if self.val[c] == UNDECIDED {
                            elims.push((c, n));
                        }
                    }
                }
            }
            self.move_cand.push(Move::Elim(SMALL_LARGE_ELIMINATION, elims));

            for n in 1..(MAX_VAL + 1) {
                if (required & (1u32 << n)) != 0 {
                    let mut cost = 0.0f64;
                    let mut pos = None;
                    let mut twice = false;
                    for c in self.shape.group_to_cells[gi] {
                        if self.val[c] == UNDECIDED {
                            if let EvCand::Elim(s) = self.cand_score[c][n as usize] {
                                cost += s;
                            } else {
                                if pos == None {
                                    pos = Some(c);
                                } else {
                                    twice = true;
                                    break;
                                }
                            }
                        } else if self.val[c] == n {
                            twice = true;
                            break;
                        }
                    }
                    if !twice {
                        if let Some(c) = pos {
                            self.move_cand.push(Move::Decide(cost + 4.0, c, n));
                        } else {
                            self.inconsistent = true;
                            return;
                        }
                    }
                }
            }
        }
    }
    fn unique_elimination(&mut self) {
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] && self.val[i] != UNDECIDED {
                let (g1, g2) = self.shape.cell_to_groups[i];
                let mut mv = vec![];
                for c in self.shape.group_to_cells[g1] {
                    if c != i {
                        mv.push((c, self.val[i]));
                    }
                }
                for c in self.shape.group_to_cells[g2] {
                    if c != i {
                        mv.push((c, self.val[i]));
                    }
                }
                self.move_cand.push(Move::Elim(UNIQUE_ELIMINATION, mv));
            }
        }
    }
    fn unique_decision(&mut self) {
        for i in 0..self.n_cells {
            if !self.shape.has_clue[i] {
                let mut cost = 0.0f64;
                let mut cand = -1;
                for v in 1..(MAX_VAL + 1) {
                    match self.cand_score[i][v as usize] {
                        EvCand::Ok => if cand == -1 {
                            cand = v;
                        } else {
                            cand = -2;
                        },
                        EvCand::Elim(c) => cost += c,
                    }
                }
                if cand == -1 {
                    self.inconsistent = true;
                    return;
                } else if cand != -2 {
                    self.move_cand.push(Move::Decide(cost, i, cand));
                }
            }
        }
    }
    fn two_cells_propagation(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut used_mask = 0u32; // bit indices are 1-origin
            let mut rem_sum = self.clue[gi];
            let mut undet1 = None;
            let mut undet2 = None;
            let mut more_than_two = false;
            for c in self.shape.group_to_cells[gi] {
                if self.val[c] == UNDECIDED {
                    if undet1 == None {
                        undet1 = Some(c);
                    } else if undet2 == None {
                        undet2 = Some(c);
                    } else {
                        more_than_two = true;
                    }
                } else {
                    rem_sum -= self.val[c];
                }
            }
            if !more_than_two && undet2 != None {
                if let (Some(c1), Some(c2)) = (undet1, undet2) {
                    for n in 1..(MAX_VAL + 1) {
                        if let EvCand::Elim(s) = self.cand_score[c1][n as usize] {
                            let n2 = rem_sum - n;
                            if 1 <= n2 && n2 <= MAX_VAL {
                                self.move_cand.push(Move::Elim(s + 5.0f64, vec![(c2, n2)]));
                            }
                        }
                        if let EvCand::Elim(s) = self.cand_score[c2][n as usize] {
                            let n2 = rem_sum - n;
                            if 1 <= n2 && n2 <= MAX_VAL {
                                self.move_cand.push(Move::Elim(s + 5.0f64, vec![(c1, n2)]));
                            }
                        }
                    }
                } else {
                    unreachable!();
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use crate::direction::{Absolute, Direction, Relative};
use crate::event::{Event, EventResult, Key};
use crate::rect::Rect;
use crate::view::IntoBoxedView;
use crate::{Printer, Vec2, View, With};

/// Arranges its children in a fixed layout.
///
/// Usually meant to use an external layout engine.
///
/// # Examples
///
/// ```rust
/// use cursive_core::{
///     views::{FixedLayout, TextView, Button},
///     Rect,
/// };
///
/// let layout = FixedLayout::new()
///     .child(Rect::from_size((0,0), (1,1)), TextView::new("/"))
///     .child(Rect::from_size((14,0), (1,1)), TextView::new(r"\"))
///     .child(Rect::from_size((0,2), (1,1)), TextView::new(r"\"))
///     .child(Rect::from_size((14,2), (1,1)), TextView::new("/"))
///     .child(Rect::from_size((3,1), (11,1)), Button::new("Clickme", |s| s.quit()));
/// ````
pub struct FixedLayout {
    children: Vec<Child>,
    focus: usize,
}

/// Represents a child view inside the FixedLayout.
struct Child {
    view: Box<dyn View>,
    position: Rect,
}

new_default!(FixedLayout);

impl FixedLayout {
    /// Returns a new, empty `FixedLayout`.
    pub fn new() -> Self {
        FixedLayout {
            children: Vec::new(),
            focus: 0,
        }
    }

    /// Adds a child. Chainable variant.
    pub fn child<V: IntoBoxedView>(self, position: Rect, view: V) -> Self {
        self.with(|s| s.add_child(position, view))
    }

    /// Adds a child.
    pub fn add_child<V: IntoBoxedView>(&mut self, position: Rect, view: V) {
        self.children.push(Child {
            view: view.as_boxed_view(),
            position,
        });
    }

    /// Returns index of focused inner view
    pub fn get_focus_index(&self) -> usize {
        self.focus
    }

    /// Attemps to set the focus on the given child.
    ///
    /// Returns `Err(())` if `index >= self.len()`, or if the view at the
    /// given index does not accept focus.
    pub fn set_focus_index(&mut self, index: usize) -> Result<(), ()> {
        if self
            .children
            .get_mut(index)
            .map(|child| child.view.take_focus(Direction::none()))
            .unwrap_or(false)
        {
            self.focus = index;
            Ok(())
        } else {
            Err(())
        }
    }

    /// How many children are in this view.
    pub fn len(&self) -> usize {
        self.children.len()
    }

    /// Returns `true` if this view has no children.
    pub fn is_empty(&self) -> bool {
        self.children.is_empty()
    }

    /// Returns a reference to a child.
    pub fn get_child(&self, i: usize) -> Option<&dyn View> {
        self.children.get(i).map(|c| &*c.view)
    }

    /// Returns a mutable reference to a child.
    pub fn get_child_mut(&mut self, i: usize) -> Option<&mut dyn View> {
        self.children.get_mut(i).map(|c| &mut *c.view)
    }

    /// Sets the position for the given child.
    pub fn set_child_position(&mut self, i: usize, position: Rect) {
        self.children[i].position = position;
    }

    /// Removes a child.
    ///
    /// If `i` is within bounds, the removed child will be returned.
    pub fn remove_child(&mut self, i: usize) -> Option<Box<dyn View>> {
        if i >= self.len() {
            return None;
        }

        if self.focus > i
            || (self.focus != 0 && self.focus == self.children.len() - 1)
        {
            self.focus -= 1;
        }

        Some(self.children.remove(i).view)
    }

    fn iter_mut<'a>(
        source: Direction,
        children: &'a mut [Child],
    ) -> Box<dyn Iterator<Item = (usize, &mut Child)> + 'a> {
        let children = children.iter_mut().enumerate();
        match source {
            Direction::Rel(Relative::Front) => Box::new(children),
            Direction::Rel(Relative::Back) => Box::new(children.rev()),
            Direction::Abs(abs) => {
                // Sort children by the given direction
                let mut children: Vec<_> = children.collect();
                children.sort_by_key(|(_, c)| c.position.edge(abs));
                Box::new(children.into_iter())
            }
        }
    }

    fn circular_mut<'a>(
        start: usize,
        children: &'a mut [Child],
    ) -> impl Iterator<Item = (usize, &mut Child)> + 'a {
        let (head, tail) = children.split_at_mut(start);

        let head = head.iter_mut().enumerate();
        let tail = tail
            .iter_mut()
            .enumerate()
            .map(move |(i, c)| (i + start, c));

        tail.chain(head)
    }

    fn move_focus_rel(&mut self, target: Relative) -> EventResult {
        let source = Direction::Rel(target.swap());
        for (i, c) in
            Self::iter_mut(source, &mut self.children).skip(self.focus + 1)
        {
            if c.view.take_focus(source) {
                self.focus = i;
                return EventResult::Consumed(None);
            }
        }

        EventResult::Ignored
    }

    fn move_focus_abs(&mut self, target: Absolute) -> EventResult {
        let source = Direction::Abs(target.opposite());
        let (orientation, rel) = target.split();

        fn intersects(a: (usize, usize), b: (usize, usize)) -> bool {
            a.1 >= b.0 && a.0 <= b.1
        }

        let current_position = self.children[self.focus].position;
        let current_side = current_position.side(orientation.swap());
        let current_edge = current_position.edge(target);

        let children =
            Self::iter_mut(source, &mut self.children).filter(|(_, c)| {
                // Only select children actually aligned with us
                Some(rel)
                    == Relative::a_to_b(current_edge, c.position.edge(target))
                    && intersects(
                        c.position.side(orientation.swap()),
                        current_side,
                    )
            });

        for (i, c) in children {
            if c.view.take_focus(source) {
                self.focus = i;
                return EventResult::Consumed(None);
            }
        }

        EventResult::Ignored
    }

    fn check_focus_grab(&mut self, event: &Event) {
        if let Event::Mouse {
            offset,
            position,
            event,
        } = *event
        {
            if !event.grabs_focus() {
                return;
            }

            let position = match position.checked_sub(offset) {
                None => return,
                Some(pos) => pos,
            };

            for (i, child) in self.children.iter_mut().enumerate() {
                if child.position.contains(position)
                    && child.view.take_focus(Direction::none())
                {
                    self.focus = i;
                }
            }
        }
    }
}

impl View for FixedLayout {
    fn draw(&self, printer: &Printer) {
        for child in &self.children {
            child.view.draw(&printer.windowed(child.position));
        }
    }

    fn layout(&mut self, _size: Vec2) {
        // TODO: re-compute children positions?
        for child in &mut self.children {
            child.view.layout(child.position.size());
        }
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        if self.is_empty() {
            return EventResult::Ignored;
        }

        self.check_focus_grab(&event);

        let child = &mut self.children[self.focus];

        let result = child
            .view
            .on_event(event.relativized(child.position.top_left()));

        match result {
            EventResult::Ignored => match event {
                Event::Shift(Key::Tab) => self.move_focus_rel(Relative::Front),
                Event::Key(Key::Tab) => self.move_focus_rel(Relative::Back),
                Event::Key(Key::Left) => self.move_focus_abs(Absolute::Left),
                Event::Key(Key::Right) => self.move_focus_abs(Absolute::Right),
                Event::Key(Key::Up) => self.move_focus_abs(Absolute::Up),
                Event::Key(Key::Down) => self.move_focus_abs(Absolute::Down),
                _ => EventResult::Ignored,
            },
            res => res,
        }
    }

    fn important_area(&self, size: Vec2) -> Rect {
        if self.is_empty() {
            return Rect::from_size((0, 0), size);
        }

        let child = &self.children[self.focus];

        child.view.important_area(child.position.size())
            + child.position.top_left()
    }

    fn required_size(&mut self, _constraint: Vec2) -> Vec2 {
        self.children
            .iter()
            .map(|c| c.position.bottom_right() + (1, 1))
            .fold(Vec2::zero(), Vec2::max)
    }

    fn take_focus(&mut self, source: Direction) -> bool {
        match source {
            Direction::Abs(Absolute::None) => {
                // We want to guarantee:
                // * If the current focus _is_ focusable, keep it
                // * If it isn't, find _any_ focusable view, and focus it
                // * Otherwise, we can't take focus.
                for (i, c) in
                    Self::circular_mut(self.focus, &mut self.children)
                {
                    if c.view.take_focus(source) {
                        self.focus = i;
                        return true;
                    }
                }

                false
            }
            source => {
                for (i, c) in Self::iter_mut(source, &mut self.children) {
                    if c.view.take_focus(source) {
                        self.focus = i;
                        return true;
                    }
                }

                false
            }
        }
    }
}
<commit_msg>Add missing method to FixedLayout<commit_after>use crate::{
    direction::{Absolute, Direction, Relative},
    event::{AnyCb, Event, EventResult, Key},
    rect::Rect,
    view::{IntoBoxedView, Selector},
    {Printer, Vec2, View, With},
};

/// Arranges its children in a fixed layout.
///
/// Usually meant to use an external layout engine.
///
/// # Examples
///
/// ```rust
/// use cursive_core::{
///     views::{FixedLayout, TextView, Button},
///     Rect,
/// };
///
/// let layout = FixedLayout::new()
///     .child(Rect::from_size((0,0), (1,1)), TextView::new("/"))
///     .child(Rect::from_size((14,0), (1,1)), TextView::new(r"\"))
///     .child(Rect::from_size((0,2), (1,1)), TextView::new(r"\"))
///     .child(Rect::from_size((14,2), (1,1)), TextView::new("/"))
///     .child(Rect::from_size((3,1), (11,1)), Button::new("Clickme", |s| s.quit()));
/// ````
pub struct FixedLayout {
    children: Vec<Child>,
    focus: usize,
}

/// Represents a child view inside the FixedLayout.
struct Child {
    view: Box<dyn View>,
    position: Rect,
}

new_default!(FixedLayout);

impl FixedLayout {
    /// Returns a new, empty `FixedLayout`.
    pub fn new() -> Self {
        FixedLayout {
            children: Vec::new(),
            focus: 0,
        }
    }

    /// Adds a child. Chainable variant.
    pub fn child<V: IntoBoxedView>(self, position: Rect, view: V) -> Self {
        self.with(|s| s.add_child(position, view))
    }

    /// Adds a child.
    pub fn add_child<V: IntoBoxedView>(&mut self, position: Rect, view: V) {
        self.children.push(Child {
            view: view.as_boxed_view(),
            position,
        });
    }

    /// Returns index of focused inner view
    pub fn get_focus_index(&self) -> usize {
        self.focus
    }

    /// Attemps to set the focus on the given child.
    ///
    /// Returns `Err(())` if `index >= self.len()`, or if the view at the
    /// given index does not accept focus.
    pub fn set_focus_index(&mut self, index: usize) -> Result<(), ()> {
        if self
            .children
            .get_mut(index)
            .map(|child| child.view.take_focus(Direction::none()))
            .unwrap_or(false)
        {
            self.focus = index;
            Ok(())
        } else {
            Err(())
        }
    }

    /// How many children are in this view.
    pub fn len(&self) -> usize {
        self.children.len()
    }

    /// Returns `true` if this view has no children.
    pub fn is_empty(&self) -> bool {
        self.children.is_empty()
    }

    /// Returns a reference to a child.
    pub fn get_child(&self, i: usize) -> Option<&dyn View> {
        self.children.get(i).map(|c| &*c.view)
    }

    /// Returns a mutable reference to a child.
    pub fn get_child_mut(&mut self, i: usize) -> Option<&mut dyn View> {
        self.children.get_mut(i).map(|c| &mut *c.view)
    }

    /// Sets the position for the given child.
    pub fn set_child_position(&mut self, i: usize, position: Rect) {
        self.children[i].position = position;
    }

    /// Removes a child.
    ///
    /// If `i` is within bounds, the removed child will be returned.
    pub fn remove_child(&mut self, i: usize) -> Option<Box<dyn View>> {
        if i >= self.len() {
            return None;
        }

        if self.focus > i
            || (self.focus != 0 && self.focus == self.children.len() - 1)
        {
            self.focus -= 1;
        }

        Some(self.children.remove(i).view)
    }

    fn iter_mut<'a>(
        source: Direction,
        children: &'a mut [Child],
    ) -> Box<dyn Iterator<Item = (usize, &mut Child)> + 'a> {
        let children = children.iter_mut().enumerate();
        match source {
            Direction::Rel(Relative::Front) => Box::new(children),
            Direction::Rel(Relative::Back) => Box::new(children.rev()),
            Direction::Abs(abs) => {
                // Sort children by the given direction
                let mut children: Vec<_> = children.collect();
                children.sort_by_key(|(_, c)| c.position.edge(abs));
                Box::new(children.into_iter())
            }
        }
    }

    fn circular_mut<'a>(
        start: usize,
        children: &'a mut [Child],
    ) -> impl Iterator<Item = (usize, &mut Child)> + 'a {
        let (head, tail) = children.split_at_mut(start);

        let head = head.iter_mut().enumerate();
        let tail = tail
            .iter_mut()
            .enumerate()
            .map(move |(i, c)| (i + start, c));

        tail.chain(head)
    }

    fn move_focus_rel(&mut self, target: Relative) -> EventResult {
        let source = Direction::Rel(target.swap());
        for (i, c) in
            Self::iter_mut(source, &mut self.children).skip(self.focus + 1)
        {
            if c.view.take_focus(source) {
                self.focus = i;
                return EventResult::Consumed(None);
            }
        }

        EventResult::Ignored
    }

    fn move_focus_abs(&mut self, target: Absolute) -> EventResult {
        let source = Direction::Abs(target.opposite());
        let (orientation, rel) = target.split();

        fn intersects(a: (usize, usize), b: (usize, usize)) -> bool {
            a.1 >= b.0 && a.0 <= b.1
        }

        let current_position = self.children[self.focus].position;
        let current_side = current_position.side(orientation.swap());
        let current_edge = current_position.edge(target);

        let children =
            Self::iter_mut(source, &mut self.children).filter(|(_, c)| {
                // Only select children actually aligned with us
                Some(rel)
                    == Relative::a_to_b(current_edge, c.position.edge(target))
                    && intersects(
                        c.position.side(orientation.swap()),
                        current_side,
                    )
            });

        for (i, c) in children {
            if c.view.take_focus(source) {
                self.focus = i;
                return EventResult::Consumed(None);
            }
        }

        EventResult::Ignored
    }

    fn check_focus_grab(&mut self, event: &Event) {
        if let Event::Mouse {
            offset,
            position,
            event,
        } = *event
        {
            if !event.grabs_focus() {
                return;
            }

            let position = match position.checked_sub(offset) {
                None => return,
                Some(pos) => pos,
            };

            for (i, child) in self.children.iter_mut().enumerate() {
                if child.position.contains(position)
                    && child.view.take_focus(Direction::none())
                {
                    self.focus = i;
                }
            }
        }
    }
}

impl View for FixedLayout {
    fn draw(&self, printer: &Printer) {
        for child in &self.children {
            child.view.draw(&printer.windowed(child.position));
        }
    }

    fn layout(&mut self, _size: Vec2) {
        // TODO: re-compute children positions?
        for child in &mut self.children {
            child.view.layout(child.position.size());
        }
    }

    fn on_event(&mut self, event: Event) -> EventResult {
        if self.is_empty() {
            return EventResult::Ignored;
        }

        self.check_focus_grab(&event);

        let child = &mut self.children[self.focus];

        let result = child
            .view
            .on_event(event.relativized(child.position.top_left()));

        match result {
            EventResult::Ignored => match event {
                Event::Shift(Key::Tab) => self.move_focus_rel(Relative::Front),
                Event::Key(Key::Tab) => self.move_focus_rel(Relative::Back),
                Event::Key(Key::Left) => self.move_focus_abs(Absolute::Left),
                Event::Key(Key::Right) => self.move_focus_abs(Absolute::Right),
                Event::Key(Key::Up) => self.move_focus_abs(Absolute::Up),
                Event::Key(Key::Down) => self.move_focus_abs(Absolute::Down),
                _ => EventResult::Ignored,
            },
            res => res,
        }
    }

    fn important_area(&self, size: Vec2) -> Rect {
        if self.is_empty() {
            return Rect::from_size((0, 0), size);
        }

        let child = &self.children[self.focus];

        child.view.important_area(child.position.size())
            + child.position.top_left()
    }

    fn required_size(&mut self, _constraint: Vec2) -> Vec2 {
        self.children
            .iter()
            .map(|c| c.position.bottom_right() + (1, 1))
            .fold(Vec2::zero(), Vec2::max)
    }

    fn take_focus(&mut self, source: Direction) -> bool {
        match source {
            Direction::Abs(Absolute::None) => {
                // We want to guarantee:
                // * If the current focus _is_ focusable, keep it
                // * If it isn't, find _any_ focusable view, and focus it
                // * Otherwise, we can't take focus.
                for (i, c) in
                    Self::circular_mut(self.focus, &mut self.children)
                {
                    if c.view.take_focus(source) {
                        self.focus = i;
                        return true;
                    }
                }

                false
            }
            source => {
                for (i, c) in Self::iter_mut(source, &mut self.children) {
                    if c.view.take_focus(source) {
                        self.focus = i;
                        return true;
                    }
                }

                false
            }
        }
    }

    fn call_on_any<'a>(
        &mut self,
        selector: &Selector<'_>,
        callback: AnyCb<'a>,
    ) {
        for child in &mut self.children {
            child.view.call_on_any(selector, callback);
        }
    }

    fn focus_view(&mut self, selector: &Selector<'_>) -> Result<(), ()> {
        for (i, child) in self.children.iter_mut().enumerate() {
            if child.view.focus_view(selector).is_ok() {
                self.focus = i;
                return Ok(());
            }
        }

        Err(())
    }
}
<|endoftext|>


<commit_before>extern crate regex;

use self::regex::{Error as RegexError, Regex};

use constant::ME;
use error::{CliError, CronError, CronErrorKind};
use lib::io::*;
use std::collections::BTreeSet;
use std::env;
use std::io::Write;
use std::path::Path;
use std::process::{self, Stdio};
use std::str;

#[derive(Debug)]
pub struct Cron {
    upper  : String,
    my_area: String,
    lower  : String,
}

impl Cron {
    fn base_mark(keyword: &str) -> String {
        format!(
            r#"###################################
# "{}" uses the lines {}.
# Please don't touch them and me!
###################################
"#,
            ME,
            keyword,
        )
    }
    fn start_mark() -> String {
        Self::base_mark("from this")
    }
    fn end_mark() -> String {
        Self::base_mark("up to here")
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, "Read cron");

        let result = process::Command::new("crontab")
            .arg("-l")
            .output();
        let output = try!(result);

        let contents = if output.status.success() {
            try!(str::from_utf8(&output.stdout).map_err(|_| CronError::new(CronErrorKind::InvalidCharacterCode)))
        } else {
            ""
        };

        let areas = format!("^(?P<upper>(.|\n)*){}(?P<my_area>(.|\n)*){}(?P<lower>(.|\n)*)$", Self::start_mark(), Self::end_mark());
        let re    = match Regex::new(&areas) {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };

        let (upper, my_area, lower) = match re.captures(contents) {
            Some(caps) => match (caps.name("upper"), caps.name("my_area"), caps.name("lower")) {
                (Some(u), Some(m), Some(l)) => (u, m, l),
                _                           => unreachable!("Mistake regular expression!!"),
            },
            None => (contents, "", ""),
        };

        Ok(Cron { upper: upper.to_string(), my_area: my_area.to_string(), lower: lower.to_string() })
    }

    pub fn update(mut self, pairs: &[(&str, &str); 2]) -> Result<Self, CliError> {
        let current_dir = try!(Self::current_dir_string());
        try!(self.delete(&current_dir));

        let my_new_area = pairs
            .iter()
            .fold(String::new(), |area, &(time, command)| {
                let line = format!("{}\tcd {} && {} {}\n", time, current_dir, ME, command);
                area + &line
            });

        self.my_area = self.my_area + &my_new_area;
        Ok(self)
    }

    fn re_for_matching_line<S: AsRef<str>>(core: S) -> String {
        format!(r".*cd\s+{}\s+&&\s+{}.*\n", core.as_ref(), ME)
    }

    pub fn delete<S: AsRef<str>>(&mut self, dir: S) -> Result<(), RegexError> {
        let re = Self::re_for_matching_line(dir);
        let re = try!(Regex::new(re.as_ref()));
        self.my_area = re.replace_all(&self.my_area, "");
        Ok(())
    }

    pub fn discard(mut self) -> Result<Self, RegexError> {
        let re = Self::re_for_matching_line(r"(?P<path>[^\s]+)");
        let target_paths = try!(Regex::new(re.as_ref()))
            .captures_iter(&self.my_area)
            .map(|caps| match caps.name("path") {
                Some(p) => p.to_string(),
                None    => unreachable!("Mistake regular expression!!"),
            })
            .filter(|path| !Path::new(path).is_dir())
            .collect::<BTreeSet<String>>(); // We want to use "&str" if ownership allows it.

        let re_core = target_paths
            .iter()
            .fold(String::new(), |core, path| core + "|" + path); // We want to use true "Iterator.reduce()".
        let re_core = re_core.trim_left_matches('|');
        let re = Self::re_for_matching_line(format!("({})", re_core));
        let re = try!(Regex::new(re.as_ref()));
        self.my_area = re.replace_all(&self.my_area, "");
        Ok(self)
    }

    pub fn set(self) -> Result<(), CliError> {
        print_with_tag(Tag::Info, "Set new cron");

        let result = process::Command::new("crontab")
            .stdin(Stdio::piped())
            .spawn();
        let mut child = try!(result);

        let contents = if self.my_area_is_empty() {
            self.upper + &self.lower
        } else {
            self.upper
                + &Self::start_mark()
                + &self.my_area
                + &Self::end_mark()
                + &self.lower
        };
        match &mut child.stdin {
            &mut Some(ref mut stdin) => try!(stdin.write_all(contents.as_bytes())),
            &mut None                => unreachable!("Please set Stdio::piped()!!"),
        };

        let output = try!(child.wait_with_output());
        if output.status.success() {
            Ok(())
        } else {
            Err(From::from(CronError::new(CronErrorKind::FailedToWrite)))
        }
    }

    pub fn current_dir_string() -> Result<String, CronError> {
        let current_dir = match env::current_dir() {
            Ok(d)  => d,
            Err(_) => unreachable!("There is a problem for current directory!!"),
        };
        current_dir
            .to_str()
            .ok_or(CronError::new(CronErrorKind::InvalidPath))
            .map(|s| s.to_string())
    }

    fn my_area_is_empty(&self) -> bool {
        let re = match Regex::new(r"^\s*$") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };
        re.is_match(self.my_area.as_ref())
    }
}

#[test]
fn my_area_is_empty_return_true() {
    let empties = [
        "",
        " ",
        "\t",
        "\r",
        "\n",
        " \t\r\n",
    ];

    for empty in &empties {
        let cron = Cron {
            upper: ""     .to_string(),
            my_area: empty.to_string(),
            lower: ""     .to_string(),
        };
        assert!(cron.my_area_is_empty());
    }
}
#[test]
fn my_area_is_empty_return_false() {
    let non_empties = [
        "a",
        "ab",
        " ab",
        "a b",
        "ab ",
        "\tab",
        "a\tb",
        "ab\t",
        "\rab",
        "a\rb",
        "ab\r",
        "\nab",
        "a\nb",
        "ab\n",
        " \t\r\nab",
        "a \t\r\nb",
        "ab \t\r\n",
    ];

    for non_empty in &non_empties {
        let cron = Cron {
            upper  : ""       .to_string(),
            my_area: non_empty.to_string(),
            lower  : ""       .to_string(),
        };
        assert!(!cron.my_area_is_empty());
    }
}

#[test]
fn delete_return_ok() {
    fn wrap_by_extra_content<S: AsRef<str>>(target: S) -> String {
        let extra_content = "when cd path_to_extra && kic command\n";
        format!("{}{}{}", extra_content, target.as_ref(), extra_content)
    }

    let mut cron = Cron {
        upper  : "upper\n".to_string(),
        my_area: ""       .to_string(),
        lower  : "lower\n".to_string(),
    };

    let dir = "path_to_dir";

    let areas = vec![
        ("".to_string(), format!("cd {} && kic\n"             , dir)),
        ("".to_string(), format!("when cd {} && kic\n"        , dir)),
        ("".to_string(), format!("cd {} && kic command\n"     , dir)),
        ("".to_string(), format!("when cd {} && kic command\n", dir)),

        (wrap_by_extra_content(""), wrap_by_extra_content(format!("cd {} && kic\n"             , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("when cd {} && kic\n"        , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("cd {} && kic command\n"     , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("when cd {} && kic command\n", dir))),
    ];

    for (correct, area) in areas.into_iter() {
        cron.my_area = area;
        cron.delete(&dir).ok();
        assert_eq!(correct, cron.my_area);
    }
}
<commit_msg>[Feature] Include "patrol" command in "cron"<commit_after>extern crate regex;

use self::regex::{Error as RegexError, Regex};

use constant::ME;
use error::{CliError, CronError, CronErrorKind};
use lib::io::*;
use std::collections::BTreeSet;
use std::env;
use std::fmt::Display;
use std::io::Write;
use std::path::Path;
use std::process::{self, Stdio};
use std::str;

#[derive(Debug)]
pub struct Cron {
    upper  : String,
    my_area: String,
    lower  : String,
}

impl Cron {
    fn base_mark<D: Display>(keyword: &str, exec: D) -> String {
        format!(
            r#"###################################
# "{}" uses the lines {}.
# Please don't touch them and me!
###################################
{}"#,
            ME,
            keyword,
            exec,
        )
    }
    fn start_mark() -> String {
        Self::base_mark("from this", Self::patrol())
    }
    fn end_mark() -> String {
        Self::base_mark("up to here", "")
    }

    fn patrol() -> String {
        format!("0 0 * * *\t{} patrol\n", ME)
    }

    fn escape_asterisk<S: AsRef<str>>(s: S) -> String {
        let re = match Regex::new(r"\*") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake regular expression!!"),
        };
        re.replace_all(s.as_ref(), "\\*")
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, "Read cron");

        let result = process::Command::new("crontab")
            .arg("-l")
            .output();
        let output = try!(result);

        let contents = if output.status.success() {
            try!(str::from_utf8(&output.stdout).map_err(|_| CronError::new(CronErrorKind::InvalidCharacterCode)))
        } else {
            ""
        };

        let areas = format!(
            "^(?P<upper>(.|\n)*){}(?P<my_area>(.|\n)*){}(?P<lower>(.|\n)*)$",
            Self::escape_asterisk(Self::start_mark()),
            Self::end_mark(),
        );
        let re = match Regex::new(&areas) {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };

        let (upper, my_area, lower) = match re.captures(contents) {
            Some(caps) => match (caps.name("upper"), caps.name("my_area"), caps.name("lower")) {
                (Some(u), Some(m), Some(l)) => (u, m, l),
                _                           => unreachable!("Mistake regular expression!!"),
            },
            None => (contents, "", ""),
        };

        Ok(Cron { upper: upper.to_string(), my_area: my_area.to_string(), lower: lower.to_string() })
    }

    pub fn update(mut self, pairs: &[(&str, &str); 2]) -> Result<Self, CliError> {
        let current_dir = try!(Self::current_dir_string());
        try!(self.delete(&current_dir));

        let my_new_area = pairs
            .iter()
            .fold(String::new(), |area, &(time, command)| {
                let line = format!("{}\tcd {} && {} {}\n", time, current_dir, ME, command);
                area + &line
            });

        self.my_area = self.my_area + &my_new_area;
        Ok(self)
    }

    fn re_for_matching_line<S: AsRef<str>>(core: S) -> String {
        format!(r".*cd\s+{}\s+&&\s+{}.*\n", core.as_ref(), ME)
    }

    pub fn delete<S: AsRef<str>>(&mut self, dir: S) -> Result<(), RegexError> {
        let re = Self::re_for_matching_line(dir);
        let re = try!(Regex::new(re.as_ref()));
        self.my_area = re.replace_all(&self.my_area, "");
        Ok(())
    }

    pub fn discard(mut self) -> Result<Self, RegexError> {
        let re = Self::re_for_matching_line(r"(?P<path>[^\s]+)");
        let target_paths = try!(Regex::new(re.as_ref()))
            .captures_iter(&self.my_area)
            .map(|caps| match caps.name("path") {
                Some(p) => p.to_string(),
                None    => unreachable!("Mistake regular expression!!"),
            })
            .filter(|path| !Path::new(path).is_dir())
            .collect::<BTreeSet<String>>(); // We want to use "&str" if ownership allows it.

        let re_core = target_paths
            .iter()
            .fold(String::new(), |core, path| core + "|" + path); // We want to use true "Iterator.reduce()".
        let re_core = re_core.trim_left_matches('|');
        let re = Self::re_for_matching_line(format!("({})", re_core));
        let re = try!(Regex::new(re.as_ref()));
        self.my_area = re.replace_all(&self.my_area, "");
        Ok(self)
    }

    pub fn set(self) -> Result<(), CliError> {
        print_with_tag(Tag::Info, "Set new cron");

        let result = process::Command::new("crontab")
            .stdin(Stdio::piped())
            .spawn();
        let mut child = try!(result);

        let contents = if self.my_area_is_empty() {
            self.upper + &self.lower
        } else {
            self.upper
                + &Self::start_mark()
                + &self.my_area
                + &Self::end_mark()
                + &self.lower
        };
        match &mut child.stdin {
            &mut Some(ref mut stdin) => try!(stdin.write_all(contents.as_bytes())),
            &mut None                => unreachable!("Please set Stdio::piped()!!"),
        };

        let output = try!(child.wait_with_output());
        if output.status.success() {
            Ok(())
        } else {
            Err(From::from(CronError::new(CronErrorKind::FailedToWrite)))
        }
    }

    pub fn current_dir_string() -> Result<String, CronError> {
        let current_dir = match env::current_dir() {
            Ok(d)  => d,
            Err(_) => unreachable!("There is a problem for current directory!!"),
        };
        current_dir
            .to_str()
            .ok_or(CronError::new(CronErrorKind::InvalidPath))
            .map(|s| s.to_string())
    }

    fn my_area_is_empty(&self) -> bool {
        let re = match Regex::new(r"^\s*$") {
            Ok(re) => re,
            Err(_) => unreachable!("Mistake the regular expression!!"),
        };
        re.is_match(self.my_area.as_ref())
    }
}

#[test]
fn my_area_is_empty_return_true() {
    let empties = [
        "",
        " ",
        "\t",
        "\r",
        "\n",
        " \t\r\n",
    ];

    for empty in &empties {
        let cron = Cron {
            upper: ""     .to_string(),
            my_area: empty.to_string(),
            lower: ""     .to_string(),
        };
        assert!(cron.my_area_is_empty());
    }
}
#[test]
fn my_area_is_empty_return_false() {
    let non_empties = [
        "a",
        "ab",
        " ab",
        "a b",
        "ab ",
        "\tab",
        "a\tb",
        "ab\t",
        "\rab",
        "a\rb",
        "ab\r",
        "\nab",
        "a\nb",
        "ab\n",
        " \t\r\nab",
        "a \t\r\nb",
        "ab \t\r\n",
    ];

    for non_empty in &non_empties {
        let cron = Cron {
            upper  : ""       .to_string(),
            my_area: non_empty.to_string(),
            lower  : ""       .to_string(),
        };
        assert!(!cron.my_area_is_empty());
    }
}

#[test]
fn delete_return_ok() {
    fn wrap_by_extra_content<S: AsRef<str>>(target: S) -> String {
        let extra_content = "when cd path_to_extra && kic command\n";
        format!("{}{}{}", extra_content, target.as_ref(), extra_content)
    }

    let mut cron = Cron {
        upper  : "upper\n".to_string(),
        my_area: ""       .to_string(),
        lower  : "lower\n".to_string(),
    };

    let dir = "path_to_dir";

    let areas = vec![
        ("".to_string(), format!("cd {} && kic\n"             , dir)),
        ("".to_string(), format!("when cd {} && kic\n"        , dir)),
        ("".to_string(), format!("cd {} && kic command\n"     , dir)),
        ("".to_string(), format!("when cd {} && kic command\n", dir)),

        (wrap_by_extra_content(""), wrap_by_extra_content(format!("cd {} && kic\n"             , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("when cd {} && kic\n"        , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("cd {} && kic command\n"     , dir))),
        (wrap_by_extra_content(""), wrap_by_extra_content(format!("when cd {} && kic command\n", dir))),
    ];

    for (correct, area) in areas.into_iter() {
        cron.my_area = area;
        cron.delete(&dir).ok();
        assert_eq!(correct, cron.my_area);
    }
}
<|endoftext|>


<commit_before>#![ cfg_attr( not( feature = "use_std" ), no_std ) ] // zzz
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico")]
#![ doc( html_root_url = "https://docs.rs/wtools/latest/wtools/")]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

// #![ feature( type_name_of_val ) ]
// #![ feature( trace_macros ) ]

//!
//! wTools - Collection of general purpose tools for solving problems. Fundamentally extend the language without spoiling, so may be used solely or in conjunction with another module of such kind.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

/* zzz : use skeptic? */

/// Dependencies.
pub mod dependencies
{
  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use ::meta_tools::former;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use ::meta_tools::options;
  #[ cfg( feature = "meta" ) ]
  pub use ::meta_tools;
  #[ cfg( feature = "mem" ) ]
  pub use ::mem_tools;
  // zzz
  // #[ cfg( feature = "impls_index" ) ]
  // pub use ::impls_index;
  // #[ cfg( feature = "mod_interface" ) ]
  // pub use ::mod_interface;
  #[ cfg( feature = "typing" ) ]
  pub use ::typing_tools;
  #[ cfg( feature = "time" ) ]
  pub use ::time_tools;
  #[ cfg( feature = "string" ) ]
  pub use ::strs_tools;
  #[ cfg( feature = "error" ) ]
  pub use ::error_tools;
  // #[ cfg( feature = "winterval" ) ]
  // pub use ::winterval;
  #[ cfg( feature = "derive" ) ]
  pub use ::derive_tools;
  #[ cfg( feature = "diagnostics" ) ]
  pub use ::diagnostics_tools;

}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::orphan::*;

  #[ cfg( feature = "iter" ) ]
  pub use ::iter_tools as iter;
  #[ cfg( feature = "meta" ) ]
  pub use ::meta_tools as meta;
  #[ cfg( feature = "mem" ) ]
  pub use ::mem_tools as mem;
  #[ cfg( feature = "typing" ) ]
  pub use ::typing_tools as typing;
  #[ cfg( feature = "diagnostics" ) ]
  pub use ::diagnostics_tools as diagnostics;
  #[ cfg( any( feature = "dt", feature = "data_type" ) ) ]
  pub use ::data_type as dt;
  #[ cfg( feature = "time" ) ]
  pub use ::time_tools as time;
  #[ cfg( feature = "error" ) ]
  pub use ::error_tools as error;
  #[ cfg( feature = "string" ) ]
  pub use ::strs_tools as string;
  #[ cfg( feature = "derive" ) ]
  pub use ::derive_tools as derive;

  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use ::meta_tools::former as former;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use ::meta_tools::options as options;

}

pub use protected::*;

/// Orphan namespace of the module.
pub mod orphan
{
  pub use super::exposed::*;
}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
  #[ cfg( feature = "iter" ) ]
  pub use super::iter::exposed::*;
  #[ cfg( feature = "meta" ) ]
  pub use super::meta::exposed::*;
  #[ cfg( feature = "mem" ) ]
  pub use super::mem::exposed::*;
  #[ cfg( feature = "typing" ) ]
  pub use super::typing::exposed::*;
  #[ cfg( feature = "diagnostics" ) ]
  pub use super::diagnostics::exposed::*;
  #[ cfg( any( feature = "dt", feature = "data_type" ) ) ]
  pub use super::dt::exposed::*;
  #[ cfg( feature = "time" ) ]
  pub use super::time::exposed::*;
  #[ cfg( feature = "error" ) ]
  pub use super::error::exposed::*;
  #[ cfg( feature = "string" ) ]
  pub use super::string::exposed::*;
  #[ cfg( feature = "derive" ) ]
  pub use super::derive::exposed::*;

  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use super::former::exposed::*;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use super::options::exposed::*;

}

/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
  #[ cfg( feature = "iter" ) ]
  pub use super::iter::prelude::*;
  #[ cfg( feature = "meta" ) ]
  pub use super::meta::prelude::*;
  #[ cfg( feature = "mem" ) ]
  pub use super::mem::prelude::*;
  #[ cfg( feature = "typing" ) ]
  pub use super::typing::prelude::*;
  #[ cfg( feature = "diagnostics" ) ]
  pub use super::diagnostics::prelude::*;
  #[ cfg( any( feature = "dt", feature = "data_type" ) ) ]
  pub use super::dt::prelude::*;
  #[ cfg( feature = "time" ) ]
  pub use super::time::prelude::*;
  #[ cfg( feature = "error" ) ]
  pub use super::error::prelude::*;
  #[ cfg( feature = "string" ) ]
  pub use super::string::prelude::*;

  #[ cfg( feature = "derive" ) ]
  pub use super::derive::prelude::*;
  // xxx
  // #[ cfg( all( feature = "derive", feature = "derive_clone_dyn" ) ) ]
  pub use super::derive::prelude::clone_dyn;

  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use super::former::prelude::*;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use super::options::prelude::*;

}
<commit_msg>Fix module `wtools`, include routines from namespace with condition<commit_after>#![ cfg_attr( not( feature = "use_std" ), no_std ) ] // zzz
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico")]
#![ doc( html_root_url = "https://docs.rs/wtools/latest/wtools/")]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

// #![ feature( type_name_of_val ) ]
// #![ feature( trace_macros ) ]

//!
//! wTools - Collection of general purpose tools for solving problems. Fundamentally extend the language without spoiling, so may be used solely or in conjunction with another module of such kind.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

/* zzz : use skeptic? */

/// Dependencies.
pub mod dependencies
{
  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use ::meta_tools::former;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use ::meta_tools::options;
  #[ cfg( feature = "meta" ) ]
  pub use ::meta_tools;
  #[ cfg( feature = "mem" ) ]
  pub use ::mem_tools;
  // zzz
  // #[ cfg( feature = "impls_index" ) ]
  // pub use ::impls_index;
  // #[ cfg( feature = "mod_interface" ) ]
  // pub use ::mod_interface;
  #[ cfg( feature = "typing" ) ]
  pub use ::typing_tools;
  #[ cfg( feature = "time" ) ]
  pub use ::time_tools;
  #[ cfg( feature = "string" ) ]
  pub use ::strs_tools;
  #[ cfg( feature = "error" ) ]
  pub use ::error_tools;
  // #[ cfg( feature = "winterval" ) ]
  // pub use ::winterval;
  #[ cfg( feature = "derive" ) ]
  pub use ::derive_tools;
  #[ cfg( feature = "diagnostics" ) ]
  pub use ::diagnostics_tools;

}

/// Protected namespace of the module.
pub mod protected
{
  pub use super::orphan::*;

  #[ cfg( feature = "iter" ) ]
  pub use ::iter_tools as iter;
  #[ cfg( feature = "meta" ) ]
  pub use ::meta_tools as meta;
  #[ cfg( feature = "mem" ) ]
  pub use ::mem_tools as mem;
  #[ cfg( feature = "typing" ) ]
  pub use ::typing_tools as typing;
  #[ cfg( feature = "diagnostics" ) ]
  pub use ::diagnostics_tools as diagnostics;
  #[ cfg( any( feature = "dt", feature = "data_type" ) ) ]
  pub use ::data_type as dt;
  #[ cfg( feature = "time" ) ]
  pub use ::time_tools as time;
  #[ cfg( feature = "error" ) ]
  pub use ::error_tools as error;
  #[ cfg( feature = "string" ) ]
  pub use ::strs_tools as string;
  #[ cfg( feature = "derive" ) ]
  pub use ::derive_tools as derive;

  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use ::meta_tools::former as former;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use ::meta_tools::options as options;

}

pub use protected::*;

/// Orphan namespace of the module.
pub mod orphan
{
  pub use super::exposed::*;
}

/// Exposed namespace of the module.
pub mod exposed
{
  pub use super::prelude::*;
  #[ cfg( feature = "iter" ) ]
  pub use super::iter::exposed::*;
  #[ cfg( feature = "meta" ) ]
  pub use super::meta::exposed::*;
  #[ cfg( feature = "mem" ) ]
  pub use super::mem::exposed::*;
  #[ cfg( feature = "typing" ) ]
  pub use super::typing::exposed::*;
  #[ cfg( feature = "diagnostics" ) ]
  pub use super::diagnostics::exposed::*;
  #[ cfg( any( feature = "dt", feature = "data_type" ) ) ]
  pub use super::dt::exposed::*;
  #[ cfg( feature = "time" ) ]
  pub use super::time::exposed::*;
  #[ cfg( feature = "error" ) ]
  pub use super::error::exposed::*;
  #[ cfg( feature = "string" ) ]
  pub use super::string::exposed::*;
  #[ cfg( feature = "derive" ) ]
  pub use super::derive::exposed::*;

  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use super::former::exposed::*;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use super::options::exposed::*;

}

/// Prelude to use essentials: `use my_module::prelude::*`.
pub mod prelude
{
  #[ cfg( feature = "iter" ) ]
  pub use super::iter::prelude::*;
  #[ cfg( feature = "meta" ) ]
  pub use super::meta::prelude::*;
  #[ cfg( feature = "mem" ) ]
  pub use super::mem::prelude::*;
  #[ cfg( feature = "typing" ) ]
  pub use super::typing::prelude::*;
  #[ cfg( feature = "diagnostics" ) ]
  pub use super::diagnostics::prelude::*;
  #[ cfg( any( feature = "dt", feature = "data_type" ) ) ]
  pub use super::dt::prelude::*;
  #[ cfg( feature = "time" ) ]
  pub use super::time::prelude::*;
  #[ cfg( feature = "error" ) ]
  pub use super::error::prelude::*;
  #[ cfg( feature = "string" ) ]
  pub use super::string::prelude::*;

  #[ cfg( feature = "derive" ) ]
  pub use super::derive::prelude::*;
  // xxx
  #[ cfg( feature = "derive_clone_dyn" ) ]
  pub use super::derive::prelude::clone_dyn;

  #[ cfg( any( feature = "former", feature = "meta_former" ) ) ]
  pub use super::former::prelude::*;
  #[ cfg( any( feature = "options", feature = "meta_options" ) ) ]
  pub use super::options::prelude::*;

}
<|endoftext|>


<commit_before>use rustc_data_structures::fx::FxHashSet;
use std::fs;
use std::hash::{Hash, Hasher};
use std::path::Path;

use rustc_errors::Handler;

#[cfg(test)]
mod tests;

macro_rules! try_something {
    ($e:expr, $diag:expr, $out:expr) => {{
        match $e {
            Ok(c) => c,
            Err(e) => {
                $diag.struct_err(&e.to_string()).emit();
                return $out;
            }
        }
    }};
}

#[derive(Debug, Clone, Eq)]
pub struct CssPath {
    pub name: String,
    pub children: FxHashSet<CssPath>,
}

// This PartialEq implementation IS NOT COMMUTATIVE!!!
//
// The order is very important: the second object must have all first's rules.
// However, the first doesn't require to have all second's rules.
impl PartialEq for CssPath {
    fn eq(&self, other: &CssPath) -> bool {
        if self.name != other.name {
            false
        } else {
            for child in &self.children {
                if !other.children.iter().any(|c| child == c) {
                    return false;
                }
            }
            true
        }
    }
}

impl Hash for CssPath {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.name.hash(state);
        for x in &self.children {
            x.hash(state);
        }
    }
}

impl CssPath {
    fn new(name: String) -> CssPath {
        CssPath { name, children: FxHashSet::default() }
    }
}

/// All variants contain the position they occur.
#[derive(Debug, Clone, Copy)]
enum Events {
    StartLineComment(usize),
    StartComment(usize),
    EndComment(usize),
    InBlock(usize),
    OutBlock(usize),
}

impl Events {
    fn get_pos(&self) -> usize {
        match *self {
            Events::StartLineComment(p)
            | Events::StartComment(p)
            | Events::EndComment(p)
            | Events::InBlock(p)
            | Events::OutBlock(p) => p,
        }
    }

    fn is_comment(&self) -> bool {
        match *self {
            Events::StartLineComment(_) | Events::StartComment(_) | Events::EndComment(_) => true,
            _ => false,
        }
    }
}

fn previous_is_line_comment(events: &[Events]) -> bool {
    if let Some(&Events::StartLineComment(_)) = events.last() { true } else { false }
}

fn is_line_comment(pos: usize, v: &[u8], events: &[Events]) -> bool {
    if let Some(&Events::StartComment(_)) = events.last() {
        return false;
    }
    v[pos + 1] == b'/'
}

fn load_css_events(v: &[u8]) -> Vec<Events> {
    let mut pos = 0;
    let mut events = Vec::with_capacity(100);

    while pos + 1 < v.len() {
        match v[pos] {
            b'/' if v[pos + 1] == b'*' => {
                events.push(Events::StartComment(pos));
                pos += 1;
            }
            b'/' if is_line_comment(pos, v, &events) => {
                events.push(Events::StartLineComment(pos));
                pos += 1;
            }
            b'\n' if previous_is_line_comment(&events) => {
                events.push(Events::EndComment(pos));
            }
            b'*' if v[pos + 1] == b'/' => {
                events.push(Events::EndComment(pos + 2));
                pos += 1;
            }
            b'{' if !previous_is_line_comment(&events) => {
                if let Some(&Events::StartComment(_)) = events.last() {
                    pos += 1;
                    continue;
                }
                events.push(Events::InBlock(pos + 1));
            }
            b'}' if !previous_is_line_comment(&events) => {
                if let Some(&Events::StartComment(_)) = events.last() {
                    pos += 1;
                    continue;
                }
                events.push(Events::OutBlock(pos + 1));
            }
            _ => {}
        }
        pos += 1;
    }
    events
}

fn get_useful_next(events: &[Events], pos: &mut usize) -> Option<Events> {
    while *pos < events.len() {
        if !events[*pos].is_comment() {
            return Some(events[*pos]);
        }
        *pos += 1;
    }
    None
}

fn get_previous_positions(events: &[Events], mut pos: usize) -> Vec<usize> {
    let mut ret = Vec::with_capacity(3);

    ret.push(events[pos].get_pos());
    if pos > 0 {
        pos -= 1;
    }
    loop {
        if pos < 1 || !events[pos].is_comment() {
            let x = events[pos].get_pos();
            if *ret.last().unwrap() != x {
                ret.push(x);
            } else {
                ret.push(0);
            }
            break;
        }
        ret.push(events[pos].get_pos());
        pos -= 1;
    }
    if ret.len() & 1 != 0 && events[pos].is_comment() {
        ret.push(0);
    }
    ret.iter().rev().cloned().collect()
}

fn build_rule(v: &[u8], positions: &[usize]) -> String {
    positions
        .chunks(2)
        .map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
        .collect::<String>()
        .trim()
        .replace("\n", " ")
        .replace("/", "")
        .replace("\t", " ")
        .replace("{", "")
        .replace("}", "")
        .split(' ')
        .filter(|s| s.len() > 0)
        .collect::<Vec<&str>>()
        .join(" ")
}

fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> FxHashSet<CssPath> {
    let mut paths = Vec::with_capacity(50);

    while *pos < events.len() {
        if let Some(Events::OutBlock(_)) = get_useful_next(events, pos) {
            *pos += 1;
            break;
        }
        if let Some(Events::InBlock(_)) = get_useful_next(events, pos) {
            paths.push(CssPath::new(build_rule(v, &get_previous_positions(events, *pos))));
            *pos += 1;
        }
        while let Some(Events::InBlock(_)) = get_useful_next(events, pos) {
            if let Some(ref mut path) = paths.last_mut() {
                for entry in inner(v, events, pos).iter() {
                    path.children.insert(entry.clone());
                }
            }
        }
        if let Some(Events::OutBlock(_)) = get_useful_next(events, pos) {
            *pos += 1;
        }
    }
    paths.iter().cloned().collect()
}

pub fn load_css_paths(v: &[u8]) -> CssPath {
    let events = load_css_events(v);
    let mut pos = 0;

    let mut parent = CssPath::new("parent".to_owned());
    parent.children = inner(v, &events, &mut pos);
    parent
}

pub fn get_differences(against: &CssPath, other: &CssPath, v: &mut Vec<String>) {
    if against.name != other.name {
        return;
    } else {
        for child in &against.children {
            let mut found = false;
            let mut found_working = false;
            let mut tmp = Vec::new();

            for other_child in &other.children {
                if child.name == other_child.name {
                    if child != other_child {
                        get_differences(child, other_child, &mut tmp);
                    } else {
                        found_working = true;
                    }
                    found = true;
                    break;
                }
            }
            if found == false {
                v.push(format!("  Missing \"{}\" rule", child.name));
            } else if found_working == false {
                v.extend(tmp.iter().cloned());
            }
        }
    }
}

pub fn test_theme_against<P: AsRef<Path>>(
    f: &P,
    against: &CssPath,
    diag: &Handler,
) -> (bool, Vec<String>) {
    let data = try_something!(fs::read(f), diag, (false, vec![]));

    let paths = load_css_paths(&data);
    let mut ret = vec![];
    get_differences(against, &paths, &mut ret);
    (true, ret)
}
<commit_msg>Minify CSS rules to be able to handle minified theme files as well<commit_after>use rustc_data_structures::fx::FxHashSet;
use std::fs;
use std::hash::{Hash, Hasher};
use std::path::Path;

use rustc_errors::Handler;

#[cfg(test)]
mod tests;

macro_rules! try_something {
    ($e:expr, $diag:expr, $out:expr) => {{
        match $e {
            Ok(c) => c,
            Err(e) => {
                $diag.struct_err(&e.to_string()).emit();
                return $out;
            }
        }
    }};
}

#[derive(Debug, Clone, Eq)]
pub struct CssPath {
    pub name: String,
    pub children: FxHashSet<CssPath>,
}

// This PartialEq implementation IS NOT COMMUTATIVE!!!
//
// The order is very important: the second object must have all first's rules.
// However, the first doesn't require to have all second's rules.
impl PartialEq for CssPath {
    fn eq(&self, other: &CssPath) -> bool {
        if self.name != other.name {
            false
        } else {
            for child in &self.children {
                if !other.children.iter().any(|c| child == c) {
                    return false;
                }
            }
            true
        }
    }
}

impl Hash for CssPath {
    fn hash<H: Hasher>(&self, state: &mut H) {
        self.name.hash(state);
        for x in &self.children {
            x.hash(state);
        }
    }
}

impl CssPath {
    fn new(name: String) -> CssPath {
        CssPath { name, children: FxHashSet::default() }
    }
}

/// All variants contain the position they occur.
#[derive(Debug, Clone, Copy)]
enum Events {
    StartLineComment(usize),
    StartComment(usize),
    EndComment(usize),
    InBlock(usize),
    OutBlock(usize),
}

impl Events {
    fn get_pos(&self) -> usize {
        match *self {
            Events::StartLineComment(p)
            | Events::StartComment(p)
            | Events::EndComment(p)
            | Events::InBlock(p)
            | Events::OutBlock(p) => p,
        }
    }

    fn is_comment(&self) -> bool {
        match *self {
            Events::StartLineComment(_) | Events::StartComment(_) | Events::EndComment(_) => true,
            _ => false,
        }
    }
}

fn previous_is_line_comment(events: &[Events]) -> bool {
    if let Some(&Events::StartLineComment(_)) = events.last() { true } else { false }
}

fn is_line_comment(pos: usize, v: &[u8], events: &[Events]) -> bool {
    if let Some(&Events::StartComment(_)) = events.last() {
        return false;
    }
    v[pos + 1] == b'/'
}

fn load_css_events(v: &[u8]) -> Vec<Events> {
    let mut pos = 0;
    let mut events = Vec::with_capacity(100);

    while pos + 1 < v.len() {
        match v[pos] {
            b'/' if v[pos + 1] == b'*' => {
                events.push(Events::StartComment(pos));
                pos += 1;
            }
            b'/' if is_line_comment(pos, v, &events) => {
                events.push(Events::StartLineComment(pos));
                pos += 1;
            }
            b'\n' if previous_is_line_comment(&events) => {
                events.push(Events::EndComment(pos));
            }
            b'*' if v[pos + 1] == b'/' => {
                events.push(Events::EndComment(pos + 2));
                pos += 1;
            }
            b'{' if !previous_is_line_comment(&events) => {
                if let Some(&Events::StartComment(_)) = events.last() {
                    pos += 1;
                    continue;
                }
                events.push(Events::InBlock(pos + 1));
            }
            b'}' if !previous_is_line_comment(&events) => {
                if let Some(&Events::StartComment(_)) = events.last() {
                    pos += 1;
                    continue;
                }
                events.push(Events::OutBlock(pos + 1));
            }
            _ => {}
        }
        pos += 1;
    }
    events
}

fn get_useful_next(events: &[Events], pos: &mut usize) -> Option<Events> {
    while *pos < events.len() {
        if !events[*pos].is_comment() {
            return Some(events[*pos]);
        }
        *pos += 1;
    }
    None
}

fn get_previous_positions(events: &[Events], mut pos: usize) -> Vec<usize> {
    let mut ret = Vec::with_capacity(3);

    ret.push(events[pos].get_pos());
    if pos > 0 {
        pos -= 1;
    }
    loop {
        if pos < 1 || !events[pos].is_comment() {
            let x = events[pos].get_pos();
            if *ret.last().unwrap() != x {
                ret.push(x);
            } else {
                ret.push(0);
            }
            break;
        }
        ret.push(events[pos].get_pos());
        pos -= 1;
    }
    if ret.len() & 1 != 0 && events[pos].is_comment() {
        ret.push(0);
    }
    ret.iter().rev().cloned().collect()
}

fn build_rule(v: &[u8], positions: &[usize]) -> String {
    minifier::css::minify(
        &positions
            .chunks(2)
            .map(|x| ::std::str::from_utf8(&v[x[0]..x[1]]).unwrap_or(""))
            .collect::<String>()
            .trim()
            .replace("\n", " ")
            .replace("/", "")
            .replace("\t", " ")
            .replace("{", "")
            .replace("}", "")
            .split(' ')
            .filter(|s| s.len() > 0)
            .collect::<Vec<&str>>()
            .join(" "),
    )
    .unwrap_or_else(|_| String::new())
}

fn inner(v: &[u8], events: &[Events], pos: &mut usize) -> FxHashSet<CssPath> {
    let mut paths = Vec::with_capacity(50);

    while *pos < events.len() {
        if let Some(Events::OutBlock(_)) = get_useful_next(events, pos) {
            *pos += 1;
            break;
        }
        if let Some(Events::InBlock(_)) = get_useful_next(events, pos) {
            paths.push(CssPath::new(build_rule(v, &get_previous_positions(events, *pos))));
            *pos += 1;
        }
        while let Some(Events::InBlock(_)) = get_useful_next(events, pos) {
            if let Some(ref mut path) = paths.last_mut() {
                for entry in inner(v, events, pos).iter() {
                    path.children.insert(entry.clone());
                }
            }
        }
        if let Some(Events::OutBlock(_)) = get_useful_next(events, pos) {
            *pos += 1;
        }
    }
    paths.iter().cloned().collect()
}

pub fn load_css_paths(v: &[u8]) -> CssPath {
    let events = load_css_events(v);
    let mut pos = 0;

    let mut parent = CssPath::new("parent".to_owned());
    parent.children = inner(v, &events, &mut pos);
    parent
}

pub fn get_differences(against: &CssPath, other: &CssPath, v: &mut Vec<String>) {
    if against.name != other.name {
        return;
    } else {
        for child in &against.children {
            let mut found = false;
            let mut found_working = false;
            let mut tmp = Vec::new();

            for other_child in &other.children {
                if child.name == other_child.name {
                    if child != other_child {
                        get_differences(child, other_child, &mut tmp);
                    } else {
                        found_working = true;
                    }
                    found = true;
                    break;
                }
            }
            if found == false {
                v.push(format!("  Missing \"{}\" rule", child.name));
            } else if found_working == false {
                v.extend(tmp.iter().cloned());
            }
        }
    }
}

pub fn test_theme_against<P: AsRef<Path>>(
    f: &P,
    against: &CssPath,
    diag: &Handler,
) -> (bool, Vec<String>) {
    let data = try_something!(fs::read(f), diag, (false, vec![]));

    let paths = load_css_paths(&data);
    let mut ret = vec![];
    get_differences(against, &paths, &mut ret);
    (true, ret)
}
<|endoftext|>


<commit_before>
extern crate ndarray;
#[macro_use]
extern crate ndarray_linalg;

use ndarray::*;
use ndarray_linalg::*;

#[test]
fn cholesky() {
    let a: Array2<f64> = random_hpd(3);
    println!("a = \n{:?}", a);
    let c: Array2<_> = (&a).cholesky(UPLO::Upper).unwrap();
    println!("c = \n{:?}", c);
    println!("cc = \n{:?}", c.t().dot(&c));
    assert_close_l2!(&c.t().dot(&c), &a, 1e-7);
}

#[test]
fn cholesky_t() {
    let a: Array2<f64> = random_hpd(3);
    println!("a = \n{:?}", a);
    let c: Array2<_> = (&a).cholesky(UPLO::Upper).unwrap();
    println!("c = \n{:?}", c);
    println!("cc = \n{:?}", c.t().dot(&c));
    assert_close_l2!(&c.t().dot(&c), &a, 1e-7);
}
<commit_msg>Remove redundant test<commit_after>
extern crate ndarray;
#[macro_use]
extern crate ndarray_linalg;

use ndarray::*;
use ndarray_linalg::*;

#[test]
fn cholesky() {
    let a: Array2<f64> = random_hpd(3);
    println!("a = \n{:?}", a);
    let c: Array2<_> = (&a).cholesky(UPLO::Upper).unwrap();
    println!("c = \n{:?}", c);
    println!("cc = \n{:?}", c.t().dot(&c));
    assert_close_l2!(&c.t().dot(&c), &a, 1e-7);
}
<|endoftext|>


<commit_before>#![feature(test)]

extern crate test;

extern crate gluon;

use gluon::{Compiler, new_vm};
use gluon::vm::thread::{Status, Thread};
use gluon::vm::api::{FunctionRef, primitive};

// Benchmarks function calls
#[bench]
fn factorial(b: &mut ::test::Bencher) {
    let vm = new_vm();
    let text = r#"
    let factorial n =
        if n < 2
        then 1
        else n * factorial (n - 1)
    factorial
    "#;
    Compiler::new()
        .load_script(&vm, "factorial", text)
        .unwrap();
    let mut factorial: FunctionRef<fn(i32) -> i32> = vm.get_global("factorial").unwrap();
    b.iter(|| {
        let result = factorial.call(100).unwrap();
        ::test::black_box(result)
    })
}

#[bench]
fn factorial_tail_call(b: &mut ::test::Bencher) {
    let vm = new_vm();
    let text = r#"
    let factorial a n =
        if n < 2
        then a
        else factorial (a * n) (n - 1)
    factorial 1
    "#;
    Compiler::new()
        .load_script(&vm, "factorial", text)
        .unwrap();
    let mut factorial: FunctionRef<fn(i32) -> i32> = vm.get_global("factorial").unwrap();
    b.iter(|| {
        let result = factorial.call(100).unwrap();
        ::test::black_box(result)
    })
}

#[bench]
fn gluon_rust_boundary_overhead(b: &mut ::test::Bencher) {
    let vm = new_vm();

    fn test_fn(_: &Thread) -> Status {
        Status::Ok
    }

    vm.define_global("test_fn", primitive::<fn(i32)>("test_fn", test_fn)).unwrap();

    let text = r#"
    let for n f =
        if n #Int== 0 then
            ()
        else
            f n
            f n
            f n
            f n
            f n
            f n
            f n
            f n
            f n
            f n
            for (n #Int- 10) f
    \n -> for n test_fn
    "#;
    Compiler::new()
        .load_script(&vm, "test", text)
        .unwrap();

    let mut test: FunctionRef<fn(i32) -> ()> = vm.get_global("test").unwrap();
    b.iter(|| {
        let result = test.call(1000).unwrap();
        ::test::black_box(result)
    })
}
<commit_msg>test: Make the function_call.rs benchmarks compile<commit_after>#![feature(test)]

extern crate test;

extern crate gluon;

use gluon::{Compiler, new_vm};
use gluon::vm::thread::{Status, Thread};
use gluon::vm::api::{FunctionRef, primitive};

// Benchmarks function calls
#[bench]
fn factorial(b: &mut ::test::Bencher) {
    let vm = new_vm();
    let text = r#"
    let factorial n =
        if n < 2
        then 1
        else n * factorial (n - 1)
    factorial
    "#;
    Compiler::new()
        .load_script(&vm, "factorial", text)
        .unwrap();
    let mut factorial: FunctionRef<fn(i32) -> i32> = vm.get_global("factorial").unwrap();
    b.iter(|| {
        let result = factorial.call(100).unwrap();
        ::test::black_box(result)
    })
}

#[bench]
fn factorial_tail_call(b: &mut ::test::Bencher) {
    let vm = new_vm();
    let text = r#"
    let factorial a n =
        if n < 2
        then a
        else factorial (a * n) (n - 1)
    factorial 1
    "#;
    Compiler::new()
        .load_script(&vm, "factorial", text)
        .unwrap();
    let mut factorial: FunctionRef<fn(i32) -> i32> = vm.get_global("factorial").unwrap();
    b.iter(|| {
        let result = factorial.call(100).unwrap();
        ::test::black_box(result)
    })
}

#[bench]
fn gluon_rust_boundary_overhead(b: &mut ::test::Bencher) {
    let vm = new_vm();

    extern "C" fn test_fn(_: &Thread) -> Status {
        Status::Ok
    }

    vm.define_global("test_fn", primitive::<fn(i32)>("test_fn", test_fn)).unwrap();

    let text = r#"
    let for n f =
        if n #Int== 0 then
            ()
        else
            f n
            f n
            f n
            f n
            f n
            f n
            f n
            f n
            f n
            f n
            for (n #Int- 10) f
    \n -> for n test_fn
    "#;
    Compiler::new()
        .load_script(&vm, "test", text)
        .unwrap();

    let mut test: FunctionRef<fn(i32) -> ()> = vm.get_global("test").unwrap();
    b.iter(|| {
        let result = test.call(1000).unwrap();
        ::test::black_box(result)
    })
}
<|endoftext|>