<commit_before>//! Just a dumping ground for cli stuff

use rustup::{self, Cfg, Notification, Toolchain, UpdateStatus};
use rustup::telemetry_analysis::TelemetryAnalysis;
use errors::*;
use rustup_utils::utils;
use rustup_utils::notify::NotificationLevel;
use self_update;
use std::io::{Write, BufRead, BufReader};
use std::process::{Command, Stdio};
use std::path::Path;
use std::{cmp, iter};
use std::sync::Arc;
use std::time::Duration;
use std;
use term2;
use wait_timeout::ChildExt;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
    print!("{} ", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "y" | "Y" => true,
        "n" | "N" => false,
        "" => default,
        _ => false,
    };

    println!("");

    Ok(r)
}

pub enum Confirm {
    Yes, No, Advanced
}

pub fn confirm_advanced() -> Result<Confirm> {
    println!("");
    println!("1) Proceed with installation (default)");
    println!("2) Customize installation");
    println!("3) Cancel installation");

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "1"|"" => Confirm::Yes,
        "2" => Confirm::Advanced,
        _ => Confirm::No,
    };

    println!("");

    Ok(r)
}

pub fn question_str(question: &str, default: &str) -> Result<String> {
    println!("{}", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default.to_string())
    } else {
        Ok(input)
    }
}

pub fn question_bool(question: &str, default: bool) -> Result<bool> {
    println!("{}", question);

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default)
    } else {
        match &*input {
            "y" | "Y" | "yes" => Ok(true),
            "n" | "N" | "no" => Ok(false),
            _ => Ok(default)
        }
    }

}

pub fn read_line() -> Result<String> {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    lines.next().and_then(|l| l.ok()).ok_or(
        "unable to read from stdin for confirmation".into())
}

pub fn set_globals(verbose: bool) -> Result<Cfg> {
    use download_tracker::DownloadTracker;
    use std::cell::RefCell;

    let download_tracker = RefCell::new(DownloadTracker::new());

    Ok(try!(Cfg::from_env(Arc::new(move |n: Notification| {
       if download_tracker.borrow_mut().handle_notification(&n) {
            return;
        }

        match n.level() {
            NotificationLevel::Verbose => {
                if verbose {
                    verbose!("{}", n);
                }
            }
            NotificationLevel::Info => {
                info!("{}", n);
            }
            NotificationLevel::Warn => {
                warn!("{}", n);
            }
            NotificationLevel::Error => {
                err!("{}", n);
            }
        }
    }))))

}

pub fn show_channel_update(cfg: &Cfg, name: &str,
                           updated: rustup::Result<UpdateStatus>) -> Result<()> {
    show_channel_updates(cfg, vec![(name.to_string(), updated)])
}

fn show_channel_updates(cfg: &Cfg, toolchains: Vec<(String, rustup::Result<UpdateStatus>)>) -> Result<()> {
    let data = toolchains.into_iter().map(|(name, result)| {
        let ref toolchain = cfg.get_toolchain(&name, false).expect("");
        let version = rustc_version(toolchain);

        let banner;
        let color;
        match result {
            Ok(UpdateStatus::Installed) => {
                banner = "installed";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Updated) => {
                banner = "updated";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Unchanged) => {
                banner = "unchanged";
                color = None;
            }
            Err(_) => {
                banner = "update failed";
                color = Some(term2::color::BRIGHT_RED);
            }
        }

        let width = name.len() + 1 + banner.len();

        (name, banner, width, color, version)
    });

    let mut t = term2::stdout();

    let data: Vec<_> = data.collect();
    let max_width = data.iter().fold(0, |a, &(_, _, width, _, _)| cmp::max(a, width));

    for (name, banner, width, color, version) in data {
        let padding = max_width - width;
        let padding: String = iter::repeat(' ').take(padding).collect();
        let _ = write!(t, "  {}", padding);
        let _ = t.attr(term2::Attr::Bold);
        if let Some(color) = color {
            let _ = t.fg(color);
        }
        let _ = write!(t, "{} ", name);
        let _ = write!(t, "{}", banner);
        let _ = t.reset();
        let _ = writeln!(t, " - {}", version);
    }
    let _ = writeln!(t, "");

    Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {

    let toolchains = try!(cfg.update_all_channels());

    if toolchains.is_empty() {
        info!("no updatable toolchains installed");
    }

    let setup_path = if self_update {
        try!(self_update::prepare_update())
    } else {
        None
    };

    if !toolchains.is_empty() {
        println!("");

        try!(show_channel_updates(cfg, toolchains));
    }

    if let Some(ref setup_path) = setup_path {
        try!(self_update::run_update(setup_path));

        unreachable!(); // update exits on success
    }

    Ok(())
}

pub fn rustc_version(toolchain: &Toolchain) -> String {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            cmd.stdin(Stdio::null());
            cmd.stdout(Stdio::piped());
            cmd.stderr(Stdio::piped());
            toolchain.set_ldpath(&mut cmd);

            // some toolchains are faulty with some combinations of platforms and
            // may fail to launch but also to timely terminate.
            // (known cases include Rust 1.3.0 through 1.10.0 in recent macOS Sierra.)
            // we guard against such cases by enforcing a reasonable timeout to read.
            let mut line1 = None;
            if let Ok(mut child) = cmd.spawn() {
                let timeout = Duration::new(3, 0);
                match child.wait_timeout(timeout) {
                    Ok(Some(status)) if status.success() => {
                        let out = child.stdout.expect("Child::stdout requested but not present");
                        let mut line = String::new();
                        if BufReader::new(out).read_line(&mut line).is_ok() {
                            let lineend = line.trim_right_matches(&['\r', '\n'][..]).len();
                            line.truncate(lineend);
                            line1 = Some(line);
                        }
                    }
                    Ok(None) => {
                        let _ = child.kill();
                    }
                    Ok(Some(_)) | Err(_) => {}
                }
            }

            if let Some(line1) = line1 {
                line1.to_owned()
            } else {
                String::from("(error reading rustc version)")
            }
        } else {
            String::from("(rustc does not exist)")
        }
    } else {
        String::from("(toolchain not installed)")
    }
}

pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        if component.component.pkg == "rust-std" {
            let target = component.component.target.as_ref().expect("rust-std should have a target");
            if component.required {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (default)", target);
                let _ = t.reset();
            } else if component.installed {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (installed)", target);
                let _ = t.reset();
            } else if component.available {
                let _ = writeln!(t, "{}", target);
            }
        }
    }

    Ok(())
}

pub fn list_components(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        let name = component.component.name();
        if component.required {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (default)", name);
            let _ = t.reset();
        } else if component.installed {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (installed)", name);
            let _ = t.reset();
        } else if component.available {
            let _ = writeln!(t, "{}", name);
        }
    }

    Ok(())
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
    let toolchains = try!(cfg.list_toolchains());

    if toolchains.is_empty() {
        println!("no installed toolchains");
    } else {
        if let Ok(Some(def_toolchain)) = cfg.find_default() {
            for toolchain in toolchains {
                let if_default = if def_toolchain.name() == &*toolchain {
                    " (default)"
                } else {
                    ""
                };
                println!("{}{}", &toolchain, if_default);
            }

        } else {
            for toolchain in toolchains {
                println!("{}", &toolchain);
            }
        }
    }
    Ok(())
}

