<commit_before>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::fmt;
use crate::marker::{PhantomData, Unpin};

/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
/// which provides customized wakeup behavior.
///
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
///
/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that
/// customizes the behavior of the `RawWaker`.
///
/// [`Waker`]: struct.Waker.html
#[derive(PartialEq, Debug)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct RawWaker {
    /// A data pointer, which can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this field gets passed to all functions that are part of
    /// the vtable as the first parameter.
    data: *const (),
    /// Virtual function pointer table that customizes the behavior of this waker.
    vtable: &'static RawWakerVTable,
}

impl RawWaker {
    /// Creates a new `RawWaker` from the provided `data` pointer and `vtable`.
    ///
    /// The `data` pointer can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this pointer will get passed to all functions that are part
    /// of the `vtable` as the first parameter.
    ///
    /// The `vtable` customizes the behavior of a `Waker` which gets created
    /// from a `RawWaker`. For each operation on the `Waker`, the associated
    /// function in the `vtable` of the underlying `RawWaker` will be called.
    #[inline]
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
    pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
        RawWaker { data, vtable }
    }
}

/// A virtual function pointer table (vtable) that specifies the behavior
/// of a [`RawWaker`].
///
/// The pointer passed to all functions inside the vtable is the `data` pointer
/// from the enclosing [`RawWaker`] object.
///
/// The functions inside this struct are only intended be called on the `data`
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
///
/// [`RawWaker`]: struct.RawWaker.html
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    clone: unsafe fn(*const ()) -> RawWaker,

    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake: unsafe fn(*const ()),

    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    wake_by_ref: unsafe fn(*const ()),

    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    drop: unsafe fn(*const ()),
}

impl RawWakerVTable {
    /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
    /// `wake_by_ref`, and `drop` functions.
    ///
    /// # `clone`
    ///
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// # `wake`
    ///
    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// # `wake_by_ref`
    ///
    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// # `drop`
    ///
    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// [`Waker`]: struct.Waker.html
    /// [`RawWaker`]: struct.RawWaker.html
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
    // without first consulting with T-Lang.
    //
    // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
    // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
    #[rustc_allow_const_fn_ptr]
    #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
    pub const fn new(
        clone: unsafe fn(*const ()) -> RawWaker,
        wake: unsafe fn(*const ()),
        wake_by_ref: unsafe fn(*const ()),
        drop: unsafe fn(*const ()),
    ) -> Self {
        Self { clone, wake, wake_by_ref, drop }
    }
}

/// The `Context` of an asynchronous task.
///
/// Currently, `Context` only serves to provide access to a `&Waker`
/// which can be used to wake the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Context<'a> {
    waker: &'a Waker,
    // Ensure we future-proof against variance changes by forcing
    // the lifetime to be invariant (argument-position lifetimes
    // are contravariant while return-position lifetimes are
    // covariant).
    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
}

impl<'a> Context<'a> {
    /// Create a new `Context` from a `&Waker`.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn from_waker(waker: &'a Waker) -> Self {
        Context { waker, _marker: PhantomData }
    }

    /// Returns a reference to the `Waker` for the current task.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn waker(&self) -> &'a Waker {
        &self.waker
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Context<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Context").field("waker", &self.waker).finish()
    }
}

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`Send`], and [`Sync`].
///
/// [`RawWaker`]: struct.RawWaker.html
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
    waker: RawWaker,
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Unpin for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Send for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Sync for Waker {}

impl Waker {
    /// Wake up the task associated with this `Waker`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake(self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.
        let wake = self.waker.vtable.wake;
        let data = self.waker.data;

        // Don't call `drop` -- the waker will be consumed by `wake`.
        crate::mem::forget(self);

        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `wake` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (wake)(data) };
    }

    /// Wake up the task associated with this `Waker` without consuming the `Waker`.
    ///
    /// This is similar to `wake`, but may be slightly less efficient in the case
    /// where an owned `Waker` is available. This method should be preferred to
    /// calling `waker.clone().wake()`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake_by_ref(&self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.

        // SAFETY: see `wake`
        unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
    }

    /// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.waker == other.waker
    }

    /// Creates a new `Waker` from [`RawWaker`].
    ///
    /// The behavior of the returned `Waker` is undefined if the contract defined
    /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
    /// Therefore this method is unsafe.
    ///
    /// [`RawWaker`]: struct.RawWaker.html
    /// [`RawWakerVTable`]: struct.RawWakerVTable.html
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub unsafe fn from_raw(waker: RawWaker) -> Waker {
        Waker { waker }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        Waker {
            // SAFETY: This is safe because `Waker::from_raw` is the only way
            // to initialize `clone` and `data` requiring the user to acknowledge
            // that the contract of [`RawWaker`] is upheld.
            waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `drop` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (self.waker.vtable.drop)(self.waker.data) }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
        f.debug_struct("Waker")
            .field("data", &self.waker.data)
            .field("vtable", &vtable_ptr)
            .finish()
    }
}
<commit_msg>Rollup merge of #76853 - denisvasilik:intra-doc-links-core-wake, r=jyn514<commit_after>#![stable(feature = "futures_api", since = "1.36.0")]

use crate::fmt;
use crate::marker::{PhantomData, Unpin};

/// A `RawWaker` allows the implementor of a task executor to create a [`Waker`]
/// which provides customized wakeup behavior.
///
/// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table
///
/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable]
/// that customizes the behavior of the `RawWaker`.
#[derive(PartialEq, Debug)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct RawWaker {
    /// A data pointer, which can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this field gets passed to all functions that are part of
    /// the vtable as the first parameter.
    data: *const (),
    /// Virtual function pointer table that customizes the behavior of this waker.
    vtable: &'static RawWakerVTable,
}

impl RawWaker {
    /// Creates a new `RawWaker` from the provided `data` pointer and `vtable`.
    ///
    /// The `data` pointer can be used to store arbitrary data as required
    /// by the executor. This could be e.g. a type-erased pointer to an `Arc`
    /// that is associated with the task.
    /// The value of this pointer will get passed to all functions that are part
    /// of the `vtable` as the first parameter.
    ///
    /// The `vtable` customizes the behavior of a `Waker` which gets created
    /// from a `RawWaker`. For each operation on the `Waker`, the associated
    /// function in the `vtable` of the underlying `RawWaker` will be called.
    #[inline]
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
    pub const fn new(data: *const (), vtable: &'static RawWakerVTable) -> RawWaker {
        RawWaker { data, vtable }
    }
}

/// A virtual function pointer table (vtable) that specifies the behavior
/// of a [`RawWaker`].
///
/// The pointer passed to all functions inside the vtable is the `data` pointer
/// from the enclosing [`RawWaker`] object.
///
/// The functions inside this struct are only intended to be called on the `data`
/// pointer of a properly constructed [`RawWaker`] object from inside the
/// [`RawWaker`] implementation. Calling one of the contained functions using
/// any other `data` pointer will cause undefined behavior.
#[stable(feature = "futures_api", since = "1.36.0")]
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct RawWakerVTable {
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    clone: unsafe fn(*const ()) -> RawWaker,

    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    wake: unsafe fn(*const ()),

    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    wake_by_ref: unsafe fn(*const ()),

    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    drop: unsafe fn(*const ()),
}

