<commit_before>use std::cmp::Ordering;

use libimagstore::storeid::StoreId;
use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::Result as StoreResult;
use libimagerror::into::IntoError;

use error::LinkErrorKind as LEK;
use error::MapErrInto;
use result::Result;

use toml::Value;
use itertools::Itertools;

pub type Link = StoreId;

pub trait InternalLinker {

    /// Get the internal links from the implementor object
    fn get_internal_links(&self) -> Result<Vec<Link>>;

    /// Set the internal links for the implementor object
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>>;

    /// Add an internal link to the implementor object
    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()>;

    /// Remove an internal link from the implementor object
    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()>;

}

impl InternalLinker for Entry {

    fn get_internal_links(&self) -> Result<Vec<Link>> {
        process_rw_result(self.get_header().read("imag.links"))
    }

    /// Set the links in a header and return the old links, if any.
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>> {
        let self_location = self.get_location().clone();
        let mut new_links = vec![];

        for link in links {
            if let Err(e) = add_foreign_link(link, self_location.clone()) {
                return Err(e);
            }
            let link = link.get_location().clone();
            new_links.push(link);
        }

        let new_links = try!(links_into_values(new_links)
                             .into_iter()
                             .fold(Ok(vec![]), |acc, elem| {
                                acc.and_then(move |mut v| {
                                    match elem {
                                        None => Err(LEK::InternalConversionError.into()),
                                        Some(e) => {
                                            v.push(e);
                                            Ok(v)
                                        },
                                    }
                                })
                            }));
        process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links)))
    }

    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let new_link = link.get_location().clone();

        add_foreign_link(link, self.get_location().clone())
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|mut links| {
                        links.push(new_link);
                        rewrite_links(self.get_header_mut(), links)
                    })
            })
    }

    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let own_loc   = link.get_location().clone();
        let other_loc = link.get_location().clone();

        link.get_internal_links()
            .and_then(|links| {
                let links = links.into_iter().filter(|l| l.clone() != own_loc).collect();
                rewrite_links(self.get_header_mut(), links)
            })
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|links| {
                        let links = links.into_iter().filter(|l| l.clone() != other_loc).collect();
                        rewrite_links(link.get_header_mut(), links)
                    })
            })
    }

}

fn links_into_values(links: Vec<StoreId>) -> Vec<Option<Value>> {
    use libimagutil::debug_result::InfoResult;

    links
        .into_iter()
        .map(|s| {
            s.to_str()
                .map_dbg_err(|e| format!("Failed to translate StoreId to String: {:?}", e))
                .ok()
        })
        .unique()
        .map(|elem| elem.map(Value::String))
        .sorted_by(|a, b| {
            match (a, b) {
                (&Some(Value::String(ref a)), &Some(Value::String(ref b))) => Ord::cmp(a, b),
                (&None, _) | (_, &None) => Ordering::Equal,
                _                                              => unreachable!()
            }
        })
}

fn rewrite_links(header: &mut EntryHeader, links: Vec<StoreId>) -> Result<()> {
    let links = try!(links_into_values(links)
                     .into_iter()
                     .fold(Ok(vec![]), |acc, elem| {
                        acc.and_then(move |mut v| {
                            match elem {
                                None => Err(LEK::InternalConversionError.into()),
                                Some(e) => {
                                    v.push(e);
                                    Ok(v)
                                },
                            }
                        })
                     }));

    let process = header.set("imag.links", Value::Array(links));
    process_rw_result(process).map(|_| ())
}

/// When Linking A -> B, the specification wants us to link back B -> A.
/// This is a helper function which does this.
fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
    target.get_internal_links()
        .and_then(|mut links| {
            links.push(from);
            let links = try!(links_into_values(links)
                             .into_iter()
                             .fold(Ok(vec![]), |acc, elem| {
                                acc.and_then(move |mut v| {
                                    match elem {
                                        None => Err(LEK::InternalConversionError.into()),
                                        Some(e) => {
                                            v.push(e);
                                            Ok(v)
                                        },
                                    }
                                })
                             }));
            process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links)))
                .map(|_| ())
        })
}

fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> {
    use std::path::PathBuf;

    let links = match links {
        Err(e) => {
            debug!("RW action on store failed. Generating LinkError");
            return Err(LEK::EntryHeaderReadError.into_error_with_cause(Box::new(e)))
        },
        Ok(None) => {
            debug!("We got no value from the header!");
            return Ok(vec![])
        },
        Ok(Some(Value::Array(l))) => l,
        Ok(Some(_)) => {
            debug!("We expected an Array for the links, but there was a non-Array!");
            return Err(LEK::ExistingLinkTypeWrong.into());
        }
    };

    if !links.iter().all(|l| is_match!(*l, Value::String(_))) {
        debug!("At least one of the Values which were expected in the Array of links is a non-String!");
        debug!("Generating LinkError");
        return Err(LEK::ExistingLinkTypeWrong.into());
    }

    let links : Vec<Link> = try!(links.into_iter()
        .map(|link| {
            match link {
                Value::String(s) => StoreId::new_baseless(PathBuf::from(s))
                    .map_err_into(LEK::StoreIdError),
                _ => unreachable!(),
            }
        })
        .collect());

    debug!("Ok, the RW action was successful, returning link vector now!");
    Ok(links)
}

<commit_msg>Rewrite internal link handling, returning Result<_> rather than Option<_><commit_after>use std::cmp::Ordering;

use libimagstore::storeid::StoreId;
use libimagstore::store::Entry;
use libimagstore::store::EntryHeader;
use libimagstore::store::Result as StoreResult;
use libimagerror::into::IntoError;

use error::LinkErrorKind as LEK;
use error::MapErrInto;
use result::Result;

use toml::Value;
use itertools::Itertools;

pub type Link = StoreId;

pub trait InternalLinker {

    /// Get the internal links from the implementor object
    fn get_internal_links(&self) -> Result<Vec<Link>>;

    /// Set the internal links for the implementor object
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>>;

    /// Add an internal link to the implementor object
    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()>;

    /// Remove an internal link from the implementor object
    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()>;

}

impl InternalLinker for Entry {

    fn get_internal_links(&self) -> Result<Vec<Link>> {
        process_rw_result(self.get_header().read("imag.links"))
    }

    /// Set the links in a header and return the old links, if any.
    fn set_internal_links(&mut self, links: Vec<&mut Entry>) -> Result<Vec<Link>> {
        let self_location = self.get_location().clone();
        let mut new_links = vec![];

        for link in links {
            if let Err(e) = add_foreign_link(link, self_location.clone()) {
                return Err(e);
            }
            let link = link.get_location().clone();
            new_links.push(link);
        }

        let new_links = try!(links_into_values(new_links)
                             .into_iter()
                             .fold(Ok(vec![]), |acc, elem| {
                                acc.and_then(move |mut v| {
                                    elem.map_err_into(LEK::InternalConversionError)
                                        .map(|e| {
                                            v.push(e);
                                            v
                                        })
                                })
                            }));
        process_rw_result(self.get_header_mut().set("imag.links", Value::Array(new_links)))
    }

    fn add_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let new_link = link.get_location().clone();

        add_foreign_link(link, self.get_location().clone())
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|mut links| {
                        links.push(new_link);
                        rewrite_links(self.get_header_mut(), links)
                    })
            })
    }

    fn remove_internal_link(&mut self, link: &mut Entry) -> Result<()> {
        let own_loc   = link.get_location().clone();
        let other_loc = link.get_location().clone();

        link.get_internal_links()
            .and_then(|links| {
                let links = links.into_iter().filter(|l| l.clone() != own_loc).collect();
                rewrite_links(self.get_header_mut(), links)
            })
            .and_then(|_| {
                self.get_internal_links()
                    .and_then(|links| {
                        let links = links.into_iter().filter(|l| l.clone() != other_loc).collect();
                        rewrite_links(link.get_header_mut(), links)
                    })
            })
    }

}

fn links_into_values(links: Vec<StoreId>) -> Vec<Result<Value>> {
    links
        .into_iter()
        .unique()
        .map(|s| s.to_str().map_err_into(LEK::InternalConversionError))
        .map(|elem| elem.map(Value::String))
        .sorted_by(|a, b| {
            match (a, b) {
                (&Ok(Value::String(ref a)), &Ok(Value::String(ref b))) => Ord::cmp(a, b),
                (&Err(_), _) | (_, &Err(_)) => Ordering::Equal,
                _ => unreachable!()
            }
        })
}

fn rewrite_links(header: &mut EntryHeader, links: Vec<StoreId>) -> Result<()> {
    let links = try!(links_into_values(links)
                     .into_iter()
                     .fold(Ok(vec![]), |acc, elem| {
                        acc.and_then(move |mut v| {
                            elem.map_err_into(LEK::InternalConversionError)
                                .map(|e| {
                                    v.push(e);
                                    v
                                })
                        })
                     }));

    let process = header.set("imag.links", Value::Array(links));
    process_rw_result(process).map(|_| ())
}

/// When Linking A -> B, the specification wants us to link back B -> A.
/// This is a helper function which does this.
fn add_foreign_link(target: &mut Entry, from: StoreId) -> Result<()> {
    target.get_internal_links()
        .and_then(|mut links| {
            links.push(from);
            let links = try!(links_into_values(links)
                             .into_iter()
                             .fold(Ok(vec![]), |acc, elem| {
                                acc.and_then(move |mut v| {
                                    elem.map_err_into(LEK::InternalConversionError)
                                        .map(|e| {
                                            v.push(e);
                                            v
                                        })
                                })
                             }));
            process_rw_result(target.get_header_mut().set("imag.links", Value::Array(links)))
                .map(|_| ())
        })
}