pub fn list_overrides(cfg: &Cfg) -> Result<()> {
    let overrides = try!(cfg.settings_file.with(|s| Ok(s.overrides.clone())));

    if overrides.is_empty() {
        println!("no overrides");
    } else {
        let mut any_not_exist = false;
        for (k, v) in overrides {
            let dir_exists = Path::new(&k).is_dir();
            if !dir_exists {
                any_not_exist = true;
            }
            println!("{:<40}\t{:<20}",
                     utils::format_path_for_display(&k) +
                     if dir_exists {
                         ""
                     } else {
                         " (not a directory)"
                     },
                     v)
        }
        if any_not_exist {
            println!("");
            info!("you may remove overrides for non-existent directories with
`rustup override unset --nonexistent`");
        }
    }
    Ok(())
}

pub fn version() -> &'static str {
    concat!(env!("CARGO_PKG_VERSION"), include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")))
}

pub fn report_error(e: &Error) {
    err!("{}", e);

    for e in e.iter().skip(1) {
        info!("caused by: {}", e);
    }

    if show_backtrace() {
        if let Some(backtrace) = e.backtrace() {
            info!("backtrace:");
            println!("");
            println!("{:?}", backtrace);
        }
    } else {
    }

    fn show_backtrace() -> bool {
        use std::env;
        use std::ops::Deref;

        if env::var("RUST_BACKTRACE").as_ref().map(Deref::deref) == Ok("1") {
            return true;
        }

        for arg in env::args() {
            if arg == "-v" || arg == "--verbose" {
                return true;
            }
        }

        false
    }
}

pub fn show_telemetry(analysis: TelemetryAnalysis) -> Result<()> {
    println!("Telemetry Analysis");

    println!("{}", analysis);

    Ok(())
}
<commit_msg>Return different message for timeout during Rust version check<commit_after>//! Just a dumping ground for cli stuff

use rustup::{self, Cfg, Notification, Toolchain, UpdateStatus};
use rustup::telemetry_analysis::TelemetryAnalysis;
use errors::*;
use rustup_utils::utils;
use rustup_utils::notify::NotificationLevel;
use self_update;
use std::io::{Write, BufRead, BufReader};
use std::process::{Command, Stdio};
use std::path::Path;
use std::{cmp, iter};
use std::sync::Arc;
use std::time::Duration;
use std;
use term2;
use wait_timeout::ChildExt;

pub fn confirm(question: &str, default: bool) -> Result<bool> {
    print!("{} ", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "y" | "Y" => true,
        "n" | "N" => false,
        "" => default,
        _ => false,
    };

    println!("");

    Ok(r)
}

pub enum Confirm {
    Yes, No, Advanced
}

pub fn confirm_advanced() -> Result<Confirm> {
    println!("");
    println!("1) Proceed with installation (default)");
    println!("2) Customize installation");
    println!("3) Cancel installation");

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    let r = match &*input {
        "1"|"" => Confirm::Yes,
        "2" => Confirm::Advanced,
        _ => Confirm::No,
    };

    println!("");

    Ok(r)
}

pub fn question_str(question: &str, default: &str) -> Result<String> {
    println!("{}", question);
    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default.to_string())
    } else {
        Ok(input)
    }
}

pub fn question_bool(question: &str, default: bool) -> Result<bool> {
    println!("{}", question);

    let _ = std::io::stdout().flush();
    let input = try!(read_line());

    println!("");

    if input.is_empty() {
        Ok(default)
    } else {
        match &*input {
            "y" | "Y" | "yes" => Ok(true),
            "n" | "N" | "no" => Ok(false),
            _ => Ok(default)
        }
    }

}

pub fn read_line() -> Result<String> {
    let stdin = std::io::stdin();
    let stdin = stdin.lock();
    let mut lines = stdin.lines();
    lines.next().and_then(|l| l.ok()).ok_or(
        "unable to read from stdin for confirmation".into())
}

pub fn set_globals(verbose: bool) -> Result<Cfg> {
    use download_tracker::DownloadTracker;
    use std::cell::RefCell;

    let download_tracker = RefCell::new(DownloadTracker::new());

    Ok(try!(Cfg::from_env(Arc::new(move |n: Notification| {
       if download_tracker.borrow_mut().handle_notification(&n) {
            return;
        }

        match n.level() {
            NotificationLevel::Verbose => {
                if verbose {
                    verbose!("{}", n);
                }
            }
            NotificationLevel::Info => {
                info!("{}", n);
            }
            NotificationLevel::Warn => {
                warn!("{}", n);
            }
            NotificationLevel::Error => {
                err!("{}", n);
            }
        }
    }))))

}

pub fn show_channel_update(cfg: &Cfg, name: &str,
                           updated: rustup::Result<UpdateStatus>) -> Result<()> {
    show_channel_updates(cfg, vec![(name.to_string(), updated)])
}

fn show_channel_updates(cfg: &Cfg, toolchains: Vec<(String, rustup::Result<UpdateStatus>)>) -> Result<()> {
    let data = toolchains.into_iter().map(|(name, result)| {
        let ref toolchain = cfg.get_toolchain(&name, false).expect("");
        let version = rustc_version(toolchain);

        let banner;
        let color;
        match result {
            Ok(UpdateStatus::Installed) => {
                banner = "installed";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Updated) => {
                banner = "updated";
                color = Some(term2::color::BRIGHT_GREEN);
            }
            Ok(UpdateStatus::Unchanged) => {
                banner = "unchanged";
                color = None;
            }
            Err(_) => {
                banner = "update failed";
                color = Some(term2::color::BRIGHT_RED);
            }
        }

        let width = name.len() + 1 + banner.len();

        (name, banner, width, color, version)
    });

    let mut t = term2::stdout();

    let data: Vec<_> = data.collect();
    let max_width = data.iter().fold(0, |a, &(_, _, width, _, _)| cmp::max(a, width));

    for (name, banner, width, color, version) in data {
        let padding = max_width - width;
        let padding: String = iter::repeat(' ').take(padding).collect();
        let _ = write!(t, "  {}", padding);
        let _ = t.attr(term2::Attr::Bold);
        if let Some(color) = color {
            let _ = t.fg(color);
        }
        let _ = write!(t, "{} ", name);
        let _ = write!(t, "{}", banner);
        let _ = t.reset();
        let _ = writeln!(t, " - {}", version);
    }
    let _ = writeln!(t, "");

    Ok(())
}

pub fn update_all_channels(cfg: &Cfg, self_update: bool) -> Result<()> {

    let toolchains = try!(cfg.update_all_channels());

    if toolchains.is_empty() {
        info!("no updatable toolchains installed");
    }

    let setup_path = if self_update {
        try!(self_update::prepare_update())
    } else {
        None
    };

    if !toolchains.is_empty() {
        println!("");

        try!(show_channel_updates(cfg, toolchains));
    }

    if let Some(ref setup_path) = setup_path {
        try!(self_update::run_update(setup_path));

        unreachable!(); // update exits on success
    }

    Ok(())
}

pub fn rustc_version(toolchain: &Toolchain) -> String {
    if toolchain.exists() {
        let rustc_path = toolchain.binary_file("rustc");
        if utils::is_file(&rustc_path) {
            let mut cmd = Command::new(&rustc_path);
            cmd.arg("--version");
            cmd.stdin(Stdio::null());
            cmd.stdout(Stdio::piped());
            cmd.stderr(Stdio::piped());
            toolchain.set_ldpath(&mut cmd);

            // some toolchains are faulty with some combinations of platforms and
            // may fail to launch but also to timely terminate.
            // (known cases include Rust 1.3.0 through 1.10.0 in recent macOS Sierra.)
            // we guard against such cases by enforcing a reasonable timeout to read.
            let mut line1 = None;
            if let Ok(mut child) = cmd.spawn() {
                let timeout = Duration::new(3, 0);
                match child.wait_timeout(timeout) {
                    Ok(Some(status)) if status.success() => {
                        let out = child.stdout.expect("Child::stdout requested but not present");
                        let mut line = String::new();
                        if BufReader::new(out).read_line(&mut line).is_ok() {
                            let lineend = line.trim_right_matches(&['\r', '\n'][..]).len();
                            line.truncate(lineend);
                            line1 = Some(line);
                        }
                    }
                    Ok(None) => {
                        let _ = child.kill();
                        return String::from("(timeout reading rustc version)")
                    }
                    Ok(Some(_)) | Err(_) => {}
                }
            }

            if let Some(line1) = line1 {
                line1.to_owned()
            } else {
                String::from("(error reading rustc version)")
            }
        } else {
            String::from("(rustc does not exist)")
        }
    } else {
        String::from("(toolchain not installed)")
    }
}

pub fn list_targets(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        if component.component.pkg == "rust-std" {
            let target = component.component.target.as_ref().expect("rust-std should have a target");
            if component.required {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (default)", target);
                let _ = t.reset();
            } else if component.installed {
                let _ = t.attr(term2::Attr::Bold);
                let _ = writeln!(t, "{} (installed)", target);
                let _ = t.reset();
            } else if component.available {
                let _ = writeln!(t, "{}", target);
            }
        }
    }

    Ok(())
}

pub fn list_components(toolchain: &Toolchain) -> Result<()> {
    let mut t = term2::stdout();
    for component in try!(toolchain.list_components()) {
        let name = component.component.name();
        if component.required {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (default)", name);
            let _ = t.reset();
        } else if component.installed {
            let _ = t.attr(term2::Attr::Bold);
            let _ = writeln!(t, "{} (installed)", name);
            let _ = t.reset();
        } else if component.available {
            let _ = writeln!(t, "{}", name);
        }
    }

    Ok(())
}

