<commit_before>use std::any::{Any, TypeId};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::mem;
use std::ptr;

use ffi;
use libc;

use AsLua;
use AsMutLua;
use Push;
use PushGuard;
use LuaRead;

use InsideCallback;
use LuaTable;

// Called when an object inside Lua is being dropped.
#[inline]
extern "C" fn destructor_wrapper<T>(lua: *mut ffi::lua_State) -> libc::c_int {
    unsafe {
        let obj = ffi::lua_touserdata(lua, -1);
        ptr::drop_in_place(obj as *mut TypeId);
        ptr::drop_in_place((obj as *mut u8).offset(mem::size_of::<TypeId>() as isize) as *mut T);
        0
    }
}

/// Pushes an object as a user data.
///
/// In Lua, a user data is anything that is not recognized by Lua. When the script attempts to
/// copy a user data, instead only a reference to the data is copied.
///
/// The way a Lua script can use the user data depends on the content of the **metatable**, which
/// is a Lua table linked to the object.
///
/// [See this link for more infos.](http://www.lua.org/manual/5.2/manual.html#2.4)
///
/// # About the Drop trait
///
/// When the Lua context detects that a userdata is no longer needed it calls the function at the
/// `__gc` index in the userdata's metatable, if any. The hlua library will automatically fill this
/// index with a function that invokes the `Drop` trait of the userdata.
///
/// You can replace the function if you wish so, although you are strongly discouraged to do it.
/// It is no unsafe to leak data in Rust, so there is no safety issue in doing so.
///
/// # Arguments
///
///  - `metatable`: Function that fills the metatable of the object.
///
#[inline]
pub fn push_userdata<'lua, L, T, F>(data: T, mut lua: L, metatable: F) -> PushGuard<L>
    where F: FnOnce(LuaTable<&mut PushGuard<&mut L>>),
          L: AsMutLua<'lua>,
          T: Send + 'static + Any
{
    unsafe {
        let typeid = TypeId::of::<T>();

        let lua_data = {
            let tot_size = mem::size_of_val(&typeid) + mem::size_of_val(&data);
            ffi::lua_newuserdata(lua.as_mut_lua().0, tot_size as libc::size_t)
        };

        // We check the alignment requirements.
        debug_assert_eq!(lua_data as usize % mem::align_of_val(&data), 0);
        // Since the size of a `TypeId` should always be a usize, this assert should pass every
        // time as well.
        debug_assert_eq!(mem::size_of_val(&typeid) % mem::align_of_val(&data), 0);

        // We write the `TypeId` first, and the data right next to it.
        ptr::write(lua_data as *mut TypeId, typeid);
        let data_loc = (lua_data as *const u8).offset(mem::size_of_val(&typeid) as isize);
        ptr::write(data_loc as *mut _, data);

        let lua_raw = lua.as_mut_lua();

        // Creating a metatable.
        ffi::lua_newtable(lua.as_mut_lua().0);

        // Index "__gc" in the metatable calls the object's destructor.

        // TODO: Could use std::intrinsics::needs_drop to avoid that if not needed.
        // After some discussion on IRC, it would be acceptable to add a reexport in libcore
        // without going through the RFC process.
        {
            match "__gc".push_to_lua(&mut lua) {
                Ok(p) => p.forget(),
                Err(_) => unreachable!(),
            };

            ffi::lua_pushcfunction(lua.as_mut_lua().0, destructor_wrapper::<T>);
            ffi::lua_settable(lua.as_mut_lua().0, -3);
        }

        // Calling the metatable closure.
        {
            let raw_lua = lua.as_lua();
            let mut guard = PushGuard {
                lua: &mut lua,
                size: 1,
                raw_lua: raw_lua,
            };
            metatable(LuaRead::lua_read(&mut guard).ok().unwrap());
            guard.forget();
        }

        ffi::lua_setmetatable(lua_raw.0, -2);
    }

    let raw_lua = lua.as_lua();
    PushGuard {
        lua: lua,
        size: 1,
        raw_lua: raw_lua,
    }
}

///
#[inline]
pub fn read_userdata<'t, 'c, T>(mut lua: &'c mut InsideCallback,
                                index: i32)
                                -> Result<&'t mut T, &'c mut InsideCallback>
    where T: 'static + Any
{
    unsafe {
        let data_ptr = ffi::lua_touserdata(lua.as_lua().0, index);
        if data_ptr.is_null() {
            return Err(lua);
        }

        let actual_typeid = data_ptr as *const TypeId;
        if *actual_typeid != TypeId::of::<T>() {
            return Err(lua);
        }

        let data = (data_ptr as *const u8).offset(mem::size_of::<TypeId>() as isize);
        Ok(&mut *(data as *mut T))
    }
}

/// Represents a user data located inside the Lua context.
pub struct UserdataOnStack<T, L> {
    variable: L,
    marker: PhantomData<T>,
}

impl<'lua, T, L> LuaRead<L> for UserdataOnStack<T, L>
    where L: AsMutLua<'lua> + AsLua<'lua>,
          T: 'lua + Any
{
    #[inline]
    fn lua_read_at_position(lua: L, index: i32) -> Result<UserdataOnStack<T, L>, L> {
        unsafe {
            let data_ptr = ffi::lua_touserdata(lua.as_lua().0, index);
            if data_ptr.is_null() {
                return Err(lua);
            }

            let actual_typeid = data_ptr as *const TypeId;
            if *actual_typeid != TypeId::of::<T>() {
                return Err(lua);
            }

            Ok(UserdataOnStack {
                variable: lua,
                marker: PhantomData,
            })
        }
    }
}

impl<'lua, T, L> Deref for UserdataOnStack<T, L>
    where L: AsLua<'lua>,
          T: 'lua + Any
{
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe {
            let base = ffi::lua_touserdata(self.variable.as_lua().0, -1);
            let data = (base as *const u8).offset(mem::size_of::<TypeId>() as isize);
            &*(data as *const T)
        }
    }
}

impl<'lua, T, L> DerefMut for UserdataOnStack<T, L>
    where L: AsMutLua<'lua>,
          T: 'lua + Any
{
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe {
            let base = ffi::lua_touserdata(self.variable.as_mut_lua().0, -1);
            let data = (base as *const u8).offset(mem::size_of::<TypeId>() as isize);
            &mut *(data as *mut T)
        }
    }
}
<commit_msg>drop redundant AsLua requirement on UserdataOnStack<commit_after>use std::any::{Any, TypeId};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::mem;
use std::ptr;

use ffi;
use libc;

use AsLua;
use AsMutLua;
use Push;
use PushGuard;
use LuaRead;

use InsideCallback;
use LuaTable;

// Called when an object inside Lua is being dropped.
#[inline]
extern "C" fn destructor_wrapper<T>(lua: *mut ffi::lua_State) -> libc::c_int {
    unsafe {
        let obj = ffi::lua_touserdata(lua, -1);
        ptr::drop_in_place(obj as *mut TypeId);
        ptr::drop_in_place((obj as *mut u8).offset(mem::size_of::<TypeId>() as isize) as *mut T);
        0
    }
}

/// Pushes an object as a user data.
///
/// In Lua, a user data is anything that is not recognized by Lua. When the script attempts to
/// copy a user data, instead only a reference to the data is copied.
///
/// The way a Lua script can use the user data depends on the content of the **metatable**, which
/// is a Lua table linked to the object.
///
/// [See this link for more infos.](http://www.lua.org/manual/5.2/manual.html#2.4)
///
/// # About the Drop trait
///
/// When the Lua context detects that a userdata is no longer needed it calls the function at the
/// `__gc` index in the userdata's metatable, if any. The hlua library will automatically fill this
/// index with a function that invokes the `Drop` trait of the userdata.
///
/// You can replace the function if you wish so, although you are strongly discouraged to do it.
/// It is no unsafe to leak data in Rust, so there is no safety issue in doing so.
///
/// # Arguments
///
///  - `metatable`: Function that fills the metatable of the object.
///
#[inline]
pub fn push_userdata<'lua, L, T, F>(data: T, mut lua: L, metatable: F) -> PushGuard<L>
    where F: FnOnce(LuaTable<&mut PushGuard<&mut L>>),
          L: AsMutLua<'lua>,
          T: Send + 'static + Any
{
    unsafe {
        let typeid = TypeId::of::<T>();

        let lua_data = {
            let tot_size = mem::size_of_val(&typeid) + mem::size_of_val(&data);
            ffi::lua_newuserdata(lua.as_mut_lua().0, tot_size as libc::size_t)
        };

        // We check the alignment requirements.
        debug_assert_eq!(lua_data as usize % mem::align_of_val(&data), 0);
        // Since the size of a `TypeId` should always be a usize, this assert should pass every
        // time as well.
        debug_assert_eq!(mem::size_of_val(&typeid) % mem::align_of_val(&data), 0);

        // We write the `TypeId` first, and the data right next to it.
        ptr::write(lua_data as *mut TypeId, typeid);
        let data_loc = (lua_data as *const u8).offset(mem::size_of_val(&typeid) as isize);
        ptr::write(data_loc as *mut _, data);

        let lua_raw = lua.as_mut_lua();

        // Creating a metatable.
        ffi::lua_newtable(lua.as_mut_lua().0);

        // Index "__gc" in the metatable calls the object's destructor.

        // TODO: Could use std::intrinsics::needs_drop to avoid that if not needed.
        // After some discussion on IRC, it would be acceptable to add a reexport in libcore
        // without going through the RFC process.
        {
            match "__gc".push_to_lua(&mut lua) {
                Ok(p) => p.forget(),
                Err(_) => unreachable!(),
            };

            ffi::lua_pushcfunction(lua.as_mut_lua().0, destructor_wrapper::<T>);
            ffi::lua_settable(lua.as_mut_lua().0, -3);
        }

        // Calling the metatable closure.
        {
            let raw_lua = lua.as_lua();
            let mut guard = PushGuard {
                lua: &mut lua,
                size: 1,
                raw_lua: raw_lua,
            };
            metatable(LuaRead::lua_read(&mut guard).ok().unwrap());
            guard.forget();
        }

        ffi::lua_setmetatable(lua_raw.0, -2);
    }

    let raw_lua = lua.as_lua();
    PushGuard {
        lua: lua,
        size: 1,
        raw_lua: raw_lua,
    }
}

