<commit_before>//! Representation of a `TextEdit`.
//!
//! `rust-analyzer` never mutates text itself and only sends diffs to clients,
//! so `TextEdit` is the ultimate representation of the work done by
//! rust-analyzer.
pub use text_size::{TextRange, TextSize};

/// `InsertDelete` -- a single "atomic" change to text
///
/// Must not overlap with other `InDel`s
#[derive(Debug, Clone)]
pub struct Indel {
    pub insert: String,
    /// Refers to offsets in the original text
    pub delete: TextRange,
}

#[derive(Default, Debug, Clone)]
pub struct TextEdit {
    indels: Vec<Indel>,
}

#[derive(Debug, Default, Clone)]
pub struct TextEditBuilder {
    indels: Vec<Indel>,
}

impl Indel {
    pub fn insert(offset: TextSize, text: String) -> Indel {
        Indel::replace(TextRange::empty(offset), text)
    }
    pub fn delete(range: TextRange) -> Indel {
        Indel::replace(range, String::new())
    }
    pub fn replace(range: TextRange, replace_with: String) -> Indel {
        Indel { delete: range, insert: replace_with }
    }

    pub fn apply(&self, text: &mut String) {
        let start: usize = self.delete.start().into();
        let end: usize = self.delete.end().into();
        text.replace_range(start..end, &self.insert);
    }
}

impl TextEdit {
    pub fn builder() -> TextEditBuilder {
        TextEditBuilder::default()
    }

    pub fn insert(offset: TextSize, text: String) -> TextEdit {
        let mut builder = TextEdit::builder();
        builder.insert(offset, text);
        builder.finish()
    }

    pub fn delete(range: TextRange) -> TextEdit {
        let mut builder = TextEdit::builder();
        builder.delete(range);
        builder.finish()
    }

    pub fn replace(range: TextRange, replace_with: String) -> TextEdit {
        let mut builder = TextEdit::builder();
        builder.replace(range, replace_with);
        builder.finish()
    }

    pub fn len(&self) -> usize {
        self.indels.len()
    }

    pub fn is_empty(&self) -> bool {
        self.indels.is_empty()
    }

    pub fn iter(&self) -> std::slice::Iter<'_, Indel> {
        self.into_iter()
    }

    pub fn apply(&self, text: &mut String) {
        match self.len() {
            0 => return,
            1 => {
                self.indels[0].apply(text);
                return;
            }
            _ => (),
        }

        let mut total_len = TextSize::of(&*text);
        for indel in self.indels.iter() {
            total_len += TextSize::of(&indel.insert);
            total_len -= indel.delete.end() - indel.delete.start();
        }
        let mut buf = String::with_capacity(total_len.into());
        let mut prev = 0;
        for indel in self.indels.iter() {
            let start: usize = indel.delete.start().into();
            let end: usize = indel.delete.end().into();
            if start > prev {
                buf.push_str(&text[prev..start]);
            }
            buf.push_str(&indel.insert);
            prev = end;
        }
        buf.push_str(&text[prev..text.len()]);
        assert_eq!(TextSize::of(&buf), total_len);

        // FIXME: figure out a way to mutate the text in-place or reuse the
        // memory in some other way
        *text = buf
    }

    pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> {
        // FIXME: can be done without allocating intermediate vector
        let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>();
        if !check_disjoint(&mut all) {
            return Err(other);
        }
        self.indels.extend(other.indels);
        assert!(check_disjoint(&mut self.indels));
        Ok(())
    }

    pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> {
        let mut res = offset;
        for indel in self.indels.iter() {
            if indel.delete.start() >= offset {
                break;
            }
            if offset < indel.delete.end() {
                return None;
            }
            res += TextSize::of(&indel.insert);
            res -= indel.delete.len();
        }
        Some(res)
    }
}

impl IntoIterator for TextEdit {
    type Item = Indel;
    type IntoIter = std::vec::IntoIter<Indel>;

    fn into_iter(self) -> Self::IntoIter {
        self.indels.into_iter()
    }
}

impl<'a> IntoIterator for &'a TextEdit {
    type Item = &'a Indel;
    type IntoIter = std::slice::Iter<'a, Indel>;

    fn into_iter(self) -> Self::IntoIter {
        self.indels.iter()
    }
}

impl TextEditBuilder {
    pub fn replace(&mut self, range: TextRange, replace_with: String) {
        self.indels.push(Indel::replace(range, replace_with))
    }
    pub fn delete(&mut self, range: TextRange) {
        self.indels.push(Indel::delete(range))
    }
    pub fn insert(&mut self, offset: TextSize, text: String) {
        self.indels.push(Indel::insert(offset, text))
    }
    pub fn finish(self) -> TextEdit {
        let mut indels = self.indels;
        assert!(check_disjoint(&mut indels));
        TextEdit { indels }
    }
    pub fn invalidates_offset(&self, offset: TextSize) -> bool {
        self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset))
    }
}

fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
    indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end()));
    indels
        .iter()
        .zip(indels.iter().skip(1))
        .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start())
}
<commit_msg>Provide better stack trace for overlapping edits<commit_after>//! Representation of a `TextEdit`.
//!
//! `rust-analyzer` never mutates text itself and only sends diffs to clients,
//! so `TextEdit` is the ultimate representation of the work done by
//! rust-analyzer.
pub use text_size::{TextRange, TextSize};

/// `InsertDelete` -- a single "atomic" change to text
///
/// Must not overlap with other `InDel`s
#[derive(Debug, Clone)]
pub struct Indel {
    pub insert: String,
    /// Refers to offsets in the original text
    pub delete: TextRange,
}

#[derive(Default, Debug, Clone)]
pub struct TextEdit {
    indels: Vec<Indel>,
}

#[derive(Debug, Default, Clone)]
pub struct TextEditBuilder {
    indels: Vec<Indel>,
}

impl Indel {
    pub fn insert(offset: TextSize, text: String) -> Indel {
        Indel::replace(TextRange::empty(offset), text)
    }
    pub fn delete(range: TextRange) -> Indel {
        Indel::replace(range, String::new())
    }
    pub fn replace(range: TextRange, replace_with: String) -> Indel {
        Indel { delete: range, insert: replace_with }
    }

    pub fn apply(&self, text: &mut String) {
        let start: usize = self.delete.start().into();
        let end: usize = self.delete.end().into();
        text.replace_range(start..end, &self.insert);
    }
}

impl TextEdit {
    pub fn builder() -> TextEditBuilder {
        TextEditBuilder::default()
    }

    pub fn insert(offset: TextSize, text: String) -> TextEdit {
        let mut builder = TextEdit::builder();
        builder.insert(offset, text);
        builder.finish()
    }

    pub fn delete(range: TextRange) -> TextEdit {
        let mut builder = TextEdit::builder();
        builder.delete(range);
        builder.finish()
    }

    pub fn replace(range: TextRange, replace_with: String) -> TextEdit {
        let mut builder = TextEdit::builder();
        builder.replace(range, replace_with);
        builder.finish()
    }

    pub fn len(&self) -> usize {
        self.indels.len()
    }

    pub fn is_empty(&self) -> bool {
        self.indels.is_empty()
    }

    pub fn iter(&self) -> std::slice::Iter<'_, Indel> {
        self.into_iter()
    }

    pub fn apply(&self, text: &mut String) {
        match self.len() {
            0 => return,
            1 => {
                self.indels[0].apply(text);
                return;
            }
            _ => (),
        }

        let mut total_len = TextSize::of(&*text);
        for indel in self.indels.iter() {
            total_len += TextSize::of(&indel.insert);
            total_len -= indel.delete.end() - indel.delete.start();
        }
        let mut buf = String::with_capacity(total_len.into());
        let mut prev = 0;
        for indel in self.indels.iter() {
            let start: usize = indel.delete.start().into();
            let end: usize = indel.delete.end().into();
            if start > prev {
                buf.push_str(&text[prev..start]);
            }
            buf.push_str(&indel.insert);
            prev = end;
        }
        buf.push_str(&text[prev..text.len()]);
        assert_eq!(TextSize::of(&buf), total_len);

        // FIXME: figure out a way to mutate the text in-place or reuse the
        // memory in some other way
        *text = buf
    }

    pub fn union(&mut self, other: TextEdit) -> Result<(), TextEdit> {
        // FIXME: can be done without allocating intermediate vector
        let mut all = self.iter().chain(other.iter()).collect::<Vec<_>>();
        if !check_disjoint(&mut all) {
            return Err(other);
        }
        self.indels.extend(other.indels);
        assert!(check_disjoint(&mut self.indels));
        Ok(())
    }

    pub fn apply_to_offset(&self, offset: TextSize) -> Option<TextSize> {
        let mut res = offset;
        for indel in self.indels.iter() {
            if indel.delete.start() >= offset {
                break;
            }
            if offset < indel.delete.end() {
                return None;
            }
            res += TextSize::of(&indel.insert);
            res -= indel.delete.len();
        }
        Some(res)
    }
}

impl IntoIterator for TextEdit {
    type Item = Indel;
    type IntoIter = std::vec::IntoIter<Indel>;

    fn into_iter(self) -> Self::IntoIter {
        self.indels.into_iter()
    }
}

impl<'a> IntoIterator for &'a TextEdit {
    type Item = &'a Indel;
    type IntoIter = std::slice::Iter<'a, Indel>;

    fn into_iter(self) -> Self::IntoIter {
        self.indels.iter()
    }
}

impl TextEditBuilder {
    pub fn replace(&mut self, range: TextRange, replace_with: String) {
        self.indel(Indel::replace(range, replace_with))
    }
    pub fn delete(&mut self, range: TextRange) {
        self.indel(Indel::delete(range))
    }
    pub fn insert(&mut self, offset: TextSize, text: String) {
        self.indel(Indel::insert(offset, text))
    }
    pub fn finish(self) -> TextEdit {
        let mut indels = self.indels;
        assert!(check_disjoint(&mut indels));
        TextEdit { indels }
    }
    pub fn invalidates_offset(&self, offset: TextSize) -> bool {
        self.indels.iter().any(|indel| indel.delete.contains_inclusive(offset))
    }
    fn indel(&mut self, indel: Indel) {
        self.indels.push(indel);
        if self.indels.len() <= 16 {
            check_disjoint(&mut self.indels);
        }
    }
}