fn process_rw_result(links: StoreResult<Option<Value>>) -> Result<Vec<Link>> {
    use std::path::PathBuf;

    let links = match links {
        Err(e) => {
            debug!("RW action on store failed. Generating LinkError");
            return Err(LEK::EntryHeaderReadError.into_error_with_cause(Box::new(e)))
        },
        Ok(None) => {
            debug!("We got no value from the header!");
            return Ok(vec![])
        },
        Ok(Some(Value::Array(l))) => l,
        Ok(Some(_)) => {
            debug!("We expected an Array for the links, but there was a non-Array!");
            return Err(LEK::ExistingLinkTypeWrong.into());
        }
    };

    if !links.iter().all(|l| is_match!(*l, Value::String(_))) {
        debug!("At least one of the Values which were expected in the Array of links is a non-String!");
        debug!("Generating LinkError");
        return Err(LEK::ExistingLinkTypeWrong.into());
    }

    let links : Vec<Link> = try!(links.into_iter()
        .map(|link| {
            match link {
                Value::String(s) => StoreId::new_baseless(PathBuf::from(s))
                    .map_err_into(LEK::StoreIdError),
                _ => unreachable!(),
            }
        })
        .collect());

    debug!("Ok, the RW action was successful, returning link vector now!");
    Ok(links)
}

<|endoftext|>


<commit_before>//! Types which pin data to its location in memory
//!
//! It is sometimes useful to have objects that are guaranteed to not move,
//! in the sense that their placement in memory does not change, and can thus be relied upon.
//!
//! A prime example of such a scenario would be building self-referential structs,
//! since moving an object with pointers to itself will invalidate them,
//! which could cause undefined behavior.
//!
//! By default, all types in Rust are movable. Rust allows passing all types by-value,
//! and common smart-pointer types such as `Box`, `Rc`, and `&mut` allow replacing and
//! moving the values they contain. In order to prevent objects from moving, they must
//! be pinned by wrapping a pointer to the data in the [`Pin`] type.
//! Doing this prohibits moving the value behind the pointer.
//! For example, `Pin<Box<T>>` functions much like a regular `Box<T>`,
//! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved,
//! but the value behind it cannot.
//!
//! Since data can be moved out of `&mut` and `Box` with functions such as [`swap`],
//! changing the location of the underlying data, [`Pin`] prohibits accessing the
//! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of
//! APIs for accessing and using the value. [`Pin`] also guarantees that no other
//! functions will move the pointed-to value. This allows for the creation of
//! self-references and other special behaviors that are only possible for unmovable
//! values.
//!
//! However, these restrictions are usually not necessary. Many types are always freely
//! movable. These types implement the [`Unpin`] auto-trait, which nullifies the effect
//! of [`Pin`]. For `T: Unpin`, `Pin<Box<T>>` and `Box<T>` function identically, as do
//! `Pin<&mut T>` and `&mut T`.
//!
//! Note that pinning and `Unpin` only affect the pointed-to type. For example, whether
//! or not `Box<T>` is `Unpin` has no affect on the behavior of `Pin<Box<T>>`. Similarly,
//! `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves, even though the
//! `T` underneath them isn't, because the pointers in `Pin<Box<_>>` and `Pin<&mut _>`
//! are always freely movable, even if the data they point to isn't.
//!
//! [`Pin`]: struct.Pin.html
//! [`Unpin`]: ../../std/marker/trait.Unpin.html
//! [`swap`]: ../../std/mem/fn.swap.html
//! [`Box`]: ../../std/boxed/struct.Box.html
//!
//! # Examples
//!
//! ```rust
//! use std::pin::Pin;
//! use std::marker::PhantomPinned;
//! use std::ptr::NonNull;
//!
//! // This is a self-referential struct since the slice field points to the data field.
//! // We cannot inform the compiler about that with a normal reference,
//! // since this pattern cannot be described with the usual borrowing rules.
//! // Instead we use a raw pointer, though one which is known to not be null,
//! // since we know it's pointing at the string.
//! struct Unmovable {
//!     data: String,
//!     slice: NonNull<String>,
//!     _pin: PhantomPinned,
//! }
//!
//! impl Unmovable {
//!     // To ensure the data doesn't move when the function returns,
//!     // we place it in the heap where it will stay for the lifetime of the object,
//!     // and the only way to access it would be through a pointer to it.
//!     fn new(data: String) -> Pin<Box<Self>> {
//!         let res = Unmovable {
//!             data,
//!             // we only create the pointer once the data is in place
//!             // otherwise it will have already moved before we even started
//!             slice: NonNull::dangling(),
//!             _pin: PhantomPinned,
//!         };
//!         let mut boxed = Box::pin(res);
//!
//!         let slice = NonNull::from(&boxed.data);
//!         // we know this is safe because modifying a field doesn't move the whole struct
//!         unsafe {
//!             let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
//!             Pin::get_unchecked_mut(mut_ref).slice = slice;
//!         }
//!         boxed
//!     }
//! }
//!
//! let unmoved = Unmovable::new("hello".to_string());
//! // The pointer should point to the correct location,
//! // so long as the struct hasn't moved.
//! // Meanwhile, we are free to move the pointer around.
//! # #[allow(unused_mut)]
//! let mut still_unmoved = unmoved;
//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
//!
//! // Since our type doesn't implement Unpin, this will fail to compile:
//! // let new_unmoved = Unmovable::new("world".to_string());
//! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
//! ```

#![stable(feature = "pin", since = "1.33.0")]

use fmt;
use marker::{Sized, Unpin};
use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn};

/// A pinned pointer.
///
/// This is a wrapper around a kind of pointer which makes that pointer "pin" its
/// value in place, preventing the value referenced by that pointer from being moved
/// unless it implements [`Unpin`].
///
/// See the [`pin` module] documentation for further explanation on pinning.
///
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
/// [`pin` module]: ../../std/pin/index.html
//
// Note: the derives below are allowed because they all only use `&P`, so they
// cannot move the value behind `pointer`.
#[stable(feature = "pin", since = "1.33.0")]
#[fundamental]
#[repr(transparent)]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Pin
 {
    pointer: P,
}

impl
 Pin

where
    P::Target: Unpin,
{
    /// Construct a new `Pin` around a pointer to some data of a type that
    /// implements `Unpin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn new(pointer: P) -> Pin
 {
        // Safety: the value pointed to is `Unpin`, and so has no requirements
        // around pinning.
        unsafe { Pin::new_unchecked(pointer) }
    }
}

impl
 Pin
 {
    /// Construct a new `Pin` around a reference to some data of a type that
    /// may or may not implement `Unpin`.
    ///
    /// # Safety
    ///
    /// This constructor is unsafe because we cannot guarantee that the data
    /// pointed to by `pointer` is pinned. If the constructed `Pin<P>` does
    /// not guarantee that the data `P` points to is pinned, constructing a
    /// `Pin<P>` is undefined behavior.
    ///
    /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
    /// instead.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub unsafe fn new_unchecked(pointer: P) -> Pin
 {
        Pin { pointer }
    }

    /// Get a pinned shared reference from this pinned pointer.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn as_ref(self: &Pin
) -> Pin<&P::Target> {
        unsafe { Pin::new_unchecked(&*self.pointer) }
    }
}

impl
 Pin
 {
    /// Get a pinned mutable reference from this pinned pointer.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn as_mut(self: &mut Pin
) -> Pin<&mut P::Target> {
        unsafe { Pin::new_unchecked(&mut *self.pointer) }
    }

    /// Assign a new value to the memory behind the pinned reference.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn set(mut self: Pin
, value: P::Target)
    where
        P::Target: Sized,
    {
        *self.pointer = value;
    }
}

impl<'a, T: ?Sized> Pin<&'a T> {
    /// Construct a new pin by mapping the interior value.
    ///
    /// For example, if you  wanted to get a `Pin` of a field of something,
    /// you could use this to get access to that field in one line of code.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that the data you return
    /// will not move so long as the argument value does not move (for example,
    /// because it is one of the fields of that value), and also that you do
    /// not move out of the argument you receive to the interior function.
    #[stable(feature = "pin", since = "1.33.0")]
    pub unsafe fn map_unchecked(self: Pin<&'a T>, func: F) -> Pin<&'a U> where
        F: FnOnce(&T) -> &U,
    {
        let pointer = &*self.pointer;
        let new_pointer = func(pointer);
        Pin::new_unchecked(new_pointer)
    }

    /// Get a shared reference out of a pin.
    ///
    /// Note: `Pin` also implements `Deref` to the target, which can be used
    /// to access the inner value. However, `Deref` only provides a reference
    /// that lives for as long as the borrow of the `Pin`, not the lifetime of
    /// the `Pin` itself. This method allows turning the `Pin` into a reference
    /// with the same lifetime as the original `Pin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn get_ref(self: Pin<&'a T>) -> &'a T {
        self.pointer
    }
}