///
#[inline]
pub fn read_userdata<'t, 'c, T>(mut lua: &'c mut InsideCallback,
                                index: i32)
                                -> Result<&'t mut T, &'c mut InsideCallback>
    where T: 'static + Any
{
    unsafe {
        let data_ptr = ffi::lua_touserdata(lua.as_lua().0, index);
        if data_ptr.is_null() {
            return Err(lua);
        }

        let actual_typeid = data_ptr as *const TypeId;
        if *actual_typeid != TypeId::of::<T>() {
            return Err(lua);
        }

        let data = (data_ptr as *const u8).offset(mem::size_of::<TypeId>() as isize);
        Ok(&mut *(data as *mut T))
    }
}

/// Represents a user data located inside the Lua context.
pub struct UserdataOnStack<T, L> {
    variable: L,
    marker: PhantomData<T>,
}

impl<'lua, T, L> LuaRead<L> for UserdataOnStack<T, L>
    where L: AsMutLua<'lua>,
          T: 'lua + Any
{
    #[inline]
    fn lua_read_at_position(lua: L, index: i32) -> Result<UserdataOnStack<T, L>, L> {
        unsafe {
            let data_ptr = ffi::lua_touserdata(lua.as_lua().0, index);
            if data_ptr.is_null() {
                return Err(lua);
            }

            let actual_typeid = data_ptr as *const TypeId;
            if *actual_typeid != TypeId::of::<T>() {
                return Err(lua);
            }

            Ok(UserdataOnStack {
                variable: lua,
                marker: PhantomData,
            })
        }
    }
}

impl<'lua, T, L> Deref for UserdataOnStack<T, L>
    where L: AsLua<'lua>,
          T: 'lua + Any
{
    type Target = T;

    #[inline]
    fn deref(&self) -> &T {
        unsafe {
            let base = ffi::lua_touserdata(self.variable.as_lua().0, -1);
            let data = (base as *const u8).offset(mem::size_of::<TypeId>() as isize);
            &*(data as *const T)
        }
    }
}

