<commit_before>// http://rosettacode.org/wiki/2048
// Uses rustbox (termbox) to draw the board.
#[cfg(unix)]
mod mod2048 {
    extern crate rustbox;
    extern crate rand;
    use std::default::Default;
    use self::rand::distributions::{IndependentSample, Range};
    use self::rustbox::{Color, RustBox};
    use self::rustbox::Key as RKey;
    #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
    pub enum Key {
        Right,
        Left,
        Up,
        Down,
        Char(char),
    }
    trait UI {
        fn wait_key(&self) -> Option<Key>;
        fn draw_grid(&self, grid: [[usize; 4]; 4]);
        fn present(&self);
        fn draw_lost(&self);
        fn draw_won(&self);
        fn draw_score(&self, text: String);
        fn draw_instructions(&self, text: String);
    }
    struct TermboxUI<'a> {
        rustbox: &'a RustBox,
    }
    impl<'a> UI for TermboxUI<'a> {
        fn wait_key(&self) -> Option<Key> {
            match self.rustbox.poll_event(false) {
                Ok(rustbox::Event::KeyEvent(key)) => {
                    match key {
                        RKey::Char('q') => Some(Key::Char('q')),
                        RKey::Up => Some(Key::Up),
                        RKey::Down => Some(Key::Down),
                        RKey::Left => Some(Key::Left),
                        RKey::Right => Some(Key::Right),
                        _ => None,
                    }
                }
                Err(e) => panic!("{}", e),
                _ => None,
            }
        }
        #[cfg_attr(feature = "clippy", allow(needless_range_loop))]
        fn draw_grid(&self, grid: [[usize; 4]; 4]) {
            let x = 0;
            let y = 2;
            let width = 36;
            let height = 18;
            let cell_width: usize = width / grid.len();
            let cell_height: usize = height / grid[0].len();
            for i in 0..grid.len() {
                let x_coord = x + i * cell_width + i;
                for j in 0..grid[0].len() {
                    let y_coord = y + j * cell_height + j;
                    let x_text_offset = cell_width / 2;
                    let y_text_offset = cell_height / 2;
                    let num: String = format!("{}", grid[i][j]);
                    let x_text_offset = x_text_offset - num.len() / 4;
                    self.draw_rectangle(x_coord,
                                        y_coord,
                                        cell_width,
                                        cell_height,
                                        Color::Black,
                                        Color::White,
                                        Color::Black);
                    if num != "0" {
                        self.rustbox.print(x_coord + x_text_offset,
                                           y_coord + y_text_offset,
                                           rustbox::RB_BOLD,
                                           Color::White,
                                           Color::Black,
                                           &num);
                    }
                }
            }
        }
        fn present(&self) {
            self.rustbox.present();
        }
        fn draw_lost(&self) {
            self.draw_text(16, 12, "You lost!".to_string(), Color::Red, Color::Default);
        }
        fn draw_won(&self) {
            self.draw_text(16, 12, "You won!".to_string(), Color::Green, Color::Default);
        }
        fn draw_score(&self, text: String) {
            self.draw_text(16, 1, text, Color::White, Color::Default);
        }
        fn draw_instructions(&self, text: String) {
            self.draw_text(14, 22, text, Color::White, Color::Default);
        }
    }
    impl<'a> TermboxUI<'a> {
        fn new(rustbox: &'a rustbox::RustBox) -> TermboxUI<'a> {
            TermboxUI { rustbox: rustbox }
        }
        fn fill_area(&self, x: usize, y: usize, w: usize, h: usize, fg: Color, bg: Color) {
            for row in 0..h {
                for column in 0..w {
                    self.rustbox.print_char(x + column, y + row, rustbox::RB_NORMAL, fg, bg, ' ');
                }
            }
        }
        fn draw_horizontal_line(&self, x: usize, y: usize, w: usize, fg: Color, bg: Color) {
            for i in 0..w + 1 {
                self.rustbox.print_char(x + i, y, rustbox::RB_NORMAL, fg, bg, '─');
            }
        }
        fn draw_vertical_line(&self, x: usize, y: usize, h: usize, fg: Color, bg: Color) {
            for i in 0..h + 1 {
                self.rustbox.print_char(x, y + i, rustbox::RB_NORMAL, fg, bg, '│');
            }
        }
        fn draw_rectangle(&self,
                          x: usize,
                          y: usize,
                          w: usize,
                          h: usize,
                          fill: Color,
                          fg: Color,
                          bg: Color) {
            self.fill_area(x, y, w, h, fill, fill);
            self.draw_horizontal_line(x, y, w, fg, bg); // top
            self.draw_horizontal_line(x, h + y, w, fg, bg); // bottom
            self.draw_vertical_line(x, y, h, fg, bg); // left
            self.draw_vertical_line(x + w, y, h, fg, bg); // right
            self.rustbox.print_char(x, y, rustbox::RB_NORMAL, fg, bg, '┌');
            self.rustbox.print_char(x + w, y, rustbox::RB_NORMAL, fg, bg, '┐');
            self.rustbox.print_char(x, y + h, rustbox::RB_NORMAL, fg, bg, '└');
            self.rustbox.print_char(x + w, y + h, rustbox::RB_NORMAL, fg, bg, '┘');
        }
        fn draw_text(&self,
                     x: usize,
                     y: usize,
                     line: String,
                     fg: Color,
                     bg: Color)
                     -> (usize, usize) {
            for (i, ch) in line.chars().enumerate() {
                self.rustbox.print_char(x + i, y, rustbox::RB_NORMAL, fg, bg, ch);
            }
            (x + line.len(), y)
        }
    }
    fn spawn_new(x: &mut usize) -> bool {
        if *x != 0 {
            return false;
        }
        let between = Range::new(0f64, 1.);
        let mut rng = rand::thread_rng();
        let a = between.ind_sample(&mut rng);
        *x = if a > 0.9 {
            4
        } else {
            2
        };
        true
    }
    #[derive(PartialEq, Debug)]
    enum State {
        Playing,
        Won,
        Lost,
    }
    struct Game<'a> {
        ui: &'a UI,
        grid: [[usize; 4]; 4],
        state: State,
        total_score: usize,
        moved: bool,
    }
    impl<'a> Game<'a> {
        fn new(ui: &'a UI) -> Game<'a> {
            let mut g = Game {
                ui: ui,
                grid: [[0; 4]; 4],
                state: State::Playing,
                total_score: 0,
                moved: false,
            };
            for _ in 0..2 {
                g.add_tile();
            }
            g
        }
        fn run(&mut self) {
            loop {
                self.draw();
                self.moved = false;
                let key = self.ui.wait_key();
                if key == Some(Key::Char('q')) {
                    break;
                }
                if self.state != State::Lost && self.state != State::Won {
                    match key {
                        Some(Key::Up) => self.move_up(),
                        Some(Key::Down) => self.move_down(),
                        Some(Key::Left) => self.move_left(),
                        Some(Key::Right) => self.move_right(),
                        _ => {}
                    }
                }
                if self.moved {
                    self.add_tile();
                } else if !self.can_move() {
                    self.state = State::Lost;
                }
            }
        }
        fn add_tile(&mut self) {
            if self.can_move() {
                let mut cell1 = rand::random::<(usize, usize)>();
                while !spawn_new(&mut self.grid[cell1.0 % 4][cell1.1 % 4]) {
                    cell1 = rand::random::<(usize, usize)>();
                }
            }
        }
        fn can_move(&self) -> bool {
            for x in 0..4 {
                for y in 0..4 {
                    if self.grid[x][y] == 0 {
                        return true;
                    }
                    if x < 3 && self.grid[x + 1][y] == self.grid[x][y] {
                        return true;
                    };
                    if x > 0 && self.grid[x - 1][y] == self.grid[x][y] {
                        return true;
                    };
                    if y < 3 && self.grid[x][y + 1] == self.grid[x][y] {
                        return true;
                    };
                    if y > 0 && self.grid[x][y - 1] == self.grid[x][y] {
                        return true;
                    };
                }
            }
            false
        }
        fn add_score(&mut self, score: usize) {
            self.total_score += score;
            if score == 2048 {
                self.state = State::Won;
            }
        }
        fn draw(&self) {
            self.ui.draw_score(format!("Score: {}", self.total_score));
            self.ui.draw_grid(self.grid);
            self.ui.draw_instructions("←,↑,→,↓ or q".to_string());
            if self.state == State::Lost {
                self.ui.draw_lost();
            } else if self.state == State::Won {
                self.ui.draw_won();
            }
            self.ui.present();
        }
        fn combine_tile(&mut self, col: usize, row: usize, testcol: usize, testrow: usize) -> bool {
            if self.grid[testcol][testrow] == 0 {
                false
            } else if self.grid[col][row] == 0 {
                self.grid[col][row] += self.grid[testcol][testrow];
                self.grid[testcol][testrow] = 0;
                self.moved = true;
                false
            } else if self.grid[col][row] == self.grid[testcol][testrow] {
                self.grid[col][row] += self.grid[testcol][testrow];
                self.grid[testcol][testrow] = 0;
                let score = self.grid[col][row];
                self.add_score(score);
                self.moved = true;
                true
            } else {
                true
            }
        }
        fn move_up(&mut self) {
            for col in 0..4 {
                for row in 0..4 {
                    for testrow in (row + 1)..4 {
                        if self.combine_tile(col, row, col, testrow) {
                            break;
                        }
                    }
                }
            }
        }
        fn move_down(&mut self) {
            for col in 0..4 {
                for row in (0..4).rev() {
                    for testrow in (0..row).rev() {
                        if self.combine_tile(col, row, col, testrow) {
                            break;
                        }
                    }
                }
            }
        }
        fn move_left(&mut self) {
            for row in 0..4 {
                for col in 0..4 {
                    for testcol in (col + 1)..4 {
                        if self.combine_tile(col, row, testcol, row) {
                            break;
                        }
                    }
                }
            }
        }
        fn move_right(&mut self) {
            for row in 0..4 {
                for col in (0..4).rev() {
                    for testcol in (0..col).rev() {
                        if self.combine_tile(col, row, testcol, row) {
                            break;
                        }
                    }
                }
            }
        }
    }
    pub fn main() {
        let rustbox = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };
        let ui = TermboxUI::new(&rustbox);
        let mut game = Game::new(&ui);
        game.run();
    }
}
#[cfg(unix)]
fn main() {
    mod2048::main();
}
// main to make the compiler happy when 2048 feature is disabled.
#[cfg(not(unix))]
fn main() {
    println!("This solution is not supported on Windows.");
}
<commit_msg>refactor functions with too many parameters<commit_after>// http://rosettacode.org/wiki/2048
// Uses rustbox (termbox) to draw the board.
#[cfg(unix)]
mod mod2048 {
    extern crate rustbox;
    extern crate rand;

