<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.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!();
                }
            }
        }
    }
}
<commit_msg>Kakuro: add naked_pair 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.naked_pair();

            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!();
                }
            }
        }
    }
    fn naked_pair(&mut self) {
        for gi in 0..self.shape.group_to_cells.len() {
            let mut two_cand_cells = vec![];
            for c1 in self.shape.group_to_cells[gi] {
                let mut oks = 0u32;
                let mut score = 0.0f64;
                for n in 1..(MAX_VAL + 1) {
                    if let EvCand::Elim(s) = self.cand_score[c1][n as usize] {
                        score += s;
                    } else {
                        oks |= 1u32 << n;
                    }
                }
                if oks.count_ones() == 2 {
                    two_cand_cells.push((c1, oks, score));
                }
            }
            for i in 0..two_cand_cells.len() {
                for j in (i + 1)..two_cand_cells.len() {
                    if two_cand_cells[i].1 == two_cand_cells[j].1 {
                        let mut elims = vec![];
                        let x = two_cand_cells[i].1.trailing_zeros() as i32;
                        let y = (two_cand_cells[i].1 ^ (1u32 << x)).trailing_zeros() as i32;
                        for c in self.shape.group_to_cells[gi] {
                            if two_cand_cells[i].0 != c && two_cand_cells[j].0 != c {
                                elims.push((c, x));
                                elims.push((c, y));
                            }
                        }
                        self.move_cand.push(Move::Elim(two_cand_cells[i].2 + two_cand_cells[j].2, elims));
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>
<commit_msg>yagni<commit_after><|endoftext|>


<commit_before>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use BuildQuery;
use Groups;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, \
                client: {:?}, pagination: {:?} }}",
               self.scheme,
               self.domain,
               self.port,
               self.client,
               self.pagination)
    }
}

impl GitLab {
    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port: port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                }
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {
                page: 1,
                per_page: 20,
            },
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", domain, 443, &private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:\
    ///                     443/api/v3/groups?\
    ///                     order_by=path&private_token=XXXXXXXXXXXXX&page=1&per_page=20";
    ///
    /// let gl = GitLab::new_https("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("groups?order_by=path"), expected_url);
    /// ```
    pub fn build_url(&self, query: &str) -> String {
        let expected_url = "https://gitlab.example.com:\
                            443/api/v3/groups?\
                            order_by=path&private_token=XXXXXXXXXXXXX&page=1&per_page=20";

        let mut params_splitter = "?";
        if query.find("?").is_some() {
            params_splitter = "&";
        }
        format!("{}://{}:{}/api/v{}/{}{}private_token={}&page={}&per_page={}",
                self.scheme,
                self.domain,
                self.port,
                API_VERSION,
                query,
                params_splitter,
                self.private_token,
                self.pagination.page,
                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url("version");
        // Close connections after each GET.
        self.client.get(&url).header(hyper::header::Connection::close()).send()
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, query: &str) -> Result<T, serde_json::Error>
        where T: serde::Deserialize
    {
        let url = self.build_url(&query);
        info!("url: {:?}", url);
        let mut res: hyper::client::Response = self.client
            .get(&url)
            .header(hyper::header::Connection::close())
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        debug!("body: {:?}", body);

        // FIXME: Properly handle the error. Will require defining our own errors...
        assert_eq!(res.status, hyper::status::StatusCode::Ok);

        serde_json::from_str(&body.as_str())
    }

    // pub fn version(&self) -> Result<Version, serde_json::Error> {
    //     self.get("version")
    // }
    //
    // pub fn groups(&self) -> Result<Groups, serde_json::Error> {
    //     self.get("groups")
    // }
    //
    // pub fn projects(&self) -> Result<Projects, serde_json::Error> {
    //     self.get("projects")
    // }

    pub fn groups(&mut self, listing: ::groups::Listing) -> Result<Groups, serde_json::Error> {
        let query = listing.build_query();
        self.get(&query)
    }

    pub fn owned_groups(&mut self) -> Result<Groups, serde_json::Error> {
        let query = ::groups::owned_groups::Listing::new().build_query();
        info!("query: {:?}", query);
        self.get(&query)
    }
}

// #[cfg(test)]
// mod tests {
//
// #[test]
// fn it_works() {
// }
// }
//
<commit_msg>needless_borrow<commit_after>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use BuildQuery;
use Groups;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f,
               "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, \
                client: {:?}, pagination: {:?} }}",
               self.scheme,
               self.domain,
               self.port,
               self.client,
               self.pagination)
    }
}

impl GitLab {
    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port: port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                }
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {
                page: 1,
                per_page: 20,
            },
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", domain, 80, private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", domain, 443, private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:\
    ///                     443/api/v3/groups?\
    ///                     order_by=path&private_token=XXXXXXXXXXXXX&page=1&per_page=20";
    ///
    /// let gl = GitLab::new_https("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("groups?order_by=path"), expected_url);
    /// ```
    pub fn build_url(&self, query: &str) -> String {
        let expected_url = "https://gitlab.example.com:\
                            443/api/v3/groups?\
                            order_by=path&private_token=XXXXXXXXXXXXX&page=1&per_page=20";

        let mut params_splitter = "?";
        if query.find("?").is_some() {
            params_splitter = "&";
        }
        format!("{}://{}:{}/api/v{}/{}{}private_token={}&page={}&per_page={}",
                self.scheme,
                self.domain,
                self.port,
                API_VERSION,
                query,
                params_splitter,
                self.private_token,
                self.pagination.page,
                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url("version");
        // Close connections after each GET.
        self.client.get(&url).header(hyper::header::Connection::close()).send()
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, query: &str) -> Result<T, serde_json::Error>
        where T: serde::Deserialize
    {
        let url = self.build_url(&query);
        info!("url: {:?}", url);
        let mut res: hyper::client::Response = self.client
            .get(&url)
            .header(hyper::header::Connection::close())
            .send()
            .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();
        debug!("body: {:?}", body);

        // FIXME: Properly handle the error. Will require defining our own errors...
        assert_eq!(res.status, hyper::status::StatusCode::Ok);

        serde_json::from_str(&body.as_str())
    }

    // pub fn version(&self) -> Result<Version, serde_json::Error> {
    //     self.get("version")
    // }
    //
    // pub fn groups(&self) -> Result<Groups, serde_json::Error> {
    //     self.get("groups")
    // }
    //
    // pub fn projects(&self) -> Result<Projects, serde_json::Error> {
    //     self.get("projects")
    // }

    pub fn groups(&mut self, listing: ::groups::Listing) -> Result<Groups, serde_json::Error> {
        let query = listing.build_query();
        self.get(&query)
    }

    pub fn owned_groups(&mut self) -> Result<Groups, serde_json::Error> {
        let query = ::groups::owned_groups::Listing::new().build_query();
        info!("query: {:?}", query);
        self.get(&query)
    }
}

// #[cfg(test)]
// mod tests {
//
// #[test]
// fn it_works() {
// }
// }
//
<|endoftext|>


<commit_before>use parser::Parser;
use token::Token;
use super::test_eq;

fn parse_from_str(doc: &str) -> Vec<Token> {
    let mut parser = Parser::new();
    parser.parse(doc).unwrap()
}

