<commit_before>//   Copyright 2015 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate atom;
extern crate time;

use std::sync::atomic::{AtomicUsize};
use std::thread;
use std::mem;
use std::ops::Deref;
use std::sync::atomic::Ordering;

use atom::*;
use time::precise_time_s;

pub use select::{Select, SelectMap};
pub use barrier::Barrier;
mod select;
mod barrier;

/// Drop rules
/// This may be freed iff state is Signald | Dropped
/// and Waiting is Dropped
struct Inner {
    state: AtomicUsize,
    waiting: Atom<Box<Waiting>>
}

// TODO 64bit sized, probably does not matter now
const PULSED: usize = 0x8000_0000;
const TX_DROP: usize = 0x4000_0000;
const TX_FLAGS: usize = PULSED | TX_DROP;
const REF_COUNT: usize = !TX_FLAGS;

struct Waiting {
    next: Option<Box<Waiting>>,
    wake: Wake
}

impl GetNextMut for Box<Waiting> {
    type NextPtr = Option<Box<Waiting>>;

    fn get_next(&mut self) -> &mut Option<Box<Waiting>> {
        &mut self.next
    }
}

enum Wake {
    Thread(thread::Thread),
    Select(select::Handle),
    Barrier(barrier::Handle)
}

impl Waiting {
    fn wake(s: Box<Self>, id: usize) {
        let mut next = Some(s);
        while let Some(s) = next {
            // There must be a better way to do this...
            let s = *s;
            let Waiting { next: n, wake } = s;
            next = n;
            match wake {
                Wake::Thread(thread) => thread.unpark(),
                Wake::Select(select) => {
                    let trigger = {
                        let mut guard = select.0.lock().unwrap();
                        guard.ready.push(id);
                        guard.trigger.take()
                    };
                    trigger.map(|x| x.pulse());
                }
                Wake::Barrier(barrier) => {
                    let count = barrier.0.count.fetch_sub(1, Ordering::Relaxed);
                    if count == 1 {
                        let mut guard = barrier.0.trigger.lock().unwrap();
                        if let Some(t) = guard.take() {
                            t.pulse();
                        }
                    }
                }
            }
        }
    }

    fn id(&self) -> usize {
        unsafe { mem::transmute(self) }
    }

    fn thread() -> Box<Waiting> {
        Box::new(Waiting {
            next: None,
            wake: Wake::Thread(thread::current())
        })
    }

    fn select(handle: select::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Select(handle)
        })
    }

    fn barrier(handle: barrier::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Barrier(handle)
        })
    }
}

unsafe impl Send for Pulse {}

/// A `Pulse` is represents an unfired signal. It is the tx side of Signal
/// A `Pulse` can only purpose it to be fired, and then it will be moved
/// as to never allow it to fire again. `Dropping` a pulse will `pulse`
/// The signal, but the signal will enter an error state.
pub struct Pulse {
    inner: *mut Inner
}

fn delete_inner(state: usize, inner: *mut Inner) {
    if state & REF_COUNT == 1 {
        let inner: Box<Inner> = unsafe {
            mem::transmute(inner)
        };
        drop(inner);
    }
}

impl Drop for Pulse {
    fn drop(&mut self) {
        self.set(TX_DROP);
        self.wake();
        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner)
    }
}

impl Pulse {
    /// Create a Pulse from a usize. This is naturally unsafe.
    pub unsafe fn cast_from_usize(ptr: usize) -> Pulse {
        Pulse {
            inner: mem::transmute(ptr)
        }
    }

    /// Convert a trigger to a `usize`, This is unsafe
    /// and it will kill your kittens if you are not careful
    pub unsafe fn cast_to_usize(self) -> usize {
        let us = mem::transmute(self.inner);
        mem::forget(self);
        us
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    fn set(&self, state: usize) -> usize {
        self.inner().state.fetch_or(state, Ordering::Relaxed)
    }

    fn wake(&self) {
        let id = unsafe { mem::transmute(self.inner) };
        match self.inner().waiting.take() {
            None => (),
            Some(v) => Waiting::wake(v, id)
        }
    }

    /// Pulse the `pulse` which will transition the `Signal` out from pending
    /// to ready. This moves the pulse so that it can only be fired once.
    pub fn pulse(self) {
        self.set(PULSED);
        self.wake();

        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner);
        unsafe { mem::forget(self) }
    }
}

unsafe impl Send for Signal {}

/// A `Signal` represents listens for a `pulse` to occur in the system. A
/// `Signal` has one of three states. Pending, Pulsed, or Errored. Pending
/// means the pulse has not fired, but still exists. Pulsed meaning the
/// pulse has fired, and no longer exists. Errored means the pulse was dropped
/// without firing. This normally means a programming error of some sort.
pub struct Signal {
    inner: *mut Inner
}

impl Clone for Signal {
    fn clone(&self) -> Signal {
        self.inner().state.fetch_add(1, Ordering::Relaxed);
        Signal { inner: self.inner }
    }
}

impl Drop for Signal {
    fn drop(&mut self) {
        let flag = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(flag, self.inner);
    }
}

impl Signal {
    /// Create a Signal and a Pulse that are associated.
    pub fn new() -> (Signal, Pulse) {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(2),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        (Signal {
            inner: inner
         },
         Pulse {
            inner: inner,
        })
    }

    #[inline]
    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    /// Read out the state of the Signal
    #[inline]
    fn state(&self) -> usize {
        self.inner().state.load(Ordering::Relaxed)
    }

    /// Check to see if the signal is pending. A signal
    #[inline]
    pub fn is_pending(&self) -> bool {
        self.state() & TX_FLAGS == 0
    }

    // Check to see if the pulse is pending or not
    fn in_use(&self) -> bool {
        let state = self.state();
        (state & REF_COUNT) != 1 || (state & TX_FLAGS) == 0
    }

    /// Add a waiter to a waitlist
    fn add_to_waitlist(&self, waiter: Box<Waiting>) -> usize {
        let id = waiter.id();

        self.inner().waiting.replace_and_set_next(waiter);

        // if armed fire now
        if !self.is_pending() {
            if let Some(t) = self.inner().waiting.take() {
                Waiting::wake(t, self.id());
            }
        }
        id
    }

    /// Remove Waiter with `id` from the waitlist
    fn remove_from_waitlist(&self, id: usize) {
        let mut wl = self.inner().waiting.take();
        while let Some(mut w) = wl {
            let next = w.next.take();
            if w.id() != id {
                self.add_to_waitlist(w);
            }
            wl = next;
        }
    }

    /// Arm a pulse to wake
    fn arm(self, waiter: Box<Waiting>) -> ArmedSignal {
        let id = self.add_to_waitlist(waiter);
        ArmedSignal {
            id: id,
            pulse: self
        }
    }

    /// This is a unique id that can be used to identify the signal from others
    /// See `Select` for how this api is useful.
    pub fn id(&self) -> usize {
        unsafe { mem::transmute_copy(&self.inner) }
    }

    /// iff the `Signal` has been Pulsed, or Errored out and this is the only
    /// cloned copy of the Signal in the system. You may `recycle` the signal.
    /// This will create a new `Pulse` that is associated with the `Siganl`
    ///
    /// This api was added for optimizations reasons, as it avoids allocations
    /// of a new signal.
    pub fn recycle(&self) -> Option<Pulse> {
        if self.in_use() {
            None
        } else {
            self.inner().state.store(2, Ordering::Relaxed);
            Some(Pulse{
                inner: self.inner,
            })
        }
    }

    // The slow inner path if the pending check fails
    // this allows the fast already set pending check to be inlined
    // and the slower loop based check (here) to run now
    fn wait_slow(&self) -> Result<(), WaitError> {
        loop {
            let id = self.add_to_waitlist(Waiting::thread());
            if self.is_pending() {
                thread::park();
            }
            self.remove_from_waitlist(id);

            if !self.is_pending() {
                let state = self.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(WaitError::Dropped)
                };
            }
        }
    }

    /// Block the current thread until a `pulse` is ready.
    /// This will block indefinably if the pulse never fires.
    #[inline]
    pub fn wait(&self) -> Result<(), WaitError> {
        if !self.is_pending() {
            let state = self.state();
            return if (state & PULSED) == PULSED {
                Ok(())
            } else {
                Err(WaitError::Dropped)
            };
        } else {
            self.wait_slow()
        }
    }

    /// Block until either the pulse is sent, or the timeout is reached
    pub fn wait_timeout_ms(&self, ms: u32) -> Result<(), TimeoutError> {
        let mut now = (precise_time_s() * 1000.) as u64;
        let end = now + ms as u64;

        loop {
            let id = self.add_to_waitlist(Waiting::thread());
            if self.is_pending() {
                now = (precise_time_s() * 1000.) as u64;
                if now > end {
                    return Err(TimeoutError::Timeout)
                }
                thread::park_timeout_ms((end - now) as u32);
            }
            self.remove_from_waitlist(id);

            if !self.is_pending() {
                let state = self.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(TimeoutError::Error(WaitError::Dropped))
                };
            }
        }
    }
}

impl IntoRawPtr for Pulse {
    unsafe fn into_raw(self) -> *mut () {
        let inner = self.inner;
        mem::forget(self);
        mem::transmute(inner)
    }
}

impl FromRawPtr for Pulse {
    unsafe fn from_raw(ptr: *mut ()) -> Pulse {
        Pulse { inner: mem::transmute(ptr) }
    }
}

/// Represents the possible errors that can occur on a `Signal`
#[derive(Debug, PartialEq, Eq)]
pub enum WaitError {
    /// The `Pulse` was dropped before it could `Pulse`
    Dropped
}

