<commit_before>use std::path::Path;
use std::fs::File;
use std::io::Read;

pub static INDEX: &'static [u8] = include_bytes!("index.hbs");
pub static CSS: &'static [u8] = include_bytes!("book.css");
pub static FAVICON: &'static [u8] = include_bytes!("favicon.png");
pub static JS: &'static [u8] = include_bytes!("book.js");
pub static HIGHLIGHT_JS: &'static [u8] = include_bytes!("highlight.js");
pub static TOMORROW_NIGHT_CSS: &'static [u8] = include_bytes!("tomorrow-night.css");
pub static HIGHLIGHT_CSS: &'static [u8] = include_bytes!("highlight.css");
pub static AYU_HIGHLIGHT_CSS: &'static [u8] = include_bytes!("ayu-highlight.css");
pub static JQUERY: &'static [u8] = include_bytes!("jquery-2.1.4.min.js");
pub static CLIPBOARD_JS: &'static [u8] = include_bytes!("clipboard.min.js");
pub static STORE_JS: &'static [u8] = include_bytes!("store.js");
pub static FONT_AWESOME: &'static [u8] = include_bytes!("_FontAwesome/css/font-awesome.min.css");
pub static FONT_AWESOME_EOT: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.eot");
pub static FONT_AWESOME_SVG: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.svg");
pub static FONT_AWESOME_TTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.ttf");
pub static FONT_AWESOME_WOFF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff");
pub static FONT_AWESOME_WOFF2: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff2");
pub static FONT_AWESOME_OTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/FontAwesome.otf");

/// The `Theme` struct should be used instead of the static variables because
/// the `new()` method
/// will look if the user has a theme directory in his source folder and use
/// the users theme instead
/// of the default.
///
/// You should exceptionnaly use the static variables only if you need the
/// default theme even if the
/// user has specified another theme.
pub struct Theme {
    pub index: Vec<u8>,
    pub css: Vec<u8>,
    pub favicon: Vec<u8>,
    pub js: Vec<u8>,
    pub highlight_css: Vec<u8>,
    pub tomorrow_night_css: Vec<u8>,
    pub ayu_highlight_css: Vec<u8>,
    pub highlight_js: Vec<u8>,
    pub clipboard_js: Vec<u8>,
    pub store_js: Vec<u8>,
    pub jquery: Vec<u8>,
}

impl Theme {
    pub fn new(src: &Path) -> Self {

        // Default theme
        let mut theme = Theme {
            index: INDEX.to_owned(),
            css: CSS.to_owned(),
            favicon: FAVICON.to_owned(),
            js: JS.to_owned(),
            highlight_css: HIGHLIGHT_CSS.to_owned(),
            tomorrow_night_css: TOMORROW_NIGHT_CSS.to_owned(),
            ayu_highlight_css: AYU_HIGHLIGHT_CSS.to_owned(),
            highlight_js: HIGHLIGHT_JS.to_owned(),
            clipboard_js: CLIPBOARD_JS.to_owned(),
            store_js: STORE_JS.to_owned(),
            jquery: JQUERY.to_owned(),
        };

        // Check if the given path exists
        if !src.exists() || !src.is_dir() {
            return theme;
        }

        // Check for individual files if they exist

        // index.hbs
        if let Ok(mut f) = File::open(&src.join("index.hbs")) {
            theme.index.clear(); // Reset the value, because read_to_string appends...
            let _ = f.read_to_end(&mut theme.index);
        }

        // book.js
        if let Ok(mut f) = File::open(&src.join("book.js")) {
            theme.js.clear();
            let _ = f.read_to_end(&mut theme.js);
        }

        // book.css
        if let Ok(mut f) = File::open(&src.join("book.css")) {
            theme.css.clear();
            let _ = f.read_to_end(&mut theme.css);
        }

        // favicon.png
        if let Ok(mut f) = File::open(&src.join("favicon.png")) {
            theme.favicon.clear();
            let _ = f.read_to_end(&mut theme.favicon);
        }

        // highlight.js
        if let Ok(mut f) = File::open(&src.join("highlight.js")) {
            theme.highlight_js.clear();
            let _ = f.read_to_end(&mut theme.highlight_js);
        }

        // clipboard.js
        if let Ok(mut f) = File::open(&src.join("clipboard.min.js")) {
            theme.clipboard_js.clear();
            let _ = f.read_to_end(&mut theme.clipboard_js);
        }

        // store.js
        if let Ok(mut f) = File::open(&src.join("store.js")) {
            theme.store_js.clear();
            let _ = f.read_to_end(&mut theme.store_js);
        }

        // highlight.css
        if let Ok(mut f) = File::open(&src.join("highlight.css")) {
            theme.highlight_css.clear();
            let _ = f.read_to_end(&mut theme.highlight_css);
        }

        // tomorrow-night.css
        if let Ok(mut f) = File::open(&src.join("tomorrow-night.css")) {
            theme.tomorrow_night_css.clear();
            let _ = f.read_to_end(&mut theme.tomorrow_night_css);
        }

        // ayu-highlight.css
        if let Ok(mut f) = File::open(&src.join("ayu-highlight.css")) {
            theme.ayu_highlight_css.clear();
            let _ = f.read_to_end(&mut theme.ayu_highlight_css);
        }

        theme
    }
}
<commit_msg>removed some repetition from the themes module<commit_after>use std::path::Path;
use std::fs::File;
use std::io::Read;

pub static INDEX: &'static [u8] = include_bytes!("index.hbs");
pub static CSS: &'static [u8] = include_bytes!("book.css");
pub static FAVICON: &'static [u8] = include_bytes!("favicon.png");
pub static JS: &'static [u8] = include_bytes!("book.js");
pub static HIGHLIGHT_JS: &'static [u8] = include_bytes!("highlight.js");
pub static TOMORROW_NIGHT_CSS: &'static [u8] = include_bytes!("tomorrow-night.css");
pub static HIGHLIGHT_CSS: &'static [u8] = include_bytes!("highlight.css");
pub static AYU_HIGHLIGHT_CSS: &'static [u8] = include_bytes!("ayu-highlight.css");
pub static JQUERY: &'static [u8] = include_bytes!("jquery-2.1.4.min.js");
pub static CLIPBOARD_JS: &'static [u8] = include_bytes!("clipboard.min.js");
pub static STORE_JS: &'static [u8] = include_bytes!("store.js");
pub static FONT_AWESOME: &'static [u8] = include_bytes!("_FontAwesome/css/font-awesome.min.css");
pub static FONT_AWESOME_EOT: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.eot");
pub static FONT_AWESOME_SVG: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.svg");
pub static FONT_AWESOME_TTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.ttf");
pub static FONT_AWESOME_WOFF: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff");
pub static FONT_AWESOME_WOFF2: &'static [u8] = include_bytes!("_FontAwesome/fonts/fontawesome-webfont.woff2");
pub static FONT_AWESOME_OTF: &'static [u8] = include_bytes!("_FontAwesome/fonts/FontAwesome.otf");

/// The `Theme` struct should be used instead of the static variables because
/// the `new()` method
/// will look if the user has a theme directory in his source folder and use
/// the users theme instead
/// of the default.
///
/// You should exceptionnaly use the static variables only if you need the
/// default theme even if the
/// user has specified another theme.
pub struct Theme {
    pub index: Vec<u8>,
    pub css: Vec<u8>,
    pub favicon: Vec<u8>,
    pub js: Vec<u8>,
    pub highlight_css: Vec<u8>,
    pub tomorrow_night_css: Vec<u8>,
    pub ayu_highlight_css: Vec<u8>,
    pub highlight_js: Vec<u8>,
    pub clipboard_js: Vec<u8>,
    pub store_js: Vec<u8>,
    pub jquery: Vec<u8>,
}

impl Theme {
    pub fn new(src: &Path) -> Self {

        // Default theme
        let mut theme = Theme {
            index: INDEX.to_owned(),
            css: CSS.to_owned(),
            favicon: FAVICON.to_owned(),
            js: JS.to_owned(),
            highlight_css: HIGHLIGHT_CSS.to_owned(),
            tomorrow_night_css: TOMORROW_NIGHT_CSS.to_owned(),
            ayu_highlight_css: AYU_HIGHLIGHT_CSS.to_owned(),
            highlight_js: HIGHLIGHT_JS.to_owned(),
            clipboard_js: CLIPBOARD_JS.to_owned(),
            store_js: STORE_JS.to_owned(),
            jquery: JQUERY.to_owned(),
        };

        // Check if the given path exists
        if !src.exists() || !src.is_dir() {
            return theme;
        }

        // Check for individual files, if they exist copy them across
        {
            let files = vec![
                (src.join("index.hbs"), &mut theme.index),
                (src.join("book.js"), &mut theme.js),
                (src.join("book.css"), &mut theme.css),
                (src.join("favicon.png"), &mut theme.favicon),
                (src.join("highlight.js"), &mut theme.highlight_js),
                (src.join("clipboard.min.js"), &mut theme.clipboard_js),
                (src.join("store.js"), &mut theme.store_js),
                (src.join("highlight.css"), &mut theme.highlight_css),
                (src.join("tomorrow-night.css"), &mut theme.tomorrow_night_css),
                (src.join("ayu-highlight.css"), &mut theme.ayu_highlight_css),
            ];

            for (filename, dest) in files {
                load_file_contents(filename, dest);
            }
        }

        theme
    }
}

fn load_file_contents<P: AsRef<Path>>(filename: P, dest: &mut Vec<u8>) {
    let filename = filename.as_ref();

    if let Ok(mut f) = File::open(filename) {
        dest.clear();
        if let Err(e) = f.read_to_end(dest) {
            warn!("Couldn't load custom file, {}: {}", filename.display(), e);
        }
    }
}<|endoftext|>


<commit_before>use clap::{App, AppSettings, Arg, SubCommand};

pub fn build_cli() -> App<'static, 'static> {
    App::new("gutenberg")
        .version(crate_version!())
        .author(crate_authors!())
        .about(crate_description!())
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(
            Arg::with_name("config")
                .short("c")
                .long("config")
                .help("Path to a config file other than config.toml")
        )
        .subcommands(vec![
            SubCommand::with_name("init")
                .about("Create a new Gutenberg project")
                .arg(
                    Arg::with_name("name")
                        .required(true)
                        .help("Name of the project. Will create a new directory with that name in the current directory")
                ),
            SubCommand::with_name("build")
                .about("Builds the site")
                .args(&[
                    Arg::with_name("base_url")
                        .short("u")
                        .long("base-url")
                        .help("Force the base URL to be that value (default to the one in config.toml)"),
                ]),
            SubCommand::with_name("serve")
                .about("Serve the site. Rebuild and reload on change automatically")
                .args(&[
                    Arg::with_name("interface")
                        .short("i")
                        .long("interface")
                        .default_value("127.0.0.1")
                        .help("Interface to bind on"),
                    Arg::with_name("port")
                        .short("p")
                        .long("port")
                        .default_value("1111")
                        .help("Which port to use"),
                ]),
        ])
}
<commit_msg>Forgot to let base-url take a value >_><commit_after>use clap::{App, AppSettings, Arg, SubCommand};