impl<'lua, T, L> DerefMut for UserdataOnStack<T, L>
    where L: AsMutLua<'lua>,
          T: 'lua + Any
{
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        unsafe {
            let base = ffi::lua_touserdata(self.variable.as_mut_lua().0, -1);
            let data = (base as *const u8).offset(mem::size_of::<TypeId>() as isize);
            &mut *(data as *mut T)
        }
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate libc;

use crate::config::Config;
use crate::layout::{Layout, LayoutMsg};
use crate::xlib_window_system::XlibWindowSystem;
use crate::state::WmState;
use crate::workspace::MoveOp;
use self::libc::execvpe;
use std::{env, iter};
use std::ptr::null;
use std::ffi::CString;
use std::process::Command;
use std::path::Path;
use std::fs::OpenOptions;
use x11::xlib::Window;
use anyhow::{bail, Context, Result};

pub enum Cmd {
    Custom(Box<dyn Fn(&WmState) -> Result<Option<Cmd>, String>>),
    Exec(String, Vec<String>),
    SwitchWorkspace(usize),
    SwitchScreen(usize),
    MoveToWorkspace(usize),
    MoveToScreen(usize),
    SendLayoutMsg(LayoutMsg),
    NestLayout(Box<dyn Fn() -> Box<dyn Layout>>),
    Reload,
    Exit,
    KillClient,
    FocusParentUp,
    FocusParentDown,
    FocusParentMaster,
    FocusUp,
    FocusDown,
    FocusMaster,
    SwapUp,
    SwapDown,
    SwapMaster,
    SwapParentUp,
    SwapParentDown,
    SwapParentMaster,
}

impl Cmd {
    pub fn call(&self, xws: &XlibWindowSystem, state: &mut WmState, config: &Config) -> Result<()> {
        match self {
            Cmd::Custom(func) => {
                debug!("Cmd::Custom");
                match func(state) {
                    Ok(Some(cmd)) => cmd.call(xws, state, config)?,
                    Ok(None) => (),
                    Err(e) => error!("Cmd::Custom failed: {}", e),
                }
            }
            Cmd::Exec(ref cmd, ref args) => {
                debug!("Cmd::Exec: {} {:?}", cmd, args);
                exec(cmd.clone(), args.clone());
            }
            Cmd::SwitchWorkspace(index) => {
                debug!("Cmd::SwitchWorkspace: {}", index);
                state.switch_to_ws(xws, config, index - 1, true);
            }
            Cmd::SwitchScreen(screen) => {
                debug!("Cmd::SwitchScreen: {}", screen);
                state.switch_to_screen(xws, config, screen - 1);
            }
            Cmd::MoveToWorkspace(index) => {
                debug!("Cmd::MoveToWorkspace: {}", index);
                state.move_window_to_ws(xws, config, index - 1);
            }
            Cmd::MoveToScreen(screen) => {
                debug!("Cmd::MoveToScreen: {}", screen);
                state.move_window_to_screen(xws, config, screen - 1);
            }
            Cmd::SendLayoutMsg(ref msg) => {
                debug!("Cmd::SendLayoutMsg::{:?}", msg);
                state.current_ws_mut().send_layout_message(xws, msg.clone());
                state.current_ws().redraw(xws, config, state.get_screens());
            }
            Cmd::NestLayout(layout_fn) => {
                let layout = layout_fn();
                debug!("Cmd::NestLayout: {}", layout.name());
                state.current_ws_mut().nest_layout(layout);
            }
            Cmd::Reload => {
                debug!("Cmd::Reload");
                reload(state)
                    .context("failed to reload xr3wm")?;
            }
            Cmd::Exit => {
                debug!("Cmd::Exit");
                xws.close();
            }
            Cmd::KillClient => {
                if let Some(window) = state.current_ws().focused_window() {
                    debug!("Cmd::KillClient: {:#x}", window);
                    xws.kill_window(window);
                }
            }
            Cmd::FocusUp | Cmd::FocusDown | Cmd::FocusMaster | Cmd::FocusParentUp | Cmd::FocusParentDown | Cmd::FocusParentMaster => {
                if let Some(window) = state.current_ws().focused_window() {
                    let workspace = state.current_ws_mut();
                    let new_focus = match self {
                        Cmd::FocusUp => {
                            debug!("Cmd::FocusUp: {:#x}", window);
                            workspace.move_focus(MoveOp::Up)
                        }
                        Cmd::FocusDown => {
                            debug!("Cmd::FocusDown: {:#x}", window);
                            workspace.move_focus(MoveOp::Down)
                        }
                        Cmd::FocusMaster => {
                            debug!("Cmd::FocusMaster: {:#x}", window);
                            workspace.move_focus(MoveOp::Swap)
                        }
                        Cmd::FocusParentUp => {
                            debug!("Cmd::FocusParentUp: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Up)
                        }
                        Cmd::FocusParentDown => {
                            debug!("Cmd::FocusParentDown: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Down)
                        }
                        Cmd::FocusParentMaster => {
                            debug!("Cmd::FocusParentMaster: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Swap)
                        }
                        _ => None
                    };

                    if let Some(window) = new_focus {
                        xws.focus_window(window);
                    }
                }
            },
            Cmd::SwapUp | Cmd::SwapDown | Cmd::SwapMaster | Cmd::SwapParentUp | Cmd::SwapParentDown | Cmd::SwapParentMaster => {
                if let Some(window) = state.current_ws().focused_window() {
                    let workspace = state.current_ws_mut();
                    let new_focus = match self {
                        Cmd::SwapUp => {
                            debug!("Cmd::SwapUp: {:#x}", window);
                            workspace.move_window(MoveOp::Up)
                        }
                        Cmd::SwapDown => {
                            debug!("Cmd::SwapDown: {:#x}", window);
                            workspace.move_window(MoveOp::Down)
                        }
                        Cmd::SwapMaster => {
                            debug!("Cmd::SwapMaster: {:#x}", window);
                            workspace.move_window(MoveOp::Swap)
                        }
                        Cmd::SwapParentUp => {
                            debug!("Cmd::SwapParentUp: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Up)
                        }
                        Cmd::SwapParentDown => {
                            debug!("Cmd::SwapParentDown: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Down)
                        }
                        Cmd::SwapParentMaster => {
                            debug!("Cmd::SwapParentMaster: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Swap)
                        }
                        _ => false
                    };

                    if new_focus {
                        state.current_ws().redraw(xws, config, state.get_screens());
                    }
                }
            }
        }
        Ok(())
    }
}

fn reload(state: &WmState) -> Result<()> {
    info!("recompiling...");

    let cfg_dir = Config::get_dir()
        .context("failed to locate config directory")?;
    let mut cmd = Command::new("cargo");

    let output = cmd.current_dir(&format!("{}/.build", cfg_dir))
        .arg("build")
        .env("RUST_LOG", "none")
        .output()
        .context("failed to run cargo")?;

    if !output.status.success() {
        let stderr_msg = String::from_utf8(output.stderr)
            .context("failed to convert cargo stderr to UTF-8")?;
        bail!("failed to recompile: {}", stderr_msg)
    }

    debug!("Cmd::Reload: restarting xr3wm...");

    let path = Path::new(&cfg_dir).join(".state.tmp");

    // save current workspace states to restore on restart
    let file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(&path)
        .context("failed to open workspace state tmp file")?;

    serde_json::to_writer(file, state)
        .context("failed to serialize workspace states")?;

    let args: Vec<*const libc::c_char> = env::args()
        .filter_map(|x| CString::new(x).ok())
        .map(|x| x.into_raw() as *const libc::c_char)
        .chain(iter::once(null()))
        .collect();

    let envs: Vec<*const libc::c_char> = env::vars()
        .filter_map(|(k,v)| CString::new(format!("{}={}", k, v)).ok())
        .map(|x| x.into_raw() as *const libc::c_char)
        .chain(iter::once(null()))
        .collect();

    unsafe {
        execvpe(args[0] as *const libc::c_char, args.as_ptr(), envs.as_ptr());
        // execvp returns only if an error has occurred
        error!("failed to reload: {}", ::std::io::Error::last_os_error());
    }

    Ok(())
}

pub struct ManageHook {
    pub class_name: String,
    pub cmd: CmdManage,
}

pub enum CmdManage {
    Move(usize),
    Float,
    Fullscreen,
    Ignore,
}

impl CmdManage {
    pub fn call(&self,
                xws: &XlibWindowSystem,
                state: &mut WmState,
                config: &Config,
                window: Window) {
        match *self {
            CmdManage::Move(index) => {
                debug!("CmdManage::Move: {}, {}", window, index);
                state.add_window(Some(index - 1), xws, config, window);
            }
            CmdManage::Float => {
                debug!("CmdManage::Float");
                unimplemented!()
            }
            CmdManage::Fullscreen => {
                debug!("CmdManage::Fullscreen");
                unimplemented!()
            }
            CmdManage::Ignore => {
                debug!("CmdManage::Ignore");
                unimplemented!()
            }
        }
    }
}

fn exec(cmd: String, args: Vec<String>) {
    if !cmd.is_empty() {
        let mut cmd = Command::new(cmd);

        if !args.is_empty() {
            cmd.args(&args);
        }

        std::thread::spawn(move || {
            match cmd.envs(env::vars()).spawn() {
                Ok(mut child) => {
                    child.wait().ok();
                },
                Err(e) => error!("failed to start \"{:?}\": {}", cmd, e),
            }
        });
    }
}
<commit_msg>Discard output of spawned commands<commit_after>#![allow(dead_code)]

extern crate libc;

use crate::config::Config;
use crate::layout::{Layout, LayoutMsg};
use crate::xlib_window_system::XlibWindowSystem;
use crate::state::WmState;
use crate::workspace::MoveOp;
use self::libc::execvpe;
use std::{env, iter};
use std::ptr::null;
use std::ffi::CString;
use std::process::{Command, Stdio};
use std::path::Path;
use std::fs::OpenOptions;
use x11::xlib::Window;
use anyhow::{bail, Context, Result};

pub enum Cmd {
    Custom(Box<dyn Fn(&WmState) -> Result<Option<Cmd>, String>>),
    Exec(String, Vec<String>),
    SwitchWorkspace(usize),
    SwitchScreen(usize),
    MoveToWorkspace(usize),
    MoveToScreen(usize),
    SendLayoutMsg(LayoutMsg),
    NestLayout(Box<dyn Fn() -> Box<dyn Layout>>),
    Reload,
    Exit,
    KillClient,
    FocusParentUp,
    FocusParentDown,
    FocusParentMaster,
    FocusUp,
    FocusDown,
    FocusMaster,
    SwapUp,
    SwapDown,
    SwapMaster,
    SwapParentUp,
    SwapParentDown,
    SwapParentMaster,
}

impl Cmd {
    pub fn call(&self, xws: &XlibWindowSystem, state: &mut WmState, config: &Config) -> Result<()> {
        match self {
            Cmd::Custom(func) => {
                debug!("Cmd::Custom");
                match func(state) {
                    Ok(Some(cmd)) => cmd.call(xws, state, config)?,
                    Ok(None) => (),
                    Err(e) => error!("Cmd::Custom failed: {}", e),
                }
            }
            Cmd::Exec(ref cmd, ref args) => {
                debug!("Cmd::Exec: {} {:?}", cmd, args);
                exec(cmd.clone(), args.clone());
            }
            Cmd::SwitchWorkspace(index) => {
                debug!("Cmd::SwitchWorkspace: {}", index);
                state.switch_to_ws(xws, config, index - 1, true);
            }
            Cmd::SwitchScreen(screen) => {
                debug!("Cmd::SwitchScreen: {}", screen);
                state.switch_to_screen(xws, config, screen - 1);
            }
            Cmd::MoveToWorkspace(index) => {
                debug!("Cmd::MoveToWorkspace: {}", index);
                state.move_window_to_ws(xws, config, index - 1);
            }
            Cmd::MoveToScreen(screen) => {
                debug!("Cmd::MoveToScreen: {}", screen);
                state.move_window_to_screen(xws, config, screen - 1);
            }
            Cmd::SendLayoutMsg(ref msg) => {
                debug!("Cmd::SendLayoutMsg::{:?}", msg);
                state.current_ws_mut().send_layout_message(xws, msg.clone());
                state.current_ws().redraw(xws, config, state.get_screens());
            }
            Cmd::NestLayout(layout_fn) => {
                let layout = layout_fn();
                debug!("Cmd::NestLayout: {}", layout.name());
                state.current_ws_mut().nest_layout(layout);
            }
            Cmd::Reload => {
                debug!("Cmd::Reload");
                reload(state)
                    .context("failed to reload xr3wm")?;
            }
            Cmd::Exit => {
                debug!("Cmd::Exit");
                xws.close();
            }
            Cmd::KillClient => {
                if let Some(window) = state.current_ws().focused_window() {
                    debug!("Cmd::KillClient: {:#x}", window);
                    xws.kill_window(window);
                }
            }
            Cmd::FocusUp | Cmd::FocusDown | Cmd::FocusMaster | Cmd::FocusParentUp | Cmd::FocusParentDown | Cmd::FocusParentMaster => {
                if let Some(window) = state.current_ws().focused_window() {
                    let workspace = state.current_ws_mut();
                    let new_focus = match self {
                        Cmd::FocusUp => {
                            debug!("Cmd::FocusUp: {:#x}", window);
                            workspace.move_focus(MoveOp::Up)
                        }
                        Cmd::FocusDown => {
                            debug!("Cmd::FocusDown: {:#x}", window);
                            workspace.move_focus(MoveOp::Down)
                        }
                        Cmd::FocusMaster => {
                            debug!("Cmd::FocusMaster: {:#x}", window);
                            workspace.move_focus(MoveOp::Swap)
                        }
                        Cmd::FocusParentUp => {
                            debug!("Cmd::FocusParentUp: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Up)
                        }
                        Cmd::FocusParentDown => {
                            debug!("Cmd::FocusParentDown: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Down)
                        }
                        Cmd::FocusParentMaster => {
                            debug!("Cmd::FocusParentMaster: {:#x}", window);
                            workspace.move_parent_focus(MoveOp::Swap)
                        }
                        _ => None
                    };

                    if let Some(window) = new_focus {
                        xws.focus_window(window);
                    }
                }
            },
            Cmd::SwapUp | Cmd::SwapDown | Cmd::SwapMaster | Cmd::SwapParentUp | Cmd::SwapParentDown | Cmd::SwapParentMaster => {
                if let Some(window) = state.current_ws().focused_window() {
                    let workspace = state.current_ws_mut();
                    let new_focus = match self {
                        Cmd::SwapUp => {
                            debug!("Cmd::SwapUp: {:#x}", window);
                            workspace.move_window(MoveOp::Up)
                        }
                        Cmd::SwapDown => {
                            debug!("Cmd::SwapDown: {:#x}", window);
                            workspace.move_window(MoveOp::Down)
                        }
                        Cmd::SwapMaster => {
                            debug!("Cmd::SwapMaster: {:#x}", window);
                            workspace.move_window(MoveOp::Swap)
                        }
                        Cmd::SwapParentUp => {
                            debug!("Cmd::SwapParentUp: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Up)
                        }
                        Cmd::SwapParentDown => {
                            debug!("Cmd::SwapParentDown: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Down)
                        }
                        Cmd::SwapParentMaster => {
                            debug!("Cmd::SwapParentMaster: {:#x}", window);
                            workspace.move_parent_window(MoveOp::Swap)
                        }
                        _ => false
                    };

                    if new_focus {
                        state.current_ws().redraw(xws, config, state.get_screens());
                    }
                }
            }
        }
        Ok(())
    }
}

fn reload(state: &WmState) -> Result<()> {
    info!("recompiling...");

    let cfg_dir = Config::get_dir()
        .context("failed to locate config directory")?;
    let mut cmd = Command::new("cargo");

    let output = cmd.current_dir(&format!("{}/.build", cfg_dir))
        .arg("build")
        .env("RUST_LOG", "none")
        .output()
        .context("failed to run cargo")?;

    if !output.status.success() {
        let stderr_msg = String::from_utf8(output.stderr)
            .context("failed to convert cargo stderr to UTF-8")?;
        bail!("failed to recompile: {}", stderr_msg)
    }

    debug!("Cmd::Reload: restarting xr3wm...");

    let path = Path::new(&cfg_dir).join(".state.tmp");

    // save current workspace states to restore on restart
    let file = OpenOptions::new()
        .create(true)
        .write(true)
        .truncate(true)
        .open(&path)
        .context("failed to open workspace state tmp file")?;

    serde_json::to_writer(file, state)
        .context("failed to serialize workspace states")?;

    let args: Vec<*const libc::c_char> = env::args()
        .filter_map(|x| CString::new(x).ok())
        .map(|x| x.into_raw() as *const libc::c_char)
        .chain(iter::once(null()))
        .collect();

    let envs: Vec<*const libc::c_char> = env::vars()
        .filter_map(|(k,v)| CString::new(format!("{}={}", k, v)).ok())
        .map(|x| x.into_raw() as *const libc::c_char)
        .chain(iter::once(null()))
        .collect();

    unsafe {
        execvpe(args[0] as *const libc::c_char, args.as_ptr(), envs.as_ptr());
        // execvp returns only if an error has occurred
        error!("failed to reload: {}", ::std::io::Error::last_os_error());
    }

    Ok(())
}

pub struct ManageHook {
    pub class_name: String,
    pub cmd: CmdManage,
}

pub enum CmdManage {
    Move(usize),
    Float,
    Fullscreen,
    Ignore,
}

impl CmdManage {
    pub fn call(&self,
                xws: &XlibWindowSystem,
                state: &mut WmState,
                config: &Config,
                window: Window) {
        match *self {
            CmdManage::Move(index) => {
                debug!("CmdManage::Move: {}, {}", window, index);
                state.add_window(Some(index - 1), xws, config, window);
            }
            CmdManage::Float => {
                debug!("CmdManage::Float");
                unimplemented!()
            }
            CmdManage::Fullscreen => {
                debug!("CmdManage::Fullscreen");
                unimplemented!()
            }
            CmdManage::Ignore => {
                debug!("CmdManage::Ignore");
                unimplemented!()
            }
        }
    }
}

fn exec(cmd: String, args: Vec<String>) {
    if !cmd.is_empty() {
        std::thread::spawn(move || {
            match Command::new(&cmd)
                .envs(env::vars())
                .stdin(Stdio::null())
                .stdout(Stdio::null())
                .stderr(Stdio::null())
                .args(&args)
                .spawn()
            {
                Ok(mut child) => {
                    child.wait().ok();
                },
                Err(e) => error!("failed to start \"{:?}\": {}", cmd, e),
            }
        });
    }
}
<|endoftext|>


<commit_before>//! Shim which is passed to Cargo as "rustc" when running the bootstrap.
//!
//! This shim will take care of some various tasks that our build process
//! requires that Cargo can't quite do through normal configuration:
//!
//! 1. When compiling build scripts and build dependencies, we need a guaranteed
//!    full standard library available. The only compiler which actually has
//!    this is the snapshot, so we detect this situation and always compile with
//!    the snapshot compiler.
//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling
//!    (and this slightly differs based on a whether we're using a snapshot or
//!    not), so we do that all here.
//!
//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.

use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::time::Instant;

fn main() {
    let args = env::args_os().skip(1).collect::<Vec<_>>();

    // Detect whether or not we're a build script depending on whether --target
    // is passed (a bit janky...)
    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
    let version = args.iter().find(|w| &**w == "-vV");

    let verbose = match env::var("RUSTC_VERBOSE") {
        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
        Err(_) => 0,
    };

    // Use a different compiler for build scripts, since there may not yet be a
    // libstd for the real compiler to use. However, if Cargo is attempting to
    // determine the version of the compiler, the real compiler needs to be
    // used. Currently, these two states are differentiated based on whether
    // --target and -vV is/isn't passed.
    let (rustc, libdir) = if target.is_none() && version.is_none() {
        ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
    } else {
        ("RUSTC_REAL", "RUSTC_LIBDIR")
    };
    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
    let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
    let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);

    let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
    let mut dylib_path = bootstrap::util::dylib_path();
    dylib_path.insert(0, PathBuf::from(&libdir));

    let mut cmd = Command::new(rustc);
    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());

    // Get the name of the crate we're compiling, if any.
    let crate_name =
        args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str());

    if let Some(crate_name) = crate_name {
        if let Some(target) = env::var_os("RUSTC_TIME") {
            if target == "all"
                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
            {
                cmd.arg("-Ztime");
            }
        }
    }

    // Print backtrace in case of ICE
    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
        cmd.env("RUST_BACKTRACE", "1");
    }

    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
        cmd.args(lint_flags.split_whitespace());
    }

    if target.is_some() {
        // The stage0 compiler has a special sysroot distinct from what we
        // actually downloaded, so we just always pass the `--sysroot` option,
        // unless one is already set.
        if !args.iter().any(|arg| arg == "--sysroot") {
            cmd.arg("--sysroot").arg(&sysroot);
        }

        // If we're compiling specifically the `panic_abort` crate then we pass
        // the `-C panic=abort` option. Note that we do not do this for any
        // other crate intentionally as this is the only crate for now that we
        // ship with panic=abort.
        //
        // This... is a bit of a hack how we detect this. Ideally this
        // information should be encoded in the crate I guess? Would likely
        // require an RFC amendment to RFC 1513, however.
        //
        // `compiler_builtins` are unconditionally compiled with panic=abort to
        // workaround undefined references to `rust_eh_unwind_resume` generated
        // otherwise, see issue https://github.com/rust-lang/rust/issues/43095.
        if crate_name == Some("panic_abort")
            || crate_name == Some("compiler_builtins") && stage != "0"
        {
            cmd.arg("-C").arg("panic=abort");
        }
    } else {
        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
        // here, but rather Cargo should know what flags to pass rustc itself.

        // Override linker if necessary.
        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
            cmd.arg(format!("-Clinker={}", host_linker));
        }

        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
            if s == "true" {
                cmd.arg("-C").arg("target-feature=+crt-static");
            }
            if s == "false" {
                cmd.arg("-C").arg("target-feature=-crt-static");
            }
        }
    }

    if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
        cmd.arg("--remap-path-prefix").arg(&map);
    }

    // Force all crates compiled by this compiler to (a) be unstable and (b)
    // allow the `rustc_private` feature to link to other unstable crates
    // also in the sysroot. We also do this for host crates, since those
    // may be proc macros, in which case we might ship them.
    if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) {
        cmd.arg("-Z").arg("force-unstable-if-unmarked");
    }

    if verbose > 1 {
        eprintln!(
            "rustc command: {:?}={:?} {:?}",
            bootstrap::util::dylib_path_var(),
            env::join_paths(&dylib_path).unwrap(),
            cmd,
        );
        eprintln!("sysroot: {:?}", sysroot);
        eprintln!("libdir: {:?}", libdir);
    }

    let start = Instant::now();
    let status = {
        let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd);
        cmd.status().expect(&errmsg)
    };

    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() {
        if let Some(crate_name) = crate_name {
            let dur = start.elapsed();
            let is_test = args.iter().any(|a| a == "--test");
            eprintln!(
                "[RUSTC-TIMING] {} test:{} {}.{:03}",
                crate_name,
                is_test,
                dur.as_secs(),
                dur.subsec_millis()
            );
        }
    }

    if status.success() {
        std::process::exit(0);
        // note: everything below here is unreachable. do not put code that
        // should run on success, after this block.
    }
    println!("\nDid not run successfully: {}\n{:?}\n-------------", status, cmd);

    if let Some(mut on_fail) = on_fail {
        on_fail.status().expect("Could not run the on_fail command");
    }

    // Preserve the exit code. In case of signal, exit with 0xfe since it's
    // awkward to preserve this status in a cross-platform way.
    match status.code() {
        Some(i) => std::process::exit(i),
        None => {
            eprintln!("rustc exited with {}", status);
            std::process::exit(0xfe);
        }
    }
}
<commit_msg>Rollup merge of #75057 - Mark-Simulacrum:avoid-long-print, r=alexcrichton<commit_after>//! Shim which is passed to Cargo as "rustc" when running the bootstrap.
//!
//! This shim will take care of some various tasks that our build process
//! requires that Cargo can't quite do through normal configuration:
//!
//! 1. When compiling build scripts and build dependencies, we need a guaranteed
//!    full standard library available. The only compiler which actually has
//!    this is the snapshot, so we detect this situation and always compile with
//!    the snapshot compiler.
//! 2. We pass a bunch of `--cfg` and other flags based on what we're compiling
//!    (and this slightly differs based on a whether we're using a snapshot or
//!    not), so we do that all here.
//!
//! This may one day be replaced by RUSTFLAGS, but the dynamic nature of
//! switching compilers for the bootstrap and for build scripts will probably
//! never get replaced.

use std::env;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use std::time::Instant;

fn main() {
    let args = env::args_os().skip(1).collect::<Vec<_>>();

    // Detect whether or not we're a build script depending on whether --target
    // is passed (a bit janky...)
    let target = args.windows(2).find(|w| &*w[0] == "--target").and_then(|w| w[1].to_str());
    let version = args.iter().find(|w| &**w == "-vV");

    let verbose = match env::var("RUSTC_VERBOSE") {
        Ok(s) => usize::from_str(&s).expect("RUSTC_VERBOSE should be an integer"),
        Err(_) => 0,
    };

    // Use a different compiler for build scripts, since there may not yet be a
    // libstd for the real compiler to use. However, if Cargo is attempting to
    // determine the version of the compiler, the real compiler needs to be
    // used. Currently, these two states are differentiated based on whether
    // --target and -vV is/isn't passed.
    let (rustc, libdir) = if target.is_none() && version.is_none() {
        ("RUSTC_SNAPSHOT", "RUSTC_SNAPSHOT_LIBDIR")
    } else {
        ("RUSTC_REAL", "RUSTC_LIBDIR")
    };
    let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
    let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
    let on_fail = env::var_os("RUSTC_ON_FAIL").map(Command::new);

    let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
    let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
    let mut dylib_path = bootstrap::util::dylib_path();
    dylib_path.insert(0, PathBuf::from(&libdir));

    let mut cmd = Command::new(rustc);
    cmd.args(&args).env(bootstrap::util::dylib_path_var(), env::join_paths(&dylib_path).unwrap());

    // Get the name of the crate we're compiling, if any.
    let crate_name =
        args.windows(2).find(|args| args[0] == "--crate-name").and_then(|args| args[1].to_str());

    if let Some(crate_name) = crate_name {
        if let Some(target) = env::var_os("RUSTC_TIME") {
            if target == "all"
                || target.into_string().unwrap().split(',').any(|c| c.trim() == crate_name)
            {
                cmd.arg("-Ztime");
            }
        }
    }

    // Print backtrace in case of ICE
    if env::var("RUSTC_BACKTRACE_ON_ICE").is_ok() && env::var("RUST_BACKTRACE").is_err() {
        cmd.env("RUST_BACKTRACE", "1");
    }

    if let Ok(lint_flags) = env::var("RUSTC_LINT_FLAGS") {
        cmd.args(lint_flags.split_whitespace());
    }

    if target.is_some() {
        // The stage0 compiler has a special sysroot distinct from what we
        // actually downloaded, so we just always pass the `--sysroot` option,
        // unless one is already set.
        if !args.iter().any(|arg| arg == "--sysroot") {
            cmd.arg("--sysroot").arg(&sysroot);
        }

        // If we're compiling specifically the `panic_abort` crate then we pass
        // the `-C panic=abort` option. Note that we do not do this for any
        // other crate intentionally as this is the only crate for now that we
        // ship with panic=abort.
        //
        // This... is a bit of a hack how we detect this. Ideally this
        // information should be encoded in the crate I guess? Would likely
        // require an RFC amendment to RFC 1513, however.
        //
        // `compiler_builtins` are unconditionally compiled with panic=abort to
        // workaround undefined references to `rust_eh_unwind_resume` generated
        // otherwise, see issue https://github.com/rust-lang/rust/issues/43095.
        if crate_name == Some("panic_abort")
            || crate_name == Some("compiler_builtins") && stage != "0"
        {
            cmd.arg("-C").arg("panic=abort");
        }
    } else {
        // FIXME(rust-lang/cargo#5754) we shouldn't be using special env vars
        // here, but rather Cargo should know what flags to pass rustc itself.

        // Override linker if necessary.
        if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
            cmd.arg(format!("-Clinker={}", host_linker));
        }

        if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") {
            if s == "true" {
                cmd.arg("-C").arg("target-feature=+crt-static");
            }
            if s == "false" {
                cmd.arg("-C").arg("target-feature=-crt-static");
            }
        }
    }

    if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
        cmd.arg("--remap-path-prefix").arg(&map);
    }

    // Force all crates compiled by this compiler to (a) be unstable and (b)
    // allow the `rustc_private` feature to link to other unstable crates
    // also in the sysroot. We also do this for host crates, since those
    // may be proc macros, in which case we might ship them.
    if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() && (stage != "0" || target.is_some()) {
        cmd.arg("-Z").arg("force-unstable-if-unmarked");
    }

    if verbose > 1 {
        eprintln!(
            "rustc command: {:?}={:?} {:?}",
            bootstrap::util::dylib_path_var(),
            env::join_paths(&dylib_path).unwrap(),
            cmd,
        );
        eprintln!("sysroot: {:?}", sysroot);
        eprintln!("libdir: {:?}", libdir);
    }

    let start = Instant::now();
    let status = {
        let errmsg = format!("\nFailed to run:\n{:?}\n-------------", cmd);
        cmd.status().expect(&errmsg)
    };

    if env::var_os("RUSTC_PRINT_STEP_TIMINGS").is_some() {
        if let Some(crate_name) = crate_name {
            let dur = start.elapsed();
            let is_test = args.iter().any(|a| a == "--test");
            eprintln!(
                "[RUSTC-TIMING] {} test:{} {}.{:03}",
                crate_name,
                is_test,
                dur.as_secs(),
                dur.subsec_millis()
            );
        }
    }

    if status.success() {
        std::process::exit(0);
        // note: everything below here is unreachable. do not put code that
        // should run on success, after this block.
    }
    if verbose > 0 {
        println!("\nDid not run successfully: {}\n{:?}\n-------------", status, cmd);
    }

    if let Some(mut on_fail) = on_fail {
        on_fail.status().expect("Could not run the on_fail command");
    }

    // Preserve the exit code. In case of signal, exit with 0xfe since it's
    // awkward to preserve this status in a cross-platform way.
    match status.code() {
        Some(i) => std::process::exit(i),
        None => {
            eprintln!("rustc exited with {}", status);
            std::process::exit(0xfe);
        }
    }
}
<|endoftext|>