/// Represents the possible errors from a wait timeout
#[derive(Debug, PartialEq, Eq)]
pub enum TimeoutError {
    /// A `WaitError` has occurred
    Error(WaitError),
    /// The `Signal` timed-out before a `Pulse` was observed.
    Timeout
}

struct ArmedSignal {
    pulse: Signal,
    id: usize
}

impl Deref for ArmedSignal {
    type Target = Signal;

    fn deref(&self) -> &Signal { &self.pulse }
}

impl ArmedSignal {
    fn disarm(self) -> Signal {
        self.remove_from_waitlist(self.id);
        self.pulse
    }
}

/// allows an object to assert a wait signal
pub trait Signals {
    /// Get a signal from a object
    fn signal(&self) -> Signal;

    /// Block the current thread until the object
    /// assets a pulse.
    fn wait(&self) -> Result<(), WaitError> {
        let signal = self.signal();
        signal.wait()
    }

    /// Block the current thread until the object
    /// assets a pulse. Or until the timeout has been asserted.
    fn wait_timeout_ms(&self, ms: u32) -> Result<(), TimeoutError> {
        let signal = self.signal();
        signal.wait_timeout_ms(ms)
    }
}
<commit_msg>added Debug<commit_after>//   Copyright 2015 Colin Sherratt
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.

extern crate atom;
extern crate time;

use std::sync::atomic::{AtomicUsize};
use std::thread;
use std::mem;
use std::fmt;
use std::ops::Deref;
use std::sync::atomic::Ordering;

use atom::*;
use time::precise_time_s;

pub use select::{Select, SelectMap};
pub use barrier::Barrier;
mod select;
mod barrier;

/// Drop rules
/// This may be freed iff state is Signald | Dropped
/// and Waiting is Dropped
struct Inner {
    state: AtomicUsize,
    waiting: Atom<Box<Waiting>>
}

// TODO 64bit sized, probably does not matter now
const PULSED: usize = 0x8000_0000;
const TX_DROP: usize = 0x4000_0000;
const TX_FLAGS: usize = PULSED | TX_DROP;
const REF_COUNT: usize = !TX_FLAGS;

struct Waiting {
    next: Option<Box<Waiting>>,
    wake: Wake
}

impl GetNextMut for Box<Waiting> {
    type NextPtr = Option<Box<Waiting>>;

    fn get_next(&mut self) -> &mut Option<Box<Waiting>> {
        &mut self.next
    }
}

enum Wake {
    Thread(thread::Thread),
    Select(select::Handle),
    Barrier(barrier::Handle)
}

impl Waiting {
    fn wake(s: Box<Self>, id: usize) {
        let mut next = Some(s);
        while let Some(s) = next {
            // There must be a better way to do this...
            let s = *s;
            let Waiting { next: n, wake } = s;
            next = n;
            match wake {
                Wake::Thread(thread) => thread.unpark(),
                Wake::Select(select) => {
                    let trigger = {
                        let mut guard = select.0.lock().unwrap();
                        guard.ready.push(id);
                        guard.trigger.take()
                    };
                    trigger.map(|x| x.pulse());
                }
                Wake::Barrier(barrier) => {
                    let count = barrier.0.count.fetch_sub(1, Ordering::Relaxed);
                    if count == 1 {
                        let mut guard = barrier.0.trigger.lock().unwrap();
                        if let Some(t) = guard.take() {
                            t.pulse();
                        }
                    }
                }
            }
        }
    }

    fn id(&self) -> usize {
        unsafe { mem::transmute(self) }
    }

    fn thread() -> Box<Waiting> {
        Box::new(Waiting {
            next: None,
            wake: Wake::Thread(thread::current())
        })
    }

    fn select(handle: select::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Select(handle)
        })
    }

    fn barrier(handle: barrier::Handle) ->Box<Waiting> {
        Box::new(Waiting{
            next: None,
            wake: Wake::Barrier(handle)
        })
    }
}

unsafe impl Send for Pulse {}

/// A `Pulse` is represents an unfired signal. It is the tx side of Signal
/// A `Pulse` can only purpose it to be fired, and then it will be moved
/// as to never allow it to fire again. `Dropping` a pulse will `pulse`
/// The signal, but the signal will enter an error state.
pub struct Pulse {
    inner: *mut Inner
}

impl fmt::Debug for Pulse {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let id: usize = unsafe { mem::transmute(self.inner) };
        write!(f, "Pulse({:?})", id)
    }
}

fn delete_inner(state: usize, inner: *mut Inner) {
    if state & REF_COUNT == 1 {
        let inner: Box<Inner> = unsafe {
            mem::transmute(inner)
        };
        drop(inner);
    }
}

impl Drop for Pulse {
    fn drop(&mut self) {
        self.set(TX_DROP);
        self.wake();
        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner)
    }
}

impl Pulse {
    /// Create a Pulse from a usize. This is naturally unsafe.
    pub unsafe fn cast_from_usize(ptr: usize) -> Pulse {
        Pulse {
            inner: mem::transmute(ptr)
        }
    }

    /// Convert a trigger to a `usize`, This is unsafe
    /// and it will kill your kittens if you are not careful
    pub unsafe fn cast_to_usize(self) -> usize {
        let us = mem::transmute(self.inner);
        mem::forget(self);
        us
    }

    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    fn set(&self, state: usize) -> usize {
        self.inner().state.fetch_or(state, Ordering::Relaxed)
    }

    fn wake(&self) {
        let id = unsafe { mem::transmute(self.inner) };
        match self.inner().waiting.take() {
            None => (),
            Some(v) => Waiting::wake(v, id)
        }
    }

    /// Pulse the `pulse` which will transition the `Signal` out from pending
    /// to ready. This moves the pulse so that it can only be fired once.
    pub fn pulse(self) {
        self.set(PULSED);
        self.wake();

        let state = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(state, self.inner);
        unsafe { mem::forget(self) }
    }
}

unsafe impl Send for Signal {}

/// A `Signal` represents listens for a `pulse` to occur in the system. A
/// `Signal` has one of three states. Pending, Pulsed, or Errored. Pending
/// means the pulse has not fired, but still exists. Pulsed meaning the
/// pulse has fired, and no longer exists. Errored means the pulse was dropped
/// without firing. This normally means a programming error of some sort.
pub struct Signal {
    inner: *mut Inner
}

impl fmt::Debug for Signal {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(f, "Signal(id={:?}, pending={:?})", self.id(), self.is_pending())
    }
}

impl Clone for Signal {
    fn clone(&self) -> Signal {
        self.inner().state.fetch_add(1, Ordering::Relaxed);
        Signal { inner: self.inner }
    }
}

impl Drop for Signal {
    fn drop(&mut self) {
        let flag = self.inner().state.fetch_sub(1, Ordering::Relaxed);
        delete_inner(flag, self.inner);
    }
}

impl Signal {
    /// Create a Signal and a Pulse that are associated.
    pub fn new() -> (Signal, Pulse) {
        let inner = Box::new(Inner {
            state: AtomicUsize::new(2),
            waiting: Atom::empty()
        });

        let inner = unsafe {mem::transmute(inner)};

        (Signal {
            inner: inner
         },
         Pulse {
            inner: inner,
        })
    }

    #[inline]
    fn inner(&self) -> &Inner {
        unsafe { mem::transmute(self.inner) }
    }

    /// Read out the state of the Signal
    #[inline]
    fn state(&self) -> usize {
        self.inner().state.load(Ordering::Relaxed)
    }

    /// Check to see if the signal is pending. A signal
    #[inline]
    pub fn is_pending(&self) -> bool {
        self.state() & TX_FLAGS == 0
    }

    // Check to see if the pulse is pending or not
    fn in_use(&self) -> bool {
        let state = self.state();
        (state & REF_COUNT) != 1 || (state & TX_FLAGS) == 0
    }

    /// Add a waiter to a waitlist
    fn add_to_waitlist(&self, waiter: Box<Waiting>) -> usize {
        let id = waiter.id();

        self.inner().waiting.replace_and_set_next(waiter);

        // if armed fire now
        if !self.is_pending() {
            if let Some(t) = self.inner().waiting.take() {
                Waiting::wake(t, self.id());
            }
        }
        id
    }

    /// Remove Waiter with `id` from the waitlist
    fn remove_from_waitlist(&self, id: usize) {
        let mut wl = self.inner().waiting.take();
        while let Some(mut w) = wl {
            let next = w.next.take();
            if w.id() != id {
                self.add_to_waitlist(w);
            }
            wl = next;
        }
    }

    /// Arm a pulse to wake
    fn arm(self, waiter: Box<Waiting>) -> ArmedSignal {
        let id = self.add_to_waitlist(waiter);
        ArmedSignal {
            id: id,
            pulse: self
        }
    }

    /// This is a unique id that can be used to identify the signal from others
    /// See `Select` for how this api is useful.
    pub fn id(&self) -> usize {
        unsafe { mem::transmute_copy(&self.inner) }
    }

    /// iff the `Signal` has been Pulsed, or Errored out and this is the only
    /// cloned copy of the Signal in the system. You may `recycle` the signal.
    /// This will create a new `Pulse` that is associated with the `Siganl`
    ///
    /// This api was added for optimizations reasons, as it avoids allocations
    /// of a new signal.
    pub fn recycle(&self) -> Option<Pulse> {
        if self.in_use() {
            None
        } else {
            self.inner().state.store(2, Ordering::Relaxed);
            Some(Pulse{
                inner: self.inner,
            })
        }
    }