pub fn list_toolchains(cfg: &Cfg) -> Result<()> {
    let toolchains = try!(cfg.list_toolchains());

    if toolchains.is_empty() {
        println!("no installed toolchains");
    } else {
        if let Ok(Some(def_toolchain)) = cfg.find_default() {
            for toolchain in toolchains {
                let if_default = if def_toolchain.name() == &*toolchain {
                    " (default)"
                } else {
                    ""
                };
                println!("{}{}", &toolchain, if_default);
            }

        } else {
            for toolchain in toolchains {
                println!("{}", &toolchain);
            }
        }
    }
    Ok(())
}

pub fn list_overrides(cfg: &Cfg) -> Result<()> {
    let overrides = try!(cfg.settings_file.with(|s| Ok(s.overrides.clone())));

    if overrides.is_empty() {
        println!("no overrides");
    } else {
        let mut any_not_exist = false;
        for (k, v) in overrides {
            let dir_exists = Path::new(&k).is_dir();
            if !dir_exists {
                any_not_exist = true;
            }
            println!("{:<40}\t{:<20}",
                     utils::format_path_for_display(&k) +
                     if dir_exists {
                         ""
                     } else {
                         " (not a directory)"
                     },
                     v)
        }
        if any_not_exist {
            println!("");
            info!("you may remove overrides for non-existent directories with
`rustup override unset --nonexistent`");
        }
    }
    Ok(())
}

pub fn version() -> &'static str {
    concat!(env!("CARGO_PKG_VERSION"), include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt")))
}

pub fn report_error(e: &Error) {
    err!("{}", e);

    for e in e.iter().skip(1) {
        info!("caused by: {}", e);
    }

    if show_backtrace() {
        if let Some(backtrace) = e.backtrace() {
            info!("backtrace:");
            println!("");
            println!("{:?}", backtrace);
        }
    } else {
    }

    fn show_backtrace() -> bool {
        use std::env;
        use std::ops::Deref;

        if env::var("RUST_BACKTRACE").as_ref().map(Deref::deref) == Ok("1") {
            return true;
        }

        for arg in env::args() {
            if arg == "-v" || arg == "--verbose" {
                return true;
            }
        }

        false
    }
}

pub fn show_telemetry(analysis: TelemetryAnalysis) -> Result<()> {
    println!("Telemetry Analysis");

    println!("{}", analysis);

    Ok(())
}
<|endoftext|>


<commit_before>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use arch::memory::{Frame, PAddr, PAGE_SIZE};

use memory::paging::{Page, FrameAllocator};

use core::marker::PhantomData;
use core::ops::{Index, IndexMut};

/// The number of entries in a page table.
pub const N_ENTRIES: usize = 512;
/// Size of a page table (in bytes)
pub const PAGE_TABLE_SIZE: usize = N_ENTRIES * PAGE_SIZE as usize;

/// PML4 table
pub const PML4: *mut Table<PML4Level>
    = 0o177777_777_777_777_777_0000 as *mut _;

/// A page table
pub struct Table<L>
where L: TableLevel { /// The entries in the page table.
                      pub entries: [Entry; N_ENTRIES]
                    , _level_marker: PhantomData<L>
                    }

pub trait TableLevel {}
pub enum PML4Level {}
pub enum PDPTLevel {}
pub enum PDLevel   {}
pub enum PTLevel   {}

impl TableLevel for PML4Level {}
impl TableLevel for PDPTLevel {}
impl TableLevel for PDLevel   {}
impl TableLevel for PTLevel   {}

pub trait Sublevel: TableLevel {
    type Next: TableLevel;
}
impl Sublevel for PML4Level {
    type Next = PDPTLevel;
}
impl Sublevel for PDPTLevel {
    type Next = PDLevel;
}
impl Sublevel for PDLevel {
    type Next = PTLevel;
}

impl<L: TableLevel> Index<usize> for Table<L> {
    type Output = Entry;

    #[inline] fn index(&self, index: usize) -> &Entry {
        &self.entries[index]
    }
}

impl<L: TableLevel> IndexMut<usize> for Table<L> {
    #[inline] fn index_mut(&mut self, index: usize) -> &mut Entry {
        &mut self.entries[index]
    }
}

impl<L: TableLevel> Table<L>  {

    /// Zeroes out the page table by setting all entries "unused"
    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused()
        }
    }

}

impl<L: Sublevel> Table<L> {

    /// Returns the address of the next table, or None if none exists.
    fn next_table_addr(&self, index: usize) -> Option<usize> {
        let flags = self[index].flags();
        if flags.contains(PRESENT) && !flags.contains(HUGE_PAGE) {
            Some(((self as *const _ as usize) << 9) | (index << 12))
        } else {
            None
        }
    }

    /// Returns the next table, or `None` if none exists
    pub fn next_table(&self, index: usize) -> Option<&Table<L::Next>> {
        self.next_table_addr(index)
            .map(|addr| unsafe { &*(addr as *const _) })
    }

    /// Mutably borrows the next table.
    pub fn next_table_mut(&self, index: usize) -> Option<& mut Table<L::Next>> {
        self.next_table_addr(index)
            .map(|addr| unsafe { &mut *(addr as *mut _) })
    }

    /// Returns the next table, creating it if it does not exist.
    pub fn create_next<A>(&mut self, index: usize, alloc: &mut A)
                         -> &mut Table<L::Next>
    where A: FrameAllocator<Frame> {
        if self.next_table(index).is_none() {
            assert!( !self[index].is_huge()
                   , "Couldn't create next table: huge pages not \
                      currently supported.");

            let frame = alloc.alloc_frame()
                             // TODO: would we rather rewrite this to return
                             // a `Result`? I think so.
                            .expect("Couldn't map page, out of frames!");

            self[index].set(frame, PRESENT | WRITABLE);
            self.next_table_mut(index).unwrap().zero();
        }
        self.next_table_mut(index).unwrap()
    }
}

/// A page table entry.
pub struct Entry(u64);

bitflags! {
    pub flags EntryFlags: u64 {
        /// Present flag.
        /// Must be 1 to map a 2-MByte page or reference a page table.
        const PRESENT =         1 << 0,
        /// Writable flag.
        /// If 0, writes may not be allowed to the 2-MB region controlled
        /// by this entry
        const WRITABLE =        1 << 1
      , const USER_ACCESSIBLE = 1 << 2
      , const WRITE_THROUGH =   1 << 3
      , const NO_CACHE =        1 << 4
      , const ACCESSED =        1 << 5
      , const DIRTY =           1 << 6
      , const HUGE_PAGE =       1 << 7
      , const GLOBAL =          1 << 8
      , const NO_EXECUTE =      1 << 63
    }
}

impl EntryFlags {
    /// Returns true if this page is huge
    #[inline]
    pub fn is_huge(&self) -> bool {
        self.contains(HUGE_PAGE)
    }

    /// Returns true if this page is present
    #[inline]
    pub fn is_present(&self) -> bool {
        self.contains(PRESENT)
    }
}

impl Entry {

    // TODO: this is one of the worst names I have ever given a thing
    pub fn do_huge(&self, offset: usize) -> Option<Frame> {
        if self.is_huge() {
            self.get_frame()
                .map(|start_frame| {
                    assert!( start_frame.number as usize % N_ENTRIES == 0
                           , "Start frame must be aligned on a 1GB boundary!");
                    start_frame + offset
                })
        } else {
            None
        }
    }

    /// Returns true if this is an unused entry
    #[inline]
    pub fn is_unused(&self) -> bool {
        self.0 == 0
    }

    /// Sets this entry to be unused
    #[inline]
    pub fn set_unused(&mut self) {
        self.0 = 0;
    }

    /// Returns true if this page is huge
    #[inline]
    pub fn is_huge(&self) -> bool {
        self.flags().is_huge()
    }

    /// Access the entry's bitflags.
    #[inline]
    pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    /// Returns the frame in memory pointed to by this page table entry.
    pub fn get_frame(&self) -> Option<Frame> {
        if self.flags().is_present() {
            // If the entry is present, mask out bits 12-51 and
            //
            Some(Frame::containing(PAddr::from(self.0 & 0x000fffff_fffff000)))
        } else { None }
    }

    pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
        let addr: u64 = frame.base_addr().into();
        assert!(addr & !0x000fffff_fffff000 == 0);
        self.0 = addr | flags.bits();
    }

}
<commit_msg>[x86_64] tweaks to pml4<commit_after>//
//  SOS: the Stupid Operating System
//  by Hawk Weisman (hi@hawkweisman.me)
//
//  Copyright (c) 2015 Hawk Weisman
//  Released under the terms of the MIT license. See `LICENSE` in the root
//  directory of this repository for more information.
//
use arch::memory::{Frame, PAddr, PAGE_SIZE};

use memory::paging::Page;
use memory::alloc::FrameAllocator;

use core::marker::PhantomData;
use core::ops::{Index, IndexMut};

/// The number of entries in a page table.
pub const N_ENTRIES: usize = 512;
/// Size of a page table (in bytes)
pub const PAGE_TABLE_SIZE: usize = N_ENTRIES * PAGE_SIZE as usize;

/// Base virtual address of the PML4 table
pub const PML4_VADDR: u64 = 0xfffffffffffff000;

/// A pointer to the PML4 table
pub const PML4_PTR: *mut Table<PML4Level> = PML4_VADDR as *mut _;

/// A page table
pub struct Table<L>
where L: TableLevel { /// The entries in the page table.
                      entries: [Entry; N_ENTRIES]
                    , _level_marker: PhantomData<L>
                    }

pub trait TableLevel {}
pub enum PML4Level {}
pub enum PDPTLevel {}
pub enum PDLevel   {}
pub enum PTLevel   {}

impl TableLevel for PML4Level {}
impl TableLevel for PDPTLevel {}
impl TableLevel for PDLevel   {}
impl TableLevel for PTLevel   {}

pub trait Sublevel: TableLevel {
    type Next: TableLevel;
}
impl Sublevel for PML4Level {
    type Next = PDPTLevel;
}
impl Sublevel for PDPTLevel {
    type Next = PDLevel;
}
impl Sublevel for PDLevel {
    type Next = PTLevel;
}

//impl Table<PML4Level> {
//    #[inline] fn get_pt
//}

impl<L: TableLevel> Index<usize> for Table<L> {
    type Output = Entry;

    #[inline] fn index(&self, index: usize) -> &Entry {
        &self.entries[index]
    }
}

impl<L: TableLevel> IndexMut<usize> for Table<L> {
    #[inline] fn index_mut(&mut self, index: usize) -> &mut Entry {
        &mut self.entries[index]
    }
}

impl<L: TableLevel> Table<L>  {

    /// Zeroes out the page table by setting all entries "unused"
    pub fn zero(&mut self) {
        for entry in self.entries.iter_mut() {
            entry.set_unused()
        }
    }

}

impl<L: Sublevel> Table<L> {

    /// Returns the address of the next table, or None if none exists.
    fn next_table_addr(&self, index: usize) -> Option<usize> {
        let flags = self[index].flags();
        if flags.contains(PRESENT) && !flags.contains(HUGE_PAGE) {
            Some(((self as *const _ as usize) << 9) | (index << 12))
        } else {
            None
        }
    }

    /// Returns the next table, or `None` if none exists
    pub fn next_table(&self, index: usize) -> Option<&Table<L::Next>> {
        self.next_table_addr(index)
            .map(|addr| unsafe { &*(addr as *const _) })
    }

    /// Mutably borrows the next table.
    pub fn next_table_mut(&self, index: usize) -> Option<& mut Table<L::Next>> {
        self.next_table_addr(index)
            .map(|addr| unsafe { &mut *(addr as *mut _) })
    }

    /// Returns the next table, creating it if it does not exist.
    pub fn create_next<A>(&mut self, index: usize, alloc: &mut A)
                         -> &mut Table<L::Next>
    where A: FrameAllocator<Frame> {
        if self.next_table(index).is_none() {
            assert!( !self[index].is_huge()
                   , "Couldn't create next table: huge pages not \
                      currently supported.");

            let frame = unsafe {
                alloc.allocate()
                     // TODO: would we rather rewrite this to return
                     // a `Result`? I think so.
                     .expect("Couldn't map page, out of frames!")
            };

            self[index].set(frame, PRESENT | WRITABLE);
            self.next_table_mut(index).unwrap().zero();
        }
        self.next_table_mut(index).unwrap()
    }
}

/// A page table entry.
pub struct Entry(u64);

bitflags! {
    pub flags EntryFlags: u64 {
        /// Present flag.
        /// Must be 1 to map a 2-MByte page or reference a page table.
        const PRESENT =         1 << 0,
        /// Writable flag.
        /// If 0, writes may not be allowed to the 2-MB region controlled
        /// by this entry
        const WRITABLE =        1 << 1
      , const USER_ACCESSIBLE = 1 << 2
      , const WRITE_THROUGH =   1 << 3
      , const NO_CACHE =        1 << 4
      , const ACCESSED =        1 << 5
      , const DIRTY =           1 << 6
      , const HUGE_PAGE =       1 << 7
      , const GLOBAL =          1 << 8
      , const NO_EXECUTE =      1 << 63
    }
}

impl EntryFlags {
    /// Returns true if this page is huge
    #[inline]
    pub fn is_huge(&self) -> bool {
        self.contains(HUGE_PAGE)
    }

    /// Returns true if this page is present
    #[inline]
    pub fn is_present(&self) -> bool {
        self.contains(PRESENT)
    }
}

impl Entry {

    // TODO: this is one of the worst names I have ever given a thing
    #[inline]
    pub fn do_huge(&self, offset: usize) -> Option<Frame> {
        if self.is_huge() {
            self.get_frame()
                .map(|start_frame| {
                    assert!( start_frame.number as usize % N_ENTRIES == 0
                           , "Start frame must be aligned on a 1GB boundary!");
                    start_frame + offset
                })
        } else {
            None
        }
    }

    /// Returns true if this is an unused entry
    #[inline]
    pub fn is_unused(&self) -> bool {
        self.0 == 0
    }

    /// Sets this entry to be unused
    #[inline]
    pub fn set_unused(&mut self) {
        self.0 = 0;
    }

    /// Returns true if this page is huge
    #[inline]
    pub fn is_huge(&self) -> bool {
        self.flags().is_huge()
    }

    /// Access the entry's bitflags.
    #[inline]
    pub fn flags(&self) -> EntryFlags {
        EntryFlags::from_bits_truncate(self.0)
    }

    /// Returns the frame in memory pointed to by this page table entry.
    pub fn get_frame(&self) -> Option<Frame> {
        if self.flags().is_present() {
            // If the entry is present, mask out bits 12-51 and
            Some(Frame::containing(PAddr::from(self.0 & PML4_VADDR)))
        } else { None }
    }

    pub fn set(&mut self, frame: Frame, flags: EntryFlags) {
        let addr: u64 = frame.base_addr().into();
        assert!(addr & !PML4_VADDR == 0);
        self.0 = addr | flags.bits();
    }

}
<|endoftext|>


<commit_before>//! Heuristics for CNF instances.
use satyrs::cnf::CNF;
use std::f64::NEG_INFINITY;

// K selected heuristically for MOM formula
#[allow(dead_code)]
const MOM_K: i32 = 10;

/// Chooses the literal with the Maximum Occurrence of clauses of minimum size.
/// Specifically, let $f*(x)$ be the number of unresolved smallest clauses containing $x$.
/// Choose $x$ that maximizes $((f&(x)) + f*(-x)) * 2^k + f*(x) * f*(!x)$.
///
/// This method gives preference to selecting literals (and negations) that occur frequently in
/// small clauses.
#[allow(dead_code, unused_variables)]
pub fn mom(cnf: &CNF) {
    unimplemented!();
}

/// One-sided jeroslow-wang heuristic. Counts the number of clauses a literal appears in,
/// weighting smaller clauses more heavily, with the formula
/// $$J(l) = \sum_{\{\omega \in \phi \mid l \in \omega}\} 2^{-|\omega|}.$$
/// In practice, one-sided is faster than two-sided, and this method can be ~30x faster than MOM!
pub fn jw(cnf: &CNF) -> i32 {
    // Can't use max_by because f64 doesn't implement total Ord. Until this works, we'll do it the
    // for loop way.
    let j = |lit_ptr: &i32| -> f64 {
        cnf.occurrences
           .get(lit_ptr)
           .unwrap()
           .iter()
           .fold(0f64,
                 |acc, occ| acc + (2f64).powi(-(cnf.clauses.get(occ).unwrap().len() as i32)))
    };
    // (Alternative functional one-liner for the mess below)
    // *cnf.occurrences.keys().max_by_key(j).unwrap()
    let mut max_j: f64 = NEG_INFINITY;
    let mut max_lit: i32 = -1;
    for lit in cnf.occurrences.keys() {
        let lit_j = j(lit);
        if lit_j > max_j {
            max_j = lit_j;
            max_lit = *lit;
        }
    }
    if max_lit == -1 { panic!("Called heuristic on formula with no occurrences"); }
    max_lit
}

