<commit_before>extern crate rustc_serialize;
extern crate dylib;

use std::env;
use std::borrow::ToOwned;
use std::collections::BTreeMap;
use core::workspaces::Workspaces;
use window_system::*;
use window_manager::WindowManager;
use handlers::{ KeyHandler, MouseHandler, ManageHook, StartupHook, LogHook };
use handlers::default::{ exit, restart, start_terminal };
use layout::{ Layout, TallLayout };

use std::mem;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::fs::{ read_dir, create_dir_all };
use std::process::Command;
use std::process::Child;
use self::dylib::DynamicLibrary;
use std::rc::Rc;
use std::sync::RwLock;
use std::thread::spawn;
use std::path::PathBuf;
use std::path::Path;
use std::fs::metadata;

pub struct GeneralConfig {
    /// Whether focus follows mouse movements or
    /// only click events and keyboard movements.
    pub focus_follows_mouse: bool,
    /// Border color for focused windows.
    pub focus_border_color: u32,
    /// Border color for unfocused windows.
    pub border_color: u32,
    /// Border width. This is the same for both, focused and unfocused.
    pub border_width: u32,
    /// Default terminal to start
    pub terminal: (String, String),
    /// Keybind for the terminal
    /// Path to the logfile
    pub logfile: String,
    /// Default tags for workspaces
    pub tags: Vec<String>,
    /// Default launcher application
    pub launcher: String,
    pub mod_mask: KeyModifiers,
    pub pipes: Vec<Rc<RwLock<Child>>>,
    pub layout: Box<Layout>
}

impl Clone for GeneralConfig {
    fn clone(&self) -> GeneralConfig {
        GeneralConfig {
            focus_follows_mouse: self.focus_follows_mouse,
            focus_border_color: self.focus_border_color,
            border_color: self.border_color,
            border_width: self.border_width,
            terminal: self.terminal.clone(),
            logfile: self.logfile.clone(),
            tags: self.tags.clone(),
            launcher: self.launcher.clone(),
            mod_mask: self.mod_mask.clone(),
            pipes: self.pipes.clone(),
            layout: self.layout.copy()
        }
    }
}

pub struct InternalConfig {
    pub library: Option<DynamicLibrary>,
    pub key_handlers: BTreeMap<KeyCommand, KeyHandler>,
    pub mouse_handlers: BTreeMap<MouseCommand, MouseHandler>,
    pub manage_hook: ManageHook,
    pub startup_hook: StartupHook,
    pub loghook: Option<LogHook>,
    pub wtftw_dir: String,
}

impl InternalConfig {
    pub fn new(manage_hook: ManageHook, startup_hook: StartupHook, home: String) -> InternalConfig {
        InternalConfig {
            library: None,
            key_handlers: BTreeMap::new(),
            mouse_handlers: BTreeMap::new(),
            manage_hook: manage_hook,
            startup_hook: startup_hook,
            loghook: None,
            wtftw_dir: format!("{}/.wtftw", home)
        }
    }
}

/// Common configuration options for the window manager.
pub struct Config {
    pub general: GeneralConfig,
    pub internal: InternalConfig
}

impl Config {
    /// Create the Config from a json file
    pub fn initialize() -> Config {
        let home = env::home_dir().unwrap_or(PathBuf::from("./")).into_os_string().into_string().unwrap();
        // Default version of the config, for fallback
        let general_config =
            GeneralConfig {
                focus_follows_mouse: true,
                focus_border_color:  0x00B6FFB0,
                border_color:        0x00444444,
                border_width:        2,
                mod_mask:            MOD1MASK,
                terminal:            ("xterm".to_owned(), "".to_owned()),
                logfile:             format!("{}/.wtftw.log", home),
                tags:                vec!(
                    "1: term".to_owned(),
                    "2: web".to_owned(),
                    "3: code".to_owned(),
                    "4: media".to_owned()),
                launcher:            "dmenu_run".to_owned(),
                pipes:               Vec::new(),
                layout:              Box::new(TallLayout { num_master: 1, increment_ratio: 0.3/100.0, ratio: 0.5 }),
            };

        let internal_config = InternalConfig::new(
            Box::new(move |a, _, _| a.clone()),
            Box::new(move |a, _, _| a.clone()),
            //Box::new(Config::default_manage_hook),
            //Box::new(Config::default_startup_hook),
            home);

        Config {
            general: general_config,
            internal: internal_config
        }
    }

    pub fn default_manage_hook(m: Workspaces, _: Rc<WindowSystem>, _: Window) -> Workspaces {
        m
    }

    pub fn default_startup_hook(m: WindowManager, _: Rc<WindowSystem>, _: &Config) -> WindowManager {
        m
    }

    pub fn default_configuration(&mut self, w: &WindowSystem) {
        let mod_mask = self.general.mod_mask.clone();
        self.add_key_handler(w.get_keycode_from_string("Return"), mod_mask | SHIFTMASK,
            Box::new(|m, ws, c| start_terminal(m, ws, c)));
        self.add_key_handler(w.get_keycode_from_string("q"), mod_mask,
            Box::new(|m, ws, c| restart(m, ws, c)));
        self.add_key_handler(w.get_keycode_from_string("q"), mod_mask | SHIFTMASK,
            Box::new(|m, ws, c| exit(m, ws, c)));
    }

    pub fn get_mod_mask(&self) -> KeyModifiers {
        self.general.mod_mask.clone()
    }

    pub fn add_key_handler(&mut self, key: u64, mask: KeyModifiers, keyhandler: KeyHandler) {
        self.internal.key_handlers.insert(KeyCommand::new(key, mask), keyhandler);
    }

    pub fn add_mouse_handler(&mut self, button: MouseButton, mask: KeyModifiers,
                             mousehandler: MouseHandler) {
        self.internal.mouse_handlers.insert(MouseCommand::new(button, mask), mousehandler);
    }

    pub fn set_manage_hook(&mut self, hook: ManageHook) {
        self.internal.manage_hook = hook;
    }

    pub fn set_log_hook(&mut self, hook: LogHook) {
        self.internal.loghook = Some(hook);
    }

    pub fn compile_and_call(&mut self, m: &mut WindowManager, w: &WindowSystem) {
        let toml = format!("{}/Cargo.toml", self.internal.wtftw_dir.clone());

        if !path_exists(&self.internal.wtftw_dir.clone()) {
            match create_dir_all(Path::new(&self.internal.wtftw_dir.clone())) {
                Ok(()) => (),
                Err(e) => panic!(format!("mkdir: {} failed with error {}", self.internal.wtftw_dir.clone(), e))
            }
        }

        if path_exists(&toml.clone()) {
            let file = File::create(Path::new(&toml).as_os_str());
            file.unwrap().write("[project]\n\
                                     name = \"config\"\n\
                                     version = \"0.0.0\"\n\
                                     authors = [\"wtftw\"]\n\n\
                                     [dependencies.wtftw_contrib]
                                     git = \"https://github.com/Kintaro/wtftw-contrib.git\"\n
                                     [dependencies.wtftw]\n\
                                     git = \"https://github.com/Kintaro/wtftw.git\"\n\n\
                                     [lib]\n\
                                     name = \"config\"\n\
                                     crate-type = [\"dylib\"]".as_bytes()).unwrap();
        }

        let config_source = format!("{}/src/config.rs", self.internal.wtftw_dir.clone());
        if path_exists(&config_source) && self.compile() {
            self.call(m, w)
        } else {
            self.default_configuration(w);
        }
    }

    pub fn compile(&self) -> bool {
        info!("updating dependencies");
        Command::new("cargo")
            .current_dir(&Path::new(&self.internal.wtftw_dir.clone()))
            .arg("update")
            .env("RUST_LOG", "none")
            .output().unwrap();
        info!("compiling config module");
        let output = Command::new("cargo")
            .current_dir(&Path::new(&self.internal.wtftw_dir.clone()))
            .arg("build")//.arg("--release")
            .env("RUST_LOG", "none")
            .output();

        match output {
            Ok(o) => {
                if o.status.success() {
                    info!("config module compiled");
                    true
                } else {
                    error!("error compiling config module");

                    spawn(move || {
                        Command::new("xmessage").arg("\"error compiling config module. run 'cargo build' in ~/.wtftw to get more info.\"").spawn().unwrap();
                    });
                    false
                }
            },
            Err(err) => {
                error!("error compiling config module");
                spawn(move || {
                    Command::new("xmessage").arg(err.description()).spawn().unwrap();
                });
                false
            }
        }
    }

    pub fn call(&mut self, m: &mut WindowManager, w: &WindowSystem) {
        debug!("looking for config module");
        let mut contents = read_dir(&Path::new(&format!("{}/target/debug", self.internal.wtftw_dir.clone()))).unwrap();
        let libname = contents.find(|x| {
                            match x {
                                &Ok(ref y) => y.path().into_os_string().as_os_str().to_str().unwrap().contains("libconfig"),
                                &Err(_) => false
                            }
        });

        if let Ok(lib) = DynamicLibrary::open(Some(&Path::new(&libname.unwrap().unwrap().path().as_os_str().to_str().unwrap()))) {
            unsafe {
                if let Ok(symbol) = lib.symbol("configure") {
                    let result = mem::transmute::<*mut u8, extern fn(&mut WindowManager,
                                                        &WindowSystem,
                                                        &mut Config)>(symbol);

                    self.internal.library = Some(lib);
                    result(m, w, self);
                } else {
                    error!("Error loading config module")
                }
            }
        }
    }
}

fn path_exists(path: &String) -> bool {
    metadata(path).is_ok()
}
<commit_msg>Fix reversed boolean logic<commit_after>extern crate rustc_serialize;
extern crate dylib;

use std::env;
use std::borrow::ToOwned;
use std::collections::BTreeMap;
use core::workspaces::Workspaces;
use window_system::*;
use window_manager::WindowManager;
use handlers::{ KeyHandler, MouseHandler, ManageHook, StartupHook, LogHook };
use handlers::default::{ exit, restart, start_terminal };
use layout::{ Layout, TallLayout };

use std::mem;
use std::error::Error;
use std::fs::File;
use std::io::Write;
use std::fs::{ read_dir, create_dir_all };
use std::process::Command;
use std::process::Child;
use self::dylib::DynamicLibrary;
use std::rc::Rc;
use std::sync::RwLock;
use std::thread::spawn;
use std::path::PathBuf;
use std::path::Path;
use std::fs::metadata;

pub struct GeneralConfig {
    /// Whether focus follows mouse movements or
    /// only click events and keyboard movements.
    pub focus_follows_mouse: bool,
    /// Border color for focused windows.
    pub focus_border_color: u32,
    /// Border color for unfocused windows.
    pub border_color: u32,
    /// Border width. This is the same for both, focused and unfocused.
    pub border_width: u32,
    /// Default terminal to start
    pub terminal: (String, String),
    /// Keybind for the terminal
    /// Path to the logfile
    pub logfile: String,
    /// Default tags for workspaces
    pub tags: Vec<String>,
    /// Default launcher application
    pub launcher: String,
    pub mod_mask: KeyModifiers,
    pub pipes: Vec<Rc<RwLock<Child>>>,
    pub layout: Box<Layout>
}

impl Clone for GeneralConfig {
    fn clone(&self) -> GeneralConfig {
        GeneralConfig {
            focus_follows_mouse: self.focus_follows_mouse,
            focus_border_color: self.focus_border_color,
            border_color: self.border_color,
            border_width: self.border_width,
            terminal: self.terminal.clone(),
            logfile: self.logfile.clone(),
            tags: self.tags.clone(),
            launcher: self.launcher.clone(),
            mod_mask: self.mod_mask.clone(),
            pipes: self.pipes.clone(),
            layout: self.layout.copy()
        }
    }
}