    // The slow inner path if the pending check fails
    // this allows the fast already set pending check to be inlined
    // and the slower loop based check (here) to run now
    fn wait_slow(&self) -> Result<(), WaitError> {
        loop {
            let id = self.add_to_waitlist(Waiting::thread());
            if self.is_pending() {
                thread::park();
            }
            self.remove_from_waitlist(id);

            if !self.is_pending() {
                let state = self.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(WaitError::Dropped)
                };
            }
        }
    }

    /// Block the current thread until a `pulse` is ready.
    /// This will block indefinably if the pulse never fires.
    #[inline]
    pub fn wait(&self) -> Result<(), WaitError> {
        if !self.is_pending() {
            let state = self.state();
            return if (state & PULSED) == PULSED {
                Ok(())
            } else {
                Err(WaitError::Dropped)
            };
        } else {
            self.wait_slow()
        }
    }

    /// Block until either the pulse is sent, or the timeout is reached
    pub fn wait_timeout_ms(&self, ms: u32) -> Result<(), TimeoutError> {
        let mut now = (precise_time_s() * 1000.) as u64;
        let end = now + ms as u64;

        loop {
            let id = self.add_to_waitlist(Waiting::thread());
            if self.is_pending() {
                now = (precise_time_s() * 1000.) as u64;
                if now > end {
                    return Err(TimeoutError::Timeout)
                }
                thread::park_timeout_ms((end - now) as u32);
            }
            self.remove_from_waitlist(id);

            if !self.is_pending() {
                let state = self.state();
                return if (state & PULSED) == PULSED {
                    Ok(())
                } else {
                    Err(TimeoutError::Error(WaitError::Dropped))
                };
            }
        }
    }
}

impl IntoRawPtr for Pulse {
    unsafe fn into_raw(self) -> *mut () {
        let inner = self.inner;
        mem::forget(self);
        mem::transmute(inner)
    }
}

impl FromRawPtr for Pulse {
    unsafe fn from_raw(ptr: *mut ()) -> Pulse {
        Pulse { inner: mem::transmute(ptr) }
    }
}

/// Represents the possible errors that can occur on a `Signal`
#[derive(Debug, PartialEq, Eq)]
pub enum WaitError {
    /// The `Pulse` was dropped before it could `Pulse`
    Dropped
}

/// Represents the possible errors from a wait timeout
#[derive(Debug, PartialEq, Eq)]
pub enum TimeoutError {
    /// A `WaitError` has occurred
    Error(WaitError),
    /// The `Signal` timed-out before a `Pulse` was observed.
    Timeout
}

struct ArmedSignal {
    pulse: Signal,
    id: usize
}

impl Deref for ArmedSignal {
    type Target = Signal;

    fn deref(&self) -> &Signal { &self.pulse }
}

impl ArmedSignal {
    fn disarm(self) -> Signal {
        self.remove_from_waitlist(self.id);
        self.pulse
    }
}

/// allows an object to assert a wait signal
pub trait Signals {
    /// Get a signal from a object
    fn signal(&self) -> Signal;

    /// Block the current thread until the object
    /// assets a pulse.
    fn wait(&self) -> Result<(), WaitError> {
        let signal = self.signal();
        signal.wait()
    }

    /// Block the current thread until the object
    /// assets a pulse. Or until the timeout has been asserted.
    fn wait_timeout_ms(&self, ms: u32) -> Result<(), TimeoutError> {
        let signal = self.signal();
        signal.wait_timeout_ms(ms)
    }
}
<|endoftext|>


<commit_before>mod error;
pub mod modules;
pub mod powerline;
pub mod terminal;
pub mod theme;
pub(crate) mod utils;

pub type R<T> = Result<T, error::Error>;
pub use error::Error;
pub use powerline::{Powerline, Segment};
<commit_msg>make cargo doc happy<commit_after>mod error;
pub mod modules;
pub mod powerline;
pub mod terminal;
pub mod theme;
pub(crate) mod utils;

pub type R<T> = Result<T, error::Error>;
pub use crate::powerline::{Powerline, Segment};
pub use error::Error;
<|endoftext|>


<commit_before>// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

/*!
A macro for declaring lazily evaluated statics.

Using this macro, it is possible to have `static`s that require code to be
executed at runtime in order to be initialized.
This includes anything requiring heap allocations, like vectors or hash maps,
as well as anything that requires function calls to be computed.

# Syntax

```ignore
lazy_static! {
    [pub] static ref NAME_1: TYPE_1 = EXPR_1;
    [pub] static ref NAME_2: TYPE_2 = EXPR_2;
    ...
    [pub] static ref NAME_N: TYPE_N = EXPR_N;
}
```

Attributes (including doc comments) are supported as well:

```rust
# #[macro_use]
# extern crate lazy_static;
# fn main() {
lazy_static! {
    /// This is an example for using doc comment attributes
    static ref EXAMPLE: u8 = 42;
}
# }
```

# Semantics

For a given `static ref NAME: TYPE = EXPR;`, the macro generates a unique type that
implements `Deref<TYPE>` and stores it in a static with name `NAME`. (Attributes end up
attaching to this type.)

On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs
can return a reference to the same object. Note that this can lead to deadlocks
if you have multiple lazy statics that depend on each other in their initialization.

Apart from the lazy initialization, the resulting "static ref" variables
have generally the same properties as regular "static" variables:

- Any type in them needs to fulfill the `Sync` trait.
- If the type has a destructor, then it will not run when the process exits.

# Example

Using the macro:

```rust
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
    static ref NUMBER: u32 = times_two(21);
}

fn times_two(n: u32) -> u32 { n * 2 }

fn main() {
    println!("The map has {} entries.", *COUNT);
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
    println!("A expensive calculation on a static results in: {}.", *NUMBER);
}
```

# Implementation details

The `Deref` implementation uses a hidden static variable that is guarded by an atomic check on each access.

# Cargo features

This crate provides two cargo features:

- `nightly`: This uses unstable language features only available on the nightly release channel for a more optimal implementation. In practice this currently means avoiding a heap allocation per static. This feature might get deprecated at a later point once all relevant optimizations are usable from stable.
- `spin_no_std` (implies `nightly`): This allows using this crate in a no-std environment, by depending on the standalone `spin` crate.

Both features depend on unstable language features, which means
no guarantees can be made about them in regard to SemVer stability.

*/

#![cfg_attr(feature="spin_no_std", feature(const_fn))]
#![cfg_attr(feature="nightly", feature(unreachable))]

#![doc(html_root_url = "https://docs.rs/lazy_static/1.0.1")]
#![no_std]

#[cfg(not(feature="nightly"))]
#[doc(hidden)]
pub mod lazy;

#[cfg(all(feature="nightly", not(feature="spin_no_std")))]
#[path="nightly_lazy.rs"]
#[doc(hidden)]
pub mod lazy;

#[cfg(all(feature="nightly", feature="spin_no_std"))]
#[path="core_lazy.rs"]
#[doc(hidden)]
pub mod lazy;

#[doc(hidden)]
pub use core::ops::Deref as __Deref;