    use std::default::Default;
    use self::rand::distributions::{IndependentSample, Range};
    use self::rustbox::{Color, RustBox};
    use self::rustbox::Key as RKey;

    struct Rectangle {
        x: usize,
        y: usize,
        w: usize,
        h: usize,
    }

    #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
    pub enum Key {
        Right,
        Left,
        Up,
        Down,
        Char(char),
    }

    trait UI {
        fn wait_key(&self) -> Option<Key>;
        fn draw_grid(&self, grid: [[usize; 4]; 4]);
        fn present(&self);
        fn draw_lost(&self);
        fn draw_won(&self);
        fn draw_score(&self, text: String);
        fn draw_instructions(&self, text: String);
    }

    struct TermboxUI<'a> {
        rustbox: &'a RustBox,
    }

    impl<'a> UI for TermboxUI<'a> {
        fn wait_key(&self) -> Option<Key> {
            match self.rustbox.poll_event(false) {
                Ok(rustbox::Event::KeyEvent(key)) => {
                    match key {
                        RKey::Char('q') => Some(Key::Char('q')),
                        RKey::Up => Some(Key::Up),
                        RKey::Down => Some(Key::Down),
                        RKey::Left => Some(Key::Left),
                        RKey::Right => Some(Key::Right),
                        _ => None,
                    }
                }
                Err(e) => panic!("{}", e),
                _ => None,
            }
        }

        #[cfg_attr(feature = "clippy", allow(needless_range_loop))]
        fn draw_grid(&self, grid: [[usize; 4]; 4]) {
            let x = 0;
            let y = 2;
            let width = 36;
            let height = 18;
            let cell_width: usize = width / grid.len();
            let cell_height: usize = height / grid[0].len();
            for i in 0..grid.len() {
                let x_coord = x + i * cell_width + i;
                for j in 0..grid[0].len() {
                    let y_coord = y + j * cell_height + j;
                    let x_text_offset = cell_width / 2;
                    let y_text_offset = cell_height / 2;
                    let num: String = format!("{}", grid[i][j]);
                    let x_text_offset = x_text_offset - num.len() / 4;

                    let rect = Rectangle {
                        x: x_coord,
                        y: y_coord,
                        w: cell_width,
                        h: cell_height,
                    };
                    self.draw_rectangle(rect, Color::Black, Color::White, Color::Black);
                    if num != "0" {
                        self.rustbox.print(x_coord + x_text_offset,
                                           y_coord + y_text_offset,
                                           rustbox::RB_BOLD,
                                           Color::White,
                                           Color::Black,
                                           &num);
                    }
                }
            }
        }

        fn present(&self) {
            self.rustbox.present();
        }

        fn draw_lost(&self) {
            self.draw_text(16, 12, "You lost!".to_string(), Color::Red, Color::Default);
        }

        fn draw_won(&self) {
            self.draw_text(16, 12, "You won!".to_string(), Color::Green, Color::Default);
        }

        fn draw_score(&self, text: String) {
            self.draw_text(16, 1, text, Color::White, Color::Default);
        }

        fn draw_instructions(&self, text: String) {
            self.draw_text(14, 22, text, Color::White, Color::Default);
        }
    }

    impl<'a> TermboxUI<'a> {
        fn new(rustbox: &'a rustbox::RustBox) -> TermboxUI<'a> {
            TermboxUI { rustbox: rustbox }
        }

        fn fill_area(&self, x: usize, y: usize, w: usize, h: usize, fg: Color, bg: Color) {
            for row in 0..h {
                for column in 0..w {
                    self.rustbox.print_char(x + column, y + row, rustbox::RB_NORMAL, fg, bg, ' ');
                }
            }
        }

        fn draw_horizontal_line(&self, x: usize, y: usize, w: usize, fg: Color, bg: Color) {
            for i in 0..w + 1 {
                self.rustbox.print_char(x + i, y, rustbox::RB_NORMAL, fg, bg, '─');
            }
        }

        fn draw_vertical_line(&self, x: usize, y: usize, h: usize, fg: Color, bg: Color) {
            for i in 0..h + 1 {
                self.rustbox.print_char(x, y + i, rustbox::RB_NORMAL, fg, bg, '│');
            }
        }

        fn draw_rectangle(&self, rect: Rectangle, fill: Color, fg: Color, bg: Color) {
            let Rectangle { x, y, w, h } = rect;

            self.fill_area(x, y, w, h, fill, fill);
            self.draw_horizontal_line(x, y, w, fg, bg); // top
            self.draw_horizontal_line(x, h + y, w, fg, bg); // bottom
            self.draw_vertical_line(x, y, h, fg, bg); // left
            self.draw_vertical_line(x + w, y, h, fg, bg); // right
            self.rustbox.print_char(x, y, rustbox::RB_NORMAL, fg, bg, '┌');
            self.rustbox.print_char(x + w, y, rustbox::RB_NORMAL, fg, bg, '┐');
            self.rustbox.print_char(x, y + h, rustbox::RB_NORMAL, fg, bg, '└');
            self.rustbox.print_char(x + w, y + h, rustbox::RB_NORMAL, fg, bg, '┘');
        }

        fn draw_text(&self,
                     x: usize,
                     y: usize,
                     line: String,
                     fg: Color,
                     bg: Color)
                     -> (usize, usize) {
            for (i, ch) in line.chars().enumerate() {
                self.rustbox.print_char(x + i, y, rustbox::RB_NORMAL, fg, bg, ch);
            }
            (x + line.len(), y)
        }
    }

    fn spawn_new(x: &mut usize) -> bool {
        if *x != 0 {
            return false;
        }

        let between = Range::new(0f64, 1.);
        let mut rng = rand::thread_rng();
        let a = between.ind_sample(&mut rng);
        *x = if a > 0.9 {
            4
        } else {
            2
        };
        true
    }

    #[derive(PartialEq, Debug)]
    enum State {
        Playing,
        Won,
        Lost,
    }

    struct Game<'a> {
        ui: &'a UI,
        grid: [[usize; 4]; 4],
        state: State,
        total_score: usize,
        moved: bool,
    }

    impl<'a> Game<'a> {
        fn new(ui: &'a UI) -> Game<'a> {
            let mut g = Game {
                ui: ui,
                grid: [[0; 4]; 4],
                state: State::Playing,
                total_score: 0,
                moved: false,
            };
            for _ in 0..2 {
                g.add_tile();
            }
            g
        }
        fn run(&mut self) {
            loop {
                self.draw();
                self.moved = false;
                let key = self.ui.wait_key();
                if key == Some(Key::Char('q')) {
                    break;
                }
                if self.state != State::Lost && self.state != State::Won {
                    match key {
                        Some(Key::Up) => self.move_up(),
                        Some(Key::Down) => self.move_down(),
                        Some(Key::Left) => self.move_left(),
                        Some(Key::Right) => self.move_right(),
                        _ => {}
                    }
                }
                if self.moved {
                    self.add_tile();
                } else if !self.can_move() {
                    self.state = State::Lost;
                }
            }
        }

        fn add_tile(&mut self) {
            if self.can_move() {
                let mut cell1 = rand::random::<(usize, usize)>();
                while !spawn_new(&mut self.grid[cell1.0 % 4][cell1.1 % 4]) {
                    cell1 = rand::random::<(usize, usize)>();
                }
            }
        }

        fn can_move(&self) -> bool {
            for x in 0..4 {
                for y in 0..4 {
                    if self.grid[x][y] == 0 {
                        return true;
                    }
                    if x < 3 && self.grid[x + 1][y] == self.grid[x][y] {
                        return true;
                    };
                    if x > 0 && self.grid[x - 1][y] == self.grid[x][y] {
                        return true;
                    };
                    if y < 3 && self.grid[x][y + 1] == self.grid[x][y] {
                        return true;
                    };
                    if y > 0 && self.grid[x][y - 1] == self.grid[x][y] {
                        return true;
                    };
                }
            }
            false
        }

        fn add_score(&mut self, score: usize) {
            self.total_score += score;
            if score == 2048 {
                self.state = State::Won;
            }
        }

        fn draw(&self) {
            self.ui.draw_score(format!("Score: {}", self.total_score));
            self.ui.draw_grid(self.grid);
            self.ui.draw_instructions("←,↑,→,↓ or q".to_string());
            if self.state == State::Lost {
                self.ui.draw_lost();
            } else if self.state == State::Won {
                self.ui.draw_won();
            }
            self.ui.present();
        }

        fn combine_tile(&mut self, col: usize, row: usize, testcol: usize, testrow: usize) -> bool {
            if self.grid[testcol][testrow] == 0 {
                false
            } else if self.grid[col][row] == 0 {
                self.grid[col][row] += self.grid[testcol][testrow];
                self.grid[testcol][testrow] = 0;
                self.moved = true;
                false
            } else if self.grid[col][row] == self.grid[testcol][testrow] {
                self.grid[col][row] += self.grid[testcol][testrow];
                self.grid[testcol][testrow] = 0;
                let score = self.grid[col][row];
                self.add_score(score);
                self.moved = true;
                true
            } else {
                true
            }
        }

        fn move_up(&mut self) {
            for col in 0..4 {
                for row in 0..4 {
                    for testrow in (row + 1)..4 {
                        if self.combine_tile(col, row, col, testrow) {
                            break;
                        }
                    }
                }
            }
        }

        fn move_down(&mut self) {
            for col in 0..4 {
                for row in (0..4).rev() {
                    for testrow in (0..row).rev() {
                        if self.combine_tile(col, row, col, testrow) {
                            break;
                        }
                    }
                }
            }
        }

        fn move_left(&mut self) {
            for row in 0..4 {
                for col in 0..4 {
                    for testcol in (col + 1)..4 {
                        if self.combine_tile(col, row, testcol, row) {
                            break;
                        }
                    }
                }
            }
        }

        fn move_right(&mut self) {
            for row in 0..4 {
                for col in (0..4).rev() {
                    for testcol in (0..col).rev() {
                        if self.combine_tile(col, row, testcol, row) {
                            break;
                        }
                    }
                }
            }
        }
    }

    pub fn main() {
        let rustbox = match RustBox::init(Default::default()) {
            Result::Ok(v) => v,
            Result::Err(e) => panic!("{}", e),
        };
        let ui = TermboxUI::new(&rustbox);
        let mut game = Game::new(&ui);
        game.run();
    }
}