pub struct InternalConfig {
    pub library: Option<DynamicLibrary>,
    pub key_handlers: BTreeMap<KeyCommand, KeyHandler>,
    pub mouse_handlers: BTreeMap<MouseCommand, MouseHandler>,
    pub manage_hook: ManageHook,
    pub startup_hook: StartupHook,
    pub loghook: Option<LogHook>,
    pub wtftw_dir: String,
}

impl InternalConfig {
    pub fn new(manage_hook: ManageHook, startup_hook: StartupHook, home: String) -> InternalConfig {
        InternalConfig {
            library: None,
            key_handlers: BTreeMap::new(),
            mouse_handlers: BTreeMap::new(),
            manage_hook: manage_hook,
            startup_hook: startup_hook,
            loghook: None,
            wtftw_dir: format!("{}/.wtftw", home)
        }
    }
}

/// Common configuration options for the window manager.
pub struct Config {
    pub general: GeneralConfig,
    pub internal: InternalConfig
}

impl Config {
    /// Create the Config from a json file
    pub fn initialize() -> Config {
        let home = env::home_dir().unwrap_or(PathBuf::from("./")).into_os_string().into_string().unwrap();
        // Default version of the config, for fallback
        let general_config =
            GeneralConfig {
                focus_follows_mouse: true,
                focus_border_color:  0x00B6FFB0,
                border_color:        0x00444444,
                border_width:        2,
                mod_mask:            MOD1MASK,
                terminal:            ("xterm".to_owned(), "".to_owned()),
                logfile:             format!("{}/.wtftw.log", home),
                tags:                vec!(
                    "1: term".to_owned(),
                    "2: web".to_owned(),
                    "3: code".to_owned(),
                    "4: media".to_owned()),
                launcher:            "dmenu_run".to_owned(),
                pipes:               Vec::new(),
                layout:              Box::new(TallLayout { num_master: 1, increment_ratio: 0.3/100.0, ratio: 0.5 }),
            };

        let internal_config = InternalConfig::new(
            Box::new(move |a, _, _| a.clone()),
            Box::new(move |a, _, _| a.clone()),
            //Box::new(Config::default_manage_hook),
            //Box::new(Config::default_startup_hook),
            home);

        Config {
            general: general_config,
            internal: internal_config
        }
    }

    pub fn default_manage_hook(m: Workspaces, _: Rc<WindowSystem>, _: Window) -> Workspaces {
        m
    }

    pub fn default_startup_hook(m: WindowManager, _: Rc<WindowSystem>, _: &Config) -> WindowManager {
        m
    }

    pub fn default_configuration(&mut self, w: &WindowSystem) {
        let mod_mask = self.general.mod_mask.clone();
        self.add_key_handler(w.get_keycode_from_string("Return"), mod_mask | SHIFTMASK,
            Box::new(|m, ws, c| start_terminal(m, ws, c)));
        self.add_key_handler(w.get_keycode_from_string("q"), mod_mask,
            Box::new(|m, ws, c| restart(m, ws, c)));
        self.add_key_handler(w.get_keycode_from_string("q"), mod_mask | SHIFTMASK,
            Box::new(|m, ws, c| exit(m, ws, c)));
    }

    pub fn get_mod_mask(&self) -> KeyModifiers {
        self.general.mod_mask.clone()
    }

    pub fn add_key_handler(&mut self, key: u64, mask: KeyModifiers, keyhandler: KeyHandler) {
        self.internal.key_handlers.insert(KeyCommand::new(key, mask), keyhandler);
    }

    pub fn add_mouse_handler(&mut self, button: MouseButton, mask: KeyModifiers,
                             mousehandler: MouseHandler) {
        self.internal.mouse_handlers.insert(MouseCommand::new(button, mask), mousehandler);
    }

    pub fn set_manage_hook(&mut self, hook: ManageHook) {
        self.internal.manage_hook = hook;
    }

    pub fn set_log_hook(&mut self, hook: LogHook) {
        self.internal.loghook = Some(hook);
    }

    pub fn compile_and_call(&mut self, m: &mut WindowManager, w: &WindowSystem) {
        let toml = format!("{}/Cargo.toml", self.internal.wtftw_dir.clone());

        if !path_exists(&self.internal.wtftw_dir.clone()) {
            match create_dir_all(Path::new(&self.internal.wtftw_dir.clone())) {
                Ok(()) => (),
                Err(e) => panic!(format!("mkdir: {} failed with error {}", self.internal.wtftw_dir.clone(), e))
            }
        }

        if !path_exists(&toml.clone()) {
            let file = File::create(Path::new(&toml).as_os_str());
            file.unwrap().write("[project]\n\
                                     name = \"config\"\n\
                                     version = \"0.0.0\"\n\
                                     authors = [\"wtftw\"]\n\n\
                                     [dependencies.wtftw_contrib]
                                     git = \"https://github.com/Kintaro/wtftw-contrib.git\"\n
                                     [dependencies.wtftw]\n\
                                     git = \"https://github.com/Kintaro/wtftw.git\"\n\n\
                                     [lib]\n\
                                     name = \"config\"\n\
                                     crate-type = [\"dylib\"]".as_bytes()).unwrap();
        }

        let config_source = format!("{}/src/config.rs", self.internal.wtftw_dir.clone());
        if path_exists(&config_source) && self.compile() {
            self.call(m, w)
        } else {
            self.default_configuration(w);
        }
    }

    pub fn compile(&self) -> bool {
        info!("updating dependencies");
        Command::new("cargo")
            .current_dir(&Path::new(&self.internal.wtftw_dir.clone()))
            .arg("update")
            .env("RUST_LOG", "none")
            .output().unwrap();
        info!("compiling config module");
        let output = Command::new("cargo")
            .current_dir(&Path::new(&self.internal.wtftw_dir.clone()))
            .arg("build")//.arg("--release")
            .env("RUST_LOG", "none")
            .output();

        match output {
            Ok(o) => {
                if o.status.success() {
                    info!("config module compiled");
                    true
                } else {
                    error!("error compiling config module");

                    spawn(move || {
                        Command::new("xmessage").arg("\"error compiling config module. run 'cargo build' in ~/.wtftw to get more info.\"").spawn().unwrap();
                    });
                    false
                }
            },
            Err(err) => {
                error!("error compiling config module");
                spawn(move || {
                    Command::new("xmessage").arg(err.description()).spawn().unwrap();
                });
                false
            }
        }
    }

    pub fn call(&mut self, m: &mut WindowManager, w: &WindowSystem) {
        debug!("looking for config module");
        let mut contents = read_dir(&Path::new(&format!("{}/target/debug", self.internal.wtftw_dir.clone()))).unwrap();
        let libname = contents.find(|x| {
                            match x {
                                &Ok(ref y) => y.path().into_os_string().as_os_str().to_str().unwrap().contains("libconfig"),
                                &Err(_) => false
                            }
        });

        if let Ok(lib) = DynamicLibrary::open(Some(&Path::new(&libname.unwrap().unwrap().path().as_os_str().to_str().unwrap()))) {
            unsafe {
                if let Ok(symbol) = lib.symbol("configure") {
                    let result = mem::transmute::<*mut u8, extern fn(&mut WindowManager,
                                                        &WindowSystem,
                                                        &mut Config)>(symbol);

                    self.internal.library = Some(lib);
                    result(m, w, self);
                } else {
                    error!("Error loading config module")
                }
            }
        }
    }
}

fn path_exists(path: &String) -> bool {
    metadata(path).is_ok()
}
<|endoftext|>


<commit_before>//! [Unlock Notification](http://sqlite.org/unlock_notify.html)

#[cfg(feature = "unlock_notify")]
use std::sync::{Condvar, Mutex};
use std::os::raw::c_int;
#[cfg(feature = "unlock_notify")]
use std::os::raw::c_void;

use ffi;

#[cfg(feature = "unlock_notify")]
struct UnlockNotification {
    cond: Condvar,      // Condition variable to wait on
    mutex: Mutex<bool>, // Mutex to protect structure
}

#[cfg(feature = "unlock_notify")]
impl UnlockNotification {
    fn new() -> UnlockNotification {
        UnlockNotification {
            cond: Condvar::new(),
            mutex: Mutex::new(false),
        }
    }

    fn fired(&mut self) {
        *self.mutex.lock().unwrap() = true;
        self.cond.notify_one();
    }

    fn wait(&mut self) -> bool {
        let mut fired = self.mutex.lock().unwrap();
        while !*fired {
            fired = self.cond.wait(fired).unwrap();
        }
        *fired
    }
}

/// This function is an unlock-notify callback
#[cfg(feature = "unlock_notify")]
unsafe extern "C" fn unlock_notify_cb(ap_arg: *mut *mut c_void, n_arg: c_int) {
    use std::slice::from_raw_parts;
    let args = from_raw_parts(ap_arg, n_arg as usize);
    for arg in args {
        let un: &mut UnlockNotification = &mut *(*arg as *mut UnlockNotification);
        un.fired();
    }
}

#[cfg(feature = "unlock_notify")]
pub fn is_locked(db: *mut ffi::sqlite3, rc: c_int) -> bool {
    return rc == ffi::SQLITE_LOCKED_SHAREDCACHE || (rc & 0xFF) == ffi::SQLITE_LOCKED && unsafe {
        ffi::sqlite3_extended_errcode(db)
    }
        == ffi::SQLITE_LOCKED_SHAREDCACHE;
}

/// This function assumes that an SQLite API call (either `sqlite3_prepare_v2()`
/// or `sqlite3_step()`) has just returned `SQLITE_LOCKED`. The argument is the
/// associated database connection.
///
/// This function calls `sqlite3_unlock_notify()` to register for an
/// unlock-notify callback, then blocks until that callback is delivered
/// and returns `SQLITE_OK`. The caller should then retry the failed operation.
///
/// Or, if `sqlite3_unlock_notify()` indicates that to block would deadlock
/// the system, then this function returns `SQLITE_LOCKED` immediately. In
/// this case the caller should not retry the operation and should roll
/// back the current transaction (if any).
#[cfg(feature = "unlock_notify")]
pub fn wait_for_unlock_notify(db: *mut ffi::sqlite3) -> c_int {
    let mut un = UnlockNotification::new();
    /* Register for an unlock-notify callback. */
    let rc = unsafe {
        ffi::sqlite3_unlock_notify(
            db,
            Some(unlock_notify_cb),
            &mut un as *mut UnlockNotification as *mut c_void,
        )
    };
    debug_assert!(
        rc == ffi::SQLITE_LOCKED || rc == ffi::SQLITE_LOCKED_SHAREDCACHE || rc == ffi::SQLITE_OK
    );
    if rc == ffi::SQLITE_OK {
        un.wait();
    }
    rc
}

#[cfg(not(feature = "unlock_notify"))]
pub fn is_locked(_db: *mut ffi::sqlite3, _rc: c_int) -> bool {
    unreachable!()
}

#[cfg(not(feature = "unlock_notify"))]
pub fn wait_for_unlock_notify(_db: *mut ffi::sqlite3) -> c_int {
    unreachable!()
}

#[cfg(feature = "unlock_notify")]
#[cfg(test)]
mod test {
    use std::sync::mpsc::sync_channel;
    use std::thread;
    use std::time;
    use {Connection, OpenFlags, Result, Transaction, TransactionBehavior};