#[cfg(test)]
mod tests {
    extern crate tempfile;

    use std::fs::File;
    use std::io::SeekFrom;
    use satyrs::cnf::parse_dimacs_file;
    use std::io::prelude::*;

    use super::*;

    #[test]
    fn jw_works() {
        let tmpfile = create_tempfile!("
            p cnf 4 4
            1 2 0
            1 3 0
            1 4 0
            -1 2 0
        ");
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        // The heuristic should select 1 as the variable
        // (2 as the literal)
        assert_eq!(jw(&cnf), 2);
    }

    #[test]
    fn jw_works_2() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            1 3 5 0
            2 5 0
            1 4 3 0
            -1 2 0
        ");
        // Now, although 1 occurs several times, 2 occurs the most in unit clauses
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        assert_eq!(jw(&cnf), 4); // I.e.
    }
}
<commit_msg>Use neg_infinity as the lowest jw heuristic value<commit_after>//! Heuristics for CNF instances.
use satyrs::cnf::CNF;

// K selected heuristically for MOM formula
#[allow(dead_code)]
const MOM_K: i32 = 10;

/// Chooses the literal with the Maximum Occurrence of clauses of minimum size.
/// Specifically, let $f*(x)$ be the number of unresolved smallest clauses containing $x$.
/// Choose $x$ that maximizes $((f&(x)) + f*(-x)) * 2^k + f*(x) * f*(!x)$.
///
/// This method gives preference to selecting literals (and negations) that occur frequently in
/// small clauses.
#[allow(dead_code, unused_variables)]
pub fn mom(cnf: &CNF) {
    unimplemented!();
}

/// One-sided jeroslow-wang heuristic. Counts the number of clauses a literal appears in,
/// weighting smaller clauses more heavily, with the formula
/// $$J(l) = \sum_{\{\omega \in \phi \mid l \in \omega}\} 2^{-|\omega|}.$$
/// In practice, one-sided is faster than two-sided, and this method can be ~30x faster than MOM!
pub fn jw(cnf: &CNF) -> i32 {
    // Can't use max_by because f64 doesn't implement total Ord. Until this works, we'll do it the
    // for loop way.
    let j = |lit_ptr: &i32| -> f64 {
        cnf.occurrences
           .get(lit_ptr)
           .unwrap()
           .iter()
           .fold(0f64,
                 |acc, occ| acc + (2f64).powi(-(cnf.clauses.get(occ).unwrap().len() as i32)))
    };
    // (Alternative functional one-liner for the mess below)
    // *cnf.occurrences.keys().max_by_key(j).unwrap()
    let mut max_j: f64 = 0_f64;
    let mut max_lit: i32 = -1;
    for lit in cnf.occurrences.keys() {
        let lit_j = j(lit);
        if lit_j > max_j {
            max_j = lit_j;
            max_lit = *lit;
        }
    }
    if max_lit == -1 {
        panic!("Called heuristic on formula with no occurrences");
    }
    max_lit
}

#[cfg(test)]
mod tests {
    extern crate tempfile;

    use std::fs::File;
    use std::io::SeekFrom;
    use satyrs::cnf::parse_dimacs_file;
    use std::io::prelude::*;

    use super::*;

    #[test]
    fn jw_works() {
        let tmpfile = create_tempfile!("
            p cnf 4 4
            1 2 0
            1 3 0
            1 4 0
            -1 2 0
        ");
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        // The heuristic should select 1 as the variable
        // (2 as the literal)
        assert_eq!(jw(&cnf), 2);
    }

    #[test]
    fn jw_works_2() {
        let tmpfile = create_tempfile!("
            p cnf 5 5
            1 2 0
            1 3 5 0
            2 5 0
            1 4 3 0
            -1 2 0
        ");
        // Now, although 1 occurs several times, 2 occurs the most in unit clauses
        let cnf = parse_dimacs_file(tmpfile).unwrap();
        assert_eq!(jw(&cnf), 4); // I.e.
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "hotload")]
extern crate dynamic_reload;

extern crate sdl2;

//#[cfg(not(feature = "hotload"))]
//extern crate minigame;

#[cfg(feature = "hotload")]
use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, UpdateState};
#[cfg(feature = "hotload")]
use std::rc::Rc;
use std::time::Duration;
use std::thread;
use std::str;
use std::ffi::CString;
use std::ptr;
use std::mem;
use std::path::Path;
use std::cell::RefCell;
use sdl2::image::{LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::pixels::Color as SdlColor;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::render::TextureCreator;
use sdl2::render::Texture as SdlTexture;
use sdl2::video::WindowContext;
#[cfg(not(feature = "hotload"))]
use test_shared::shared_fun;

use spritebatch::SpriteBatch;
use color::Color;
use texture::Texture;
use texturemanager::TextureManager;

pub mod gl {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
use self::gl::types::*;

#[cfg(feature = "hotload")]
struct Plugins {
    plugins: Vec<Rc<Lib>>,
}

#[cfg(feature = "hotload")]
impl Plugins {
    fn add_plugin(&mut self, plugin: &Rc<Lib>) {
        self.plugins.push(plugin.clone());
    }

    fn unload_plugins(&mut self, lib: &Rc<Lib>) {
        for i in (0..self.plugins.len()).rev() {
            if &self.plugins[i] == lib {
                self.plugins.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self, lib: &Rc<Lib>) {
        Self::add_plugin(self, lib);
    }

    // called when a lib needs to be reloaded.
    fn reload_callback(&mut self, state: UpdateState, lib: Option<&Rc<Lib>>) {
        match state {
            UpdateState::Before => Self::unload_plugins(self, lib.unwrap()),
            UpdateState::After => Self::reload_plugin(self, lib.unwrap()),
            UpdateState::ReloadFailed(_) => println!("Failed to reload"),
        }
    }
}

fn find_sdl_gl_driver() -> Option<u32> {
    for (index, item) in sdl2::render::drivers().enumerate() {
        sdl2::log::log(item.name);
        if item.name.contains("opengl") {
            sdl2::log::log("Driver chosen follows");
            sdl2::log::log(item.name);
            return Some(index as u32);
        }
    }
    sdl2::log::log("No OpenGL driver chosen");
    None
}

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];

// Shader sources
#[cfg(any(target_os="android", target_os="ios"))]
fn precision() -> String {
    String::from("precision mediump float;\n")
}

#[cfg(not(any(target_os="android", target_os="ios")))]
fn precision() -> String {
    String::from("")
}

static VS_SRC: &'static str = "\n\
    attribute vec2 position;\n\
    varying vec4 color;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
       color = vec4(1.0, 1.0, 1.0, 1.0);\n\
       gl_PointSize = 1.0;\n\
    }";

static FS_SRC: &'static str = "\n\
    varying vec4 color;\n\
    void main() {\n\
       gl_FragColor = color;\n\
    }";

pub fn foo() {

}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::new(src.as_bytes()).unwrap();
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader,
                                 len,
                                 ptr::null_mut(),
                                 buf.as_mut_ptr() as *mut GLchar);
            panic!("{}",
                   str::from_utf8(&buf)
                       .ok()
                       .expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    unsafe {
        let program = gl::CreateProgram();
        gl::AttachShader(program, vs);
        gl::AttachShader(program, fs);
        gl::LinkProgram(program);
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program,
                                  len,
                                  ptr::null_mut(),
                                  buf.as_mut_ptr() as *mut GLchar);
            panic!("{}",
                   str::from_utf8(&buf)
                       .ok()
                       .expect("ProgramInfoLog not valid utf8"));
        }
        program
    }
}

#[cfg(feature = "hotload")]
fn plugin_load<'a>() -> (Plugins, DynamicReload<'a>) {
    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);
    let mut plugs = Plugins { plugins: Vec::new() };

    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return (plugs, reload_handler);
        }
    }

    (plugs, reload_handler)
}

#[cfg(not(feature = "hotload"))]
fn plugin_load() -> (i32, i32) {
    (0, 0)
}

#[cfg(feature = "hotload")]
fn plugin_update<'a>(mut plugs: &mut Plugins, mut reload_handler: &mut DynamicReload<'a>) {
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> =
                unsafe { plugs.plugins[0].lib.get(b"shared_fun\0").unwrap() };

            println!("Value {}", fun());
        }
}