#[cfg(unix)]
fn main() {
    mod2048::main();
}

#[cfg(not(unix))]
fn main() {
    println!("This solution is not supported on Windows.");
}
<|endoftext|>


<commit_before>
pub struct User {
	id: u64,
	display_name: String
}

impl User {
	pub fn id(&self) -> &u64 {
		&self.id
	}

	pub fn display_name(&self) -> &String {
		&self.display_name
	}
}
<commit_msg>Added UserState and UserType types for handling user state changes in chat<commit_after>
use std::collections::HashMap;

pub struct User {
	id: u64,
	display_name: String
}

impl User {
	pub fn id(&self) -> &u64 {
		&self.id
	}

	pub fn display_name(&self) -> &String {
		&self.display_name
	}
}

pub struct UserState {
	badges: HashMap<String, String>,
	color: String,
	display: String,
	emotes: String,
	channel: String,
	subscriber: bool,
	moderator: bool,
	user_type: UserType
}

impl UserState {
	pub fn from_irc(irc: String) -> UserState {
		// TODO: determine UserState from IRC message
		unimplemented!()
	}
}

pub enum UserType {
	Viewer,
	Moderator,
	GlobalModerator,
	Broadcaster,
	Admin,
	Staff
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 fd developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

extern crate ctrlc;

use exec;
use fshelper;
use internal::{error, FdOptions, EXITCODE_SIGINT, MAX_BUFFER_LENGTH};
use output;

use std::error::Error;
use std::path::PathBuf;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;

use ignore::overrides::OverrideBuilder;
use ignore::{self, WalkBuilder};
use regex::Regex;

/// The receiver thread can either be buffering results or directly streaming to the console.
enum ReceiverMode {
    /// Receiver is still buffering in order to sort the results, if the search finishes fast
    /// enough.
    Buffering,

    /// Receiver is directly printing results to the output.
    Streaming,
}

/// Recursively scan the given search path for files / pathnames matching the pattern.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) {
    let mut path_iter = path_vec.iter();
    let first_path_buf = path_iter
        .next()
        .expect("Error: Path vector can not be empty");
    let (tx, rx) = channel();
    let threads = config.threads;

    let mut override_builder = OverrideBuilder::new(first_path_buf.as_path());

    for pattern in &config.exclude_patterns {
        let res = override_builder.add(pattern);
        if res.is_err() {
            error(&format!("Error: malformed exclude pattern '{}'", pattern));
        }
    }
    let overrides = override_builder.build().unwrap_or_else(|_| {
        error("Mismatch in exclude patterns");
    });

    let mut walker = WalkBuilder::new(first_path_buf.as_path());
    walker
        .hidden(config.ignore_hidden)
        .ignore(false)
        .parents(config.read_fdignore || config.read_vcsignore)
        .git_ignore(config.read_vcsignore)
        .git_global(config.read_vcsignore)
        .git_exclude(config.read_vcsignore)
        .overrides(overrides)
        .follow_links(config.follow_links)
        .max_depth(config.max_depth);

    if config.read_fdignore {
        walker.add_custom_ignore_filename(".fdignore");
    }

    for ignore_file in &config.ignore_files {
        let result = walker.add_ignore(ignore_file);
        if let Some(err) = result {
            match err {
                ignore::Error::Partial(_) => (),
                _ => {
                    error(&format!(
                        "Error while parsing custom ignore file '{}': {}.",
                        ignore_file.to_string_lossy(),
                        err.description()
                    ));
                }
            }
        }
    }

    for path_entry in path_iter {
        walker.add(path_entry.as_path());
    }

    let parallel_walker = walker.threads(threads).build_parallel();

    let wants_to_quit = Arc::new(AtomicBool::new(false));
    let receiver_wtq = Arc::clone(&wants_to_quit);
    let sender_wtq = Arc::clone(&wants_to_quit);
    if config.ls_colors.is_some() && config.command.is_none() {
        let wq = Arc::clone(&receiver_wtq);
        ctrlc::set_handler(move || {
            wq.store(true, Ordering::Relaxed);
        }).unwrap();
    }

    // Spawn the thread that receives all results through the channel.
    let rx_config = Arc::clone(&config);
    let receiver_thread = thread::spawn(move || {
        // This will be set to `Some` if the `--exec` argument was supplied.
        if let Some(ref cmd) = rx_config.command {
            let shared_rx = Arc::new(Mutex::new(rx));

            let out_perm = Arc::new(Mutex::new(()));

            // TODO: the following line is a workaround to replace the `unsafe` block that was
            // previously used here to avoid the (unnecessary?) cloning of the command. The
            // `unsafe` block caused problems on some platforms (SIGILL instructions on Linux) and
            // therefore had to be removed.
            let cmd = Arc::new(cmd.clone());

            // Each spawned job will store it's thread handle in here.
            let mut handles = Vec::with_capacity(threads);
            for _ in 0..threads {
                let rx = Arc::clone(&shared_rx);
                let cmd = Arc::clone(&cmd);
                let out_perm = Arc::clone(&out_perm);

                // Spawn a job thread that will listen for and execute inputs.
                let handle = thread::spawn(move || exec::job(rx, cmd, out_perm));

                // Push the handle of the spawned thread into the vector for later joining.
                handles.push(handle);
            }

            // Wait for all threads to exit before exiting the program.
            for h in handles {
                h.join().unwrap();
            }
        } else {
            let start = time::Instant::now();

            let mut buffer = vec![];

            // Start in buffering mode
            let mut mode = ReceiverMode::Buffering;

            // Maximum time to wait before we start streaming to the console.
            let max_buffer_time = rx_config
                .max_buffer_time
                .unwrap_or_else(|| time::Duration::from_millis(100));

            for value in rx {
                match mode {
                    ReceiverMode::Buffering => {
                        buffer.push(value);

                        // Have we reached the maximum buffer size or maximum buffering time?
                        if buffer.len() > MAX_BUFFER_LENGTH
                            || time::Instant::now() - start > max_buffer_time
                        {
                            // Flush the buffer
                            for v in &buffer {
                                output::print_entry(v, &rx_config, &receiver_wtq);
                            }
                            buffer.clear();

                            // Start streaming
                            mode = ReceiverMode::Streaming;
                        }
                    }
                    ReceiverMode::Streaming => {
                        output::print_entry(&value, &rx_config, &receiver_wtq);
                    }
                }
            }

            // If we have finished fast enough (faster than max_buffer_time), we haven't streamed
            // anything to the console, yet. In this case, sort the results and print them:
            if !buffer.is_empty() {
                buffer.sort();
                for value in buffer {
                    output::print_entry(&value, &rx_config, &receiver_wtq);
                }
            }
        }
    });