pub fn build_cli() -> App<'static, 'static> {
    App::new("gutenberg")
        .version(crate_version!())
        .author(crate_authors!())
        .about(crate_description!())
        .setting(AppSettings::SubcommandRequiredElseHelp)
        .arg(
            Arg::with_name("config")
                .short("c")
                .long("config")
                .help("Path to a config file other than config.toml")
        )
        .subcommands(vec![
            SubCommand::with_name("init")
                .about("Create a new Gutenberg project")
                .arg(
                    Arg::with_name("name")
                        .required(true)
                        .help("Name of the project. Will create a new directory with that name in the current directory")
                ),
            SubCommand::with_name("build")
                .about("Builds the site")
                .args(&[
                    Arg::with_name("base_url")
                        .short("u")
                        .long("base-url")
                        .takes_value(true)
                        .help("Force the base URL to be that value (default to the one in config.toml)"),
                ]),
            SubCommand::with_name("serve")
                .about("Serve the site. Rebuild and reload on change automatically")
                .args(&[
                    Arg::with_name("interface")
                        .short("i")
                        .long("interface")
                        .default_value("127.0.0.1")
                        .help("Interface to bind on"),
                    Arg::with_name("port")
                        .short("p")
                        .long("port")
                        .default_value("1111")
                        .help("Which port to use"),
                ]),
        ])
}
<|endoftext|>


<commit_before>use std::io::{self, Write};
use std::sync::Arc;

use term::{self, Terminal};
use term::color::Color;
use term::terminfo::TermInfo;
#[cfg(windows)]
use term::WinConsole;

use terminal::TerminfoTerminal;

pub type StdoutTerminal = Box<Terminal<Output=io::BufWriter<io::Stdout>> + Send>;

/// Gets a terminal that supports color if available.
#[cfg(windows)]
fn term_stdout(color: bool) -> StdoutTerminal {
    let stdout = io::BufWriter::new(io::stdout());
    WinConsole::new(stdout)
        .ok()
        .map(|t| Box::new(t))
        .unwrap_or_else(|| {
            let stdout = io::BufWriter::new(io::stdout());
            Box::new(NoColorTerminal::new(stdout))
        })
}

/// Gets a terminal that supports color if available.
#[cfg(not(windows))]
fn term_stdout(color: bool) -> StdoutTerminal {
    let stdout = io::BufWriter::new(io::stdout());
    if !color || TERMINFO.is_none() {
        Box::new(NoColorTerminal::new(stdout))
    } else {
        let info = TERMINFO.clone().unwrap();
        Box::new(TerminfoTerminal::new_with_terminfo(stdout, info))
    }
}

/// Out controls the actual output of all search results for a particular file
/// to the end user.
///
/// (The difference between Out and Printer is that a Printer works with
/// individual search results where as Out works with search results for each
/// file as a whole. For example, it knows when to print a file separator.)
pub struct Out {
    term: StdoutTerminal,
    printed: bool,
    file_separator: Option<Vec<u8>>,
}

impl Out {
    /// Create a new Out that writes to the wtr given.
    pub fn new(color: bool) -> Out {
        Out {
            term: term_stdout(color),
            printed: false,
            file_separator: None,
        }
    }

    /// If set, the separator is printed between matches from different files.
    /// By default, no separator is printed.
    ///
    /// If sep is empty, then no file separator is printed.
    pub fn file_separator(mut self, sep: Vec<u8>) -> Out {
        self.file_separator = Some(sep);
        self
    }

    /// Write the search results of a single file to the underlying wtr and
    /// flush wtr.
    pub fn write(&mut self, buf: &OutBuffer) {
        if let Some(ref sep) = self.file_separator {
            if self.printed {
                let _ = self.term.write_all(sep);
                let _ = self.term.write_all(b"\n");
            }
        }
        match *buf {
            OutBuffer::Colored(ref tt) => {
                let _ = self.term.write_all(tt.get_ref());
            }
            OutBuffer::Windows(ref w) => {
                w.print_stdout(&mut self.term);
            }
            OutBuffer::NoColor(ref buf) => {
                let _ = self.term.write_all(buf);
            }
        }
        let _ = self.term.flush();
        self.printed = true;
    }
}

/// OutBuffer corresponds to the final output buffer for search results. All
/// search results are written to a buffer and then a buffer is flushed to
/// stdout only after the full search has completed.
#[derive(Clone, Debug)]
pub enum OutBuffer {
    Colored(TerminfoTerminal<Vec<u8>>),
    Windows(WindowsBuffer),
    NoColor(Vec<u8>),
}

#[derive(Clone, Debug)]
pub struct WindowsBuffer {
    buf: Vec<u8>,
    pos: usize,
    colors: Vec<WindowsColor>,
}

#[derive(Clone, Debug)]
pub struct WindowsColor {
    pos: usize,
    opt: WindowsOption,
}

#[derive(Clone, Debug)]
pub enum WindowsOption {
    Foreground(Color),
    Background(Color),
    Reset,
}

lazy_static! {
    static ref TERMINFO: Option<Arc<TermInfo>> = {
        match TermInfo::from_env() {
            Ok(info) => Some(Arc::new(info)),
            Err(err) => {
                debug!("error loading terminfo for coloring: {}", err);
                None
            }
        }
    };
}

impl OutBuffer {
    /// Create a new output buffer.
    ///
    /// When color is true, the buffer will attempt to support coloring.
    pub fn new(color: bool) -> OutBuffer {
        // If we want color, build a TerminfoTerminal and see if the current
        // environment supports coloring. If not, bail with NoColor. To avoid
        // losing our writer (ownership), do this the long way.
        if !color {
            return OutBuffer::NoColor(vec![]);
        }
        if cfg!(windows) {
            return OutBuffer::Windows(WindowsBuffer {
                buf: vec![],
                pos: 0,
                colors: vec![]
            });
        }
        if TERMINFO.is_none() {
            return OutBuffer::NoColor(vec![]);
        }
        let info = TERMINFO.clone().unwrap();
        let tt = TerminfoTerminal::new_with_terminfo(vec![], info);
        if !tt.supports_color() {
            debug!("environment doesn't support coloring");
            return OutBuffer::NoColor(tt.into_inner());
        }
        OutBuffer::Colored(tt)
    }

    /// Clear the give buffer of all search results such that it is reusable
    /// in another search.
    pub fn clear(&mut self) {
        match *self {
            OutBuffer::Colored(ref mut tt) => {
                tt.get_mut().clear();
            }
            OutBuffer::Windows(ref mut win) => {
                win.buf.clear();
                win.colors.clear();
                win.pos = 0;
            }
            OutBuffer::NoColor(ref mut buf) => {
                buf.clear();
            }
        }
    }

    fn map_result<F, G>(
        &mut self,
        mut f: F,
        mut g: G,
    ) -> term::Result<()>
    where F: FnMut(&mut TerminfoTerminal<Vec<u8>>) -> term::Result<()>,
          G: FnMut(&mut WindowsBuffer) -> term::Result<()> {
        match *self {
            OutBuffer::Colored(ref mut w) => f(w),
            OutBuffer::Windows(ref mut w) => g(w),
            OutBuffer::NoColor(_) => Err(term::Error::NotSupported),
        }
    }

    fn map_bool<F, G>(
        &self,
        mut f: F,
        mut g: G,
    ) -> bool
    where F: FnMut(&TerminfoTerminal<Vec<u8>>) -> bool,
          G: FnMut(&WindowsBuffer) -> bool {
        match *self {
            OutBuffer::Colored(ref w) => f(w),
            OutBuffer::Windows(ref w) => g(w),
            OutBuffer::NoColor(_) => false,
        }
    }
}