#[cfg(not(feature = "hotload"))]
fn plugin_update(mut plugs: &mut i32, mut reload_handler: &mut i32) {
    println!("Value {}", shared_fun());
}

//#[cfg(feature = "hotload")]
pub fn run_loop() {
    let (mut plugs, mut reload_handler) = plugin_load();
    /*
    let mut plugs = Plugins { plugins: Vec::new() };

    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);
    */
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem
        .window("rust-sdl2 demo: Video", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    sdl2::log::log("Looking for OpenGL drivers");
    let mut canvas = window
    .into_canvas()
    .index(find_sdl_gl_driver().unwrap())
    .build()
    .unwrap();

    sdl2::log::log("Loading GL extensions");
    gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const _);
    sdl2::log::log("Setting current GL context");
    canvas.window().gl_set_context_to_current();

    // Create GLSL shaders
    sdl2::log::log("Compiling vertex shader");
    let vs_src = precision()+VS_SRC;
    let vs = compile_shader(&vs_src, gl::VERTEX_SHADER);
    sdl2::log::log("Compiling fragment shader");
    let fs_src = precision()+FS_SRC;
    let fs = compile_shader(&fs_src, gl::FRAGMENT_SHADER);
    sdl2::log::log("Linking shaders");
    let program = link_program(vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Use shader program
        gl::UseProgram(program);

        //let col_attr = gl::GetAttribLocation(program, CString::new("color").unwrap().as_ptr());

        // Specify the layout of the vertex data
        let pos_attr = gl::GetAttribLocation(program, CString::new("position").unwrap().as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint,
                                2,
                                gl::FLOAT,
                                gl::FALSE as GLboolean,
                                0,
                                mem::transmute(&VERTEX_DATA[0]));
    }

    let mut event_pump = sdl_context.event_pump().unwrap();

    /*
    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return;
        }
    }
    */

    let texture_creator = canvas.texture_creator();
    let mut tm = TextureManager::new(&texture_creator);
    tm.load(String::from("wabbit"), Path::new("assets/wabbit_alpha.png"));
    let wabbit = tm.get(String::from("wabbit"));

    //
    // While this is running (printing a number) change return value in file src/test_shared.rs
    // build the project with cargo build and notice that this code will now return the new value
    //
    'running: loop {
        plugin_update(&mut plugs, &mut reload_handler);

        /*
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> =
                unsafe { plugs.plugins[0].lib.get(b"shared_fun\0").unwrap() };

            println!("Value {}", fun());
        }
        */

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => break 'running,
                _ => {}
            }
        }

        canvas.set_draw_color(SdlColor::RGB(255, 0, 0));
        canvas.clear();

        sdl2::log::log("Drawing triangle");
        unsafe {
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }

        {
            let mut sb = SpriteBatch::new(&canvas);
            sb.draw(&wabbit, None, None, None, None, 0.0, None, Color::white(), 0.0);
        }

        canvas.present();

        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
        // The rest of the game loop goes here...

        // Wait for 0.5 sec
        thread::sleep(Duration::from_millis(500));
    }

     // Cleanup
    unsafe {
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        gl::DeleteBuffers(1, &vbo);
    }
}
<commit_msg>Fixed passing reference to TextureCreator to TextureManager<commit_after>#[cfg(feature = "hotload")]
extern crate dynamic_reload;

extern crate sdl2;

//#[cfg(not(feature = "hotload"))]
//extern crate minigame;

#[cfg(feature = "hotload")]
use dynamic_reload::{DynamicReload, Lib, Symbol, Search, PlatformName, UpdateState};
#[cfg(feature = "hotload")]
use std::rc::Rc;
use std::time::Duration;
use std::thread;
use std::str;
use std::ffi::CString;
use std::ptr;
use std::mem;
use std::path::Path;
use std::cell::RefCell;
use sdl2::image::{LoadTexture, INIT_PNG, INIT_JPG};
use sdl2::pixels::Color as SdlColor;
use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::render::TextureCreator;
use sdl2::render::Texture as SdlTexture;
use sdl2::video::WindowContext;
#[cfg(not(feature = "hotload"))]
use test_shared::shared_fun;

use spritebatch::SpriteBatch;
use color::Color;
use texture::Texture;
use texturemanager::TextureManager;

pub mod gl {
    include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
}
use self::gl::types::*;

#[cfg(feature = "hotload")]
struct Plugins {
    plugins: Vec<Rc<Lib>>,
}

#[cfg(feature = "hotload")]
impl Plugins {
    fn add_plugin(&mut self, plugin: &Rc<Lib>) {
        self.plugins.push(plugin.clone());
    }

    fn unload_plugins(&mut self, lib: &Rc<Lib>) {
        for i in (0..self.plugins.len()).rev() {
            if &self.plugins[i] == lib {
                self.plugins.swap_remove(i);
            }
        }
    }

    fn reload_plugin(&mut self, lib: &Rc<Lib>) {
        Self::add_plugin(self, lib);
    }

    // called when a lib needs to be reloaded.
    fn reload_callback(&mut self, state: UpdateState, lib: Option<&Rc<Lib>>) {
        match state {
            UpdateState::Before => Self::unload_plugins(self, lib.unwrap()),
            UpdateState::After => Self::reload_plugin(self, lib.unwrap()),
            UpdateState::ReloadFailed(_) => println!("Failed to reload"),
        }
    }
}

fn find_sdl_gl_driver() -> Option<u32> {
    for (index, item) in sdl2::render::drivers().enumerate() {
        sdl2::log::log(item.name);
        if item.name.contains("opengl") {
            sdl2::log::log("Driver chosen follows");
            sdl2::log::log(item.name);
            return Some(index as u32);
        }
    }
    sdl2::log::log("No OpenGL driver chosen");
    None
}

// Vertex data
static VERTEX_DATA: [GLfloat; 6] = [0.0, 0.5, 0.5, -0.5, -0.5, -0.5];

// Shader sources
#[cfg(any(target_os="android", target_os="ios"))]
fn precision() -> String {
    String::from("precision mediump float;\n")
}

#[cfg(not(any(target_os="android", target_os="ios")))]
fn precision() -> String {
    String::from("")
}

static VS_SRC: &'static str = "\n\
    attribute vec2 position;\n\
    varying vec4 color;\n\
    void main() {\n\
       gl_Position = vec4(position, 0.0, 1.0);\n\
       color = vec4(1.0, 1.0, 1.0, 1.0);\n\
       gl_PointSize = 1.0;\n\
    }";

static FS_SRC: &'static str = "\n\
    varying vec4 color;\n\
    void main() {\n\
       gl_FragColor = color;\n\
    }";

pub fn foo() {

}

fn compile_shader(src: &str, ty: GLenum) -> GLuint {
    let shader;
    unsafe {
        shader = gl::CreateShader(ty);
        // Attempt to compile the shader
        let c_str = CString::new(src.as_bytes()).unwrap();
        gl::ShaderSource(shader, 1, &c_str.as_ptr(), ptr::null());
        gl::CompileShader(shader);

        // Get the compile status
        let mut status = gl::FALSE as GLint;
        gl::GetShaderiv(shader, gl::COMPILE_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len = 0;
            gl::GetShaderiv(shader, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetShaderInfoLog(shader,
                                 len,
                                 ptr::null_mut(),
                                 buf.as_mut_ptr() as *mut GLchar);
            panic!("{}",
                   str::from_utf8(&buf)
                       .ok()
                       .expect("ShaderInfoLog not valid utf8"));
        }
    }
    shader
}

fn link_program(vs: GLuint, fs: GLuint) -> GLuint {
    unsafe {
        let program = gl::CreateProgram();
        gl::AttachShader(program, vs);
        gl::AttachShader(program, fs);
        gl::LinkProgram(program);
        // Get the link status
        let mut status = gl::FALSE as GLint;
        gl::GetProgramiv(program, gl::LINK_STATUS, &mut status);

        // Fail on error
        if status != (gl::TRUE as GLint) {
            let mut len: GLint = 0;
            gl::GetProgramiv(program, gl::INFO_LOG_LENGTH, &mut len);
            let mut buf = Vec::with_capacity(len as usize);
            buf.set_len((len as usize) - 1); // subtract 1 to skip the trailing null character
            gl::GetProgramInfoLog(program,
                                  len,
                                  ptr::null_mut(),
                                  buf.as_mut_ptr() as *mut GLchar);
            panic!("{}",
                   str::from_utf8(&buf)
                       .ok()
                       .expect("ProgramInfoLog not valid utf8"));
        }
        program
    }
}

#[cfg(feature = "hotload")]
fn plugin_load<'a>() -> (Plugins, DynamicReload<'a>) {
    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);
    let mut plugs = Plugins { plugins: Vec::new() };

    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return (plugs, reload_handler);
        }
    }

    (plugs, reload_handler)
}