    // Spawn the sender threads.
    parallel_walker.run(|| {
        let config = Arc::clone(&config);
        let pattern = Arc::clone(&pattern);
        let tx_thread = tx.clone();
        let wants_to_quit = Arc::clone(&sender_wtq);

        Box::new(move |entry_o| {
            if wants_to_quit.load(Ordering::Relaxed) {
                return ignore::WalkState::Quit;
            }

            let entry = match entry_o {
                Ok(e) => e,
                Err(_) => return ignore::WalkState::Continue,
            };

            if entry.depth() == 0 {
                return ignore::WalkState::Continue;
            }

            // Filter out unwanted file types.

            if let Some(ref file_types) = config.file_types {
                if let Some(ref entry_type) = entry.file_type() {
                    if (entry_type.is_file() && !file_types.files)
                        || (entry_type.is_dir() && !file_types.directories)
                        || (entry_type.is_symlink() && !file_types.symlinks)
                        || (entry.metadata().is_ok()
                            && !fshelper::is_executable(&entry.metadata().unwrap())
                            && file_types.executables_only)
                    {
                        return ignore::WalkState::Continue;
                    } else if !(entry_type.is_file() || entry_type.is_dir()
                        || entry_type.is_symlink())
                    {
                        // This is probably a block device, char device, fifo or socket. Skip it.
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            let entry_path = entry.path();

            // Filter out unwanted extensions.
            if let Some(ref exts_regex) = config.extensions {
                if let Some(path_str) = entry_path.file_name().map_or(None, |s| s.to_str()) {
                    if !exts_regex.is_match(path_str) {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted sizes if it is a file and we have been given size constraints.
            if config.size_constraints.len() > 0 && entry_path.is_file() {
                if let Ok(metadata) = entry_path.metadata() {
                    let file_size = metadata.len();
                    if config
                        .size_constraints
                        .iter()
                        .any(|sc| !sc.is_within(file_size))
                    {
                        return ignore::WalkState::Continue;
                    }
                }
            }

            let search_str_o = if config.search_full_path {
                match fshelper::path_absolute_form(entry_path) {
                    Ok(path_abs_buf) => Some(path_abs_buf.to_string_lossy().into_owned().into()),
                    Err(_) => error("Error: unable to get full path."),
                }
            } else {
                entry_path.file_name().map(|f| f.to_string_lossy())
            };

            if let Some(search_str) = search_str_o {
                if pattern.is_match(&*search_str) {
                    // TODO: take care of the unwrap call
                    tx_thread.send(entry_path.to_owned()).unwrap()
                }
            }

            ignore::WalkState::Continue
        })
    });

    // Drop the initial sender. If we don't do this, the receiver will block even
    // if all threads have finished, since there is still one sender around.
    drop(tx);

    // Wait for the receiver thread to print out all results.
    receiver_thread.join().unwrap();

    if wants_to_quit.load(Ordering::Relaxed) {
        process::exit(EXITCODE_SIGINT);
    }
}
<commit_msg>Do not include non-files when using --size<commit_after>// Copyright (c) 2017 fd developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

extern crate ctrlc;

use exec;
use fshelper;
use internal::{error, FdOptions, EXITCODE_SIGINT, MAX_BUFFER_LENGTH};
use output;

use std::error::Error;
use std::path::PathBuf;
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::mpsc::channel;
use std::sync::{Arc, Mutex};
use std::thread;
use std::time;

use ignore::overrides::OverrideBuilder;
use ignore::{self, WalkBuilder};
use regex::Regex;

/// The receiver thread can either be buffering results or directly streaming to the console.
enum ReceiverMode {
    /// Receiver is still buffering in order to sort the results, if the search finishes fast
    /// enough.
    Buffering,

    /// Receiver is directly printing results to the output.
    Streaming,
}

/// Recursively scan the given search path for files / pathnames matching the pattern.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(path_vec: &[PathBuf], pattern: Arc<Regex>, config: Arc<FdOptions>) {
    let mut path_iter = path_vec.iter();
    let first_path_buf = path_iter
        .next()
        .expect("Error: Path vector can not be empty");
    let (tx, rx) = channel();
    let threads = config.threads;

    let mut override_builder = OverrideBuilder::new(first_path_buf.as_path());

    for pattern in &config.exclude_patterns {
        let res = override_builder.add(pattern);
        if res.is_err() {
            error(&format!("Error: malformed exclude pattern '{}'", pattern));
        }
    }
    let overrides = override_builder.build().unwrap_or_else(|_| {
        error("Mismatch in exclude patterns");
    });

    let mut walker = WalkBuilder::new(first_path_buf.as_path());
    walker
        .hidden(config.ignore_hidden)
        .ignore(false)
        .parents(config.read_fdignore || config.read_vcsignore)
        .git_ignore(config.read_vcsignore)
        .git_global(config.read_vcsignore)
        .git_exclude(config.read_vcsignore)
        .overrides(overrides)
        .follow_links(config.follow_links)
        .max_depth(config.max_depth);

    if config.read_fdignore {
        walker.add_custom_ignore_filename(".fdignore");
    }

    for ignore_file in &config.ignore_files {
        let result = walker.add_ignore(ignore_file);
        if let Some(err) = result {
            match err {
                ignore::Error::Partial(_) => (),
                _ => {
                    error(&format!(
                        "Error while parsing custom ignore file '{}': {}.",
                        ignore_file.to_string_lossy(),
                        err.description()
                    ));
                }
            }
        }
    }

    for path_entry in path_iter {
        walker.add(path_entry.as_path());
    }

    let parallel_walker = walker.threads(threads).build_parallel();

    let wants_to_quit = Arc::new(AtomicBool::new(false));
    let receiver_wtq = Arc::clone(&wants_to_quit);
    let sender_wtq = Arc::clone(&wants_to_quit);
    if config.ls_colors.is_some() && config.command.is_none() {
        let wq = Arc::clone(&receiver_wtq);
        ctrlc::set_handler(move || {
            wq.store(true, Ordering::Relaxed);
        }).unwrap();
    }

    // Spawn the thread that receives all results through the channel.
    let rx_config = Arc::clone(&config);
    let receiver_thread = thread::spawn(move || {
        // This will be set to `Some` if the `--exec` argument was supplied.
        if let Some(ref cmd) = rx_config.command {
            let shared_rx = Arc::new(Mutex::new(rx));

            let out_perm = Arc::new(Mutex::new(()));

            // TODO: the following line is a workaround to replace the `unsafe` block that was
            // previously used here to avoid the (unnecessary?) cloning of the command. The
            // `unsafe` block caused problems on some platforms (SIGILL instructions on Linux) and
            // therefore had to be removed.
            let cmd = Arc::new(cmd.clone());

            // Each spawned job will store it's thread handle in here.
            let mut handles = Vec::with_capacity(threads);
            for _ in 0..threads {
                let rx = Arc::clone(&shared_rx);
                let cmd = Arc::clone(&cmd);
                let out_perm = Arc::clone(&out_perm);

                // Spawn a job thread that will listen for and execute inputs.
                let handle = thread::spawn(move || exec::job(rx, cmd, out_perm));

                // Push the handle of the spawned thread into the vector for later joining.
                handles.push(handle);
            }

            // Wait for all threads to exit before exiting the program.
            for h in handles {
                h.join().unwrap();
            }
        } else {
            let start = time::Instant::now();

            let mut buffer = vec![];

            // Start in buffering mode
            let mut mode = ReceiverMode::Buffering;

            // Maximum time to wait before we start streaming to the console.
            let max_buffer_time = rx_config
                .max_buffer_time
                .unwrap_or_else(|| time::Duration::from_millis(100));

            for value in rx {
                match mode {
                    ReceiverMode::Buffering => {
                        buffer.push(value);

                        // Have we reached the maximum buffer size or maximum buffering time?
                        if buffer.len() > MAX_BUFFER_LENGTH
                            || time::Instant::now() - start > max_buffer_time
                        {
                            // Flush the buffer
                            for v in &buffer {
                                output::print_entry(v, &rx_config, &receiver_wtq);
                            }
                            buffer.clear();

                            // Start streaming
                            mode = ReceiverMode::Streaming;
                        }
                    }
                    ReceiverMode::Streaming => {
                        output::print_entry(&value, &rx_config, &receiver_wtq);
                    }
                }
            }

            // If we have finished fast enough (faster than max_buffer_time), we haven't streamed
            // anything to the console, yet. In this case, sort the results and print them:
            if !buffer.is_empty() {
                buffer.sort();
                for value in buffer {
                    output::print_entry(&value, &rx_config, &receiver_wtq);
                }
            }
        }
    });

    // Spawn the sender threads.
    parallel_walker.run(|| {
        let config = Arc::clone(&config);
        let pattern = Arc::clone(&pattern);
        let tx_thread = tx.clone();
        let wants_to_quit = Arc::clone(&sender_wtq);

        Box::new(move |entry_o| {
            if wants_to_quit.load(Ordering::Relaxed) {
                return ignore::WalkState::Quit;
            }

            let entry = match entry_o {
                Ok(e) => e,
                Err(_) => return ignore::WalkState::Continue,
            };

            if entry.depth() == 0 {
                return ignore::WalkState::Continue;
            }

            // Filter out unwanted file types.

            if let Some(ref file_types) = config.file_types {
                if let Some(ref entry_type) = entry.file_type() {
                    if (entry_type.is_file() && !file_types.files)
                        || (entry_type.is_dir() && !file_types.directories)
                        || (entry_type.is_symlink() && !file_types.symlinks)
                        || (entry.metadata().is_ok()
                            && !fshelper::is_executable(&entry.metadata().unwrap())
                            && file_types.executables_only)
                    {
                        return ignore::WalkState::Continue;
                    } else if !(entry_type.is_file() || entry_type.is_dir()
                        || entry_type.is_symlink())
                    {
                        // This is probably a block device, char device, fifo or socket. Skip it.
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            let entry_path = entry.path();

            // Filter out unwanted extensions.
            if let Some(ref exts_regex) = config.extensions {
                if let Some(path_str) = entry_path.file_name().map_or(None, |s| s.to_str()) {
                    if !exts_regex.is_match(path_str) {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            // Filter out unwanted sizes if it is a file and we have been given size constraints.
            if config.size_constraints.len() > 0 {
                if entry_path.is_file() {
                    if let Ok(metadata) = entry_path.metadata() {
                        let file_size = metadata.len();
                        if config
                            .size_constraints
                            .iter()
                            .any(|sc| !sc.is_within(file_size))
                        {
                            return ignore::WalkState::Continue;
                        }
                    } else {
                        return ignore::WalkState::Continue;
                    }
                } else {
                    return ignore::WalkState::Continue;
                }
            }

            let search_str_o = if config.search_full_path {
                match fshelper::path_absolute_form(entry_path) {
                    Ok(path_abs_buf) => Some(path_abs_buf.to_string_lossy().into_owned().into()),
                    Err(_) => error("Error: unable to get full path."),
                }
            } else {
                entry_path.file_name().map(|f| f.to_string_lossy())
            };

            if let Some(search_str) = search_str_o {
                if pattern.is_match(&*search_str) {
                    // TODO: take care of the unwrap call
                    tx_thread.send(entry_path.to_owned()).unwrap()
                }
            }

            ignore::WalkState::Continue
        })
    });

    // Drop the initial sender. If we don't do this, the receiver will block even
    // if all threads have finished, since there is still one sender around.
    drop(tx);

    // Wait for the receiver thread to print out all results.
    receiver_thread.join().unwrap();

    if wants_to_quit.load(Ordering::Relaxed) {
        process::exit(EXITCODE_SIGINT);
    }
}
<|endoftext|>


<commit_before>use std::process::Command;
use XML;

pub fn panel_xslt() -> String {
    let scss = Command::new("/usr/local/bin/sassc").arg("/Users/jadencarver/dev/superconductor/assets/__pm.scss").output().unwrap();
    let css = String::from_utf8(scss.stdout).unwrap();

    let markup = html! {
        xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" {
            xsl:output method="html" indent="yes" {}

            xsl:template match="/" {
                div#__pm__panel {
                    style type="text/css" (css)
                    style type="text/css" "@import url('//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/styles/agate.min.css');"
                    form#__pm__commit method="post" name="commit" {
                        ul#__pm__commits {
                            xsl:apply-templates select="/state/log/commit" {}
                        }
                        hr {}
                        dl.properties {
                            xsl:apply-templates select="/state/properties/property" {
                                xsl:with-param name="value" "5"
                            }
                        }
                        textarea id="__pm__commit__message" tabindex="1" name="message" placeholder="Add a Comment" {
                            xsl:value-of select="/state/message" {}
                        }
                        div#__pm__new_commit {
                            input type="submit" tabindex="4" name="save_update" value="Save Update" {}
                            xsl:if test="/state/changes/change" {
                                fieldset#__pm__commit__changes.details {
                                    legend#__pm__commit__changes_legend tabindex="2" role="button" {
                                        "Include Changes"
                                        span#__pm__commit__changes__statistics.token {
                                            xsl:if test="/state/changes/statistics/files != 0" {
                                                span {
                                                    xsl:value-of select="format-number(/state/changes/statistics/files, '#,###.##')" {}
                                                    " file"
                                                    xsl:if test="/state/changes/statistics/files != 1" {
                                                        "s"
                                                    }
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/insertions != 0" {
                                                span.token--positive {
                                                    "+"
                                                    xsl:value-of select="format-number(/state/changes/statistics/insertions, '#,###.##')" {}
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/deletions != 0" {
                                                span.token--negative {
                                                    "-"
                                                    xsl:value-of select="format-number(/state/changes/statistics/deletions, '#,###.##')" {}
                                                }
                                            }
                                        }
                                    }
                                    ul {
                                        xsl:apply-templates select="/state/changes/change" {}
                                    }
                                }
                            }
                        }
                    }
                    xsl:choose {
                        xsl:when test="/state/diffs" {
                            xsl:apply-templates select="/state/diffs" {}
                        }
                        xsl:otherwise {
                            xsl:apply-templates select="/state/tasks" {}
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property" {
                div.property {
                    xsl:choose {
                        xsl:when test="name = 'Status'" {
                            dt { label for="__pm__commit__properties--status" "Status" }
                            dd.select tabindex="1" {
                                xsl:value-of select="value" {}
                                select id="__pm__commit__properties--status" name="property" data-name="Status" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Developer'" {
                            dt "Developer"
                            dd.select {
                                input type="text" value="Jaden Carver" {}
                                select name="property" data-name="Developer" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Description'" {
                            dt "Description"
                            dd {
                                textarea name="property" data-name="Description" {
                                    xsl:value-of select="value" {}
                                }
                            }
                        }
                        xsl:otherwise {
                            dt "Estimate"
                            dd.input {
                                input type="text" name="property" data-name="Estimate" value="{value}" {}
                            }
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property/options/option" {
                xsl:element name="option" {
                    xsl:attribute name="value" {
                        xsl:value-of select="." {}
                    }
                    xsl:if test="./parent::options/parent::property/value = ." {
                        xsl:attribute name="selected" "selected"
                    }
                    xsl:value-of select="." {}
                }
            }
            xsl:template match="/state/diffs" {
                div.diff {
                    pre {
                        code {
                            xsl:copy-of select="*" {}
                        }
                    }
                }
            }
            xsl:template name="diff-lines" {
                xsl:param name="limit" select="1" {}
                xsl:param name="count" select="1" {}
                xsl:if test="$count <= $limit" {
                    li {
                        xsl:value-of select="$count" {}
                    }
                    xsl:call-template name="diff-lines" {
                        xsl:with-param name="limit" select="$limit" {}
                        xsl:with-param name="count" select="$count + 1" {}
                    }
                }
            }
            xsl:template match="/state/tasks" {
                ul.tiles {
                    header "Sprint"
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                }
                ul.tiles {
                    header {
                        "In Progress"
                    }
                    li draggable="true" {
                        div {
                            strong {
                                xsl:value-of select="/state/task" {}
                            }
                        }
                    }
                }
                ul.tiles {
                    header "In Review"
                    li draggable="true" {
                        div {
                            strong {
                                "Some issue"
                            }
                        }
                    }
                }
                ul.tiles {
                    header "Blocked"
                }
                ul.tiles {
                    header "Done"
                    li draggable="true" {
                        div {
                            strong {
                                "Some other issue"
                            }
                        }
                    }
                }
            }
            xsl:template match="/state/log/commit" {
                li {
                    xsl:if test="./preceding-sibling::commit[1]/user/email=user/email and ./preceding-sibling::commit[1]/timestamp - timestamp > -7200" {
                        xsl:attribute name="class" "continuous"
                    }
                    img src="{user/image}" alt="{user/name} <{user/email}>" {}
                    xsl:if test="changes" {
                        button.button--medium.attachments {
                            svg id="i-paperclip" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="20" height="20" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" {
                                path d="M10 9 L10 24 C10 28 13 30 16 30 19 30 22 28 22 24 L22 6 C22 3 20 2 18 2 16 2 14 3 14 6 L14 23 C14 24 15 25 16 25 17 25 18 24 18 23 L18 9" {}
                            }
                        }
                    }
                    blockquote {
                        a.user__name href="#" {
                            xsl:value-of select="user/name" {}
                        }
                        xsl:value-of select="message" {}
                    }
                    xsl:if test="task" {
                        dl.tasks {
                            xsl:apply-templates select="task" {}
                        }
                    }
                    div {
                        time datetime="{localtime}" {
                            xsl:value-of select="localtime" {}
                        }
                    }
                }
            }
            xsl:template match="/state/log/commit/task" {
                dt { xsl:value-of select="name" {} }
                dd {
                    ul.properties {
                        xsl:apply-templates select="property" {}
                    }
                }
            }
            xsl:template match="/state/log/commit/task/property" {
                li.token {
                    span.name { xsl:value-of select="name" {} }
                    xsl:if test="before" {
                        span.before.token--neutral { xsl:value-of select="before" {} }
                    }
                    span.after.token--positive { xsl:value-of select="after" {} }
                }
            }
            xsl:template match="/state/changes/change" {
                li tabindex="3" id="{concat('__pm__changes__checkbox--', @id)}" {
                    xsl:element name="input" {
                        xsl:attribute name="name" { "include" }
                        xsl:attribute name="id" {
                            xsl:value-of select="concat('__pm__changes--', @id)" {}
                        }
                        xsl:attribute name="value" {
                            xsl:value-of select="path" {}
                        }
                        xsl:attribute name="tabindex" "-1"
                        xsl:attribute name="type" "checkbox"
                        xsl:if test="included='true'" {
                            xsl:attribute name="checked" {}
                        }
                        xsl:if test="removal='true'" {
                            xsl:attribute name="class" { "delete" }
                        }
                    }
                    label for="__pm__changes--{@id}" {
                        xsl:value-of select="path" {}
                    }
                    button.button--tiny name="diff" value="{path}" { " +10 -10" }
                }
            }
        }
    };
    format!("{}{}", XML, markup.into_string())
}

<commit_msg>Only show diff when index is present. --- "BLBA-1234":    Description: ""   Developer: Sprint   Estimate: "5"   Status: Done<commit_after>use std::process::Command;
use XML;

pub fn panel_xslt() -> String {
    let scss = Command::new("/usr/local/bin/sassc").arg("/Users/jadencarver/dev/superconductor/assets/__pm.scss").output().unwrap();
    let css = String::from_utf8(scss.stdout).unwrap();

    let markup = html! {
        xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" {
            xsl:output method="html" indent="yes" {}

            xsl:template match="/" {
                div#__pm__panel {
                    style type="text/css" (css)
                    style type="text/css" "@import url('//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.10.0/styles/agate.min.css');"
                    form#__pm__commit method="post" name="commit" {
                        ul#__pm__commits {
                            xsl:apply-templates select="/state/log/commit" {}
                        }
                        hr {}
                        dl.properties {
                            xsl:apply-templates select="/state/properties/property" {
                                xsl:with-param name="value" "5"
                            }
                        }
                        textarea id="__pm__commit__message" tabindex="1" name="message" placeholder="Add a Comment" {
                            xsl:value-of select="/state/message" {}
                        }
                        div#__pm__new_commit {
                            input type="submit" tabindex="4" name="save_update" value="Save Update" {}
                            xsl:if test="/state/changes/change" {
                                fieldset#__pm__commit__changes.details {
                                    legend#__pm__commit__changes_legend tabindex="2" role="button" {
                                        "Include Changes"
                                        span#__pm__commit__changes__statistics.token {
                                            xsl:if test="/state/changes/statistics/files != 0" {
                                                span {
                                                    xsl:value-of select="format-number(/state/changes/statistics/files, '#,###.##')" {}
                                                    " file"
                                                    xsl:if test="/state/changes/statistics/files != 1" {
                                                        "s"
                                                    }
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/insertions != 0" {
                                                span.token--positive {
                                                    "+"
                                                    xsl:value-of select="format-number(/state/changes/statistics/insertions, '#,###.##')" {}
                                                }
                                            }
                                            xsl:if test="/state/changes/statistics/deletions != 0" {
                                                span.token--negative {
                                                    "-"
                                                    xsl:value-of select="format-number(/state/changes/statistics/deletions, '#,###.##')" {}
                                                }
                                            }
                                        }
                                    }
                                    ul {
                                        xsl:apply-templates select="/state/changes/change" {}
                                    }
                                }
                            }
                        }
                    }
                    xsl:choose {
                        xsl:when test="/state/diffs/*" {
                            xsl:apply-templates select="/state/diffs" {}
                        }
                        xsl:otherwise {
                            xsl:apply-templates select="/state/tasks" {}
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property" {
                div.property {
                    xsl:choose {
                        xsl:when test="name = 'Status'" {
                            dt { label for="__pm__commit__properties--status" "Status" }
                            dd.select tabindex="1" {
                                xsl:value-of select="value" {}
                                select id="__pm__commit__properties--status" name="property" data-name="Status" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Developer'" {
                            dt "Developer"
                            dd.select {
                                input type="text" value="Jaden Carver" {}
                                select name="property" data-name="Developer" {
                                    xsl:apply-templates "options/option" {}
                                }
                            }
                        }
                        xsl:when test="name = 'Description'" {
                            dt "Description"
                            dd {
                                textarea name="property" data-name="Description" {
                                    xsl:value-of select="value" {}
                                }
                            }
                        }
                        xsl:otherwise {
                            dt "Estimate"
                            dd.input {
                                input type="text" name="property" data-name="Estimate" value="{value}" {}
                            }
                        }
                    }
                }
            }
            xsl:template match="/state/properties/property/options/option" {
                xsl:element name="option" {
                    xsl:attribute name="value" {
                        xsl:value-of select="." {}
                    }
                    xsl:if test="./parent::options/parent::property/value = ." {
                        xsl:attribute name="selected" "selected"
                    }
                    xsl:value-of select="." {}
                }
            }
            xsl:template match="/state/diffs" {
                div.diff {
                    pre {
                        code {
                            xsl:copy-of select="*" {}
                        }
                    }
                }
            }
            xsl:template name="diff-lines" {
                xsl:param name="limit" select="1" {}
                xsl:param name="count" select="1" {}
                xsl:if test="$count <= $limit" {
                    li {
                        xsl:value-of select="$count" {}
                    }
                    xsl:call-template name="diff-lines" {
                        xsl:with-param name="limit" select="$limit" {}
                        xsl:with-param name="count" select="$count + 1" {}
                    }
                }
            }
            xsl:template match="/state/tasks" {
                ul.tiles {
                    header "Sprint"
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                    li draggable="true" {
                        div {
                            strong "BLBA-1234"
                            p "Some upcoming issue"
                        }
                    }
                }
                ul.tiles {
                    header {
                        "In Progress"
                    }
                    li draggable="true" {
                        div {
                            strong {
                                xsl:value-of select="/state/task" {}
                            }
                        }
                    }
                }
                ul.tiles {
                    header "In Review"
                    li draggable="true" {
                        div {
                            strong {
                                "Some issue"
                            }
                        }
                    }
                }
                ul.tiles {
                    header "Blocked"
                }
                ul.tiles {
                    header "Done"
                    li draggable="true" {
                        div {
                            strong {
                                "Some other issue"
                            }
                        }
                    }
                }
            }
            xsl:template match="/state/log/commit" {
                li {
                    xsl:if test="./preceding-sibling::commit[1]/user/email=user/email and ./preceding-sibling::commit[1]/timestamp - timestamp > -7200" {
                        xsl:attribute name="class" "continuous"
                    }
                    img src="{user/image}" alt="{user/name} <{user/email}>" {}
                    xsl:if test="changes" {
                        button.button--medium.attachments {
                            svg id="i-paperclip" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="20" height="20" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" {
                                path d="M10 9 L10 24 C10 28 13 30 16 30 19 30 22 28 22 24 L22 6 C22 3 20 2 18 2 16 2 14 3 14 6 L14 23 C14 24 15 25 16 25 17 25 18 24 18 23 L18 9" {}
                            }
                        }
                    }
                    blockquote {
                        a.user__name href="#" {
                            xsl:value-of select="user/name" {}
                        }
                        xsl:value-of select="message" {}
                    }
                    xsl:if test="task" {
                        dl.tasks {
                            xsl:apply-templates select="task" {}
                        }
                    }
                    div {
                        time datetime="{localtime}" {
                            xsl:value-of select="localtime" {}
                        }
                    }
                }
            }
            xsl:template match="/state/log/commit/task" {
                dt { xsl:value-of select="name" {} }
                dd {
                    ul.properties {
                        xsl:apply-templates select="property" {}
                    }
                }
            }
            xsl:template match="/state/log/commit/task/property" {
                li.token {
                    span.name { xsl:value-of select="name" {} }
                    xsl:if test="before" {
                        span.before.token--neutral { xsl:value-of select="before" {} }
                    }
                    span.after.token--positive { xsl:value-of select="after" {} }
                }
            }
            xsl:template match="/state/changes/change" {
                li tabindex="3" id="{concat('__pm__changes__checkbox--', @id)}" {
                    xsl:element name="input" {
                        xsl:attribute name="name" { "include" }
                        xsl:attribute name="id" {
                            xsl:value-of select="concat('__pm__changes--', @id)" {}
                        }
                        xsl:attribute name="value" {
                            xsl:value-of select="path" {}
                        }
                        xsl:attribute name="tabindex" "-1"
                        xsl:attribute name="type" "checkbox"
                        xsl:if test="included='true'" {
                            xsl:attribute name="checked" {}
                        }
                        xsl:if test="removal='true'" {
                            xsl:attribute name="class" { "delete" }
                        }
                    }
                    label for="__pm__changes--{@id}" {
                        xsl:value-of select="path" {}
                    }
                    button.button--tiny name="diff" value="{path}" { " +10 -10" }
                }
            }
        }
    };
    format!("{}{}", XML, markup.into_string())
}

<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

mod struct_log;
<commit_msg>[logging] remove unused file<commit_after><|endoftext|>


<commit_before>enum OptionalInt {
    Value(int),
    Missing
}

#[warn(dead_code)]
fn main() {
    println!("Hello, world!");

    let x = OptionalInt::Value(15i);

    match x {
        OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
        OptionalInt::Value(..) => println!("Got an int!"),
        OptionalInt::Missing => println!("No such luck"),
    };
}
<commit_msg>fix int type<commit_after>enum OptionalInt {
    Value(i32),
    Missing
}

#[warn(dead_code)]
fn main() {
    println!("Hello, world!");

    let x = OptionalInt::Value(15i32);

    match x {
        OptionalInt::Value(i) if i > 5 => println!("Got an i32 bigger than five!"),
        OptionalInt::Value(..) => println!("Got an i32!"),
        OptionalInt::Missing => println!("No such luck"),
    };

    let y = OptionalInt::Missing;

    match y {
        OptionalInt::Value(i) if i > 5 => println!("Got an i32 bigger than five!"),
        OptionalInt::Value(..) => println!("Got an i32!"),
        OptionalInt::Missing => println!("No such luck"),
    };
}
<|endoftext|>


<commit_before>use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::{fmt, mem};
use core::convert::{Into, TryFrom, TryInto};

use usize_conversions::{usize_from, FromUsize};
use bit_field::BitField;
use ux::*;

/// A canonical 64-bit virtual memory address.
///
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
/// on non 64-bit systems. The `UsizeConversions` trait can be used for performing conversions
/// between `u64` and `usize`.
///
/// On `x86_64`, only the 48 lower bits of a virtual address can be used. The top 16 bits need
/// to be copies of bit 47, i.e. the most significant bit. Addresses that fulfil this criterium
/// are called “canonical”. This type guarantees that it always represents a canonical address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct VirtAddr(u64);

/// A 64-bit physical memory address.
///
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
/// on non 64-bit systems. The `UsizeConversions` trait can be used for performing conversions
/// between `u64` and `usize`.
///
/// On `x86_64`, only the 52 lower bits of a physical address can be used. The top 12 bits need
/// to be zero. This type guarantees that it always represents a valid physical address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct PhysAddr(u64);

/// A passed `u64` was not a valid virtual address.
///
/// This means that bits 48 to 64 are not
/// a valid sign extension and are not null either. So automatic sign extension would have
/// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid
/// address calculation.
#[derive(Debug)]
pub struct VirtAddrNotValid(u64);

impl VirtAddr {
    /// Creates a new canonical virtual address.
    ///
    /// This function performs sign extension of bit 47 to make the address canonical. Panics
    /// if the bits in the range 48 to 64 contain data (i.e. are not null and no sign extension).
    pub fn new(addr: u64) -> VirtAddr {
        Self::try_new(addr).expect("address passed to VirtAddr::new must not contain any data \
        in bits 48 to 64")
    }

    /// Tries to create a new canonical virtual address.
    ///
    /// This function tries to performs sign
    /// extension of bit 47 to make the address canonical. It succeeds if bits 48 to 64 are
    /// either a correct sign extension (i.e. copies of bit 47) or all null. Else, an error
    /// is returned.
    pub fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
        match addr.get_bits(47..64) {
            0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical
            1 => Ok(VirtAddr::new_unchecked(addr)), // address needs sign extension
            other => Err(VirtAddrNotValid(other))
        }
    }

    /// Creates a new canonical virtual address without checks.
    ///
    /// This function performs sign extension of bit 47 to make the address canonical, so
    /// bits 48 to 64 are overwritten. If you want to check that these bits contain no data,
    /// use `new` or `try_new`.
    pub fn new_unchecked(mut addr: u64) -> VirtAddr {
        if addr.get_bit(47) {
            addr.set_bits(48..64, 0xffff);
        } else {
            addr.set_bits(48..64, 0);
        }
        VirtAddr(addr)
    }

    /// Converts the address to an `u64`.
    pub fn as_u64(self) -> u64 {
        self.0
    }

    pub fn as_ptr<T>(self) -> *const T {
        usize_from(self.as_u64()) as *const T
    }

    pub fn as_mut_ptr<T>(self) -> *mut T {
        self.as_ptr::<T>() as *mut T
    }

    /// Aligns the virtual address upwards to the given alignment.
    ///
    /// See the `align_up` function for more information.
    pub fn align_up<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        VirtAddr(align_up(self.0, align.into()))
    }

    /// Aligns the virtual address downwards to the given alignment.
    ///
    /// See the `align_down` function for more information.
    pub fn align_down<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        VirtAddr(align_down(self.0, align.into()))
    }

    /// Returns the 12-bit page offset of this virtual address.
    pub fn page_offset(&self) -> u12 {
        u12::new((self.0 & 0xfff).try_into().unwrap())
    }

    /// Returns the 9-bit level 1 page table index.
    pub fn p1_index(&self) -> u9 {
        u9::new(((self.0 >> 12) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 2 page table index.
    pub fn p2_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 3 page table index.
    pub fn p3_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9 >> 9) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 4 page table index.
    pub fn p4_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9 >> 9 >> 9) & 0o777).try_into().unwrap())
    }
}

impl fmt::Debug for VirtAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "VirtAddr({:#x})", self.0)
    }
}