    #[test]
    fn test_unlock_notify() {
        let url = "file::memory:?cache=shared";
        let flags = OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_URI;
        let db1 = Connection::open_with_flags(url, flags).unwrap();
        db1.execute_batch("CREATE TABLE foo (x)").unwrap();
        let (rx, tx) = sync_channel(0);
        let child = thread::spawn(move || {
            let mut db2 = Connection::open_with_flags(url, flags).unwrap();
            let tx2 = Transaction::new(&mut db2, TransactionBehavior::Immediate).unwrap();
            tx2.execute_batch("INSERT INTO foo VALUES (42)").unwrap();
            rx.send(1).unwrap();
            let ten_millis = time::Duration::from_millis(10);
            thread::sleep(ten_millis);
            tx2.commit().unwrap();
        });
        assert_eq!(tx.recv().unwrap(), 1);
        let the_answer: Result<i64> = db1.query_row("SELECT x FROM foo", &[], |r| r.get(0));
        assert_eq!(42i64, the_answer.unwrap());
        child.join().unwrap();
    }
}
<commit_msg>Fix clippy warnings<commit_after>//! [Unlock Notification](http://sqlite.org/unlock_notify.html)

#[cfg(feature = "unlock_notify")]
use std::sync::{Condvar, Mutex};
use std::os::raw::c_int;
#[cfg(feature = "unlock_notify")]
use std::os::raw::c_void;

use ffi;

#[cfg(feature = "unlock_notify")]
struct UnlockNotification {
    cond: Condvar,      // Condition variable to wait on
    mutex: Mutex<bool>, // Mutex to protect structure
}

#[cfg(feature = "unlock_notify")]
impl UnlockNotification {
    fn new() -> UnlockNotification {
        UnlockNotification {
            cond: Condvar::new(),
            mutex: Mutex::new(false),
        }
    }

    fn fired(&mut self) {
        *self.mutex.lock().unwrap() = true;
        self.cond.notify_one();
    }

    fn wait(&mut self) {
        let mut fired = self.mutex.lock().unwrap();
        while !*fired {
            fired = self.cond.wait(fired).unwrap();
        }
    }
}

/// This function is an unlock-notify callback
#[cfg(feature = "unlock_notify")]
unsafe extern "C" fn unlock_notify_cb(ap_arg: *mut *mut c_void, n_arg: c_int) {
    use std::slice::from_raw_parts;
    let args = from_raw_parts(ap_arg, n_arg as usize);
    for arg in args {
        let un: &mut UnlockNotification = &mut *(*arg as *mut UnlockNotification);
        un.fired();
    }
}

#[cfg(feature = "unlock_notify")]
pub fn is_locked(db: *mut ffi::sqlite3, rc: c_int) -> bool {
    rc == ffi::SQLITE_LOCKED_SHAREDCACHE || (rc & 0xFF) == ffi::SQLITE_LOCKED && unsafe {
        ffi::sqlite3_extended_errcode(db)
    }
        == ffi::SQLITE_LOCKED_SHAREDCACHE
}

/// This function assumes that an SQLite API call (either `sqlite3_prepare_v2()`
/// or `sqlite3_step()`) has just returned `SQLITE_LOCKED`. The argument is the
/// associated database connection.
///
/// This function calls `sqlite3_unlock_notify()` to register for an
/// unlock-notify callback, then blocks until that callback is delivered
/// and returns `SQLITE_OK`. The caller should then retry the failed operation.
///
/// Or, if `sqlite3_unlock_notify()` indicates that to block would deadlock
/// the system, then this function returns `SQLITE_LOCKED` immediately. In
/// this case the caller should not retry the operation and should roll
/// back the current transaction (if any).
#[cfg(feature = "unlock_notify")]
pub fn wait_for_unlock_notify(db: *mut ffi::sqlite3) -> c_int {
    let mut un = UnlockNotification::new();
    /* Register for an unlock-notify callback. */
    let rc = unsafe {
        ffi::sqlite3_unlock_notify(
            db,
            Some(unlock_notify_cb),
            &mut un as *mut UnlockNotification as *mut c_void,
        )
    };
    debug_assert!(
        rc == ffi::SQLITE_LOCKED || rc == ffi::SQLITE_LOCKED_SHAREDCACHE || rc == ffi::SQLITE_OK
    );
    if rc == ffi::SQLITE_OK {
        un.wait();
    }
    rc
}

#[cfg(not(feature = "unlock_notify"))]
pub fn is_locked(_db: *mut ffi::sqlite3, _rc: c_int) -> bool {
    unreachable!()
}

#[cfg(not(feature = "unlock_notify"))]
pub fn wait_for_unlock_notify(_db: *mut ffi::sqlite3) -> c_int {
    unreachable!()
}

#[cfg(feature = "unlock_notify")]
#[cfg(test)]
mod test {
    use std::sync::mpsc::sync_channel;
    use std::thread;
    use std::time;
    use {Connection, OpenFlags, Result, Transaction, TransactionBehavior};

    #[test]
    fn test_unlock_notify() {
        let url = "file::memory:?cache=shared";
        let flags = OpenFlags::SQLITE_OPEN_READ_WRITE | OpenFlags::SQLITE_OPEN_URI;
        let db1 = Connection::open_with_flags(url, flags).unwrap();
        db1.execute_batch("CREATE TABLE foo (x)").unwrap();
        let (rx, tx) = sync_channel(0);
        let child = thread::spawn(move || {
            let mut db2 = Connection::open_with_flags(url, flags).unwrap();
            let tx2 = Transaction::new(&mut db2, TransactionBehavior::Immediate).unwrap();
            tx2.execute_batch("INSERT INTO foo VALUES (42)").unwrap();
            rx.send(1).unwrap();
            let ten_millis = time::Duration::from_millis(10);
            thread::sleep(ten_millis);
            tx2.commit().unwrap();
        });
        assert_eq!(tx.recv().unwrap(), 1);
        let the_answer: Result<i64> = db1.query_row("SELECT x FROM foo", &[], |r| r.get(0));
        assert_eq!(42i64, the_answer.unwrap());
        child.join().unwrap();
    }
}
<|endoftext|>


<commit_before>use weak_gradient::*;
use polynomial;
use polynomial::{Polynomial, PolyOwning, PolyBorrowingMons, approx_equiv};
use monomial::{Mon2d, MaxMonDeg};
use mesh::{OShape};
use rectangle_mesh::{RectMesh, MeshCoord};

use common::*;
use std::vec;

// Tests below use the fact that if a polynomial p is in P_k(e) for some finite element e, where the
// weak gradient approximation space is [P_{k-1}(e)]^d, then wgrad(p) = grad(p) on the interior of e.
// Thus we can test weak gradient calculations on such polynomials and verify this equality. However,
// the weak gradient module only computes weak gradients of shape functions defined piecewise to be
// monomials on a single supporting face and 0 elsewhere. So to compute weak gradients of a polynomial
// across an entire finite element, we consider the polynomial as the sum of face-relative shape functions,
// and using the linearity of the weak gradient, we then compute the original polynomial's weak gradient
// as the sum of the weak gradients of these shape functions.

#[test]
fn test_wgrad_xy() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0f64, 0.],
                                              ~[3f64, 3.],
                                              ~[MeshCoord(3), MeshCoord(3)]);
  let mut wgrad_solver: WeakGradSolver<Mon2d> = WeakGradSolver::new(MaxMonDeg(3), rmesh);

  let one = Mon2d { exps: [Deg(0), Deg(0)] };
  let x = Mon2d { exps: [Deg(1), Deg(0)] };
  let y = Mon2d { exps: [Deg(0), Deg(1)] };

  let (int_mon_wgrads, side_mon_wgrads) =
    wgrad_solver.wgrads_on_oshape([x*y],   // interior
                                  [&[one], // left side (ignored because xy is 0 here)
                                  &[y],   // right
                                  &[one], // bottom    (ignored ")
                                  &[x]],  // top
                                  OShape(0),
                                  rmesh);

  let xy_on_int_wgrad = &int_mon_wgrads[0];
  let y_on_right_side_wgrad = &side_mon_wgrads[1][0];
  let x_on_top_side_wgrad = &side_mon_wgrads[3][0];

  let wgrad = &lcomb_wgrads([(1., xy_on_int_wgrad), (1., y_on_right_side_wgrad), (1., x_on_top_side_wgrad)]);

  let wgrad_comp0 = PolyOwning::new(wgrad.comp_mon_coefs[0].clone(), wgrad_solver.wgrad_comp_mons.clone());
  let wgrad_comp1 = PolyOwning::new(wgrad.comp_mon_coefs[1].clone(), wgrad_solver.wgrad_comp_mons.clone());

  assert!(approx_equiv(&wgrad_comp0, &PolyOwning::new(~[1.],~[y]), 1e-9));
  assert!(approx_equiv(&wgrad_comp1, &PolyOwning::new(~[1.],~[x]), 1e-9));
}

#[test]
fn test_wgrad_x2y() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0f64, 0.],
                                              ~[3f64, 3.],
                                              ~[MeshCoord(3), MeshCoord(3)]);
  let mut wgrad_solver: WeakGradSolver<Mon2d> = WeakGradSolver::new(MaxMonDeg(3), rmesh);

  let one = Mon2d { exps: [Deg(0), Deg(0)] };
  let x = Mon2d { exps: [Deg(1), Deg(0)] };
  let y = Mon2d { exps: [Deg(0), Deg(1)] };

  let (int_mon_wgrads, side_mon_wgrads) =
    wgrad_solver.wgrads_on_oshape([x*x*y],   // interior
                                  [&[one],   // left side (ignored because xy is 0 here)
                                  &[y],     // right
                                  &[one],   // bottom    (ignored ")
                                  &[x*x]],  // top
                                  OShape(0),
                                  rmesh);

  let x2y_on_int_wgrad = &int_mon_wgrads[0];
  let y_on_right_side_wgrad = &side_mon_wgrads[1][0];
  let x2_on_top_side_wgrad = &side_mon_wgrads[3][0];

  let wgrad = &lcomb_wgrads([(1., x2y_on_int_wgrad), (1., y_on_right_side_wgrad), (1., x2_on_top_side_wgrad)]);

  let wgrad_comp0 = PolyOwning::new(wgrad.comp_mon_coefs[0].clone(), wgrad_solver.wgrad_comp_mons.clone());
  let wgrad_comp1 = PolyOwning::new(wgrad.comp_mon_coefs[1].clone(), wgrad_solver.wgrad_comp_mons.clone());

  assert!(approx_equiv(&wgrad_comp0, &PolyOwning::new(~[2.],~[x*y]), 1e-9));
  assert!(approx_equiv(&wgrad_comp1, &PolyOwning::new(~[1.],~[x*x]), 1e-9));
}

#[test]
fn test_wgrad_dot() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0f64, 0.],
                                              ~[3f64, 3.],
                                              ~[MeshCoord(3), MeshCoord(3)]);
  let wgrad_solver: WeakGradSolver<Mon2d> = WeakGradSolver::new(MaxMonDeg(2), rmesh);

  let wgrad1 = WeakGrad { comp_mon_coefs: ~[~[-2.5, 3., 0., 15., -6., -15.], ~[-2.5, 15., -15., 3., -6., 0.]] };
  let wgrad2 = WeakGrad { comp_mon_coefs: ~[~[2.5, -2., -0., -15., 6., 15.], ~[0., 0., 0., 0., 0., 0.]] };

  let mut wgrad_ops = wgrad_solver.weak_grad_ops();

  let fast_dot_prod = wgrad_ops.dot(&wgrad1, &wgrad2);

  // Compiler prevents second call of dot() which would have silently overwritten the existing wgrad's shared coefficients buffer. Beautiful!
  // let wgrad_x_top_dot_wgrad_y_right = wgrad_ops.dot(&wgrad1, &wgrad1);
  //   =>  error: cannot borrow `*wgrad_ops` as mutable more than once at a time

  let p1_0 = PolyBorrowingMons::new(wgrad1.comp_mon_coefs[0].clone(), wgrad_solver.wgrad_comp_mons);
  let p1_1 = PolyBorrowingMons::new(wgrad1.comp_mon_coefs[1].clone(), wgrad_solver.wgrad_comp_mons);
  let p2_0 = PolyBorrowingMons::new(wgrad2.comp_mon_coefs[0].clone(), wgrad_solver.wgrad_comp_mons);
  let p2_1 = PolyBorrowingMons::new(wgrad2.comp_mon_coefs[1].clone(), wgrad_solver.wgrad_comp_mons);
  let polys_dot_prod = PolyOwning::from_polys_lcomb([(1., &polynomial::mul(&p1_0, &p2_0)), (1., &polynomial::mul(&p1_1, &p2_1))]);

  println!("fast dot product:  {}", fast_dot_prod.to_str());
  println!("polys dot product: {}", polys_dot_prod.to_str());

  let canon_fast_dot_prod = fast_dot_prod.canonical_form();
  assert_eq!(&canon_fast_dot_prod.coefs, &polys_dot_prod.coefs);
  assert_eq!(&canon_fast_dot_prod.mons, &polys_dot_prod.mons);
}