impl io::Write for OutBuffer {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            OutBuffer::Colored(ref mut w) => w.write(buf),
            OutBuffer::Windows(ref mut w) => w.write(buf),
            OutBuffer::NoColor(ref mut w) => w.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl term::Terminal for OutBuffer {
    type Output = Vec<u8>;

    fn fg(&mut self, fg: term::color::Color) -> term::Result<()> {
        self.map_result(|w| w.fg(fg), |w| w.fg(fg))
    }

    fn bg(&mut self, bg: term::color::Color) -> term::Result<()> {
        self.map_result(|w| w.bg(bg), |w| w.bg(bg))
    }

    fn attr(&mut self, attr: term::Attr) -> term::Result<()> {
        self.map_result(|w| w.attr(attr), |w| w.attr(attr))
    }

    fn supports_attr(&self, attr: term::Attr) -> bool {
        self.map_bool(|w| w.supports_attr(attr), |w| w.supports_attr(attr))
    }

    fn reset(&mut self) -> term::Result<()> {
        self.map_result(|w| w.reset(), |w| w.reset())
    }

    fn supports_reset(&self) -> bool {
        self.map_bool(|w| w.supports_reset(), |w| w.supports_reset())
    }

    fn supports_color(&self) -> bool {
        self.map_bool(|w| w.supports_color(), |w| w.supports_color())
    }

    fn cursor_up(&mut self) -> term::Result<()> {
        self.map_result(|w| w.cursor_up(), |w| w.cursor_up())
    }

    fn delete_line(&mut self) -> term::Result<()> {
        self.map_result(|w| w.delete_line(), |w| w.delete_line())
    }

    fn carriage_return(&mut self) -> term::Result<()> {
        self.map_result(|w| w.carriage_return(), |w| w.carriage_return())
    }

    fn get_ref(&self) -> &Vec<u8> {
        match *self {
            OutBuffer::Colored(ref w) => w.get_ref(),
            OutBuffer::Windows(ref w) => w.get_ref(),
            OutBuffer::NoColor(ref w) => w,
        }
    }

    fn get_mut(&mut self) -> &mut Vec<u8> {
        match *self {
            OutBuffer::Colored(ref mut w) => w.get_mut(),
            OutBuffer::Windows(ref mut w) => w.get_mut(),
            OutBuffer::NoColor(ref mut w) => w,
        }
    }

    fn into_inner(self) -> Vec<u8> {
        match self {
            OutBuffer::Colored(w) => w.into_inner(),
            OutBuffer::Windows(w) => w.into_inner(),
            OutBuffer::NoColor(w) => w,
        }
    }
}

impl WindowsBuffer {
    fn push(&mut self, opt: WindowsOption) {
        let pos = self.pos;
        self.colors.push(WindowsColor { pos: pos, opt: opt });
    }
}

impl WindowsBuffer {
    /// Print the contents to the given terminal.
    pub fn print_stdout(&self, tt: &mut StdoutTerminal) {
        if !tt.supports_color() {
            let _ = tt.write_all(&self.buf);
            let _ = tt.flush();
            return;
        }
        let mut last = 0;
        for col in &self.colors {
            let _ = tt.write_all(&self.buf[last..col.pos]);
            match col.opt {
                WindowsOption::Foreground(c) => {
                    let _ = tt.fg(c);
                }
                WindowsOption::Background(c) => {
                    let _ = tt.bg(c);
                }
                WindowsOption::Reset => {
                    let _ = tt.reset();
                }
            }
            last = col.pos;
        }
        let _ = tt.write_all(&self.buf[last..]);
        let _ = tt.flush();
    }
}

impl io::Write for WindowsBuffer {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = try!(self.buf.write(buf));
        self.pos += n;
        Ok(n)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl term::Terminal for WindowsBuffer {
    type Output = Vec<u8>;

    fn fg(&mut self, fg: term::color::Color) -> term::Result<()> {
        self.push(WindowsOption::Foreground(fg));
        Ok(())
    }

    fn bg(&mut self, bg: term::color::Color) -> term::Result<()> {
        self.push(WindowsOption::Background(bg));
        Ok(())
    }

    fn attr(&mut self, attr: term::Attr) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn supports_attr(&self, attr: term::Attr) -> bool {
        false
    }

    fn reset(&mut self) -> term::Result<()> {
        self.push(WindowsOption::Reset);
        Ok(())
    }

    fn supports_reset(&self) -> bool {
        true
    }

    fn supports_color(&self) -> bool {
        true
    }

    fn cursor_up(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn delete_line(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn carriage_return(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn get_ref(&self) -> &Vec<u8> {
        &self.buf
    }

    fn get_mut(&mut self) -> &mut Vec<u8> {
        &mut self.buf
    }

    fn into_inner(self) -> Vec<u8> {
        self.buf
    }
}

/// NoColorTerminal implements Terminal, but supports no coloring.
///
/// Its useful when an API requires a Terminal, but coloring isn't needed.
pub struct NoColorTerminal<W> {
    wtr: W,
}

impl<W: Send + io::Write> NoColorTerminal<W> {
    /// Wrap the given writer in a Terminal interface.
    pub fn new(wtr: W) -> NoColorTerminal<W> {
        NoColorTerminal {
            wtr: wtr,
        }
    }
}

impl<W: Send + io::Write> io::Write for NoColorTerminal<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.wtr.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.wtr.flush()
    }
}

impl<W: Send + io::Write> term::Terminal for NoColorTerminal<W> {
    type Output = W;

    fn fg(&mut self, fg: term::color::Color) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn bg(&mut self, bg: term::color::Color) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn attr(&mut self, attr: term::Attr) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn supports_attr(&self, attr: term::Attr) -> bool {
        false
    }

    fn reset(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn supports_reset(&self) -> bool {
        false
    }

    fn supports_color(&self) -> bool {
        false
    }

    fn cursor_up(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn delete_line(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn carriage_return(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn get_ref(&self) -> &W {
        &self.wtr
    }

    fn get_mut(&mut self) -> &mut W {
        &mut self.wtr
    }

    fn into_inner(self) -> W {
        self.wtr
    }
}
<commit_msg>fix windows build<commit_after>use std::io::{self, Write};
use std::sync::Arc;

use term::{self, Terminal};
use term::color::Color;
use term::terminfo::TermInfo;
#[cfg(windows)]
use term::WinConsole;

use terminal::TerminfoTerminal;

pub type StdoutTerminal = Box<Terminal<Output=io::Stdout> + Send>;

/// Gets a terminal that supports color if available.
#[cfg(windows)]
fn term_stdout(color: bool) -> StdoutTerminal {
    let stdout = io::stdout();
    WinConsole::new(stdout)
        .ok()
        .map(|t| Box::new(t) as StdoutTerminal)
        .unwrap_or_else(|| {
            let stdout = io::stdout();
            Box::new(NoColorTerminal::new(stdout)) as StdoutTerminal
        })
}

/// Gets a terminal that supports color if available.
#[cfg(not(windows))]
fn term_stdout(color: bool) -> StdoutTerminal {
    let stdout = io::stdout();
    if !color || TERMINFO.is_none() {
        Box::new(NoColorTerminal::new(stdout))
    } else {
        let info = TERMINFO.clone().unwrap();
        Box::new(TerminfoTerminal::new_with_terminfo(stdout, info))
    }
}

/// Out controls the actual output of all search results for a particular file
/// to the end user.
///
/// (The difference between Out and Printer is that a Printer works with
/// individual search results where as Out works with search results for each
/// file as a whole. For example, it knows when to print a file separator.)
pub struct Out {
    term: StdoutTerminal,
    printed: bool,
    file_separator: Option<Vec<u8>>,
}

impl Out {
    /// Create a new Out that writes to the wtr given.
    pub fn new(color: bool) -> Out {
        Out {
            term: term_stdout(color),
            printed: false,
            file_separator: None,
        }
    }

    /// If set, the separator is printed between matches from different files.
    /// By default, no separator is printed.
    ///
    /// If sep is empty, then no file separator is printed.
    pub fn file_separator(mut self, sep: Vec<u8>) -> Out {
        self.file_separator = Some(sep);
        self
    }

    /// Write the search results of a single file to the underlying wtr and
    /// flush wtr.
    pub fn write(&mut self, buf: &OutBuffer) {
        if let Some(ref sep) = self.file_separator {
            if self.printed {
                let _ = self.term.write_all(sep);
                let _ = self.term.write_all(b"\n");
            }
        }
        match *buf {
            OutBuffer::Colored(ref tt) => {
                let _ = self.term.write_all(tt.get_ref());
            }
            OutBuffer::Windows(ref w) => {
                w.print_stdout(&mut self.term);
            }
            OutBuffer::NoColor(ref buf) => {
                let _ = self.term.write_all(buf);
            }
        }
        let _ = self.term.flush();
        self.printed = true;
    }
}

/// OutBuffer corresponds to the final output buffer for search results. All
/// search results are written to a buffer and then a buffer is flushed to
/// stdout only after the full search has completed.
#[derive(Clone, Debug)]
pub enum OutBuffer {
    Colored(TerminfoTerminal<Vec<u8>>),
    Windows(WindowsBuffer),
    NoColor(Vec<u8>),
}

#[derive(Clone, Debug)]
pub struct WindowsBuffer {
    buf: Vec<u8>,
    pos: usize,
    colors: Vec<WindowsColor>,
}

#[derive(Clone, Debug)]
pub struct WindowsColor {
    pos: usize,
    opt: WindowsOption,
}

#[derive(Clone, Debug)]
pub enum WindowsOption {
    Foreground(Color),
    Background(Color),
    Reset,
}

lazy_static! {
    static ref TERMINFO: Option<Arc<TermInfo>> = {
        match TermInfo::from_env() {
            Ok(info) => Some(Arc::new(info)),
            Err(err) => {
                debug!("error loading terminfo for coloring: {}", err);
                None
            }
        }
    };
}

impl OutBuffer {
    /// Create a new output buffer.
    ///
    /// When color is true, the buffer will attempt to support coloring.
    pub fn new(color: bool) -> OutBuffer {
        // If we want color, build a TerminfoTerminal and see if the current
        // environment supports coloring. If not, bail with NoColor. To avoid
        // losing our writer (ownership), do this the long way.
        if !color {
            return OutBuffer::NoColor(vec![]);
        }
        if cfg!(windows) {
            return OutBuffer::Windows(WindowsBuffer {
                buf: vec![],
                pos: 0,
                colors: vec![]
            });
        }
        if TERMINFO.is_none() {
            return OutBuffer::NoColor(vec![]);
        }
        let info = TERMINFO.clone().unwrap();
        let tt = TerminfoTerminal::new_with_terminfo(vec![], info);
        if !tt.supports_color() {
            debug!("environment doesn't support coloring");
            return OutBuffer::NoColor(tt.into_inner());
        }
        OutBuffer::Colored(tt)
    }

    /// Clear the give buffer of all search results such that it is reusable
    /// in another search.
    pub fn clear(&mut self) {
        match *self {
            OutBuffer::Colored(ref mut tt) => {
                tt.get_mut().clear();
            }
            OutBuffer::Windows(ref mut win) => {
                win.buf.clear();
                win.colors.clear();
                win.pos = 0;
            }
            OutBuffer::NoColor(ref mut buf) => {
                buf.clear();
            }
        }
    }

    fn map_result<F, G>(
        &mut self,
        mut f: F,
        mut g: G,
    ) -> term::Result<()>
    where F: FnMut(&mut TerminfoTerminal<Vec<u8>>) -> term::Result<()>,
          G: FnMut(&mut WindowsBuffer) -> term::Result<()> {
        match *self {
            OutBuffer::Colored(ref mut w) => f(w),
            OutBuffer::Windows(ref mut w) => g(w),
            OutBuffer::NoColor(_) => Err(term::Error::NotSupported),
        }
    }

    fn map_bool<F, G>(
        &self,
        mut f: F,
        mut g: G,
    ) -> bool
    where F: FnMut(&TerminfoTerminal<Vec<u8>>) -> bool,
          G: FnMut(&WindowsBuffer) -> bool {
        match *self {
            OutBuffer::Colored(ref w) => f(w),
            OutBuffer::Windows(ref w) => g(w),
            OutBuffer::NoColor(_) => false,
        }
    }
}

impl io::Write for OutBuffer {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        match *self {
            OutBuffer::Colored(ref mut w) => w.write(buf),
            OutBuffer::Windows(ref mut w) => w.write(buf),
            OutBuffer::NoColor(ref mut w) => w.write(buf),
        }
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl term::Terminal for OutBuffer {
    type Output = Vec<u8>;

    fn fg(&mut self, fg: term::color::Color) -> term::Result<()> {
        self.map_result(|w| w.fg(fg), |w| w.fg(fg))
    }

    fn bg(&mut self, bg: term::color::Color) -> term::Result<()> {
        self.map_result(|w| w.bg(bg), |w| w.bg(bg))
    }

    fn attr(&mut self, attr: term::Attr) -> term::Result<()> {
        self.map_result(|w| w.attr(attr), |w| w.attr(attr))
    }

    fn supports_attr(&self, attr: term::Attr) -> bool {
        self.map_bool(|w| w.supports_attr(attr), |w| w.supports_attr(attr))
    }

    fn reset(&mut self) -> term::Result<()> {
        self.map_result(|w| w.reset(), |w| w.reset())
    }

    fn supports_reset(&self) -> bool {
        self.map_bool(|w| w.supports_reset(), |w| w.supports_reset())
    }

    fn supports_color(&self) -> bool {
        self.map_bool(|w| w.supports_color(), |w| w.supports_color())
    }

    fn cursor_up(&mut self) -> term::Result<()> {
        self.map_result(|w| w.cursor_up(), |w| w.cursor_up())
    }

    fn delete_line(&mut self) -> term::Result<()> {
        self.map_result(|w| w.delete_line(), |w| w.delete_line())
    }

    fn carriage_return(&mut self) -> term::Result<()> {
        self.map_result(|w| w.carriage_return(), |w| w.carriage_return())
    }

    fn get_ref(&self) -> &Vec<u8> {
        match *self {
            OutBuffer::Colored(ref w) => w.get_ref(),
            OutBuffer::Windows(ref w) => w.get_ref(),
            OutBuffer::NoColor(ref w) => w,
        }
    }

    fn get_mut(&mut self) -> &mut Vec<u8> {
        match *self {
            OutBuffer::Colored(ref mut w) => w.get_mut(),
            OutBuffer::Windows(ref mut w) => w.get_mut(),
            OutBuffer::NoColor(ref mut w) => w,
        }
    }

    fn into_inner(self) -> Vec<u8> {
        match self {
            OutBuffer::Colored(w) => w.into_inner(),
            OutBuffer::Windows(w) => w.into_inner(),
            OutBuffer::NoColor(w) => w,
        }
    }
}

impl WindowsBuffer {
    fn push(&mut self, opt: WindowsOption) {
        let pos = self.pos;
        self.colors.push(WindowsColor { pos: pos, opt: opt });
    }
}

impl WindowsBuffer {
    /// Print the contents to the given terminal.
    pub fn print_stdout(&self, tt: &mut StdoutTerminal) {
        if !tt.supports_color() {
            let _ = tt.write_all(&self.buf);
            let _ = tt.flush();
            return;
        }
        let mut last = 0;
        for col in &self.colors {
            let _ = tt.write_all(&self.buf[last..col.pos]);
            match col.opt {
                WindowsOption::Foreground(c) => {
                    let _ = tt.fg(c);
                }
                WindowsOption::Background(c) => {
                    let _ = tt.bg(c);
                }
                WindowsOption::Reset => {
                    let _ = tt.reset();
                }
            }
            last = col.pos;
        }
        let _ = tt.write_all(&self.buf[last..]);
        let _ = tt.flush();
    }
}

impl io::Write for WindowsBuffer {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        let n = try!(self.buf.write(buf));
        self.pos += n;
        Ok(n)
    }

    fn flush(&mut self) -> io::Result<()> {
        Ok(())
    }
}

impl term::Terminal for WindowsBuffer {
    type Output = Vec<u8>;

    fn fg(&mut self, fg: term::color::Color) -> term::Result<()> {
        self.push(WindowsOption::Foreground(fg));
        Ok(())
    }

    fn bg(&mut self, bg: term::color::Color) -> term::Result<()> {
        self.push(WindowsOption::Background(bg));
        Ok(())
    }

    fn attr(&mut self, attr: term::Attr) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn supports_attr(&self, attr: term::Attr) -> bool {
        false
    }

    fn reset(&mut self) -> term::Result<()> {
        self.push(WindowsOption::Reset);
        Ok(())
    }

    fn supports_reset(&self) -> bool {
        true
    }

    fn supports_color(&self) -> bool {
        true
    }

    fn cursor_up(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn delete_line(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn carriage_return(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn get_ref(&self) -> &Vec<u8> {
        &self.buf
    }

    fn get_mut(&mut self) -> &mut Vec<u8> {
        &mut self.buf
    }

    fn into_inner(self) -> Vec<u8> {
        self.buf
    }
}

/// NoColorTerminal implements Terminal, but supports no coloring.
///
/// Its useful when an API requires a Terminal, but coloring isn't needed.
pub struct NoColorTerminal<W> {
    wtr: W,
}

impl<W: Send + io::Write> NoColorTerminal<W> {
    /// Wrap the given writer in a Terminal interface.
    pub fn new(wtr: W) -> NoColorTerminal<W> {
        NoColorTerminal {
            wtr: wtr,
        }
    }
}

impl<W: Send + io::Write> io::Write for NoColorTerminal<W> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.wtr.write(buf)
    }

    fn flush(&mut self) -> io::Result<()> {
        self.wtr.flush()
    }
}

impl<W: Send + io::Write> term::Terminal for NoColorTerminal<W> {
    type Output = W;

    fn fg(&mut self, fg: term::color::Color) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn bg(&mut self, bg: term::color::Color) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn attr(&mut self, attr: term::Attr) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn supports_attr(&self, attr: term::Attr) -> bool {
        false
    }

    fn reset(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn supports_reset(&self) -> bool {
        false
    }

    fn supports_color(&self) -> bool {
        false
    }

    fn cursor_up(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn delete_line(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn carriage_return(&mut self) -> term::Result<()> {
        Err(term::Error::NotSupported)
    }

    fn get_ref(&self) -> &W {
        &self.wtr
    }

    fn get_mut(&mut self) -> &mut W {
        &mut self.wtr
    }

    fn into_inner(self) -> W {
        self.wtr
    }
}
<|endoftext|>


<commit_before>use super::super::{Y, X, Coord, Grid};
use grid_loop::{Edge, GridLoop, GridLoopField};
use super::*;

pub struct Field<'a> {
    grid_loop: GridLoop,
    clue: Grid<Clue>,
    dic: &'a Dictionary,
}
impl<'a> Field<'a> {
    pub fn new(clue: &Grid<Clue>, dic: &'a Dictionary) -> Field<'a> {
        let grid_loop = GridLoop::new(clue.height(), clue.width());

        Field {
            grid_loop: grid_loop,
            clue: clue.clone(),
            dic: dic,
        }
    }
    pub fn height(&self) -> i32 {
        self.clue.height()
    }
    pub fn width(&self) -> i32 {
        self.clue.width()
    }
    pub fn inconsistent(&self) -> bool {
        self.grid_loop.inconsistent()
    }
    pub fn set_inconsistent(&mut self) {
        self.grid_loop.set_inconsistent()
    }
    pub fn fully_solved(&self) -> bool {
        self.grid_loop.fully_solved()
    }
    pub fn check_all_cell(&mut self) {
        let height = self.height();
        let width = self.width();
        let mut handle = GridLoop::get_handle(self);
        for y in 0..height {
            for x in 0..width {
                let clue = handle.get_clue((Y(y), X(x)));
                if clue != NO_CLUE {
                    GridLoop::check(&mut *handle, (Y(y * 2 + 1), X(x * 2 + 1)));
                }
            }
        }
    }
    pub fn get_clue(&self, cd: Coord) -> Clue {
        self.clue[cd]
    }
    pub fn add_clue(&mut self, cd: Coord, clue: Clue) {
        if self.clue[cd] != NO_CLUE {
            if self.clue[cd] != clue {
                self.grid_loop.set_inconsistent();
            }
        } else {
            self.clue[cd] = clue;
            GridLoop::check(self, cd);
        }
    }
    pub fn get_edge(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge(cd)
    }
    pub fn get_edge_safe(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge_safe(cd)
    }

    fn inspect_technique(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 1 && x % 2 == 1 {
            let clue = self.clue[(Y(y / 2), X(x / 2))];
            if clue == Clue(3) {
                let neighbor = [
                    (Y(1), X(0)),
                    (Y(0), X(1)),
                    (Y(-1), X(0)),
                    (Y(0), X(-1)),
                ];

                // adjacent 3
                for d in 0..4 {
                    let (Y(dy), X(dx)) = neighbor[d];
                    let cell2 = (Y(y / 2 + dy), X(x / 2 + dx));
                    if self.clue.is_valid_coord(cell2) && self.clue[cell2] == Clue(3) {
                        // Deriberately ignoring the possible small loop encircling the two 3's
                        GridLoop::decide_edge(self, (Y(y - dy), X(x - dx)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + 3 * dy), X(x + 3 * dx)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + dy + 2 * dx), X(x + dx + 2 * dy)), Edge::Blank);
                        GridLoop::decide_edge(self, (Y(y + dy - 2 * dx), X(x + dx - 2 * dy)), Edge::Blank);
                    }
                }

                // diagonal 3
                for d in 0..4 {
                    let (Y(dy1), X(dx1)) = neighbor[d];
                    let (Y(dy2), X(dx2)) = neighbor[(d + 1) % 4];
                    let cell2 = (Y(y / 2 + dy1 + dy2), X(x / 2 + dx1 + dx2));
                    if self.clue.is_valid_coord(cell2) && self.clue[cell2] == Clue(3) {
                        GridLoop::decide_edge(self, (Y(y - dy1), X(x - dx1)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y - dy2), X(x - dx2)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + 2 * dy1 + 3 * dy2), X(x + 2 * dx1 + 3 * dx2)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + 3 * dy1 + 2 * dy2), X(x + 3 * dx1 + 2 * dx2)), Edge::Line);
                    }
                }
            }
        }
    }
}
impl<'a> GridLoopField for Field<'a> {
    fn grid_loop(&mut self) -> &mut GridLoop {
        &mut self.grid_loop
    }
    fn check_neighborhood(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 1 {
            GridLoop::check(self, (Y(y - 1), X(x)));
            GridLoop::check(self, (Y(y + 1), X(x)));

            GridLoop::check(self, (Y(y), X(x - 1)));
            GridLoop::check(self, (Y(y), X(x + 1)));
            GridLoop::check(self, (Y(y - 2), X(x - 1)));
            GridLoop::check(self, (Y(y - 2), X(x + 1)));
            GridLoop::check(self, (Y(y + 2), X(x - 1)));
            GridLoop::check(self, (Y(y + 2), X(x + 1)));
        } else {
            GridLoop::check(self, (Y(y), X(x - 1)));
            GridLoop::check(self, (Y(y), X(x + 1)));

            GridLoop::check(self, (Y(y - 1), X(x)));
            GridLoop::check(self, (Y(y + 1), X(x)));
            GridLoop::check(self, (Y(y - 1), X(x - 2)));
            GridLoop::check(self, (Y(y + 1), X(x - 2)));
            GridLoop::check(self, (Y(y - 1), X(x + 2)));
            GridLoop::check(self, (Y(y + 1), X(x + 2)));
        }
    }
    fn inspect(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 1 && x % 2 == 1 {
            let clue = self.clue[(Y(y / 2), X(x / 2))];
            if clue == NO_CLUE { return; }

            let mut neighbors_code = 0;
            let mut pow3 = 1;
            for i in 0..DICTIONARY_NEIGHBOR_SIZE {
                let (Y(dy), X(dx)) = DICTIONARY_EDGE_OFFSET[i];
                neighbors_code += pow3 * match self.grid_loop.get_edge_safe((Y(y + dy), X(x + dx))) {
                    Edge::Undecided => 0,
                    Edge::Line => 1,
                    Edge::Blank => 2,
                };
                pow3 *= 3;
            }

            let res = self.dic.consult_raw(clue, neighbors_code);
            if res == DICTIONARY_INCONSISTENT {
                self.grid_loop.set_inconsistent();
                return;
            }
            for i in 0..DICTIONARY_NEIGHBOR_SIZE {
                let e = (res >> (2 * i)) & 3;
                if e == 1 {
                    let (Y(dy), X(dx)) = DICTIONARY_EDGE_OFFSET[i];
                    GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Line);
                } else if e == 2 {
                    let (Y(dy), X(dx)) = DICTIONARY_EDGE_OFFSET[i];
                    GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Blank);
                }
            }

            self.inspect_technique((Y(y), X(x)));
        }
    }
}

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

    fn run_problem_test(dic: &Dictionary, input: &[&str], fully_solved: bool) {
        let height = (input.len() / 2) as i32;
        let width = (input[0].len() / 2) as i32;

        let mut clue = Grid::new(height, width, NO_CLUE);
        for y in 0..height {
            let mut row_iter = input[(y * 2 + 1) as usize].chars();

            for x in 0..width {
                row_iter.next();
                let c = row_iter.next().unwrap();
                if '0' <= c && c <= '3' {
                    clue[(Y(y), X(x))] = Clue(((c as u8) - ('0' as u8)) as i32);
                }
            }
        }

        let mut field = Field::new(&clue, dic);
        field.check_all_cell();

        assert_eq!(field.inconsistent(), false);
        assert_eq!(field.fully_solved(), fully_solved);

        for y in 0..(input.len() as i32) {
            let mut row_iter = input[y as usize].chars();

            for x in 0..(input[0].len() as i32) {
                let ch = row_iter.next().unwrap();

                if !field.grid_loop().is_edge((Y(y), X(x))) {
                    continue;
                }

                let expected_edge = match ch {
                    '|' | '-' => Edge::Line,
                    'x' => Edge::Blank,
                    _ => Edge::Undecided,
                };

                assert_eq!(field.get_edge((Y(y), X(x))), expected_edge, "Comparing at y={}, x={}", y, x);
            }
        }
    }

    #[test]
    fn test_problem() {
        let dic = Dictionary::complete();

        run_problem_test(&dic, &[
            "+x+-+-+ +",
            "x | x    ",
            "+x+-+x+ +",
            "x0x3|    ",
            "+x+-+x+ +",
            "x | x    ",
            "+x+-+-+ +",
        ], false);
        run_problem_test(&dic, &[
            "+x+-+x+x+",
            "x |3| x x",
            "+x+x+-+-+",
            "x | x x3|",
            "+x+-+x+-+",
            "x0x2| | x",
            "+x+x+-+x+",
        ], true);
        run_problem_test(&dic, &[
            "+-+-+-+-+",
            "|3x x x |",
            "+-+ +-+x+",
            "x     | |",
            "+x+ +x+-+",
            "x x x0x1x",
            "+x+x+x+x+",
        ], false);
        run_problem_test(&dic, &[
            "+ +-+-+x+",
            " 2  x2| x",
            "+ +x+x+-+",
            "| x x0x |",
            "+ + +x+ +",
            "         ",
            "+ + + + +",
        ], false);
        run_problem_test(&dic, &[
            "+ +-+ +x+",
            "   3   1x",
            "+x+-+x+ +",
            "   3  |  ",
            "+ +-+ + +",
            "         ",
            "+ + + + +",
        ], false);
        run_problem_test(&dic, &[
            "+-+-+ + +",
            "|2x      ",
            "+x+-+ + +",
            "| |3     ",
            "+ + + + +",
            "     3| x",
            "+ + +-+x+",
        ], false);
    }
}
<commit_msg>Slitherlink: apply inspect_technique only when a clue is added or check_all_cell is invoked<commit_after>use super::super::{Y, X, Coord, Grid};
use grid_loop::{Edge, GridLoop, GridLoopField};
use super::*;

pub struct Field<'a> {
    grid_loop: GridLoop,
    clue: Grid<Clue>,
    dic: &'a Dictionary,
}
impl<'a> Field<'a> {
    pub fn new(clue: &Grid<Clue>, dic: &'a Dictionary) -> Field<'a> {
        let grid_loop = GridLoop::new(clue.height(), clue.width());

        Field {
            grid_loop: grid_loop,
            clue: clue.clone(),
            dic: dic,
        }
    }
    pub fn height(&self) -> i32 {
        self.clue.height()
    }
    pub fn width(&self) -> i32 {
        self.clue.width()
    }
    pub fn inconsistent(&self) -> bool {
        self.grid_loop.inconsistent()
    }
    pub fn set_inconsistent(&mut self) {
        self.grid_loop.set_inconsistent()
    }
    pub fn fully_solved(&self) -> bool {
        self.grid_loop.fully_solved()
    }
    pub fn check_all_cell(&mut self) {
        let height = self.height();
        let width = self.width();
        let mut handle = GridLoop::get_handle(self);
        for y in 0..height {
            for x in 0..width {
                let clue = handle.get_clue((Y(y), X(x)));
                if clue != NO_CLUE {
                    handle.inspect_technique((Y(y * 2 + 1), X(x * 2 + 1)));
                    GridLoop::check(&mut *handle, (Y(y * 2 + 1), X(x * 2 + 1)));
                }
            }
        }
    }
    pub fn get_clue(&self, cd: Coord) -> Clue {
        self.clue[cd]
    }
    pub fn add_clue(&mut self, cd: Coord, clue: Clue) {
        if self.clue[cd] != NO_CLUE {
            if self.clue[cd] != clue {
                self.grid_loop.set_inconsistent();
            }
        } else {
            self.clue[cd] = clue;

            let mut handle = GridLoop::get_handle(self);
            handle.inspect_technique(cd);
            GridLoop::check(&mut *handle, cd);
        }
    }
    pub fn get_edge(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge(cd)
    }
    pub fn get_edge_safe(&self, cd: Coord) -> Edge {
        self.grid_loop.get_edge_safe(cd)
    }

    fn inspect_technique(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 1 && x % 2 == 1 {
            let clue = self.clue[(Y(y / 2), X(x / 2))];
            if clue == Clue(3) {
                let neighbor = [
                    (Y(1), X(0)),
                    (Y(0), X(1)),
                    (Y(-1), X(0)),
                    (Y(0), X(-1)),
                ];

                // adjacent 3
                for d in 0..4 {
                    let (Y(dy), X(dx)) = neighbor[d];
                    let cell2 = (Y(y / 2 + dy), X(x / 2 + dx));
                    if self.clue.is_valid_coord(cell2) && self.clue[cell2] == Clue(3) {
                        // Deriberately ignoring the possible small loop encircling the two 3's
                        GridLoop::decide_edge(self, (Y(y - dy), X(x - dx)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + 3 * dy), X(x + 3 * dx)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + dy + 2 * dx), X(x + dx + 2 * dy)), Edge::Blank);
                        GridLoop::decide_edge(self, (Y(y + dy - 2 * dx), X(x + dx - 2 * dy)), Edge::Blank);
                    }
                }

                // diagonal 3
                for d in 0..4 {
                    let (Y(dy1), X(dx1)) = neighbor[d];
                    let (Y(dy2), X(dx2)) = neighbor[(d + 1) % 4];
                    let cell2 = (Y(y / 2 + dy1 + dy2), X(x / 2 + dx1 + dx2));
                    if self.clue.is_valid_coord(cell2) && self.clue[cell2] == Clue(3) {
                        GridLoop::decide_edge(self, (Y(y - dy1), X(x - dx1)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y - dy2), X(x - dx2)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + 2 * dy1 + 3 * dy2), X(x + 2 * dx1 + 3 * dx2)), Edge::Line);
                        GridLoop::decide_edge(self, (Y(y + 3 * dy1 + 2 * dy2), X(x + 3 * dx1 + 2 * dx2)), Edge::Line);
                    }
                }
            }
        }
    }
}
impl<'a> GridLoopField for Field<'a> {
    fn grid_loop(&mut self) -> &mut GridLoop {
        &mut self.grid_loop
    }
    fn check_neighborhood(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 1 {
            GridLoop::check(self, (Y(y - 1), X(x)));
            GridLoop::check(self, (Y(y + 1), X(x)));

            GridLoop::check(self, (Y(y), X(x - 1)));
            GridLoop::check(self, (Y(y), X(x + 1)));
            GridLoop::check(self, (Y(y - 2), X(x - 1)));
            GridLoop::check(self, (Y(y - 2), X(x + 1)));
            GridLoop::check(self, (Y(y + 2), X(x - 1)));
            GridLoop::check(self, (Y(y + 2), X(x + 1)));
        } else {
            GridLoop::check(self, (Y(y), X(x - 1)));
            GridLoop::check(self, (Y(y), X(x + 1)));

            GridLoop::check(self, (Y(y - 1), X(x)));
            GridLoop::check(self, (Y(y + 1), X(x)));
            GridLoop::check(self, (Y(y - 1), X(x - 2)));
            GridLoop::check(self, (Y(y + 1), X(x - 2)));
            GridLoop::check(self, (Y(y - 1), X(x + 2)));
            GridLoop::check(self, (Y(y + 1), X(x + 2)));
        }
    }
    fn inspect(&mut self, (Y(y), X(x)): Coord) {
        if y % 2 == 1 && x % 2 == 1 {
            let clue = self.clue[(Y(y / 2), X(x / 2))];
            if clue == NO_CLUE { return; }

            let mut neighbors_code = 0;
            let mut pow3 = 1;
            for i in 0..DICTIONARY_NEIGHBOR_SIZE {
                let (Y(dy), X(dx)) = DICTIONARY_EDGE_OFFSET[i];
                neighbors_code += pow3 * match self.grid_loop.get_edge_safe((Y(y + dy), X(x + dx))) {
                    Edge::Undecided => 0,
                    Edge::Line => 1,
                    Edge::Blank => 2,
                };
                pow3 *= 3;
            }

            let res = self.dic.consult_raw(clue, neighbors_code);
            if res == DICTIONARY_INCONSISTENT {
                self.grid_loop.set_inconsistent();
                return;
            }
            for i in 0..DICTIONARY_NEIGHBOR_SIZE {
                let e = (res >> (2 * i)) & 3;
                if e == 1 {
                    let (Y(dy), X(dx)) = DICTIONARY_EDGE_OFFSET[i];
                    GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Line);
                } else if e == 2 {
                    let (Y(dy), X(dx)) = DICTIONARY_EDGE_OFFSET[i];
                    GridLoop::decide_edge(self, (Y(y + dy), X(x + dx)), Edge::Blank);
                }
            }
        }
    }
}

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

    fn run_problem_test(dic: &Dictionary, input: &[&str], fully_solved: bool) {
        let height = (input.len() / 2) as i32;
        let width = (input[0].len() / 2) as i32;

        let mut clue = Grid::new(height, width, NO_CLUE);
        for y in 0..height {
            let mut row_iter = input[(y * 2 + 1) as usize].chars();

            for x in 0..width {
                row_iter.next();
                let c = row_iter.next().unwrap();
                if '0' <= c && c <= '3' {
                    clue[(Y(y), X(x))] = Clue(((c as u8) - ('0' as u8)) as i32);
                }
            }
        }

        let mut field = Field::new(&clue, dic);
        field.check_all_cell();

        assert_eq!(field.inconsistent(), false);
        assert_eq!(field.fully_solved(), fully_solved);

        for y in 0..(input.len() as i32) {
            let mut row_iter = input[y as usize].chars();

            for x in 0..(input[0].len() as i32) {
                let ch = row_iter.next().unwrap();

                if !field.grid_loop().is_edge((Y(y), X(x))) {
                    continue;
                }

                let expected_edge = match ch {
                    '|' | '-' => Edge::Line,
                    'x' => Edge::Blank,
                    _ => Edge::Undecided,
                };

                assert_eq!(field.get_edge((Y(y), X(x))), expected_edge, "Comparing at y={}, x={}", y, x);
            }
        }
    }

    #[test]
    fn test_problem() {
        let dic = Dictionary::complete();

        run_problem_test(&dic, &[
            "+x+-+-+ +",
            "x | x    ",
            "+x+-+x+ +",
            "x0x3|    ",
            "+x+-+x+ +",
            "x | x    ",
            "+x+-+-+ +",
        ], false);
        run_problem_test(&dic, &[
            "+x+-+x+x+",
            "x |3| x x",
            "+x+x+-+-+",
            "x | x x3|",
            "+x+-+x+-+",
            "x0x2| | x",
            "+x+x+-+x+",
        ], true);
        run_problem_test(&dic, &[
            "+-+-+-+-+",
            "|3x x x |",
            "+-+ +-+x+",
            "x     | |",
            "+x+ +x+-+",
            "x x x0x1x",
            "+x+x+x+x+",
        ], false);
        run_problem_test(&dic, &[
            "+ +-+-+x+",
            " 2  x2| x",
            "+ +x+x+-+",
            "| x x0x |",
            "+ + +x+ +",
            "         ",
            "+ + + + +",
        ], false);
        run_problem_test(&dic, &[
            "+ +-+ +x+",
            "   3   1x",
            "+x+-+x+ +",
            "   3  |  ",
            "+ +-+ + +",
            "         ",
            "+ + + + +",
        ], false);
        run_problem_test(&dic, &[
            "+-+-+ + +",
            "|2x      ",
            "+x+-+ + +",
            "| |3     ",
            "+ + + + +",
            "     3| x",
            "+ + +-+x+",
        ], false);
    }
}
<|endoftext|>