impl Add<u64> for VirtAddr {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        VirtAddr::new(self.0 + rhs)
    }
}

impl AddAssign<u64> for VirtAddr {
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl Add<usize> for VirtAddr where u64: FromUsize {
    type Output = Self;
    fn add(self, rhs: usize) -> Self::Output {
        self + u64::from_usize(rhs)
    }
}

impl AddAssign<usize> for VirtAddr where u64: FromUsize {
    fn add_assign(&mut self, rhs: usize) {
        self.add_assign(u64::from_usize(rhs))
    }
}

impl Sub<u64> for VirtAddr {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        VirtAddr::new(self.0 - rhs)
    }
}

impl SubAssign<u64> for VirtAddr {
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl Sub<usize> for VirtAddr where u64: FromUsize {
    type Output = Self;
    fn sub(self, rhs: usize) -> Self::Output {
        self - u64::from_usize(rhs)
    }
}

impl SubAssign<usize> for VirtAddr where u64: FromUsize {
    fn sub_assign(&mut self, rhs: usize) {
        self.sub_assign(u64::from_usize(rhs))
    }
}

impl Sub<VirtAddr> for VirtAddr {
    type Output = u64;
    fn sub(self, rhs: VirtAddr) -> Self::Output {
        self.as_u64() - rhs.as_u64()
    }
}

/// A passed `u64` was not a valid physical address.
///
/// This means that bits 52 to 64 are not were not all null.
#[derive(Debug)]
pub struct PhysAddrNotValid(u64);

impl PhysAddr {
    /// Creates a new physical address.
    ///
    /// Panics if a bit in the range 52 to 64 is set.
    pub fn new(addr: u64) -> PhysAddr {
        assert_eq!(addr.get_bits(52..64), 0,
            "physical addresses must not have any bits in the range 52 to 64 set");
        PhysAddr(addr)
    }