fn check_disjoint(indels: &mut [impl std::borrow::Borrow<Indel>]) -> bool {
    indels.sort_by_key(|indel| (indel.borrow().delete.start(), indel.borrow().delete.end()));
    indels
        .iter()
        .zip(indels.iter().skip(1))
        .all(|(l, r)| l.borrow().delete.end() <= r.borrow().delete.start())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::io;
use std::io::prelude::*;

type SudokuCandidate = u64;
type SudokuCellGroups = HashMap<usize, Vec<Vec<usize>>>;
const SUDOKU_DIGIT_BASE: u32 = 10;
const SUDOKU_CANDIDATE_SIZE: usize = 9;
const SUDOKU_BOX_SIZE: usize = 3;
const SUDOKU_GROUP_SIZE: usize = 9;
const SUDOKU_CELL_SIZE: usize = 81;
const SUDOKU_ALL_CANDIDATES: SudokuCandidate = ((1 << SUDOKU_CANDIDATE_SIZE) - 1);

// Sudoku cell that contains candidates as a bitboard
#[derive(Clone, Copy)]
struct SudokuCell {
    candidates: SudokuCandidate
}

impl SudokuCell {
    fn new() -> SudokuCell {
        SudokuCell { candidates: 0 }
    }

    fn to_string(&self) -> String {
        let mut line = String::new();
        for candidate in 0..(SUDOKU_CANDIDATE_SIZE as SudokuCandidate) {
            if self.has_candidate(&candidate) {
                line.push_str(&(candidate+1).to_string());
            }
        }
        line
    }

    fn preset_full_candidate(&mut self) {
        self.candidates = SUDOKU_ALL_CANDIDATES;
    }

    // Input '1'..'9'
    fn preset_candidate(&mut self, ch: char) {
        let code_digit_base = '1'.to_digit(SUDOKU_DIGIT_BASE).unwrap();
        match ch {
            '1'...'9' => {
                let number = (ch.to_digit(SUDOKU_DIGIT_BASE).unwrap() - code_digit_base) as SudokuCandidate;
                self.candidates = self.digit_to_candidate(&number);
            }
            _ => {}
        }
    }

    // Input 0..8
    fn overwrite_candidate(&mut self, candidate: SudokuCandidate) {
        if self.count_candidates() > 1 {
            self.candidates = self.digit_to_candidate(&candidate);
        }
    }

    fn count_candidates(&self) -> usize {
        let f = |candidate| {
            if (self.candidates & self.digit_to_candidate(&candidate))
                != 0 { 1 } else { 0 } };
        (0..SUDOKU_CANDIDATE_SIZE as SudokuCandidate).fold(
            0, |sum, candidates| sum + f(candidates))
    }

    fn has_unique_candidate(&self) -> bool {
        SudokuCell::is_unique_candidate(self.candidates)
    }

    fn is_unique_candidate(candidates: SudokuCandidate) -> bool {
        // Check whether only one bit is set
        candidates > 0 && (candidates & (candidates - 1)) == 0
    }

    fn has_all_candidates(&self) -> bool {
        self.candidates == SUDOKU_ALL_CANDIDATES
    }

    // Input 0..8
    fn can_mask(&mut self, candidates: SudokuCandidate) -> bool {
        (self.candidates & self.digit_to_candidate(&candidates)) != 0
    }

    fn merge_candidate(&mut self, rhs: &SudokuCell) {
        self.candidates |= rhs.candidates;
    }

    // Returns whether no candidates are merged
    fn merge_unique_candidate(&mut self, rhs: &SudokuCell) -> bool {
        if rhs.has_unique_candidate() {
            if (self.candidates & rhs.candidates) != 0 {
                return true;
            }
            self.candidates |= rhs.candidates;
        }
        false
    }

    fn filter_by_candidates(&mut self, rhs: &SudokuCell) {
        if !self.has_unique_candidate() {
            self.candidates &= !rhs.candidates;
        }
    }

    fn fill_unused_candidate(&mut self, rhs: &SudokuCell) {
        if !self.has_unique_candidate() {
            let candidates = SUDOKU_ALL_CANDIDATES & !rhs.candidates;
            if SudokuCell::is_unique_candidate(candidates) {
                self.candidates = candidates;
            }
        }
    }

    // Inner methods
    // Input 0..8
    fn digit_to_candidate(&self, candidate: &SudokuCandidate) -> SudokuCandidate {
        (1 as SudokuCandidate) << candidate
    }

    // Input 0..8
    fn has_candidate(&self, candidate: &SudokuCandidate) -> bool {
        (self.candidates & self.digit_to_candidate(&candidate)) != 0
    }
}

// Generator for sudoku cellgroups
struct SudokuGroupGen {
    index: usize
}

impl SudokuGroupGen {
    fn new() -> SudokuGroupGen {
        SudokuGroupGen { index:0 }
    }

    fn next(&mut self) -> Option<Vec<usize>> {
        if self.index < SUDOKU_GROUP_SIZE {
            let lower = self.index * SUDOKU_GROUP_SIZE;
            let upper = (self.index + 1) * SUDOKU_GROUP_SIZE;
            self.index += 1;
            Some((lower..upper).collect::<Vec<_>>())
        } else if self.index < (SUDOKU_GROUP_SIZE * 2) {
            let column = self.index - SUDOKU_GROUP_SIZE;
            self.index += 1;
            Some((0..SUDOKU_GROUP_SIZE).map(|i| column + i * SUDOKU_GROUP_SIZE).collect::<Vec<_>>())
        } else if self.index < (SUDOKU_GROUP_SIZE * 3) {
            let box_index = self.index - SUDOKU_GROUP_SIZE * 2;
            let offset = (box_index % 3) * 3  + (box_index / 3) * SUDOKU_GROUP_SIZE * 3;
            let mut indexes : Vec<usize> = Vec::new();
            for row in 0..SUDOKU_BOX_SIZE {
                let x = (0..SUDOKU_BOX_SIZE).map(|column| row * SUDOKU_GROUP_SIZE + column + offset).collect::<Vec<_>>();
                indexes.extend(x);
            }
            self.index += 1;
            Some(indexes)
        } else {
            None
        }
    }
}

// Sudoku cell map
struct SudokuMap<'a> {
    cells : Vec<SudokuCell>,
    groups : &'a SudokuCellGroups,
}

impl<'a> SudokuMap<'a> {
    fn new(line: &str, cell_groups: &'a SudokuCellGroups) -> SudokuMap<'a> {
        let mut cells = vec![SudokuCell::new(); SUDOKU_CELL_SIZE];
        for cell in &mut cells {
            cell.preset_full_candidate();
        }

        for (index, ch) in line.chars().enumerate() {
            cells[index].preset_candidate(ch);
        };
        SudokuMap { cells:cells, groups: cell_groups }
    }

    fn to_string(&self, one_line: bool) -> String {
        let mut full_text = String::new();

        for row in 0..SUDOKU_GROUP_SIZE {
            let mut line = String::new();
            for column in 0..SUDOKU_GROUP_SIZE {
                let index = row * SUDOKU_GROUP_SIZE + column;
                let cell_str = self.cells[index].to_string();
                line.push_str(&cell_str);
                if !one_line {
                    line.push_str(":");
                }
            }
            if !one_line {
                line.push_str("\n");
            }
            full_text.push_str(&line);
        }
        full_text
    }

    fn solve(&mut self) -> bool {
        let mut prev_count = SUDOKU_CELL_SIZE * SUDOKU_CANDIDATE_SIZE;
        loop {
            self.filter_unique_candidates();
            self.find_unused_candidates();

            if self.is_solved() {
                return true;
            }
            if !self.is_consistent() {
                return false;
            }

            let count = (0..SUDOKU_CELL_SIZE).fold(0, |sum, index| sum + self.cells[index].count_candidates());
            if prev_count == count {
                break;
            }
            prev_count = count;
        }

        let index_min_count = self.find_backtracking_target();
        if self.cells[index_min_count].count_candidates() <= 1 {
            return false;
        }

        for candidate in 0..(SUDOKU_CANDIDATE_SIZE as SudokuCandidate) {
            if self.cells[index_min_count].can_mask(candidate) {
                let mut new_map = SudokuMap::new("", self.groups);
                new_map.cells = self.cells.clone();
                new_map.cells[index_min_count].overwrite_candidate(candidate);
                if new_map.solve() {
                    self.cells = new_map.cells;
                    return self.is_solved();
                }
            }
        }

        false
    }

    fn filter_unique_candidates(&mut self) {
        for target_index in 0..SUDOKU_CELL_SIZE {
            let mut sum = SudokuCell::new();
            for group in self.groups[&target_index].iter() {
                for cell_index in group.iter() {
                    if *cell_index != target_index {
                        sum.merge_unique_candidate(&self.cells[*cell_index]);
                    }
                }
            }
            self.cells[target_index].filter_by_candidates(&sum);
        }
    }

    fn find_unused_candidates(&mut self) {
        for target_index in 0..SUDOKU_CELL_SIZE {
            for group in self.groups[&target_index].iter() {
                let mut sum = SudokuCell::new();
                for cell_index in group.iter() {
                    if *cell_index != target_index {
                        sum.merge_candidate(&self.cells[*cell_index]);
                    }
                }
                self.cells[target_index].fill_unused_candidate(&sum);
            }
        }
    }

    fn find_backtracking_target(&self) -> usize {
        // SUDOKU_CELL_SIZE = a large enough number
        let mut min_count = SUDOKU_CELL_SIZE;
        let mut cell_counts = Vec::new();

        for row_index in 0..SUDOKU_GROUP_SIZE {
            let mut row_counts = vec![SUDOKU_CELL_SIZE; SUDOKU_GROUP_SIZE];
            for column_index in 0..SUDOKU_GROUP_SIZE {
                let cell_count = self.cells[row_index * SUDOKU_GROUP_SIZE + column_index].count_candidates();
                if cell_count > 1 {
                    row_counts[column_index] = cell_count;
                    if cell_count < min_count {
                        min_count = cell_count;
                    }
                }
            }
            cell_counts.push(row_counts);
        }

        let row_counts = cell_counts.iter().map(
            |row| row.iter().fold(0, |sum, &count| sum + if count == min_count { 1 } else { 0 })).collect::<Vec<usize>>();
        let max_row_count = row_counts.iter().max().unwrap();
        let target_row = row_counts.iter().position(|&count| count == *max_row_count).unwrap();
        let target_column = cell_counts[target_row].iter().position(|&count| count == min_count).unwrap();
        target_row * SUDOKU_GROUP_SIZE + target_column
    }

    fn is_solved(&self) -> bool {
        let mut group_gen = SudokuGroupGen::new();
        while let Some(indexes) = group_gen.next() {
            if !self.is_group_solved(indexes) {
                return false;
            }
        }
        true
    }

    fn is_group_solved(&self, cell_indexes: Vec<usize>) -> bool {
        let mut sum = SudokuCell::new();
        let mut conflict = false;
        for cell_index in cell_indexes {
            conflict |= sum.merge_unique_candidate(&self.cells[cell_index]);
        }
        sum.has_all_candidates() && !conflict
    }

    fn is_consistent(&self) -> bool {
        let mut group_gen = SudokuGroupGen::new();
        while let Some(indexes) = group_gen.next() {
            if !self.is_group_consistent(indexes) {
                return false;
            }
        }
        true
    }

    fn is_group_consistent(&self, cell_indexes: Vec<usize>) -> bool {
        let mut all_candidates = SudokuCell::new();
        let mut unique_candidates = SudokuCell::new();
        let mut conflict = false;

        for cell_index in cell_indexes {
            all_candidates.merge_candidate(&self.cells[cell_index]);
            conflict |= unique_candidates.merge_unique_candidate(&self.cells[cell_index]);
        }
        all_candidates.has_all_candidates() && !conflict
    }
}

// Set of sudoku cellgroups
fn create_group_index_set() -> SudokuCellGroups {
    let mut groups = HashMap::new();
    for cell_index in 0..SUDOKU_CELL_SIZE {
        let mut group_candidates = Vec::new();
        let row_number = cell_index / SUDOKU_GROUP_SIZE;
        let row_lower = row_number * SUDOKU_GROUP_SIZE;
        let row_upper = (row_number + 1) * SUDOKU_GROUP_SIZE;
        let row = (row_lower..row_upper).collect::<Vec<_>>();
        group_candidates.push(row);

        let column_number = cell_index % SUDOKU_GROUP_SIZE;
        let column = (0..SUDOKU_GROUP_SIZE).map(|i| column_number + i * SUDOKU_GROUP_SIZE).collect::<Vec<_>>();
        group_candidates.push(column);

        let box_offset = (row_number / SUDOKU_BOX_SIZE) * SUDOKU_BOX_SIZE * SUDOKU_GROUP_SIZE +
            (column_number / SUDOKU_BOX_SIZE) * SUDOKU_BOX_SIZE;
        let mut cell_box = Vec::new();
        for row_offset in 0..SUDOKU_BOX_SIZE {
            let x = (0..SUDOKU_BOX_SIZE).map(|column_offset| row_offset * SUDOKU_GROUP_SIZE + column_offset + box_offset);
            cell_box.extend(x);
        }
        group_candidates.push(cell_box);
        groups.insert(cell_index, group_candidates);
    }
    groups
}

fn main() {
    // Shares cell groups between all questions
    let cell_groups = create_group_index_set();
    println!("Solving in Rust");

    let stdin = io::stdin();
    let mut lines = Vec::new();
    let mut count = 0;
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        lines.push(line);
        count += 1;
    }