<commit_before>pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

pub fn tokenize(input: &str) -> Tokenizer {
    Tokenizer {text: String::from_str(input)}
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

fn is_numberlike(c: char) -> bool {
    match c {
        c if c.is_numeric() => true,
        '.' | '-'           => true,
        _                   => false,
    }
}

struct Tokenizer {
    text: String
}

impl Iterator<Token> for Tokenizer {
    fn next(&mut self) -> Option<Token> {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return None
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if is_numberlike(c) => {
                let number = c.to_string() + self.read_until_whitespace().as_slice();
                let x: f64 = number.parse().unwrap();
                Some(Token::Number(x))
            }
            c => {
                let word = c.to_string() + self.read_until_whitespace().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokenizer {
    fn pop_char(&mut self) -> Option<char> {
        if self.text.is_empty() {
            None
        } else {
            self.text.remove(0)
        }
    }

    fn read_until_whitespace(&mut self) -> String {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return "".to_string()
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.read_until_whitespace().as_slice(),
        }
    }
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "world"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_1number() {
    let test_str = "4.2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "4.2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2numbers() {
    let test_str = ".38 -2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "0.38"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "-2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_point() {
    let test_str = "POINT (10 -20)";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "POINT"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::ParenOpen => (),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "10"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "-20"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::ParenClose => (),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}
<commit_msg>Add test for empty string<commit_after>pub enum Token {
    Comma,
    Number(f64),
    ParenClose,
    ParenOpen,
    Word(String),
}

pub fn tokenize(input: &str) -> Tokenizer {
    Tokenizer {text: String::from_str(input)}
}

fn is_whitespace(c: char) -> bool {
    match c {
        '\n' | '\r' | '\t' | ' ' => true,
        _                        => false,
    }
}

fn is_numberlike(c: char) -> bool {
    match c {
        c if c.is_numeric() => true,
        '.' | '-'           => true,
        _                   => false,
    }
}

struct Tokenizer {
    text: String
}

impl Iterator<Token> for Tokenizer {
    fn next(&mut self) -> Option<Token> {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return None
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' => None,
            '(' => Some(Token::ParenOpen),
            ')' => Some(Token::ParenClose),
            ',' => Some(Token::Comma),
            c if is_whitespace(c) => self.next(),
            c if is_numberlike(c) => {
                let number = c.to_string() + self.read_until_whitespace().as_slice();
                let x: f64 = number.parse().unwrap();
                Some(Token::Number(x))
            }
            c => {
                let word = c.to_string() + self.read_until_whitespace().as_slice();
                Some(Token::Word(word))
            }
        }
    }
}

impl Tokenizer {
    fn pop_char(&mut self) -> Option<char> {
        if self.text.is_empty() {
            None
        } else {
            self.text.remove(0)
        }
    }

    fn read_until_whitespace(&mut self) -> String {
        let popped_char = self.pop_char();
        if popped_char.is_none() {
            return "".to_string()
        }
        let next_char = popped_char.unwrap();

        match next_char {
            '\0' | '(' | ')' | ',' => {
                self.text.insert(0, next_char);
                "".to_string()
            }
            c if is_whitespace(c) => "".to_string(),
            _ => next_char.to_string() + self.read_until_whitespace().as_slice(),
        }
    }
}

#[test]
fn test_tokenizer_empty() {
    let test_str = "";
    let mut tokens = tokenize(test_str);
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_1word() {
    let test_str = "hello";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2words() {
    let test_str = "hello world";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "hello"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "world"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_1number() {
    let test_str = "4.2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "4.2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_2numbers() {
    let test_str = ".38 -2";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "0.38"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "-2"),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}

#[test]
fn test_tokenizer_point() {
    let test_str = "POINT (10 -20)";
    let mut tokens = tokenize(test_str);
    match tokens.next().unwrap() {
        Token::Word(n) => assert_eq!(n, "POINT"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::ParenOpen => (),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "10"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::Number(n) => assert_eq!(n.to_string(), "-20"),
        _ => panic!("fail")
    }
    match tokens.next().unwrap() {
        Token::ParenClose => (),
        _ => panic!("fail")
    }
    assert!(tokens.next().is_none());
}
<|endoftext|>


<commit_before>use core::num::Wrapping;
use core::ops::Mul;
use {CheckedMul, One};

/// Binary operator for raising a value to a power.
pub trait Pow<RHS> {
    /// The result after applying the operator.
    type Output;

    /// Returns `self` to the power `rhs`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::Pow;
    /// assert_eq!(Pow::pow(10u32, 2u32), 100);
    /// ```
    fn pow(self, rhs: RHS) -> Self::Output;
}

macro_rules! pow_impl {
    ($t:ty) => {
        pow_impl!($t, u8);
        pow_impl!($t, usize);

        // FIXME: these should be possible
        // pow_impl!($t, u16);
        // pow_impl!($t, u32);
        // pow_impl!($t, u64);
    };
    ($t:ty, $rhs:ty) => {
        pow_impl!($t, $rhs, usize, pow);
    };
    ($t:ty, $rhs:ty, $desired_rhs:ty, $method:expr) => {
        impl Pow<$rhs> for $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: $rhs) -> $t {
                ($method)(self, <$desired_rhs>::from(rhs))
            }
        }

        impl<'a> Pow<&'a $rhs> for $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> $t {
                ($method)(self, <$desired_rhs>::from(*rhs))
            }
        }

        impl<'a> Pow<$rhs> for &'a $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: $rhs) -> $t {
                ($method)(*self, <$desired_rhs>::from(rhs))
            }
        }

        impl<'a, 'b> Pow<&'a $rhs> for &'b $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> $t {
                ($method)(*self, <$desired_rhs>::from(*rhs))
            }
        }
    };
}

pow_impl!(u8, u8, u32, u8::pow);
pow_impl!(u8, u16, u32, u8::pow);
pow_impl!(u8, u32, u32, u8::pow);
pow_impl!(u8, usize);
pow_impl!(i8, u8, u32, i8::pow);
pow_impl!(i8, u16, u32, i8::pow);
pow_impl!(i8, u32, u32, i8::pow);
pow_impl!(i8, usize);
pow_impl!(u16, u8, u32, u16::pow);
pow_impl!(u16, u16, u32, u16::pow);
pow_impl!(u16, u32, u32, u16::pow);
pow_impl!(u16, usize);
pow_impl!(i16, u8, u32, i16::pow);
pow_impl!(i16, u16, u32, i16::pow);
pow_impl!(i16, u32, u32, i16::pow);
pow_impl!(i16, usize);
pow_impl!(u32, u8, u32, u32::pow);
pow_impl!(u32, u16, u32, u32::pow);
pow_impl!(u32, u32, u32, u32::pow);
pow_impl!(u32, usize);
pow_impl!(i32, u8, u32, i32::pow);
pow_impl!(i32, u16, u32, i32::pow);
pow_impl!(i32, u32, u32, i32::pow);
pow_impl!(i32, usize);
pow_impl!(u64, u8, u32, u64::pow);
pow_impl!(u64, u16, u32, u64::pow);
pow_impl!(u64, u32, u32, u64::pow);
pow_impl!(u64, usize);
pow_impl!(i64, u8, u32, i64::pow);
pow_impl!(i64, u16, u32, i64::pow);
pow_impl!(i64, u32, u32, i64::pow);
pow_impl!(i64, usize);

#[cfg(has_i128)]
pow_impl!(u128, u8, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, u16, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, u32, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, usize);

#[cfg(has_i128)]
pow_impl!(i128, u8, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, u16, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, u32, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, usize);

pow_impl!(usize, u8, u32, usize::pow);
pow_impl!(usize, u16, u32, usize::pow);
pow_impl!(usize, u32, u32, usize::pow);
pow_impl!(usize, usize);
pow_impl!(isize, u8, u32, isize::pow);
pow_impl!(isize, u16, u32, isize::pow);
pow_impl!(isize, u32, u32, isize::pow);
pow_impl!(isize, usize);
pow_impl!(Wrapping<u8>);
pow_impl!(Wrapping<i8>);
pow_impl!(Wrapping<u16>);
pow_impl!(Wrapping<i16>);
pow_impl!(Wrapping<u32>);
pow_impl!(Wrapping<i32>);
pow_impl!(Wrapping<u64>);
pow_impl!(Wrapping<i64>);
#[cfg(has_i128)]
pow_impl!(Wrapping<u128>);
#[cfg(has_i128)]
pow_impl!(Wrapping<i128>);
pow_impl!(Wrapping<usize>);
pow_impl!(Wrapping<isize>);

// FIXME: these should be possible
// pow_impl!(u8, u64);
// pow_impl!(i16, u64);
// pow_impl!(i8, u64);
// pow_impl!(u16, u64);
// pow_impl!(u32, u64);
// pow_impl!(i32, u64);
// pow_impl!(u64, u64);
// pow_impl!(i64, u64);
// pow_impl!(usize, u64);
// pow_impl!(isize, u64);

#[cfg(feature = "std")]
mod float_impls {
    use super::Pow;

    pow_impl!(f32, i8, i32, f32::powi);
    pow_impl!(f32, u8, i32, f32::powi);
    pow_impl!(f32, i16, i32, f32::powi);
    pow_impl!(f32, u16, i32, f32::powi);
    pow_impl!(f32, i32, i32, f32::powi);
    pow_impl!(f64, i8, i32, f64::powi);
    pow_impl!(f64, u8, i32, f64::powi);
    pow_impl!(f64, i16, i32, f64::powi);
    pow_impl!(f64, u16, i32, f64::powi);
    pow_impl!(f64, i32, i32, f64::powi);
    pow_impl!(f32, f32, f32, f32::powf);
    pow_impl!(f64, f32, f64, f64::powf);
    pow_impl!(f64, f64, f64, f64::powf);
}

/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// Note that `0⁰` (`pow(0, 0)`) returnes `1`. Mathematically this is undefined.
///
/// # Example
///
/// ```rust
/// use num_traits::pow;
///
/// assert_eq!(pow(2i8, 4), 16);
/// assert_eq!(pow(6u8, 3), 216);
/// assert_eq!(pow(0u8, 0), 1); // Be aware if this case affects you
/// ```
#[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
    if exp == 0 {
        return T::one();
    }

    while exp & 1 == 0 {
        base = base.clone() * base;
        exp >>= 1;
    }
    if exp == 1 {
        return base;
    }

    let mut acc = base.clone();
    while exp > 1 {
        exp >>= 1;
        base = base.clone() * base;
        if exp & 1 == 1 {
            acc = acc * base.clone();
        }
    }
    acc
}

/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Note that `0⁰` (`checked_pow(0, 0)`) returnes `Some(1)`. Mathematically this is undefined.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num_traits::checked_pow;
///
/// assert_eq!(checked_pow(2i8, 4), Some(16));
/// assert_eq!(checked_pow(7i8, 8), None);
/// assert_eq!(checked_pow(7u32, 8), Some(5_764_801));
/// assert_eq!(checked_pow(0u32, 0), Some(1)); // Be aware if this case affect you
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
    if exp == 0 {
        return Some(T::one());
    }

    macro_rules! optry {
        ($expr:expr) => {
            if let Some(val) = $expr {
                val
            } else {
                return None;
            }
        };
    }

    while exp & 1 == 0 {
        base = optry!(base.checked_mul(&base));
        exp >>= 1;
    }
    if exp == 1 {
        return Some(base);
    }

    let mut acc = base.clone();
    while exp > 1 {
        exp >>= 1;
        base = optry!(base.checked_mul(&base));
        if exp & 1 == 1 {
            acc = optry!(acc.checked_mul(&base));
        }
    }
    Some(acc)
}
<commit_msg>Typo fixes.<commit_after>use core::num::Wrapping;
use core::ops::Mul;
use {CheckedMul, One};

/// Binary operator for raising a value to a power.
pub trait Pow<RHS> {
    /// The result after applying the operator.
    type Output;

    /// Returns `self` to the power `rhs`.
    ///
    /// # Examples
    ///
    /// ```
    /// use num_traits::Pow;
    /// assert_eq!(Pow::pow(10u32, 2u32), 100);
    /// ```
    fn pow(self, rhs: RHS) -> Self::Output;
}

macro_rules! pow_impl {
    ($t:ty) => {
        pow_impl!($t, u8);
        pow_impl!($t, usize);

        // FIXME: these should be possible
        // pow_impl!($t, u16);
        // pow_impl!($t, u32);
        // pow_impl!($t, u64);
    };
    ($t:ty, $rhs:ty) => {
        pow_impl!($t, $rhs, usize, pow);
    };
    ($t:ty, $rhs:ty, $desired_rhs:ty, $method:expr) => {
        impl Pow<$rhs> for $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: $rhs) -> $t {
                ($method)(self, <$desired_rhs>::from(rhs))
            }
        }

        impl<'a> Pow<&'a $rhs> for $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> $t {
                ($method)(self, <$desired_rhs>::from(*rhs))
            }
        }

        impl<'a> Pow<$rhs> for &'a $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: $rhs) -> $t {
                ($method)(*self, <$desired_rhs>::from(rhs))
            }
        }

        impl<'a, 'b> Pow<&'a $rhs> for &'b $t {
            type Output = $t;
            #[inline]
            fn pow(self, rhs: &'a $rhs) -> $t {
                ($method)(*self, <$desired_rhs>::from(*rhs))
            }
        }
    };
}