fn lcomb_wgrads(terms: &[(R,&WeakGrad)]) -> WeakGrad {
  if terms.len() == 0 { fail!("lcomb_wgrads: At least one weak gradient is required.") }
  let (space_dims, num_comp_mons) = match terms[0] { (_, wgrad) => (wgrad.comp_mon_coefs.len(), wgrad.comp_mon_coefs[0].len()) };
  WeakGrad {
    comp_mon_coefs:
      vec::from_fn(space_dims, |d|
        vec::from_fn(num_comp_mons, |mon_num|
          terms.iter().fold(0 as R, |sum, &(c, wgrad)| sum + c * wgrad.comp_mon_coefs[d][mon_num])))
  }
}

<commit_msg>Fix formatting.<commit_after>use weak_gradient::*;
use polynomial;
use polynomial::{Polynomial, PolyOwning, PolyBorrowingMons, approx_equiv};
use monomial::{Mon2d, MaxMonDeg};
use mesh::{OShape};
use rectangle_mesh::{RectMesh, MeshCoord};

use common::*;
use std::vec;

// Tests below use the fact that if a polynomial p is in P_k(e) for some finite element e, where the
// weak gradient approximation space is [P_{k-1}(e)]^d, then wgrad(p) = grad(p) on the interior of e.
// Thus we can test weak gradient calculations on such polynomials and verify this equality. However,
// the weak gradient module only computes weak gradients of shape functions defined piecewise to be
// monomials on a single supporting face and 0 elsewhere. So to compute weak gradients of a polynomial
// across an entire finite element, we consider the polynomial as the sum of face-relative shape functions,
// and using the linearity of the weak gradient, we then compute the original polynomial's weak gradient
// as the sum of the weak gradients of these shape functions.

#[test]
fn test_wgrad_xy() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0f64, 0.],
                                              ~[3f64, 3.],
                                              ~[MeshCoord(3), MeshCoord(3)]);
  let mut wgrad_solver: WeakGradSolver<Mon2d> = WeakGradSolver::new(MaxMonDeg(3), rmesh);

  let one = Mon2d { exps: [Deg(0), Deg(0)] };
  let x = Mon2d { exps: [Deg(1), Deg(0)] };
  let y = Mon2d { exps: [Deg(0), Deg(1)] };

  let (int_mon_wgrads, side_mon_wgrads) =
    wgrad_solver.wgrads_on_oshape([x*y],   // interior
                                  [&[one], // left side (ignored because xy is 0 here)
                                  &[y],   // right
                                  &[one], // bottom    (ignored ")
                                  &[x]],  // top
                                  OShape(0),
                                  rmesh);

  let xy_on_int_wgrad = &int_mon_wgrads[0];
  let y_on_right_side_wgrad = &side_mon_wgrads[1][0];
  let x_on_top_side_wgrad = &side_mon_wgrads[3][0];

  let wgrad = &lcomb_wgrads([(1., xy_on_int_wgrad), (1., y_on_right_side_wgrad), (1., x_on_top_side_wgrad)]);

  let wgrad_comp0 = PolyOwning::new(wgrad.comp_mon_coefs[0].clone(), wgrad_solver.wgrad_comp_mons.clone());
  let wgrad_comp1 = PolyOwning::new(wgrad.comp_mon_coefs[1].clone(), wgrad_solver.wgrad_comp_mons.clone());

  assert!(approx_equiv(&wgrad_comp0, &PolyOwning::new(~[1.],~[y]), 1e-9));
  assert!(approx_equiv(&wgrad_comp1, &PolyOwning::new(~[1.],~[x]), 1e-9));
}

#[test]
fn test_wgrad_x2y() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0f64, 0.],
                                              ~[3f64, 3.],
                                              ~[MeshCoord(3), MeshCoord(3)]);
  let mut wgrad_solver: WeakGradSolver<Mon2d> = WeakGradSolver::new(MaxMonDeg(3), rmesh);

  let one = Mon2d { exps: [Deg(0), Deg(0)] };
  let x = Mon2d { exps: [Deg(1), Deg(0)] };
  let y = Mon2d { exps: [Deg(0), Deg(1)] };

  let (int_mon_wgrads, side_mon_wgrads) =
    wgrad_solver.wgrads_on_oshape([x*x*y],  // interior
                                  [&[one],  // left side (ignored because xy is 0 here)
                                  &[y],     // right
                                  &[one],   // bottom    (ignored ")
                                  &[x*x]],  // top
                                  OShape(0),
                                  rmesh);

  let x2y_on_int_wgrad = &int_mon_wgrads[0];
  let y_on_right_side_wgrad = &side_mon_wgrads[1][0];
  let x2_on_top_side_wgrad = &side_mon_wgrads[3][0];

  let wgrad = &lcomb_wgrads([(1., x2y_on_int_wgrad), (1., y_on_right_side_wgrad), (1., x2_on_top_side_wgrad)]);

  let wgrad_comp0 = PolyOwning::new(wgrad.comp_mon_coefs[0].clone(), wgrad_solver.wgrad_comp_mons.clone());
  let wgrad_comp1 = PolyOwning::new(wgrad.comp_mon_coefs[1].clone(), wgrad_solver.wgrad_comp_mons.clone());

  assert!(approx_equiv(&wgrad_comp0, &PolyOwning::new(~[2.],~[x*y]), 1e-9));
  assert!(approx_equiv(&wgrad_comp1, &PolyOwning::new(~[1.],~[x*x]), 1e-9));
}

#[test]
fn test_wgrad_dot() {
  let rmesh: ~RectMesh<Mon2d> = RectMesh::new(~[0f64, 0.],
                                              ~[3f64, 3.],
                                              ~[MeshCoord(3), MeshCoord(3)]);
  let wgrad_solver: WeakGradSolver<Mon2d> = WeakGradSolver::new(MaxMonDeg(2), rmesh);

  let wgrad1 = WeakGrad { comp_mon_coefs: ~[~[-2.5, 3., 0., 15., -6., -15.], ~[-2.5, 15., -15., 3., -6., 0.]] };
  let wgrad2 = WeakGrad { comp_mon_coefs: ~[~[2.5, -2., -0., -15., 6., 15.], ~[0., 0., 0., 0., 0., 0.]] };

  let mut wgrad_ops = wgrad_solver.weak_grad_ops();

  let fast_dot_prod = wgrad_ops.dot(&wgrad1, &wgrad2);

  // Compiler prevents second call of dot() which would have silently overwritten the existing wgrad's shared coefficients buffer. Beautiful!
  // let wgrad_x_top_dot_wgrad_y_right = wgrad_ops.dot(&wgrad1, &wgrad1);
  //   =>  error: cannot borrow `*wgrad_ops` as mutable more than once at a time

  let p1_0 = PolyBorrowingMons::new(wgrad1.comp_mon_coefs[0].clone(), wgrad_solver.wgrad_comp_mons);
  let p1_1 = PolyBorrowingMons::new(wgrad1.comp_mon_coefs[1].clone(), wgrad_solver.wgrad_comp_mons);
  let p2_0 = PolyBorrowingMons::new(wgrad2.comp_mon_coefs[0].clone(), wgrad_solver.wgrad_comp_mons);
  let p2_1 = PolyBorrowingMons::new(wgrad2.comp_mon_coefs[1].clone(), wgrad_solver.wgrad_comp_mons);
  let polys_dot_prod = PolyOwning::from_polys_lcomb([(1., &polynomial::mul(&p1_0, &p2_0)), (1., &polynomial::mul(&p1_1, &p2_1))]);

  println!("fast dot product:  {}", fast_dot_prod.to_str());
  println!("polys dot product: {}", polys_dot_prod.to_str());

  let canon_fast_dot_prod = fast_dot_prod.canonical_form();
  assert_eq!(&canon_fast_dot_prod.coefs, &polys_dot_prod.coefs);
  assert_eq!(&canon_fast_dot_prod.mons, &polys_dot_prod.mons);
}

fn lcomb_wgrads(terms: &[(R,&WeakGrad)]) -> WeakGrad {
  if terms.len() == 0 { fail!("lcomb_wgrads: At least one weak gradient is required.") }
  let (space_dims, num_comp_mons) = match terms[0] { (_, wgrad) => (wgrad.comp_mon_coefs.len(), wgrad.comp_mon_coefs[0].len()) };
  WeakGrad {
    comp_mon_coefs:
      vec::from_fn(space_dims, |d|
        vec::from_fn(num_comp_mons, |mon_num|
          terms.iter().fold(0 as R, |sum, &(c, wgrad)| sum + c * wgrad.comp_mon_coefs[d][mon_num])))
  }
}

<|endoftext|>


<commit_before>use askama::Template;

#[derive(Template)]
#[template(source = "{% let v = s %}{{ v }}", ext = "txt")]
struct LetTemplate<'a> {
    s: &'a str,
}

#[test]
fn test_let() {
    let t = LetTemplate { s: "foo" };
    assert_eq!(t.render().unwrap(), "foo");
}

#[derive(Template)]
#[template(path = "let.html")]
struct LetTupleTemplate<'a> {
    s: &'a str,
    t: (&'a str, &'a str),
}

#[test]
fn test_let_tuple() {
    let t = LetTupleTemplate {
        s: "foo",
        t: ("bar", "bazz"),
    };
    assert_eq!(t.render().unwrap(), "foo\nbarbazz");
}

#[derive(Template)]
#[template(path = "let-decl.html")]
struct LetDeclTemplate<'a> {
    cond: bool,
    s: &'a str,
}

#[test]
fn test_let_decl() {
    let t = LetDeclTemplate {
        cond: false,
        s: "bar",
    };
    assert_eq!(t.render().unwrap(), "bar");
}

#[derive(Template)]
#[template(
    source = "{% for v in self.0 %}{{ v }}{% endfor %}",
    ext = "txt",
    print = "code"
)]
struct SelfIterTemplate(Vec<usize>);

#[test]
fn test_self_iter() {
    let t = SelfIterTemplate(vec![1, 2, 3]);
    assert_eq!(t.render().unwrap(), "123");
}
<commit_msg>Remove debugging cruft<commit_after>use askama::Template;

#[derive(Template)]
#[template(source = "{% let v = s %}{{ v }}", ext = "txt")]
struct LetTemplate<'a> {
    s: &'a str,
}

#[test]
fn test_let() {
    let t = LetTemplate { s: "foo" };
    assert_eq!(t.render().unwrap(), "foo");
}

#[derive(Template)]
#[template(path = "let.html")]
struct LetTupleTemplate<'a> {
    s: &'a str,
    t: (&'a str, &'a str),
}

#[test]
fn test_let_tuple() {
    let t = LetTupleTemplate {
        s: "foo",
        t: ("bar", "bazz"),
    };
    assert_eq!(t.render().unwrap(), "foo\nbarbazz");
}