impl RawWakerVTable {
    /// Creates a new `RawWakerVTable` from the provided `clone`, `wake`,
    /// `wake_by_ref`, and `drop` functions.
    ///
    /// # `clone`
    ///
    /// This function will be called when the [`RawWaker`] gets cloned, e.g. when
    /// the [`Waker`] in which the [`RawWaker`] is stored gets cloned.
    ///
    /// The implementation of this function must retain all resources that are
    /// required for this additional instance of a [`RawWaker`] and associated
    /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup
    /// of the same task that would have been awoken by the original [`RawWaker`].
    ///
    /// # `wake`
    ///
    /// This function will be called when `wake` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    ///
    /// # `wake_by_ref`
    ///
    /// This function will be called when `wake_by_ref` is called on the [`Waker`].
    /// It must wake up the task associated with this [`RawWaker`].
    ///
    /// This function is similar to `wake`, but must not consume the provided data
    /// pointer.
    ///
    /// # `drop`
    ///
    /// This function gets called when a [`RawWaker`] gets dropped.
    ///
    /// The implementation of this function must make sure to release any
    /// resources that are associated with this instance of a [`RawWaker`] and
    /// associated task.
    #[rustc_promotable]
    #[stable(feature = "futures_api", since = "1.36.0")]
    // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else
    // without first consulting with T-Lang.
    //
    // FIXME: remove whenever we have a stable way to accept fn pointers from const fn
    // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062)
    #[rustc_allow_const_fn_ptr]
    #[rustc_const_stable(feature = "futures_api", since = "1.36.0")]
    pub const fn new(
        clone: unsafe fn(*const ()) -> RawWaker,
        wake: unsafe fn(*const ()),
        wake_by_ref: unsafe fn(*const ()),
        drop: unsafe fn(*const ()),
    ) -> Self {
        Self { clone, wake, wake_by_ref, drop }
    }
}

/// The `Context` of an asynchronous task.
///
/// Currently, `Context` only serves to provide access to a `&Waker`
/// which can be used to wake the current task.
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Context<'a> {
    waker: &'a Waker,
    // Ensure we future-proof against variance changes by forcing
    // the lifetime to be invariant (argument-position lifetimes
    // are contravariant while return-position lifetimes are
    // covariant).
    _marker: PhantomData<fn(&'a ()) -> &'a ()>,
}

impl<'a> Context<'a> {
    /// Create a new `Context` from a `&Waker`.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn from_waker(waker: &'a Waker) -> Self {
        Context { waker, _marker: PhantomData }
    }

    /// Returns a reference to the `Waker` for the current task.
    #[stable(feature = "futures_api", since = "1.36.0")]
    #[inline]
    pub fn waker(&self) -> &'a Waker {
        &self.waker
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Context<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Context").field("waker", &self.waker).finish()
    }
}

/// A `Waker` is a handle for waking up a task by notifying its executor that it
/// is ready to be run.
///
/// This handle encapsulates a [`RawWaker`] instance, which defines the
/// executor-specific wakeup behavior.
///
/// Implements [`Clone`], [`Send`], and [`Sync`].
#[repr(transparent)]
#[stable(feature = "futures_api", since = "1.36.0")]
pub struct Waker {
    waker: RawWaker,
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Unpin for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Send for Waker {}
#[stable(feature = "futures_api", since = "1.36.0")]
unsafe impl Sync for Waker {}

impl Waker {
    /// Wake up the task associated with this `Waker`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake(self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.
        let wake = self.waker.vtable.wake;
        let data = self.waker.data;