pow_impl!(u8, u8, u32, u8::pow);
pow_impl!(u8, u16, u32, u8::pow);
pow_impl!(u8, u32, u32, u8::pow);
pow_impl!(u8, usize);
pow_impl!(i8, u8, u32, i8::pow);
pow_impl!(i8, u16, u32, i8::pow);
pow_impl!(i8, u32, u32, i8::pow);
pow_impl!(i8, usize);
pow_impl!(u16, u8, u32, u16::pow);
pow_impl!(u16, u16, u32, u16::pow);
pow_impl!(u16, u32, u32, u16::pow);
pow_impl!(u16, usize);
pow_impl!(i16, u8, u32, i16::pow);
pow_impl!(i16, u16, u32, i16::pow);
pow_impl!(i16, u32, u32, i16::pow);
pow_impl!(i16, usize);
pow_impl!(u32, u8, u32, u32::pow);
pow_impl!(u32, u16, u32, u32::pow);
pow_impl!(u32, u32, u32, u32::pow);
pow_impl!(u32, usize);
pow_impl!(i32, u8, u32, i32::pow);
pow_impl!(i32, u16, u32, i32::pow);
pow_impl!(i32, u32, u32, i32::pow);
pow_impl!(i32, usize);
pow_impl!(u64, u8, u32, u64::pow);
pow_impl!(u64, u16, u32, u64::pow);
pow_impl!(u64, u32, u32, u64::pow);
pow_impl!(u64, usize);
pow_impl!(i64, u8, u32, i64::pow);
pow_impl!(i64, u16, u32, i64::pow);
pow_impl!(i64, u32, u32, i64::pow);
pow_impl!(i64, usize);