impl<'a, T: ?Sized> Pin<&'a mut T> {
    /// Convert this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> {
        Pin { pointer: self.pointer }
    }

    /// Get a mutable reference to the data inside of this `Pin`.
    ///
    /// This requires that the data inside this `Pin` is `Unpin`.
    ///
    /// Note: `Pin` also implements `DerefMut` to the data, which can be used
    /// to access the inner value. However, `DerefMut` only provides a reference
    /// that lives for as long as the borrow of the `Pin`, not the lifetime of
    /// the `Pin` itself. This method allows turning the `Pin` into a reference
    /// with the same lifetime as the original `Pin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn get_mut(self: Pin<&'a mut T>) -> &'a mut T
        where T: Unpin,
    {
        self.pointer
    }

    /// Get a mutable reference to the data inside of this `Pin`.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that you will never move
    /// the data out of the mutable reference you receive when you call this
    /// function, so that the invariants on the `Pin` type can be upheld.
    ///
    /// If the underlying data is `Unpin`, `Pin::get_mut` should be used
    /// instead.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub unsafe fn get_unchecked_mut(self: Pin<&'a mut T>) -> &'a mut T {
        self.pointer
    }

    /// Construct a new pin by mapping the interior value.
    ///
    /// For example, if you  wanted to get a `Pin` of a field of something,
    /// you could use this to get access to that field in one line of code.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that the data you return
    /// will not move so long as the argument value does not move (for example,
    /// because it is one of the fields of that value), and also that you do
    /// not move out of the argument you receive to the interior function.
    #[stable(feature = "pin", since = "1.33.0")]
    pub unsafe fn map_unchecked_mut(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where
        F: FnOnce(&mut T) -> &mut U,
    {
        let pointer = Pin::get_unchecked_mut(self);
        let new_pointer = func(pointer);
        Pin::new_unchecked(new_pointer)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 Deref for Pin
 {
    type Target = P::Target;
    fn deref(&self) -> &P::Target {
        Pin::get_ref(Pin::as_ref(self))
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 DerefMut for Pin

where
    P::Target: Unpin
{
    fn deref_mut(&mut self) -> &mut P::Target {
        Pin::get_mut(Pin::as_mut(self))
    }
}

#[unstable(feature = "receiver_trait", issue = "0")]
impl
 Receiver for Pin
 {}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Debug for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.pointer, f)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Display for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.pointer, f)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Pointer for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(&self.pointer, f)
    }
}

// Note: this means that any impl of `CoerceUnsized` that allows coercing from
// a type that impls `Deref<Target=impl !Unpin>` to a type that impls
// `Deref<Target=Unpin>` is unsound. Any such impl would probably be unsound
// for other reasons, though, so we just need to take care not to allow such
// impls to land in std.
#[stable(feature = "pin", since = "1.33.0")]
impl
 CoerceUnsized<Pin> for Pin

where
    P: CoerceUnsized,
{}

#[stable(feature = "pin", since = "1.33.0")]
impl<'a, P, U> DispatchFromDyn<Pin> for Pin

where
    P: DispatchFromDyn,
{}
<commit_msg>Reborrow Pin
 using &mut in `Pin::set`<commit_after>//! Types which pin data to its location in memory
//!
//! It is sometimes useful to have objects that are guaranteed to not move,
//! in the sense that their placement in memory does not change, and can thus be relied upon.
//!
//! A prime example of such a scenario would be building self-referential structs,
//! since moving an object with pointers to itself will invalidate them,
//! which could cause undefined behavior.
//!
//! By default, all types in Rust are movable. Rust allows passing all types by-value,
//! and common smart-pointer types such as `Box`, `Rc`, and `&mut` allow replacing and
//! moving the values they contain. In order to prevent objects from moving, they must
//! be pinned by wrapping a pointer to the data in the [`Pin`] type.
//! Doing this prohibits moving the value behind the pointer.
//! For example, `Pin<Box<T>>` functions much like a regular `Box<T>`,
//! but doesn't allow moving `T`. The pointer value itself (the `Box`) can still be moved,
//! but the value behind it cannot.
//!
//! Since data can be moved out of `&mut` and `Box` with functions such as [`swap`],
//! changing the location of the underlying data, [`Pin`] prohibits accessing the
//! underlying pointer type (the `&mut` or `Box`) directly, and provides its own set of
//! APIs for accessing and using the value. [`Pin`] also guarantees that no other
//! functions will move the pointed-to value. This allows for the creation of
//! self-references and other special behaviors that are only possible for unmovable
//! values.
//!
//! However, these restrictions are usually not necessary. Many types are always freely
//! movable. These types implement the [`Unpin`] auto-trait, which nullifies the effect
//! of [`Pin`]. For `T: Unpin`, `Pin<Box<T>>` and `Box<T>` function identically, as do
//! `Pin<&mut T>` and `&mut T`.
//!
//! Note that pinning and `Unpin` only affect the pointed-to type. For example, whether
//! or not `Box<T>` is `Unpin` has no affect on the behavior of `Pin<Box<T>>`. Similarly,
//! `Pin<Box<T>>` and `Pin<&mut T>` are always `Unpin` themselves, even though the
//! `T` underneath them isn't, because the pointers in `Pin<Box<_>>` and `Pin<&mut _>`
//! are always freely movable, even if the data they point to isn't.
//!
//! [`Pin`]: struct.Pin.html
//! [`Unpin`]: ../../std/marker/trait.Unpin.html
//! [`swap`]: ../../std/mem/fn.swap.html
//! [`Box`]: ../../std/boxed/struct.Box.html
//!
//! # Examples
//!
//! ```rust
//! use std::pin::Pin;
//! use std::marker::PhantomPinned;
//! use std::ptr::NonNull;
//!
//! // This is a self-referential struct since the slice field points to the data field.
//! // We cannot inform the compiler about that with a normal reference,
//! // since this pattern cannot be described with the usual borrowing rules.
//! // Instead we use a raw pointer, though one which is known to not be null,
//! // since we know it's pointing at the string.
//! struct Unmovable {
//!     data: String,
//!     slice: NonNull<String>,
//!     _pin: PhantomPinned,
//! }
//!
//! impl Unmovable {
//!     // To ensure the data doesn't move when the function returns,
//!     // we place it in the heap where it will stay for the lifetime of the object,
//!     // and the only way to access it would be through a pointer to it.
//!     fn new(data: String) -> Pin<Box<Self>> {
//!         let res = Unmovable {
//!             data,
//!             // we only create the pointer once the data is in place
//!             // otherwise it will have already moved before we even started
//!             slice: NonNull::dangling(),
//!             _pin: PhantomPinned,
//!         };
//!         let mut boxed = Box::pin(res);
//!
//!         let slice = NonNull::from(&boxed.data);
//!         // we know this is safe because modifying a field doesn't move the whole struct
//!         unsafe {
//!             let mut_ref: Pin<&mut Self> = Pin::as_mut(&mut boxed);
//!             Pin::get_unchecked_mut(mut_ref).slice = slice;
//!         }
//!         boxed
//!     }
//! }
//!
//! let unmoved = Unmovable::new("hello".to_string());
//! // The pointer should point to the correct location,
//! // so long as the struct hasn't moved.
//! // Meanwhile, we are free to move the pointer around.
//! # #[allow(unused_mut)]
//! let mut still_unmoved = unmoved;
//! assert_eq!(still_unmoved.slice, NonNull::from(&still_unmoved.data));
//!
//! // Since our type doesn't implement Unpin, this will fail to compile:
//! // let new_unmoved = Unmovable::new("world".to_string());
//! // std::mem::swap(&mut *still_unmoved, &mut *new_unmoved);
//! ```

#![stable(feature = "pin", since = "1.33.0")]

use fmt;
use marker::{Sized, Unpin};
use ops::{Deref, DerefMut, Receiver, CoerceUnsized, DispatchFromDyn};

/// A pinned pointer.
///
/// This is a wrapper around a kind of pointer which makes that pointer "pin" its
/// value in place, preventing the value referenced by that pointer from being moved
/// unless it implements [`Unpin`].
///
/// See the [`pin` module] documentation for further explanation on pinning.
///
/// [`Unpin`]: ../../std/marker/trait.Unpin.html
/// [`pin` module]: ../../std/pin/index.html
//
// Note: the derives below are allowed because they all only use `&P`, so they
// cannot move the value behind `pointer`.
#[stable(feature = "pin", since = "1.33.0")]
#[fundamental]
#[repr(transparent)]
#[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct Pin
 {
    pointer: P,
}

impl
 Pin

where
    P::Target: Unpin,
{
    /// Construct a new `Pin` around a pointer to some data of a type that
    /// implements `Unpin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn new(pointer: P) -> Pin
 {
        // Safety: the value pointed to is `Unpin`, and so has no requirements
        // around pinning.
        unsafe { Pin::new_unchecked(pointer) }
    }
}

impl
 Pin
 {
    /// Construct a new `Pin` around a reference to some data of a type that
    /// may or may not implement `Unpin`.
    ///
    /// # Safety
    ///
    /// This constructor is unsafe because we cannot guarantee that the data
    /// pointed to by `pointer` is pinned. If the constructed `Pin<P>` does
    /// not guarantee that the data `P` points to is pinned, constructing a
    /// `Pin<P>` is undefined behavior.
    ///
    /// If `pointer` dereferences to an `Unpin` type, `Pin::new` should be used
    /// instead.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub unsafe fn new_unchecked(pointer: P) -> Pin
 {
        Pin { pointer }
    }

    /// Get a pinned shared reference from this pinned pointer.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn as_ref(self: &Pin
) -> Pin<&P::Target> {
        unsafe { Pin::new_unchecked(&*self.pointer) }
    }
}