        // Don't call `drop` -- the waker will be consumed by `wake`.
        crate::mem::forget(self);

        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `wake` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (wake)(data) };
    }

    /// Wake up the task associated with this `Waker` without consuming the `Waker`.
    ///
    /// This is similar to `wake`, but may be slightly less efficient in the case
    /// where an owned `Waker` is available. This method should be preferred to
    /// calling `waker.clone().wake()`.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn wake_by_ref(&self) {
        // The actual wakeup call is delegated through a virtual function call
        // to the implementation which is defined by the executor.

        // SAFETY: see `wake`
        unsafe { (self.waker.vtable.wake_by_ref)(self.waker.data) }
    }

    /// Returns `true` if this `Waker` and another `Waker` have awoken the same task.
    ///
    /// This function works on a best-effort basis, and may return false even
    /// when the `Waker`s would awaken the same task. However, if this function
    /// returns `true`, it is guaranteed that the `Waker`s will awaken the same task.
    ///
    /// This function is primarily used for optimization purposes.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub fn will_wake(&self, other: &Waker) -> bool {
        self.waker == other.waker
    }

    /// Creates a new `Waker` from [`RawWaker`].
    ///
    /// The behavior of the returned `Waker` is undefined if the contract defined
    /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld.
    /// Therefore this method is unsafe.
    #[inline]
    #[stable(feature = "futures_api", since = "1.36.0")]
    pub unsafe fn from_raw(waker: RawWaker) -> Waker {
        Waker { waker }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Clone for Waker {
    #[inline]
    fn clone(&self) -> Self {
        Waker {
            // SAFETY: This is safe because `Waker::from_raw` is the only way
            // to initialize `clone` and `data` requiring the user to acknowledge
            // that the contract of [`RawWaker`] is upheld.
            waker: unsafe { (self.waker.vtable.clone)(self.waker.data) },
        }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl Drop for Waker {
    #[inline]
    fn drop(&mut self) {
        // SAFETY: This is safe because `Waker::from_raw` is the only way
        // to initialize `drop` and `data` requiring the user to acknowledge
        // that the contract of `RawWaker` is upheld.
        unsafe { (self.waker.vtable.drop)(self.waker.data) }
    }
}

#[stable(feature = "futures_api", since = "1.36.0")]
impl fmt::Debug for Waker {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let vtable_ptr = self.waker.vtable as *const RawWakerVTable;
        f.debug_struct("Waker")
            .field("data", &self.waker.data)
            .field("vtable", &vtable_ptr)
            .finish()
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate error_chain;
#[macro_use]
extern crate lanta;

use lanta::errors::*;
use lanta::layout::*;
use lanta::{cmd, Lanta, ModKey};

macro_rules! spawn {
    ($cmd:expr) => (::lanta::cmd::lazy::spawn(::std::process::Command::new($cmd)));
    ($cmd:expr, $($arg:expr),*) => {{
        let mut command = ::std::process::Command::new($cmd);
        $(
            command.arg($arg);
        )*
        ::lanta::cmd::lazy::spawn(command)
    }}
}

fn run() -> Result<()> {
    lanta::intiailize_logger()?;

    let modkey = ModKey::Mod4;
    let shift = ModKey::Shift;
    let mut keys = keys![
        ([modkey], XK_w, cmd::lazy::close_focused_window()),
        ([modkey], XK_j, cmd::lazy::focus_next()),
        ([modkey], XK_k, cmd::lazy::focus_previous()),
        ([modkey, shift], XK_j, cmd::lazy::shuffle_next()),
        ([modkey, shift], XK_k, cmd::lazy::shuffle_previous()),
        ([modkey], XK_Tab, cmd::lazy::layout_next()),
        ([modkey], XK_Return, spawn!("urxvt")),
        ([modkey], XK_c, spawn!("firefox-nightly")),
        ([modkey], XK_v, spawn!("code-oss")),
        (
            [modkey],
            XK_b,
            spawn!("spotify --force-device-scale-factor=2")
        ),
        ([modkey], XK_q, spawn!("change-wallpaper")),
        (
            [],
            XF86XK_MonBrightnessUp,
            spawn!("xbacklight", "-inc", "10")
        ),
        (
            [],
            XF86XK_MonBrightnessDown,
            spawn!("xbacklight", "-dec", "10")
        ),
        ([], XF86XK_AudioPrev, spawn!("playerctl", "previous")),
        ([], XF86XK_AudioPlay, spawn!("playerctl", "play-pause")),
        ([], XF86XK_AudioNext, spawn!("playerctl", "next")),
        (
            [],
            XF86XK_AudioRaiseVolume,
            spawn!("amixer", "-q", "set", "Master", "5%+")
        ),
        (
            [],
            XF86XK_AudioLowerVolume,
            spawn!("amixer", "-q", "set", "Master", "5%-")
        ),
        (
            [],
            XF86XK_AudioMute,
            spawn!("amixer", "-q", "set", "Master", "toggle")
        ),
    ];

    let padding = 20;
    let layouts = layouts![
        StackLayout::new("stack-padded", padding),
        StackLayout::new("stack", 0),
        TiledLayout::new("tiled", padding),
    ];

    let groups = groups! {
        keys,
        shift,
        [
            ([modkey], XK_a, "chrome", "stack"),
            ([modkey], XK_s, "code", "stack"),
            ([modkey], XK_d, "term", "tiled"),
            ([modkey], XK_f, "misc", "tiled"),
        ]
    };

    Lanta::new(keys, groups, &layouts)?.run();

    Ok(())
}

quick_main!(run);
<commit_msg>Remove error-chain from bin/lanta.rs.<commit_after>#[macro_use]
extern crate lanta;

use lanta::errors::*;
use lanta::layout::*;
use lanta::{cmd, Lanta, ModKey};

macro_rules! spawn {
    ($cmd:expr) => (::lanta::cmd::lazy::spawn(::std::process::Command::new($cmd)));
    ($cmd:expr, $($arg:expr),*) => {{
        let mut command = ::std::process::Command::new($cmd);
        $(
            command.arg($arg);
        )*
        ::lanta::cmd::lazy::spawn(command)
    }}
}

fn main() -> Result<()> {
    lanta::intiailize_logger()?;

    let modkey = ModKey::Mod4;
    let shift = ModKey::Shift;
    let mut keys = keys![
        ([modkey], XK_w, cmd::lazy::close_focused_window()),
        ([modkey], XK_j, cmd::lazy::focus_next()),
        ([modkey], XK_k, cmd::lazy::focus_previous()),
        ([modkey, shift], XK_j, cmd::lazy::shuffle_next()),
        ([modkey, shift], XK_k, cmd::lazy::shuffle_previous()),
        ([modkey], XK_Tab, cmd::lazy::layout_next()),
        ([modkey], XK_Return, spawn!("urxvt")),
        ([modkey], XK_c, spawn!("firefox-nightly")),
        ([modkey], XK_v, spawn!("code-oss")),
        (
            [modkey],
            XK_b,
            spawn!("spotify --force-device-scale-factor=2")
        ),
        ([modkey], XK_q, spawn!("change-wallpaper")),
        (
            [],
            XF86XK_MonBrightnessUp,
            spawn!("xbacklight", "-inc", "10")
        ),
        (
            [],
            XF86XK_MonBrightnessDown,
            spawn!("xbacklight", "-dec", "10")
        ),
        ([], XF86XK_AudioPrev, spawn!("playerctl", "previous")),
        ([], XF86XK_AudioPlay, spawn!("playerctl", "play-pause")),
        ([], XF86XK_AudioNext, spawn!("playerctl", "next")),
        (
            [],
            XF86XK_AudioRaiseVolume,
            spawn!("amixer", "-q", "set", "Master", "5%+")
        ),
        (
            [],
            XF86XK_AudioLowerVolume,
            spawn!("amixer", "-q", "set", "Master", "5%-")
        ),
        (
            [],
            XF86XK_AudioMute,
            spawn!("amixer", "-q", "set", "Master", "toggle")
        ),
    ];

    let padding = 20;
    let layouts = layouts![
        StackLayout::new("stack-padded", padding),
        StackLayout::new("stack", 0),
        TiledLayout::new("tiled", padding),
    ];

    let groups = groups! {
        keys,
        shift,
        [
            ([modkey], XK_a, "chrome", "stack"),
            ([modkey], XK_s, "code", "stack"),
            ([modkey], XK_d, "term", "tiled"),
            ([modkey], XK_f, "misc", "tiled"),
        ]
    };

    Lanta::new(keys, groups, &layouts)?.run();

    Ok(())
}
<|endoftext|>


<commit_before>extern crate cargo_apk_injected_glue;

extern {
    fn main(_: isize, _: *const *const u8);
}

// This function is here because we are sure that it will be included by the linker.
// So we call app_dummy in it, in order to be sure that the native glue will be included.
pub fn start(_: isize, _: *const *const u8) -> isize {
    unsafe { cargo_apk_injected_glue::ffi::app_dummy() };
    1
}

#[no_mangle]
#[inline(never)]
#[allow(non_snake_case)]
pub extern "C" fn android_main(app: *mut ()) {
    cargo_apk_injected_glue::android_main2(app as *mut _, move |c, v| unsafe { main(c, v) });
}
<commit_msg>Add #![no_std] to the glue object<commit_after>#![no_std]

extern crate cargo_apk_injected_glue;

extern {
    fn main(_: isize, _: *const *const u8);
}

// This function is here because we are sure that it will be included by the linker.
// So we call app_dummy in it, in order to be sure that the native glue will be included.
pub fn start(_: isize, _: *const *const u8) -> isize {
    unsafe { cargo_apk_injected_glue::ffi::app_dummy() };
    1
}

#[no_mangle]
#[inline(never)]
#[allow(non_snake_case)]
pub extern "C" fn android_main(app: *mut ()) {
    cargo_apk_injected_glue::android_main2(app as *mut _, move |c, v| unsafe { main(c, v) });
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Bookmark management.

use std::path::PathBuf;
use std::sync::Mutex;

use rusqlite::Connection;
use rusqlite::types::ToSql;

use app::AppResult;

lazy_static! {
    static ref CONNECTION: Mutex<Option<Connection>> = Mutex::new(None);
}

/// A bookmark has a title and a URL and optionally some tags.
#[derive(Debug)]
pub struct Bookmark {
    pub tags: String,
    pub title: String,
    pub url: String,
}

impl Bookmark {
    /// Create a new bookmark.
    pub fn new(url: String, title: String, tags: String) -> Self {
        Bookmark {
            tags: tags,
            title: title,
            url: url,
        }
    }
}

/// A bookmark manager is use to add, search and remove bookmarks.
pub struct BookmarkManager {
}

impl BookmarkManager {
    /// Create a new bookmark manager.
    pub fn new() -> Self {
        BookmarkManager {
        }
    }

    /// Add a bookmark.
    /// Returns true if the bookmark was added.
    pub fn add(&self, url: String, title: Option<String>) -> AppResult<bool> {
        if let Some(ref connection) = *CONNECTION.lock()? {
            if let Ok(inserted_count) = connection.execute("
                INSERT INTO bookmarks (title, url)
                VALUES ($1, $2)
                ", &[&title.unwrap_or_default(), &url])
            {
                return Ok(inserted_count > 0);
            }
        }
        Ok(false)
    }

    /// Connect to the database if it is not already connected.
    pub fn connect(&self, filename: PathBuf) -> AppResult<()> {
        let mut connection = CONNECTION.lock()?;
        if connection.is_none() {
            *connection = Some(Connection::open(filename)?);
        }
        Ok(())
    }

    /// Create the SQL tables for the bookmarks.
    pub fn create_tables(&self) -> AppResult<()> {
        if let Some(ref connection) = *CONNECTION.lock()? {
            connection.execute("
            CREATE TABLE IF NOT EXISTS bookmarks
            ( id INTEGER PRIMARY KEY
            , title TEXT NOT NULL
            , url TEXT NOT NULL UNIQUE
            , visit_count INTEGER NOT NULL DEFAULT 0
            )", &[])?;

            connection.execute("
            CREATE TABLE IF NOT EXISTS tags
            ( id INTEGER PRIMARY KEY
            , name TEXT NOT NULL UNIQUE
            )", &[])?;

            connection.execute("
            CREATE TABLE IF NOT EXISTS bookmarks_tags
            ( bookmark_id INTEGER NOT NULL
            , tag_id INTEGER NOT NULL
            , FOREIGN KEY(bookmark_id) REFERENCES bookmarks(id)
            , FOREIGN KEY(tag_id) REFERENCES tags(id)
            )", &[])?;
        }
        Ok(())
    }

    /// Delete a bookmark.
    /// Returns true if a bookmark was deleted.
    pub fn delete(&self, url: &str) -> AppResult<bool> {
        if let Some(ref connection) = *CONNECTION.lock()? {
            if let Ok(deleted_count) = connection.execute("
                DELETE FROM bookmarks
                WHERE url = $1
                ", &[&url.to_string()])
            {
                return Ok(deleted_count > 0);
            }
        }
        Ok(false)
    }

    /// Get the id of a bookmark.
    pub fn get_id(&self, url: &str) -> Option<i32> {
        if let Ok(guard) = CONNECTION.lock() {
            if let Some(ref connection) = *guard {
                if let Ok(mut statement) = connection.prepare("
                        SELECT id
                        FROM bookmarks
                        WHERE url = $1
                    ")
                {
                    if let Ok(mut rows) = statement.query(&[&url.to_string()])
                    {
                        return rows.next().and_then(|row| row.ok().map(|row| row.get(0)));
                    }
                }
            }
        }
        None
    }

    /// Get the tag ID of a bookmark.
    pub fn get_tag_id(&self, connection: &Connection, tag: &str) -> AppResult<i32> {
        let mut statement = connection.prepare("
            SELECT id
            FROM tags
            WHERE name = $1
        ")?;
        let mut rows = statement.query(&[&tag.to_string()])?;
        let row = rows.next().unwrap(); // TODO: handle the error
        let id = row.map(|row| row.get(0))?;
        Ok(id)
    }

    /// Get the tags of a bookmark.
    pub fn get_tags(&self, url: &str) -> Option<Vec<String>> {
        if let Ok(guard) = CONNECTION.lock() {
            if let Some(ref connection) = *guard {
                if let Ok(mut statement) = connection.prepare("
                        SELECT name
                        FROM tags
                        INNER JOIN bookmarks_tags
                            ON tags.id = bookmarks_tags.tag_id
                        INNER JOIN bookmarks
                            ON bookmarks_tags.bookmark_id = bookmarks.id
                        WHERE url = $1
                    ")
                {
                    if let Ok(rows) = statement.query_map(&[&url.to_string()], |row| {
                            row.get(0)
                        })
                    {
                        return rows.collect::<Result<Vec<_>, _>>().ok();
                    }
                }
            }
        }
        None
    }

    /// Query the bookmarks.
    pub fn query(&self, input: BookmarkInput) -> Vec<Bookmark> {
        if let Ok(guard) = CONNECTION.lock() {
            if let Some(ref connection) = *guard {
                let mut params: Vec<&ToSql> = vec![];

                let mut title_idents = vec![];
                for (index, title) in input.words.iter().enumerate() {
                    title_idents.push(format!("(title LIKE '%' || ${} || '%' OR url LIKE '%' || ${} || '%')", index, index + 1));
                    params.push(title);
                    params.push(title);
                }
                let title_idents = title_idents.join(" AND ");
                let where_clause =
                    if !title_idents.is_empty() {
                        format!("WHERE {}", title_idents)
                    }
                    else {
                        String::new()
                    };

                let delta = params.len();
                let mut tag_idents = vec![];
                for (index, tag) in input.tags.iter().enumerate() {
                    tag_idents.push(format!("tags.name LIKE ${} || '%'", index + delta));
                    params.push(tag);
                }
                let tag_idents = tag_idents.join(" OR ");
                let having_clause =
                    if !tag_idents.is_empty() {
                        format!("HAVING COUNT(CASE WHEN {} THEN 1 END) = {}", tag_idents, input.tags.len())
                    }
                    else {
                        String::new()
                    };

                if let Ok(mut statement) = connection.prepare(&format!("
                        SELECT title, url, GROUP_CONCAT(tags.name, ' #')
                        FROM bookmarks
                        LEFT OUTER JOIN bookmarks_tags
                            ON bookmarks.id = bookmarks_tags.bookmark_id
                        LEFT OUTER JOIN tags
                            ON bookmarks_tags.tag_id = tags.id
                        {}
                        GROUP BY url
                        {}
                    ", where_clause, having_clause))
                {
                    if let Ok(rows) = statement.query_map(&params, |row| {
                            Bookmark::new(row.get(1), row.get(0), row.get(2))
                        })
                    {
                        return rows.collect::<Result<Vec<_>, _>>().unwrap_or_else(|_| vec![]);
                    }
                }
            }
        }
        vec![]
    }

    /// Set the tags of a bookmark.
    pub fn set_tags(&self, url: &str, tags: Vec<String>) -> AppResult<()> {
        if let Some(bookmark_id) = self.get_id(url) {
            // TODO: refactor to use only two queries instead of a loop of queries.
            for tag in &tags {
                let tag = tag.to_lowercase();
                if let Some(ref connection) = *CONNECTION.lock()? {
                    connection.execute("
                        INSERT OR IGNORE INTO tags (name)
                        VALUES ($1)
                    ", &[&tag])?;
                    let tag_id = self.get_tag_id(connection, &tag)?;
                    connection.execute("
                        INSERT INTO bookmarks_tags (bookmark_id, tag_id)
                        VALUES ($1, $2)
                    ", &[&bookmark_id, &tag_id])?;
                }
            }
        }
        Ok(())
    }
}

/// A bookmark input query.
pub struct BookmarkInput {
    pub tags: Vec<String>,
    pub words: Vec<String>,
}
<commit_msg>Added ON DELETE CASCADE and activated foreign keys.<commit_after>/*
 * Copyright (c) 2016 Boucher, Antoni <bouanto@zoho.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
 * this software and associated documentation files (the "Software"), to deal in
 * the Software without restriction, including without limitation the rights to
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 * the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

//! Bookmark management.

use std::path::PathBuf;
use std::sync::Mutex;

use rusqlite::Connection;
use rusqlite::types::ToSql;

use app::AppResult;

lazy_static! {
    static ref CONNECTION: Mutex<Option<Connection>> = Mutex::new(None);
}

/// A bookmark has a title and a URL and optionally some tags.
#[derive(Debug)]
pub struct Bookmark {
    pub tags: String,
    pub title: String,
    pub url: String,
}

impl Bookmark {
    /// Create a new bookmark.
    pub fn new(url: String, title: String, tags: String) -> Self {
        Bookmark {
            tags: tags,
            title: title,
            url: url,
        }
    }
}

/// A bookmark manager is use to add, search and remove bookmarks.
pub struct BookmarkManager {
}

impl BookmarkManager {
    /// Create a new bookmark manager.
    pub fn new() -> Self {
        BookmarkManager {
        }
    }

    /// Add a bookmark.
    /// Returns true if the bookmark was added.
    pub fn add(&self, url: String, title: Option<String>) -> AppResult<bool> {
        if let Some(ref connection) = *CONNECTION.lock()? {
            if let Ok(inserted_count) = connection.execute("
                INSERT INTO bookmarks (title, url)
                VALUES ($1, $2)
                ", &[&title.unwrap_or_default(), &url])
            {
                return Ok(inserted_count > 0);
            }
        }
        Ok(false)
    }

    /// Connect to the database if it is not already connected.
    pub fn connect(&self, filename: PathBuf) -> AppResult<()> {
        let mut connection = CONNECTION.lock()?;
        if connection.is_none() {
            let db = Connection::open(filename)?;
            // Activate foreign key contraints in SQLite.
            db.execute("PRAGMA foreign_keys = ON", &[])?;
            *connection = Some(db);
        }
        Ok(())
    }

    /// Create the SQL tables for the bookmarks.
    pub fn create_tables(&self) -> AppResult<()> {
        if let Some(ref connection) = *CONNECTION.lock()? {
            connection.execute("
            CREATE TABLE IF NOT EXISTS bookmarks
            ( id INTEGER PRIMARY KEY
            , title TEXT NOT NULL
            , url TEXT NOT NULL UNIQUE
            , visit_count INTEGER NOT NULL DEFAULT 0
            )", &[])?;

            connection.execute("
            CREATE TABLE IF NOT EXISTS tags
            ( id INTEGER PRIMARY KEY
            , name TEXT NOT NULL UNIQUE
            )", &[])?;

            connection.execute("
            CREATE TABLE IF NOT EXISTS bookmarks_tags
            ( bookmark_id INTEGER NOT NULL
            , tag_id INTEGER NOT NULL
            , FOREIGN KEY(bookmark_id) REFERENCES bookmarks(id) ON DELETE CASCADE
            , FOREIGN KEY(tag_id) REFERENCES tags(id) ON DELETE CASCADE
            )", &[])?;
        }
        Ok(())
    }

    /// Delete a bookmark.
    /// Returns true if a bookmark was deleted.
    pub fn delete(&self, url: &str) -> AppResult<bool> {
        if let Some(ref connection) = *CONNECTION.lock()? {
            if let Ok(deleted_count) = connection.execute("
                DELETE FROM bookmarks
                WHERE url = $1
                ", &[&url.to_string()])
            {
                return Ok(deleted_count > 0);
            }
        }
        Ok(false)
    }

    /// Get the id of a bookmark.
    pub fn get_id(&self, url: &str) -> Option<i32> {
        if let Ok(guard) = CONNECTION.lock() {
            if let Some(ref connection) = *guard {
                if let Ok(mut statement) = connection.prepare("
                        SELECT id
                        FROM bookmarks
                        WHERE url = $1
                    ")
                {
                    if let Ok(mut rows) = statement.query(&[&url.to_string()])
                    {
                        return rows.next().and_then(|row| row.ok().map(|row| row.get(0)));
                    }
                }
            }
        }
        None
    }

    /// Get the tag ID of a bookmark.
    pub fn get_tag_id(&self, connection: &Connection, tag: &str) -> AppResult<i32> {
        let mut statement = connection.prepare("
            SELECT id
            FROM tags
            WHERE name = $1
        ")?;
        let mut rows = statement.query(&[&tag.to_string()])?;
        let row = rows.next().unwrap(); // TODO: handle the error
        let id = row.map(|row| row.get(0))?;
        Ok(id)
    }

    /// Get the tags of a bookmark.
    pub fn get_tags(&self, url: &str) -> Option<Vec<String>> {
        if let Ok(guard) = CONNECTION.lock() {
            if let Some(ref connection) = *guard {
                if let Ok(mut statement) = connection.prepare("
                        SELECT name
                        FROM tags
                        INNER JOIN bookmarks_tags
                            ON tags.id = bookmarks_tags.tag_id
                        INNER JOIN bookmarks
                            ON bookmarks_tags.bookmark_id = bookmarks.id
                        WHERE url = $1
                    ")
                {
                    if let Ok(rows) = statement.query_map(&[&url.to_string()], |row| {
                            row.get(0)
                        })
                    {
                        return rows.collect::<Result<Vec<_>, _>>().ok();
                    }
                }
            }
        }
        None
    }

    /// Query the bookmarks.
    pub fn query(&self, input: BookmarkInput) -> Vec<Bookmark> {
        if let Ok(guard) = CONNECTION.lock() {
            if let Some(ref connection) = *guard {
                let mut params: Vec<&ToSql> = vec![];

                let mut title_idents = vec![];
                for (index, title) in input.words.iter().enumerate() {
                    title_idents.push(format!("(title LIKE '%' || ${} || '%' OR url LIKE '%' || ${} || '%')", index, index + 1));
                    params.push(title);
                    params.push(title);
                }
                let title_idents = title_idents.join(" AND ");
                let where_clause =
                    if !title_idents.is_empty() {
                        format!("WHERE {}", title_idents)
                    }
                    else {
                        String::new()
                    };

                let delta = params.len();
                let mut tag_idents = vec![];
                for (index, tag) in input.tags.iter().enumerate() {
                    tag_idents.push(format!("tags.name LIKE ${} || '%'", index + delta));
                    params.push(tag);
                }
                let tag_idents = tag_idents.join(" OR ");
                let having_clause =
                    if !tag_idents.is_empty() {
                        format!("HAVING COUNT(CASE WHEN {} THEN 1 END) = {}", tag_idents, input.tags.len())
                    }
                    else {
                        String::new()
                    };

                if let Ok(mut statement) = connection.prepare(&format!("
                        SELECT title, url, GROUP_CONCAT(tags.name, ' #')
                        FROM bookmarks
                        LEFT OUTER JOIN bookmarks_tags
                            ON bookmarks.id = bookmarks_tags.bookmark_id
                        LEFT OUTER JOIN tags
                            ON bookmarks_tags.tag_id = tags.id
                        {}
                        GROUP BY url
                        {}
                    ", where_clause, having_clause))
                {
                    if let Ok(rows) = statement.query_map(&params, |row| {
                            Bookmark::new(row.get(1), row.get(0), row.get(2))
                        })
                    {
                        return rows.collect::<Result<Vec<_>, _>>().unwrap_or_else(|_| vec![]);
                    }
                }
            }
        }
        vec![]
    }

    /// Set the tags of a bookmark.
    pub fn set_tags(&self, url: &str, tags: Vec<String>) -> AppResult<()> {
        if let Some(bookmark_id) = self.get_id(url) {
            for tag in &tags {
                let tag = tag.to_lowercase();
                if let Some(ref connection) = *CONNECTION.lock()? {
                    connection.execute("
                        INSERT OR IGNORE INTO tags (name)
                        VALUES ($1)
                    ", &[&tag])?;
                    let tag_id = self.get_tag_id(connection, &tag)?;
                    connection.execute("
                        INSERT INTO bookmarks_tags (bookmark_id, tag_id)
                        VALUES ($1, $2)
                    ", &[&bookmark_id, &tag_id])?;
                }
            }
        }
        Ok(())
    }
}

/// A bookmark input query.
pub struct BookmarkInput {
    pub tags: Vec<String>,
    pub words: Vec<String>,
}
<|endoftext|>


<commit_before>use ndarray::{Axis, stack};
use std::collections::BTreeMap;
use helper::*;
use join::*;
use error::*;
use types::*;

#[derive(Debug, Clone, PartialEq)]
pub struct DataFrame {
    columns: BTreeMap<ColumnType, usize>,
    data: Matrix<InnerType>,
    index: BTreeMap<IndexType, usize>,
}

impl DataFrame {
    pub fn new(data: Matrix<f64>) -> DataFrame {
        let data: Matrix<InnerType> = data.mapv(InnerType::from);

        let columns: BTreeMap<ColumnType, usize> = (0..data.shape()[1])
            .enumerate()
            .map(|(x, y)| (ColumnType::Str(x.to_string()), y))
            .collect();

        let index: BTreeMap<IndexType, usize> = (0..data.shape()[0])
            .enumerate()
            .map(|(x, y)| (IndexType::Str(x.to_string()), y))
            .collect();

        DataFrame {
            data: data,
            columns: columns,
            index: index,
        }
    }

    pub fn columns(mut self, columns: Vec<String>) -> Result<DataFrame> {
        if columns.len() != self.data.shape()[1] {
            return Err(ErrorKind::ColumnShapeMismatch.into());
        }
        self.columns = columns.iter()
            .zip((0..columns.len()))
            .map(|(x, y)| (ColumnType::from(x.to_string()), y))
            .collect();
        Ok(self)
    }

    pub fn index(mut self, index: Vec<String>) -> Result<DataFrame> {
        if index.len() != self.data.shape()[0] {
            return Err(ErrorKind::RowShapeMismatch.into());
        }
        self.index = index.iter()
            .zip((0..index.len()))
            .map(|(x, y)| (IndexType::from(x.to_string()), y))
            .collect();
        Ok(self)
    }

    pub fn names(&self) -> Vec<ColumnType> {
        self.columns.keys().map(|x| x.to_owned()).collect()
    }

    // pub fn new(data: Matrix<f64>,
    //            columns: BTreeMap<ColumnType, usize>,
    //            index: Option<BTreeMap<IndexType, usize>>)
    //            -> Result<DataFrame> {
    //
    //     let data: Matrix<InnerType> = data.mapv(InnerType::from);
    //
    //     if columns.len() != data.shape()[1] {
    //         return Err(ErrorKind::ColumnShapeMismatch.into());
    //     }
    //
    //
    //     let idx = match index {
    //         Some(z) => {
    //             if z.len() != data.shape()[0] {
    //                 return Err(ErrorKind::RowShapeMismatch.into());
    //             }
    //             z
    //         }
    //         None => {
    //             let b: BTreeMap<IndexType, usize> = (0..data.shape()[0])
    //                 .enumerate()
    //                 .map(|(x, y)| (IndexType::Str(x.to_string()), y))
    //                 .collect();
    //             b
    //         }
    //     };
    //
    //     let dm = DataFrame {
    //         columns: columns,
    //         data: data,
    //         index: idx,
    //     };
    //
    //     Ok(dm)
    // }

    pub fn get(self, name: &str) -> Result<Column<InnerType>> {
        let name = ColumnType::from(name.to_string());
        match self.columns.get(&name) {
            Some(x) => Ok(self.data.column(*x).to_owned()),
            None => {
                match name {
                    ColumnType::Str(z) => {
                        return Err(ErrorKind::InvalidColumnName(z.to_string()).into())
                    }
                    ColumnType::Date(z) => {
                        return Err(ErrorKind::InvalidColumnName(z.to_string()).into())
                    }
                    ColumnType::Int(z) => {
                        return Err(ErrorKind::InvalidColumnName(z.to_string()).into())
                    }
                }
            }
        }
    }

    pub fn insert_row(mut self, data: Matrix<InnerType>, index: &str) -> Result<DataFrame> {
        let index = IndexType::from(index.to_string());

        let ind_idx = {
            self.index.len()
        };
        self.index.insert(index, ind_idx);
        self.data = match stack(Axis(0), &[self.data.view(), data.view()]) {
            Ok(z) => z,
            Err(_) => return Err(ErrorKind::StackFail.into()),
        };
        Ok(self)

    }

    pub fn insert_column(mut self, data: Matrix<f64>, name: &str) -> Result<DataFrame> {
        let name = ColumnType::from(name.to_string());
        let data = data.mapv(InnerType::from);
        let columns_idx = {
            self.columns.len()
        };
        self.columns.insert(name, columns_idx);
        self.data = match stack(Axis(1), &[self.data.view(), data.view()]) {
            Ok(z) => z,
            Err(_) => return Err(ErrorKind::StackFail.into()),
        };
        Ok(self)

    }

    pub fn shape(&self) -> (usize, usize) {
        self.data.dim()
    }

    pub fn drop_row(&mut self, indexes: &[&str]) -> Result<DataFrame> {
        let mut idxs = vec![];
        let indexes: Vec<IndexType> =
            indexes.iter().map(|x| IndexType::from(x.to_string())).collect();

        let new_map: &mut BTreeMap<IndexType, usize> = &mut self.index.clone();
        for name in indexes.iter() {
            let idx = new_map.remove(name);
            idxs.push(idx.unwrap());
            for (_, y) in new_map.iter_mut() {
                if y > &mut idx.unwrap() {
                    *y -= 1;
                }
            }
        }
        let rows = self.shape().0;
        let to_keep: Vec<usize> = (0..rows).filter(|x| !idxs.iter().any(|&y| y == *x)).collect();
        Ok(DataFrame {
            data: self.data.select(Axis(0), &to_keep[..]),
            columns: self.columns.to_owned(),
            index: new_map.to_owned(),
        })
    }

    pub fn drop_column(&mut self, names: &[&str]) -> Result<DataFrame> {
        let mut idxs = vec![];
        let names: Vec<ColumnType> =
            names.iter().map(|x| ColumnType::from(x.to_string())).collect();

        let new_map: &mut BTreeMap<ColumnType, usize> = &mut self.columns.clone();
        for name in names.iter() {
            let idx = new_map.remove(name);
            idxs.push(idx.unwrap());
            for (_, y) in new_map.iter_mut() {
                if y > &mut idx.unwrap() {
                    *y -= 1;
                }
            }
        }
        let cols = self.shape().1;
        let to_keep: Vec<usize> = (0..cols).filter(|x| !idxs.iter().any(|&y| y == *x)).collect();

        Ok(DataFrame {
            data: self.data.select(Axis(1), &to_keep[..]),
            columns: new_map.to_owned(),
            index: self.index.to_owned(),
        })
    }

    pub fn concat(&self, axis: Axis, other: &DataFrame) -> Result<DataFrame> {

        match axis {
            Axis(0) => {
                if self.shape().1 == other.shape().1 {
                    let new_map: BTreeMap<ColumnType, usize> = self.columns
                        .iter()
                        .map(|(x, y)| (x.to_owned(), *y))
                        .collect();

                    let new_index: BTreeMap<IndexType, usize> = concat_index_maps(&self.index,
                                                                                &other.index);

                    let new_matrix = match stack(Axis(0), &[self.data.view(), other.data.view()]) {
                        Ok(z) => z,
                        Err(_) => return Err(ErrorKind::StackFail.into()),
                    };
                    Ok(DataFrame {
                        data: new_matrix,
                        columns: new_map,
                        index: new_index,
                    })
                } else {
                    return Err(ErrorKind::ColumnShapeMismatch.into());
                }
            }
            Axis(1) => {
                if self.shape().0 == other.shape().0 {
                    let other_map: BTreeMap<ColumnType, usize> = other.columns
                        .iter()
                        .map(|(x, y)| (x.to_owned(), y + self.columns.len()))
                        .collect();
                    let new_map: BTreeMap<ColumnType, usize> = self.columns
                        .iter()
                        .chain(other_map.iter())
                        .map(|(x, y)| (x.to_owned(), *y))
                        .collect();

                    let new_matrix = match stack(Axis(1), &[self.data.view(), other.data.view()]) {
                        Ok(z) => z,
                        Err(_) => return Err(ErrorKind::StackFail.into()),
                    };
                    Ok(DataFrame {
                        data: new_matrix,
                        columns: new_map,
                        index: self.index.to_owned(),
                    })
                } else {
                    return Err(ErrorKind::RowShapeMismatch.into());
                }
            }
            _ => return Err(ErrorKind::InvalidAxis.into()),
        }

    }
    pub fn inner_join(&self, other: &DataFrame) -> Result<DataFrame> {

        let idxs: Vec<(IndexType, usize, Option<usize>)> =
            Join::new(JoinType::InnerJoin,
                      self.index.clone().into_iter(),
                      other.index.clone())
                .collect();

        if idxs.len() == 0 {
            return Err(ErrorKind::NoCommonValues.into());
        }

        let new_matrix: Matrix<InnerType> = {
            let i1: Vec<usize> = idxs.iter().map(|&(_, x, _)| x).collect();
            let i2: Vec<usize> = idxs.iter().map(|&(_, _, y)| y.unwrap()).collect();
            let mat1 = self.data.select(Axis(0), &i1[..]);
            let mat2 = other.data.select(Axis(0), &i2[..]);
            match stack(Axis(1), &[mat1.view(), mat2.view()]) {
                Ok(z) => z,
                Err(_) => return Err(ErrorKind::StackFail.into()),
            }
        };

        Ok(DataFrame {
            data: new_matrix,
            columns: concat_column_maps(&self.columns, &other.columns),
            index: merge_maps(&self.index, &other.index),
        })
    }
}

// To implement....?
// // parallelized join
// // parallelized concatenation
// // parallelized frequency counts
// // index dataframe?
// // sample rows
// // find/select
// // sort
// // statistics (mean, median, stdev)
// // print
//
// // statistics (mean, median, stdev)
// // print
<commit_msg>removed old new function<commit_after>use ndarray::{Axis, stack};
use std::collections::BTreeMap;
use helper::*;
use join::*;
use error::*;
use types::*;

#[derive(Debug, Clone, PartialEq)]
pub struct DataFrame {
    columns: BTreeMap<ColumnType, usize>,
    data: Matrix<InnerType>,
    index: BTreeMap<IndexType, usize>,
}

impl DataFrame {
    pub fn new(data: Matrix<f64>) -> DataFrame {
        let data: Matrix<InnerType> = data.mapv(InnerType::from);

        let columns: BTreeMap<ColumnType, usize> = (0..data.shape()[1])
            .enumerate()
            .map(|(x, y)| (ColumnType::Str(x.to_string()), y))
            .collect();

        let index: BTreeMap<IndexType, usize> = (0..data.shape()[0])
            .enumerate()
            .map(|(x, y)| (IndexType::Str(x.to_string()), y))
            .collect();

        DataFrame {
            data: data,
            columns: columns,
            index: index,
        }
    }

    pub fn columns(mut self, columns: Vec<String>) -> Result<DataFrame> {
        if columns.len() != self.data.shape()[1] {
            return Err(ErrorKind::ColumnShapeMismatch.into());
        }
        self.columns = columns.iter()
            .zip((0..columns.len()))
            .map(|(x, y)| (ColumnType::from(x.to_string()), y))
            .collect();
        Ok(self)
    }

    pub fn index(mut self, index: Vec<String>) -> Result<DataFrame> {
        if index.len() != self.data.shape()[0] {
            return Err(ErrorKind::RowShapeMismatch.into());
        }
        self.index = index.iter()
            .zip((0..index.len()))
            .map(|(x, y)| (IndexType::from(x.to_string()), y))
            .collect();
        Ok(self)
    }

    pub fn names(&self) -> Vec<ColumnType> {
        self.columns.keys().map(|x| x.to_owned()).collect()
    }

    pub fn get(self, name: &str) -> Result<Column<InnerType>> {
        let name = ColumnType::from(name.to_string());
        match self.columns.get(&name) {
            Some(x) => Ok(self.data.column(*x).to_owned()),
            None => {
                match name {
                    ColumnType::Str(z) => {
                        return Err(ErrorKind::InvalidColumnName(z.to_string()).into())
                    }
                    ColumnType::Date(z) => {
                        return Err(ErrorKind::InvalidColumnName(z.to_string()).into())
                    }
                    ColumnType::Int(z) => {
                        return Err(ErrorKind::InvalidColumnName(z.to_string()).into())
                    }
                }
            }
        }
    }

    pub fn insert_row(mut self, data: Matrix<InnerType>, index: &str) -> Result<DataFrame> {
        let index = IndexType::from(index.to_string());

        let ind_idx = {
            self.index.len()
        };
        self.index.insert(index, ind_idx);
        self.data = match stack(Axis(0), &[self.data.view(), data.view()]) {
            Ok(z) => z,
            Err(_) => return Err(ErrorKind::StackFail.into()),
        };
        Ok(self)

    }

    pub fn insert_column(mut self, data: Matrix<f64>, name: &str) -> Result<DataFrame> {
        let name = ColumnType::from(name.to_string());
        let data = data.mapv(InnerType::from);
        let columns_idx = {
            self.columns.len()
        };
        self.columns.insert(name, columns_idx);
        self.data = match stack(Axis(1), &[self.data.view(), data.view()]) {
            Ok(z) => z,
            Err(_) => return Err(ErrorKind::StackFail.into()),
        };
        Ok(self)

    }

    pub fn shape(&self) -> (usize, usize) {
        self.data.dim()
    }

    pub fn drop_row(&mut self, indexes: &[&str]) -> Result<DataFrame> {
        let mut idxs = vec![];
        let indexes: Vec<IndexType> =
            indexes.iter().map(|x| IndexType::from(x.to_string())).collect();

        let new_map: &mut BTreeMap<IndexType, usize> = &mut self.index.clone();
        for name in indexes.iter() {
            let idx = new_map.remove(name);
            idxs.push(idx.unwrap());
            for (_, y) in new_map.iter_mut() {
                if y > &mut idx.unwrap() {
                    *y -= 1;
                }
            }
        }
        let rows = self.shape().0;
        let to_keep: Vec<usize> = (0..rows).filter(|x| !idxs.iter().any(|&y| y == *x)).collect();
        Ok(DataFrame {
            data: self.data.select(Axis(0), &to_keep[..]),
            columns: self.columns.to_owned(),
            index: new_map.to_owned(),
        })
    }

    pub fn drop_column(&mut self, names: &[&str]) -> Result<DataFrame> {
        let mut idxs = vec![];
        let names: Vec<ColumnType> =
            names.iter().map(|x| ColumnType::from(x.to_string())).collect();

        let new_map: &mut BTreeMap<ColumnType, usize> = &mut self.columns.clone();
        for name in names.iter() {
            let idx = new_map.remove(name);
            idxs.push(idx.unwrap());
            for (_, y) in new_map.iter_mut() {
                if y > &mut idx.unwrap() {
                    *y -= 1;
                }
            }
        }
        let cols = self.shape().1;
        let to_keep: Vec<usize> = (0..cols).filter(|x| !idxs.iter().any(|&y| y == *x)).collect();

        Ok(DataFrame {
            data: self.data.select(Axis(1), &to_keep[..]),
            columns: new_map.to_owned(),
            index: self.index.to_owned(),
        })
    }

    pub fn concat(&self, axis: Axis, other: &DataFrame) -> Result<DataFrame> {

        match axis {
            Axis(0) => {
                if self.shape().1 == other.shape().1 {
                    let new_map: BTreeMap<ColumnType, usize> = self.columns
                        .iter()
                        .map(|(x, y)| (x.to_owned(), *y))
                        .collect();

                    let new_index: BTreeMap<IndexType, usize> = concat_index_maps(&self.index,
                                                                                &other.index);

                    let new_matrix = match stack(Axis(0), &[self.data.view(), other.data.view()]) {
                        Ok(z) => z,
                        Err(_) => return Err(ErrorKind::StackFail.into()),
                    };
                    Ok(DataFrame {
                        data: new_matrix,
                        columns: new_map,
                        index: new_index,
                    })
                } else {
                    return Err(ErrorKind::ColumnShapeMismatch.into());
                }
            }
            Axis(1) => {
                if self.shape().0 == other.shape().0 {
                    let other_map: BTreeMap<ColumnType, usize> = other.columns
                        .iter()
                        .map(|(x, y)| (x.to_owned(), y + self.columns.len()))
                        .collect();
                    let new_map: BTreeMap<ColumnType, usize> = self.columns
                        .iter()
                        .chain(other_map.iter())
                        .map(|(x, y)| (x.to_owned(), *y))
                        .collect();

                    let new_matrix = match stack(Axis(1), &[self.data.view(), other.data.view()]) {
                        Ok(z) => z,
                        Err(_) => return Err(ErrorKind::StackFail.into()),
                    };
                    Ok(DataFrame {
                        data: new_matrix,
                        columns: new_map,
                        index: self.index.to_owned(),
                    })
                } else {
                    return Err(ErrorKind::RowShapeMismatch.into());
                }
            }
            _ => return Err(ErrorKind::InvalidAxis.into()),
        }

    }
    pub fn inner_join(&self, other: &DataFrame) -> Result<DataFrame> {

        let idxs: Vec<(IndexType, usize, Option<usize>)> =
            Join::new(JoinType::InnerJoin,
                      self.index.clone().into_iter(),
                      other.index.clone())
                .collect();

        if idxs.len() == 0 {
            return Err(ErrorKind::NoCommonValues.into());
        }

        let new_matrix: Matrix<InnerType> = {
            let i1: Vec<usize> = idxs.iter().map(|&(_, x, _)| x).collect();
            let i2: Vec<usize> = idxs.iter().map(|&(_, _, y)| y.unwrap()).collect();
            let mat1 = self.data.select(Axis(0), &i1[..]);
            let mat2 = other.data.select(Axis(0), &i2[..]);
            match stack(Axis(1), &[mat1.view(), mat2.view()]) {
                Ok(z) => z,
                Err(_) => return Err(ErrorKind::StackFail.into()),
            }
        };

        Ok(DataFrame {
            data: new_matrix,
            columns: concat_column_maps(&self.columns, &other.columns),
            index: merge_maps(&self.index, &other.index),
        })
    }
}

// To implement....?
// // parallelized join
// // parallelized concatenation
// // parallelized frequency counts
// // index dataframe?
// // sample rows
// // find/select
// // sort
// // statistics (mean, median, stdev)
// // print
//
// // statistics (mean, median, stdev)
// // print
<|endoftext|>


<commit_before>extern crate redis;

pub use self::redis::{RedisError};

/// A DataStore needs to implement store and retrieve methods.
pub trait DataStore : Send {
    fn store(&self, key: &str, value: &str) -> Result<(), DataStoreError>;
    fn retrieve(&self, key: &str) -> Result<String, DataStoreError>;
    fn delete(&self, key: &str) -> Result<(), DataStoreError>;
}

/// A struct representing a datastore error.
#[derive(Debug)]
pub struct DataStoreError {
    pub repr: ErrorKind,
}

/// An enum containing all possible error kinds.
#[derive(Debug)]
pub enum ErrorKind {
    RedisError(redis::RedisError),
}

impl From<redis::RedisError> for DataStoreError {
    fn from(err: redis::RedisError) -> DataStoreError {
        DataStoreError { repr: ErrorKind::RedisError(err) }
    }
}
<commit_msg>datastore: Cleanup DataStoreError<commit_after>extern crate redis;

pub use self::redis::{RedisError};

/// A DataStore needs to implement store and retrieve methods.
pub trait DataStore : Send {
    fn store(&self, key: &str, value: &str) -> Result<(), DataStoreError>;
    fn retrieve(&self, key: &str) -> Result<String, DataStoreError>;
    fn delete(&self, key: &str) -> Result<(), DataStoreError>;
}

/// An enum representing a datastore error.
#[derive(Debug)]
pub enum DataStoreError {
    RedisError(redis::RedisError),
}

impl From<redis::RedisError> for DataStoreError {
    fn from(err: redis::RedisError) -> DataStoreError {
        DataStoreError::RedisError(err)
    }
}

<|endoftext|>


<commit_before>use std::marker::PhantomData;

use Construct;
use Data;
use Count;
use Of;
use Subspace;
use ToIndex;
use ToPos;

/// Dimension is natural number, position is the same as index.
pub struct Dimension<T>(PhantomData<T>);

impl<T> Construct for Dimension<T> {
    fn new() -> Dimension<T> { Dimension(PhantomData) }
}

impl Count<usize> for Dimension<Data> {
    fn count(&self, dim: usize) -> usize { dim }
}

impl<T, U> Count<(usize, U)> for Dimension<Subspace<T>>
    where
        T: Construct + Count<U>
{
    fn count(&self, (a, b): (usize, U)) -> usize {
        let subspace: T = Construct::new();
        a * subspace.count(b)
    }
}

impl<T, U> Count<U> for Dimension<Of<T>>
    where
        T: Construct + Count<U>
{
    fn count(&self, dim: U) -> usize {
        let of: T = Construct::new();
        of.count(dim)
    }
}

impl ToIndex<usize, usize> for Dimension<Data> {
    fn to_index(&self, _dim: usize, pos: usize) -> usize { pos }
}

impl<T, U: Copy, V> ToIndex<(usize, U), (usize, V)> for Dimension<Subspace<T>>
    where
        T: Construct + Count<U> + ToIndex<U, V>
{
    fn to_index(&self, (_a, b): (usize, U), (pa, pb): (usize, V)) -> usize {
        let subspace: T = Construct::new();
        let count = subspace.count(b);
        pa * count + subspace.to_index(b, pb)
    }
}

impl ToPos<usize, usize> for Dimension<Data> {
    fn to_pos(&self, _dim: usize, index: usize, pos: &mut usize) {
        *pos = index;
    }
}

impl<T, U: Copy, V>
ToPos<(usize, U), (usize, V)> for Dimension<Subspace<T>>
    where
        T: Construct + Count<U> + ToPos<U, V>
{
    fn to_pos(
        &self,
        (_a, b): (usize, U),
        index: usize,
        &mut (ref mut head, ref mut tail): &mut (usize, V)
    ) {
        let subspace: T = Construct::new();
        let count = subspace.count(b);
        let x = index / count;
        *head = x;
        subspace.to_pos(b, index - x * count, tail)
    }
}

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

    #[test]
    fn features() {
        is_complete::<Dimension<Data>, usize, usize, usize>();
        does_count::<Dimension<Subspace<Pair<Data>>>, (usize, usize)>();
        does_count::<Dimension<Of<Pair<Data>>>, usize>();
    }

    #[test]
    fn subspace() {
        type D2 = Dimension<Subspace<Dimension<Data>>>;
        type D3 = Dimension<Subspace<D2>>;

        let x: D3 = Construct::new();
        let dim = (3, (3, 3));
        assert_eq!(x.count(dim), 27);
        let pos = (1, (0, 2));
        let index = x.to_index(dim, pos);
        assert_eq!(index, 11);
        let mut new_pos = pos;
        x.to_pos(dim, index, &mut new_pos);
        assert_eq!(pos, new_pos);
    }
}
<commit_msg>Completed `Dimension`<commit_after>use std::marker::PhantomData;

use Construct;
use Data;
use Count;
use Of;
use Subspace;
use ToIndex;
use ToPos;

/// Dimension is natural number, position is the same as index.
pub struct Dimension<T>(PhantomData<T>);

impl<T> Construct for Dimension<T> {
    fn new() -> Dimension<T> { Dimension(PhantomData) }
}

impl Count<usize> for Dimension<Data> {
    fn count(&self, dim: usize) -> usize { dim }
}

impl<T, U> Count<(usize, U)> for Dimension<Subspace<T>>
    where
        T: Construct + Count<U>
{
    fn count(&self, (a, b): (usize, U)) -> usize {
        let subspace: T = Construct::new();
        a * subspace.count(b)
    }
}

impl<T, U> Count<U> for Dimension<Of<T>>
    where
        T: Construct + Count<U>
{
    fn count(&self, dim: U) -> usize {
        let of: T = Construct::new();
        of.count(dim)
    }
}

impl ToIndex<usize, usize> for Dimension<Data> {
    fn to_index(&self, _dim: usize, pos: usize) -> usize { pos }
}

impl<T, U: Copy, V> ToIndex<(usize, U), (usize, V)> for Dimension<Subspace<T>>
    where
        T: Construct + Count<U> + ToIndex<U, V>
{
    fn to_index(&self, (_a, b): (usize, U), (pa, pb): (usize, V)) -> usize {
        let subspace: T = Construct::new();
        let count = subspace.count(b);
        pa * count + subspace.to_index(b, pb)
    }
}

impl<T, U, V> ToIndex<U, V> for Dimension<Of<T>>
    where
        T: Construct + ToIndex<U, V>
{
    fn to_index(&self, dim: U, pos: V) -> usize {
        let of: T = Construct::new();
        of.to_index(dim, pos)
    }
}

impl ToPos<usize, usize> for Dimension<Data> {
    fn to_pos(&self, _dim: usize, index: usize, pos: &mut usize) {
        *pos = index;
    }
}

impl<T, U: Copy, V>
ToPos<(usize, U), (usize, V)> for Dimension<Subspace<T>>
    where
        T: Construct + Count<U> + ToPos<U, V>
{
    fn to_pos(
        &self,
        (_a, b): (usize, U),
        index: usize,
        &mut (ref mut head, ref mut tail): &mut (usize, V)
    ) {
        let subspace: T = Construct::new();
        let count = subspace.count(b);
        let x = index / count;
        *head = x;
        subspace.to_pos(b, index - x * count, tail)
    }
}

impl<T, U, V> ToPos<U, V> for Dimension<Of<T>>
    where
        T: Construct + ToPos<U, V>
{
    fn to_pos(&self, dim: U, index: usize, pos: &mut V) {
        let of: T = Construct::new();
        of.to_pos(dim, index, pos);
    }
}

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

    #[test]
    fn features() {
        is_complete::<Dimension<Data>, usize, usize, usize>();
        is_complete::<Dimension<Subspace<Pair<Data>>>,
            (usize, usize), // dimension
            (usize, (usize, usize)), // read position
            (usize, (usize, usize)) // write position
        >();
        is_complete::<Dimension<Of<Pair<Data>>>,
            usize,
            (usize, usize),
            (usize, usize)
        >();
    }

    #[test]
    fn subspace() {
        type D2 = Dimension<Subspace<Dimension<Data>>>;
        type D3 = Dimension<Subspace<D2>>;

        let x: D3 = Construct::new();
        let dim = (3, (3, 3));
        assert_eq!(x.count(dim), 27);
        let pos = (1, (0, 2));
        let index = x.to_index(dim, pos);
        assert_eq!(index, 11);
        let mut new_pos = pos;
        x.to_pos(dim, index, &mut new_pos);
        assert_eq!(pos, new_pos);
    }
}
<|endoftext|>