<commit_before>//! Tracks minimal sets of mutually incomparable elements of a partial order.

use std::fmt::Debug;
use std::default::Default;
use std::cmp::Ordering;

use progress::CountMap;

/// A set of mutually incomparable elements.
#[derive(Default, Clone, Debug)]
pub struct Antichain<T> {
    elements: Vec<T>
}

impl<T: PartialOrd+Eq+Copy+Debug> Antichain<T> {
    /// Updates the `Antichain` if the element is not greater than or equal to some present element.
    ///
    /// Returns true if element is added to the set
    pub fn insert(&mut self, element: T) -> bool {
        // bail if any element exceeds the candidate
        if self.elements.iter().any(|x| element.ge(x)) {
            return false;
        }
        let mut removed = 0;
        for index in 0..self.elements.len() {
            let new_index = index - removed;
            if element.lt(&self.elements[new_index]) {
                self.elements.swap_remove(new_index);
                removed += 1;
            }
        }

        self.elements.push(element);
        true
    }

    /// Creates a new empty `Antichain`.
    pub fn new() -> Antichain<T> { Antichain { elements: Vec::new() } }

    /// Creates a new singleton `Antichain`.
    pub fn from_elem(element: T) -> Antichain<T> { Antichain { elements: vec![element] } }

    /// Reveals the elements in the `Antichain`.
    pub fn elements(&self) -> &[T] { &self.elements[..] }
}