    let mut result = true;
    let mut answers = String::new();
    for line in lines {
        let mut sudoku_map = SudokuMap::new(&line, &cell_groups);
        result &= sudoku_map.solve();
        let s = sudoku_map.to_string(true);
        answers.push_str(&s);
        answers.push_str("\n");
    }

    print!("{}", answers);
    if result {
        println!("All {} cases passed.", count);
    }
}
<commit_msg>Make the Rust solver fast<commit_after>use std::collections::HashMap;
use std::io;
use std::io::prelude::*;

type SudokuCandidate = u64;  // or u32
type SudokuCellGroups = HashMap<usize, Vec<Vec<usize>>>;

const SUDOKU_DIGIT_BASE: u32 = 10;
const SUDOKU_BOX_SIZE: usize = 3;
const SUDOKU_NO_CANDIDATES: SudokuCandidate = 0;
const SUDOKU_ALL_CANDIDATES: SudokuCandidate = ((1 << SUDOKU_CANDIDATE_SIZE) - 1);

const SUDOKU_GROUP_SIZE: usize = SUDOKU_BOX_SIZE * SUDOKU_BOX_SIZE;
const SUDOKU_CANDIDATE_SIZE: usize = SUDOKU_GROUP_SIZE;
const SUDOKU_CELL_SIZE: usize = SUDOKU_GROUP_SIZE * SUDOKU_GROUP_SIZE;

// Sudoku cell that contains candidates as a bitboard
#[derive(Clone, Copy)]
struct SudokuCell {
    candidates: SudokuCandidate
}

impl SudokuCell {
    fn new() -> SudokuCell {
        SudokuCell { candidates: SUDOKU_NO_CANDIDATES }
    }

    fn to_string(&self) -> String {
        let mut line = String::new();
        for candidate in 0..(SUDOKU_CANDIDATE_SIZE as SudokuCandidate) {
            if self.has_candidate(&candidate) {
                line.push_str(&(candidate+1).to_string());
            }
        }
        line
    }

    fn preset_full_candidate(&mut self) {
        self.candidates = SUDOKU_ALL_CANDIDATES;
    }

    // Input '1'..'9'
    fn preset_candidate(&mut self, ch: char) {
        let code_digit_base = '1'.to_digit(SUDOKU_DIGIT_BASE).unwrap();
        match ch {
            '1'...'9' => {
                let number = (ch.to_digit(SUDOKU_DIGIT_BASE).unwrap() - code_digit_base) as SudokuCandidate;
                self.candidates = self.digit_to_candidate(&number);
            }
            _ => {}
        }
    }

    // Input 0..8
    fn overwrite_candidate(&mut self, candidate: SudokuCandidate) {
        if self.count_candidates() > 1 {
            self.candidates = self.digit_to_candidate(&candidate);
        }
    }

    fn count_candidates(&self) -> usize {
        (self.candidates & SUDOKU_ALL_CANDIDATES).count_ones() as usize
    }

    fn has_unique_candidate(&self) -> bool {
        SudokuCell::is_unique_candidate(self.candidates)
    }

    fn is_unique_candidate(candidates: SudokuCandidate) -> bool {
        // Check whether only one bit is set
        candidates > 0 && (candidates & (candidates - 1)) == 0
    }

    fn has_all_candidates(&self) -> bool {
        self.candidates == SUDOKU_ALL_CANDIDATES
    }

    // Input 0..8
    fn can_mask(&mut self, candidates: SudokuCandidate) -> bool {
        (self.candidates & self.digit_to_candidate(&candidates)) != 0
    }

    fn merge_candidate(&mut self, rhs: &SudokuCell) {
        self.candidates |= rhs.candidates;
    }

    // Returns whether no candidates are merged
    fn merge_unique_candidate(&mut self, rhs: &SudokuCell) -> bool {
        if rhs.has_unique_candidate() {
            if (self.candidates & rhs.candidates) != 0 {
                return true;
            }
            self.candidates |= rhs.candidates;
        }
        false
    }

    fn filter_by_candidates(&mut self, rhs: &SudokuCell) {
        if !self.has_unique_candidate() {
            self.candidates &= !rhs.candidates;
        }
    }

    fn fill_unused_candidate(&mut self, rhs: &SudokuCell) {
        if !self.has_unique_candidate() {
            let candidates = SUDOKU_ALL_CANDIDATES & !rhs.candidates;
            if SudokuCell::is_unique_candidate(candidates) {
                self.candidates = candidates;
            }
        }
    }

    // Input 0..8
    fn digit_to_candidate(&self, candidate: &SudokuCandidate) -> SudokuCandidate {
        (1 as SudokuCandidate) << candidate
    }

    // Input 0..8
    fn has_candidate(&self, candidate: &SudokuCandidate) -> bool {
        (self.candidates & self.digit_to_candidate(&candidate)) != 0
    }
}

// Generator for sudoku cellgroups
struct SudokuGroupGen {
    index: usize
}

impl SudokuGroupGen {
    fn new() -> SudokuGroupGen {
        SudokuGroupGen { index:0 }
    }

    fn next(&mut self) -> Option<Vec<usize>> {
        if self.index < SUDOKU_GROUP_SIZE {
            let lower = self.index * SUDOKU_GROUP_SIZE;
            let upper = (self.index + 1) * SUDOKU_GROUP_SIZE;
            self.index += 1;
            Some((lower..upper).collect::<Vec<_>>())
        } else if self.index < (SUDOKU_GROUP_SIZE * 2) {
            let column = self.index - SUDOKU_GROUP_SIZE;
            self.index += 1;
            Some((0..SUDOKU_GROUP_SIZE).map(
                |row| column + row * SUDOKU_GROUP_SIZE).collect::<Vec<_>>())
        } else if self.index < (SUDOKU_GROUP_SIZE * 3) {
            let box_index = self.index - SUDOKU_GROUP_SIZE * 2;
            let offset = (box_index % 3) * 3  + (box_index / 3) * SUDOKU_GROUP_SIZE * 3;
            let mut indexes : Vec<usize> = Vec::new();
            for row in 0..SUDOKU_BOX_SIZE {
                let x = (0..SUDOKU_BOX_SIZE).map(
                    |column| row * SUDOKU_GROUP_SIZE + column + offset).collect::<Vec<_>>();
                indexes.extend(x);
            }
            self.index += 1;
            Some(indexes)
        } else {
            None
        }
    }
}

// Sudoku cell map
struct SudokuMap<'a> {
    cells : Vec<SudokuCell>,
    groups : &'a SudokuCellGroups,
}