#[cfg(has_i128)]
pow_impl!(u128, u8, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, u16, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, u32, u32, u128::pow);
#[cfg(has_i128)]
pow_impl!(u128, usize);

#[cfg(has_i128)]
pow_impl!(i128, u8, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, u16, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, u32, u32, i128::pow);
#[cfg(has_i128)]
pow_impl!(i128, usize);

pow_impl!(usize, u8, u32, usize::pow);
pow_impl!(usize, u16, u32, usize::pow);
pow_impl!(usize, u32, u32, usize::pow);
pow_impl!(usize, usize);
pow_impl!(isize, u8, u32, isize::pow);
pow_impl!(isize, u16, u32, isize::pow);
pow_impl!(isize, u32, u32, isize::pow);
pow_impl!(isize, usize);
pow_impl!(Wrapping<u8>);
pow_impl!(Wrapping<i8>);
pow_impl!(Wrapping<u16>);
pow_impl!(Wrapping<i16>);
pow_impl!(Wrapping<u32>);
pow_impl!(Wrapping<i32>);
pow_impl!(Wrapping<u64>);
pow_impl!(Wrapping<i64>);
#[cfg(has_i128)]
pow_impl!(Wrapping<u128>);
#[cfg(has_i128)]
pow_impl!(Wrapping<i128>);
pow_impl!(Wrapping<usize>);
pow_impl!(Wrapping<isize>);