#[derive(Template)]
#[template(path = "let-decl.html")]
struct LetDeclTemplate<'a> {
    cond: bool,
    s: &'a str,
}

#[test]
fn test_let_decl() {
    let t = LetDeclTemplate {
        cond: false,
        s: "bar",
    };
    assert_eq!(t.render().unwrap(), "bar");
}

#[derive(Template)]
#[template(source = "{% for v in self.0 %}{{ v }}{% endfor %}", ext = "txt")]
struct SelfIterTemplate(Vec<usize>);

#[test]
fn test_self_iter() {
    let t = SelfIterTemplate(vec![1, 2, 3]);
    assert_eq!(t.render().unwrap(), "123");
}
<|endoftext|>


<commit_before>use std::env;
use std::io::{stdout, stderr};
use std::fs::read_link;

use argparse::{ArgumentParser, Store, StoreTrue};
use unshare::{Command, Namespace};

use options::build_mode::BuildMode;
use config::Settings;
use process_util::{capture_fd3, set_uidmap, copy_env_vars, squash_stdio};
use container::uidmap::get_max_uidmap;

pub fn build_container(settings: &Settings, name: &String, mode: BuildMode)
    -> Result<String, String>
{
    use options::build_mode::BuildMode::*;
    let ver = match mode {
        Normal => try!(build_internal(settings, name, &[])),
        NoBuild => format!("{}.{}", &name, try!(get_version(settings, &name))),
        NoVersion => {
            let lnk = format!(".vagga/{}", name);
            let path = try!(read_link(&lnk)
                .map_err(|e| format!("Can't read link {:?}: {}", lnk, e)));
            try!(path.iter().rev().nth(1).and_then(|x| x.to_str())
                .ok_or(format!("Bad symlink {:?}: {:?}", lnk, path)))
                .to_string()
        }
    };
    Ok(ver)
}

/// Similar to build_container but never actually builds
pub fn get_version(settings: &Settings, name: &str) -> Result<String, String> {
    let mut cmd = Command::new("/proc/self/exe");
    cmd.arg0("vagga_wrapper");
    cmd.arg("_version_hash");
    cmd.arg("--short");
    cmd.arg("--fd3");
    cmd.arg(name);
    cmd.env_clear();
    copy_env_vars(&mut cmd, settings);
    if let Ok(x) = env::var("RUST_LOG") {
        cmd.env("RUST_LOG", x);
    }
    if let Ok(x) = env::var("RUST_BACKTRACE") {
        cmd.env("RUST_BACKTRACE", x);
    }
    if let Ok(x) = env::var("HOME") {
        cmd.env("_VAGGA_HOME", x);
    }
    cmd.unshare(
        [Namespace::Mount, Namespace::Ipc, Namespace::Pid].iter().cloned());
    set_uidmap(&mut cmd, &get_max_uidmap().unwrap(), true);

    capture_fd3(cmd)
    .and_then(|x| String::from_utf8(x)
                  .map_err(|e| format!("Can't decode version: {}", e)))
}

fn build_internal(settings: &Settings, name: &str, args: &[String])
    -> Result<String, String>
{
    let mut cmd = Command::new("/proc/self/exe");
    squash_stdio(&mut cmd);
    cmd.arg0("vagga_wrapper");
    cmd.arg("_build");
    cmd.arg(name);
    cmd.args(&args);
    cmd.env_clear();
    copy_env_vars(&mut cmd, settings);
    if let Ok(x) = env::var("RUST_LOG") {
        cmd.env("RUST_LOG", x);
    }
    if let Ok(x) = env::var("RUST_BACKTRACE") {
        cmd.env("RUST_BACKTRACE", x);
    }
    if let Ok(x) = env::var("HOME") {
        cmd.env("_VAGGA_HOME", x);
    }
    cmd.unshare(
        [Namespace::Mount, Namespace::Ipc, Namespace::Pid].iter().cloned());
    cmd.make_group_leader(true);
    set_uidmap(&mut cmd, &get_max_uidmap().unwrap(), true);

    capture_fd3(cmd)
    .and_then(|x| String::from_utf8(x)
                  .map_err(|e| format!("Can't decode version: {}", e)))
}

pub fn build_command(settings: &Settings, args: Vec<String>)
    -> Result<i32, String>
{
    let mut name: String = "".to_string();
    let mut force: bool = false;
    {
        let mut cmdline = args.clone();
        cmdline.insert(0, "vagga _build".to_string());
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Internal vagga tool to setup basic system sandbox
            ");
        ap.refer(&mut name)
            .add_argument("container_name", Store,
                "Container name to build");
        ap.refer(&mut force)
            .add_option(&["--force"], StoreTrue,
                "Force build even if container is considered up to date");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(122);
            }
        }
    }
    let mut args = Vec::new();
    if force {
        args.push("--force".to_string());
    }

    build_internal(settings, &name, &args)
    .map(|v| debug!("Container {:?} build with version {:?}", name, v))
    .map(|()| 0)
}
<commit_msg>Fix errorneous use of squash_stdio<commit_after>use std::env;
use std::io::{stdout, stderr};
use std::fs::read_link;

use argparse::{ArgumentParser, Store, StoreTrue};
use unshare::{Command, Namespace};

use options::build_mode::BuildMode;
use config::Settings;
use process_util::{capture_fd3, set_uidmap, copy_env_vars, squash_stdio};
use container::uidmap::get_max_uidmap;

pub fn build_container(settings: &Settings, name: &String, mode: BuildMode)
    -> Result<String, String>
{
    use options::build_mode::BuildMode::*;
    let ver = match mode {
        Normal => try!(build_internal(settings, name, &[])),
        NoBuild => format!("{}.{}", &name, try!(get_version(settings, &name))),
        NoVersion => {
            let lnk = format!(".vagga/{}", name);
            let path = try!(read_link(&lnk)
                .map_err(|e| format!("Can't read link {:?}: {}", lnk, e)));
            try!(path.iter().rev().nth(1).and_then(|x| x.to_str())
                .ok_or(format!("Bad symlink {:?}: {:?}", lnk, path)))
                .to_string()
        }
    };
    Ok(ver)
}

/// Similar to build_container but never actually builds
pub fn get_version(settings: &Settings, name: &str) -> Result<String, String> {
    let mut cmd = Command::new("/proc/self/exe");
    cmd.arg0("vagga_wrapper");
    cmd.arg("_version_hash");
    cmd.arg("--short");
    cmd.arg("--fd3");
    cmd.arg(name);
    cmd.env_clear();
    copy_env_vars(&mut cmd, settings);
    if let Ok(x) = env::var("RUST_LOG") {
        cmd.env("RUST_LOG", x);
    }
    if let Ok(x) = env::var("RUST_BACKTRACE") {
        cmd.env("RUST_BACKTRACE", x);
    }
    if let Ok(x) = env::var("HOME") {
        cmd.env("_VAGGA_HOME", x);
    }
    cmd.unshare(
        [Namespace::Mount, Namespace::Ipc, Namespace::Pid].iter().cloned());
    set_uidmap(&mut cmd, &get_max_uidmap().unwrap(), true);

    capture_fd3(cmd)
    .and_then(|x| String::from_utf8(x)
                  .map_err(|e| format!("Can't decode version: {}", e)))
}

fn build_internal(settings: &Settings, name: &str, args: &[String])
    -> Result<String, String>
{
    let mut cmd = Command::new("/proc/self/exe");
    try!(squash_stdio(&mut cmd));
    cmd.arg0("vagga_wrapper");
    cmd.arg("_build");
    cmd.arg(name);
    cmd.args(&args);
    cmd.env_clear();
    copy_env_vars(&mut cmd, settings);
    if let Ok(x) = env::var("RUST_LOG") {
        cmd.env("RUST_LOG", x);
    }
    if let Ok(x) = env::var("RUST_BACKTRACE") {
        cmd.env("RUST_BACKTRACE", x);
    }
    if let Ok(x) = env::var("HOME") {
        cmd.env("_VAGGA_HOME", x);
    }
    cmd.unshare(
        [Namespace::Mount, Namespace::Ipc, Namespace::Pid].iter().cloned());
    cmd.make_group_leader(true);
    set_uidmap(&mut cmd, &get_max_uidmap().unwrap(), true);

    capture_fd3(cmd)
    .and_then(|x| String::from_utf8(x)
                  .map_err(|e| format!("Can't decode version: {}", e)))
}