impl<'a> SudokuMap<'a> {
    fn new(line: &str, cell_groups: &'a SudokuCellGroups) -> SudokuMap<'a> {
        let mut cells = vec![SudokuCell::new(); SUDOKU_CELL_SIZE];
        for cell in &mut cells {
            cell.preset_full_candidate();
        }

        // Leave tail cells if the line is shorter than the number of cells.
        for (index, ch) in line.chars().enumerate() {
            cells[index].preset_candidate(ch);
        };
        SudokuMap { cells:cells, groups: cell_groups }
    }

    fn to_string(&self, one_line: bool) -> String {
        let mut full_text = String::new();

        for row in 0..SUDOKU_GROUP_SIZE {
            let mut line = String::new();
            for column in 0..SUDOKU_GROUP_SIZE {
                let index = row * SUDOKU_GROUP_SIZE + column;
                let cell_str = self.cells[index].to_string();
                line.push_str(&cell_str);
                if !one_line {
                    line.push_str(":");
                }
            }
            if !one_line {
                line.push_str("\n");
            }
            full_text.push_str(&line);
        }
        full_text
    }

    fn solve(&mut self) -> bool {
        let mut prev_count = SUDOKU_CELL_SIZE * SUDOKU_CANDIDATE_SIZE;
        loop {
            self.filter_unique_candidates();
            self.find_unused_candidates();

            if self.is_solved() {
                return true;
            }

            if !self.is_consistent() {
                return false;
            }

            let count = (0..SUDOKU_CELL_SIZE).fold(
                0, |sum, index| sum + self.cells[index].count_candidates());
            if prev_count == count {
                break;
            }
            prev_count = count;
        }

        let index_min_count = self.find_backtracking_target();
        if self.cells[index_min_count].count_candidates() <= 1 {
            return false;
        }

        for candidate in 0..(SUDOKU_CANDIDATE_SIZE as SudokuCandidate) {
            if self.cells[index_min_count].can_mask(candidate) {
                let mut new_map = SudokuMap::new("", self.groups);
                new_map.cells = self.cells.clone();
                new_map.cells[index_min_count].overwrite_candidate(candidate);
                if new_map.solve() {
                    self.cells = new_map.cells;
                    return self.is_solved();
                }
            }
        }

        false
    }

    fn filter_unique_candidates(&mut self) {
        for target_index in 0..SUDOKU_CELL_SIZE {
            if self.cells[target_index].has_unique_candidate() {
                continue;
            }

            let mut sum = SudokuCell::new();
            for group in self.groups[&target_index].iter() {
                for cell_index in group.iter() {
                    if *cell_index != target_index {
                        sum.merge_unique_candidate(&self.cells[*cell_index]);
                    }
                }
            }
            self.cells[target_index].filter_by_candidates(&sum);
        }
    }

    fn find_unused_candidates(&mut self) {
        for target_index in 0..SUDOKU_CELL_SIZE {
            if self.cells[target_index].has_unique_candidate() {
                continue;
            }

            for group in self.groups[&target_index].iter() {
                let mut sum = SudokuCell::new();
                for cell_index in group.iter() {
                    if *cell_index != target_index {
                        sum.merge_candidate(&self.cells[*cell_index]);
                    }
                }
                self.cells[target_index].fill_unused_candidate(&sum);
            }
        }
    }

    fn find_backtracking_target(&self) -> usize {
        // SUDOKU_CELL_SIZE = a large enough number
        let mut min_count = SUDOKU_CELL_SIZE;
        let mut cell_counts = Vec::new();

        for row_index in 0..SUDOKU_GROUP_SIZE {
            let mut row_counts = vec![SUDOKU_CELL_SIZE; SUDOKU_GROUP_SIZE];
            for column_index in 0..SUDOKU_GROUP_SIZE {
                let cell_count = self.cells[row_index * SUDOKU_GROUP_SIZE + column_index].count_candidates();
                if cell_count > 1 {
                    row_counts[column_index] = cell_count;
                    if cell_count < min_count {
                        min_count = cell_count;
                    }
                }
            }
            cell_counts.push(row_counts);
        }

        let row_counts = cell_counts.iter().map(
            |row| row.iter().fold(0, |sum, &count| sum + if count == min_count { 1 } else { 0 })).collect::<Vec<usize>>();
        let max_row_count = row_counts.iter().max().unwrap();
        let target_row = row_counts.iter().position(|&count| count == *max_row_count).unwrap();
        let target_column = cell_counts[target_row].iter().position(|&count| count == min_count).unwrap();
        target_row * SUDOKU_GROUP_SIZE + target_column
    }

    fn is_solved(&self) -> bool {
        let mut group_gen = SudokuGroupGen::new();
        while let Some(indexes) = group_gen.next() {
            if !self.is_group_solved(indexes) {
                return false;
            }
        }
        true
    }

    fn is_group_solved(&self, cell_indexes: Vec<usize>) -> bool {
        let mut sum = SudokuCell::new();
        let mut conflict = false;
        for cell_index in cell_indexes {
            let cell = &self.cells[cell_index];
            conflict |= sum.merge_unique_candidate(&cell);
        }
        sum.has_all_candidates() && !conflict
    }

    fn is_consistent(&self) -> bool {
        let mut group_gen = SudokuGroupGen::new();
        while let Some(indexes) = group_gen.next() {
            if !self.is_group_consistent(indexes) {
                return false;
            }
        }
        true
    }

    fn is_group_consistent(&self, cell_indexes: Vec<usize>) -> bool {
        let mut all_candidates = SudokuCell::new();
        let mut unique_candidates = SudokuCell::new();
        let mut conflict = false;

        for cell_index in cell_indexes {
            all_candidates.merge_candidate(&self.cells[cell_index]);
            conflict |= unique_candidates.merge_unique_candidate(&self.cells[cell_index]);
        }
        all_candidates.has_all_candidates() && !conflict
    }
}

// Set of sudoku cellgroups
fn create_group_index_set() -> SudokuCellGroups {
    let mut groups = HashMap::new();
    for cell_index in 0..SUDOKU_CELL_SIZE {
        let mut group_candidates = Vec::new();
        let row_number = cell_index / SUDOKU_GROUP_SIZE;
        let row_lower = row_number * SUDOKU_GROUP_SIZE;
        let row_upper = (row_number + 1) * SUDOKU_GROUP_SIZE;
        let row = (row_lower..row_upper).collect::<Vec<_>>();
        group_candidates.push(row);

        let column_number = cell_index % SUDOKU_GROUP_SIZE;
        let column = (0..SUDOKU_GROUP_SIZE).map(|i| column_number + i * SUDOKU_GROUP_SIZE).collect::<Vec<_>>();
        group_candidates.push(column);

        let box_offset = (row_number / SUDOKU_BOX_SIZE) * SUDOKU_BOX_SIZE * SUDOKU_GROUP_SIZE +
            (column_number / SUDOKU_BOX_SIZE) * SUDOKU_BOX_SIZE;
        let mut cell_box = Vec::new();
        for row_offset in 0..SUDOKU_BOX_SIZE {
            let x = (0..SUDOKU_BOX_SIZE).map(|column_offset| row_offset * SUDOKU_GROUP_SIZE + column_offset + box_offset);
            cell_box.extend(x);
        }
        group_candidates.push(cell_box);
        groups.insert(cell_index, group_candidates);
    }
    groups
}

fn main() {
    // Shares cell groups between all questions
    let cell_groups = create_group_index_set();
    println!("Solving in Rust");

    let stdin = io::stdin();
    let mut lines = Vec::new();
    let mut count = 0;
    for line in stdin.lock().lines() {
        let line = line.unwrap();
        lines.push(line);
        count += 1;
    }

    let mut result = true;
    let mut answers = String::new();
    for line in lines {
        let mut sudoku_map = SudokuMap::new(&line, &cell_groups);
        result &= sudoku_map.solve();
        let s = sudoku_map.to_string(true);
        answers.push_str(&s);
        answers.push_str("\n");
    }

    print!("{}", answers);
    if result {
        println!("All {} cases passed.", count);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use syntax::ast::{ItemKind, MetaItem};
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use utils::match_ty_unwrap;

pub fn expand_reflector(cx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable: &Annotatable,
                        push: &mut FnMut(Annotatable)) {
    if let &Annotatable::Item(ref item) = annotatable {
        if let ItemKind::Struct(ref def, _) = item.node {
            let struct_name = item.ident;
            // This path has to be hardcoded, unfortunately, since we can't resolve paths at expansion time
            match def.fields().iter().find(
                    |f| match_ty_unwrap(&*f.ty, &["dom", "bindings", "reflector", "Reflector"]).is_some()) {
                // If it has a field that is a Reflector, use that
                Some(f) => {
                    let field_name = f.ident;
                    let impl_item = quote_item!(cx,
                        impl ::dom::bindings::reflector::Reflectable for $struct_name {
                            fn reflector<'a>(&'a self) -> &'a ::dom::bindings::reflector::Reflector {
                                &self.$field_name
                            }
                        }
                    );
                    let impl_item_mut = quote_item!(cx,
                        impl ::dom::bindings::reflector::MutReflectable for $struct_name {
                            fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
                                self.$field_name.set_jsobject(obj);
                            }
                        }
                    );
                    impl_item.map(|it| push(Annotatable::Item(it)));
                    impl_item_mut.map(|it| push(Annotatable::Item(it)))
                },
                // Or just call it on the first field (supertype).
                None => {
                    let field_name = def.fields()[0].ident;
                    let impl_item = quote_item!(cx,
                        impl ::dom::bindings::reflector::Reflectable for $struct_name {
                            fn reflector<'a>(&'a self) -> &'a ::dom::bindings::reflector::Reflector {
                                self.$field_name.reflector()
                            }
                        }
                    );
                    let impl_item_mut = quote_item!(cx,
                        impl ::dom::bindings::reflector::MutReflectable for $struct_name {
                            fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
                                self.$field_name.init_reflector(obj);
                            }
                        }
                    );
                    impl_item.map(|it| push(Annotatable::Item(it)));
                    impl_item_mut.map(|it| push(Annotatable::Item(it)))
                }
            };

            let impl_item = quote_item!(cx,
                impl ::js::conversions::ToJSValConvertible for $struct_name {
                    #[allow(unsafe_code)]
                    unsafe fn to_jsval(&self,
                                       cx: *mut ::js::jsapi::JSContext,
                                       rval: ::js::jsapi::MutableHandleValue) {
                        let object = ::dom::bindings::reflector::Reflectable::reflector(self).get_jsobject();
                        object.to_jsval(cx, rval)
                    }
                }
            );
            impl_item.map(|it| push(Annotatable::Item(it)));
        } else {
            cx.span_err(span, "#[dom_struct] seems to have been applied to a non-struct");
        }
    }
}
<commit_msg>Auto merge of #13425 - Manishearth:no-crash-empty-dom, r=emilio,Ms2ger<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use syntax::ast::{ItemKind, MetaItem};
use syntax::codemap::Span;
use syntax::ext::base::{Annotatable, ExtCtxt};
use utils::match_ty_unwrap;