#[cfg(not(feature = "hotload"))]
fn plugin_load() -> (i32, i32) {
    (0, 0)
}

#[cfg(feature = "hotload")]
fn plugin_update<'a>(mut plugs: &mut Plugins, mut reload_handler: &mut DynamicReload<'a>) {
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> =
                unsafe { plugs.plugins[0].lib.get(b"shared_fun\0").unwrap() };

            println!("Value {}", fun());
        }
}

#[cfg(not(feature = "hotload"))]
fn plugin_update(mut plugs: &mut i32, mut reload_handler: &mut i32) {
    println!("Value {}", shared_fun());
}

//#[cfg(feature = "hotload")]
pub fn run_loop() {
    let (mut plugs, mut reload_handler) = plugin_load();
    /*
    let mut plugs = Plugins { plugins: Vec::new() };

    // Setup the reload handler. A temporary directory will be created inside the target/debug
    // where plugins will be loaded from. That is because on some OS:es loading a shared lib
    // will lock the file so we can't overwrite it so this works around that issue.
    let mut reload_handler = DynamicReload::new(Some(vec!["target/debug"]),
                                                Some("target/debug"),
                                                Search::Default);
    */
    let sdl_context = sdl2::init().unwrap();
    let video_subsystem = sdl_context.video().unwrap();

    let window = video_subsystem
        .window("rust-sdl2 demo: Video", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    sdl2::log::log("Looking for OpenGL drivers");
    let mut canvas = window
    .into_canvas()
    .index(find_sdl_gl_driver().unwrap())
    .build()
    .unwrap();

    sdl2::log::log("Loading GL extensions");
    gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const _);
    sdl2::log::log("Setting current GL context");
    canvas.window().gl_set_context_to_current();

    // Create GLSL shaders
    sdl2::log::log("Compiling vertex shader");
    let vs_src = precision()+VS_SRC;
    let vs = compile_shader(&vs_src, gl::VERTEX_SHADER);
    sdl2::log::log("Compiling fragment shader");
    let fs_src = precision()+FS_SRC;
    let fs = compile_shader(&fs_src, gl::FRAGMENT_SHADER);
    sdl2::log::log("Linking shaders");
    let program = link_program(vs, fs);

    let mut vao = 0;
    let mut vbo = 0;

    unsafe {
        // Use shader program
        gl::UseProgram(program);

        //let col_attr = gl::GetAttribLocation(program, CString::new("color").unwrap().as_ptr());

        // Specify the layout of the vertex data
        let pos_attr = gl::GetAttribLocation(program, CString::new("position").unwrap().as_ptr());
        gl::EnableVertexAttribArray(pos_attr as GLuint);
        gl::VertexAttribPointer(pos_attr as GLuint,
                                2,
                                gl::FLOAT,
                                gl::FALSE as GLboolean,
                                0,
                                mem::transmute(&VERTEX_DATA[0]));
    }

    let mut event_pump = sdl_context.event_pump().unwrap();

    /*
    // test_shared is generated in build.rs
    match reload_handler.add_library("test_shared", PlatformName::Yes) {
        Ok(lib) => plugs.add_plugin(&lib),
        Err(e) => {
            println!("Unable to load dynamic lib, err {:?}", e);
            return;
        }
    }
    */

    let texture_creator = canvas.texture_creator();
    let mut tm = TextureManager::new(&texture_creator);
    tm.load(String::from("wabbit"), Path::new("assets/wabbit_alpha.png"));
    let wabbit = tm.get(&String::from("wabbit"));

    //
    // While this is running (printing a number) change return value in file src/test_shared.rs
    // build the project with cargo build and notice that this code will now return the new value
    //
    'running: loop {
        plugin_update(&mut plugs, &mut reload_handler);

        /*
        reload_handler.update(Plugins::reload_callback, &mut plugs);

        if plugs.plugins.len() > 0 {
            // In a real program you want to cache the symbol and not do it every time if your
            // application is performance critical
            let fun: Symbol<extern "C" fn() -> i32> =
                unsafe { plugs.plugins[0].lib.get(b"shared_fun\0").unwrap() };

            println!("Value {}", fun());
        }
        */

        for event in event_pump.poll_iter() {
            match event {
                Event::Quit { .. } |
                Event::KeyDown { keycode: Some(Keycode::Escape), .. } => break 'running,
                _ => {}
            }
        }

        canvas.set_draw_color(SdlColor::RGB(255, 0, 0));
        canvas.clear();

        sdl2::log::log("Drawing triangle");
        unsafe {
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
        }

        {
            let mut sb = SpriteBatch::new(&canvas);
            sb.draw(&wabbit, None, None, None, None, 0.0, None, Color::white(), 0.0);
        }

        canvas.present();

        ::std::thread::sleep(Duration::new(0, 1_000_000_000u32 / 60));
        // The rest of the game loop goes here...

        // Wait for 0.5 sec
        thread::sleep(Duration::from_millis(500));
    }

     // Cleanup
    unsafe {
        gl::DeleteProgram(program);
        gl::DeleteShader(fs);
        gl::DeleteShader(vs);
        gl::DeleteBuffers(1, &vbo);
    }
}
<|endoftext|>


<commit_before>
<commit_msg>First pass at `OptionFromResultL`.<commit_after>//! These lenticuloids deal with Rust's basic error-handling types: `Option`
//! and `Result`.
use std::marker::PhantomData;
use std::fmt::{self, Debug, Formatter};
use super::{Iso, Lens, Lenticuloid, Prism};

/// A lenticuloid that converts between `Option`s and `Result`s in a
/// left-biased fashion.
pub struct OptionFromResultL<A, B, C> {
  phantom_ro: PhantomData<Fn(Result<A, B>) -> Option<A>>,
  phantom_or: PhantomData<Fn(Option<C>) -> Result<C, B>>,
}

impl<A, B, C> OptionFromResultL<A, B, C> {
  #[inline]
  pub fn mk() -> Self {
    OptionFromResultL {
      phantom_ro: PhantomData,
      phantom_or: PhantomData,
    }
  }
}

impl<A, B, C> Debug for OptionFromResultL<A, B, C> {
  fn fmt(&self, fm: &mut Formatter) -> fmt::Result {
    fm.debug_struct("OptionFromResultL")
      .field("phantom_ro", &self.phantom_ro)
      .field("phantom_or", &self.phantom_or)
      .finish()
  }
}

impl<A, B, C> Clone for OptionFromResultL<A, B, C> {
  #[inline]
  fn clone(&self) -> Self { *self }

  #[inline]
  fn clone_from(&mut self, source: &Self) { *self = *source; }
}

impl<A, B, C> Copy for OptionFromResultL<A, B, C> {}

impl<A, B, C> Default for OptionFromResultL<A, B, C> {
  #[inline]
  fn default() -> Self { Self::mk() }
}

impl<A, B, C> Lenticuloid for OptionFromResultL<A, B, C> {
  type InitialSource = Result<A, B>;

  type InitialTarget = Option<A>;

  type FinalSource = Result<C, B>;

  type FinalTarget = Option<C>;
}

impl<A, C> Lens for OptionFromResultL<A, (), C> {
  fn get(&self, v: Self::InitialSource) -> Self::InitialTarget {
    match v {
      Ok(a) => Some(a),
      Err(()) => None,
    }
  }

  fn set(&self, _v: Self::InitialSource, x: Self::FinalTarget) -> Self::FinalSource {
    match x {
      Some(a) => Ok(a),
      None => Err(()),
    }
  }

  fn modify<F>(&self, v: Self::InitialSource, f: F) -> Self::FinalSource
    where F: FnOnce(Self::InitialTarget) -> Self::FinalTarget {
    match f(match v {
      Ok(a) => Some(a),
      Err(()) => None,
    }) {
      Some(b) => Ok(b),
      None => Err(()),
    }
  }
}

impl<A, C> Prism for OptionFromResultL<A, (), C> {
  fn try_get(&self, v: Self::InitialSource) -> Result<Self::InitialTarget, Self::FinalSource> {
    Ok(match v {
      Ok(a) => Some(a),
      Err(()) => None,
    })
  }