/// An antichain based on a multiset whose elements frequencies can be updated.
///
/// In particular, unlike `Antichain`, element frequencies can be decremented, removing elements in
/// the antichain and revealing other elements that were previously obscured.
/// As part of this, the `MutableAntichain` must maintain the frequences for all elements, not just
/// those in the antichain at the moment.
#[derive(Default, Debug, Clone)]
pub struct MutableAntichain<T:Eq> {
    occurrences:    CountMap<T>,    // occurrence count of each time
    precedents:     Vec<(T, i64)>,  // counts number of distinct times in occurences strictly less than element
    elements:       Vec<T>,         // the set of times with precedent count == 0
}

impl<T: PartialOrd+Eq+Clone+Debug+'static> MutableAntichain<T> {
    /// Creates a new empty `MutableAntichain`.
    pub fn new() -> MutableAntichain<T> {
        MutableAntichain {
            occurrences:    Default::default(),
            precedents:     Default::default(),
            elements:       Vec::new(),
        }
    }

    /// Removes all elements from the antichain.
    pub fn clear(&mut self) {
        self.occurrences.clear();
        self.precedents.clear();
        self.elements.clear();
    }

    /// Reveals the element in the `MutableAntichain`.
    pub fn elements(&self) -> &[T] { &self.elements }

    /// Creates a new singleton `MutableAntichain`.
    pub fn new_bottom(bottom: T) -> MutableAntichain<T> {
        let mut result = MutableAntichain::new();
        result.update_weight(&bottom, 1, &mut Default::default());
        result
    }

    /// Returns true if there are no elements in the `MutableAntichain`.
    pub fn empty(&self) -> bool { self.elements.is_empty() }

    /// Returns true if any item in the `MutableAntichain` is strictly less than the argument.
    #[inline]
    pub fn lt(&self, time: &T) -> bool {
        self.elements.iter().any(|x| x.lt(time))
    }

    /// Returns true if any item in the `MutableAntichain` is less than or equal to the argument.
    #[inline]
    pub fn le(&self, time: &T) -> bool {
        self.elements.iter().any(|x| x.le(time))
    }

    /// Returns the number of times an element exists in the set.
    #[inline]
    pub fn count(&self, time: &T) -> Option<i64> {
        self.occurrences.iter().filter(|x| time.eq(&x.0)).next().map(|i| i.1)
    }

    // TODO : Four different versions of basically the same code. Fix that!
    // TODO : Should this drain updates through to the CM? Check out uses!
    /// Incorporates `updates` into the antichain, pushing frontier changes into `results`.
    pub fn update_into_cm(&mut self, updates: &CountMap<T>, results: &mut CountMap<T>) -> () {
        self.update_iter_and(updates.iter().cloned(), |time, val| { results.update(time, val); });
    }

    /// Performs a single update to the antichain, pushing frontier changes into `results`.
    pub fn update_weight(&mut self, elem: &T, delta: i64, results: &mut CountMap<T>) -> () {
        self.update_and(elem, delta, |time, delta| { results.update(time, delta); });
    }

    /// Applies a single update to the antichain.
    #[inline] pub fn update(&mut self, elem: &T, delta: i64) { self.update_and(elem, delta, |_,_| {}); }

    /// Applies updates to the antichain and applies `action` to each frontier change.
    //#[inline(always)]
    pub fn update_iter_and<I: Iterator<Item = (T, i64)>,
                           A: FnMut(&T, i64) -> ()>(&mut self, updates: I, mut action: A) -> () {
        for (ref elem, delta) in updates {
            self.update_and(elem, delta, |t,d| action(t,d));
        }
    }

    /// Tests the size of the antichain against a threshould.
    ///
    /// This is a diagnostic method in place to observe when antichains become surprisingly large.
    /// If either `self.occurrences` or `self.precedents` exceeds the threshold, they are listed.
    #[inline]
    pub fn test_size(&self, threshold: usize, name: &str) {
        if self.occurrences.len() > threshold {
            println!("{}:\toccurrences:\tlen() = {}", name, self.occurrences.len());
            // for &(ref key, val) in self.occurrences.elements().iter() { println!("{}: \toccurrence: {:?} : {:?}", name, key, val); }
            // panic!();
        }
        if self.precedents.len() > threshold {
            println!("{}: precedents:\tlen() = {}", name, self.precedents.len());
        }
    }

    /// Applies an update to the antichain and takes an action on any frontier changes.
    #[inline]
    pub fn update_and<A: FnMut(&T, i64)->()>(&mut self, elem: &T, delta: i64, mut action: A) -> () {

        if delta != 0 {
            // self.test_size(100, "???");
            let new_value = self.occurrences.update(elem, delta);
            let old_value = new_value - delta;

            // if the value went from non-positive to positive we need to update self.precedents
            if old_value <= 0 && new_value > 0 {
                let mut preceded_by = 0;

                // maintain precedent counts relative to the set
                for &mut (ref key, ref mut val) in &mut self.precedents {
                    if let Some(comparison) = elem.partial_cmp(key) {
                        match comparison {
                            Ordering::Less    => {
                                if *val == 0 {
                                    self.elements.retain(|x| x != key);
                                    action(key, -1);
                                }
                                *val += 1;
                            },
                            Ordering::Equal   => { panic!("surprising!"); },
                            Ordering::Greater => { preceded_by += 1; },
                        }
                    }
                }

                // insert count always; maybe put in elements
                self.precedents.push((elem.clone(), preceded_by));
                if preceded_by == 0 {
                    self.elements.push(elem.clone());
                    action(elem, 1);
                }
            }

            // if the value went from positive to non-positive we need to update self.precedents.
            if old_value > 0 && new_value <= 0 {
                // maintain precedent counts relative to the set
                for &mut (ref key, ref mut val) in &mut self.precedents {
                    if elem < key {
                        *val -= 1;
                        if *val == 0 {
                            self.elements.push(key.clone());
                            action(key, 1);
                        }
                    }
                }

                if let Some(position) = self.elements.iter().position(|x| x == elem) {
                    action(elem, -1);
                    self.elements.swap_remove(position);
                }

                self.precedents.retain(|x| &x.0 != elem);
            }
        }
    }
}
<commit_msg>removed Debug requirement<commit_after>//! Tracks minimal sets of mutually incomparable elements of a partial order.

use std::default::Default;
use std::cmp::Ordering;

use progress::CountMap;

/// A set of mutually incomparable elements.
#[derive(Default, Clone, Debug)]
pub struct Antichain<T> {
    elements: Vec<T>
}

impl<T: PartialOrd+Eq+Copy> Antichain<T> {
    /// Updates the `Antichain` if the element is not greater than or equal to some present element.
    ///
    /// Returns true if element is added to the set
    pub fn insert(&mut self, element: T) -> bool {
        // bail if any element exceeds the candidate
        if self.elements.iter().any(|x| element.ge(x)) {
            return false;
        }
        let mut removed = 0;
        for index in 0..self.elements.len() {
            let new_index = index - removed;
            if element.lt(&self.elements[new_index]) {
                self.elements.swap_remove(new_index);
                removed += 1;
            }
        }

        self.elements.push(element);
        true
    }

    /// Creates a new empty `Antichain`.
    pub fn new() -> Antichain<T> { Antichain { elements: Vec::new() } }

    /// Creates a new singleton `Antichain`.
    pub fn from_elem(element: T) -> Antichain<T> { Antichain { elements: vec![element] } }

    /// Reveals the elements in the `Antichain`.
    pub fn elements(&self) -> &[T] { &self.elements[..] }
}

/// An antichain based on a multiset whose elements frequencies can be updated.
///
/// In particular, unlike `Antichain`, element frequencies can be decremented, removing elements in
/// the antichain and revealing other elements that were previously obscured.
/// As part of this, the `MutableAntichain` must maintain the frequences for all elements, not just
/// those in the antichain at the moment.
#[derive(Default, Debug, Clone)]
pub struct MutableAntichain<T:Eq> {
    occurrences:    CountMap<T>,    // occurrence count of each time
    precedents:     Vec<(T, i64)>,  // counts number of distinct times in occurences strictly less than element
    elements:       Vec<T>,         // the set of times with precedent count == 0
}