pub fn expand_reflector(cx: &mut ExtCtxt, span: Span, _: &MetaItem, annotatable: &Annotatable,
                        push: &mut FnMut(Annotatable)) {
    if let &Annotatable::Item(ref item) = annotatable {
        if let ItemKind::Struct(ref def, _) = item.node {
            if def.fields().is_empty() {
                cx.span_err(span, "#[dom_struct] should have a reflector or \
                                   parent dom struct as its first field");
                return;
            }
            let struct_name = item.ident;
            // This path has to be hardcoded, unfortunately, since we can't resolve paths at expansion time
            match def.fields().iter().find(
                    |f| match_ty_unwrap(&*f.ty, &["dom", "bindings", "reflector", "Reflector"]).is_some()) {
                // If it has a field that is a Reflector, use that
                Some(f) => {
                    let field_name = f.ident;
                    let impl_item = quote_item!(cx,
                        impl ::dom::bindings::reflector::Reflectable for $struct_name {
                            fn reflector<'a>(&'a self) -> &'a ::dom::bindings::reflector::Reflector {
                                &self.$field_name
                            }
                        }
                    );
                    let impl_item_mut = quote_item!(cx,
                        impl ::dom::bindings::reflector::MutReflectable for $struct_name {
                            fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
                                self.$field_name.set_jsobject(obj);
                            }
                        }
                    );
                    impl_item.map(|it| push(Annotatable::Item(it)));
                    impl_item_mut.map(|it| push(Annotatable::Item(it)))
                },
                // Or just call it on the first field (supertype).
                None => {
                    let field_name = def.fields()[0].ident;
                    let impl_item = quote_item!(cx,
                        impl ::dom::bindings::reflector::Reflectable for $struct_name {
                            fn reflector<'a>(&'a self) -> &'a ::dom::bindings::reflector::Reflector {
                                self.$field_name.reflector()
                            }
                        }
                    );
                    let impl_item_mut = quote_item!(cx,
                        impl ::dom::bindings::reflector::MutReflectable for $struct_name {
                            fn init_reflector(&mut self, obj: *mut ::js::jsapi::JSObject) {
                                self.$field_name.init_reflector(obj);
                            }
                        }
                    );
                    impl_item.map(|it| push(Annotatable::Item(it)));
                    impl_item_mut.map(|it| push(Annotatable::Item(it)))
                }
            };

            let impl_item = quote_item!(cx,
                impl ::js::conversions::ToJSValConvertible for $struct_name {
                    #[allow(unsafe_code)]
                    unsafe fn to_jsval(&self,
                                       cx: *mut ::js::jsapi::JSContext,
                                       rval: ::js::jsapi::MutableHandleValue) {
                        let object = ::dom::bindings::reflector::Reflectable::reflector(self).get_jsobject();
                        object.to_jsval(cx, rval)
                    }
                }
            );
            impl_item.map(|it| push(Annotatable::Item(it)));
        } else {
            cx.span_err(span, "#[dom_struct] seems to have been applied to a non-struct");
        }
    }
}
<|endoftext|>


<commit_before>extern crate pkg_config;
extern crate semver;

use std::error::Error;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use std::{env, fs};
use semver::Version;

const LIBRARY: &'static str = "tensorflow_c";
const REPOSITORY: &'static str = "https://github.com/tensorflow/tensorflow.git";
const TARGET: &'static str = "tensorflow:libtensorflow_c.so";
const TAG: &'static str = "v0.12.0";
const MIN_BAZEL: &'static str = "0.3.2";

macro_rules! get(($name:expr) => (ok!(env::var($name))));
macro_rules! ok(($expression:expr) => ($expression.unwrap()));
macro_rules! log {
    ($fmt:expr) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt), line!()));
    ($fmt:expr, $($arg:tt)*) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt), line!(), $($arg)*));
}
macro_rules! log_var(($var:ident) => (log!(concat!(stringify!($var), " = {:?}"), $var)));

fn main() {
    if pkg_config::find_library(LIBRARY).is_ok() {
        log!("Returning early because {} was already found", LIBRARY);
        return;
    }

    let output = PathBuf::from(&get!("OUT_DIR"));
    log_var!(output);
    let source = PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join(format!("target/source-{}", TAG));
    log_var!(source);
    let lib_dir = output.join(format!("lib-{}", TAG));
    log_var!(lib_dir);
    if lib_dir.exists() {
        log!("Directory {:?} already exists", lib_dir);
    } else {
        log!("Creating directory {:?}", lib_dir);
        fs::create_dir(lib_dir.clone()).unwrap();
    }
    let library_path = lib_dir.join(format!("lib{}.so", LIBRARY));
    log_var!(library_path);
    if library_path.exists() {
        log!("{:?} already exists, not building", library_path);
    } else {
        if let Err(e) = check_bazel() {
            println!("cargo:error=Bazel must be installed at be version {} or greater. (Error: {})", MIN_BAZEL, e);
            process::exit(1);
        }
        let target_path = &TARGET.replace(":", "/");
        log_var!(target_path);
        if !Path::new(&source.join(".git")).exists() {
            run("git", |command| command.arg("clone")
                                        .arg(format!("--branch={}", TAG))
                                        .arg("--recursive")
                                        .arg(REPOSITORY)
                                        .arg(&source));
        }
        run("bash", |command| command.current_dir(&source).arg("-c").arg("yes ''|./configure"));
        run("bazel", |command| command.current_dir(&source)
                                      .arg("build")
                                      .arg(format!("--jobs={}", get!("NUM_JOBS")))
                                      .arg("--compilation_mode=opt")
                                      .arg(TARGET));
        let target_bazel_bin = source.join("bazel-bin").join(target_path);
        log!("Copying {:?} to {:?}", target_bazel_bin, library_path);
        fs::copy(target_bazel_bin, library_path).unwrap();
    }

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", lib_dir.display());
}

fn run<F>(name: &str, mut configure: F) where F: FnMut(&mut Command) -> &mut Command {
    let mut command = Command::new(name);
    let configured = configure(&mut command);
    log!("Executing {:?}", configured);
    if !ok!(configured.status()).success() {
        panic!("failed to execute {:?}", configured);
    }
    log!("Command {:?} finished successfully", configured);
}

// Building TF 0.11.0rc1 with Bazel 0.3.0 gives this error when running `configure`:
//   expected ConfigurationTransition or NoneType for 'cfg' while calling label_list but got string instead:     data.
//       ERROR: com.google.devtools.build.lib.packages.BuildFileContainsErrorsException: error loading package '': Extension file 'tensorflow/tensorflow.bzl' has errors.
// And the simple solution is to require Bazel 0.3.1 or higher.
fn check_bazel() -> Result<(), Box<Error>> {
    let mut command = Command::new("bazel");
    command.arg("version");
    log!("Executing {:?}", command);
    let out = try!(command.output());
    log!("Command {:?} finished successfully", command);
    let stdout = try!(String::from_utf8(out.stdout));
    let mut found_version = false;
    for line in stdout.lines() {
        if line.starts_with("Build label:") {
            found_version = true;
            let version_str = line.split(":").nth(1).unwrap().trim();
            let version = try!(Version::parse(version_str));
            let want = try!(Version::parse(MIN_BAZEL));
            if version < want {
                return Err(format!("Installed version {} is less than required version {}", version_str, MIN_BAZEL).into());
            }
        }
    }
    if !found_version {
        return Err("Did not find version number in `bazel version` output.".into());
    }
    Ok(())
}
<commit_msg>Support resuming TensorFlow build<commit_after>extern crate pkg_config;
extern crate semver;

use std::error::Error;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process;
use std::process::Command;
use std::{env, fs};
use semver::Version;

const LIBRARY: &'static str = "tensorflow_c";
const REPOSITORY: &'static str = "https://github.com/tensorflow/tensorflow.git";
const TARGET: &'static str = "tensorflow:libtensorflow_c.so";
const TAG: &'static str = "v0.12.0";
const MIN_BAZEL: &'static str = "0.3.2";

macro_rules! get(($name:expr) => (ok!(env::var($name))));
macro_rules! ok(($expression:expr) => ($expression.unwrap()));
macro_rules! log {
    ($fmt:expr) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt), line!()));
    ($fmt:expr, $($arg:tt)*) => (println!(concat!("libtensorflow-sys/build.rs:{}: ", $fmt), line!(), $($arg)*));
}
macro_rules! log_var(($var:ident) => (log!(concat!(stringify!($var), " = {:?}"), $var)));

fn main() {
    if pkg_config::find_library(LIBRARY).is_ok() {
        log!("Returning early because {} was already found", LIBRARY);
        return;
    }

    let output = PathBuf::from(&get!("OUT_DIR"));
    log_var!(output);
    let source = PathBuf::from(&get!("CARGO_MANIFEST_DIR")).join(format!("target/source-{}", TAG));
    log_var!(source);
    let lib_dir = output.join(format!("lib-{}", TAG));
    log_var!(lib_dir);
    if lib_dir.exists() {
        log!("Directory {:?} already exists", lib_dir);
    } else {
        log!("Creating directory {:?}", lib_dir);
        fs::create_dir(lib_dir.clone()).unwrap();
    }
    let library_path = lib_dir.join(format!("lib{}.so", LIBRARY));
    log_var!(library_path);
    if library_path.exists() {
        log!("{:?} already exists, not building", library_path);
    } else {
        if let Err(e) = check_bazel() {
            println!("cargo:error=Bazel must be installed at be version {} or greater. (Error: {})", MIN_BAZEL, e);
            process::exit(1);
        }
        let target_path = &TARGET.replace(":", "/");
        log_var!(target_path);
        if !Path::new(&source.join(".git")).exists() {
            run("git", |command| command.arg("clone")
                                        .arg(format!("--branch={}", TAG))
                                        .arg("--recursive")
                                        .arg(REPOSITORY)
                                        .arg(&source));
        }
        // Only configure if not previously configured.  Configuring runs a
        // `bazel clean`, which we don't want, because we want to be able to
        // continue from a cancelled build.
        let configure_hint_file_pb = source.join(".rust-configured");
        let configure_hint_file = Path::new(&configure_hint_file_pb);
        if !configure_hint_file.exists() {
            run("bash", |command| command.current_dir(&source).arg("-c").arg("yes ''|./configure"));
            File::create(configure_hint_file).unwrap();
        }
        run("bazel", |command| command.current_dir(&source)
                                      .arg("build")
                                      .arg(format!("--jobs={}", get!("NUM_JOBS")))
                                      .arg("--compilation_mode=opt")
                                      .arg(TARGET));
        let target_bazel_bin = source.join("bazel-bin").join(target_path);
        log!("Copying {:?} to {:?}", target_bazel_bin, library_path);
        fs::copy(target_bazel_bin, library_path).unwrap();
    }

    println!("cargo:rustc-link-lib=dylib={}", LIBRARY);
    println!("cargo:rustc-link-search={}", lib_dir.display());
}