    /// Tries to create a new physical address.
    ///
    /// Fails if any bits in the range 52 to 64 are set.
    pub fn try_new(addr: u64) -> Result<PhysAddr, PhysAddrNotValid> {
        match addr.get_bits(52..64) {
            0 => Ok(PhysAddr(addr)), // address is valid
            other => Err(PhysAddrNotValid(other))
        }
    }

    /// Converts the address to an `u64`.
    pub fn as_u64(self) -> u64 {
        self.0
    }

    /// Convenience method for checking if a physical address is null.
    pub fn is_null(&self) -> bool {
        self.0 == 0
    }

    /// Aligns the physical address upwards to the given alignment.
    ///
    /// See the `align_up` function for more information.
    pub fn align_up<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        PhysAddr(align_up(self.0, align.into()))
    }

    /// Aligns the physical address downwards to the given alignment.
    ///
    /// See the `align_down` function for more information.
    pub fn align_down<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        PhysAddr(align_down(self.0, align.into()))
    }
}

impl fmt::Debug for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PhysAddr({:#x})", self.0)
    }
}

impl fmt::Binary for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl Add<u64> for PhysAddr {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        PhysAddr::new(self.0 + rhs)
    }
}

impl AddAssign<u64> for PhysAddr {
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl Add<usize> for PhysAddr where u64: FromUsize {
    type Output = Self;
    fn add(self, rhs: usize) -> Self::Output {
        self + u64::from_usize(rhs)
    }
}

impl AddAssign<usize> for PhysAddr where u64: FromUsize {
    fn add_assign(&mut self, rhs: usize) {
        self.add_assign(u64::from_usize(rhs))
    }
}

impl Sub<u64> for PhysAddr {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        PhysAddr::new(self.0 - rhs)
    }
}