impl
 Pin
 {
    /// Get a pinned mutable reference from this pinned pointer.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn as_mut(self: &mut Pin
) -> Pin<&mut P::Target> {
        unsafe { Pin::new_unchecked(&mut *self.pointer) }
    }

    /// Assign a new value to the memory behind the pinned reference.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn set(self: &mut Pin
, value: P::Target)
    where
        P::Target: Sized,
    {
        *(self.pointer) = value;
    }
}

impl<'a, T: ?Sized> Pin<&'a T> {
    /// Construct a new pin by mapping the interior value.
    ///
    /// For example, if you  wanted to get a `Pin` of a field of something,
    /// you could use this to get access to that field in one line of code.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that the data you return
    /// will not move so long as the argument value does not move (for example,
    /// because it is one of the fields of that value), and also that you do
    /// not move out of the argument you receive to the interior function.
    #[stable(feature = "pin", since = "1.33.0")]
    pub unsafe fn map_unchecked(self: Pin<&'a T>, func: F) -> Pin<&'a U> where
        F: FnOnce(&T) -> &U,
    {
        let pointer = &*self.pointer;
        let new_pointer = func(pointer);
        Pin::new_unchecked(new_pointer)
    }

    /// Get a shared reference out of a pin.
    ///
    /// Note: `Pin` also implements `Deref` to the target, which can be used
    /// to access the inner value. However, `Deref` only provides a reference
    /// that lives for as long as the borrow of the `Pin`, not the lifetime of
    /// the `Pin` itself. This method allows turning the `Pin` into a reference
    /// with the same lifetime as the original `Pin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn get_ref(self: Pin<&'a T>) -> &'a T {
        self.pointer
    }
}

impl<'a, T: ?Sized> Pin<&'a mut T> {
    /// Convert this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn into_ref(self: Pin<&'a mut T>) -> Pin<&'a T> {
        Pin { pointer: self.pointer }
    }

    /// Get a mutable reference to the data inside of this `Pin`.
    ///
    /// This requires that the data inside this `Pin` is `Unpin`.
    ///
    /// Note: `Pin` also implements `DerefMut` to the data, which can be used
    /// to access the inner value. However, `DerefMut` only provides a reference
    /// that lives for as long as the borrow of the `Pin`, not the lifetime of
    /// the `Pin` itself. This method allows turning the `Pin` into a reference
    /// with the same lifetime as the original `Pin`.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub fn get_mut(self: Pin<&'a mut T>) -> &'a mut T
        where T: Unpin,
    {
        self.pointer
    }

    /// Get a mutable reference to the data inside of this `Pin`.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that you will never move
    /// the data out of the mutable reference you receive when you call this
    /// function, so that the invariants on the `Pin` type can be upheld.
    ///
    /// If the underlying data is `Unpin`, `Pin::get_mut` should be used
    /// instead.
    #[stable(feature = "pin", since = "1.33.0")]
    #[inline(always)]
    pub unsafe fn get_unchecked_mut(self: Pin<&'a mut T>) -> &'a mut T {
        self.pointer
    }

    /// Construct a new pin by mapping the interior value.
    ///
    /// For example, if you  wanted to get a `Pin` of a field of something,
    /// you could use this to get access to that field in one line of code.
    ///
    /// # Safety
    ///
    /// This function is unsafe. You must guarantee that the data you return
    /// will not move so long as the argument value does not move (for example,
    /// because it is one of the fields of that value), and also that you do
    /// not move out of the argument you receive to the interior function.
    #[stable(feature = "pin", since = "1.33.0")]
    pub unsafe fn map_unchecked_mut(self: Pin<&'a mut T>, func: F) -> Pin<&'a mut U> where
        F: FnOnce(&mut T) -> &mut U,
    {
        let pointer = Pin::get_unchecked_mut(self);
        let new_pointer = func(pointer);
        Pin::new_unchecked(new_pointer)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 Deref for Pin
 {
    type Target = P::Target;
    fn deref(&self) -> &P::Target {
        Pin::get_ref(Pin::as_ref(self))
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 DerefMut for Pin

where
    P::Target: Unpin
{
    fn deref_mut(&mut self) -> &mut P::Target {
        Pin::get_mut(Pin::as_mut(self))
    }
}

#[unstable(feature = "receiver_trait", issue = "0")]
impl
 Receiver for Pin
 {}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Debug for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Debug::fmt(&self.pointer, f)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Display for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.pointer, f)
    }
}

#[stable(feature = "pin", since = "1.33.0")]
impl
 fmt::Pointer for Pin
 {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Pointer::fmt(&self.pointer, f)
    }
}

// Note: this means that any impl of `CoerceUnsized` that allows coercing from
// a type that impls `Deref<Target=impl !Unpin>` to a type that impls
// `Deref<Target=Unpin>` is unsound. Any such impl would probably be unsound
// for other reasons, though, so we just need to take care not to allow such
// impls to land in std.
#[stable(feature = "pin", since = "1.33.0")]
impl
 CoerceUnsized<Pin> for Pin

where
    P: CoerceUnsized,
{}

#[stable(feature = "pin", since = "1.33.0")]
impl<'a, P, U> DispatchFromDyn<Pin> for Pin

where
    P: DispatchFromDyn,
{}
<|endoftext|>


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

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two implementations,
//! the `TerminfoTerminal`, which uses control characters from a
//! [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Examples
//!
//! ```no_run
//! extern crate term;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     (write!(t, "hello, ")).unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     (writeln!(t, "world!")).unwrap();
//!
//!     t.reset().unwrap();
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![crate_name = "term"]
#![experimental]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/",
       html_playground_url = "http://play.rust-lang.org/")]

#![allow(unknown_features)]
#![feature(macro_rules, phase, slicing_syntax, globs)]

#![deny(missing_docs)]

#[phase(plugin, link)] extern crate log;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::IoResult;

pub mod terminfo;

#[cfg(windows)]
mod win;

/// A hack to work around the fact that `Box<Writer + Send>` does not
/// currently implement `Writer`.
pub struct WriterWrapper {
    wrapped: Box<Writer + Send>,
}

impl Writer for WriterWrapper {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.wrapped.write(buf)
    }

    #[inline]
    fn flush(&mut self) -> IoResult<()> {
        self.wrapped.flush()
    }
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stdout() as Box<Writer + Send>,
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    let ti = TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stdout() as Box<Writer + Send>,
    });

    match ti {
        Some(t) => Some(t),
        None => {
            WinConsole::new(WriterWrapper {
                wrapped: box std::io::stdout() as Box<Writer + Send>,
            })
        }
    }
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stderr() as Box<Writer + Send>,
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    let ti = TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stderr() as Box<Writer + Send>,
    });

    match ti {
        Some(t) => Some(t),
        None => {
            WinConsole::new(WriterWrapper {
                wrapped: box std::io::stderr() as Box<Writer + Send>,
            })
        }
    }
}

/// Terminal color definitions
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK:   Color = 0u16;
    pub const RED:     Color = 1u16;
    pub const GREEN:   Color = 2u16;
    pub const YELLOW:  Color = 3u16;
    pub const BLUE:    Color = 4u16;
    pub const MAGENTA: Color = 5u16;
    pub const CYAN:    Color = 6u16;
    pub const WHITE:   Color = 7u16;

    pub const BRIGHT_BLACK:   Color = 8u16;
    pub const BRIGHT_RED:     Color = 9u16;
    pub const BRIGHT_GREEN:   Color = 10u16;
    pub const BRIGHT_YELLOW:  Color = 11u16;
    pub const BRIGHT_BLUE:    Color = 12u16;
    pub const BRIGHT_MAGENTA: Color = 13u16;
    pub const BRIGHT_CYAN:    Color = 14u16;
    pub const BRIGHT_WHITE:   Color = 15u16;
}

/// Terminal attributes
pub mod attr {
    pub use self::Attr::*;

    /// Terminal attributes for use with term.attr().
    ///
    /// Most attributes can only be turned on and must be turned off with term.reset().
    /// The ones that can be turned off explicitly take a boolean value.
    /// Color is also represented as an attribute for convenience.
    #[deriving(Copy)]
    pub enum Attr {
        /// Bold (or possibly bright) mode
        Bold,
        /// Dim mode, also called faint or half-bright. Often not supported
        Dim,
        /// Italics mode. Often not supported
        Italic(bool),
        /// Underline mode
        Underline(bool),
        /// Blink mode
        Blink,
        /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
        Standout(bool),
        /// Reverse mode, inverts the foreground and background colors
        Reverse,
        /// Secure mode, also called invis mode. Hides the printed text
        Secure,
        /// Convenience attribute to set the foreground color
        ForegroundColor(super::color::Color),
        /// Convenience attribute to set the background color
        BackgroundColor(super::color::Color)
    }
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal<T: Writer>: Writer {
    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn fg(&mut self, color: color::Color) -> IoResult<bool>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn bg(&mut self, color: color::Color) -> IoResult<bool>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
    /// there was an I/O error.
    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: attr::Attr) -> bool;

    /// Resets all terminal attributes and color to the default.
    /// Returns `Ok()`.
    fn reset(&mut self) -> IoResult<()>;

    /// Gets an immutable reference to the stream inside
    fn get_ref<'a>(&'a self) -> &'a T;

    /// Gets a mutable reference to the stream inside
    fn get_mut<'a>(&'a mut self) -> &'a mut T;
}