  fn inject(&self, v: Self::FinalTarget) -> Self::FinalSource {
    match v {
      Some(a) => Ok(a),
      None => Err(()),
    }
  }
}

impl<A, C> Iso for OptionFromResultL<A, (), C> {}
<|endoftext|>


<commit_before>use std::fmt;
use std::io;
use std::string::FromUtf8Error;

#[derive(Debug)]
pub enum Word2VecError {
    Io(io::Error),
    Decode(FromUtf8Error),
    WrongHeader,
}

impl fmt::Display for Word2VecError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Word2VecError::Io(ref err) => write!(f, "IO error: {}", err),
            Word2VecError::Decode(ref err) => write!(f, "Decode error: {}", err),
            Word2VecError::WrongHeader => write!(f, "Wrong header length."),
        }
    }
}

impl From<io::Error> for Word2VecError {
    fn from(err: io::Error) -> Word2VecError {
        Word2VecError::Io(err)
    }
}

impl From<FromUtf8Error> for Word2VecError {
    fn from(err: FromUtf8Error) -> Word2VecError {
        Word2VecError::Decode(err)
    }
}
<commit_msg>Implement std::error::Error for error::Word2VecError<commit_after>use std::error;
use std::fmt;
use std::io;
use std::string::FromUtf8Error;

/// Common error type for errors  concerning loading and processing binary word vectors
///
/// This error type mostly wraps I/O and encoding errors, but also adds crate-specific error
/// variants.
#[derive(Debug)]
pub enum Word2VecError {
    Io(io::Error),
    Decode(FromUtf8Error),
    WrongHeader,
}

impl error::Error for Word2VecError {
    fn description(&self) -> &str {
        match *self {
            Word2VecError::Decode(ref err) => err.description(),
            Word2VecError::Io(ref err) => err.description(),
            Word2VecError::WrongHeader => "Wrong header format",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Word2VecError::Decode(ref e) => e.cause(),
            Word2VecError::Io(ref e) => e.cause(),
            _ => None,
        }
    }
}

impl fmt::Display for Word2VecError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Word2VecError::Io(ref err) => write!(f, "IO error: {}", err),
            Word2VecError::Decode(ref err) => write!(f, "Decode error: {}", err),
            Word2VecError::WrongHeader => write!(f, "Wrong header length."),
        }
    }
}

impl From<io::Error> for Word2VecError {
    fn from(err: io::Error) -> Word2VecError {
        Word2VecError::Io(err)
    }
}

impl From<FromUtf8Error> for Word2VecError {
    fn from(err: FromUtf8Error) -> Word2VecError {
        Word2VecError::Decode(err)
    }
}

<|endoftext|>


<commit_before>extern crate centralgithook;
extern crate git2;
extern crate tempdir;

use centralgithook::migrate;
use std::fs::File;
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use tempdir::TempDir;

pub fn _oid_to_sha1(oid: &[u8]) -> String
{
    oid.iter()
        .fold(Vec::new(), |mut acc, x| {
            acc.push(format!("{0:>02x}", x));
            acc
        })
        .concat()
}

pub struct TestHost
{
    td: TempDir,
}

impl TestHost
{
    pub fn new() -> Self
    {
        TestHost { td: TempDir::new("test_host").expect("folder test_host should be created") }
    }
}

impl TestHost {
    pub fn repo_dir(&self, module: &str) -> PathBuf { self.td.path().join(&Path::new(module)) }
}

impl migrate::RepoHost for TestHost
{
    fn create_project(&self, module: &str) -> Result<(), git2::Error>
    {
        println!("TestHost: create_project {} in {:?}",
                 module,
                 self.repo_dir(module));
        git2::Repository::init_bare(&self.repo_dir(module)).expect("TestHost: init_bare failed");
        // empty_commit(&repo);
        Ok(())
    }

    fn remote_url(&self, module_path: &str) -> String
    {
        self.td.path().join(&module_path).to_string_lossy().to_string()
    }
}

pub struct TestRepo
{
    pub repo: git2::Repository,
    pub path: PathBuf,
    pub shell: migrate::Shell,
}

impl TestRepo
{
    pub fn new(path: &Path) -> Self
    {
        TestRepo {
            repo: git2::Repository::init(path).expect("init should succeed"),
            path: path.to_path_buf(),
            shell: migrate::Shell { cwd: path.to_path_buf() },
        }
    }

    pub fn commit(&self, message: &str) -> String
    {
        self.shell.command(&format!("git commit -m \"{}\"", message));
        return _oid_to_sha1(self.repo.revparse_single("HEAD").expect("no HEAD").id().as_bytes());
    }

    pub fn add(&self, filename: &str)
    {
        let f = self.path.join(filename);
        let parent_dir = f.parent().expect("need to get parent");
        fs::create_dir_all(parent_dir).expect("create directories");

        let mut file = File::create(&f).expect("create file");
        file.write_all("test content".as_bytes()).expect("write to file");
        self.shell.command(&format!("git add {}", filename));
    }
}

// fn empty_commit(repo: &git2::Repository) {
//     let sig = git2::Signature::now("foo", "bar").expect("created signature");
//     repo.commit(
//         Some("HEAD"),
//         &sig,
//         &sig,
//         "initial",
//         &repo.find_tree(repo.treebuilder(None).expect("cannot create empty tree")
// .write().expect("cannot write empty tree")).expect("cannot find empty
// tree"),
//         &[]
//     ).expect("cannot commit empty");
// }
<commit_msg>git config<commit_after>extern crate centralgithook;
extern crate git2;
extern crate tempdir;

use centralgithook::migrate;
use std::fs::File;
use std::fs;
use std::io::Write;
use std::path::{Path, PathBuf};
use tempdir::TempDir;

pub fn _oid_to_sha1(oid: &[u8]) -> String
{
    oid.iter()
        .fold(Vec::new(), |mut acc, x| {
            acc.push(format!("{0:>02x}", x));
            acc
        })
        .concat()
}

pub struct TestHost
{
    td: TempDir,
}

impl TestHost
{
    pub fn new() -> Self
    {
        TestHost { td: TempDir::new("test_host").expect("folder test_host should be created") }
    }
}

impl TestHost {
    pub fn repo_dir(&self, module: &str) -> PathBuf { self.td.path().join(&Path::new(module)) }
}

impl migrate::RepoHost for TestHost
{
    fn create_project(&self, module: &str) -> Result<(), git2::Error>
    {
        println!("TestHost: create_project {} in {:?}",
                 module,
                 self.repo_dir(module));
        git2::Repository::init_bare(&self.repo_dir(module)).expect("TestHost: init_bare failed");
        // empty_commit(&repo);
        Ok(())
    }

    fn remote_url(&self, module_path: &str) -> String
    {
        self.td.path().join(&module_path).to_string_lossy().to_string()
    }
}

pub struct TestRepo
{
    pub repo: git2::Repository,
    pub path: PathBuf,
    pub shell: migrate::Shell,
}

impl TestRepo
{
    pub fn new(path: &Path) -> Self
    {
        let tr = TestRepo {
            repo: git2::Repository::init(path).expect("init should succeed"),
            path: path.to_path_buf(),
            shell: migrate::Shell { cwd: path.to_path_buf() },
        };
        tr.shell.command("git config user.name test");
        tr.shell.command("git config user.email test@test.com");
        return tr;
    }

    pub fn commit(&self, message: &str) -> String
    {
        self.shell.command(&format!("git commit -m \"{}\"", message));
        return _oid_to_sha1(self.repo.revparse_single("HEAD").expect("no HEAD").id().as_bytes());
    }

    pub fn add(&self, filename: &str)
    {
        let f = self.path.join(filename);
        let parent_dir = f.parent().expect("need to get parent");
        fs::create_dir_all(parent_dir).expect("create directories");

        let mut file = File::create(&f).expect("create file");
        file.write_all("test content".as_bytes()).expect("write to file");
        self.shell.command(&format!("git add {}", filename));
    }
}

// fn empty_commit(repo: &git2::Repository) {
//     let sig = git2::Signature::now("foo", "bar").expect("created signature");
//     repo.commit(
//         Some("HEAD"),
//         &sig,
//         &sig,
//         "initial",
//         &repo.find_tree(repo.treebuilder(None).expect("cannot create empty tree")
// .write().expect("cannot write empty tree")).expect("cannot find empty
// tree"),
//         &[]
//     ).expect("cannot commit empty");
// }
<|endoftext|>