fn run<F>(name: &str, mut configure: F) where F: FnMut(&mut Command) -> &mut Command {
    let mut command = Command::new(name);
    let configured = configure(&mut command);
    log!("Executing {:?}", configured);
    if !ok!(configured.status()).success() {
        panic!("failed to execute {:?}", configured);
    }
    log!("Command {:?} finished successfully", configured);
}

// Building TF 0.11.0rc1 with Bazel 0.3.0 gives this error when running `configure`:
//   expected ConfigurationTransition or NoneType for 'cfg' while calling label_list but got string instead:     data.
//       ERROR: com.google.devtools.build.lib.packages.BuildFileContainsErrorsException: error loading package '': Extension file 'tensorflow/tensorflow.bzl' has errors.
// And the simple solution is to require Bazel 0.3.1 or higher.
fn check_bazel() -> Result<(), Box<Error>> {
    let mut command = Command::new("bazel");
    command.arg("version");
    log!("Executing {:?}", command);
    let out = try!(command.output());
    log!("Command {:?} finished successfully", command);
    let stdout = try!(String::from_utf8(out.stdout));
    let mut found_version = false;
    for line in stdout.lines() {
        if line.starts_with("Build label:") {
            found_version = true;
            let version_str = line.split(":").nth(1).unwrap().trim();
            let version = try!(Version::parse(version_str));
            let want = try!(Version::parse(MIN_BAZEL));
            if version < want {
                return Err(format!("Installed version {} is less than required version {}", version_str, MIN_BAZEL).into());
            }
        }
    }
    if !found_version {
        return Err("Did not find version number in `bazel version` output.".into());
    }
    Ok(())
}
<|endoftext|>


<commit_before>use clap;

use std::fs;
use std::io;
use std::io::Write;
use std::path::PathBuf;
use std::process;
use std::rc::Rc;

pub enum Command {
	Dedupe,
	PrintExtents,
}

pub struct Arguments {
	pub command: Command,
	pub database_path: Option <PathBuf>,
	pub minimum_file_size: u64,
	pub content_hash_batch_size: u64,
	pub extent_hash_batch_size: u64,
	pub dedupe_batch_size: u64,
	pub dedupe_sleep_time: u64,
	pub root_paths: Vec <Rc <PathBuf>>,
}