impl SubAssign<u64> for PhysAddr {
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl Sub<usize> for PhysAddr where u64: FromUsize {
    type Output = Self;
    fn sub(self, rhs: usize) -> Self::Output {
        self - u64::from_usize(rhs)
    }
}

impl SubAssign<usize> for PhysAddr where u64: FromUsize {
    fn sub_assign(&mut self, rhs: usize) {
        self.sub_assign(u64::from_usize(rhs))
    }
}

impl Sub<PhysAddr> for PhysAddr {
    type Output = u64;
    fn sub(self, rhs: PhysAddr) -> Self::Output {
        self.as_u64() - rhs.as_u64()
    }
}

/// Align address downwards.
///
/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be
///  a power of 2.
pub fn align_down(addr: u64, align: u64) -> u64 {
    assert!(align.is_power_of_two(), "`align` must be a power of two");
    addr & !(align - 1)
}

/// Align address upwards.
///
/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be
/// a power of 2.
pub fn align_up(addr: u64, align: u64) -> u64 {
    assert!(align.is_power_of_two(), "`align` must be a power of two");
    let align_mask = align - 1;
    if addr & align_mask == 0 {
        addr // already aligned
    } else {
        (addr | align_mask) + 1
    }
}

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

    #[test]
    pub fn test_align_up() {
        // align 1
        assert_eq!(align_up(0, 1), 0);
        assert_eq!(align_up(1234, 1), 1234);
        assert_eq!(align_up(0xffffffffffffffff, 1), 0xffffffffffffffff);
        // align 2
        assert_eq!(align_up(0, 2), 0);
        assert_eq!(align_up(1233, 2), 1234);
        assert_eq!(align_up(0xfffffffffffffffe, 2), 0xfffffffffffffffe);
        // address 0
        assert_eq!(align_up(0, 128), 0);
        assert_eq!(align_up(0, 1), 0);
        assert_eq!(align_up(0, 2), 0);
        assert_eq!(align_up(0, 0x8000000000000000), 0);
    }
}
<commit_msg>Remove unused imports<commit_after>use core::ops::{Add, AddAssign, Sub, SubAssign};
use core::fmt;
use core::convert::{Into, TryInto};

use usize_conversions::{usize_from, FromUsize};
use bit_field::BitField;
use ux::*;

/// A canonical 64-bit virtual memory address.
///
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
/// on non 64-bit systems. The `UsizeConversions` trait can be used for performing conversions
/// between `u64` and `usize`.
///
/// On `x86_64`, only the 48 lower bits of a virtual address can be used. The top 16 bits need
/// to be copies of bit 47, i.e. the most significant bit. Addresses that fulfil this criterium
/// are called “canonical”. This type guarantees that it always represents a canonical address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct VirtAddr(u64);

/// A 64-bit physical memory address.
///
/// This is a wrapper type around an `u64`, so it is always 8 bytes, even when compiled
/// on non 64-bit systems. The `UsizeConversions` trait can be used for performing conversions
/// between `u64` and `usize`.
///
/// On `x86_64`, only the 52 lower bits of a physical address can be used. The top 12 bits need
/// to be zero. This type guarantees that it always represents a valid physical address.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[repr(transparent)]
pub struct PhysAddr(u64);