// FIXME: these should be possible
// pow_impl!(u8, u64);
// pow_impl!(i16, u64);
// pow_impl!(i8, u64);
// pow_impl!(u16, u64);
// pow_impl!(u32, u64);
// pow_impl!(i32, u64);
// pow_impl!(u64, u64);
// pow_impl!(i64, u64);
// pow_impl!(usize, u64);
// pow_impl!(isize, u64);

#[cfg(feature = "std")]
mod float_impls {
    use super::Pow;

    pow_impl!(f32, i8, i32, f32::powi);
    pow_impl!(f32, u8, i32, f32::powi);
    pow_impl!(f32, i16, i32, f32::powi);
    pow_impl!(f32, u16, i32, f32::powi);
    pow_impl!(f32, i32, i32, f32::powi);
    pow_impl!(f64, i8, i32, f64::powi);
    pow_impl!(f64, u8, i32, f64::powi);
    pow_impl!(f64, i16, i32, f64::powi);
    pow_impl!(f64, u16, i32, f64::powi);
    pow_impl!(f64, i32, i32, f64::powi);
    pow_impl!(f32, f32, f32, f32::powf);
    pow_impl!(f64, f32, f64, f64::powf);
    pow_impl!(f64, f64, f64, f64::powf);
}

/// Raises a value to the power of exp, using exponentiation by squaring.
///
/// Note that `0⁰` (`pow(0, 0)`) returns `1`. Mathematically this is undefined.
///
/// # Example
///
/// ```rust
/// use num_traits::pow;
///
/// assert_eq!(pow(2i8, 4), 16);
/// assert_eq!(pow(6u8, 3), 216);
/// assert_eq!(pow(0u8, 0), 1); // Be aware if this case affects you
/// ```
#[inline]
pub fn pow<T: Clone + One + Mul<T, Output = T>>(mut base: T, mut exp: usize) -> T {
    if exp == 0 {
        return T::one();
    }

    while exp & 1 == 0 {
        base = base.clone() * base;
        exp >>= 1;
    }
    if exp == 1 {
        return base;
    }

    let mut acc = base.clone();
    while exp > 1 {
        exp >>= 1;
        base = base.clone() * base;
        if exp & 1 == 1 {
            acc = acc * base.clone();
        }
    }
    acc
}

/// Raises a value to the power of exp, returning `None` if an overflow occurred.
///
/// Note that `0⁰` (`checked_pow(0, 0)`) returns `Some(1)`. Mathematically this is undefined.
///
/// Otherwise same as the `pow` function.
///
/// # Example
///
/// ```rust
/// use num_traits::checked_pow;
///
/// assert_eq!(checked_pow(2i8, 4), Some(16));
/// assert_eq!(checked_pow(7i8, 8), None);
/// assert_eq!(checked_pow(7u32, 8), Some(5_764_801));
/// assert_eq!(checked_pow(0u32, 0), Some(1)); // Be aware if this case affect you
/// ```
#[inline]
pub fn checked_pow<T: Clone + One + CheckedMul>(mut base: T, mut exp: usize) -> Option<T> {
    if exp == 0 {
        return Some(T::one());
    }

    macro_rules! optry {
        ($expr:expr) => {
            if let Some(val) = $expr {
                val
            } else {
                return None;
            }
        };
    }

    while exp & 1 == 0 {
        base = optry!(base.checked_mul(&base));
        exp >>= 1;
    }
    if exp == 1 {
        return Some(base);
    }

    let mut acc = base.clone();
    while exp > 1 {
        exp >>= 1;
        base = optry!(base.checked_mul(&base));
        if exp & 1 == 1 {
            acc = optry!(acc.checked_mul(&base));
        }
    }
    Some(acc)
}
<|endoftext|>


<commit_before>use heartbeats_simple_sys::pow::{heartbeat_pow_init, heartbeat_pow};
use std::mem;
use std::io::{self, Write};
use std::fs::File;