impl<T: PartialOrd+Eq+Clone+'static> MutableAntichain<T> {
    /// Creates a new empty `MutableAntichain`.
    pub fn new() -> MutableAntichain<T> {
        MutableAntichain {
            occurrences:    Default::default(),
            precedents:     Default::default(),
            elements:       Vec::new(),
        }
    }

    /// Removes all elements from the antichain.
    pub fn clear(&mut self) {
        self.occurrences.clear();
        self.precedents.clear();
        self.elements.clear();
    }

    /// Reveals the element in the `MutableAntichain`.
    pub fn elements(&self) -> &[T] { &self.elements }

    /// Creates a new singleton `MutableAntichain`.
    pub fn new_bottom(bottom: T) -> MutableAntichain<T> {
        let mut result = MutableAntichain::new();
        result.update_weight(&bottom, 1, &mut Default::default());
        result
    }

    /// Returns true if there are no elements in the `MutableAntichain`.
    pub fn empty(&self) -> bool { self.elements.is_empty() }

    /// Returns true if any item in the `MutableAntichain` is strictly less than the argument.
    #[inline]
    pub fn lt(&self, time: &T) -> bool {
        self.elements.iter().any(|x| x.lt(time))
    }

    /// Returns true if any item in the `MutableAntichain` is less than or equal to the argument.
    #[inline]
    pub fn le(&self, time: &T) -> bool {
        self.elements.iter().any(|x| x.le(time))
    }

    /// Returns the number of times an element exists in the set.
    #[inline]
    pub fn count(&self, time: &T) -> Option<i64> {
        self.occurrences.iter().filter(|x| time.eq(&x.0)).next().map(|i| i.1)
    }

    // TODO : Four different versions of basically the same code. Fix that!
    // TODO : Should this drain updates through to the CM? Check out uses!
    /// Incorporates `updates` into the antichain, pushing frontier changes into `results`.
    pub fn update_into_cm(&mut self, updates: &CountMap<T>, results: &mut CountMap<T>) -> () {
        self.update_iter_and(updates.iter().cloned(), |time, val| { results.update(time, val); });
    }

    /// Performs a single update to the antichain, pushing frontier changes into `results`.
    pub fn update_weight(&mut self, elem: &T, delta: i64, results: &mut CountMap<T>) -> () {
        self.update_and(elem, delta, |time, delta| { results.update(time, delta); });
    }

    /// Applies a single update to the antichain.
    #[inline] pub fn update(&mut self, elem: &T, delta: i64) { self.update_and(elem, delta, |_,_| {}); }

    /// Applies updates to the antichain and applies `action` to each frontier change.
    //#[inline(always)]
    pub fn update_iter_and<I: Iterator<Item = (T, i64)>,
                           A: FnMut(&T, i64) -> ()>(&mut self, updates: I, mut action: A) -> () {
        for (ref elem, delta) in updates {
            self.update_and(elem, delta, |t,d| action(t,d));
        }
    }

    /// Tests the size of the antichain against a threshould.
    ///
    /// This is a diagnostic method in place to observe when antichains become surprisingly large.
    /// If either `self.occurrences` or `self.precedents` exceeds the threshold, they are listed.
    #[inline]
    pub fn test_size(&self, threshold: usize, name: &str) {
        if self.occurrences.len() > threshold {
            println!("{}:\toccurrences:\tlen() = {}", name, self.occurrences.len());
            // for &(ref key, val) in self.occurrences.elements().iter() { println!("{}: \toccurrence: {:?} : {:?}", name, key, val); }
            // panic!();
        }
        if self.precedents.len() > threshold {
            println!("{}: precedents:\tlen() = {}", name, self.precedents.len());
        }
    }

    /// Applies an update to the antichain and takes an action on any frontier changes.
    #[inline]
    pub fn update_and<A: FnMut(&T, i64)->()>(&mut self, elem: &T, delta: i64, mut action: A) -> () {

        if delta != 0 {
            // self.test_size(100, "???");
            let new_value = self.occurrences.update(elem, delta);
            let old_value = new_value - delta;

            // if the value went from non-positive to positive we need to update self.precedents
            if old_value <= 0 && new_value > 0 {
                let mut preceded_by = 0;

                // maintain precedent counts relative to the set
                for &mut (ref key, ref mut val) in &mut self.precedents {
                    if let Some(comparison) = elem.partial_cmp(key) {
                        match comparison {
                            Ordering::Less    => {
                                if *val == 0 {
                                    self.elements.retain(|x| x != key);
                                    action(key, -1);
                                }
                                *val += 1;
                            },
                            Ordering::Equal   => { panic!("surprising!"); },
                            Ordering::Greater => { preceded_by += 1; },
                        }
                    }
                }

                // insert count always; maybe put in elements
                self.precedents.push((elem.clone(), preceded_by));
                if preceded_by == 0 {
                    self.elements.push(elem.clone());
                    action(elem, 1);
                }
            }

            // if the value went from positive to non-positive we need to update self.precedents.
            if old_value > 0 && new_value <= 0 {
                // maintain precedent counts relative to the set
                for &mut (ref key, ref mut val) in &mut self.precedents {
                    if elem < key {
                        *val -= 1;
                        if *val == 0 {
                            self.elements.push(key.clone());
                            action(key, 1);
                        }
                    }
                }

                if let Some(position) = self.elements.iter().position(|x| x == elem) {
                    action(elem, -1);
                    self.elements.swap_remove(position);
                }

                self.precedents.retain(|x| &x.0 != elem);
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::hash::{Hash, Hasher, SipHasher};

pub fn name_hash(str_: &str) -> u64 {
    let mut hasher = SipHasher::new();
    str_.hash(&mut hasher);
    hasher.finish()
}

pub trait NameTableIdx {
    fn to_index(&self) -> usize;
}

impl NameTableIdx for usize {
    fn to_index(&self) -> usize { *self }
}

pub trait NameTable {
    fn initial_local(&self) -> usize;
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>>;

    fn len_local(&self) -> usize;
    fn at_local<'a>(&'a self, idx: usize) -> &'a str;
    fn find_local(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None
    }

    fn len(&self) -> usize {
        return self.len_local() +
            self.parent().map_or(0usize, |parent_table| parent_table.len());
    }

    fn at<'a>(&'a self, idx: usize) -> &'a str {
        let initial = self.initial_local();
        if idx >= initial {
            return self.at_local(idx - initial)
        }
        else if let Some(parent_table) = self.parent().as_ref() {
            &parent_table.at(idx)
        }
        else {
            panic!("access out of bound");
        }
    }

    fn find(&self, name: &str) -> Option<usize> {
        let initial = self.initial_local();
        self.find_local(name).map(|idx| idx + initial).or_else(|| {
            if let Some(parent_table) = self.parent().as_ref() {
                return parent_table.find(name)
            }
            return None
        })
    }
}

pub struct StaticNameTable<'a> {
    initial_idx: usize,
    names : &'static str,
    name_offsets : &'static [usize],
    parent : Option<Box<NameTable + 'a>>,
}

impl<'x> NameTable for StaticNameTable<'x> {
    fn initial_local(&self) -> usize { self.initial_idx }
    fn len_local(&self) -> usize { self.name_offsets.len() - 1}
    fn at_local<'a>(&'a self, idx: usize) -> &'a str { &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]] }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> { self.parent.as_ref()}
}

impl<'x> StaticNameTable<'x> {
    pub fn new(names_: &'static str, name_offsets_ : &'static [usize]) -> Self {
        return StaticNameTable {
            initial_idx: 0usize,
            names : names_,
            name_offsets : name_offsets_,
            parent : None
        }
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(names_: &'static str, name_offsets_ : &'static [usize], parent: ParentTableType) -> Self {
        return StaticNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names : names_,
            name_offsets : name_offsets_,
            parent : Some(Box::new(parent)),
        }
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }
}

pub struct DynamicNameTable<'a> {
    initial_idx: usize,
    names : Box<Vec<String>>,
    parent : Option<Box<NameTable + 'a>>,
}

impl<'x> NameTable for DynamicNameTable<'x> {
    fn initial_local(&self) -> usize { self.initial_idx }
    fn len_local(&self) -> usize { self.names.len() }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str { self.names[idx].as_str() }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> { self.parent.as_ref()}
}

impl<'x> DynamicNameTable<'x> {
    pub fn new() -> Self {
        return DynamicNameTable {
            initial_idx: 0usize,
            names : Box::new(Vec::new()),
            parent : None
        }
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(parent: ParentTableType) -> Self {
        return DynamicNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names : Box::new(Vec::new()),
            parent : Some(Box::new(parent)),
        }
    }

    pub fn intern(&mut self, name: &str) -> usize {
        self.find(name).or_else(|| Some({
            self.names.as_mut().push(name.to_owned());
            self.initial_idx + self.names.len() - 1
        })).unwrap()
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }
}

pub struct StaticHashedNameTable<'a> {
    initial_idx: usize,
    names : &'static str,
    name_offsets : &'static [usize],
    hash_idxes : &'static [(u64, usize)],
    parent : Option<Box<NameTable + 'a>>,
}

impl<'x> StaticHashedNameTable<'x> {
    pub fn new(names_: &'static str, name_offsets_ : &'static [usize],
               hash_idxes_ : &'static [(u64, usize)]) -> Self {

        return StaticHashedNameTable {
            initial_idx: 0usize,
            names : names_,
            name_offsets : name_offsets_,
            hash_idxes : hash_idxes_,
            parent : None
        }
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(
        names_: &'static str, name_offsets_ : &'static [usize],
        hash_idxes_ : &'static [(u64, usize)], parent: ParentTableType) -> Self {

        return StaticHashedNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names : names_,
            name_offsets : name_offsets_,
            hash_idxes : hash_idxes_,
            parent : Some(Box::new(parent)),
        }
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }

    fn hash_enabled(&self) -> bool {
        self.hash_idxes.len() != 0
    }

    fn find_local_hashing(&self, name: &str) -> Option<usize> {
        let target = name_hash(name);
        let result = self.hash_idxes.binary_search_by(|&(a, _)| a.cmp(&target));
        match result {
            Ok(val) => {
                if self.at_local(val) == name {
                    Some(val + self.initial_idx)
                } else {
                    None
                }
            },
            _ => None,
        }
    }

    fn find_local_fallback(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() { if self.at_local(i) == name { return Some(i); } } return None
    }
}

impl<'x> NameTable for StaticHashedNameTable<'x> {
    fn initial_local(&self) -> usize { self.initial_idx }
    fn len_local(&self) -> usize { self.name_offsets.len() - 1}
    fn at_local<'a>(&'a self, idx: usize) -> &'a str { &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]] }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> { self.parent.as_ref()}

    fn find_local(&self, name: &str) -> Option<usize> {
        if self.hash_enabled() {
            self.find_local_hashing(name)
        } else {
            self.find_local_fallback(name)
        }
    }
}