#[test]
fn h_p_em() {
    let doc = "
Test
====

some *emphasis* required
";
    let mut parser = Parser::new();
    let res = parser.parse(doc).unwrap();
    let expected = vec![Token::Header(1, vec![Token::Str(String::from("Test"))]),
                        Token::Paragraph(vec![Token::Str(String::from("some ")),
                              Token::Emphasis(vec![Token::Str(String::from("emphasis"))]),
                              Token::Str(String::from(" required"))])];
    assert_eq!(res, expected);
}

#[test]
fn link_inline() {
    let doc = "[a link](http://foo.bar)";
    let mut parser = Parser::new();
    let res = parser.parse(doc).unwrap();

    assert_eq!(res,
               vec![Token::Paragraph(vec![Token::Link(String::from("http://foo.bar"),
                                                      String::from(""),
                                                      vec![Token::Str(String::from("a link"))])])]);
}

#[test]
fn reference_link() {
    let doc = "
[reference link][1]

[1]: http://foo.bar
";
    let expected = r#"[Paragraph([Link("http://foo.bar", "", [Str("reference link")])])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    assert_eq!(&result, expected);
}

#[test]
fn rule() {
    let doc = "a paragraph
****
another one";
    let expected = r#"[Paragraph([Str("a paragraph")]), Rule, Paragraph([Str("another one")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn lists() {
    let doc = "
* banana
    3. 3
    -  4
* apple
* orange
";
    let expected = "[List([Item([Str(\"banana\"), OrderedList(3, [Item([Str(\"3\")])]), \
                    List([Item([Str(\"4\")])])]), Item([Str(\"apple\")]), \
                    Item([Str(\"orange\")])])]";
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn blockquote() {
    let doc = "
normal paragraph

> some
> blockquote
";
    let expected = "[Paragraph([Str(\"normal paragraph\")]), \
                    BlockQuote([Paragraph([Str(\"some\"), SoftBreak, Str(\"blockquote\")])])]";
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn code_block() {
    let doc = "
normal paragraph

```
code block
```

```rust
rust code block
```
";
    let expected = r#"[Paragraph([Str("normal paragraph")]), CodeBlock("", [Str("code block\n")]), CodeBlock("rust", [Str("rust code block\n")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn strong_emphasis() {
    let doc = "
*normal emphasis*

**strong emphasis**
";
    let expected = r#"[Paragraph([Emphasis([Str("normal emphasis")])]), Paragraph([Strong([Str("strong emphasis")])])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn code() {
    let doc = "some `code` inlined";
    let expected = r#"[Paragraph([Str("some "), Code([Str("code")]), Str(" inlined")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn image_reference_inline() {
    let doc = "
Test: ![alt text][logo]

[logo]: http://foo.bar/baz.png \"Title\"
";
    let expected = r#"[Paragraph([Str("Test: "), Image("http://foo.bar/baz.png", "Title", [Str("alt text")])])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn image_reference_standalone() {
    let doc = "
![alt text][logo]

[logo]: http://foo.bar/baz.png \"Title\"
";
    let expected = r#"[StandaloneImage("http://foo.bar/baz.png", "Title", [Str("alt text")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn image_standalone() {
    let doc = "![alt text](http://foo.bar/baz.png \"Title\")";
    let expected = r#"[StandaloneImage("http://foo.bar/baz.png", "Title", [Str("alt text")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn table_simple() {
    let doc = "
| A             | Simple        | Table |
| ------------- |---------------| ------|
| bla           | bla           |  bla  |
| bla           | bla           |  bla  |
";
    let expected = "[Table([None, None, None], [TableHead([TableCell([Str(\" A             \")]), \
                    TableCell([Str(\" Simple        \")]), TableCell([Str(\" Table \")])]), \
                    TableRow([TableCell([Str(\" bla           \")]), TableCell([Str(\" bla           \
                    \")]), TableCell([Str(\"  bla  \")])]), TableRow([TableCell([Str(\" bla           \
                    \")]), TableCell([Str(\" bla           \")]), TableCell([Str(\"  bla  \
                    \")])])])]";
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn foonote_correct() {
    let doc = "A foonote[^1]...

[^1]: with a valid definition";
    let expected = "[Paragraph([Str(\"A foonote\"), Footnote([Paragraph([Str(\"with a valid \
                    definition\")])]), Str(\"...\")]), SoftBreak]";
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn footnote_incorrect() {
    let doc = "A foonote[^1]...

[^2]: without a valid definition";

    let mut parser = Parser::new();
    let result = parser.parse(doc);
    assert!(result.is_err());
}
<commit_msg>Revert table tests to before API changes<commit_after>use parser::Parser;
use token::Token;
use super::test_eq;

fn parse_from_str(doc: &str) -> Vec<Token> {
    let mut parser = Parser::new();
    parser.parse(doc).unwrap()
}

#[test]
fn h_p_em() {
    let doc = "
Test
====

some *emphasis* required
";
    let mut parser = Parser::new();
    let res = parser.parse(doc).unwrap();
    let expected = vec![Token::Header(1, vec![Token::Str(String::from("Test"))]),
                        Token::Paragraph(vec![Token::Str(String::from("some ")),
                              Token::Emphasis(vec![Token::Str(String::from("emphasis"))]),
                              Token::Str(String::from(" required"))])];
    assert_eq!(res, expected);
}

#[test]
fn link_inline() {
    let doc = "[a link](http://foo.bar)";
    let mut parser = Parser::new();
    let res = parser.parse(doc).unwrap();

    assert_eq!(res,
               vec![Token::Paragraph(vec![Token::Link(String::from("http://foo.bar"),
                                                      String::from(""),
                                                      vec![Token::Str(String::from("a link"))])])]);
}

#[test]
fn reference_link() {
    let doc = "
[reference link][1]

[1]: http://foo.bar
";
    let expected = r#"[Paragraph([Link("http://foo.bar", "", [Str("reference link")])])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    assert_eq!(&result, expected);
}

#[test]
fn rule() {
    let doc = "a paragraph
****
another one";
    let expected = r#"[Paragraph([Str("a paragraph")]), Rule, Paragraph([Str("another one")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn lists() {
    let doc = "
* banana
    3. 3
    -  4
* apple
* orange
";
    let expected = "[List([Item([Str(\"banana\"), OrderedList(3, [Item([Str(\"3\")])]), \
                    List([Item([Str(\"4\")])])]), Item([Str(\"apple\")]), \
                    Item([Str(\"orange\")])])]";
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn blockquote() {
    let doc = "
normal paragraph

> some
> blockquote
";
    let expected = "[Paragraph([Str(\"normal paragraph\")]), \
                    BlockQuote([Paragraph([Str(\"some\"), SoftBreak, Str(\"blockquote\")])])]";
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn code_block() {
    let doc = "
normal paragraph

```
code block
```

```rust
rust code block
```
";
    let expected = r#"[Paragraph([Str("normal paragraph")]), CodeBlock("", [Str("code block\n")]), CodeBlock("rust", [Str("rust code block\n")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn strong_emphasis() {
    let doc = "
*normal emphasis*

**strong emphasis**
";
    let expected = r#"[Paragraph([Emphasis([Str("normal emphasis")])]), Paragraph([Strong([Str("strong emphasis")])])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn code() {
    let doc = "some `code` inlined";
    let expected = r#"[Paragraph([Str("some "), Code([Str("code")]), Str(" inlined")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn image_reference_inline() {
    let doc = "
Test: ![alt text][logo]

[logo]: http://foo.bar/baz.png \"Title\"
";
    let expected = r#"[Paragraph([Str("Test: "), Image("http://foo.bar/baz.png", "Title", [Str("alt text")])])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn image_reference_standalone() {
    let doc = "
![alt text][logo]

[logo]: http://foo.bar/baz.png \"Title\"
";
    let expected = r#"[StandaloneImage("http://foo.bar/baz.png", "Title", [Str("alt text")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn image_standalone() {
    let doc = "![alt text](http://foo.bar/baz.png \"Title\")";
    let expected = r#"[StandaloneImage("http://foo.bar/baz.png", "Title", [Str("alt text")])]"#;
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn table_simple() {
    let doc = "
| A             | Simple        | Table |
| ------------- |---------------| ------|
| bla           | bla           |  bla  |
| bla           | bla           |  bla  |
";
    let expected = "[Table(3, [TableHead([TableCell([Str(\" A             \")]), \
                    TableCell([Str(\" Simple        \")]), TableCell([Str(\" Table \")])]), \
                    TableRow([TableCell([Str(\" bla           \")]), TableCell([Str(\" bla           \
                    \")]), TableCell([Str(\"  bla  \")])]), TableRow([TableCell([Str(\" bla           \
                    \")]), TableCell([Str(\" bla           \")]), TableCell([Str(\"  bla  \
                    \")])])])]";
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn foonote_correct() {
    let doc = "A foonote[^1]...

[^1]: with a valid definition";
    let expected = "[Paragraph([Str(\"A foonote\"), Footnote([Paragraph([Str(\"with a valid \
                    definition\")])]), Str(\"...\")]), SoftBreak]";
    let result = format!("{:?}", parse_from_str(doc));
    test_eq(&result, expected);
}

#[test]
fn footnote_incorrect() {
    let doc = "A foonote[^1]...

[^2]: without a valid definition";

    let mut parser = Parser::new();
    let result = parser.parse(doc);
    assert!(result.is_err());
}
<|endoftext|>


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

use std::char;

#[test]
fn test_is_lowercase() {
    assert!('a'.is_lowercase());
    assert!('ö'.is_lowercase());
    assert!('ß'.is_lowercase());
    assert!(!'Ü'.is_lowercase());
    assert!(!'P'.is_lowercase());
}

#[test]
fn test_is_uppercase() {
    assert!(!'h'.is_uppercase());
    assert!(!'ä'.is_uppercase());
    assert!(!'ß'.is_uppercase());
    assert!('Ö'.is_uppercase());
    assert!('T'.is_uppercase());
}

#[test]
fn test_is_whitespace() {
    assert!(' '.is_whitespace());
    assert!('\u{2007}'.is_whitespace());
    assert!('\t'.is_whitespace());
    assert!('\n'.is_whitespace());
    assert!(!'a'.is_whitespace());
    assert!(!'_'.is_whitespace());
    assert!(!'\u{0}'.is_whitespace());
}

#[test]
fn test_to_digit() {
    assert_eq!('0'.to_digit(10), Some(0));
    assert_eq!('1'.to_digit(2), Some(1));
    assert_eq!('2'.to_digit(3), Some(2));
    assert_eq!('9'.to_digit(10), Some(9));
    assert_eq!('a'.to_digit(16), Some(10));
    assert_eq!('A'.to_digit(16), Some(10));
    assert_eq!('b'.to_digit(16), Some(11));
    assert_eq!('B'.to_digit(16), Some(11));
    assert_eq!('z'.to_digit(36), Some(35));
    assert_eq!('Z'.to_digit(36), Some(35));
    assert_eq!(' '.to_digit(10), None);
    assert_eq!('$'.to_digit(36), None);
}

#[test]
fn test_to_lowercase() {
    fn lower(c: char) -> Vec<char> {
        c.to_lowercase().collect()
    }
    assert_eq!(lower('A'), ['a']);
    assert_eq!(lower('Ö'), ['ö']);
    assert_eq!(lower('ß'), ['ß']);
    assert_eq!(lower('Ü'), ['ü']);
    assert_eq!(lower('💩'), ['💩']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('Τ'), ['τ']);
    assert_eq!(lower('Ι'), ['ι']);
    assert_eq!(lower('Γ'), ['γ']);
    assert_eq!(lower('Μ'), ['μ']);
    assert_eq!(lower('Α'), ['α']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('ǅ'), ['ǆ']);
    assert_eq!(lower('ﬁ'), ['ﬁ']);
    assert_eq!(lower('İ'), ['i', '\u{307}']);
}

#[test]
fn test_to_uppercase() {
    fn upper(c: char) -> Vec<char> {
        c.to_uppercase().collect()
    }
    assert_eq!(upper('a'), ['A']);
    assert_eq!(upper('ö'), ['Ö']);
    assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s
    assert_eq!(upper('ü'), ['Ü']);
    assert_eq!(upper('💩'), ['💩']);

    assert_eq!(upper('σ'), ['Σ']);
    assert_eq!(upper('τ'), ['Τ']);
    assert_eq!(upper('ι'), ['Ι']);
    assert_eq!(upper('γ'), ['Γ']);
    assert_eq!(upper('μ'), ['Μ']);
    assert_eq!(upper('α'), ['Α']);
    assert_eq!(upper('ς'), ['Σ']);
    assert_eq!(upper('ǅ'), ['Ǆ']);
    assert_eq!(upper('ﬁ'), ['F', 'I']);
    assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']);
}

#[test]
fn test_is_control() {
    assert!('\u{0}'.is_control());
    assert!('\u{3}'.is_control());
    assert!('\u{6}'.is_control());
    assert!('\u{9}'.is_control());
    assert!('\u{7f}'.is_control());
    assert!('\u{92}'.is_control());
    assert!(!'\u{20}'.is_control());
    assert!(!'\u{55}'.is_control());
    assert!(!'\u{68}'.is_control());
}

#[test]
fn test_is_digit() {
   assert!('2'.is_numeric());
   assert!('7'.is_numeric());
   assert!(!'c'.is_numeric());
   assert!(!'i'.is_numeric());
   assert!(!'z'.is_numeric());
   assert!(!'Q'.is_numeric());
}

#[test]
fn test_escape_default() {
    fn string(c: char) -> String {
        c.escape_default().collect()
    }
    let s = string('\n');
    assert_eq!(s, "\\n");
    let s = string('\r');
    assert_eq!(s, "\\r");
    let s = string('\'');
    assert_eq!(s, "\\'");
    let s = string('"');
    assert_eq!(s, "\\\"");
    let s = string(' ');
    assert_eq!(s, " ");
    let s = string('a');
    assert_eq!(s, "a");
    let s = string('~');
    assert_eq!(s, "~");
    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\x1f');
    assert_eq!(s, "\\u{1f}");
    let s = string('\x7f');
    assert_eq!(s, "\\u{7f}");
    let s = string('\u{ff}');
    assert_eq!(s, "\\u{ff}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_escape_unicode() {
    fn string(c: char) -> String { c.escape_unicode().collect() }

    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\n');
    assert_eq!(s, "\\u{a}");
    let s = string(' ');
    assert_eq!(s, "\\u{20}");
    let s = string('a');
    assert_eq!(s, "\\u{61}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_encode_utf8() {
    fn check(input: char, expect: &[u8]) {
        assert_eq!(input.encode_utf8().as_slice(), expect);
        for (a, b) in input.encode_utf8().zip(expect) {
            assert_eq!(a, *b);
        }
    }

    check('x', &[0x78]);
    check('\u{e9}', &[0xc3, 0xa9]);
    check('\u{a66e}', &[0xea, 0x99, 0xae]);
    check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]);
}

#[test]
fn test_encode_utf16() {
    fn check(input: char, expect: &[u16]) {
        assert_eq!(input.encode_utf16().as_slice(), expect);
        for (a, b) in input.encode_utf16().zip(expect) {
            assert_eq!(a, *b);
        }
    }

    check('x', &[0x0078]);
    check('\u{e9}', &[0x00e9]);
    check('\u{a66e}', &[0xa66e]);
    check('\u{1f4a9}', &[0xd83d, 0xdca9]);
}

#[test]
fn test_len_utf16() {
    assert!('x'.len_utf16() == 1);
    assert!('\u{e9}'.len_utf16() == 1);
    assert!('\u{a66e}'.len_utf16() == 1);
    assert!('\u{1f4a9}'.len_utf16() == 2);
}

#[test]
fn test_decode_utf16() {
    fn check(s: &[u16], expected: &[Result<char, u16>]) {
        let v = char::decode_utf16(s.iter().cloned())
                     .map(|r| r.map_err(|e| e.unpaired_surrogate()))
                     .collect::<Vec<_>>();
        assert_eq!(v, expected);
    }
    check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]);
    check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]);
}

#[test]
fn ed_iterator_specializations() {
    // Check counting
    assert_eq!('\n'.escape_default().count(), 2);
    assert_eq!('c'.escape_default().count(), 1);
    assert_eq!(' '.escape_default().count(), 1);
    assert_eq!('\\'.escape_default().count(), 2);
    assert_eq!('\''.escape_default().count(), 2);

    // Check nth

    // Check that OoB is handled correctly
    assert_eq!('\n'.escape_default().nth(2), None);
    assert_eq!('c'.escape_default().nth(1), None);
    assert_eq!(' '.escape_default().nth(1), None);
    assert_eq!('\\'.escape_default().nth(2), None);
    assert_eq!('\''.escape_default().nth(2), None);

    // Check the first char
    assert_eq!('\n'.escape_default().nth(0), Some('\\'));
    assert_eq!('c'.escape_default().nth(0), Some('c'));
    assert_eq!(' '.escape_default().nth(0), Some(' '));
    assert_eq!('\\'.escape_default().nth(0), Some('\\'));
    assert_eq!('\''.escape_default().nth(0), Some('\\'));

    // Check the second char
    assert_eq!('\n'.escape_default().nth(1), Some('n'));
    assert_eq!('\\'.escape_default().nth(1), Some('\\'));
    assert_eq!('\''.escape_default().nth(1), Some('\''));

    // Check the last char
    assert_eq!('\n'.escape_default().last(), Some('n'));
    assert_eq!('c'.escape_default().last(), Some('c'));
    assert_eq!(' '.escape_default().last(), Some(' '));
    assert_eq!('\\'.escape_default().last(), Some('\\'));
    assert_eq!('\''.escape_default().last(), Some('\''));
}

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

use std::char;

#[test]
fn test_is_lowercase() {
    assert!('a'.is_lowercase());
    assert!('ö'.is_lowercase());
    assert!('ß'.is_lowercase());
    assert!(!'Ü'.is_lowercase());
    assert!(!'P'.is_lowercase());
}

#[test]
fn test_is_uppercase() {
    assert!(!'h'.is_uppercase());
    assert!(!'ä'.is_uppercase());
    assert!(!'ß'.is_uppercase());
    assert!('Ö'.is_uppercase());
    assert!('T'.is_uppercase());
}

#[test]
fn test_is_whitespace() {
    assert!(' '.is_whitespace());
    assert!('\u{2007}'.is_whitespace());
    assert!('\t'.is_whitespace());
    assert!('\n'.is_whitespace());
    assert!(!'a'.is_whitespace());
    assert!(!'_'.is_whitespace());
    assert!(!'\u{0}'.is_whitespace());
}

#[test]
fn test_to_digit() {
    assert_eq!('0'.to_digit(10), Some(0));
    assert_eq!('1'.to_digit(2), Some(1));
    assert_eq!('2'.to_digit(3), Some(2));
    assert_eq!('9'.to_digit(10), Some(9));
    assert_eq!('a'.to_digit(16), Some(10));
    assert_eq!('A'.to_digit(16), Some(10));
    assert_eq!('b'.to_digit(16), Some(11));
    assert_eq!('B'.to_digit(16), Some(11));
    assert_eq!('z'.to_digit(36), Some(35));
    assert_eq!('Z'.to_digit(36), Some(35));
    assert_eq!(' '.to_digit(10), None);
    assert_eq!('$'.to_digit(36), None);
}

#[test]
fn test_to_lowercase() {
    fn lower(c: char) -> Vec<char> {
        c.to_lowercase().collect()
    }
    assert_eq!(lower('A'), ['a']);
    assert_eq!(lower('Ö'), ['ö']);
    assert_eq!(lower('ß'), ['ß']);
    assert_eq!(lower('Ü'), ['ü']);
    assert_eq!(lower('💩'), ['💩']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('Τ'), ['τ']);
    assert_eq!(lower('Ι'), ['ι']);
    assert_eq!(lower('Γ'), ['γ']);
    assert_eq!(lower('Μ'), ['μ']);
    assert_eq!(lower('Α'), ['α']);
    assert_eq!(lower('Σ'), ['σ']);
    assert_eq!(lower('ǅ'), ['ǆ']);
    assert_eq!(lower('ﬁ'), ['ﬁ']);
    assert_eq!(lower('İ'), ['i', '\u{307}']);
}

#[test]
fn test_to_uppercase() {
    fn upper(c: char) -> Vec<char> {
        c.to_uppercase().collect()
    }
    assert_eq!(upper('a'), ['A']);
    assert_eq!(upper('ö'), ['Ö']);
    assert_eq!(upper('ß'), ['S', 'S']); // not ẞ: Latin capital letter sharp s
    assert_eq!(upper('ü'), ['Ü']);
    assert_eq!(upper('💩'), ['💩']);

    assert_eq!(upper('σ'), ['Σ']);
    assert_eq!(upper('τ'), ['Τ']);
    assert_eq!(upper('ι'), ['Ι']);
    assert_eq!(upper('γ'), ['Γ']);
    assert_eq!(upper('μ'), ['Μ']);
    assert_eq!(upper('α'), ['Α']);
    assert_eq!(upper('ς'), ['Σ']);
    assert_eq!(upper('ǅ'), ['Ǆ']);
    assert_eq!(upper('ﬁ'), ['F', 'I']);
    assert_eq!(upper('ᾀ'), ['Ἀ', 'Ι']);
}

#[test]
fn test_is_control() {
    assert!('\u{0}'.is_control());
    assert!('\u{3}'.is_control());
    assert!('\u{6}'.is_control());
    assert!('\u{9}'.is_control());
    assert!('\u{7f}'.is_control());
    assert!('\u{92}'.is_control());
    assert!(!'\u{20}'.is_control());
    assert!(!'\u{55}'.is_control());
    assert!(!'\u{68}'.is_control());
}

#[test]
fn test_is_digit() {
   assert!('2'.is_numeric());
   assert!('7'.is_numeric());
   assert!(!'c'.is_numeric());
   assert!(!'i'.is_numeric());
   assert!(!'z'.is_numeric());
   assert!(!'Q'.is_numeric());
}

#[test]
fn test_escape_default() {
    fn string(c: char) -> String {
        c.escape_default().collect()
    }
    let s = string('\n');
    assert_eq!(s, "\\n");
    let s = string('\r');
    assert_eq!(s, "\\r");
    let s = string('\'');
    assert_eq!(s, "\\'");
    let s = string('"');
    assert_eq!(s, "\\\"");
    let s = string(' ');
    assert_eq!(s, " ");
    let s = string('a');
    assert_eq!(s, "a");
    let s = string('~');
    assert_eq!(s, "~");
    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\x1f');
    assert_eq!(s, "\\u{1f}");
    let s = string('\x7f');
    assert_eq!(s, "\\u{7f}");
    let s = string('\u{ff}');
    assert_eq!(s, "\\u{ff}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_escape_unicode() {
    fn string(c: char) -> String { c.escape_unicode().collect() }

    let s = string('\x00');
    assert_eq!(s, "\\u{0}");
    let s = string('\n');
    assert_eq!(s, "\\u{a}");
    let s = string(' ');
    assert_eq!(s, "\\u{20}");
    let s = string('a');
    assert_eq!(s, "\\u{61}");
    let s = string('\u{11b}');
    assert_eq!(s, "\\u{11b}");
    let s = string('\u{1d4b6}');
    assert_eq!(s, "\\u{1d4b6}");
}

#[test]
fn test_encode_utf8() {
    fn check(input: char, expect: &[u8]) {
        assert_eq!(input.encode_utf8().as_slice(), expect);
        for (a, b) in input.encode_utf8().zip(expect) {
            assert_eq!(a, *b);
        }
    }

    check('x', &[0x78]);
    check('\u{e9}', &[0xc3, 0xa9]);
    check('\u{a66e}', &[0xea, 0x99, 0xae]);
    check('\u{1f4a9}', &[0xf0, 0x9f, 0x92, 0xa9]);
}

#[test]
fn test_encode_utf16() {
    fn check(input: char, expect: &[u16]) {
        assert_eq!(input.encode_utf16().as_slice(), expect);
        for (a, b) in input.encode_utf16().zip(expect) {
            assert_eq!(a, *b);
        }
    }

    check('x', &[0x0078]);
    check('\u{e9}', &[0x00e9]);
    check('\u{a66e}', &[0xa66e]);
    check('\u{1f4a9}', &[0xd83d, 0xdca9]);
}

#[test]
fn test_len_utf16() {
    assert!('x'.len_utf16() == 1);
    assert!('\u{e9}'.len_utf16() == 1);
    assert!('\u{a66e}'.len_utf16() == 1);
    assert!('\u{1f4a9}'.len_utf16() == 2);
}

#[test]
fn test_decode_utf16() {
    fn check(s: &[u16], expected: &[Result<char, u16>]) {
        let v = char::decode_utf16(s.iter().cloned())
                     .map(|r| r.map_err(|e| e.unpaired_surrogate()))
                     .collect::<Vec<_>>();
        assert_eq!(v, expected);
    }
    check(&[0xD800, 0x41, 0x42], &[Err(0xD800), Ok('A'), Ok('B')]);
    check(&[0xD800, 0], &[Err(0xD800), Ok('\0')]);
}

#[test]
fn ed_iterator_specializations() {
    // Check counting
    assert_eq!('\n'.escape_default().count(), 2);
    assert_eq!('c'.escape_default().count(), 1);
    assert_eq!(' '.escape_default().count(), 1);
    assert_eq!('\\'.escape_default().count(), 2);
    assert_eq!('\''.escape_default().count(), 2);

    // Check nth

    // Check that OoB is handled correctly
    assert_eq!('\n'.escape_default().nth(2), None);
    assert_eq!('c'.escape_default().nth(1), None);
    assert_eq!(' '.escape_default().nth(1), None);
    assert_eq!('\\'.escape_default().nth(2), None);
    assert_eq!('\''.escape_default().nth(2), None);

    // Check the first char
    assert_eq!('\n'.escape_default().nth(0), Some('\\'));
    assert_eq!('c'.escape_default().nth(0), Some('c'));
    assert_eq!(' '.escape_default().nth(0), Some(' '));
    assert_eq!('\\'.escape_default().nth(0), Some('\\'));
    assert_eq!('\''.escape_default().nth(0), Some('\\'));

    // Check the second char
    assert_eq!('\n'.escape_default().nth(1), Some('n'));
    assert_eq!('\\'.escape_default().nth(1), Some('\\'));
    assert_eq!('\''.escape_default().nth(1), Some('\''));

    // Check the last char
    assert_eq!('\n'.escape_default().last(), Some('n'));
    assert_eq!('c'.escape_default().last(), Some('c'));
    assert_eq!(' '.escape_default().last(), Some(' '));
    assert_eq!('\\'.escape_default().last(), Some('\\'));
    assert_eq!('\''.escape_default().last(), Some('\''));
}

#[test]
fn eu_iterator_specializations() {
    fn check(c: char) {
        let len = c.escape_unicode().count();

        // Check OoB
        assert_eq!(c.escape_unicode().nth(len), None);

        // For all possible in-bound offsets
        let mut iter = c.escape_unicode();
        for offset in 0..len {
            // Check last
            assert_eq!(iter.clone().last(), Some('}'));

            // Check counting
            assert_eq!(iter.clone().count(), len - offset);

            // Check nth
            assert_eq!(c.escape_unicode().nth(offset), iter.next());
        }

        // Check post-last
        assert_eq!(iter.clone().last(), None);
        assert_eq!(iter.clone().count(), 0);
    }

    check('\u{0}');
    check('\u{1}');
    check('\u{12}');
    check('\u{123}');
    check('\u{1234}');
    check('\u{12340}');
    check('\u{10FFFF}');
}
<|endoftext|>


<commit_before>/*!

Rust MIR: a lowered representation of Rust. Also: an experiment!

*/

#![feature(in_band_lifetimes)]
#![feature(slice_patterns)]
#![feature(slice_sort_by_cached_key)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(core_intrinsics)]
#![feature(const_fn)]
#![feature(decl_macro)]
#![feature(exhaustive_patterns)]
#![feature(range_contains)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_attrs)]
#![feature(never_type)]
#![feature(specialization)]
#![feature(try_trait)]
#![feature(unicode_internals)]
#![feature(step_trait)]
#![feature(slice_concat_ext)]
#![feature(try_from)]
#![feature(reverse_bits)]

#![recursion_limit="256"]

#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]

#[macro_use]
extern crate bitflags;
#[macro_use] extern crate log;
#[macro_use]
extern crate rustc;
#[macro_use] extern crate rustc_data_structures;
#[allow(unused_extern_crates)]
extern crate serialize as rustc_serialize; // used by deriving
#[macro_use]
extern crate syntax;

// Once we can use edition 2018 in the compiler,
// replace this with real try blocks.
macro_rules! try_block {
    ($($inside:tt)*) => (
        (||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
    )
}

mod diagnostics;

mod borrow_check;
mod build;
mod dataflow;
mod hair;
mod lints;
mod shim;
pub mod transform;
pub mod util;
pub mod interpret;
pub mod monomorphize;
pub mod const_eval;

pub use hair::pattern::check_crate as matchck_crate;
use rustc::ty::query::Providers;

pub fn provide(providers: &mut Providers<'_>) {
    borrow_check::provide(providers);
    shim::provide(providers);
    transform::provide(providers);
    monomorphize::partitioning::provide(providers);
    providers.const_eval = const_eval::const_eval_provider;
    providers.const_eval_raw = const_eval::const_eval_raw_provider;
    providers.check_match = hair::pattern::check_match;
}

__build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
<commit_msg>Revert removed #![feature(nll)]<commit_after>/*!

Rust MIR: a lowered representation of Rust. Also: an experiment!

*/

#![feature(nll)]
#![feature(in_band_lifetimes)]
#![feature(slice_patterns)]
#![feature(slice_sort_by_cached_key)]
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(crate_visibility_modifier)]
#![feature(core_intrinsics)]
#![feature(const_fn)]
#![feature(decl_macro)]
#![feature(exhaustive_patterns)]
#![feature(range_contains)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_attrs)]
#![feature(never_type)]
#![feature(specialization)]
#![feature(try_trait)]
#![feature(unicode_internals)]
#![feature(step_trait)]
#![feature(slice_concat_ext)]
#![feature(try_from)]
#![feature(reverse_bits)]

#![recursion_limit="256"]

#![deny(rust_2018_idioms)]
#![allow(explicit_outlives_requirements)]

#[macro_use]
extern crate bitflags;
#[macro_use] extern crate log;
#[macro_use]
extern crate rustc;
#[macro_use] extern crate rustc_data_structures;
#[allow(unused_extern_crates)]
extern crate serialize as rustc_serialize; // used by deriving
#[macro_use]
extern crate syntax;

// Once we can use edition 2018 in the compiler,
// replace this with real try blocks.
macro_rules! try_block {
    ($($inside:tt)*) => (
        (||{ ::std::ops::Try::from_ok({ $($inside)* }) })()
    )
}

mod diagnostics;

mod borrow_check;
mod build;
mod dataflow;
mod hair;
mod lints;
mod shim;
pub mod transform;
pub mod util;
pub mod interpret;
pub mod monomorphize;
pub mod const_eval;

pub use hair::pattern::check_crate as matchck_crate;
use rustc::ty::query::Providers;

pub fn provide(providers: &mut Providers<'_>) {
    borrow_check::provide(providers);
    shim::provide(providers);
    transform::provide(providers);
    monomorphize::partitioning::provide(providers);
    providers.const_eval = const_eval::const_eval_provider;
    providers.const_eval_raw = const_eval::const_eval_raw_provider;
    providers.check_match = hair::pattern::check_match;
}

__build_diagnostic_array! { librustc_mir, DIAGNOSTICS }
<|endoftext|>


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

//! Simple file-locking apis for each OS.
//!
//! This is not meant to be in the standard library, it does nothing with
//! green/native threading. This is just a bare-bones enough solution for
//! librustdoc, it is not production quality at all.

#[allow(non_camel_case_types)];

pub use self::imp::Lock;

#[cfg(unix)]
mod imp {
    use std::libc;

    #[cfg(target_os = "linux")]
    mod os {
        use std::libc;

        pub struct flock {
            l_type: libc::c_short,
            l_whence: libc::c_short,
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,

            // not actually here, but brings in line with freebsd
            l_sysid: libc::c_int,
        }

        pub static F_WRLCK: libc::c_short = 1;
        pub static F_UNLCK: libc::c_short = 2;
        pub static F_SETLK: libc::c_int = 6;
        pub static F_SETLKW: libc::c_int = 7;
    }

    #[cfg(target_os = "freebsd")]
    mod os {
        use std::libc;

        pub struct flock {
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,
            l_type: libc::c_short,
            l_whence: libc::c_short,
            l_sysid: libc::c_int,
        }

        pub static F_UNLCK: libc::c_short = 2;
        pub static F_WRLCK: libc::c_short = 3;
        pub static F_SETLK: libc::c_int = 12;
        pub static F_SETLKW: libc::c_int = 13;
    }

    #[cfg(target_os = "macos")]
    mod os {
        use std::libc;

        pub struct flock {
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,
            l_type: libc::c_short,
            l_whence: libc::c_short,

            // not actually here, but brings in line with freebsd
            l_sysid: libc::c_int,
        }

        pub static F_UNLCK: libc::c_short = 2;
        pub static F_WRLCK: libc::c_short = 3;
        pub static F_SETLK: libc::c_int = 8;
        pub static F_SETLKW: libc::c_int = 9;
    }

    pub struct Lock {
        priv fd: libc::c_int,
    }

    impl Lock {
        pub fn new(p: &Path) -> Lock {
            let fd = p.with_c_str(|s| unsafe {
                libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
            });
            assert!(fd > 0);
            let flock = os::flock {
                l_start: 0,
                l_len: 0,
                l_pid: 0,
                l_whence: libc::SEEK_SET as libc::c_short,
                l_type: os::F_WRLCK,
                l_sysid: 0,
            };
            let ret = unsafe {
                libc::fcntl(fd, os::F_SETLKW, &flock as *os::flock)
            };
            if ret == -1 {
                unsafe { libc::close(fd); }
                fail!("could not lock `{}`", p.display())
            }
            Lock { fd: fd }
        }
    }

    impl Drop for Lock {
        fn drop(&mut self) {
            let flock = os::flock {
                l_start: 0,
                l_len: 0,
                l_pid: 0,
                l_whence: libc::SEEK_SET as libc::c_short,
                l_type: os::F_UNLCK,
                l_sysid: 0,
            };
            unsafe {
                libc::fcntl(self.fd, os::F_SETLK, &flock as *os::flock);
                libc::close(self.fd);
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use std::libc;
    use std::mem;
    use std::os::win32::as_utf16_p;
    use std::ptr;

    static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002;

    extern "system" {
        fn LockFileEx(hFile: libc::HANDLE,
                      dwFlags: libc::DWORD,
                      dwReserved: libc::DWORD,
                      nNumberOfBytesToLockLow: libc::DWORD,
                      nNumberOfBytesToLockHigh: libc::DWORD,
                      lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
        fn UnlockFileEx(hFile: libc::HANDLE,
                        dwReserved: libc::DWORD,
                        nNumberOfBytesToLockLow: libc::DWORD,
                        nNumberOfBytesToLockHigh: libc::DWORD,
                        lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
    }

    pub struct Lock {
        priv handle: libc::HANDLE,
    }

    impl Lock {
        pub fn new(p: &Path) -> Lock {
            let handle = as_utf16_p(p.as_str().unwrap(), |p| unsafe {
                libc::CreateFileW(p, libc::GENERIC_READ, 0, ptr::mut_null(),
                                  libc::CREATE_ALWAYS,
                                  libc::FILE_ATTRIBUTE_NORMAL,
                                  ptr::mut_null())
            });
            assert!(handle as uint != libc::INVALID_HANDLE_VALUE as uint);
            let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
            let ret = unsafe {
                LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
                           &mut overlapped)
            };
            if ret == 0 {
                unsafe { libc::CloseHandle(handle); }
                fail!("could not lock `{}`", p.display())
            }
            Lock { handle: handle }
        }
    }

    impl Drop for Lock {
        fn drop(&mut self) {
            let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
            unsafe {
                UnlockFileEx(self.handle, 0, 100, 0, &mut overlapped);
                libc::CloseHandle(self.handle);
            }
        }
    }
}
<commit_msg>auto merge of #13043 : alexcrichton/rust/fix-rustdoc-windows, r=brson<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Simple file-locking apis for each OS.
//!
//! This is not meant to be in the standard library, it does nothing with
//! green/native threading. This is just a bare-bones enough solution for
//! librustdoc, it is not production quality at all.

#[allow(non_camel_case_types)];

pub use self::imp::Lock;

#[cfg(unix)]
mod imp {
    use std::libc;

    #[cfg(target_os = "linux")]
    mod os {
        use std::libc;

        pub struct flock {
            l_type: libc::c_short,
            l_whence: libc::c_short,
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,

            // not actually here, but brings in line with freebsd
            l_sysid: libc::c_int,
        }

        pub static F_WRLCK: libc::c_short = 1;
        pub static F_UNLCK: libc::c_short = 2;
        pub static F_SETLK: libc::c_int = 6;
        pub static F_SETLKW: libc::c_int = 7;
    }

    #[cfg(target_os = "freebsd")]
    mod os {
        use std::libc;

        pub struct flock {
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,
            l_type: libc::c_short,
            l_whence: libc::c_short,
            l_sysid: libc::c_int,
        }

        pub static F_UNLCK: libc::c_short = 2;
        pub static F_WRLCK: libc::c_short = 3;
        pub static F_SETLK: libc::c_int = 12;
        pub static F_SETLKW: libc::c_int = 13;
    }

    #[cfg(target_os = "macos")]
    mod os {
        use std::libc;

        pub struct flock {
            l_start: libc::off_t,
            l_len: libc::off_t,
            l_pid: libc::pid_t,
            l_type: libc::c_short,
            l_whence: libc::c_short,

            // not actually here, but brings in line with freebsd
            l_sysid: libc::c_int,
        }

        pub static F_UNLCK: libc::c_short = 2;
        pub static F_WRLCK: libc::c_short = 3;
        pub static F_SETLK: libc::c_int = 8;
        pub static F_SETLKW: libc::c_int = 9;
    }

    pub struct Lock {
        priv fd: libc::c_int,
    }

    impl Lock {
        pub fn new(p: &Path) -> Lock {
            let fd = p.with_c_str(|s| unsafe {
                libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
            });
            assert!(fd > 0);
            let flock = os::flock {
                l_start: 0,
                l_len: 0,
                l_pid: 0,
                l_whence: libc::SEEK_SET as libc::c_short,
                l_type: os::F_WRLCK,
                l_sysid: 0,
            };
            let ret = unsafe {
                libc::fcntl(fd, os::F_SETLKW, &flock as *os::flock)
            };
            if ret == -1 {
                unsafe { libc::close(fd); }
                fail!("could not lock `{}`", p.display())
            }
            Lock { fd: fd }
        }
    }

    impl Drop for Lock {
        fn drop(&mut self) {
            let flock = os::flock {
                l_start: 0,
                l_len: 0,
                l_pid: 0,
                l_whence: libc::SEEK_SET as libc::c_short,
                l_type: os::F_UNLCK,
                l_sysid: 0,
            };
            unsafe {
                libc::fcntl(self.fd, os::F_SETLK, &flock as *os::flock);
                libc::close(self.fd);
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    use std::libc;
    use std::mem;
    use std::os::win32::as_utf16_p;
    use std::os;
    use std::ptr;

    static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002;

    extern "system" {
        fn LockFileEx(hFile: libc::HANDLE,
                      dwFlags: libc::DWORD,
                      dwReserved: libc::DWORD,
                      nNumberOfBytesToLockLow: libc::DWORD,
                      nNumberOfBytesToLockHigh: libc::DWORD,
                      lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
        fn UnlockFileEx(hFile: libc::HANDLE,
                        dwReserved: libc::DWORD,
                        nNumberOfBytesToLockLow: libc::DWORD,
                        nNumberOfBytesToLockHigh: libc::DWORD,
                        lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
    }

    pub struct Lock {
        priv handle: libc::HANDLE,
    }

    impl Lock {
        pub fn new(p: &Path) -> Lock {
            let handle = as_utf16_p(p.as_str().unwrap(), |p| unsafe {
                libc::CreateFileW(p,
                                  libc::FILE_GENERIC_READ |
                                    libc::FILE_GENERIC_WRITE,
                                  libc::FILE_SHARE_READ |
                                    libc::FILE_SHARE_DELETE |
                                    libc::FILE_SHARE_WRITE,
                                  ptr::mut_null(),
                                  libc::CREATE_ALWAYS,
                                  libc::FILE_ATTRIBUTE_NORMAL,
                                  ptr::mut_null())
            });
            if handle as uint == libc::INVALID_HANDLE_VALUE as uint {
                fail!("create file error: {}", os::last_os_error());
            }
            let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
            let ret = unsafe {
                LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
                           &mut overlapped)
            };
            if ret == 0 {
                unsafe { libc::CloseHandle(handle); }
                fail!("could not lock `{}`: {}", p.display(),
                      os::last_os_error())
            }
            Lock { handle: handle }
        }
    }

    impl Drop for Lock {
        fn drop(&mut self) {
            let mut overlapped: libc::OVERLAPPED = unsafe { mem::init() };
            unsafe {
                UnlockFileEx(self.handle, 0, 100, 0, &mut overlapped);
                libc::CloseHandle(self.handle);
            }
        }
    }
}
<|endoftext|>


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

//! A "once initialization" primitive
//!
//! This primitive is meant to be used to run one-time initialization. An
//! example use case would be for initializing an FFI library.

use prelude::v1::*;

use isize;
use sync::atomic::{AtomicIsize, Ordering, ATOMIC_ISIZE_INIT};
use sync::{StaticMutex, MUTEX_INIT};

/// A synchronization primitive which can be used to run a one-time global
/// initialization. Useful for one-time initialization for FFI or related
/// functionality. This type can only be constructed with the `ONCE_INIT`
/// value.
///
/// # Examples
///
/// ```
/// use std::sync::{Once, ONCE_INIT};
///
/// static START: Once = ONCE_INIT;
///
/// START.call_once(|| {
///     // run initialization here
/// });
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Once {
    mutex: StaticMutex,
    cnt: AtomicIsize,
    lock_cnt: AtomicIsize,
}

/// Initialization value for static `Once` values.
#[stable(feature = "rust1", since = "1.0.0")]
pub const ONCE_INIT: Once = Once {
    mutex: MUTEX_INIT,
    cnt: ATOMIC_ISIZE_INIT,
    lock_cnt: ATOMIC_ISIZE_INIT,
};

impl Once {
    /// Performs an initialization routine once and only once. The given closure
    /// will be executed if this is the first time `call_once` has been called,
    /// and otherwise the routine will *not* be invoked.
    ///
    /// This method will block the calling task if another initialization
    /// routine is currently running.
    ///
    /// When this function returns, it is guaranteed that some initialization
    /// has run and completed (it may not be the closure specified).
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn call_once<F>(&'static self, f: F) where F: FnOnce() {
        // Optimize common path: load is much cheaper than fetch_add.
        if self.cnt.load(Ordering::SeqCst) < 0 {
            return
        }

        // Implementation-wise, this would seem like a fairly trivial primitive.
        // The stickler part is where our mutexes currently require an
        // allocation, and usage of a `Once` shouldn't leak this allocation.
        //
        // This means that there must be a deterministic destroyer of the mutex
        // contained within (because it's not needed after the initialization
        // has run).
        //
        // The general scheme here is to gate all future threads once
        // initialization has completed with a "very negative" count, and to
        // allow through threads to lock the mutex if they see a non negative
        // count. For all threads grabbing the mutex, exactly one of them should
        // be responsible for unlocking the mutex, and this should only be done
        // once everyone else is done with the mutex.
        //
        // This atomicity is achieved by swapping a very negative value into the
        // shared count when the initialization routine has completed. This will
        // read the number of threads which will at some point attempt to
        // acquire the mutex. This count is then squirreled away in a separate
        // variable, and the last person on the way out of the mutex is then
        // responsible for destroying the mutex.
        //
        // It is crucial that the negative value is swapped in *after* the
        // initialization routine has completed because otherwise new threads
        // calling `call_once` will return immediately before the initialization
        // has completed.

        let prev = self.cnt.fetch_add(1, Ordering::SeqCst);
        if prev < 0 {
            // Make sure we never overflow, we'll never have isize::MIN
            // simultaneous calls to `call_once` to make this value go back to 0
            self.cnt.store(isize::MIN, Ordering::SeqCst);
            return
        }

        // If the count is negative, then someone else finished the job,
        // otherwise we run the job and record how many people will try to grab
        // this lock
        let guard = self.mutex.lock();
        if self.cnt.load(Ordering::SeqCst) > 0 {
            f();
            let prev = self.cnt.swap(isize::MIN, Ordering::SeqCst);
            self.lock_cnt.store(prev, Ordering::SeqCst);
        }
        drop(guard);

        // Last one out cleans up after everyone else, no leaks!
        if self.lock_cnt.fetch_add(-1, Ordering::SeqCst) == 1 {
            unsafe { self.mutex.destroy() }
        }
    }
}

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

    use thread;
    use super::{ONCE_INIT, Once};
    use sync::mpsc::channel;

    #[test]
    fn smoke_once() {
        static O: Once = ONCE_INIT;
        let mut a = 0;
        O.call_once(|| a += 1);
        assert_eq!(a, 1);
        O.call_once(|| a += 1);
        assert_eq!(a, 1);
    }

    #[test]
    fn stampede_once() {
        static O: Once = ONCE_INIT;
        static mut run: bool = false;

        let (tx, rx) = channel();
        for _ in 0..10 {
            let tx = tx.clone();
            thread::spawn(move|| {
                for _ in 0..4 { thread::yield_now() }
                unsafe {
                    O.call_once(|| {
                        assert!(!run);
                        run = true;
                    });
                    assert!(run);
                }
                tx.send(()).unwrap();
            });
        }

        unsafe {
            O.call_once(|| {
                assert!(!run);
                run = true;
            });
            assert!(run);
        }

        for _ in 0..10 {
            rx.recv().unwrap();
        }
    }
}
<commit_msg>Clarify Once::call_once memory ordering guarantees in docs<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A "once initialization" primitive
//!
//! This primitive is meant to be used to run one-time initialization. An
//! example use case would be for initializing an FFI library.

use prelude::v1::*;

use isize;
use sync::atomic::{AtomicIsize, Ordering, ATOMIC_ISIZE_INIT};
use sync::{StaticMutex, MUTEX_INIT};

/// A synchronization primitive which can be used to run a one-time global
/// initialization. Useful for one-time initialization for FFI or related
/// functionality. This type can only be constructed with the `ONCE_INIT`
/// value.
///
/// # Examples
///
/// ```
/// use std::sync::{Once, ONCE_INIT};
///
/// static START: Once = ONCE_INIT;
///
/// START.call_once(|| {
///     // run initialization here
/// });
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Once {
    mutex: StaticMutex,
    cnt: AtomicIsize,
    lock_cnt: AtomicIsize,
}

/// Initialization value for static `Once` values.
#[stable(feature = "rust1", since = "1.0.0")]
pub const ONCE_INIT: Once = Once {
    mutex: MUTEX_INIT,
    cnt: ATOMIC_ISIZE_INIT,
    lock_cnt: ATOMIC_ISIZE_INIT,
};

impl Once {
    /// Performs an initialization routine once and only once. The given closure
    /// will be executed if this is the first time `call_once` has been called,
    /// and otherwise the routine will *not* be invoked.
    ///
    /// This method will block the calling task if another initialization
    /// routine is currently running.
    ///
    /// When this function returns, it is guaranteed that some initialization
    /// has run and completed (it may not be the closure specified). It is also
    /// guaranteed that any memory writes performed by the executed closure can
    /// be reliably observed by other tasks at this point (there is a
    /// happens-before relation between the closure and code executing after the
    /// return).
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn call_once<F>(&'static self, f: F) where F: FnOnce() {
        // Optimize common path: load is much cheaper than fetch_add.
        if self.cnt.load(Ordering::SeqCst) < 0 {
            return
        }

        // Implementation-wise, this would seem like a fairly trivial primitive.
        // The stickler part is where our mutexes currently require an
        // allocation, and usage of a `Once` shouldn't leak this allocation.
        //
        // This means that there must be a deterministic destroyer of the mutex
        // contained within (because it's not needed after the initialization
        // has run).
        //
        // The general scheme here is to gate all future threads once
        // initialization has completed with a "very negative" count, and to
        // allow through threads to lock the mutex if they see a non negative
        // count. For all threads grabbing the mutex, exactly one of them should
        // be responsible for unlocking the mutex, and this should only be done
        // once everyone else is done with the mutex.
        //
        // This atomicity is achieved by swapping a very negative value into the
        // shared count when the initialization routine has completed. This will
        // read the number of threads which will at some point attempt to
        // acquire the mutex. This count is then squirreled away in a separate
        // variable, and the last person on the way out of the mutex is then
        // responsible for destroying the mutex.
        //
        // It is crucial that the negative value is swapped in *after* the
        // initialization routine has completed because otherwise new threads
        // calling `call_once` will return immediately before the initialization
        // has completed.

        let prev = self.cnt.fetch_add(1, Ordering::SeqCst);
        if prev < 0 {
            // Make sure we never overflow, we'll never have isize::MIN
            // simultaneous calls to `call_once` to make this value go back to 0
            self.cnt.store(isize::MIN, Ordering::SeqCst);
            return
        }

        // If the count is negative, then someone else finished the job,
        // otherwise we run the job and record how many people will try to grab
        // this lock
        let guard = self.mutex.lock();
        if self.cnt.load(Ordering::SeqCst) > 0 {
            f();
            let prev = self.cnt.swap(isize::MIN, Ordering::SeqCst);
            self.lock_cnt.store(prev, Ordering::SeqCst);
        }
        drop(guard);

        // Last one out cleans up after everyone else, no leaks!
        if self.lock_cnt.fetch_add(-1, Ordering::SeqCst) == 1 {
            unsafe { self.mutex.destroy() }
        }
    }
}

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

    use thread;
    use super::{ONCE_INIT, Once};
    use sync::mpsc::channel;

    #[test]
    fn smoke_once() {
        static O: Once = ONCE_INIT;
        let mut a = 0;
        O.call_once(|| a += 1);
        assert_eq!(a, 1);
        O.call_once(|| a += 1);
        assert_eq!(a, 1);
    }

    #[test]
    fn stampede_once() {
        static O: Once = ONCE_INIT;
        static mut run: bool = false;

        let (tx, rx) = channel();
        for _ in 0..10 {
            let tx = tx.clone();
            thread::spawn(move|| {
                for _ in 0..4 { thread::yield_now() }
                unsafe {
                    O.call_once(|| {
                        assert!(!run);
                        run = true;
                    });
                    assert!(run);
                }
                tx.send(()).unwrap();
            });
        }

        unsafe {
            O.call_once(|| {
                assert!(!run);
                run = true;
            });
            assert!(run);
        }

        for _ in 0..10 {
            rx.recv().unwrap();
        }
    }
}
<|endoftext|>