pub fn parse_arguments (
) -> Arguments {

	let application = (
		clap::App::new ("Btrfs Dedupe")

		.about (
			"Deduplicates identical files on BTRFS file systems.\n\nPlease \
			visit https://btrfs-dedupe.com for more information.")

		.author (
			"James Pharaoh <james@pharaoh.uk>")

		.subcommand (

			clap::SubCommand::with_name ("dedupe")
				.about ("Automatically runs all deduplication steps (default)")

			.arg (
				clap::Arg::with_name ("database")
					.long ("database")
					.value_name ("PATH")
					.help ("Database path to store metadata and hashes")
			)

			.arg (
				clap::Arg::with_name ("minimum-file-size")
					.long ("minimum-file-size")
					.value_name ("SIZE")
					.default_value ("1KiB")
					.help ("Minimum file size to consider for deduplication")
			)

			.arg (
				clap::Arg::with_name ("content-hash-batch-size")
					.long ("content-hash-batch-size")
					.value_name ("SIZE")
					.default_value ("2GiB")
					.help ("Amount of file contents data to hash before \
						writing database")
			)

			.arg (
				clap::Arg::with_name ("extent-hash-batch-size")
					.long ("extent-hash-batch-size")
					.value_name ("SIZE")
					.default_value ("8GiB")
					.help ("Amount of file extent data to hash before writing \
						database")
			)

			.arg (
				clap::Arg::with_name ("dedupe-batch-size")
					.long ("dedupe-batch-size")
					.value_name ("SIZE")
					.default_value ("64MiB")
					.help ("Amount of file data to deduplicate before writing \
						database and sleeping")
			)

			.arg (
				clap::Arg::with_name ("dedupe-sleep-time")
					.long ("dedupe-sleep-time")
					.value_name ("SECONDS")
					.default_value ("5")
					.help ("Amount of time to sleep between deduplication \
						batches")
			)

			.arg (
				clap::Arg::with_name ("root-path")
					.multiple (true)
					.value_name ("PATH")
					.help ("Root path to scan for files")
			)

		)

		.subcommand (

			clap::SubCommand::with_name ("print-extents")
				.about ("Prints file extent information for a given file")

			.arg (
				clap::Arg::with_name ("file-path")
					.multiple (true)
					.value_name ("PATH")
					.help ("Path to file")
			)

		)

	);

	let argument_matches =
		application.clone ().get_matches ();

	if let Some (dedupe_matches) =
		argument_matches.subcommand_matches ("dedupe") {

		let database_path =
			dedupe_matches.value_of_os (
				"database",
			).map (
				|os_value|

				PathBuf::from (
					os_value)

			);

		let content_hash_batch_size = (

			parse_size (
				dedupe_matches.value_of (
					"content-hash-batch-size",
				).unwrap ()
			)

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --content-hash-batch-size: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let extent_hash_batch_size = (

			parse_size (
				dedupe_matches.value_of (
					"extent-hash-batch-size",
				).unwrap ()
			)

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --extent-hash-batch-size: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let dedupe_batch_size = (

			parse_size (
				dedupe_matches.value_of (
					"dedupe-batch-size",
				).unwrap ()
			)

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --dedupe-batch-size: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let dedupe_sleep_time = (

			dedupe_matches.value_of (
				"dedupe-sleep-time",
			).unwrap ().parse::<u64> ()

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --dedupe-sleep-time: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let minimum_file_size = (

			parse_size (
				dedupe_matches.value_of (
					"minimum-file-size",
				).unwrap ()
			)

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --minimum-file-size: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let mut root_paths = (
			dedupe_matches.values_of_os (
				"root-path",
			)
		).map (
			|os_values|

			os_values.map (
				|os_value|

				Rc::new (
					fs::canonicalize (
						PathBuf::from (
							os_value),
					).unwrap ()
				)

			).collect ()

		).unwrap_or (
			Vec::new (),
		);

		root_paths.sort ();

		Arguments {
			command: Command::Dedupe,
			database_path: database_path,
			minimum_file_size: minimum_file_size,
			content_hash_batch_size: content_hash_batch_size,
			extent_hash_batch_size: extent_hash_batch_size,
			dedupe_batch_size: dedupe_batch_size,
			dedupe_sleep_time: dedupe_sleep_time,
			root_paths: root_paths,
		}

	} else if let Some (print_extents_matches) =
		argument_matches.subcommand_matches ("print-extents") {

		let paths = (
			print_extents_matches.values_of_os (
				"file-path",
			)
		).map (
			|os_values|

			os_values.map (
				|os_value|

				Rc::new (
					fs::canonicalize (
						PathBuf::from (
							os_value),
					).unwrap ()
				)

			).collect ()

		).unwrap_or (
			Vec::new (),
		);

		Arguments {
			command: Command::PrintExtents,
			database_path: None,
			minimum_file_size: 0,
			content_hash_batch_size: 0,
			extent_hash_batch_size: 0,
			dedupe_batch_size: 0,
			dedupe_sleep_time: 0,
			root_paths: paths,
		}

	} else {

		let stderr =
			io::stderr ();

		let mut stderr_lock =
			stderr.lock ();

		stderr_lock.write (
			b"\n");

		application.write_help (
			& mut stderr_lock);

		stderr_lock.write (
			b"\n\n");

		process::exit (0);

	}

}

pub fn parse_size (
	size_string: & str,
) -> Result <u64, String> {

	let (multiplier, suffix_length) =

		if size_string.ends_with ("KiB") {
			(1024, 3)
		} else if size_string.ends_with ("MiB") {
			(1024 * 1024, 3)
		} else if size_string.ends_with ("GiB") {
			(1024 * 1024 * 1024, 3)
		} else if size_string.ends_with ("TiB") {
			(1024 * 1024 * 1024 * 1024, 3)

		} else if size_string.ends_with ("KB") {
			(1000, 2)
		} else if size_string.ends_with ("MB") {
			(1000 * 1000, 2)
		} else if size_string.ends_with ("GB") {
			(1000 * 1000 * 1000, 2)
		} else if size_string.ends_with ("TB") {
			(1000 * 1000 * 1000 * 1000, 2)

		} else if size_string.ends_with ("K") {
			(1024, 1)
		} else if size_string.ends_with ("M") {
			(1024 * 1024, 1)
		} else if size_string.ends_with ("G") {
			(1024 * 1024 * 1024, 1)
		} else if size_string.ends_with ("T") {
			(1024 * 1024 * 1024 * 1024, 1)

		} else if size_string.ends_with ("B") {
			(1, 1)

		} else {

			return Err (
				"Units not specified or recognised".to_owned ());

		};

	let quantity_string =
		& size_string [
			0 ..
			size_string.len () - suffix_length];

	let quantity_integer =
		try! (
			quantity_string.parse::<u64> (
			).map_err (
				|_|
				"Unable to parse integer value".to_owned ()
			));

	Ok (
		multiplier * quantity_integer
	)

}

// ex: noet ts=4 filetype=rust
<commit_msg>reduce throughput limits on dedupe<commit_after>use clap;

use std::fs;
use std::io;
use std::io::Write;
use std::path::PathBuf;
use std::process;
use std::rc::Rc;

pub enum Command {
	Dedupe,
	PrintExtents,
}

pub struct Arguments {
	pub command: Command,
	pub database_path: Option <PathBuf>,
	pub minimum_file_size: u64,
	pub content_hash_batch_size: u64,
	pub extent_hash_batch_size: u64,
	pub dedupe_batch_size: u64,
	pub dedupe_sleep_time: u64,
	pub root_paths: Vec <Rc <PathBuf>>,
}

pub fn parse_arguments (
) -> Arguments {

	let application = (
		clap::App::new ("Btrfs Dedupe")

		.about (
			"Deduplicates identical files on BTRFS file systems.\n\nPlease \
			visit https://btrfs-dedupe.com for more information.")

		.author (
			"James Pharaoh <james@pharaoh.uk>")

		.subcommand (

			clap::SubCommand::with_name ("dedupe")
				.about ("Automatically runs all deduplication steps (default)")

			.arg (
				clap::Arg::with_name ("database")
					.long ("database")
					.value_name ("PATH")
					.help ("Database path to store metadata and hashes")
			)

			.arg (
				clap::Arg::with_name ("minimum-file-size")
					.long ("minimum-file-size")
					.value_name ("SIZE")
					.default_value ("1KiB")
					.help ("Minimum file size to consider for deduplication")
			)

			.arg (
				clap::Arg::with_name ("content-hash-batch-size")
					.long ("content-hash-batch-size")
					.value_name ("SIZE")
					.default_value ("2GiB")
					.help ("Amount of file contents data to hash before \
						writing database")
			)

			.arg (
				clap::Arg::with_name ("extent-hash-batch-size")
					.long ("extent-hash-batch-size")
					.value_name ("SIZE")
					.default_value ("8GiB")
					.help ("Amount of file extent data to hash before writing \
						database")
			)

			.arg (
				clap::Arg::with_name ("dedupe-batch-size")
					.long ("dedupe-batch-size")
					.value_name ("SIZE")
					.default_value ("512MiB")
					.help ("Amount of file data to deduplicate before writing \
						database and sleeping")
			)

			.arg (
				clap::Arg::with_name ("dedupe-sleep-time")
					.long ("dedupe-sleep-time")
					.value_name ("SECONDS")
					.default_value ("1")
					.help ("Amount of time to sleep between deduplication \
						batches")
			)

			.arg (
				clap::Arg::with_name ("root-path")
					.multiple (true)
					.value_name ("PATH")
					.help ("Root path to scan for files")
			)

		)

		.subcommand (

			clap::SubCommand::with_name ("print-extents")
				.about ("Prints file extent information for a given file")

			.arg (
				clap::Arg::with_name ("file-path")
					.multiple (true)
					.value_name ("PATH")
					.help ("Path to file")
			)

		)

	);

	let argument_matches =
		application.clone ().get_matches ();

	if let Some (dedupe_matches) =
		argument_matches.subcommand_matches ("dedupe") {

		let database_path =
			dedupe_matches.value_of_os (
				"database",
			).map (
				|os_value|

				PathBuf::from (
					os_value)

			);

		let content_hash_batch_size = (

			parse_size (
				dedupe_matches.value_of (
					"content-hash-batch-size",
				).unwrap ()
			)

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --content-hash-batch-size: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let extent_hash_batch_size = (

			parse_size (
				dedupe_matches.value_of (
					"extent-hash-batch-size",
				).unwrap ()
			)

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --extent-hash-batch-size: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let dedupe_batch_size = (

			parse_size (
				dedupe_matches.value_of (
					"dedupe-batch-size",
				).unwrap ()
			)

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --dedupe-batch-size: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let dedupe_sleep_time = (

			dedupe_matches.value_of (
				"dedupe-sleep-time",
			).unwrap ().parse::<u64> ()

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --dedupe-sleep-time: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let minimum_file_size = (

			parse_size (
				dedupe_matches.value_of (
					"minimum-file-size",
				).unwrap ()
			)

		).map_err (
			|error|

			clap::Error {

				message:
					format! (
						"Can't parse --minimum-file-size: {}",
						error),

				kind:
					clap::ErrorKind::InvalidValue,

				info:
					None,

			}.exit ()

		).unwrap ();

		let mut root_paths = (
			dedupe_matches.values_of_os (
				"root-path",
			)
		).map (
			|os_values|

			os_values.map (
				|os_value|

				Rc::new (
					fs::canonicalize (
						PathBuf::from (
							os_value),
					).unwrap ()
				)

			).collect ()

		).unwrap_or (
			Vec::new (),
		);

		root_paths.sort ();

		Arguments {
			command: Command::Dedupe,
			database_path: database_path,
			minimum_file_size: minimum_file_size,
			content_hash_batch_size: content_hash_batch_size,
			extent_hash_batch_size: extent_hash_batch_size,
			dedupe_batch_size: dedupe_batch_size,
			dedupe_sleep_time: dedupe_sleep_time,
			root_paths: root_paths,
		}

	} else if let Some (print_extents_matches) =
		argument_matches.subcommand_matches ("print-extents") {

		let paths = (
			print_extents_matches.values_of_os (
				"file-path",
			)
		).map (
			|os_values|

			os_values.map (
				|os_value|

				Rc::new (
					fs::canonicalize (
						PathBuf::from (
							os_value),
					).unwrap ()
				)

			).collect ()

		).unwrap_or (
			Vec::new (),
		);

		Arguments {
			command: Command::PrintExtents,
			database_path: None,
			minimum_file_size: 0,
			content_hash_batch_size: 0,
			extent_hash_batch_size: 0,
			dedupe_batch_size: 0,
			dedupe_sleep_time: 0,
			root_paths: paths,
		}

	} else {

		let stderr =
			io::stderr ();

		let mut stderr_lock =
			stderr.lock ();

		stderr_lock.write (
			b"\n");

		application.write_help (
			& mut stderr_lock);

		stderr_lock.write (
			b"\n\n");

		process::exit (0);

	}

}

pub fn parse_size (
	size_string: & str,
) -> Result <u64, String> {

	let (multiplier, suffix_length) =

		if size_string.ends_with ("KiB") {
			(1024, 3)
		} else if size_string.ends_with ("MiB") {
			(1024 * 1024, 3)
		} else if size_string.ends_with ("GiB") {
			(1024 * 1024 * 1024, 3)
		} else if size_string.ends_with ("TiB") {
			(1024 * 1024 * 1024 * 1024, 3)

		} else if size_string.ends_with ("KB") {
			(1000, 2)
		} else if size_string.ends_with ("MB") {
			(1000 * 1000, 2)
		} else if size_string.ends_with ("GB") {
			(1000 * 1000 * 1000, 2)
		} else if size_string.ends_with ("TB") {
			(1000 * 1000 * 1000 * 1000, 2)

		} else if size_string.ends_with ("K") {
			(1024, 1)
		} else if size_string.ends_with ("M") {
			(1024 * 1024, 1)
		} else if size_string.ends_with ("G") {
			(1024 * 1024 * 1024, 1)
		} else if size_string.ends_with ("T") {
			(1024 * 1024 * 1024 * 1024, 1)

		} else if size_string.ends_with ("B") {
			(1, 1)

		} else {

			return Err (
				"Units not specified or recognised".to_owned ());

		};

	let quantity_string =
		& size_string [
			0 ..
			size_string.len () - suffix_length];

	let quantity_integer =
		try! (
			quantity_string.parse::<u64> (
			).map_err (
				|_|
				"Unable to parse integer value".to_owned ()
			));

	Ok (
		multiplier * quantity_integer
	)

}

// ex: noet ts=4 filetype=rust
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Parsing and loading Executable and Linkable Format (ELF) 32- and 64-bit
//! binaries.
//!
//! For more information on the ELF format, refer to:
//!
//!  + [Wikipedia](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
//!  + The [OS Dev Wiki](http://wiki.osdev.org/ELF)
//!  + The [ELF Format Specification](elfspec)
//!
//! [elfspec]: http://www.skyfree.org/linux/references/ELF_Format.pdf
#![feature(core_intrinsics)]
#![feature(try_from)]
#![no_std]

#[macro_use] extern crate bitflags;
#[macro_use] extern crate macro_attr;

extern crate memory;

use core::{ ops, mem, slice };

macro_rules! impl_getters {
    ($(#[$attr:meta])* pub fn $name:ident(&self) -> $ty:ty; $($rest:tt)*) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ($(#[$attr:meta])* fn $name:ident(&self) -> $ty:ty; $($rest:tt)*) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ( $(#[$attr:meta])* pub fn $name: ident (&self)-> $ty:ty; ) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
    };
    ( $(#[$attr:meta])* fn $name: ident (&self)-> $ty:ty; ) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
    };
    () => {};
}

pub mod section;
pub mod file;
pub mod program;

/// An ELF section header.
pub type Section<'a> = section::Header<'a>;
/// An ELF header file.
pub type FileHeader<W> = file::HeaderRepr<W>;

/// TODO: should ELF have its own error type?
pub type ElfResult<T> = Result<T, &'static str>;

pub trait ElfWord: Sized + Copy + Clone
                         + ops::Add<Self> + ops::Sub<Self>
                         + ops::Mul<Self> + ops::Div<Self>
                         + ops::Shl<Self> + ops::Shr<Self> { }
impl ElfWord for u64 { }
impl ElfWord for u32 { }

/// Hack to make the type-system let me do what I want
trait ValidatesWord<Word: ElfWord> {
    fn check(&self) -> ElfResult<()>;
}

/// A handle on a parsed ELF binary
///  TODO: do we want this to own a HashMap of section names to section headers,
///        to speed up section lookup?
//          - eliza, 03/08/2017
#[derive(Debug)]
pub struct Image<'a, Word, Header = file::HeaderRepr<Word>>
where Word: ElfWord + 'a
    , Header: file::Header<Word = Word> + 'a
    {
    /// the binary's [file header](file/trait.Header.html)
    pub header: &'a Header
  , /// references to each [section header](section/struct.Header.html)
    pub sections: &'a [section::Header<'a>]
  , /// the raw binary contents of the ELF binary.
    /// note that this includes the _entire_ binary contents of the file,
    /// so the file header and each section header is included in this slice.
    binary: &'a [u8]
}

impl<'a, Word, Header> Image<'a, Word, Header>
where Word: ElfWord + 'a
    , Header: file::Header<Word = Word> + 'a
    {
    /// Returns the section header [string table].
    ///
    /// [string table]: section/struct.StrTable.html
    pub fn sh_str_table(&'a self) -> section::StrTable<'a> {
        // TODO: do we want to validate that the string table index is
        //       reasonable (e.g. it's not longer than the binary)?
        //          - eliza, 03/08/2017
        // TODO: do we want to cache a ref to the string table?
        //          - eliza, 03/08/2017
        section::StrTable::from(&self.binary[self.header.sh_str_idx()..])
    }

}

/// Extract `n` instances of type `T` from a byte slice.
///
/// This is essentially just a _slightly_ safer wrapper around
/// [`slice::from_raw_parts`]. Unlike `from_raw_parts`, this function takes
/// a valid byte slice, rather than a pointer. Therefore, some of the safety
/// issues with `from_raw_parts` are avoided:
///
/// + the lifetime (`'slice`) of the returned slice should be the same as the
///   lifetime of the input slice (`data`), rather than inferred arbitrarily.
/// + this function will panic rather than reading past the end of the slice.
///
/// # Arguments
///
/// + `data`: the byte slice to extract a slice of `&[T]`s from
/// + `offset`: a start offset into `data`
/// + `n`: the number of instances of `T` which should be contained
///        in `data[offset..]`
///
/// # Safety
///
/// While this function is safer than [`slice::from_raw_parts`],
/// it is still unsafe for the following reasons:
///
/// + The contents of `data` may not be able to be interpreted as instances of
///   type `T`.
///
/// # Caveats
///
/// + If `n` == 0, this will give you an `&[]`. Just a warning.
//    thanks to Max for making  me figure this out.
/// + `offset` must be aligned on a `T`-sized boundary.
///
/// # Panics
///
/// + If the slice `data` is not long enough to contain `n` instances of `T`.
/// + If the index `offset` is longer than `T`
/// + If `offset` is not aligned on a `T`-sized boundary.
///
/// TODO: rewrite this as a `TryFrom` implementation (see issue #85)
//          - eliza, 03/09/2017
///       wait, possibly we should NOT do that. actually we should
///       almost certainly not do that. since this function is unsafe,
///       but `TryFrom` is not, and because this would be WAY generic.
//          - eliza, 03/09/2017
/// TODO: is this general enough to move into util?
//          - eliza, 03/09/2017
/// TODO: should this be refactored to return a `Result`?
//          - eliza, 03/13/2017
/// TODO: assert that `offset` is aligned on a `T`-sized boundary
//          - eliza, 03/13/2017
/// TODO: refactor this to take a `RangeArgument`?
//          - eliza, 03/13/2017
///
/// [`slice::from_raw_parts`]: https://doc.rust-lang.org/stable/std/slice/fn.from_raw_parts.html
unsafe fn extract_from_slice<'slice, T: Sized>( data: &'slice [u8]
                                              , offset: usize
                                              , n: usize)
                                              -> &'slice [T] {
    use core::intrinsics::type_name;
    assert!( offset % mem::align_of::<T>() == 0
           , "Offset {} not aligned on a {}-sized boundary (must be \
              divisible by {})."
           , offset, type_name::<T>(), mem::align_of::<T>()
           );
    assert!( data.len() - offset >= mem::size_of::<T>() * n
           , "Slice too short to contain {} objects of type {}"
           , n, type_name::<T>()
           );
    slice::from_raw_parts(data[offset..].as_ptr() as *const T, n)
}
<commit_msg>feat(elf): add program headers slice ref to elf image<commit_after>//
//  SOS: the Stupid Operating System
//  by Eliza Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015-2017 Eliza Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
//! Parsing and loading Executable and Linkable Format (ELF) 32- and 64-bit
//! binaries.
//!
//! For more information on the ELF format, refer to:
//!
//!  + [Wikipedia](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format)
//!  + The [OS Dev Wiki](http://wiki.osdev.org/ELF)
//!  + The [ELF Format Specification](elfspec)
//!
//! [elfspec]: http://www.skyfree.org/linux/references/ELF_Format.pdf
#![feature(core_intrinsics)]
#![feature(try_from)]
#![no_std]

#[macro_use] extern crate bitflags;
#[macro_use] extern crate macro_attr;

extern crate memory;

use core::{ ops, mem, slice };

macro_rules! impl_getters {
    ($(#[$attr:meta])* pub fn $name:ident(&self) -> $ty:ty; $($rest:tt)*) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ($(#[$attr:meta])* fn $name:ident(&self) -> $ty:ty; $($rest:tt)*) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
        impl_getters!{ $( $rest )* }
    };
    ( $(#[$attr:meta])* pub fn $name: ident (&self)-> $ty:ty; ) => {
        $(#[$attr])* #[inline] pub fn $name(&self) -> $ty { self.$name as $ty }
    };
    ( $(#[$attr:meta])* fn $name: ident (&self)-> $ty:ty; ) => {
        $(#[$attr])* #[inline] fn $name(&self) -> $ty { self.$name as $ty }
    };
    () => {};
}

pub mod section;
pub mod file;
pub mod program;

/// An ELF section header.
pub type Section<'a> = section::Header<'a>;
/// An ELF header file.
pub type FileHeader<W> = file::HeaderRepr<W>;

/// TODO: should ELF have its own error type?
pub type ElfResult<T> = Result<T, &'static str>;

pub trait ElfWord: Sized + Copy + Clone
                         + ops::Add<Self> + ops::Sub<Self>
                         + ops::Mul<Self> + ops::Div<Self>
                         + ops::Shl<Self> + ops::Shr<Self> { }
impl ElfWord for u64 { }
impl ElfWord for u32 { }

/// Hack to make the type-system let me do what I want
trait ValidatesWord<Word: ElfWord> {
    fn check(&self) -> ElfResult<()>;
}

/// A handle on a parsed ELF binary
///  TODO: do we want this to own a HashMap of section names to section headers,
///        to speed up section lookup?
//          - eliza, 03/08/2017
#[derive(Debug)]
pub struct Image<'a, Word, ProgHeader, Header = file::HeaderRepr<Word>>
where Word: ElfWord + 'a
    , Header: file::Header<Word = Word> + 'a
    , ProgHeader: program::Header<Word = Word> + 'a
    {
    /// the binary's [file header](file/trait.Header.html)
    pub header: &'a Header
  , /// references to each [section header](section/struct.Header.html)
    pub sections: &'a [section::Header<'a>]
  , /// references to each [program header](program/trait.Header.html)
    pub program_headers: &'a [ProgHeader]
  , /// the raw binary contents of the ELF binary.
    /// note that this includes the _entire_ binary contents of the file,
    /// so the file header and each section header is included in this slice.
    binary: &'a [u8]
}

impl<'a, Word, ProgHeader, Header> Image<'a, Word, ProgHeader, Header>
where Word: ElfWord + 'a
    , Header: file::Header<Word = Word> + 'a
    , ProgHeader: program::Header<Word = Word> + 'a
    {
    /// Returns the section header [string table].
    ///
    /// [string table]: section/struct.StrTable.html
    pub fn sh_str_table(&'a self) -> section::StrTable<'a> {
        // TODO: do we want to validate that the string table index is
        //       reasonable (e.g. it's not longer than the binary)?
        //          - eliza, 03/08/2017
        // TODO: do we want to cache a ref to the string table?
        //          - eliza, 03/08/2017
        section::StrTable::from(&self.binary[self.header.sh_str_idx()..])
    }

}

/// Extract `n` instances of type `T` from a byte slice.
///
/// This is essentially just a _slightly_ safer wrapper around
/// [`slice::from_raw_parts`]. Unlike `from_raw_parts`, this function takes
/// a valid byte slice, rather than a pointer. Therefore, some of the safety
/// issues with `from_raw_parts` are avoided:
///
/// + the lifetime (`'slice`) of the returned slice should be the same as the
///   lifetime of the input slice (`data`), rather than inferred arbitrarily.
/// + this function will panic rather than reading past the end of the slice.
///
/// # Arguments
///
/// + `data`: the byte slice to extract a slice of `&[T]`s from
/// + `offset`: a start offset into `data`
/// + `n`: the number of instances of `T` which should be contained
///        in `data[offset..]`
///
/// # Safety
///
/// While this function is safer than [`slice::from_raw_parts`],
/// it is still unsafe for the following reasons:
///
/// + The contents of `data` may not be able to be interpreted as instances of
///   type `T`.
///
/// # Caveats
///
/// + If `n` == 0, this will give you an `&[]`. Just a warning.
//    thanks to Max for making  me figure this out.
/// + `offset` must be aligned on a `T`-sized boundary.
///
/// # Panics
///
/// + If the slice `data` is not long enough to contain `n` instances of `T`.
/// + If the index `offset` is longer than `T`
/// + If `offset` is not aligned on a `T`-sized boundary.
///
/// TODO: rewrite this as a `TryFrom` implementation (see issue #85)
//          - eliza, 03/09/2017
///       wait, possibly we should NOT do that. actually we should
///       almost certainly not do that. since this function is unsafe,
///       but `TryFrom` is not, and because this would be WAY generic.
//          - eliza, 03/09/2017
/// TODO: is this general enough to move into util?
//          - eliza, 03/09/2017
/// TODO: should this be refactored to return a `Result`?
//          - eliza, 03/13/2017
/// TODO: assert that `offset` is aligned on a `T`-sized boundary
//          - eliza, 03/13/2017
/// TODO: refactor this to take a `RangeArgument`?
//          - eliza, 03/13/2017
///
/// [`slice::from_raw_parts`]: https://doc.rust-lang.org/stable/std/slice/fn.from_raw_parts.html
unsafe fn extract_from_slice<'slice, T: Sized>( data: &'slice [u8]
                                              , offset: usize
                                              , n: usize)
                                              -> &'slice [T] {
    use core::intrinsics::type_name;
    assert!( offset % mem::align_of::<T>() == 0
           , "Offset {} not aligned on a {}-sized boundary (must be \
              divisible by {})."
           , offset, type_name::<T>(), mem::align_of::<T>()
           );
    assert!( data.len() - offset >= mem::size_of::<T>() * n
           , "Slice too short to contain {} objects of type {}"
           , n, type_name::<T>()
           );
    slice::from_raw_parts(data[offset..].as_ptr() as *const T, n)
}
<|endoftext|>