pub use heartbeats_simple_sys::pow::heartbeat_pow_context as HeartbeatPowContext;
pub use heartbeats_simple_sys::pow::heartbeat_pow_record as HeartbeatPowRecord;
pub use heartbeats_simple_sys::pow::heartbeat_pow_window_complete as HeartbeatPowWindowComplete;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatPow {
    pub hb: HeartbeatPowContext,
    pub hbr: Vec<HeartbeatPowRecord>,
    pub log: Option<File>,
}

impl HeartbeatPow {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<HeartbeatPowWindowComplete>,
               mut log: Option<File>) -> Result<HeartbeatPow, &'static str> {
        let mut hbr: Vec<HeartbeatPowRecord> = Vec::with_capacity(window_size);
        let hb: HeartbeatPowContext = unsafe {
            // must explicitly set size so we can read data later
            // (Rust isn't aware of native code modifying the buffer)
            hbr.set_len(window_size);
            let mut hb = mem::uninitialized();
            match heartbeat_pow_init(&mut hb,
                                     hbr.capacity() as u64,
                                     hbr.as_mut_ptr(),
                                     hwc_callback) {
                0 => hb,
                _ => return Err("Failed to initialize heartbeat")
            }
        };
        // write header to log file if there is one
        if let Some(ref mut l) = log {
            l.write_all(format!("{:6} {:6} \
                         {:11} {:11} {:11} \
                         {:15} {:15} {:20} {:20} \
                         {:15} {:15} {:15} \
                         {:15} {:15} {:15} {:15} \
                         {:15} {:15} {}\n",
                        "HB", "Tag",
                        "Global_Work", "Window_Work", "Work",
                        "Global_Time", "Window_Time", "Start_Time", "End_Time",
                        "Global_Perf", "Window_Perf", "Instant_Perf",
                        "Global_Energy", "Window_Energy", "Start_Energy", "End_Energy",
                        "Global_Pwr", "Window_Pwr", "Instant_Pwr").as_bytes()).unwrap()
        }
        Ok(HeartbeatPow { hb: hb, hbr: hbr, log: log, })
    }

    /// Issue a heartbeat
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64,
                     start_energy: u64,
                     end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    fn write_log(r: &HeartbeatPowRecord, l: &mut File) -> io::Result<usize> {
        l.write(format!("{:<6} {:<6} \
                         {:<11} {:<11} {:<11} \
                         {:<15} {:<15} {:<20} {:<20} \
                         {:<15.6} {:<15.6} {:<15.6} \
                         {:<15} {:<15} {:<15} {:<15} \
                         {:<15.6} {:<15.6} {:<.6}\n",
                        r.id, r.user_tag,
                        r.wd.global, r.wd.window, r.work,
                        r.td.global, r.td.window, r.start_time, r.end_time,
                        r.perf.global, r.perf.window, r.perf.instant,
                        r.ed.global, r.ed.window, r.start_energy, r.end_energy,
                        r.pwr.global, r.pwr.window, r.pwr.instant).as_bytes())
    }

    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
        match self.log {
            Some(ref mut l) => {
                for i in 0..self.hb.ws.buffer_index {
                    match HeartbeatPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                }
                l.flush()
            }
            None => Ok(())
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::File;

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatPow::new(5, None, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        for tag in 0..10 {
            hb.heartbeat(tag, 1, start_time, end_time, start_energy, end_energy);
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }

    #[test]
    fn test_callback() {
        static mut received_cb: bool = false;
        extern fn callback(_hb: *const HeartbeatPowContext) {
            unsafe {
                received_cb = true;
            }
        }

        let mut hb = HeartbeatPow::new(1, Some(callback), None).unwrap();
        hb.heartbeat(0, 1, 0, 1000, 0, 0);
        unsafe {
            assert!(received_cb);
        }
    }

    #[test]
    fn test_file() {
        let mut hb = HeartbeatPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
        hb.heartbeat(0, 1, 0, 1000, 0, 0);
        hb.log_to_buffer_index().unwrap();
    }
}
<commit_msg>Add utility functions<commit_after>use heartbeats_simple_sys::pow::*;
use std::mem;
use std::io::{self, Write};
use std::fs::File;

pub use heartbeats_simple_sys::pow::heartbeat_pow_context as HeartbeatPowContext;
pub use heartbeats_simple_sys::pow::heartbeat_pow_record as HeartbeatPowRecord;
pub use heartbeats_simple_sys::pow::heartbeat_pow_window_complete as HeartbeatPowWindowComplete;

/// Contains the Heartbeat and its window data buffer.
pub struct HeartbeatPow {
    pub hb: HeartbeatPowContext,
    pub hbr: Vec<HeartbeatPowRecord>,
    pub log: Option<File>,
}

impl HeartbeatPow {
    /// Allocate and initialize a new `Heartbeat`.
    pub fn new(window_size: usize,
               hwc_callback: Option<HeartbeatPowWindowComplete>,
               mut log: Option<File>) -> Result<HeartbeatPow, &'static str> {
        let mut hbr: Vec<HeartbeatPowRecord> = Vec::with_capacity(window_size);
        let hb: HeartbeatPowContext = unsafe {
            // must explicitly set size so we can read data later
            // (Rust isn't aware of native code modifying the buffer)
            hbr.set_len(window_size);
            let mut hb = mem::uninitialized();
            match heartbeat_pow_init(&mut hb,
                                     hbr.capacity() as u64,
                                     hbr.as_mut_ptr(),
                                     hwc_callback) {
                0 => hb,
                _ => return Err("Failed to initialize heartbeat")
            }
        };
        // write header to log file if there is one
        if let Some(ref mut l) = log {
            l.write_all(format!("{:6} {:6} \
                         {:11} {:11} {:11} \
                         {:15} {:15} {:20} {:20} \
                         {:15} {:15} {:15} \
                         {:15} {:15} {:15} {:15} \
                         {:15} {:15} {}\n",
                        "HB", "Tag",
                        "Global_Work", "Window_Work", "Work",
                        "Global_Time", "Window_Time", "Start_Time", "End_Time",
                        "Global_Perf", "Window_Perf", "Instant_Perf",
                        "Global_Energy", "Window_Energy", "Start_Energy", "End_Energy",
                        "Global_Pwr", "Window_Pwr", "Instant_Pwr").as_bytes()).unwrap()
        }
        Ok(HeartbeatPow { hb: hb, hbr: hbr, log: log, })
    }

    /// Issue a heartbeat
    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     start_time: u64,
                     end_time: u64,
                     start_energy: u64,
                     end_energy: u64) {
        unsafe {
            heartbeat_pow(&mut self.hb, tag, work, start_time, end_time, start_energy, end_energy)
        }
    }

    fn write_log(r: &HeartbeatPowRecord, l: &mut File) -> io::Result<usize> {
        l.write(format!("{:<6} {:<6} \
                         {:<11} {:<11} {:<11} \
                         {:<15} {:<15} {:<20} {:<20} \
                         {:<15.6} {:<15.6} {:<15.6} \
                         {:<15} {:<15} {:<15} {:<15} \
                         {:<15.6} {:<15.6} {:<.6}\n",
                        r.id, r.user_tag,
                        r.wd.global, r.wd.window, r.work,
                        r.td.global, r.td.window, r.start_time, r.end_time,
                        r.perf.global, r.perf.window, r.perf.instant,
                        r.ed.global, r.ed.window, r.start_energy, r.end_energy,
                        r.pwr.global, r.pwr.window, r.pwr.instant).as_bytes())
    }

    /// Rust-only function that logs the buffer (up to buffer_index) to a file.
    pub fn log_to_buffer_index(&mut self) -> io::Result<()> {
        match self.log {
            Some(ref mut l) => {
                for i in 0..self.hb.ws.buffer_index {
                    match HeartbeatPow::write_log(self.hbr.get(i as usize).unwrap(), l) {
                        Ok(_) => (),
                        Err(e) => return Err(e),
                    }
                }
                l.flush()
            }
            None => Ok(())
        }
    }

    pub fn get_window_size(&self) -> u64 {
        unsafe {
            hb_pow_get_window_size(&self.hb)
        }
    }

    pub fn get_user_tag(&self) -> u64 {
        unsafe {
            hb_pow_get_user_tag(&self.hb)
        }
    }

    pub fn get_global_time(&self) -> u64 {
        unsafe {
            hb_pow_get_global_time(&self.hb)
        }
    }

    pub fn get_window_time(&self) -> u64 {
        unsafe {
            hb_pow_get_window_time(&self.hb)
        }
    }

    pub fn get_global_work(&self) -> u64 {
        unsafe {
            hb_pow_get_global_work(&self.hb)
        }
    }

    pub fn get_window_work(&self) -> u64 {
        unsafe {
            hb_pow_get_window_work(&self.hb)
        }
    }

    pub fn get_global_perf(&self) -> f64 {
        unsafe {
            hb_pow_get_global_perf(&self.hb)
        }
    }

    pub fn get_window_perf(&self) -> f64 {
        unsafe {
            hb_pow_get_window_perf(&self.hb)
        }
    }

    pub fn get_instant_perf(&self) -> f64 {
        unsafe {
            hb_pow_get_instant_perf(&self.hb)
        }
    }

    pub fn get_global_energy(&self) -> u64 {
        unsafe {
            hb_pow_get_global_energy(&self.hb)
        }
    }

    pub fn get_window_energy(&self) -> u64 {
        unsafe {
            hb_pow_get_window_energy(&self.hb)
        }
    }

    pub fn get_global_power(&self) -> f64 {
        unsafe {
            hb_pow_get_global_power(&self.hb)
        }
    }

    pub fn get_window_power(&self) -> f64 {
        unsafe {
            hb_pow_get_window_power(&self.hb)
        }
    }

    pub fn get_instant_power(&self) -> f64 {
        unsafe {
            hb_pow_get_instant_power(&self.hb)
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::fs::File;

    #[test]
    fn test_simple() {
        const TIME_INC: u64 = 1000000000;
        const ENERGY_INC: u64 = 1000000;
        let mut hb = HeartbeatPow::new(5, None, None).unwrap();
        let mut start_time: u64 = 0;
        let mut end_time: u64 = TIME_INC;
        let mut start_energy: u64 = 0;
        let mut end_energy: u64 = ENERGY_INC;
        for tag in 0..10 {
            hb.heartbeat(tag, 1, start_time, end_time, start_energy, end_energy);
            start_time = end_time;
            end_time += TIME_INC;
            start_energy = end_energy;
            end_energy += ENERGY_INC;
        }
    }

    #[test]
    fn test_callback() {
        static mut received_cb: bool = false;
        extern fn callback(_hb: *const HeartbeatPowContext) {
            unsafe {
                received_cb = true;
            }
        }

        let mut hb = HeartbeatPow::new(1, Some(callback), None).unwrap();
        hb.heartbeat(0, 1, 0, 1000, 0, 0);
        unsafe {
            assert!(received_cb);
        }
    }

    #[test]
    fn test_file() {
        let mut hb = HeartbeatPow::new(5, None, Some(File::create("foo.log").unwrap())).unwrap();
        hb.heartbeat(0, 1, 0, 1000, 0, 0);
        hb.log_to_buffer_index().unwrap();
    }
}
<|endoftext|>