<commit_msg>Fix hashed name table implementation.<commit_after>use std::hash::{Hash, Hasher, SipHasher};

pub fn name_hash(str_: &str) -> u64 {
    let mut hasher = SipHasher::new();
    str_.hash(&mut hasher);
    hasher.finish()
}

pub trait NameTableIdx {
    fn to_index(&self) -> usize;
}

impl NameTableIdx for usize {
    fn to_index(&self) -> usize { *self }
}

pub trait NameTable {
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>>;

    fn initial_local(&self) -> usize;
    fn len_local(&self) -> usize;
    fn at_local<'a>(&'a self, idx: usize) -> &'a str;
    fn find_local(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() {
            if self.at_local(i) == name {
                return Some(i);
            }
        }
        return None
    }

    fn len(&self) -> usize {
        return self.len_local() +
            self.parent().map_or(0usize, |parent_table| parent_table.len());
    }

    fn at<'a>(&'a self, idx: usize) -> &'a str {
        let initial = self.initial_local();
        if idx >= initial {
            return self.at_local(idx - initial)
        }
        else if let Some(parent_table) = self.parent().as_ref() {
            &parent_table.at(idx)
        }
        else {
            panic!("access out of bound");
        }
    }

    fn find(&self, name: &str) -> Option<usize> {
        let initial = self.initial_local();
        self.find_local(name).map(|idx| idx + initial).or_else(|| {
            if let Some(parent_table) = self.parent().as_ref() {
                return parent_table.find(name)
            }
            return None
        })
    }
}

pub struct StaticNameTable<'a> {
    initial_idx: usize,
    names : &'static str,
    name_offsets : &'static [usize],
    parent : Option<Box<NameTable + 'a>>,
}

impl<'x> NameTable for StaticNameTable<'x> {
    fn initial_local(&self) -> usize { self.initial_idx }
    fn len_local(&self) -> usize { self.name_offsets.len() - 1}
    fn at_local<'a>(&'a self, idx: usize) -> &'a str { &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]] }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> { self.parent.as_ref()}
}

impl<'x> StaticNameTable<'x> {
    pub fn new(names_: &'static str, name_offsets_ : &'static [usize]) -> Self {
        return StaticNameTable {
            initial_idx: 0usize,
            names : names_,
            name_offsets : name_offsets_,
            parent : None
        }
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(names_: &'static str, name_offsets_ : &'static [usize], parent: ParentTableType) -> Self {
        return StaticNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names : names_,
            name_offsets : name_offsets_,
            parent : Some(Box::new(parent)),
        }
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }
}

pub struct DynamicNameTable<'a> {
    initial_idx: usize,
    names : Box<Vec<String>>,
    parent : Option<Box<NameTable + 'a>>,
}

impl<'x> NameTable for DynamicNameTable<'x> {
    fn initial_local(&self) -> usize { self.initial_idx }
    fn len_local(&self) -> usize { self.names.len() }
    fn at_local<'a>(&'a self, idx: usize) -> &'a str { self.names[idx].as_str() }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> { self.parent.as_ref()}
}

impl<'x> DynamicNameTable<'x> {
    pub fn new() -> Self {
        return DynamicNameTable {
            initial_idx: 0usize,
            names : Box::new(Vec::new()),
            parent : None
        }
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(parent: ParentTableType) -> Self {
        return DynamicNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names : Box::new(Vec::new()),
            parent : Some(Box::new(parent)),
        }
    }

    pub fn intern(&mut self, name: &str) -> usize {
        self.find(name).or_else(|| Some({
            self.names.as_mut().push(name.to_owned());
            self.initial_idx + self.names.len() - 1
        })).unwrap()
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }
}

pub struct StaticHashedNameTable<'a> {
    initial_idx: usize,
    names : &'static str,
    name_offsets : &'static [usize],
    hash_idxes : &'static [(u64, usize)],
    parent : Option<Box<NameTable + 'a>>,
}

impl<'x> StaticHashedNameTable<'x> {
    pub fn new(names_: &'static str, name_offsets_ : &'static [usize],
               hash_idxes_ : &'static [(u64, usize)]) -> Self {

        return StaticHashedNameTable {
            initial_idx: 0usize,
            names : names_,
            name_offsets : name_offsets_,
            hash_idxes : hash_idxes_,
            parent : None
        }
    }

    pub fn new_upon<ParentTableType: 'x + NameTable>(
        names_: &'static str, name_offsets_ : &'static [usize],
        hash_idxes_ : &'static [(u64, usize)], parent: ParentTableType) -> Self {

        return StaticHashedNameTable {
            initial_idx: parent.initial_local() + parent.len_local(),
            names : names_,
            name_offsets : name_offsets_,
            hash_idxes : hash_idxes_,
            parent : Some(Box::new(parent)),
        }
    }

    pub fn index<T: NameTableIdx>(&'x self, idx: T) -> &'x str {
        &self.at(idx.to_index())
    }

    fn hash_enabled(&self) -> bool {
        self.hash_idxes.len() != 0
    }

    fn find_local_hashing(&self, name: &str) -> Option<usize> {
        let target = name_hash(name);
        let result = self.hash_idxes.binary_search_by(|&(a, _)| a.cmp(&target));
        match result {
            Ok(val) => {
                if self.at_local(self.hash_idxes[val].1) == name {
                    Some(self.hash_idxes[val].1)
                } else {
                    None
                }
            },
            _ => None,
        }
    }

    fn find_local_fallback(&self, name: &str) -> Option<usize> {
        for i in 0..self.len_local() { if self.at_local(i) == name { return Some(i); } } return None
    }
}

impl<'x> NameTable for StaticHashedNameTable<'x> {
    fn initial_local(&self) -> usize { self.initial_idx }
    fn len_local(&self) -> usize { self.name_offsets.len() - 1}
    fn at_local<'a>(&'a self, idx: usize) -> &'a str { &self.names[self.name_offsets[idx]..self.name_offsets[idx + 1]] }
    fn parent<'a>(&'a self) -> Option<&Box<NameTable + 'a>> { self.parent.as_ref()}

    fn find_local(&self, name: &str) -> Option<usize> {
        if self.hash_enabled() {
            self.find_local_hashing(name)
        } else {
            self.find_local_fallback(name)
        }
    }
}

<|endoftext|>


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

use std::path::{Path, PathBuf};

use bindgen::cargo::cargo_expand;
use bindgen::cargo::cargo_lock::{self, Lock};
pub(crate) use bindgen::cargo::cargo_metadata::PackageRef;
use bindgen::cargo::cargo_metadata::{self, Metadata};
use bindgen::cargo::cargo_toml;
use bindgen::error::Error;
use bindgen::ir::Cfg;

/// Parse a dependency string used in Cargo.lock
fn parse_dep_string(dep_string: &str) -> (&str, &str) {
    let split: Vec<&str> = dep_string.split_whitespace().collect();

    (split[0], split[1])
}

/// A collection of metadata for a library from cargo.
#[derive(Clone, Debug)]
pub(crate) struct Cargo {
    manifest_path: PathBuf,
    binding_crate_name: String,

    lock: Option<Lock>,
    metadata: Metadata,
    clean: bool,
}

impl Cargo {
    /// Gather metadata from cargo for a specific library and binding crate
    /// name. If dependency finding isn't needed then Cargo.lock files don't
    /// need to be parsed.
    pub(crate) fn load(
        crate_dir: &Path,
        lock_file: Option<&str>,
        binding_crate_name: Option<&str>,
        use_cargo_lock: bool,
        clean: bool,
    ) -> Result<Cargo, Error> {
        let toml_path = crate_dir.join("Cargo.toml");
        let metadata = cargo_metadata::metadata(&toml_path)
            .map_err(|x| Error::CargoMetadata(toml_path.to_str().unwrap().to_owned(), x))?;
        let lock_path = lock_file
            .map(PathBuf::from)
            .unwrap_or_else(|| Path::new(&metadata.workspace_root).join("Cargo.lock"));

        let lock = if use_cargo_lock {
            match cargo_lock::lock(&lock_path) {
                Ok(lock) => Some(lock),
                Err(x) => {
                    warn!("Couldn't load lock file {:?}: {:?}", lock_path, x);
                    None
                }
            }
        } else {
            None
        };

        // Use the specified binding crate name or infer it from the manifest
        let manifest = cargo_toml::manifest(&toml_path)
            .map_err(|x| Error::CargoToml(toml_path.to_str().unwrap().to_owned(), x))?;

        let binding_crate_name =
            binding_crate_name.map_or(manifest.package.name.clone(), |x| x.to_owned());

        Ok(Cargo {
            manifest_path: toml_path,
            binding_crate_name: binding_crate_name,
            lock: lock,
            metadata: metadata,
            clean: clean,
        })
    }

    pub(crate) fn binding_crate_name(&self) -> &str {
        &self.binding_crate_name
    }

    pub(crate) fn binding_crate_ref(&self) -> PackageRef {
        self.find_pkg_ref(&self.binding_crate_name).unwrap()
    }

    pub(crate) fn dependencies(&self, package: &PackageRef) -> Vec<(PackageRef, Option<Cfg>)> {
        let lock = self.lock.as_ref().unwrap();

        let mut dependencies = None;

        // Find the dependencies listing in the lockfile
        if let &Some(ref root) = &lock.root {
            if root.name == package.name && root.version == package.version {
                dependencies = root.dependencies.as_ref();
            }
        }
        if dependencies.is_none() {
            if let Some(ref lock_packages) = lock.package {
                for lock_package in lock_packages {
                    if lock_package.name == package.name && lock_package.version == package.version
                    {
                        dependencies = lock_package.dependencies.as_ref();
                        break;
                    }
                }
            }
        }
        if dependencies.is_none() {
            return vec![];
        }

        dependencies
            .unwrap()
            .iter()
            .map(|dep| {
                let (dep_name, dep_version) = parse_dep_string(dep);

                // Try to find the cfgs in the Cargo.toml
                let cfg = self
                    .metadata
                    .packages
                    .get(package)
                    .and_then(|meta_package| meta_package.dependencies.get(dep_name))
                    .and_then(|meta_dep| Cfg::load_metadata(meta_dep));

                let package_ref = PackageRef {
                    name: dep_name.to_owned(),
                    version: dep_version.to_owned(),
                };

                (package_ref, cfg)
            })
            .collect()
    }

    /// Finds the package reference in `cargo metadata` that has `package_name`
    /// ignoring the version.
    fn find_pkg_ref(&self, package_name: &str) -> Option<PackageRef> {
        for package in &self.metadata.packages {
            if package.name_and_version.name == package_name {
                return Some(package.name_and_version.clone());
            }
        }
        None
    }