#[macro_export]
#[doc(hidden)]
macro_rules! __lazy_static_internal {
    // optional visibility restrictions are wrapped in `()` to allow for
    // explicitly passing otherwise implicit information about private items
    ($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        __lazy_static_internal!(@MAKE TY, $(#[$attr])*, ($($vis)*), $N);
        __lazy_static_internal!(@TAIL, $N : $T = $e);
        lazy_static!($($t)*);
    };
    (@TAIL, $N:ident : $T:ty = $e:expr) => {
        impl $crate::__Deref for $N {
            type Target = $T;
            #[allow(unsafe_code)]
            fn deref(&self) -> &$T {
                unsafe {
                    #[inline(always)]
                    fn __static_ref_initialize() -> $T { $e }

                    #[inline(always)]
                    unsafe fn __stability() -> &'static $T {
                        __lazy_static_create!(LAZY, $T);
                        LAZY.get(__static_ref_initialize)
                    }
                    __stability()
                }
            }
        }
        impl $crate::LazyStatic for $N {
            fn initialize(lazy: &Self) {
                let _ = &**lazy;
            }
        }
    };
    // `vis` is wrapped in `()` to prevent parsing ambiguity
    (@MAKE TY, $(#[$attr:meta])*, ($($vis:tt)*), $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        $(#[$attr])*
        $($vis)* struct $N {__private_field: ()}
        #[doc(hidden)]
        $($vis)* static $N: $N = $N {__private_field: ()};
    };
    () => ()
}

#[macro_export]
macro_rules! lazy_static {
    ($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        // use `()` to explicitly forward the information about private items
        __lazy_static_internal!($(#[$attr])* () static ref $N : $T = $e; $($t)*);
    };
    ($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        __lazy_static_internal!($(#[$attr])* (pub) static ref $N : $T = $e; $($t)*);
    };
    ($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        __lazy_static_internal!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $e; $($t)*);
    };
    () => ()
}

/// Support trait for enabling a few common operation on lazy static values.
///
/// This is implemented by each defined lazy static, and
/// used by the free functions in this crate.
pub trait LazyStatic {
    #[doc(hidden)]
    fn initialize(lazy: &Self);
}

/// Takes a shared reference to a lazy static and initializes
/// it if it has not been already.
///
/// This can be used to control the initialization point of a lazy static.
///
/// Example:
///
/// ```rust
/// #[macro_use]
/// extern crate lazy_static;
///
/// lazy_static! {
///     static ref BUFFER: Vec<u8> = (0..65537).collect();
/// }
///
/// fn main() {
///     lazy_static::initialize(&BUFFER);
///
///     // ...
///     work_with_initialized_data(&BUFFER);
/// }
/// # fn work_with_initialized_data(_: &[u8]) {}
/// ```
pub fn initialize<T: LazyStatic>(lazy: &T) {
    LazyStatic::initialize(lazy);
}
<commit_msg>Use local_inner_macros to resolve all helper macros within $crate<commit_after>// Copyright 2016 lazy-static.rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

/*!
A macro for declaring lazily evaluated statics.

Using this macro, it is possible to have `static`s that require code to be
executed at runtime in order to be initialized.
This includes anything requiring heap allocations, like vectors or hash maps,
as well as anything that requires function calls to be computed.

# Syntax

```ignore
lazy_static! {
    [pub] static ref NAME_1: TYPE_1 = EXPR_1;
    [pub] static ref NAME_2: TYPE_2 = EXPR_2;
    ...
    [pub] static ref NAME_N: TYPE_N = EXPR_N;
}
```

Attributes (including doc comments) are supported as well:

```rust
# #[macro_use]
# extern crate lazy_static;
# fn main() {
lazy_static! {
    /// This is an example for using doc comment attributes
    static ref EXAMPLE: u8 = 42;
}
# }
```

# Semantics

For a given `static ref NAME: TYPE = EXPR;`, the macro generates a unique type that
implements `Deref<TYPE>` and stores it in a static with name `NAME`. (Attributes end up
attaching to this type.)

On first deref, `EXPR` gets evaluated and stored internally, such that all further derefs
can return a reference to the same object. Note that this can lead to deadlocks
if you have multiple lazy statics that depend on each other in their initialization.

Apart from the lazy initialization, the resulting "static ref" variables
have generally the same properties as regular "static" variables:

- Any type in them needs to fulfill the `Sync` trait.
- If the type has a destructor, then it will not run when the process exits.

# Example

Using the macro:

```rust
#[macro_use]
extern crate lazy_static;

use std::collections::HashMap;

lazy_static! {
    static ref HASHMAP: HashMap<u32, &'static str> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        m
    };
    static ref COUNT: usize = HASHMAP.len();
    static ref NUMBER: u32 = times_two(21);
}

fn times_two(n: u32) -> u32 { n * 2 }

fn main() {
    println!("The map has {} entries.", *COUNT);
    println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap());
    println!("A expensive calculation on a static results in: {}.", *NUMBER);
}
```

# Implementation details

The `Deref` implementation uses a hidden static variable that is guarded by an atomic check on each access.

# Cargo features

This crate provides two cargo features:

- `nightly`: This uses unstable language features only available on the nightly release channel for a more optimal implementation. In practice this currently means avoiding a heap allocation per static. This feature might get deprecated at a later point once all relevant optimizations are usable from stable.
- `spin_no_std` (implies `nightly`): This allows using this crate in a no-std environment, by depending on the standalone `spin` crate.

Both features depend on unstable language features, which means
no guarantees can be made about them in regard to SemVer stability.

*/

#![cfg_attr(feature="spin_no_std", feature(const_fn))]
#![cfg_attr(feature="nightly", feature(unreachable))]

#![doc(html_root_url = "https://docs.rs/lazy_static/1.0.1")]
#![no_std]

#[cfg(not(feature="nightly"))]
#[doc(hidden)]
pub mod lazy;

#[cfg(all(feature="nightly", not(feature="spin_no_std")))]
#[path="nightly_lazy.rs"]
#[doc(hidden)]
pub mod lazy;

#[cfg(all(feature="nightly", feature="spin_no_std"))]
#[path="core_lazy.rs"]
#[doc(hidden)]
pub mod lazy;

#[doc(hidden)]
pub use core::ops::Deref as __Deref;

#[macro_export(local_inner_macros)]
#[doc(hidden)]
macro_rules! __lazy_static_internal {
    // optional visibility restrictions are wrapped in `()` to allow for
    // explicitly passing otherwise implicit information about private items
    ($(#[$attr:meta])* ($($vis:tt)*) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        __lazy_static_internal!(@MAKE TY, $(#[$attr])*, ($($vis)*), $N);
        __lazy_static_internal!(@TAIL, $N : $T = $e);
        lazy_static!($($t)*);
    };
    (@TAIL, $N:ident : $T:ty = $e:expr) => {
        impl $crate::__Deref for $N {
            type Target = $T;
            #[allow(unsafe_code)]
            fn deref(&self) -> &$T {
                unsafe {
                    #[inline(always)]
                    fn __static_ref_initialize() -> $T { $e }

                    #[inline(always)]
                    unsafe fn __stability() -> &'static $T {
                        __lazy_static_create!(LAZY, $T);
                        LAZY.get(__static_ref_initialize)
                    }
                    __stability()
                }
            }
        }
        impl $crate::LazyStatic for $N {
            fn initialize(lazy: &Self) {
                let _ = &**lazy;
            }
        }
    };
    // `vis` is wrapped in `()` to prevent parsing ambiguity
    (@MAKE TY, $(#[$attr:meta])*, ($($vis:tt)*), $N:ident) => {
        #[allow(missing_copy_implementations)]
        #[allow(non_camel_case_types)]
        #[allow(dead_code)]
        $(#[$attr])*
        $($vis)* struct $N {__private_field: ()}
        #[doc(hidden)]
        $($vis)* static $N: $N = $N {__private_field: ()};
    };
    () => ()
}

#[macro_export(local_inner_macros)]
macro_rules! lazy_static {
    ($(#[$attr:meta])* static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        // use `()` to explicitly forward the information about private items
        __lazy_static_internal!($(#[$attr])* () static ref $N : $T = $e; $($t)*);
    };
    ($(#[$attr:meta])* pub static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        __lazy_static_internal!($(#[$attr])* (pub) static ref $N : $T = $e; $($t)*);
    };
    ($(#[$attr:meta])* pub ($($vis:tt)+) static ref $N:ident : $T:ty = $e:expr; $($t:tt)*) => {
        __lazy_static_internal!($(#[$attr])* (pub ($($vis)+)) static ref $N : $T = $e; $($t)*);
    };
    () => ()
}

/// Support trait for enabling a few common operation on lazy static values.
///
/// This is implemented by each defined lazy static, and
/// used by the free functions in this crate.
pub trait LazyStatic {
    #[doc(hidden)]
    fn initialize(lazy: &Self);
}

/// Takes a shared reference to a lazy static and initializes
/// it if it has not been already.
///
/// This can be used to control the initialization point of a lazy static.
///
/// Example:
///
/// ```rust
/// #[macro_use]
/// extern crate lazy_static;
///
/// lazy_static! {
///     static ref BUFFER: Vec<u8> = (0..65537).collect();
/// }
///
/// fn main() {
///     lazy_static::initialize(&BUFFER);
///
///     // ...
///     work_with_initialized_data(&BUFFER);
/// }
/// # fn work_with_initialized_data(_: &[u8]) {}
/// ```
pub fn initialize<T: LazyStatic>(lazy: &T) {
    LazyStatic::initialize(lazy);
}
<|endoftext|>


<commit_before>#![deny(missing_docs)]

//! A simple and type agnostic quaternion math library designed for reexporting

extern crate vecmath;

use vecmath::Vector3;
use vecmath::traits::Float;

/// Quaternion type alias.
pub type Quaternion<T> = (T, [T; 3]);

/// Constructs identity quaternion.
#[inline(always)]
pub fn id<T>() -> Quaternion<T>
    where T: Float
{
    let one = T::one();
    let zero = T::zero();
    (one, [zero, zero, zero])
}

/// Adds two quaternions.
#[inline(always)]
pub fn add<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_add as add;
    (a.0 + b.0, add(a.1, b.1))
}

/// Scales a quaternion (element-wise) by a scalar
#[inline(always)]
pub fn scale<T>(
    q: Quaternion<T>,
    t: T
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_scale as scale;
    (q.0 * t, scale(q.1, t))
}

/// Dot product of two quaternions
#[inline(always)]
pub fn dot<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> T
    where T: Float
{
    a.0 * b.0 + vecmath::vec3_dot(a.1, b.1)
}

/// Multiplies two quaternions.
#[inline(always)]
pub fn mul<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_cross as cross;
    use vecmath::vec3_add as add;
    use vecmath::vec3_dot as dot;
    use vecmath::vec3_scale as scale;

    (
        a.0 * b.0 - dot(a.1, b.1),
        add(
            add(scale(b.1, a.0), scale(a.1, b.0)),
            cross(a.1, b.1)
        )
    )
}

/// Takes the quaternion conjugate.
#[inline(always)]
pub fn conj<T>(a: Quaternion<T>) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_neg as neg;

    (a.0, neg(a.1))
}

/// Computes the square length of a quaternion.
#[inline(always)]
pub fn square_len<T>(q: Quaternion<T>) -> T
    where T: Float
{
    use vecmath::vec3_square_len as square_len;
    q.0 * q.0 + square_len(q.1)
}

/// Computes the length of a quaternion.
#[inline(always)]
pub fn len<T>(q: Quaternion<T>) -> T
    where T: Float
{
    square_len(q).sqrt()
}

/// Rotate the given vector using the given quaternion
#[inline(always)]
pub fn rotate_vector<T>(q: Quaternion<T>, v: Vector3<T>) -> Vector3<T>
    where T: Float
{
    let zero = T::zero();
    let v_as_q : Quaternion<T> = (zero, v);
    let q_conj = conj(q);
    mul(mul(q, v_as_q), q_conj).1
}

/// Construct a quaternion representing the given euler angle rotations (in radians)
#[inline(always)]
pub fn euler_angles<T>(x: T, y: T, z: T) -> Quaternion<T>
    where T: Float
{
    let two: T = T::one() + T::one();

    let half_x = x / two;
    let half_y = y / two;
    let half_z = z / two;

    let cos_x_2 = half_x.cos();
    let cos_y_2 = half_y.cos();
    let cos_z_2 = half_z.cos();

    let sin_x_2 = half_x.sin();
    let sin_y_2 = half_y.sin();
    let sin_z_2 = half_z.sin();

    (
        cos_x_2 * cos_y_2 * cos_z_2 + sin_x_2 * sin_y_2 * sin_z_2,
        [
            sin_x_2 * cos_y_2 * cos_z_2 + cos_x_2 * sin_y_2 * sin_z_2,
            cos_x_2 * sin_y_2 * cos_z_2 + sin_x_2 * cos_y_2 * sin_z_2,
            cos_x_2 * cos_y_2 * sin_z_2 + sin_x_2 * sin_y_2 * cos_z_2
        ]
    )
}

/// Construct a quaternion for the given angle (in radians)
/// about the given axis.
/// Axis must be a unit vector.
#[inline(always)]
pub fn axis_angle<T>(axis: Vector3<T>, angle: T) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_scale as scale;
    let two: T = T::one() + T::one();
    let half_angle = angle / two;
    (half_angle.cos(), scale(axis, half_angle.sin()))
}

/// Tests
#[cfg(test)]
mod test {
    use super::*;
    use vecmath::Vector3;
    use std::f32::consts::PI;

    /// Fudge factor for float equality checks
    static EPSILON: f32 = 0.000001;

    #[test]
    fn test_axis_angle() {
        use vecmath::vec3_normalized as normalized;
        let axis: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle(
            normalized(axis),
            PI
        );

        // Should be a unit quaternion
        assert!((square_len(q) - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_euler_angle() {
        let q: Quaternion<f32> = euler_angles(PI, PI, PI);
        // Should be a unit quaternion
        assert!((square_len(q) - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotate_vector_axis_angle() {
        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle([0.0, 1.0, 0.0], PI);
        let rotated = rotate_vector(q, v);
        assert!((rotated[0] - -1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - -1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotate_vector_euler_angle() {
        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = euler_angles(0.0, PI, 0.0);
        let rotated = rotate_vector(q, v);
        assert!((rotated[0] - -1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - -1.0).abs() < EPSILON);
    }

    /// Rotation on axis parallel to vector direction should have no effect
    #[test]
    fn test_rotate_vector_axis_angle_same_axis() {
        use vecmath::vec3_normalized as normalized;

        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let arbitrary_angle = 32.12f32;
        let axis: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle(
            normalized(axis),
            arbitrary_angle
        );
        let rotated = rotate_vector(q, v);

        assert!((rotated[0] - 1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - 1.0).abs() < EPSILON);
    }
}
<commit_msg>Added `rotation_from_to`<commit_after>#![deny(missing_docs)]

//! A simple and type agnostic quaternion math library designed for reexporting

extern crate vecmath;

use vecmath::Vector3;
use vecmath::traits::Float;

/// Quaternion type alias.
pub type Quaternion<T> = (T, [T; 3]);

/// Constructs identity quaternion.
#[inline(always)]
pub fn id<T>() -> Quaternion<T>
    where T: Float
{
    let one = T::one();
    let zero = T::zero();
    (one, [zero, zero, zero])
}

/// Adds two quaternions.
#[inline(always)]
pub fn add<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_add as add;
    (a.0 + b.0, add(a.1, b.1))
}

/// Scales a quaternion (element-wise) by a scalar
#[inline(always)]
pub fn scale<T>(
    q: Quaternion<T>,
    t: T
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_scale as scale;
    (q.0 * t, scale(q.1, t))
}

/// Dot product of two quaternions
#[inline(always)]
pub fn dot<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> T
    where T: Float
{
    a.0 * b.0 + vecmath::vec3_dot(a.1, b.1)
}

/// Multiplies two quaternions.
#[inline(always)]
pub fn mul<T>(
    a: Quaternion<T>,
    b: Quaternion<T>
) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_cross as cross;
    use vecmath::vec3_add as add;
    use vecmath::vec3_dot as dot;
    use vecmath::vec3_scale as scale;

    (
        a.0 * b.0 - dot(a.1, b.1),
        add(
            add(scale(b.1, a.0), scale(a.1, b.0)),
            cross(a.1, b.1)
        )
    )
}

/// Takes the quaternion conjugate.
#[inline(always)]
pub fn conj<T>(a: Quaternion<T>) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_neg as neg;

    (a.0, neg(a.1))
}

/// Computes the square length of a quaternion.
#[inline(always)]
pub fn square_len<T>(q: Quaternion<T>) -> T
    where T: Float
{
    use vecmath::vec3_square_len as square_len;
    q.0 * q.0 + square_len(q.1)
}

/// Computes the length of a quaternion.
#[inline(always)]
pub fn len<T>(q: Quaternion<T>) -> T
    where T: Float
{
    square_len(q).sqrt()
}

/// Rotate the given vector using the given quaternion
#[inline(always)]
pub fn rotate_vector<T>(q: Quaternion<T>, v: Vector3<T>) -> Vector3<T>
    where T: Float
{
    let zero = T::zero();
    let v_as_q : Quaternion<T> = (zero, v);
    let q_conj = conj(q);
    mul(mul(q, v_as_q), q_conj).1
}

/// Construct a quaternion representing the rotation from a to b
#[inline(always)]
pub fn rotation_from_to<T>(a: Vector3<T>, b: Vector3<T>) -> Quaternion<T>
    where T: Float
{
    use vecmath::{vec3_cross, vec3_dot, vec3_square_len, vec3_normalized};
    use std::f64::consts::PI;

    let _1 = T::one();
    let _0 = T::zero();

    let a = vec3_normalized(a);
    let b = vec3_normalized(b);
    let dot = vec3_dot(a, b);

    if dot >= _1 {
        // a, b are parallel
        return id();
    }

    if dot < T::from_f64(-0.999999) {
        // a, b are anti-parallel
        let mut axis = vec3_cross([_1, _0, _0], a);
        if vec3_square_len(axis) == _0 {
            axis = vec3_cross([_0, _1, _0], a);
        }
        axis = vec3_normalized(axis);
        axis_angle(axis, T::from_f64(PI))
    } else {
        let q = (
            _1 + dot,
            vec3_cross(a, b)
        );
        scale(q, _1 / len(q))
    }
}

/// Construct a quaternion representing the given euler angle rotations (in radians)
#[inline(always)]
pub fn euler_angles<T>(x: T, y: T, z: T) -> Quaternion<T>
    where T: Float
{
    let two: T = T::one() + T::one();

    let half_x = x / two;
    let half_y = y / two;
    let half_z = z / two;

    let cos_x_2 = half_x.cos();
    let cos_y_2 = half_y.cos();
    let cos_z_2 = half_z.cos();

    let sin_x_2 = half_x.sin();
    let sin_y_2 = half_y.sin();
    let sin_z_2 = half_z.sin();

    (
        cos_x_2 * cos_y_2 * cos_z_2 + sin_x_2 * sin_y_2 * sin_z_2,
        [
            sin_x_2 * cos_y_2 * cos_z_2 + cos_x_2 * sin_y_2 * sin_z_2,
            cos_x_2 * sin_y_2 * cos_z_2 + sin_x_2 * cos_y_2 * sin_z_2,
            cos_x_2 * cos_y_2 * sin_z_2 + sin_x_2 * sin_y_2 * cos_z_2
        ]
    )
}

/// Construct a quaternion for the given angle (in radians)
/// about the given axis.
/// Axis must be a unit vector.
#[inline(always)]
pub fn axis_angle<T>(axis: Vector3<T>, angle: T) -> Quaternion<T>
    where T: Float
{
    use vecmath::vec3_scale as scale;
    let two: T = T::one() + T::one();
    let half_angle = angle / two;
    (half_angle.cos(), scale(axis, half_angle.sin()))
}

/// Tests
#[cfg(test)]
mod test {
    use super::*;
    use vecmath::Vector3;
    use std::f32::consts::PI;

    /// Fudge factor for float equality checks
    static EPSILON: f32 = 0.000001;

    #[test]
    fn test_axis_angle() {
        use vecmath::vec3_normalized as normalized;
        let axis: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle(
            normalized(axis),
            PI
        );

        // Should be a unit quaternion
        assert!((square_len(q) - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_euler_angle() {
        let q: Quaternion<f32> = euler_angles(PI, PI, PI);
        // Should be a unit quaternion
        assert!((square_len(q) - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotate_vector_axis_angle() {
        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle([0.0, 1.0, 0.0], PI);
        let rotated = rotate_vector(q, v);
        assert!((rotated[0] - -1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - -1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotate_vector_euler_angle() {
        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = euler_angles(0.0, PI, 0.0);
        let rotated = rotate_vector(q, v);
        assert!((rotated[0] - -1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - -1.0).abs() < EPSILON);
    }

    /// Rotation on axis parallel to vector direction should have no effect
    #[test]
    fn test_rotate_vector_axis_angle_same_axis() {
        use vecmath::vec3_normalized as normalized;

        let v: Vector3<f32> = [1.0, 1.0, 1.0];
        let arbitrary_angle = 32.12f32;
        let axis: Vector3<f32> = [1.0, 1.0, 1.0];
        let q: Quaternion<f32> = axis_angle(
            normalized(axis),
            arbitrary_angle
        );
        let rotated = rotate_vector(q, v);

        assert!((rotated[0] - 1.0).abs() < EPSILON);
        assert!((rotated[1] - 1.0).abs() < EPSILON);
        assert!((rotated[2] - 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotation_from_to_1() {
        use vecmath::vec3_normalized as normalized;

        let a: Vector3<f32> = [1.0, 1.0, 1.0];
        let b: Vector3<f32> = [-1.0, -1.0, -1.0];

        let q = super::rotation_from_to(a, b);

        let a_prime = super::rotate_vector(q, a);

        println!("a_prime = {:?}", a_prime);

        assert!((a_prime[0] + 1.0).abs() < EPSILON);
        assert!((a_prime[1] + 1.0).abs() < EPSILON);
        assert!((a_prime[2] + 1.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotation_from_to_2() {
        use vecmath;
        use vecmath::vec3_normalized as normalized;

        let a: Vector3<f32> = normalized([1.0, 1.0, 0.0]);
        let b: Vector3<f32> = [0.0, 1.0, 0.0];

        let q = super::rotation_from_to(a, b);
        let a_prime = super::rotate_vector(q, a);

        println!("a_prime = {:?}", a_prime);

        assert!((a_prime[0] - 0.0).abs() < EPSILON);
        assert!((a_prime[1] - 1.0).abs() < EPSILON);
        assert!((a_prime[2] - 0.0).abs() < EPSILON);
    }

    #[test]
    fn test_rotation_from_to_3() {
        use vecmath::vec3_normalized as normalized;

        let a: Vector3<f32> = [1.0, 0.0, 0.0];
        let b: Vector3<f32> = [0.0, -1.0, 0.0];

        let q = super::rotation_from_to(a, b);

        let a_prime = super::rotate_vector(q, a);

        println!("a_prime = {:?}", a_prime);

        assert!((a_prime[0] - 0.0).abs() < EPSILON);
        assert!((a_prime[1] - -1.0).abs() < EPSILON);
        assert!((a_prime[2] - 0.0).abs() < EPSILON);
    }

}
<|endoftext|>


<commit_before>mod platform;
mod farmhashna;
mod farmhashmk;
mod farmhashuo;
mod farmhashxo;
mod farmhashna_shared;
mod farmhashcc_shared;
mod farmhashmk_shared;

use farmhashmk::mk_hash32;
use farmhashmk::mk_hash32_with_seed;
use farmhashxo::xo_hash64;
use farmhashxo::xo_hash64_with_seed;
use farmhashxo::xo_hash64_with_seeds;
use std::hash::Hasher;

/// Create a new farmhash based u32 for a gives array of bytes.
///
/// # Examples
///
/// ```
/// let value: &str = "hello world";
/// let res32 = farmhash::hash32(&value.as_bytes());
/// //res32 ==> 430397466
/// ```
pub fn hash32(s: &[u8]) -> u32 {
    mk_hash32(s)
}
/// Create a new farmhash based u32 for a gives array of bytes with a given seed.
pub fn hash32_with_seed(s: &[u8], seed: u32) -> u32 {
    mk_hash32_with_seed(s, seed)
}

/// Create a new farmhash based u64 for a gives array of bytes.
///
/// # Examples
///
/// ```
/// let value: &str = "hello world";
/// let res64 = farmhash::hash64(&value.as_bytes());
/// //res64 ==> 6381520714923946011
/// ```
pub fn hash64(s: &[u8]) -> u64 {
    xo_hash64(s)
}

/// Create a new farmhash based u64 for a gives array of bytes with a given seed.
pub fn hash64_with_seed(s: &[u8], seed: u64) -> u64 {
    xo_hash64_with_seed(s, seed)
}

/// Create a new farmhash based u64 for a gives array of bytes with 2 given seeds.
pub fn hash64_with_seeds(s: &[u8], seed0: u64, seed1: u64) -> u64 {
    xo_hash64_with_seeds(s, seed0, seed1)
}

pub struct FarmHasher {
    bytes: Vec<u8>
}

impl Default for FarmHasher {
    #[inline]
    fn default() -> FarmHasher { FarmHasher{bytes: Vec::with_capacity(20)} }
}

impl Hasher for FarmHasher {
    #[inline]
    fn finish(&self) -> u64 {
        hash64(&self.bytes[..])
    }
    #[inline]
    fn write(&mut self, bytes: &[u8]) {
        self.bytes.extend(bytes.iter().cloned());
    }
}
<commit_msg>Fix non-grammatical doc comments<commit_after>mod platform;
mod farmhashna;
mod farmhashmk;
mod farmhashuo;
mod farmhashxo;
mod farmhashna_shared;
mod farmhashcc_shared;
mod farmhashmk_shared;

use farmhashmk::mk_hash32;
use farmhashmk::mk_hash32_with_seed;
use farmhashxo::xo_hash64;
use farmhashxo::xo_hash64_with_seed;
use farmhashxo::xo_hash64_with_seeds;
use std::hash::Hasher;

/// Create a new farmhash based u32 for an array of bytes.
///
/// # Examples
///
/// ```
/// let value: &str = "hello world";
/// let res32 = farmhash::hash32(&value.as_bytes());
/// //res32 ==> 430397466
/// ```
pub fn hash32(s: &[u8]) -> u32 {
    mk_hash32(s)
}
/// Create a new farmhash based u32 for an array of bytes with a given seed.
pub fn hash32_with_seed(s: &[u8], seed: u32) -> u32 {
    mk_hash32_with_seed(s, seed)
}

/// Create a new farmhash based u64 for an array of bytes.
///
/// # Examples
///
/// ```
/// let value: &str = "hello world";
/// let res64 = farmhash::hash64(&value.as_bytes());
/// //res64 ==> 6381520714923946011
/// ```
pub fn hash64(s: &[u8]) -> u64 {
    xo_hash64(s)
}

/// Create a new farmhash based u64 for an array of bytes with a given seed.
pub fn hash64_with_seed(s: &[u8], seed: u64) -> u64 {
    xo_hash64_with_seed(s, seed)
}

/// Create a new farmhash based u64 for an array of bytes with 2 given seeds.
pub fn hash64_with_seeds(s: &[u8], seed0: u64, seed1: u64) -> u64 {
    xo_hash64_with_seeds(s, seed0, seed1)
}

pub struct FarmHasher {
    bytes: Vec<u8>
}

impl Default for FarmHasher {
    #[inline]
    fn default() -> FarmHasher { FarmHasher{bytes: Vec::with_capacity(20)} }
}

impl Hasher for FarmHasher {
    #[inline]
    fn finish(&self) -> u64 {
        hash64(&self.bytes[..])
    }
    #[inline]
    fn write(&mut self, bytes: &[u8]) {
        self.bytes.extend(bytes.iter().cloned());
    }
}
<|endoftext|>


<commit_before>#![allow(dead_code)]

extern crate hyper;
extern crate rustc_serialize;

pub mod client;
pub mod schema;

mod fleet;
<commit_msg>Reexport public types and make modules private.<commit_after>#![allow(dead_code)]

extern crate hyper;
extern crate rustc_serialize;

pub use client::Client;
pub use schema::{Machine, Unit, UnitOption, UnitState, UnitStates};

mod client;
mod fleet;
mod schema;
<|endoftext|>


<commit_before>//Copyright 2022  secret-service-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! # Secret Service libary
//!
//! This library implements a rust interface to the Secret Service API which is implemented
//! in Linux.
//!
//! ## About Secret Service API
//! http://standards.freedesktop.org/secret-service/
//!
//! Secret Service provides a secure place to store secrets.
//! Gnome keyring and KWallet implement the Secret Service API.
//!
//! ## Basic Usage
//! ```
//! use secret_service::SecretService;
//! use secret_service::EncryptionType;
//! use std::collections::HashMap;
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() {
//!    // initialize secret service (dbus connection and encryption session)
//!    let ss = SecretService::connect(EncryptionType::Dh).await.unwrap();
//!
//!    // get default collection
//!    let collection = ss.get_default_collection().await.unwrap();
//!
//!    let mut properties = HashMap::new();
//!    properties.insert("test", "test_value");
//!
//!    //create new item
//!    collection.create_item(
//!        "test_label", // label
//!        properties,
//!        b"test_secret", //secret
//!        false, // replace item with same attributes
//!        "text/plain" // secret content type
//!    ).await.unwrap();
//!
//!    // search items by properties
//!    let search_items = ss.search_items(
//!        HashMap::from([("test", "test_value")])
//!    ).await.unwrap();
//!
//!    let item = search_items.get(0).unwrap();
//!
//!    // retrieve secret from item
//!    let secret = item.get_secret().await.unwrap();
//!    assert_eq!(secret, b"test_secret");
//!
//!    // delete item (deletes the dbus object, not the struct instance)
//!    item.delete().await.unwrap()
//! }
//! ```
//!
//! ## Overview of this library:
//! ### Entry point
//! The entry point for this library is the `SecretService` struct. A new instance of
//! `SecretService` will initialize the dbus connection and negotiate an encryption session.
//!
//! ```
//! # use secret_service::SecretService;
//! # use secret_service::EncryptionType;
//! # async fn call() {
//! SecretService::connect(EncryptionType::Plain).await.unwrap();
//! # }
//! ```
//!
//! or
//!
//! ```
//! # use secret_service::SecretService;
//! # use secret_service::EncryptionType;
//! # async fn call() {
//! SecretService::connect(EncryptionType::Dh).await.unwrap();
//! # }
//! ```
//!
//! Once the SecretService struct is initialized, it can be used to navigate to a collection.
//! Items can also be directly searched for without getting a collection first.
//!
//! ### Collections and Items
//! The Secret Service API organizes secrets into collections, and holds each secret
//! in an item.
//!
//! Items consist of a label, attributes, and the secret. The most common way to find
//! an item is a search by attributes.
//!
//! While it's possible to create new collections, most users will simply create items
//! within the default collection.
//!
//! ### Actions overview
//! The most common supported actions are `create`, `get`, `search`, and `delete` for
//! `Collections` and `Items`. For more specifics and exact method names, please see
//! each struct's documentation.
//!
//! In addition, `set` and `get` actions are available for secrets contained in an `Item`.
//!
//! ### Crypto
//! Specifics in SecretService API Draft Proposal:
//! http://standards.freedesktop.org/secret-service/
//!
//! ### Async
//!
//! This crate, following `zbus`, is async by default. If you want a synchronous interface
//! that blocks, see the [blocking] module instead.
//
// Util currently has interfaces (dbus method namespace) to make it easier to call methods.
// Util contains function to execute prompts (used in many collection and item methods, like
// delete)

pub mod blocking;
mod error;
mod proxy;
mod session;
mod ss;
mod util;

mod collection;
pub use collection::Collection;

pub use error::Error;

mod item;
pub use item::Item;

pub use session::EncryptionType;

use crate::proxy::service::ServiceProxy;
use crate::session::Session;
use crate::ss::SS_COLLECTION_LABEL;
use crate::util::exec_prompt;
use futures_util::TryFutureExt;
use std::collections::HashMap;
use zbus::zvariant::{ObjectPath, Value};

/// Secret Service Struct.
///
/// This the main entry point for usage of the library.
///
/// Creating a new [SecretService] will also initialize dbus
/// and negotiate a new cryptographic session
/// ([EncryptionType::Plain] or [EncryptionType::Dh])
pub struct SecretService<'a> {
    conn: zbus::Connection,
    session: Session,
    service_proxy: ServiceProxy<'a>,
}

/// Used to indicate locked and unlocked items in the
/// return value of [SecretService::search_items]
/// and [blocking::SecretService::search_items].
pub struct SearchItemsResult<T> {
    pub unlocked: Vec<T>,
    pub locked: Vec<T>,
}

impl<'a> SecretService<'a> {
    /// Create a new `SecretService` instance.
    pub async fn connect(encryption: EncryptionType) -> Result<SecretService<'a>, Error> {
        let conn = zbus::Connection::session()
            .await
            .map_err(util::handle_conn_error)?;

        let service_proxy = ServiceProxy::new(&conn)
            .await
            .map_err(util::handle_conn_error)?;

        let session = Session::new(&service_proxy, encryption).await?;

        Ok(SecretService {
            conn,
            session,
            service_proxy,
        })
    }

    /// Get all collections
    pub async fn get_all_collections(&self) -> Result<Vec<Collection<'_>>, Error> {
        let collections = self.service_proxy.collections().await?;

        futures_util::future::join_all(collections.into_iter().map(|object_path| {
            Collection::new(
                self.conn.clone(),
                &self.session,
                &self.service_proxy,
                object_path.into(),
            )
        }))
        .await
        .into_iter()
        .collect::<Result<_, _>>()
    }

    /// Get collection by alias.
    ///
    /// Most common would be the `default` alias, but there
    /// is also a specific method for getting the collection
    /// by default alias.
    pub async fn get_collection_by_alias(&self, alias: &str) -> Result<Collection<'_>, Error> {
        let object_path = self.service_proxy.read_alias(alias).await?;

        if object_path.as_str() == "/" {
            Err(Error::NoResult)
        } else {
            Collection::new(
                self.conn.clone(),
                &self.session,
                &self.service_proxy,
                object_path,
            )
            .await
        }
    }

    /// Get default collection.
    /// (The collection whos alias is `default`)
    pub async fn get_default_collection(&self) -> Result<Collection<'_>, Error> {
        self.get_collection_by_alias("default").await
    }

    /// Get any collection.
    /// First tries `default` collection, then `session`
    /// collection, then the first collection when it
    /// gets all collections.
    pub async fn get_any_collection(&self) -> Result<Collection<'_>, Error> {
        // default first, then session, then first

        self.get_default_collection()
            .or_else(|_| self.get_collection_by_alias("session"))
            .or_else(|_| async {
                let mut collections = self.get_all_collections().await?;
                if collections.is_empty() {
                    Err(Error::NoResult)
                } else {
                    Ok(collections.swap_remove(0))
                }
            })
            .await
    }

    /// Creates a new collection with a label and an alias.
    pub async fn create_collection(
        &self,
        label: &str,
        alias: &str,
    ) -> Result<Collection<'_>, Error> {
        let mut properties: HashMap<&str, Value> = HashMap::new();
        properties.insert(SS_COLLECTION_LABEL, label.into());

        let created_collection = self
            .service_proxy
            .create_collection(properties, alias)
            .await?;

        // This prompt handling is practically identical to create_collection
        let collection_path: ObjectPath = {
            // Get path of created object
            let created_path = created_collection.collection;

            // Check if that path is "/", if so should execute a prompt
            if created_path.as_str() == "/" {
                let prompt_path = created_collection.prompt;

                // Exec prompt and parse result
                let prompt_res = exec_prompt(self.conn.clone(), &prompt_path).await?;
                prompt_res.try_into()?
            } else {
                // if not, just return created path
                created_path.into()
            }
        };

        Collection::new(
            self.conn.clone(),
            &self.session,
            &self.service_proxy,
            collection_path.into(),
        )
        .await
    }

    /// Searches all items by attributes
    pub async fn search_items(
        &self,
        attributes: HashMap<&str, &str>,
    ) -> Result<SearchItemsResult<Item<'_>>, Error> {
        let items = self.service_proxy.search_items(attributes).await?;

        let object_paths_to_items = |items: Vec<_>| {
            futures_util::future::join_all(items.into_iter().map(|item_path| {
                Item::new(
                    self.conn.clone(),
                    &self.session,
                    &self.service_proxy,
                    item_path,
                )
            }))
        };

        Ok(SearchItemsResult {
            unlocked: object_paths_to_items(items.unlocked)
                .await
                .into_iter()
                .collect::<Result<_, _>>()?,
            locked: object_paths_to_items(items.locked)
                .await
                .into_iter()
                .collect::<Result<_, _>>()?,
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::convert::TryFrom;
    use zbus::zvariant::ObjectPath;

    #[tokio::test]
    async fn should_create_secret_service() {
        SecretService::connect(EncryptionType::Plain).await.unwrap();
    }

    #[tokio::test]
    async fn should_get_all_collections() {
        // Assumes that there will always be a default collection
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        let collections = ss.get_all_collections().await.unwrap();
        assert!(!collections.is_empty(), "no collections found");
    }

    #[tokio::test]
    async fn should_get_collection_by_alias() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        ss.get_collection_by_alias("session").await.unwrap();
    }

    #[tokio::test]
    async fn should_return_error_if_collection_doesnt_exist() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();

        match ss
            .get_collection_by_alias("definitely_defintely_does_not_exist")
            .await
        {
            Err(Error::NoResult) => {}
            _ => panic!(),
        };
    }

    #[tokio::test]
    async fn should_get_default_collection() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        ss.get_default_collection().await.unwrap();
    }

    #[tokio::test]
    async fn should_get_any_collection() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        let _ = ss.get_any_collection().await.unwrap();
    }

    #[tokio::test]
    async fn should_create_and_delete_collection() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        let test_collection = ss.create_collection("Test", "").await.unwrap();
        assert_eq!(
            ObjectPath::from(test_collection.collection_path.clone()),
            ObjectPath::try_from("/org/freedesktop/secrets/collection/Test").unwrap()
        );
        test_collection.delete().await.unwrap();
    }

    #[tokio::test]
    async fn should_search_items() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        let collection = ss.get_default_collection().await.unwrap();

        // Create an item
        let item = collection
            .create_item(
                "test",
                HashMap::from([("test_attribute_in_ss", "test_value")]),
                b"test_secret",
                false,
                "text/plain",
            )
            .await
            .unwrap();

        // handle empty vec search
        ss.search_items(HashMap::new()).await.unwrap();

        // handle no result
        let bad_search = ss
            .search_items(HashMap::from([("test", "test")]))
            .await
            .unwrap();
        assert_eq!(bad_search.unlocked.len(), 0);
        assert_eq!(bad_search.locked.len(), 0);

        // handle correct search for item and compare
        let search_item = ss
            .search_items(HashMap::from([("test_attribute_in_ss", "test_value")]))
            .await
            .unwrap();

        assert_eq!(item.item_path, search_item.unlocked[0].item_path);
        assert_eq!(search_item.locked.len(), 0);
        item.delete().await.unwrap();
    }
}
<commit_msg>Reflect search_items API change in documentation<commit_after>//Copyright 2022  secret-service-rs Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! # Secret Service libary
//!
//! This library implements a rust interface to the Secret Service API which is implemented
//! in Linux.
//!
//! ## About Secret Service API
//! <https://standards.freedesktop.org/secret-service/>
//!
//! Secret Service provides a secure place to store secrets.
//! Gnome keyring and KWallet implement the Secret Service API.
//!
//! ## Basic Usage
//! ```
//! use secret_service::SecretService;
//! use secret_service::EncryptionType;
//! use std::collections::HashMap;
//!
//! #[tokio::main(flavor = "current_thread")]
//! async fn main() {
//!    // initialize secret service (dbus connection and encryption session)
//!    let ss = SecretService::connect(EncryptionType::Dh).await.unwrap();
//!
//!    // get default collection
//!    let collection = ss.get_default_collection().await.unwrap();
//!
//!    let mut properties = HashMap::new();
//!    properties.insert("test", "test_value");
//!
//!    //create new item
//!    collection.create_item(
//!        "test_label", // label
//!        properties,
//!        b"test_secret", //secret
//!        false, // replace item with same attributes
//!        "text/plain" // secret content type
//!    ).await.unwrap();
//!
//!    // search items by properties
//!    let search_items = ss.search_items(
//!        HashMap::from([("test", "test_value")])
//!    ).await.unwrap();
//!
//!    // retrieve one item, first by checking the unlocked items
//!    let item = match search_items.unlocked.first() {
//!        Some(item) => item,
//!        None => {
//!            // if there aren't any, check the locked items and unlock the first one
//!            let locked_item = search_items
//!                .locked
//!                .first()
//!                .expect("Search didn't return any items!");
//!            locked_item.unlock().await.unwrap();
//!            locked_item
//!        }
//!    };
//!
//!    // retrieve secret from item
//!    let secret = item.get_secret().await.unwrap();
//!    assert_eq!(secret, b"test_secret");
//!
//!    // delete item (deletes the dbus object, not the struct instance)
//!    item.delete().await.unwrap()
//! }
//! ```
//!
//! ## Overview of this library:
//! ### Entry point
//! The entry point for this library is the `SecretService` struct. A new instance of
//! `SecretService` will initialize the dbus connection and negotiate an encryption session.
//!
//! ```
//! # use secret_service::SecretService;
//! # use secret_service::EncryptionType;
//! # async fn call() {
//! SecretService::connect(EncryptionType::Plain).await.unwrap();
//! # }
//! ```
//!
//! or
//!
//! ```
//! # use secret_service::SecretService;
//! # use secret_service::EncryptionType;
//! # async fn call() {
//! SecretService::connect(EncryptionType::Dh).await.unwrap();
//! # }
//! ```
//!
//! Once the SecretService struct is initialized, it can be used to navigate to a collection.
//! Items can also be directly searched for without getting a collection first.
//!
//! ### Collections and Items
//! The Secret Service API organizes secrets into collections, and holds each secret
//! in an item.
//!
//! Items consist of a label, attributes, and the secret. The most common way to find
//! an item is a search by attributes.
//!
//! While it's possible to create new collections, most users will simply create items
//! within the default collection.
//!
//! ### Actions overview
//! The most common supported actions are `create`, `get`, `search`, and `delete` for
//! `Collections` and `Items`. For more specifics and exact method names, please see
//! each struct's documentation.
//!
//! In addition, `set` and `get` actions are available for secrets contained in an `Item`.
//!
//! ### Crypto
//! Specifics in SecretService API Draft Proposal:
//! <https://standards.freedesktop.org/secret-service/>
//!
//! ### Async
//!
//! This crate, following `zbus`, is async by default. If you want a synchronous interface
//! that blocks, see the [blocking] module instead.
//
// Util currently has interfaces (dbus method namespace) to make it easier to call methods.
// Util contains function to execute prompts (used in many collection and item methods, like
// delete)

pub mod blocking;
mod error;
mod proxy;
mod session;
mod ss;
mod util;

mod collection;
pub use collection::Collection;

pub use error::Error;

mod item;
pub use item::Item;

pub use session::EncryptionType;

use crate::proxy::service::ServiceProxy;
use crate::session::Session;
use crate::ss::SS_COLLECTION_LABEL;
use crate::util::exec_prompt;
use futures_util::TryFutureExt;
use std::collections::HashMap;
use zbus::zvariant::{ObjectPath, Value};

/// Secret Service Struct.
///
/// This the main entry point for usage of the library.
///
/// Creating a new [SecretService] will also initialize dbus
/// and negotiate a new cryptographic session
/// ([EncryptionType::Plain] or [EncryptionType::Dh])
pub struct SecretService<'a> {
    conn: zbus::Connection,
    session: Session,
    service_proxy: ServiceProxy<'a>,
}

/// Used to indicate locked and unlocked items in the
/// return value of [SecretService::search_items]
/// and [blocking::SecretService::search_items].
pub struct SearchItemsResult<T> {
    pub unlocked: Vec<T>,
    pub locked: Vec<T>,
}

impl<'a> SecretService<'a> {
    /// Create a new `SecretService` instance.
    pub async fn connect(encryption: EncryptionType) -> Result<SecretService<'a>, Error> {
        let conn = zbus::Connection::session()
            .await
            .map_err(util::handle_conn_error)?;

        let service_proxy = ServiceProxy::new(&conn)
            .await
            .map_err(util::handle_conn_error)?;

        let session = Session::new(&service_proxy, encryption).await?;

        Ok(SecretService {
            conn,
            session,
            service_proxy,
        })
    }

    /// Get all collections
    pub async fn get_all_collections(&self) -> Result<Vec<Collection<'_>>, Error> {
        let collections = self.service_proxy.collections().await?;

        futures_util::future::join_all(collections.into_iter().map(|object_path| {
            Collection::new(
                self.conn.clone(),
                &self.session,
                &self.service_proxy,
                object_path.into(),
            )
        }))
        .await
        .into_iter()
        .collect::<Result<_, _>>()
    }

    /// Get collection by alias.
    ///
    /// Most common would be the `default` alias, but there
    /// is also a specific method for getting the collection
    /// by default alias.
    pub async fn get_collection_by_alias(&self, alias: &str) -> Result<Collection<'_>, Error> {
        let object_path = self.service_proxy.read_alias(alias).await?;

        if object_path.as_str() == "/" {
            Err(Error::NoResult)
        } else {
            Collection::new(
                self.conn.clone(),
                &self.session,
                &self.service_proxy,
                object_path,
            )
            .await
        }
    }

    /// Get default collection.
    /// (The collection whos alias is `default`)
    pub async fn get_default_collection(&self) -> Result<Collection<'_>, Error> {
        self.get_collection_by_alias("default").await
    }

    /// Get any collection.
    /// First tries `default` collection, then `session`
    /// collection, then the first collection when it
    /// gets all collections.
    pub async fn get_any_collection(&self) -> Result<Collection<'_>, Error> {
        // default first, then session, then first

        self.get_default_collection()
            .or_else(|_| self.get_collection_by_alias("session"))
            .or_else(|_| async {
                let mut collections = self.get_all_collections().await?;
                if collections.is_empty() {
                    Err(Error::NoResult)
                } else {
                    Ok(collections.swap_remove(0))
                }
            })
            .await
    }

    /// Creates a new collection with a label and an alias.
    pub async fn create_collection(
        &self,
        label: &str,
        alias: &str,
    ) -> Result<Collection<'_>, Error> {
        let mut properties: HashMap<&str, Value> = HashMap::new();
        properties.insert(SS_COLLECTION_LABEL, label.into());

        let created_collection = self
            .service_proxy
            .create_collection(properties, alias)
            .await?;

        // This prompt handling is practically identical to create_collection
        let collection_path: ObjectPath = {
            // Get path of created object
            let created_path = created_collection.collection;

            // Check if that path is "/", if so should execute a prompt
            if created_path.as_str() == "/" {
                let prompt_path = created_collection.prompt;

                // Exec prompt and parse result
                let prompt_res = exec_prompt(self.conn.clone(), &prompt_path).await?;
                prompt_res.try_into()?
            } else {
                // if not, just return created path
                created_path.into()
            }
        };

        Collection::new(
            self.conn.clone(),
            &self.session,
            &self.service_proxy,
            collection_path.into(),
        )
        .await
    }

    /// Searches all items by attributes
    pub async fn search_items(
        &self,
        attributes: HashMap<&str, &str>,
    ) -> Result<SearchItemsResult<Item<'_>>, Error> {
        let items = self.service_proxy.search_items(attributes).await?;

        let object_paths_to_items = |items: Vec<_>| {
            futures_util::future::join_all(items.into_iter().map(|item_path| {
                Item::new(
                    self.conn.clone(),
                    &self.session,
                    &self.service_proxy,
                    item_path,
                )
            }))
        };

        Ok(SearchItemsResult {
            unlocked: object_paths_to_items(items.unlocked)
                .await
                .into_iter()
                .collect::<Result<_, _>>()?,
            locked: object_paths_to_items(items.locked)
                .await
                .into_iter()
                .collect::<Result<_, _>>()?,
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::convert::TryFrom;
    use zbus::zvariant::ObjectPath;

    #[tokio::test]
    async fn should_create_secret_service() {
        SecretService::connect(EncryptionType::Plain).await.unwrap();
    }

    #[tokio::test]
    async fn should_get_all_collections() {
        // Assumes that there will always be a default collection
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        let collections = ss.get_all_collections().await.unwrap();
        assert!(!collections.is_empty(), "no collections found");
    }

    #[tokio::test]
    async fn should_get_collection_by_alias() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        ss.get_collection_by_alias("session").await.unwrap();
    }

    #[tokio::test]
    async fn should_return_error_if_collection_doesnt_exist() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();

        match ss
            .get_collection_by_alias("definitely_defintely_does_not_exist")
            .await
        {
            Err(Error::NoResult) => {}
            _ => panic!(),
        };
    }

    #[tokio::test]
    async fn should_get_default_collection() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        ss.get_default_collection().await.unwrap();
    }

    #[tokio::test]
    async fn should_get_any_collection() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        let _ = ss.get_any_collection().await.unwrap();
    }

    #[tokio::test]
    async fn should_create_and_delete_collection() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        let test_collection = ss.create_collection("Test", "").await.unwrap();
        assert_eq!(
            ObjectPath::from(test_collection.collection_path.clone()),
            ObjectPath::try_from("/org/freedesktop/secrets/collection/Test").unwrap()
        );
        test_collection.delete().await.unwrap();
    }

    #[tokio::test]
    async fn should_search_items() {
        let ss = SecretService::connect(EncryptionType::Plain).await.unwrap();
        let collection = ss.get_default_collection().await.unwrap();

        // Create an item
        let item = collection
            .create_item(
                "test",
                HashMap::from([("test_attribute_in_ss", "test_value")]),
                b"test_secret",
                false,
                "text/plain",
            )
            .await
            .unwrap();

        // handle empty vec search
        ss.search_items(HashMap::new()).await.unwrap();

        // handle no result
        let bad_search = ss
            .search_items(HashMap::from([("test", "test")]))
            .await
            .unwrap();
        assert_eq!(bad_search.unlocked.len(), 0);
        assert_eq!(bad_search.locked.len(), 0);

        // handle correct search for item and compare
        let search_item = ss
            .search_items(HashMap::from([("test_attribute_in_ss", "test_value")]))
            .await
            .unwrap();

        assert_eq!(item.item_path, search_item.unlocked[0].item_path);
        assert_eq!(search_item.locked.len(), 0);
        item.delete().await.unwrap();
    }
}
<|endoftext|>