/// A passed `u64` was not a valid virtual address.
///
/// This means that bits 48 to 64 are not
/// a valid sign extension and are not null either. So automatic sign extension would have
/// overwritten possibly meaningful bits. This likely indicates a bug, for example an invalid
/// address calculation.
#[derive(Debug)]
pub struct VirtAddrNotValid(u64);

impl VirtAddr {
    /// Creates a new canonical virtual address.
    ///
    /// This function performs sign extension of bit 47 to make the address canonical. Panics
    /// if the bits in the range 48 to 64 contain data (i.e. are not null and no sign extension).
    pub fn new(addr: u64) -> VirtAddr {
        Self::try_new(addr).expect("address passed to VirtAddr::new must not contain any data \
        in bits 48 to 64")
    }

    /// Tries to create a new canonical virtual address.
    ///
    /// This function tries to performs sign
    /// extension of bit 47 to make the address canonical. It succeeds if bits 48 to 64 are
    /// either a correct sign extension (i.e. copies of bit 47) or all null. Else, an error
    /// is returned.
    pub fn try_new(addr: u64) -> Result<VirtAddr, VirtAddrNotValid> {
        match addr.get_bits(47..64) {
            0 | 0x1ffff => Ok(VirtAddr(addr)), // address is canonical
            1 => Ok(VirtAddr::new_unchecked(addr)), // address needs sign extension
            other => Err(VirtAddrNotValid(other))
        }
    }

    /// Creates a new canonical virtual address without checks.
    ///
    /// This function performs sign extension of bit 47 to make the address canonical, so
    /// bits 48 to 64 are overwritten. If you want to check that these bits contain no data,
    /// use `new` or `try_new`.
    pub fn new_unchecked(mut addr: u64) -> VirtAddr {
        if addr.get_bit(47) {
            addr.set_bits(48..64, 0xffff);
        } else {
            addr.set_bits(48..64, 0);
        }
        VirtAddr(addr)
    }

    /// Converts the address to an `u64`.
    pub fn as_u64(self) -> u64 {
        self.0
    }

    pub fn as_ptr<T>(self) -> *const T {
        usize_from(self.as_u64()) as *const T
    }

    pub fn as_mut_ptr<T>(self) -> *mut T {
        self.as_ptr::<T>() as *mut T
    }

    /// Aligns the virtual address upwards to the given alignment.
    ///
    /// See the `align_up` function for more information.
    pub fn align_up<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        VirtAddr(align_up(self.0, align.into()))
    }

    /// Aligns the virtual address downwards to the given alignment.
    ///
    /// See the `align_down` function for more information.
    pub fn align_down<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        VirtAddr(align_down(self.0, align.into()))
    }

    /// Returns the 12-bit page offset of this virtual address.
    pub fn page_offset(&self) -> u12 {
        u12::new((self.0 & 0xfff).try_into().unwrap())
    }

    /// Returns the 9-bit level 1 page table index.
    pub fn p1_index(&self) -> u9 {
        u9::new(((self.0 >> 12) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 2 page table index.
    pub fn p2_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 3 page table index.
    pub fn p3_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9 >> 9) & 0o777).try_into().unwrap())
    }

    /// Returns the 9-bit level 4 page table index.
    pub fn p4_index(&self) -> u9 {
        u9::new(((self.0 >> 12 >> 9 >> 9 >> 9) & 0o777).try_into().unwrap())
    }
}

impl fmt::Debug for VirtAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "VirtAddr({:#x})", self.0)
    }
}

impl Add<u64> for VirtAddr {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        VirtAddr::new(self.0 + rhs)
    }
}

impl AddAssign<u64> for VirtAddr {
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl Add<usize> for VirtAddr where u64: FromUsize {
    type Output = Self;
    fn add(self, rhs: usize) -> Self::Output {
        self + u64::from_usize(rhs)
    }
}

impl AddAssign<usize> for VirtAddr where u64: FromUsize {
    fn add_assign(&mut self, rhs: usize) {
        self.add_assign(u64::from_usize(rhs))
    }
}

impl Sub<u64> for VirtAddr {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        VirtAddr::new(self.0 - rhs)
    }
}

impl SubAssign<u64> for VirtAddr {
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl Sub<usize> for VirtAddr where u64: FromUsize {
    type Output = Self;
    fn sub(self, rhs: usize) -> Self::Output {
        self - u64::from_usize(rhs)
    }
}

impl SubAssign<usize> for VirtAddr where u64: FromUsize {
    fn sub_assign(&mut self, rhs: usize) {
        self.sub_assign(u64::from_usize(rhs))
    }
}

impl Sub<VirtAddr> for VirtAddr {
    type Output = u64;
    fn sub(self, rhs: VirtAddr) -> Self::Output {
        self.as_u64() - rhs.as_u64()
    }
}

/// A passed `u64` was not a valid physical address.
///
/// This means that bits 52 to 64 are not were not all null.
#[derive(Debug)]
pub struct PhysAddrNotValid(u64);

impl PhysAddr {
    /// Creates a new physical address.
    ///
    /// Panics if a bit in the range 52 to 64 is set.
    pub fn new(addr: u64) -> PhysAddr {
        assert_eq!(addr.get_bits(52..64), 0,
            "physical addresses must not have any bits in the range 52 to 64 set");
        PhysAddr(addr)
    }

    /// Tries to create a new physical address.
    ///
    /// Fails if any bits in the range 52 to 64 are set.
    pub fn try_new(addr: u64) -> Result<PhysAddr, PhysAddrNotValid> {
        match addr.get_bits(52..64) {
            0 => Ok(PhysAddr(addr)), // address is valid
            other => Err(PhysAddrNotValid(other))
        }
    }

    /// Converts the address to an `u64`.
    pub fn as_u64(self) -> u64 {
        self.0
    }

    /// Convenience method for checking if a physical address is null.
    pub fn is_null(&self) -> bool {
        self.0 == 0
    }

    /// Aligns the physical address upwards to the given alignment.
    ///
    /// See the `align_up` function for more information.
    pub fn align_up<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        PhysAddr(align_up(self.0, align.into()))
    }

    /// Aligns the physical address downwards to the given alignment.
    ///
    /// See the `align_down` function for more information.
    pub fn align_down<U>(self, align: U) -> Self
        where U: Into<u64>
    {
        PhysAddr(align_down(self.0, align.into()))
    }
}

impl fmt::Debug for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PhysAddr({:#x})", self.0)
    }
}

impl fmt::Binary for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::LowerHex for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::Octal for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl fmt::UpperHex for PhysAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.0.fmt(f)
    }
}

impl Add<u64> for PhysAddr {
    type Output = Self;
    fn add(self, rhs: u64) -> Self::Output {
        PhysAddr::new(self.0 + rhs)
    }
}

impl AddAssign<u64> for PhysAddr {
    fn add_assign(&mut self, rhs: u64) {
        *self = *self + rhs;
    }
}

impl Add<usize> for PhysAddr where u64: FromUsize {
    type Output = Self;
    fn add(self, rhs: usize) -> Self::Output {
        self + u64::from_usize(rhs)
    }
}

impl AddAssign<usize> for PhysAddr where u64: FromUsize {
    fn add_assign(&mut self, rhs: usize) {
        self.add_assign(u64::from_usize(rhs))
    }
}

impl Sub<u64> for PhysAddr {
    type Output = Self;
    fn sub(self, rhs: u64) -> Self::Output {
        PhysAddr::new(self.0 - rhs)
    }
}

impl SubAssign<u64> for PhysAddr {
    fn sub_assign(&mut self, rhs: u64) {
        *self = *self - rhs;
    }
}

impl Sub<usize> for PhysAddr where u64: FromUsize {
    type Output = Self;
    fn sub(self, rhs: usize) -> Self::Output {
        self - u64::from_usize(rhs)
    }
}

impl SubAssign<usize> for PhysAddr where u64: FromUsize {
    fn sub_assign(&mut self, rhs: usize) {
        self.sub_assign(u64::from_usize(rhs))
    }
}

impl Sub<PhysAddr> for PhysAddr {
    type Output = u64;
    fn sub(self, rhs: PhysAddr) -> Self::Output {
        self.as_u64() - rhs.as_u64()
    }
}

/// Align address downwards.
///
/// Returns the greatest x with alignment `align` so that x <= addr. The alignment must be
///  a power of 2.
pub fn align_down(addr: u64, align: u64) -> u64 {
    assert!(align.is_power_of_two(), "`align` must be a power of two");
    addr & !(align - 1)
}

/// Align address upwards.
///
/// Returns the smallest x with alignment `align` so that x >= addr. The alignment must be
/// a power of 2.
pub fn align_up(addr: u64, align: u64) -> u64 {
    assert!(align.is_power_of_two(), "`align` must be a power of two");
    let align_mask = align - 1;
    if addr & align_mask == 0 {
        addr // already aligned
    } else {
        (addr | align_mask) + 1
    }
}

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

    #[test]
    pub fn test_align_up() {
        // align 1
        assert_eq!(align_up(0, 1), 0);
        assert_eq!(align_up(1234, 1), 1234);
        assert_eq!(align_up(0xffffffffffffffff, 1), 0xffffffffffffffff);
        // align 2
        assert_eq!(align_up(0, 2), 0);
        assert_eq!(align_up(1233, 2), 1234);
        assert_eq!(align_up(0xfffffffffffffffe, 2), 0xfffffffffffffffe);
        // address 0
        assert_eq!(align_up(0, 128), 0);
        assert_eq!(align_up(0, 1), 0);
        assert_eq!(align_up(0, 2), 0);
        assert_eq!(align_up(0, 0x8000000000000000), 0);
    }
}
<|endoftext|>