    /// Finds the directory for a specified package reference.
    #[allow(unused)]
    pub(crate) fn find_crate_dir(&self, package: &PackageRef) -> Option<PathBuf> {
        self.metadata
            .packages
            .get(package)
            .and_then(|meta_package| {
                Path::new(&meta_package.manifest_path)
                    .parent()
                    .map(|x| x.to_owned())
            })
    }

    /// Finds `src/lib.rs` for a specified package reference.
    pub(crate) fn find_crate_src(&self, package: &PackageRef) -> Option<PathBuf> {
        let kind_lib = String::from("lib");
        let kind_staticlib = String::from("staticlib");
        let kind_rlib = String::from("rlib");
        let kind_cdylib = String::from("cdylib");
        let kind_dylib = String::from("dylib");

        self.metadata
            .packages
            .get(package)
            .and_then(|meta_package| {
                for target in &meta_package.targets {
                    if target.kind.contains(&kind_lib)
                        || target.kind.contains(&kind_staticlib)
                        || target.kind.contains(&kind_rlib)
                        || target.kind.contains(&kind_cdylib)
                        || target.kind.contains(&kind_dylib)
                    {
                        return Some(PathBuf::from(&target.src_path));
                    }
                }
                None
            })
    }

    pub(crate) fn expand_crate(
        &self,
        package: &PackageRef,
        expand_all_features: bool,
        expand_default_features: bool,
        expand_features: &Option<Vec<String>>,
    ) -> Result<String, cargo_expand::Error> {
        cargo_expand::expand(
            &self.manifest_path,
            &package.name,
            &package.version,
            self.clean,
            expand_all_features,
            expand_default_features,
            expand_features,
        )
    }
}
<commit_msg>Fix binding generation with no Cargo.lock.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::path::{Path, PathBuf};

use bindgen::cargo::cargo_expand;
use bindgen::cargo::cargo_lock::{self, Lock};
pub(crate) use bindgen::cargo::cargo_metadata::PackageRef;
use bindgen::cargo::cargo_metadata::{self, Metadata};
use bindgen::cargo::cargo_toml;
use bindgen::error::Error;
use bindgen::ir::Cfg;

/// Parse a dependency string used in Cargo.lock
fn parse_dep_string(dep_string: &str) -> (&str, &str) {
    let split: Vec<&str> = dep_string.split_whitespace().collect();

    (split[0], split[1])
}

/// A collection of metadata for a library from cargo.
#[derive(Clone, Debug)]
pub(crate) struct Cargo {
    manifest_path: PathBuf,
    binding_crate_name: String,
    lock: Option<Lock>,
    metadata: Metadata,
    clean: bool,
}

impl Cargo {
    /// Gather metadata from cargo for a specific library and binding crate
    /// name. If dependency finding isn't needed then Cargo.lock files don't
    /// need to be parsed.
    pub(crate) fn load(
        crate_dir: &Path,
        lock_file: Option<&str>,
        binding_crate_name: Option<&str>,
        use_cargo_lock: bool,
        clean: bool,
    ) -> Result<Cargo, Error> {
        let toml_path = crate_dir.join("Cargo.toml");
        let metadata = cargo_metadata::metadata(&toml_path)
            .map_err(|x| Error::CargoMetadata(toml_path.to_str().unwrap().to_owned(), x))?;
        let lock_path = lock_file
            .map(PathBuf::from)
            .unwrap_or_else(|| Path::new(&metadata.workspace_root).join("Cargo.lock"));

        let lock = if use_cargo_lock {
            match cargo_lock::lock(&lock_path) {
                Ok(lock) => Some(lock),
                Err(x) => {
                    warn!("Couldn't load lock file {:?}: {:?}", lock_path, x);
                    None
                }
            }
        } else {
            None
        };

        // Use the specified binding crate name or infer it from the manifest
        let manifest = cargo_toml::manifest(&toml_path)
            .map_err(|x| Error::CargoToml(toml_path.to_str().unwrap().to_owned(), x))?;

        let binding_crate_name =
            binding_crate_name.map_or(manifest.package.name.clone(), |x| x.to_owned());

        Ok(Cargo {
            manifest_path: toml_path,
            binding_crate_name,
            lock,
            metadata,
            clean,
        })
    }

    pub(crate) fn binding_crate_name(&self) -> &str {
        &self.binding_crate_name
    }

    pub(crate) fn binding_crate_ref(&self) -> PackageRef {
        self.find_pkg_ref(&self.binding_crate_name).unwrap()
    }

    pub(crate) fn dependencies(&self, package: &PackageRef) -> Vec<(PackageRef, Option<Cfg>)> {
        let lock = match self.lock {
            Some(ref lock) => lock,
            None => return vec![],
        };

        let mut dependencies = None;

        // Find the dependencies listing in the lockfile
        if let Some(ref root) = lock.root {
            if root.name == package.name && root.version == package.version {
                dependencies = root.dependencies.as_ref();
            }
        }
        if dependencies.is_none() {
            if let Some(ref lock_packages) = lock.package {
                for lock_package in lock_packages {
                    if lock_package.name == package.name && lock_package.version == package.version
                    {
                        dependencies = lock_package.dependencies.as_ref();
                        break;
                    }
                }
            }
        }
        if dependencies.is_none() {
            return vec![];
        }

        dependencies
            .unwrap()
            .iter()
            .map(|dep| {
                let (dep_name, dep_version) = parse_dep_string(dep);

                // Try to find the cfgs in the Cargo.toml
                let cfg = self
                    .metadata
                    .packages
                    .get(package)
                    .and_then(|meta_package| meta_package.dependencies.get(dep_name))
                    .and_then(|meta_dep| Cfg::load_metadata(meta_dep));

                let package_ref = PackageRef {
                    name: dep_name.to_owned(),
                    version: dep_version.to_owned(),
                };

                (package_ref, cfg)
            })
            .collect()
    }

    /// Finds the package reference in `cargo metadata` that has `package_name`
    /// ignoring the version.
    fn find_pkg_ref(&self, package_name: &str) -> Option<PackageRef> {
        for package in &self.metadata.packages {
            if package.name_and_version.name == package_name {
                return Some(package.name_and_version.clone());
            }
        }
        None
    }

    /// Finds the directory for a specified package reference.
    #[allow(unused)]
    pub(crate) fn find_crate_dir(&self, package: &PackageRef) -> Option<PathBuf> {
        self.metadata
            .packages
            .get(package)
            .and_then(|meta_package| {
                Path::new(&meta_package.manifest_path)
                    .parent()
                    .map(|x| x.to_owned())
            })
    }

    /// Finds `src/lib.rs` for a specified package reference.
    pub(crate) fn find_crate_src(&self, package: &PackageRef) -> Option<PathBuf> {
        let kind_lib = String::from("lib");
        let kind_staticlib = String::from("staticlib");
        let kind_rlib = String::from("rlib");
        let kind_cdylib = String::from("cdylib");
        let kind_dylib = String::from("dylib");

        self.metadata
            .packages
            .get(package)
            .and_then(|meta_package| {
                for target in &meta_package.targets {
                    if target.kind.contains(&kind_lib)
                        || target.kind.contains(&kind_staticlib)
                        || target.kind.contains(&kind_rlib)
                        || target.kind.contains(&kind_cdylib)
                        || target.kind.contains(&kind_dylib)
                    {
                        return Some(PathBuf::from(&target.src_path));
                    }
                }
                None
            })
    }

    pub(crate) fn expand_crate(
        &self,
        package: &PackageRef,
        expand_all_features: bool,
        expand_default_features: bool,
        expand_features: &Option<Vec<String>>,
    ) -> Result<String, cargo_expand::Error> {
        cargo_expand::expand(
            &self.manifest_path,
            &package.name,
            &package.version,
            self.clean,
            expand_all_features,
            expand_default_features,
            expand_features,
        )
    }
}
<|endoftext|>


<commit_before>use rm::linalg::matrix::Matrix;
use rm::learning::UnSupModel;
use rm::learning::k_means::KMeansClassifier;
use rm::learning::k_means::InitAlgorithm;

#[test]
fn test_model_default() {
    let mut model = KMeansClassifier::new(3);
    let data = Matrix::new(3, 2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    let pred_data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);

    model.train(data);

    let a = model.predict(pred_data);

    assert_eq!(a.data.len(), 3);
}

#[test]
fn test_model_forgy() {
    let mut model = KMeansClassifier::new(3);
    let data = Matrix::new(3, 2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    let pred_data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);

    model.init_algorithm = InitAlgorithm::Forgy;
    model.train(data);

    let a = model.predict(pred_data);

    assert_eq!(a.data.len(), 3);
}

#[test]
fn test_model_ran_partition() {
    let mut model = KMeansClassifier::new(3);
    let data = Matrix::new(3, 2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    let pred_data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);

    model.init_algorithm = InitAlgorithm::RandomPartition;
    model.train(data);

    let a = model.predict(pred_data);

    assert_eq!(a.data.len(), 3);
}<commit_msg>Added test for varied iterations.<commit_after>use rm::linalg::matrix::Matrix;
use rm::learning::UnSupModel;
use rm::learning::k_means::KMeansClassifier;
use rm::learning::k_means::InitAlgorithm;

#[test]
fn test_model_default() {
    let mut model = KMeansClassifier::new(3);
    let data = Matrix::new(3, 2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    let pred_data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);

    model.train(data);

    let a = model.predict(pred_data);

    assert_eq!(a.data.len(), 3);
}

#[test]
fn test_model_iter() {
    let mut model = KMeansClassifier::new(3);
    let data = Matrix::new(3, 2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    let pred_data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);

    model.iters = 1000;
    model.train(data);

    let a = model.predict(pred_data);

    assert_eq!(a.data.len(), 3);
}

#[test]
fn test_model_forgy() {
    let mut model = KMeansClassifier::new(3);
    let data = Matrix::new(3, 2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    let pred_data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);

    model.init_algorithm = InitAlgorithm::Forgy;
    model.train(data);

    let a = model.predict(pred_data);

    assert_eq!(a.data.len(), 3);
}

#[test]
fn test_model_ran_partition() {
    let mut model = KMeansClassifier::new(3);
    let data = Matrix::new(3, 2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);
    let pred_data = Matrix::new(3,2, vec![1.0, 2.0, 1.0, 3.0, 1.0, 4.0]);

    model.init_algorithm = InitAlgorithm::RandomPartition;
    model.train(data);

    let a = model.predict(pred_data);

    assert_eq!(a.data.len(), 3);
}<|endoftext|>