/// A terminal which can be unwrapped.
pub trait UnwrappableTerminal<T: Writer>: Terminal<T> {
    /// Returns the contained stream, destroying the `Terminal`
    fn unwrap(self) -> T;
}
<commit_msg>term: Deprecate the in-tree version<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Terminal formatting library.
//!
//! This crate provides the `Terminal` trait, which abstracts over an [ANSI
//! Terminal][ansi] to provide color printing, among other things. There are two implementations,
//! the `TerminfoTerminal`, which uses control characters from a
//! [terminfo][ti] database, and `WinConsole`, which uses the [Win32 Console
//! API][win].
//!
//! # Examples
//!
//! ```no_run
//! extern crate term;
//!
//! fn main() {
//!     let mut t = term::stdout().unwrap();
//!
//!     t.fg(term::color::GREEN).unwrap();
//!     (write!(t, "hello, ")).unwrap();
//!
//!     t.fg(term::color::RED).unwrap();
//!     (writeln!(t, "world!")).unwrap();
//!
//!     t.reset().unwrap();
//! }
//! ```
//!
//! [ansi]: https://en.wikipedia.org/wiki/ANSI_escape_code
//! [win]: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682010%28v=vs.85%29.aspx
//! [ti]: https://en.wikipedia.org/wiki/Terminfo

#![crate_name = "term"]
#![experimental = "use the crates.io `term` library instead"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/",
       html_playground_url = "http://play.rust-lang.org/")]

#![allow(unknown_features)]
#![feature(macro_rules, phase, slicing_syntax, globs)]

#![deny(missing_docs)]

#[phase(plugin, link)] extern crate log;

pub use terminfo::TerminfoTerminal;
#[cfg(windows)]
pub use win::WinConsole;

use std::io::IoResult;

pub mod terminfo;

#[cfg(windows)]
mod win;

/// A hack to work around the fact that `Box<Writer + Send>` does not
/// currently implement `Writer`.
pub struct WriterWrapper {
    wrapped: Box<Writer + Send>,
}

impl Writer for WriterWrapper {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
        self.wrapped.write(buf)
    }

    #[inline]
    fn flush(&mut self) -> IoResult<()> {
        self.wrapped.flush()
    }
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stdout() as Box<Writer + Send>,
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    let ti = TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stdout() as Box<Writer + Send>,
    });

    match ti {
        Some(t) => Some(t),
        None => {
            WinConsole::new(WriterWrapper {
                wrapped: box std::io::stdout() as Box<Writer + Send>,
            })
        }
    }
}

#[cfg(not(windows))]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stderr() as Box<Writer + Send>,
    })
}

#[cfg(windows)]
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send>> {
    let ti = TerminfoTerminal::new(WriterWrapper {
        wrapped: box std::io::stderr() as Box<Writer + Send>,
    });

    match ti {
        Some(t) => Some(t),
        None => {
            WinConsole::new(WriterWrapper {
                wrapped: box std::io::stderr() as Box<Writer + Send>,
            })
        }
    }
}

/// Terminal color definitions
pub mod color {
    /// Number for a terminal color
    pub type Color = u16;

    pub const BLACK:   Color = 0u16;
    pub const RED:     Color = 1u16;
    pub const GREEN:   Color = 2u16;
    pub const YELLOW:  Color = 3u16;
    pub const BLUE:    Color = 4u16;
    pub const MAGENTA: Color = 5u16;
    pub const CYAN:    Color = 6u16;
    pub const WHITE:   Color = 7u16;

    pub const BRIGHT_BLACK:   Color = 8u16;
    pub const BRIGHT_RED:     Color = 9u16;
    pub const BRIGHT_GREEN:   Color = 10u16;
    pub const BRIGHT_YELLOW:  Color = 11u16;
    pub const BRIGHT_BLUE:    Color = 12u16;
    pub const BRIGHT_MAGENTA: Color = 13u16;
    pub const BRIGHT_CYAN:    Color = 14u16;
    pub const BRIGHT_WHITE:   Color = 15u16;
}

/// Terminal attributes
pub mod attr {
    pub use self::Attr::*;

    /// Terminal attributes for use with term.attr().
    ///
    /// Most attributes can only be turned on and must be turned off with term.reset().
    /// The ones that can be turned off explicitly take a boolean value.
    /// Color is also represented as an attribute for convenience.
    #[deriving(Copy)]
    pub enum Attr {
        /// Bold (or possibly bright) mode
        Bold,
        /// Dim mode, also called faint or half-bright. Often not supported
        Dim,
        /// Italics mode. Often not supported
        Italic(bool),
        /// Underline mode
        Underline(bool),
        /// Blink mode
        Blink,
        /// Standout mode. Often implemented as Reverse, sometimes coupled with Bold
        Standout(bool),
        /// Reverse mode, inverts the foreground and background colors
        Reverse,
        /// Secure mode, also called invis mode. Hides the printed text
        Secure,
        /// Convenience attribute to set the foreground color
        ForegroundColor(super::color::Color),
        /// Convenience attribute to set the background color
        BackgroundColor(super::color::Color)
    }
}

/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal<T: Writer>: Writer {
    /// Sets the foreground color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn fg(&mut self, color: color::Color) -> IoResult<bool>;

    /// Sets the background color to the given color.
    ///
    /// If the color is a bright color, but the terminal only supports 8 colors,
    /// the corresponding normal color will be used instead.
    ///
    /// Returns `Ok(true)` if the color was set, `Ok(false)` otherwise, and `Err(e)`
    /// if there was an I/O error.
    fn bg(&mut self, color: color::Color) -> IoResult<bool>;

    /// Sets the given terminal attribute, if supported.  Returns `Ok(true)`
    /// if the attribute was supported, `Ok(false)` otherwise, and `Err(e)` if
    /// there was an I/O error.
    fn attr(&mut self, attr: attr::Attr) -> IoResult<bool>;

    /// Returns whether the given terminal attribute is supported.
    fn supports_attr(&self, attr: attr::Attr) -> bool;

    /// Resets all terminal attributes and color to the default.
    /// Returns `Ok()`.
    fn reset(&mut self) -> IoResult<()>;

    /// Gets an immutable reference to the stream inside
    fn get_ref<'a>(&'a self) -> &'a T;

    /// Gets a mutable reference to the stream inside
    fn get_mut<'a>(&'a mut self) -> &'a mut T;
}

/// A terminal which can be unwrapped.
pub trait UnwrappableTerminal<T: Writer>: Terminal<T> {
    /// Returns the contained stream, destroying the `Terminal`
    fn unwrap(self) -> T;
}
<|endoftext|>


<commit_before>pub mod config;

pub use config::Config;

use heck::SnakeCase;
use lucet_module::bindings::Bindings;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

pub fn hostcall_name(m: &witx::Module, f: &witx::InterfaceFunc) -> String {
    format!(
        "hostcall_{}_{}",
        m.name.as_str().to_snake_case(),
        f.name.as_str().to_snake_case()
    )
}
pub fn hostcall_bindings(_doc: &witx::Document) -> Bindings {
    unimplemented!()
}

pub fn generate(doc: &witx::Document, config: &Config) -> TokenStream {
    let names = wiggle_generate::Names::new(&config.wiggle);
    let fs = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            let coretype = f.core_type();
            let func_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                let atom = names.atom_type(a.repr());
                quote!(#name: #atom)
            });
            let call_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                quote!(#name)
            });
            let rets = coretype
                .ret
                .as_ref()
                .map(|r| {
                    let atom = names.atom_type(r.repr());
                    quote!(#atom)
                })
                .unwrap_or(quote!(()));
            let mod_name = names.module(&m.name);
            let method_name = names.func(&f.name);
            let ctx_type = config.wiggle.ctx.name.clone();
            let ctx_constructor = config.constructor.clone();
            quote! {
                #[lucet_hostcall]
                #[no_mangle]
                pub fn #name(vmctx: &mut lucet_runtime::vmctx::Vmctx, #(#func_args),*) -> #rets {
                    let memory= lucet_wiggle_runtime::LucetMemory::new(vmctx);
                    let mut ctx: #ctx_type = #ctx_constructor;
                    #mod_name::#method_name(&ctx, &memory, #(#call_args),*)
                }
            }
        });
        quote!(#(#fs)*)
    });

    let init = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            quote!(#name as _)
        });
        quote!(#(#fs),*)
    });

    quote! {
        use lucet_runtime::lucet_hostcall;
        #(#fs)*
        pub fn init() {
            let funcs: &[*const extern "C" fn()] = &[
                #(#init),*
            ];
            ::std::mem::forget(::std::rc::Rc::new(funcs));
        }
    }
}
<commit_msg>fill in bindings generation<commit_after>pub mod config;

pub use config::Config;

use heck::SnakeCase;
use lucet_module::bindings::Bindings;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};

pub fn hostcall_name(m: &witx::Module, f: &witx::InterfaceFunc) -> String {
    format!(
        "hostcall_{}_{}",
        m.name.as_str().to_snake_case(),
        f.name.as_str().to_snake_case()
    )
}
pub fn hostcall_bindings(doc: &witx::Document) -> Bindings {
    let bs = doc
        .modules()
        .map(|m| {
            (
                m.name.as_str().to_owned(),
                m.funcs()
                    .map(|f| (f.name.as_str().to_owned(), hostcall_name(&m, &f)))
                    .collect(),
            )
        })
        .collect();
    Bindings::new(bs)
}