pub fn build_command(settings: &Settings, args: Vec<String>)
    -> Result<i32, String>
{
    let mut name: String = "".to_string();
    let mut force: bool = false;
    {
        let mut cmdline = args.clone();
        cmdline.insert(0, "vagga _build".to_string());
        let mut ap = ArgumentParser::new();
        ap.set_description("
            Internal vagga tool to setup basic system sandbox
            ");
        ap.refer(&mut name)
            .add_argument("container_name", Store,
                "Container name to build");
        ap.refer(&mut force)
            .add_option(&["--force"], StoreTrue,
                "Force build even if container is considered up to date");
        match ap.parse(cmdline, &mut stdout(), &mut stderr()) {
            Ok(()) => {}
            Err(0) => return Ok(0),
            Err(_) => {
                return Ok(122);
            }
        }
    }
    let mut args = Vec::new();
    if force {
        args.push("--force".to_string());
    }

    build_internal(settings, &name, &args)
    .map(|v| debug!("Container {:?} build with version {:?}", name, v))
    .map(|()| 0)
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use std::collections::{HashMap, HashSet};
use context::Context;
use framebuffer::FramebufferBinding;
use program::ProgramAttrib;
use vertex_data::{VertexData, VertexBytes, VertexAttribute};
use index_data::{IndexData, IndexDatum};
use buffer::{Buffer, BufferBinding,
             ArrayBufferBinding, ElementArrayBufferBinding};
use types::DrawingMode;

#[derive(Debug)]
pub enum AttribAddError {
    DuplicateAttrib(String)
}

#[derive(Debug)]
pub struct AttribError {
    missing_attribs: Vec<String>,
    unknown_attribs: Vec<String>
}

pub struct AttribBinder {
    attribs: HashMap<String, ProgramAttrib>
}

impl AttribBinder {
    pub fn new() -> Self {
        AttribBinder {
            attribs: HashMap::new()
        }
    }

    pub fn add(&mut self, name: &str, attrib: ProgramAttrib)
        -> Result<(), AttribAddError>
    {
        match self.attribs.insert(name.into(), attrib) {
            None => Ok(()),
            Some(_) => Err(AttribAddError::DuplicateAttrib(name.into()))
        }
    }

    fn for_each<T, F>(&self, mut f: F) -> Result<(), AttribError>
        where T: VertexData, F: FnMut(VertexAttribute, ProgramAttrib)
    {
        // TODO: Avoid heap allocations
        // TODO: Avoid redundant calls to T::visit_attributes
        let mut attribs =
            HashMap::<String, (VertexAttribute, ProgramAttrib)>::new();
        let mut missing = Vec::<String>::new();

        T::visit_attributes(|vertex_attrib| {
            match self.attribs.get(&vertex_attrib.name) {
                Some(program_attrib) => {
                    let pair = (vertex_attrib.clone(), *program_attrib);
                    attribs.insert(vertex_attrib.name, pair);
                },
                None => {
                    missing.push(vertex_attrib.name);
                }
            }
        });

        let unknown: Vec<_> = {
            let expected: HashSet<_> = self.attribs.keys().collect();
            let actual: HashSet<_> = attribs.keys().collect();
            expected.difference(&actual).cloned().cloned().collect()
        };

        if missing.is_empty() && unknown.is_empty() {
            for (_, (vertex_attrib, program_attrib)) in attribs.into_iter() {
                f(vertex_attrib, program_attrib);
            }
            Ok(())
        }
        else {
            Err(AttribError {
                missing_attribs: missing,
                unknown_attribs: unknown
            })
        }
    }

    pub fn enable<T: VertexData>(&self, gl: &Context)
        -> Result<(), AttribError>
    {
        self.for_each::<T, _>(|_, program_attrib| {
            gl.enable_vertex_attrib_array(program_attrib)
        })
    }

    pub fn bind<T: VertexData>(&self, gl_buffer: &ArrayBufferBinding)
        -> Result<(), AttribError>
    {
        self.for_each::<T, _>(|vertex_attrib, program_attrib| {
            unsafe {
                gl_buffer.vertex_attrib_pointer(
                    program_attrib,
                    vertex_attrib.ty.components,
                    vertex_attrib.ty.data,
                    vertex_attrib.ty.normalize,
                    vertex_attrib.stride,
                    vertex_attrib.offset
                );
            }
        })
    }
}

pub struct VertexBuffer<T: VertexData> {
    attrib_binder: Option<AttribBinder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn bind_attrib_pointers(&mut self, binder: AttribBinder) {
        self.attrib_binder = Some(binder);
    }

    pub fn bind(&self, gl_buffer: &ArrayBufferBinding) -> Result<(), ()> {
        match self.attrib_binder {
            Some(ref binder) => {
                let mut gl = unsafe { Context::current_context() };
                try!(binder.enable::<T>(&mut gl).or(Err(())));
                try!(binder.bind::<T>(gl_buffer).or(Err(())));
                Ok(())
            },
            None => { Err(()) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData + 'a> {
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData + 'a> VertexBufferBinding<'a, T> {
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }
}

impl<'a> FramebufferBinding<'a> {
    pub fn draw_arrays_range_vbo<T>(&mut self,
                                    gl_vbo: &VertexBufferBinding<T>,
                                    mode: DrawingMode,
                                    start: u32,
                                    length: usize)
        where T: VertexData
    {
        debug_assert!((start as usize) + length <= gl_vbo.vbo.count);

        unsafe {
            self.draw_arrays_range(&gl_vbo.gl_buffer, mode, start, length);
        }
    }

    pub fn draw_arrays_vbo<T>(&mut self,
                              gl_vbo: &VertexBufferBinding<T>,
                              mode: DrawingMode)
        where T: VertexData
    {
        unsafe {
            self.draw_arrays_range(&gl_vbo.gl_buffer,
                                   mode,
                                   0,
                                   gl_vbo.vbo.count);
        }
    }

    pub fn draw_n_elements_buffered_vbo<T, I>(&mut self,
                                              gl_vbo: &VertexBufferBinding<T>,
                                              gl_ibo: &IndexBufferBinding<I>,
                                              mode: DrawingMode,
                                              length: usize)
        where T: VertexData, I: IndexDatum
    {
        debug_assert!(length <= gl_ibo.ibo.count);

        unsafe {
            self.draw_n_elements_buffered(&gl_vbo.gl_buffer,
                                          &gl_ibo.gl_buffer,
                                          mode,
                                          length,
                                          I::index_datum_type());
        }
    }

    pub fn draw_elements_buffered_vbo<T, I>(&mut self,
                                            gl_vbo: &VertexBufferBinding<T>,
                                            gl_ibo: &IndexBufferBinding<I>,
                                            mode: DrawingMode)
        where T: VertexData, I: IndexDatum
    {
        unsafe {
            self.draw_n_elements_buffered(&gl_vbo.gl_buffer,
                                          &gl_ibo.gl_buffer,
                                          mode,
                                          gl_ibo.ibo.count,
                                          I::index_datum_type());
        }
    }

    pub fn draw_n_elements_vbo<T, I>(&mut self,
                                     gl_vbo: &VertexBufferBinding<'a, T>,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where T: VertexData, I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.draw_n_elements(&gl_vbo.gl_buffer, mode, count, indices);
        }
    }

    pub fn draw_elements_vbo<T, I>(&mut self,
                                   gl_vbo: &VertexBufferBinding<'a, T>,
                                   mode: DrawingMode,
                                   indices: &[I])
        where T: VertexData, I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.draw_elements(&gl_vbo.gl_buffer, mode, indices);
        }
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub struct IndexBuffer<T: IndexDatum> {
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: IndexDatum> IndexBuffer<T> {
    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct IndexBufferBinding<'a, T: IndexDatum + 'a> {
    gl_buffer: ElementArrayBufferBinding<'a>,
    ibo: &'a mut IndexBuffer<T>
}

impl<'a, T: IndexDatum + 'a> IndexBufferBinding<'a, T> {
    pub fn new(gl_buffer: ElementArrayBufferBinding<'a>,
               ibo: &'a mut IndexBuffer<T>)
        -> Self
    {
        IndexBufferBinding {
            gl_buffer: gl_buffer,
            ibo: ibo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: IndexData
    {
        self.ibo.count = data.len();
        self.gl_buffer.buffer_bytes(data.index_bytes(), usage);
    }
}

impl Context {
    pub fn new_index_buffer<T: IndexDatum>(&self) -> IndexBuffer<T> {
        IndexBuffer {
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let mut binder = $crate::AttribBinder::new();
            $(binder.add(stringify!($field_name), $field_attrib).unwrap());*;
            binder
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = {
                attrib_pointers!($gl, vbo, {
                    $($field_name => $field_attrib),*
                })
            };
            vbo.bind_attrib_pointers(binder);
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;

            let gl_buffer = bind_array_buffer!($gl, vbo.buffer_mut());
            vbo.bind(&gl_buffer).unwrap();
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}

#[macro_export]
macro_rules! bind_index_buffer {
    ($gl:expr, $ibo:expr) => {
        {
            let ibo = $ibo;

            let gl_buffer = bind_element_array_buffer!($gl, ibo.buffer_mut());
            $crate::IndexBufferBinding::new(gl_buffer, ibo)
        }
    }
}
<commit_msg>Add `VertexBindError` type used for `VertexBuffer.bind()`<commit_after>use std::marker::PhantomData;
use std::collections::{HashMap, HashSet};
use context::Context;
use framebuffer::FramebufferBinding;
use program::ProgramAttrib;
use vertex_data::{VertexData, VertexBytes, VertexAttribute};
use index_data::{IndexData, IndexDatum};
use buffer::{Buffer, BufferBinding,
             ArrayBufferBinding, ElementArrayBufferBinding};
use types::DrawingMode;

#[derive(Debug)]
pub enum AttribAddError {
    DuplicateAttrib(String)
}

#[derive(Debug)]
pub struct AttribError {
    missing_attribs: Vec<String>,
    unknown_attribs: Vec<String>
}

pub struct AttribBinder {
    attribs: HashMap<String, ProgramAttrib>
}

impl AttribBinder {
    pub fn new() -> Self {
        AttribBinder {
            attribs: HashMap::new()
        }
    }

    pub fn add(&mut self, name: &str, attrib: ProgramAttrib)
        -> Result<(), AttribAddError>
    {
        match self.attribs.insert(name.into(), attrib) {
            None => Ok(()),
            Some(_) => Err(AttribAddError::DuplicateAttrib(name.into()))
        }
    }

    fn for_each<T, F>(&self, mut f: F) -> Result<(), AttribError>
        where T: VertexData, F: FnMut(VertexAttribute, ProgramAttrib)
    {
        // TODO: Avoid heap allocations
        // TODO: Avoid redundant calls to T::visit_attributes
        let mut attribs =
            HashMap::<String, (VertexAttribute, ProgramAttrib)>::new();
        let mut missing = Vec::<String>::new();

        T::visit_attributes(|vertex_attrib| {
            match self.attribs.get(&vertex_attrib.name) {
                Some(program_attrib) => {
                    let pair = (vertex_attrib.clone(), *program_attrib);
                    attribs.insert(vertex_attrib.name, pair);
                },
                None => {
                    missing.push(vertex_attrib.name);
                }
            }
        });

        let unknown: Vec<_> = {
            let expected: HashSet<_> = self.attribs.keys().collect();
            let actual: HashSet<_> = attribs.keys().collect();
            expected.difference(&actual).cloned().cloned().collect()
        };

        if missing.is_empty() && unknown.is_empty() {
            for (_, (vertex_attrib, program_attrib)) in attribs.into_iter() {
                f(vertex_attrib, program_attrib);
            }
            Ok(())
        }
        else {
            Err(AttribError {
                missing_attribs: missing,
                unknown_attribs: unknown
            })
        }
    }

    pub fn enable<T: VertexData>(&self, gl: &Context)
        -> Result<(), AttribError>
    {
        self.for_each::<T, _>(|_, program_attrib| {
            gl.enable_vertex_attrib_array(program_attrib)
        })
    }

    pub fn bind<T: VertexData>(&self, gl_buffer: &ArrayBufferBinding)
        -> Result<(), AttribError>
    {
        self.for_each::<T, _>(|vertex_attrib, program_attrib| {
            unsafe {
                gl_buffer.vertex_attrib_pointer(
                    program_attrib,
                    vertex_attrib.ty.components,
                    vertex_attrib.ty.data,
                    vertex_attrib.ty.normalize,
                    vertex_attrib.stride,
                    vertex_attrib.offset
                );
            }
        })
    }
}

#[derive(Debug)]
pub enum VertexBindError {
    BindingError(AttribError),
    NoAttributeBindings
}

impl From<AttribError> for VertexBindError {
    fn from(attrib_error: AttribError) -> VertexBindError {
        VertexBindError::BindingError(attrib_error)
    }
}

pub struct VertexBuffer<T: VertexData> {
    attrib_binder: Option<AttribBinder>,
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: VertexData> VertexBuffer<T> {
    pub fn bind_attrib_pointers(&mut self, binder: AttribBinder) {
        self.attrib_binder = Some(binder);
    }

    pub fn bind(&self, gl_buffer: &ArrayBufferBinding)
        -> Result<(), VertexBindError>
    {
        match self.attrib_binder {
            Some(ref binder) => {
                let mut gl = unsafe { Context::current_context() };
                try!(binder.enable::<T>(&mut gl));
                try!(binder.bind::<T>(gl_buffer));
                Ok(())
            },
            None => { Err(VertexBindError::NoAttributeBindings) }
        }
    }

    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct VertexBufferBinding<'a, T: VertexData + 'a> {
    gl_buffer: ArrayBufferBinding<'a>,
    vbo: &'a mut VertexBuffer<T>
}

impl<'a, T: VertexData + 'a> VertexBufferBinding<'a, T> {
    pub fn new(gl_buffer: ArrayBufferBinding<'a>, vbo: &'a mut VertexBuffer<T>)
        -> Self
    {
        VertexBufferBinding {
            gl_buffer: gl_buffer,
            vbo: vbo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: VertexBytes
    {
        self.vbo.count = data.len();
        self.gl_buffer.buffer_bytes(data.vertex_bytes(), usage);
    }
}

impl<'a> FramebufferBinding<'a> {
    pub fn draw_arrays_range_vbo<T>(&mut self,
                                    gl_vbo: &VertexBufferBinding<T>,
                                    mode: DrawingMode,
                                    start: u32,
                                    length: usize)
        where T: VertexData
    {
        debug_assert!((start as usize) + length <= gl_vbo.vbo.count);

        unsafe {
            self.draw_arrays_range(&gl_vbo.gl_buffer, mode, start, length);
        }
    }

    pub fn draw_arrays_vbo<T>(&mut self,
                              gl_vbo: &VertexBufferBinding<T>,
                              mode: DrawingMode)
        where T: VertexData
    {
        unsafe {
            self.draw_arrays_range(&gl_vbo.gl_buffer,
                                   mode,
                                   0,
                                   gl_vbo.vbo.count);
        }
    }

    pub fn draw_n_elements_buffered_vbo<T, I>(&mut self,
                                              gl_vbo: &VertexBufferBinding<T>,
                                              gl_ibo: &IndexBufferBinding<I>,
                                              mode: DrawingMode,
                                              length: usize)
        where T: VertexData, I: IndexDatum
    {
        debug_assert!(length <= gl_ibo.ibo.count);

        unsafe {
            self.draw_n_elements_buffered(&gl_vbo.gl_buffer,
                                          &gl_ibo.gl_buffer,
                                          mode,
                                          length,
                                          I::index_datum_type());
        }
    }

    pub fn draw_elements_buffered_vbo<T, I>(&mut self,
                                            gl_vbo: &VertexBufferBinding<T>,
                                            gl_ibo: &IndexBufferBinding<I>,
                                            mode: DrawingMode)
        where T: VertexData, I: IndexDatum
    {
        unsafe {
            self.draw_n_elements_buffered(&gl_vbo.gl_buffer,
                                          &gl_ibo.gl_buffer,
                                          mode,
                                          gl_ibo.ibo.count,
                                          I::index_datum_type());
        }
    }

    pub fn draw_n_elements_vbo<T, I>(&mut self,
                                     gl_vbo: &VertexBufferBinding<'a, T>,
                                     mode: DrawingMode,
                                     count: usize,
                                     indices: &[I])
        where T: VertexData, I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.draw_n_elements(&gl_vbo.gl_buffer, mode, count, indices);
        }
    }

    pub fn draw_elements_vbo<T, I>(&mut self,
                                   gl_vbo: &VertexBufferBinding<'a, T>,
                                   mode: DrawingMode,
                                   indices: &[I])
        where T: VertexData, I: IndexDatum, [I]: IndexData
    {
        unsafe {
            self.draw_elements(&gl_vbo.gl_buffer, mode, indices);
        }
    }
}

impl Context {
    pub fn new_vertex_buffer<T: VertexData>(&self) -> VertexBuffer<T> {
        VertexBuffer {
            attrib_binder: None,
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

pub struct IndexBuffer<T: IndexDatum> {
    buffer: Buffer,
    count: usize,
    phantom: PhantomData<*const T>
}

impl<T: IndexDatum> IndexBuffer<T> {
    pub fn buffer(&self) -> &Buffer {
        &self.buffer
    }

    pub fn buffer_mut(&mut self) -> &mut Buffer {
        &mut self.buffer
    }
}

pub struct IndexBufferBinding<'a, T: IndexDatum + 'a> {
    gl_buffer: ElementArrayBufferBinding<'a>,
    ibo: &'a mut IndexBuffer<T>
}

impl<'a, T: IndexDatum + 'a> IndexBufferBinding<'a, T> {
    pub fn new(gl_buffer: ElementArrayBufferBinding<'a>,
               ibo: &'a mut IndexBuffer<T>)
        -> Self
    {
        IndexBufferBinding {
            gl_buffer: gl_buffer,
            ibo: ibo
        }
    }

    pub fn buffer_data(&mut self, data: &[T], usage: super::BufferDataUsage)
        where [T]: IndexData
    {
        self.ibo.count = data.len();
        self.gl_buffer.buffer_bytes(data.index_bytes(), usage);
    }
}

impl Context {
    pub fn new_index_buffer<T: IndexDatum>(&self) -> IndexBuffer<T> {
        IndexBuffer {
            buffer: self.gen_buffer(),
            count: 0,
            phantom: PhantomData
        }
    }
}

#[macro_export]
macro_rules! attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let mut binder = $crate::AttribBinder::new();
            $(binder.add(stringify!($field_name), $field_attrib).unwrap());*;
            binder
        }
    }
}

#[macro_export]
macro_rules! bind_attrib_pointers {
    ($gl:expr, $vbo:expr, {
        $($field_name:ident => $field_attrib:expr),*
    }) => {
        {
            let vbo = $vbo;
            let binder = {
                attrib_pointers!($gl, vbo, {
                    $($field_name => $field_attrib),*
                })
            };
            vbo.bind_attrib_pointers(binder);
        }
    }
}

#[macro_export]
macro_rules! bind_vertex_buffer {
    ($gl:expr, $vbo:expr) => {
        {
            let vbo = $vbo;

            let gl_buffer = bind_array_buffer!($gl, vbo.buffer_mut());
            vbo.bind(&gl_buffer).unwrap();
            $crate::VertexBufferBinding::new(gl_buffer, vbo)
        }
    }
}

#[macro_export]
macro_rules! bind_index_buffer {
    ($gl:expr, $ibo:expr) => {
        {
            let ibo = $ibo;

            let gl_buffer = bind_element_array_buffer!($gl, ibo.buffer_mut());
            $crate::IndexBufferBinding::new(gl_buffer, ibo)
        }
    }
}
<|endoftext|>


<commit_before>use http;
use regex::Regex;
use video::Video;

lazy_static! {
    static ref DECRYPT_FUNC_NAME: Regex = Regex::new(r#"\.sig\|\|(.+?)\(.+?\)"#).unwrap();
}

enum CryptOp {
    Reverse,        // reverses entire string
    Swap(usize),    // swaps character at idx with first character
    Slice(usize),   // removes characters up to idx
}

impl CryptOp {
    fn swap(s: &str) -> CryptOp {
        unimplemented!()
    }

    fn slice(s: &str) -> CryptOp {
        unimplemented!()
    }

    fn apply(&self, sig: &mut Vec<char>) {
        match *self {
            CryptOp::Reverse => *sig = sig.iter().cloned().rev().collect(),
            CryptOp::Swap(idx) => sig.swap(0, idx),
            CryptOp::Slice(idx) => *sig = sig.split_off(idx),
        }
    }
}

#[derive(Debug)]
pub struct YoutubeVideo {
    title: String,
    uri: String,
    js_player: String,
}

impl YoutubeVideo {
    pub fn new(title: &str, uri: &str, js_player: &str, signature: &Option<String>) -> YoutubeVideo {
        let mut uri = uri.to_owned();
        if let &Some(ref signature) = signature {
            uri = decrypt(&uri, js_player, signature);
        }

        YoutubeVideo {
            title: title.to_owned(),
            uri: uri,
            js_player: js_player.to_owned(),
        }
    }
}

impl Video for YoutubeVideo {
    fn title(&self) -> &str {
        &self.title
    }

    fn uri(&mut self) -> &str {
        &self.uri
    }
}

fn decrypt(uri: &str, js_player: &str, signature: &str) -> String {
    let js = http::download_string(js_player).expect("failed to download js");
    let operations = discover_operations(&js);

    let mut signature: Vec<_> = signature.chars().collect();
    for op in operations {
        op.apply(&mut signature);
    }

    let signature: String = signature.iter().cloned().collect();
    format!("{}&signature={}", uri, signature)
}

fn discover_operations(js: &str) -> Vec<CryptOp> {
    let function_pattern = Regex::new(&format!("{}=function\\(\\w\\){{(.*?)}}", decrypt_function(js))).expect("dynamic regex failed to compile");
    let function_body = function_pattern.captures(js).and_then(|cap| cap.at(1)).expect("unable to capture decrypt function");

    let mut reverse_id = None;
    let mut swap_id = None;
    let mut slice_id = None;

    function_body.split(';').skip(1).filter(|line| !line.starts_with("return")).map(|line| {
        let id = get_id(&line);

        match reverse_id {
            None => if is_reverse_id(&id) {
                reverse_id = Some(id.to_owned());
                return CryptOp::Reverse;
            },
            Some(ref reverse_id) => if reverse_id == id {
                return CryptOp::Reverse;
            }
        }

        match swap_id {
            None => if is_swap_id(&id) {
                swap_id = Some(id.to_owned());
                return CryptOp::swap(line);
            },
            Some(ref swap_id) => if swap_id == id {
                return CryptOp::swap(line);
            }
        }

        match slice_id {
            None => if is_slice_id(&id) {
                slice_id = Some(id.to_owned());
                return CryptOp::slice(line);
            },
            Some(ref slice_id) => if slice_id == id {
                return CryptOp::slice(line);
            }
        }

        panic!("unknown crypto transform");
    }).collect()
}

fn get_id(s: &str) -> &str {
    unimplemented!()
}

fn is_reverse_id(id: &str) -> bool {
    unimplemented!()
}

fn is_swap_id(id: &str) -> bool {
    unimplemented!()
}

fn is_slice_id(id: &str) -> bool {
    unimplemented!()
}

/// Returns the decryption function found in the javascript source code
fn decrypt_function(js: &str) -> &str {
    // the C# program I'm porting had a custom-build dfa or state machine or
    // whatever for this crap... I feel like rust's regex crate is good enough
    // I can just say fuck all that noise

    DECRYPT_FUNC_NAME.captures(js).and_then(|cap| cap.at(1)).expect("unable to find decrypt function")
}

#[cfg(test)]
mod tests {
    #[test]
    fn regex_patterns_compile() {
        use video::youtube::{
            DECRYPT_FUNC_NAME
        };

        DECRYPT_FUNC_NAME.is_match("");
    }

    #[test]
    fn swap() {
        use video::youtube::CryptOp;

        let op = CryptOp::Swap(4);
        let target = ['e', 'b', 'c', 'd', 'a'];
        let mut vec = vec!['a', 'b', 'c', 'd', 'e'];

        op.apply(&mut vec);
        assert_eq!(target, vec.as_ref());
    }

    #[test]
    fn slice() {
        use video::youtube::CryptOp;

        let op = CryptOp::Slice(2);
        let target = ['c', 'd', 'e'];
        let mut vec = vec!['a', 'b', 'c', 'd', 'e'];

        op.apply(&mut vec);
        assert_eq!(target, vec.as_ref());
    }

    #[test]
    fn reverse() {
        use video::youtube::CryptOp;

        let op = CryptOp::Reverse;
        let target = ['e', 'd', 'c', 'b', 'a'];
        let mut vec = vec!['a', 'b', 'c', 'd', 'e'];

        op.apply(&mut vec);
        assert_eq!(target, vec.as_ref());
    }
}
<commit_msg>first semi-working version<commit_after>use http;
use regex::Regex;
use video::Video;

lazy_static! {
    static ref DECRYPT_FUNC_NAME: Regex = Regex::new(r#"\.sig\|\|(\w+[.])?(\w+)\("#).unwrap();
    static ref FUNC_ID: Regex = Regex::new(r#"(\w+)\("#).unwrap();
}

enum CryptOp {
    Reverse,        // reverses entire string
    Swap(usize),    // swaps character at idx with first character
    Slice(usize),   // removes characters up to idx
}

impl CryptOp {
    fn swap(s: &str) -> CryptOp {
        let numeric_values: String = s.chars().filter(|value| value.is_numeric()).collect();
        CryptOp::Swap(numeric_values.parse().expect(&format!("swap unable to parse {:?} {:?} as number", s,numeric_values)))
    }

    fn slice(s: &str) -> CryptOp {
        let numeric_values: String = s.chars().filter(|value| value.is_numeric()).collect();
        CryptOp::Slice(numeric_values.parse().expect(&format!("swap unable to parse {:?} {:?} as number", s,numeric_values)))
    }

    fn apply(&self, sig: &mut Vec<char>) {
        match *self {
            CryptOp::Reverse => *sig = sig.iter().cloned().rev().collect(),
            CryptOp::Swap(idx) => sig.swap(0, idx),
            CryptOp::Slice(idx) => *sig = sig.split_off(idx),
        }
    }
}

#[derive(Debug)]
pub struct YoutubeVideo {
    title: String,
    uri: String,
    js_player: String,
}

impl YoutubeVideo {
    pub fn new(title: &str, uri: &str, js_player: &str, signature: &Option<String>) -> YoutubeVideo {
        let mut uri = uri.to_owned();
        if let &Some(ref signature) = signature {
            uri = decrypt(&uri, js_player, signature);
        }

        YoutubeVideo {
            title: title.to_owned(),
            uri: uri,
            js_player: js_player.to_owned(),
        }
    }
}

impl Video for YoutubeVideo {
    fn title(&self) -> &str {
        &self.title
    }

    fn uri(&mut self) -> &str {
        &self.uri
    }
}

fn decrypt(uri: &str, js_player: &str, signature: &str) -> String {
    let js = http::download_string(js_player).expect("failed to download js");
    let operations = discover_operations(&js);

    let mut signature: Vec<_> = signature.chars().collect();
    for op in operations {
        op.apply(&mut signature);
    }

    let signature: String = signature.iter().cloned().collect();
    format!("{}&signature={}", uri, signature)
}

fn discover_operations(js: &str) -> Vec<CryptOp> {
    let pattern = format!("{}=function\\(\\w\\)\\{{(.*?)\\}}", decrypt_function(js));
    let regex = Regex::new(&pattern).expect(&format!("dynamic regex failed to compile: {}", pattern));
    let function_body = regex.captures(js).and_then(|cap| cap.at(1)).expect("unable to capture decrypt function");

    let mut reverse_id = None;
    let mut swap_id = None;
    let mut slice_id = None;

    function_body.split(';').skip(1).filter(|line| !line.starts_with("return")).map(|line| {
        let id = get_id(&line);

        match reverse_id {
            None => if is_reverse_id(id, js) {
                reverse_id = Some(id.to_owned());
                return CryptOp::Reverse;
            },
            Some(ref reverse_id) => if reverse_id == id {
                return CryptOp::Reverse;
            }
        }

        match swap_id {
            None => if is_swap_id(id, js) {
                swap_id = Some(id.to_owned());
                return CryptOp::swap(line);
            },
            Some(ref swap_id) => if swap_id == id {
                return CryptOp::swap(line);
            }
        }

        match slice_id {
            None => if is_slice_id(&id, &js) {
                slice_id = Some(id.to_owned());
                return CryptOp::slice(line);
            },
            Some(ref slice_id) => if slice_id == id {
                return CryptOp::slice(line);
            }
        }

        panic!("unknown crypto transform");
    }).collect()
}

fn get_id(s: &str) -> &str {
    FUNC_ID.captures(s).and_then(|cap| cap.at(1)).unwrap_or("")
}

fn is_reverse_id(id: &str, js: &str) -> bool {
    Regex::new(&format!("{}:\\bfunction\\b\\(\\w+\\)", id))
        .map(|pattern| pattern.is_match(js))
        .unwrap_or(false)
}

fn is_swap_id(id: &str, js: &str) -> bool {
    Regex::new(&format!("{}\\bfunction\\b\\(\\w+\\,\\w\\).\\bvar\\b.\\bc=a\\b", id))
        .map(|pattern| pattern.is_match(js))
        .unwrap_or(false)
}

fn is_slice_id(id: &str, js: &str) -> bool {
    Regex::new(&format!("{}:\\bfunction\\b\\([a],b\\).(\\breturn\\b)?.?\\w+\\.", id))
        .map(|pattern| pattern.is_match(js))
        .unwrap_or(false)
}

/// Returns the decryption function found in the javascript source code
fn decrypt_function(js: &str) -> &str {
    // the C# program I'm porting had a custom-build dfa or state machine or
    // whatever for this crap... I feel like rust's regex crate is good enough
    // I can just say fuck all that noise

    DECRYPT_FUNC_NAME.captures(js).and_then(|cap| cap.at(2)).expect("unable to find decrypt function")
}

#[cfg(test)]
mod tests {
    #[test]
    fn regex_patterns_compile() {
        use regex::Regex;
        use video::youtube::{
            DECRYPT_FUNC_NAME,
            FUNC_ID,
        };

        DECRYPT_FUNC_NAME.is_match("");
        FUNC_ID.is_match("");

        // this is an example of the dynamic regex used to find the decrypt function
        let pattern = r#"by=function\(\w\)\{(.*?)\}"#;
        Regex::new(pattern).unwrap();
    }

    #[test]
    fn swap() {
        use video::youtube::CryptOp;

        let op = CryptOp::Swap(4);
        let target = ['e', 'b', 'c', 'd', 'a'];
        let mut vec = vec!['a', 'b', 'c', 'd', 'e'];

        op.apply(&mut vec);
        assert_eq!(target, vec.as_ref());
    }

    #[test]
    fn slice() {
        use video::youtube::CryptOp;

        let op = CryptOp::Slice(2);
        let target = ['c', 'd', 'e'];
        let mut vec = vec!['a', 'b', 'c', 'd', 'e'];

        op.apply(&mut vec);
        assert_eq!(target, vec.as_ref());
    }

    #[test]
    fn reverse() {
        use video::youtube::CryptOp;

        let op = CryptOp::Reverse;
        let target = ['e', 'd', 'c', 'b', 'a'];
        let mut vec = vec!['a', 'b', 'c', 'd', 'e'];

        op.apply(&mut vec);
        assert_eq!(target, vec.as_ref());
    }
}
<|endoftext|>


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

#[macro_escape];

// Some basic logging
macro_rules! rtdebug (
    ($( $arg:expr),+) => ( {
        dumb_println(fmt!( $($arg),+ ));

        fn dumb_println(s: &str) {
            use io::WriterUtil;
            let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
            dbg.write_str(s);
            dbg.write_str("\n");
        }

    } )
)

// An alternate version with no output, for turning off logging
macro_rules! rtdebug_ (
    ($( $arg:expr),+) => ( $(let _ = $arg)*; )
)

macro_rules! abort(
    ($( $msg:expr),+) => ( {
        rtdebug!($($msg),+);

        unsafe { ::libc::abort(); }
    } )
)
<commit_msg>core: Turn off rtdebug logging<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[macro_escape];

// Some basic logging
macro_rules! rtdebug_ (
    ($( $arg:expr),+) => ( {
        dumb_println(fmt!( $($arg),+ ));

        fn dumb_println(s: &str) {
            use io::WriterUtil;
            let dbg = ::libc::STDERR_FILENO as ::io::fd_t;
            dbg.write_str(s);
            dbg.write_str("\n");
        }

    } )
)

// An alternate version with no output, for turning off logging
macro_rules! rtdebug (
    ($( $arg:expr),+) => ( $(let _ = $arg)*; )
)

macro_rules! abort(
    ($( $msg:expr),+) => ( {
        rtdebug!($($msg),+);

        unsafe { ::libc::abort(); }
    } )
)
<|endoftext|>


<commit_before>use owning_ref::{OwningHandle, RcRef};
use std::any::Any;
use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use view::{Selector, View, ViewWrapper};

/// Wrapper around a view to provide interior mutability.
pub struct IdView<V: View> {
    view: Rc<RefCell<V>>,
    id: String,
}

/// Mutable reference to a view.
///
/// This behaves like a [`RefMut`], but without being tied to a lifetime.
///
/// [`RefMut`]: https://doc.rust-lang.org/std/cell/struct.RefMut.html
pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>;

impl<V: View> IdView<V> {
    /// Wraps `view` in a new `IdView`.
    pub fn new<S: Into<String>>(id: S, view: V) -> Self {
        IdView {
            view: Rc::new(RefCell::new(view)),
            id: id.into(),
        }
    }

    /// Gets mutable access to the inner view.
    ///
    /// This returns a `ViewRef<V>`, which implement `DerefMut<Target = V>`.
    ///
    /// # Panics
    ///
    /// Panics if another reference for this view already exists.
    pub fn get_mut(&mut self) -> ViewRef<V> {
        let cell_ref = RcRef::new(Rc::clone(&self.view));

        OwningHandle::new_mut(cell_ref)
    }
}

impl<T: View + 'static> ViewWrapper for IdView<T> {
    type V = T;

    fn with_view<F, R>(&self, f: F) -> Option<R>
    where
        F: FnOnce(&Self::V) -> R,
    {
        self.view.try_borrow().ok().map(|v| f(&*v))
    }

    fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
    where
        F: FnOnce(&mut Self::V) -> R,
    {
        self.view.try_borrow_mut().ok().map(|mut v| f(&mut *v))
    }

    // Some for<'b> weirdness here to please the borrow checker gods...
    fn wrap_call_on_any<'a>(
        &mut self, selector: &Selector,
        mut callback: Box<for<'b> FnMut(&'b mut Any) + 'a>,
    ) {
        match selector {
            &Selector::Id(id) if id == self.id => callback(self),
            s => {
                self.view
                    .try_borrow_mut()
                    .ok()
                    .map(|mut v| v.call_on_any(s, callback));
            }
        }
    }

    fn wrap_focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        match selector {
            &Selector::Id(id) if id == self.id => Ok(()),
            s => self.view
                .try_borrow_mut()
                .map_err(|_| ())
                .and_then(|mut v| v.focus_view(s)),
        }
    }
}
<commit_msg>Use intermediate type<commit_after>use owning_ref::{OwningHandle, RcRef};
use std::any::Any;
use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use view::{Selector, View, ViewWrapper};

/// Wrapper around a view to provide interior mutability.
pub struct IdView<V: View> {
    view: Rc<RefCell<V>>,
    id: String,
}

/// Mutable reference to a view.
///
/// This behaves like a [`RefMut`], but without being tied to a lifetime.
///
/// [`RefMut`]: https://doc.rust-lang.org/std/cell/struct.RefMut.html
pub type ViewRef<V> = OwningHandle<RcRef<RefCell<V>>, RefMut<'static, V>>;

impl<V: View> IdView<V> {
    /// Wraps `view` in a new `IdView`.
    pub fn new<S: Into<String>>(id: S, view: V) -> Self {
        IdView {
            view: Rc::new(RefCell::new(view)),
            id: id.into(),
        }
    }

    /// Gets mutable access to the inner view.
    ///
    /// This returns a `ViewRef<V>`, which implement `DerefMut<Target = V>`.
    ///
    /// # Panics
    ///
    /// Panics if another reference for this view already exists.
    pub fn get_mut(&mut self) -> ViewRef<V> {
        let cell_ref = RcRef::new(Rc::clone(&self.view));

        OwningHandle::new_mut(cell_ref)
    }
}

// Shortcut for a boxed callback (for the wrap_call_on_any method).
type BoxedCallback<'a> = Box<for<'b> FnMut(&'b mut Any) + 'a>;

impl<T: View + 'static> ViewWrapper for IdView<T> {
    type V = T;

    fn with_view<F, R>(&self, f: F) -> Option<R>
    where
        F: FnOnce(&Self::V) -> R,
    {
        self.view.try_borrow().ok().map(|v| f(&*v))
    }

    fn with_view_mut<F, R>(&mut self, f: F) -> Option<R>
    where
        F: FnOnce(&mut Self::V) -> R,
    {
        self.view.try_borrow_mut().ok().map(|mut v| f(&mut *v))
    }

    // Some for<'b> weirdness here to please the borrow checker gods...
    fn wrap_call_on_any<'a>(
        &mut self, selector: &Selector, mut callback: BoxedCallback<'a>
    ) {
        match selector {
            &Selector::Id(id) if id == self.id => callback(self),
            s => {
                self.view
                    .try_borrow_mut()
                    .ok()
                    .map(|mut v| v.call_on_any(s, callback));
            }
        }
    }

    fn wrap_focus_view(&mut self, selector: &Selector) -> Result<(), ()> {
        match selector {
            &Selector::Id(id) if id == self.id => Ok(()),
            s => self.view
                .try_borrow_mut()
                .map_err(|_| ())
                .and_then(|mut v| v.focus_view(s)),
        }
    }
}
<|endoftext|>