pub fn generate(doc: &witx::Document, config: &Config) -> TokenStream {
    let names = wiggle_generate::Names::new(&config.wiggle);
    let fs = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            let coretype = f.core_type();
            let func_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                let atom = names.atom_type(a.repr());
                quote!(#name: #atom)
            });
            let call_args = coretype.args.iter().map(|a| {
                let name = names.func_core_arg(a);
                quote!(#name)
            });
            let rets = coretype
                .ret
                .as_ref()
                .map(|r| {
                    let atom = names.atom_type(r.repr());
                    quote!(#atom)
                })
                .unwrap_or(quote!(()));
            let mod_name = names.module(&m.name);
            let method_name = names.func(&f.name);
            let ctx_type = config.wiggle.ctx.name.clone();
            let ctx_constructor = config.constructor.clone();
            quote! {
                #[lucet_hostcall]
                #[no_mangle]
                pub fn #name(vmctx: &mut lucet_runtime::vmctx::Vmctx, #(#func_args),*) -> #rets {
                    let memory= lucet_wiggle_runtime::LucetMemory::new(vmctx);
                    let mut ctx: #ctx_type = #ctx_constructor;
                    #mod_name::#method_name(&ctx, &memory, #(#call_args),*)
                }
            }
        });
        quote!(#(#fs)*)
    });

    let init = doc.modules().map(|m| {
        let fs = m.funcs().map(|f| {
            let name = format_ident!("{}", hostcall_name(&m, &f));
            quote!(#name as _)
        });
        quote!(#(#fs),*)
    });

    quote! {
        use lucet_runtime::lucet_hostcall;
        #(#fs)*
        pub fn init() {
            let funcs: &[*const extern "C" fn()] = &[
                #(#init),*
            ];
            ::std::mem::forget(::std::rc::Rc::new(funcs));
        }
    }
}
<|endoftext|>


<commit_before>extern crate rocksdb;

mod disk_db;

pub use self::disk_db::DiskDB;

#[derive(Debug)]
pub struct DBError {
    message: String
}

impl DBError {
    fn new(message: String) -> Self {
        Self { message }
    }
}

pub trait ClientDB: Sync + Send {
    fn get(&self, col: &str, key: &[u8])
        -> Result<Option<&[u8]>, DBError>;
}
<commit_msg>Implement get and put on ClientDB trait<commit_after>extern crate rocksdb;

mod disk_db;

pub use self::disk_db::DiskDB;

type DBValue = Vec<u8>;

#[derive(Debug)]
pub struct DBError {
    message: String
}

impl DBError {
    pub fn new(message: String) -> Self {
        Self { message }
    }
}

pub trait ClientDB: Sync + Send {
    fn get(&self, col: &str, key: &[u8])
        -> Result<Option<DBValue>, DBError>;

    fn put(&self, col: &str, key: &[u8], val: &[u8])
        -> Result<(), DBError>;
}
<|endoftext|>


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

//! The `PhilipsHueAdapter`
//!
//! This adapter implements support for Philips Hue bridges.

// Clippy complains about `hub_id` and `hub_ip` being too similar,
// suggests renaming to `hub_i_p`.
#![allow(clippy)]

pub mod discovery;
pub mod http;
pub mod hub;
pub mod hub_api;
pub mod lights;
pub mod structs;

use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::channel::*;
use foxbox_taxonomy::manager::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::{ Color, OnOff, Type, TypeError, Value };

use std::collections::HashMap;
use std::sync::{ Arc, Mutex };
use std::thread;
use self::hub::Hub;
use self::lights::Light;
use traits::Controller;
use transformable_channels::mpsc::*;

static ADAPTER_NAME: &'static str = "Philips Hue adapter (built-in)";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

/// Philips Hue Adapter's main loop handles messages of these types.
#[allow(dead_code)]
pub enum HueAction {
    TriggerDiscovery,
    AddHub(String, String),         // Hub id, hub ip
    AddLight(String, String),       // Hub id, light id
    RemoveHub(String),              // Hub id
    RemoveLight(String, String),    // Hub id, light id
    StopAdapter,
}

pub type LightServiceMap = Arc<Mutex<LightServiceMapInternal>>;

pub struct LightServiceMapInternal {
    getters: HashMap<Id<Channel>, Light>,
    setters: HashMap<Id<Channel>, Light>,
}

#[derive(Clone)]
pub struct PhilipsHueAdapter<C> {
    /// A reference to the AdapterManager.
    manager: Arc<AdapterManager>,

    controller: C,

    services: LightServiceMap,

    /// Tx channel for sending messages to the adapter's main loop.
    tx: Arc<Mutex<RawSender<HueAction>>>,

    /// The ID of this adapter (permanently fixed)
    adapter_id: Id<AdapterId>,
}

impl<C: Controller> PhilipsHueAdapter<C> {
    #[allow(dead_code)]
    pub fn init(manager: &Arc<AdapterManager>, controller: C) -> Result<(), Error> {
        let services = Arc::new(Mutex::new(LightServiceMapInternal {
            getters: HashMap::new(),
            setters: HashMap::new(),
        }));

        let (tx, rx) = channel();

        let adapter = PhilipsHueAdapter {
            manager: manager.clone(),
            controller: controller.clone(),
            services: services.clone(),
            tx: Arc::new(Mutex::new(tx.clone())),
            adapter_id: create_adapter_id(),
        };

        try!(manager.add_adapter(Arc::new(adapter.clone())));

        // Trigger discovery
        let _ = tx.send(HueAction::TriggerDiscovery);

        let manager = manager.clone();
        let services = services.clone();

        thread::spawn(move || {
            debug!("Starting Philips Hue Adapter main thread");

            let mut hubs: HashMap<String, Arc<Mutex<Hub<C>>>> = HashMap::new();
            let mut lights: HashMap<String, Arc<Mutex<Light>>> = HashMap::new();

            let discovery = discovery::Discovery::new(adapter.clone());

            'recv: for action in rx {
                match action {
                    HueAction::TriggerDiscovery => {
                        debug!("HueAction::TriggerDiscovery received");
                        discovery.do_discovery();
                    },
                    HueAction::AddHub(hub_id, hub_ip) => {
                        debug!("HueAction::AddHub({},{}) received", hub_id, hub_ip);
                        let is_known_hub = hubs.contains_key(&hub_id);
                        if is_known_hub {
                            let mut hub = hubs.get_mut(&hub_id).unwrap().lock().unwrap();
                            hub.update_ip(&hub_ip);
                        } else {
                            let new_hub = Hub::new(adapter.clone(), &hub_id, &hub_ip);
                            new_hub.start();
                            hubs.insert(hub_id, Arc::new(Mutex::new(new_hub)));
                        }
                    },
                    HueAction::AddLight(hub_id, light_id) => {
                        debug!("HueAction::AddLight({},{}) received", hub_id, light_id);
                        let id = format!("{}::{}", hub_id, light_id);
                        let is_known_light = lights.contains_key(&id);
                        if is_known_light {
                            warn!("Ignoring request to add pre-existing Hue light");
                        } else {
                            // TODO: check if hub is known
                            let hub = hubs.get(&hub_id).unwrap().lock().unwrap();
                            let mut new_light: Light = Light::new(hub.api.clone(), &hub_id,
                                &light_id);
                            let _ = new_light.init_service(manager.clone(), services.clone());
                            new_light.start();
                            lights.insert(id, Arc::new(Mutex::new(new_light)));
                        }
                    },
                    // Currently unused
                    HueAction::RemoveHub(hub_id) => {
                        debug!("HueAction::RemoveHub({}) received", hub_id);
                        let is_known_hub = hubs.contains_key(&hub_id);
                        if is_known_hub {
                            let _ = hubs.remove(&hub_id);
                        } else {
                            warn!("Ignoring request to remove unknown Hue hub");
                        }
                    },
                    // Currently unused
                    HueAction::RemoveLight(hub_id, light_id) => {
                        debug!("HueAction::RemoveLight({},{}) received", hub_id, light_id);
                        let id = format!("{}::{}", hub_id, light_id);
                        let is_known_light = lights.contains_key(&id);
                        if is_known_light {
                            let _ = lights.remove(&id);
                        } else {
                            warn!("Ignoring request to remove unknown Hue hub");
                        }
                    },
                    // TODO: Currently unused, but required for teardown
                    HueAction::StopAdapter => {
                        debug!("HueAction::StopAdapter received");
                        break;
                    },
                }
            }

            debug!("Stopping Philips Hue Adapter main thread.");

            for (_, light) in lights.drain() {
                light.lock().unwrap().stop();
            }

            for (_, hub) in hubs.drain() {
                hub.lock().unwrap().stop();
            }

        });

        Ok(())
    }

    // TODO: This should be called on tear-down by the adapter manager or
    // the taxonomy manager, but currently it can't be because the adapter
    // manager is never given a reference and .stop() is not part of a
    // trait shared amongst adapters.
    #[allow(dead_code)]
    pub fn stop(&self) {
        let _ = self.tx.lock().unwrap().send(HueAction::StopAdapter);
    }

    pub fn send(&self, action: HueAction) {
        let _ = self.tx.lock().unwrap().send(action);
    }
}

pub fn create_adapter_id() -> Id<AdapterId> {
    Id::new("philips_hue@link.mozilla.org")
}

pub fn create_light_id(hub_id: &str, light_id: &str) -> Id<ServiceId> {
    Id::new(&format!("service:{}.{}.{}", light_id, hub_id, create_adapter_id()))
}

pub fn create_channel_id(op: &str, hub_id: &str, light_id: &str) -> Id<Channel> {
    Id::new(&format!("channel:{}.{}.{}.{}", op, light_id, hub_id, create_adapter_id()))
}

impl<C: Controller> Adapter for PhilipsHueAdapter<C> {
    fn id(&self) -> Id<AdapterId> {
        create_adapter_id()
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32; 4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Channel>>, _: User)
        -> ResultMap<Id<Channel>, Option<Value>, Error>
    {
        set.drain(..).map(|id| {
            let light = match self.services.lock().unwrap().getters.get(&id) {
                Some(light) => light.clone(),
                None => return (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
            };

            if id == light.get_available_id {
                if light.get_available() {
                    return (id, Ok(Some(Value::OnOff(OnOff::On))));
                } else {
                    return (id, Ok(Some(Value::OnOff(OnOff::Off))));
                }
            }
            if id == light.channel_power_id {
                if light.get_power() {
                    return (id, Ok(Some(Value::OnOff(OnOff::On))));
                } else {
                    return (id, Ok(Some(Value::OnOff(OnOff::Off))));
                }
            }
            if id == light.channel_color_id {
                let (h, s, v) = light.get_color();
                return (id, Ok(Some(Value::Color(Color::HSV(h, s, v)))));
            }

            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Channel>, Value>, _: User)
        -> ResultMap<Id<Channel>, (), Error>
    {
        values.drain().map(|(id, value)| {
            let light = match self.services.lock().unwrap().setters.get(&id) {
                Some(light) => light.clone(),
                None => return (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
            };

            if id == light.channel_power_id {
                match value {
                    Value::OnOff(OnOff::On)  => { light.set_power(true); },
                    Value::OnOff(OnOff::Off) => { light.set_power(false); },
                    _ => {
                        return (id, Err(Error::TypeError(TypeError {
                                        got: value.get_type(),
                                        expected: Type::OnOff
                                    })));
                    }
                }
                return (id, Ok(()));
            }
            if id == light.channel_color_id {
                match value {
                    Value::Color(Color::HSV(h, s, v)) => { light.set_color((h, s, v)); },
                    _ => {
                        return (id, Err(Error::TypeError(TypeError {
                                        got: value.get_type(),
                                        expected: Type::Color
                                    })));
                    }
                }
                return (id, Ok(()));
            }

            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }
}
<commit_msg>Philips Hue: Removing reliance upon Serde's (De)serialize<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! The `PhilipsHueAdapter`
//!
//! This adapter implements support for Philips Hue bridges.

// Clippy complains about `hub_id` and `hub_ip` being too similar,
// suggests renaming to `hub_i_p`.
#![allow(clippy)]

pub mod discovery;
pub mod http;
pub mod hub;
pub mod hub_api;
pub mod lights;
pub mod structs;

use foxbox_taxonomy::api::{ Error, InternalError, User };
use foxbox_taxonomy::channel::*;
use foxbox_taxonomy::manager::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::values::{ Color, OnOff, Type, TypeError, Value };

use std::collections::HashMap;
use std::sync::{ Arc, Mutex };
use std::thread;
use self::hub::Hub;
use self::lights::Light;
use traits::Controller;
use transformable_channels::mpsc::*;

static ADAPTER_NAME: &'static str = "Philips Hue adapter (built-in)";
static ADAPTER_VENDOR: &'static str = "team@link.mozilla.org";
static ADAPTER_VERSION: [u32;4] = [0, 0, 0, 0];

/// Philips Hue Adapter's main loop handles messages of these types.
#[allow(dead_code)]
pub enum HueAction {
    TriggerDiscovery,
    AddHub(String, String),         // Hub id, hub ip
    AddLight(String, String),       // Hub id, light id
    RemoveHub(String),              // Hub id
    RemoveLight(String, String),    // Hub id, light id
    StopAdapter,
}

pub type LightServiceMap = Arc<Mutex<LightServiceMapInternal>>;

pub struct LightServiceMapInternal {
    getters: HashMap<Id<Channel>, Light>,
    setters: HashMap<Id<Channel>, Light>,
}

#[derive(Clone)]
pub struct PhilipsHueAdapter<C> {
    /// A reference to the AdapterManager.
    manager: Arc<AdapterManager>,

    controller: C,

    services: LightServiceMap,

    /// Tx channel for sending messages to the adapter's main loop.
    tx: Arc<Mutex<RawSender<HueAction>>>,

    /// The ID of this adapter (permanently fixed)
    adapter_id: Id<AdapterId>,
}

impl<C: Controller> PhilipsHueAdapter<C> {
    #[allow(dead_code)]
    pub fn init(manager: &Arc<AdapterManager>, controller: C) -> Result<(), Error> {
        let services = Arc::new(Mutex::new(LightServiceMapInternal {
            getters: HashMap::new(),
            setters: HashMap::new(),
        }));

        let (tx, rx) = channel();

        let adapter = PhilipsHueAdapter {
            manager: manager.clone(),
            controller: controller.clone(),
            services: services.clone(),
            tx: Arc::new(Mutex::new(tx.clone())),
            adapter_id: create_adapter_id(),
        };

        try!(manager.add_adapter(Arc::new(adapter.clone())));

        // Trigger discovery
        let _ = tx.send(HueAction::TriggerDiscovery);

        let manager = manager.clone();
        let services = services.clone();

        thread::spawn(move || {
            debug!("Starting Philips Hue Adapter main thread");

            let mut hubs: HashMap<String, Arc<Mutex<Hub<C>>>> = HashMap::new();
            let mut lights: HashMap<String, Arc<Mutex<Light>>> = HashMap::new();

            let discovery = discovery::Discovery::new(adapter.clone());

            'recv: for action in rx {
                match action {
                    HueAction::TriggerDiscovery => {
                        debug!("HueAction::TriggerDiscovery received");
                        discovery.do_discovery();
                    },
                    HueAction::AddHub(hub_id, hub_ip) => {
                        debug!("HueAction::AddHub({},{}) received", hub_id, hub_ip);
                        let is_known_hub = hubs.contains_key(&hub_id);
                        if is_known_hub {
                            let mut hub = hubs.get_mut(&hub_id).unwrap().lock().unwrap();
                            hub.update_ip(&hub_ip);
                        } else {
                            let new_hub = Hub::new(adapter.clone(), &hub_id, &hub_ip);
                            new_hub.start();
                            hubs.insert(hub_id, Arc::new(Mutex::new(new_hub)));
                        }
                    },
                    HueAction::AddLight(hub_id, light_id) => {
                        debug!("HueAction::AddLight({},{}) received", hub_id, light_id);
                        let id = format!("{}::{}", hub_id, light_id);
                        let is_known_light = lights.contains_key(&id);
                        if is_known_light {
                            warn!("Ignoring request to add pre-existing Hue light");
                        } else {
                            // TODO: check if hub is known
                            let hub = hubs.get(&hub_id).unwrap().lock().unwrap();
                            let mut new_light: Light = Light::new(hub.api.clone(), &hub_id,
                                &light_id);
                            let _ = new_light.init_service(manager.clone(), services.clone());
                            new_light.start();
                            lights.insert(id, Arc::new(Mutex::new(new_light)));
                        }
                    },
                    // Currently unused
                    HueAction::RemoveHub(hub_id) => {
                        debug!("HueAction::RemoveHub({}) received", hub_id);
                        let is_known_hub = hubs.contains_key(&hub_id);
                        if is_known_hub {
                            let _ = hubs.remove(&hub_id);
                        } else {
                            warn!("Ignoring request to remove unknown Hue hub");
                        }
                    },
                    // Currently unused
                    HueAction::RemoveLight(hub_id, light_id) => {
                        debug!("HueAction::RemoveLight({},{}) received", hub_id, light_id);
                        let id = format!("{}::{}", hub_id, light_id);
                        let is_known_light = lights.contains_key(&id);
                        if is_known_light {
                            let _ = lights.remove(&id);
                        } else {
                            warn!("Ignoring request to remove unknown Hue hub");
                        }
                    },
                    // TODO: Currently unused, but required for teardown
                    HueAction::StopAdapter => {
                        debug!("HueAction::StopAdapter received");
                        break;
                    },
                }
            }

            debug!("Stopping Philips Hue Adapter main thread.");

            for (_, light) in lights.drain() {
                light.lock().unwrap().stop();
            }

            for (_, hub) in hubs.drain() {
                hub.lock().unwrap().stop();
            }

        });

        Ok(())
    }

    // TODO: This should be called on tear-down by the adapter manager or
    // the taxonomy manager, but currently it can't be because the adapter
    // manager is never given a reference and .stop() is not part of a
    // trait shared amongst adapters.
    #[allow(dead_code)]
    pub fn stop(&self) {
        let _ = self.tx.lock().unwrap().send(HueAction::StopAdapter);
    }

    pub fn send(&self, action: HueAction) {
        let _ = self.tx.lock().unwrap().send(action);
    }
}

pub fn create_adapter_id() -> Id<AdapterId> {
    Id::new("philips_hue@link.mozilla.org")
}

pub fn create_light_id(hub_id: &str, light_id: &str) -> Id<ServiceId> {
    Id::new(&format!("service:{}.{}.{}", light_id, hub_id, create_adapter_id()))
}

pub fn create_channel_id(op: &str, hub_id: &str, light_id: &str) -> Id<Channel> {
    Id::new(&format!("channel:{}.{}.{}.{}", op, light_id, hub_id, create_adapter_id()))
}

impl<C: Controller> Adapter for PhilipsHueAdapter<C> {
    fn id(&self) -> Id<AdapterId> {
        create_adapter_id()
    }

    fn name(&self) -> &str {
        ADAPTER_NAME
    }

    fn vendor(&self) -> &str {
        ADAPTER_VENDOR
    }

    fn version(&self) -> &[u32; 4] {
        &ADAPTER_VERSION
    }

    fn fetch_values(&self, mut set: Vec<Id<Channel>>, _: User)
        -> ResultMap<Id<Channel>, Option<Value>, Error>
    {
        set.drain(..).map(|id| {
            let light = match self.services.lock().unwrap().getters.get(&id) {
                Some(light) => light.clone(),
                None => return (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
            };

            if id == light.get_available_id {
                if light.get_available() {
                    return (id, Ok(Some(Value::OnOff(OnOff::On))));
                } else {
                    return (id, Ok(Some(Value::OnOff(OnOff::Off))));
                }
            }
            if id == light.channel_power_id {
                if light.get_power() {
                    return (id, Ok(Some(Value::OnOff(OnOff::On))));
                } else {
                    return (id, Ok(Some(Value::OnOff(OnOff::Off))));
                }
            }
            if id == light.channel_color_id {
                let (h, s, v) = light.get_color();
                return (id, Ok(Some(Value::Color(Color::HSV(h, s, v)))));
            }

            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }

    fn send_values(&self, mut values: HashMap<Id<Channel>, Value>, _: User)
        -> ResultMap<Id<Channel>, (), Error>
    {
        values.drain().map(|(id, value)| {
            let light = match self.services.lock().unwrap().setters.get(&id) {
                Some(light) => light.clone(),
                None => return (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
            };

            if id == light.channel_power_id {
                match value {
                    Value::OnOff(OnOff::On)  => { light.set_power(true); },
                    Value::OnOff(OnOff::Off) => { light.set_power(false); },
                    _ => {
                        return (id, Err(Error::TypeError(TypeError {
                                        got: value.get_type().name(),
                                        expected: Type::OnOff.name()
                                    })));
                    }
                }
                return (id, Ok(()));
            }
            if id == light.channel_color_id {
                match value {
                    Value::Color(Color::HSV(h, s, v)) => { light.set_color((h, s, v)); },
                    _ => {
                        return (id, Err(Error::TypeError(TypeError {
                                        got: value.get_type().name(),
                                        expected: Type::Color.name()
                                    })));
                    }
                }
                return (id, Ok(()));
            }

            (id.clone(), Err(Error::InternalError(InternalError::NoSuchChannel(id))))
        }).collect()
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2019 Sajeer Ahamed <ahamedsajeer.15.15@cse.mrt.ac.lk>
// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Extracts release for [GStreamer](https://gstreamer.freedesktop.org) plugin metadata
//!
//! See [`get_info`](fn.get_info.html) for details.
//!
//! This function is supposed to be used as follows in the `build.rs` of a crate that implements a
//! plugin:
//!
//! ```rust,ignore
//! extern crate gst_plugin_version_helper;
//!
//! gst_plugin_version_helper::get_info();
//! ```
//!
//! Inside `lib.rs` of the plugin, the information provided by `get_info` are usable as follows:
//!
//! ```rust,ignore
//! gst_plugin_define!(
//!     the_plugin_name,
//!     env!("CARGO_PKG_DESCRIPTION"),
//!     plugin_init,
//!     concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")),
//!     "The Plugin's License",
//!     env!("CARGO_PKG_NAME"),
//!     env!("CARGO_PKG_NAME"),
//!     env!("CARGO_PKG_REPOSITORY"),
//!     env!("BUILD_REL_DATE")
//! );
//! ```

mod git;

use chrono::TimeZone;
use std::convert::TryInto;
use std::time::SystemTime;
use std::{env, fs, path};

/// Extracts release for GStreamer plugin metadata
///
/// Release information is first tried to be extracted from a git repository at the same
/// place as the `Cargo.toml`, or one directory up to allow for Cargo workspaces. If no
/// git repository is found, we assume this is a release.
///
/// - If extracted from a git repository, sets the `COMMIT_ID` environment variable to the short
///   commit id of the latest commit and the `BUILD_REL_DATE` environment variable to the date of the
///   commit.
///
/// - If not, `COMMIT_ID` will be set to the string `RELEASE` and the
///   `BUILD_REL_DATE` variable will be set to the mtime of `Cargo.toml`.
///
/// - If neither is possible, `COMMIT_ID` is set to the string `UNKNOWN` and `BUILD_REL_DATE` to the
///   current date.
///
pub fn get_info() {
    let crate_dir =
        path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
    let mut repo_dir = crate_dir.clone();

    // First check for a git repository in the manifest directory and if there
    // is none try one directory up in case we're in a Cargo workspace
    let git_info = git::repo_hash(&repo_dir).or_else(move || {
        repo_dir.pop();
        git::repo_hash(&repo_dir)
    });

    // If there is a git repository, extract the version information from there.
    // Otherwise assume this is a release and use Cargo.toml mtime as date.
    let (commit_id, commit_date) = git_info.unwrap_or_else(|| {
        let date = cargo_mtime_date(crate_dir).expect("Failed to get Cargo.toml mtime");
        ("RELEASE".into(), date)
    });

    println!("cargo:rustc-env=COMMIT_ID={}", commit_id);
    println!("cargo:rustc-env=BUILD_REL_DATE={}", commit_date);
}

fn cargo_mtime_date(crate_dir: path::PathBuf) -> Option<String> {
    let mut cargo_toml = crate_dir;
    cargo_toml.push("Cargo.toml");

    let metadata = fs::metadata(&cargo_toml).ok()?;
    let mtime = metadata.modified().ok()?;
    let unix_time = mtime.duration_since(SystemTime::UNIX_EPOCH).ok()?;
    let dt = chrono::Utc.timestamp(unix_time.as_secs().try_into().ok()?, 0);

    Some(dt.format("%Y-%m-%d").to_string())
}
<commit_msg>version-helper: Remove unneeded `extern crate`<commit_after>// Copyright (C) 2019 Sajeer Ahamed <ahamedsajeer.15.15@cse.mrt.ac.lk>
// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>

//! Extracts release for [GStreamer](https://gstreamer.freedesktop.org) plugin metadata
//!
//! See [`get_info`](fn.get_info.html) for details.
//!
//! This function is supposed to be used as follows in the `build.rs` of a crate that implements a
//! plugin:
//!
//! ```rust,ignore
//! gst_plugin_version_helper::get_info();
//! ```
//!
//! Inside `lib.rs` of the plugin, the information provided by `get_info` are usable as follows:
//!
//! ```rust,ignore
//! gst_plugin_define!(
//!     the_plugin_name,
//!     env!("CARGO_PKG_DESCRIPTION"),
//!     plugin_init,
//!     concat!(env!("CARGO_PKG_VERSION"), "-", env!("COMMIT_ID")),
//!     "The Plugin's License",
//!     env!("CARGO_PKG_NAME"),
//!     env!("CARGO_PKG_NAME"),
//!     env!("CARGO_PKG_REPOSITORY"),
//!     env!("BUILD_REL_DATE")
//! );
//! ```

mod git;

use chrono::TimeZone;
use std::convert::TryInto;
use std::time::SystemTime;
use std::{env, fs, path};

/// Extracts release for GStreamer plugin metadata
///
/// Release information is first tried to be extracted from a git repository at the same
/// place as the `Cargo.toml`, or one directory up to allow for Cargo workspaces. If no
/// git repository is found, we assume this is a release.
///
/// - If extracted from a git repository, sets the `COMMIT_ID` environment variable to the short
///   commit id of the latest commit and the `BUILD_REL_DATE` environment variable to the date of the
///   commit.
///
/// - If not, `COMMIT_ID` will be set to the string `RELEASE` and the
///   `BUILD_REL_DATE` variable will be set to the mtime of `Cargo.toml`.
///
/// - If neither is possible, `COMMIT_ID` is set to the string `UNKNOWN` and `BUILD_REL_DATE` to the
///   current date.
///
pub fn get_info() {
    let crate_dir =
        path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR not set"));
    let mut repo_dir = crate_dir.clone();

    // First check for a git repository in the manifest directory and if there
    // is none try one directory up in case we're in a Cargo workspace
    let git_info = git::repo_hash(&repo_dir).or_else(move || {
        repo_dir.pop();
        git::repo_hash(&repo_dir)
    });

    // If there is a git repository, extract the version information from there.
    // Otherwise assume this is a release and use Cargo.toml mtime as date.
    let (commit_id, commit_date) = git_info.unwrap_or_else(|| {
        let date = cargo_mtime_date(crate_dir).expect("Failed to get Cargo.toml mtime");
        ("RELEASE".into(), date)
    });

    println!("cargo:rustc-env=COMMIT_ID={}", commit_id);
    println!("cargo:rustc-env=BUILD_REL_DATE={}", commit_date);
}

fn cargo_mtime_date(crate_dir: path::PathBuf) -> Option<String> {
    let mut cargo_toml = crate_dir;
    cargo_toml.push("Cargo.toml");

    let metadata = fs::metadata(&cargo_toml).ok()?;
    let mtime = metadata.modified().ok()?;
    let unix_time = mtime.duration_since(SystemTime::UNIX_EPOCH).ok()?;
    let dt = chrono::Utc.timestamp(unix_time.as_secs().try_into().ok()?, 0);

    Some(dt.format("%Y-%m-%d").to_string())
}
<|endoftext|>