<commit_before>use std::fmt;
use super::atom::Atom;
use super::parser;
use super::token::{Token, Tokenizer, CurlyAroundTokenizer};
use std::collections::BTreeMap;

#[derive(Debug, PartialEq, Clone)]
pub enum Sexp {
    Atom(Atom),

    // ( ... )
    Tuple(Vec<Sexp>),

    // [ ... ]
    Array(Vec<Sexp>),

    // { key val ... }
    Map(Vec<(Sexp, Sexp)>),
}

impl Sexp {
    /// Converts a Sexp::Map into a BTreeMap<String, Sexp> if possible.
    pub fn into_map(self) -> Result<BTreeMap<String, Sexp>, &'static str> {
        match self {
            Sexp::Map(pairs) => {
                let mut map = BTreeMap::new();
                for (key, val) in pairs {
                    match key {
                        Sexp::Atom(Atom::Str(s)) => {
                            if map.insert(s, val).is_some() {
                                return Err("duplicate key");
                            }
                        }
                        _ => return Err("key has to be a string"),
                    }
                }
                return Ok(map);
            }
            _ => Err("expr is not a Sexp::Map"),
        }
    }

    pub fn get_uint(&self) -> Option<u64> {
        match self {
            &Sexp::Atom(Atom::UInt(u)) => Some(u),
            _ => None,
        }
    }

    pub fn get_int(&self) -> Option<i64> {
        match self {
            &Sexp::Atom(Atom::SInt(s)) => Some(s),
            _ => None,
        }
    }

    pub fn get_float(&self) -> Option<f64> {
        match self {
            &Sexp::Atom(Atom::Float(f)) => Some(f),
            _ => None,
        }
    }

    pub fn get_str(&self) -> Option<&str> {
        match self {
            &Sexp::Atom(Atom::Str(ref s)) => Some(s),
            _ => None,
        }
    }

    pub fn get_vec<'a, F, R>(&'a self, f: F) -> Option<Vec<R>>
        where F: Fn(&'a Sexp) -> Option<R>
    {
        match self {
            &Sexp::Array(ref ary) => {
                let mut a = Vec::new();
                for elm in ary.iter() {
                    if let Some(u) = f(elm) {
                        a.push(u);
                    } else {
                        return None;
                    }
                }
                Some(a)
            }
            _ => None,
        }
    }

    pub fn get_uint_vec(&self) -> Option<Vec<u64>> {
        self.get_vec(|elm| elm.get_uint())
    }

    pub fn parse_iter<'a, I>(mut iter: I) -> Result<Sexp, ()>
        where I: Iterator<Item = Token<'a>>
    {
        if let Ok(expr) = parser::parse_sexp(&mut iter) {
            if parser::at_end(&mut iter) {
                return Ok(expr);
            }
        }
        Err(())
    }

    pub fn parse(s: &str) -> Result<Sexp, ()> {
        Sexp::parse_iter(Tokenizer::new(s, true))
    }

    pub fn parse_toplevel(s: &str) -> Result<Sexp, ()> {
        Sexp::parse_iter(CurlyAroundTokenizer::new(Tokenizer::new(s, true)))
    }
}

impl<T> From<T> for Sexp where T: Into<Atom>
{
    fn from(t: T) -> Sexp {
        Sexp::Atom(t.into())
    }
}

impl From<()> for Sexp {
    fn from(_e: ()) -> Sexp {
        Sexp::Tuple(vec![])
    }
}

impl<A> From<(A,)> for Sexp where A: Into<Sexp>
{
    fn from(e: (A,)) -> Sexp {
        Sexp::Tuple(vec![e.0.into()])
    }
}

impl<A, B> From<(A, B)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>
{
    fn from(e: (A, B)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into()])
    }
}

impl<A, B, C> From<(A, B, C)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>,
          C: Into<Sexp>
{
    fn from(e: (A, B, C)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into(), e.2.into()])
    }
}

impl<A, B, C, D> From<(A, B, C, D)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>,
          C: Into<Sexp>,
          D: Into<Sexp>
{
    fn from(e: (A, B, C, D)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into(), e.2.into(), e.3.into()])
    }
}

impl<A> From<Vec<A>> for Sexp where A: Into<Sexp>
{
    fn from(arr: Vec<A>) -> Sexp {
        Sexp::Array(arr.into_iter().map(|e| e.into()).collect())
    }
}

pub fn prettyprint<W: fmt::Write>(sexp: &Sexp,
                                  f: &mut W,
                                  indent: usize,
                                  newline: bool)
                                  -> Result<(), fmt::Error> {
    use std::cmp;

    if newline {
        for _ in 0..cmp::min(4, indent) {
            try!(write!(f, "\n{:>4}", ""));
        }
    }

    match *sexp {
        Sexp::Atom(ref a) => write!(f, "{}", a),
        Sexp::Tuple(ref t) => {
            try!(write!(f, "("));
            for (i, expr) in t.iter().enumerate() {
                if i > 0 {
                    try!(write!(f, " "));
                }
                try!(prettyprint(expr, f, indent, false));
            }
            write!(f, ")")
        }
        Sexp::Array(ref t) => {
            try!(write!(f, "["));
            for (_, expr) in t.iter().enumerate() {
                try!(prettyprint(expr, f, indent + 1, true));
            }
            write!(f, "\n]")
        }
        Sexp::Map(ref t) => {
            try!(write!(f, "{}", "{"));
            for (i, expr) in t.iter().enumerate() {
                if i > 0 {
                    try!(write!(f, " "));
                }
                try!(prettyprint(&expr.0, f, indent, false));
                try!(write!(f, " "));
                try!(prettyprint(&expr.1, f, indent, false));
            }
            write!(f, "{}", "}")
        }
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Sexp::Atom(ref a) => write!(f, "{}", a),
            Sexp::Tuple(ref t) => {
                try!(write!(f, "("));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, ")")
            }
            Sexp::Array(ref t) => {
                try!(write!(f, "["));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, "]")
            }
            Sexp::Map(ref t) => {
                try!(write!(f, "{}", "{"));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{} {}", space, expr.0, expr.1));
                }
                write!(f, "{}", "}")
            }
        }
    }
}

#[test]
fn test_display() {
    assert_eq!("12345", &format!("{}", Sexp::Atom(Atom::UInt(12345))));
    assert_eq!("1.0", &format!("{}", Sexp::Atom(Atom::Float(1.0))));

    assert_eq!("(12345)",
               &format!("{}", Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345))])));
    assert_eq!("(12345 abc)",
               &format!("{}",
                        Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345)),
                                         Sexp::Atom(Atom::Str("abc".to_string()))])));
    assert_eq!("(12345 (abc))",
               &format!("{}",
                        Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345)),
                                         Sexp::Tuple(vec![
                                         Sexp::Atom(Atom::Str("abc".to_string()))
                                         ])])));

}

#[test]
fn test_from() {
    assert_eq!(Sexp::Atom(Atom::UInt(123)), Sexp::from(123u64));
    assert_eq!(Sexp::Atom(Atom::SInt(123)), Sexp::from(123i64));
    assert_eq!(Sexp::Atom(Atom::Str("test".to_string())),
               Sexp::from("test"));
    assert_eq!(Sexp::Atom(Atom::Float(123.45)), Sexp::from(123.45));
    assert_eq!(Sexp::Tuple(vec![Sexp::Atom(Atom::Float(123.45))]),
               Sexp::from((123.45,)));
    assert_eq!(Sexp::Array(vec![Sexp::Atom(Atom::Float(123.45))]),
               Sexp::from(vec![123.45]));

}

#[test]
fn test_parse() {
    assert_eq!(Ok(Sexp::from(("abc", 123u64, ("-", 123.43, 11.0)))),
               Sexp::parse("(abc 123 (- 123.43 11.0))"));
}

#[test]
fn test_parse_toplevel() {
    assert_eq!(Sexp::parse("{a 1 b 2}"), Sexp::parse_toplevel("a 1 b 2"));
}

#[test]
fn test_map() {
    let map = Sexp::parse("{a 1 b 2}").unwrap().into_map().unwrap();
    assert_eq!(true, map.contains_key("a"));
    assert_eq!(true, map.contains_key("b"));
    assert_eq!(false, map.contains_key("c"));

    assert_eq!(Err("duplicate key"),
               Sexp::parse("{a 1 b 2 a 1}").unwrap().into_map());
    assert_eq!(Err("key has to be a string"),
               Sexp::parse("{1 1 b 2 a 1}").unwrap().into_map());

}
<commit_msg>Write newline only once<commit_after>use std::fmt;
use super::atom::Atom;
use super::parser;
use super::token::{Token, Tokenizer, CurlyAroundTokenizer};
use std::collections::BTreeMap;

#[derive(Debug, PartialEq, Clone)]
pub enum Sexp {
    Atom(Atom),

    // ( ... )
    Tuple(Vec<Sexp>),

    // [ ... ]
    Array(Vec<Sexp>),

    // { key val ... }
    Map(Vec<(Sexp, Sexp)>),
}

impl Sexp {
    /// Converts a Sexp::Map into a BTreeMap<String, Sexp> if possible.
    pub fn into_map(self) -> Result<BTreeMap<String, Sexp>, &'static str> {
        match self {
            Sexp::Map(pairs) => {
                let mut map = BTreeMap::new();
                for (key, val) in pairs {
                    match key {
                        Sexp::Atom(Atom::Str(s)) => {
                            if map.insert(s, val).is_some() {
                                return Err("duplicate key");
                            }
                        }
                        _ => return Err("key has to be a string"),
                    }
                }
                return Ok(map);
            }
            _ => Err("expr is not a Sexp::Map"),
        }
    }

    pub fn get_uint(&self) -> Option<u64> {
        match self {
            &Sexp::Atom(Atom::UInt(u)) => Some(u),
            _ => None,
        }
    }

    pub fn get_int(&self) -> Option<i64> {
        match self {
            &Sexp::Atom(Atom::SInt(s)) => Some(s),
            _ => None,
        }
    }

    pub fn get_float(&self) -> Option<f64> {
        match self {
            &Sexp::Atom(Atom::Float(f)) => Some(f),
            _ => None,
        }
    }

    pub fn get_str(&self) -> Option<&str> {
        match self {
            &Sexp::Atom(Atom::Str(ref s)) => Some(s),
            _ => None,
        }
    }

    pub fn get_vec<'a, F, R>(&'a self, f: F) -> Option<Vec<R>>
        where F: Fn(&'a Sexp) -> Option<R>
    {
        match self {
            &Sexp::Array(ref ary) => {
                let mut a = Vec::new();
                for elm in ary.iter() {
                    if let Some(u) = f(elm) {
                        a.push(u);
                    } else {
                        return None;
                    }
                }
                Some(a)
            }
            _ => None,
        }
    }

    pub fn get_uint_vec(&self) -> Option<Vec<u64>> {
        self.get_vec(|elm| elm.get_uint())
    }

    pub fn parse_iter<'a, I>(mut iter: I) -> Result<Sexp, ()>
        where I: Iterator<Item = Token<'a>>
    {
        if let Ok(expr) = parser::parse_sexp(&mut iter) {
            if parser::at_end(&mut iter) {
                return Ok(expr);
            }
        }
        Err(())
    }

    pub fn parse(s: &str) -> Result<Sexp, ()> {
        Sexp::parse_iter(Tokenizer::new(s, true))
    }

    pub fn parse_toplevel(s: &str) -> Result<Sexp, ()> {
        Sexp::parse_iter(CurlyAroundTokenizer::new(Tokenizer::new(s, true)))
    }
}

impl<T> From<T> for Sexp where T: Into<Atom>
{
    fn from(t: T) -> Sexp {
        Sexp::Atom(t.into())
    }
}

impl From<()> for Sexp {
    fn from(_e: ()) -> Sexp {
        Sexp::Tuple(vec![])
    }
}

impl<A> From<(A,)> for Sexp where A: Into<Sexp>
{
    fn from(e: (A,)) -> Sexp {
        Sexp::Tuple(vec![e.0.into()])
    }
}

impl<A, B> From<(A, B)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>
{
    fn from(e: (A, B)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into()])
    }
}

impl<A, B, C> From<(A, B, C)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>,
          C: Into<Sexp>
{
    fn from(e: (A, B, C)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into(), e.2.into()])
    }
}

impl<A, B, C, D> From<(A, B, C, D)> for Sexp
    where A: Into<Sexp>,
          B: Into<Sexp>,
          C: Into<Sexp>,
          D: Into<Sexp>
{
    fn from(e: (A, B, C, D)) -> Sexp {
        Sexp::Tuple(vec![e.0.into(), e.1.into(), e.2.into(), e.3.into()])
    }
}

impl<A> From<Vec<A>> for Sexp where A: Into<Sexp>
{
    fn from(arr: Vec<A>) -> Sexp {
        Sexp::Array(arr.into_iter().map(|e| e.into()).collect())
    }
}

pub fn prettyprint<W: fmt::Write>(sexp: &Sexp,
                                  f: &mut W,
                                  indent: usize,
                                  newline: bool)
                                  -> Result<(), fmt::Error> {
    use std::cmp;

    if newline {
        try!(write!(f, "\n"));
        for _ in 0..cmp::min(4, indent) {
            try!(write!(f, "{:>4}", ""));
        }
    }

    match *sexp {
        Sexp::Atom(ref a) => write!(f, "{}", a),
        Sexp::Tuple(ref t) => {
            try!(write!(f, "("));
            for (i, expr) in t.iter().enumerate() {
                if i > 0 {
                    try!(write!(f, " "));
                }
                try!(prettyprint(expr, f, indent, false));
            }
            write!(f, ")")
        }
        Sexp::Array(ref t) => {
            try!(write!(f, "["));
            for (_, expr) in t.iter().enumerate() {
                try!(prettyprint(expr, f, indent + 1, true));
            }
            write!(f, "\n]")
        }
        Sexp::Map(ref t) => {
            try!(write!(f, "{}", "{"));
            for (i, expr) in t.iter().enumerate() {
                if i > 0 {
                    try!(write!(f, " "));
                }
                try!(prettyprint(&expr.0, f, indent, false));
                try!(write!(f, " "));
                try!(prettyprint(&expr.1, f, indent, false));
            }
            write!(f, "{}", "}")
        }
    }
}

impl fmt::Display for Sexp {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Sexp::Atom(ref a) => write!(f, "{}", a),
            Sexp::Tuple(ref t) => {
                try!(write!(f, "("));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, ")")
            }
            Sexp::Array(ref t) => {
                try!(write!(f, "["));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{}", space, expr));
                }
                write!(f, "]")
            }
            Sexp::Map(ref t) => {
                try!(write!(f, "{}", "{"));
                for (i, expr) in t.iter().enumerate() {
                    let space = if i > 0 {
                        " "
                    } else {
                        ""
                    };
                    try!(write!(f, "{}{} {}", space, expr.0, expr.1));
                }
                write!(f, "{}", "}")
            }
        }
    }
}

#[test]
fn test_display() {
    assert_eq!("12345", &format!("{}", Sexp::Atom(Atom::UInt(12345))));
    assert_eq!("1.0", &format!("{}", Sexp::Atom(Atom::Float(1.0))));

    assert_eq!("(12345)",
               &format!("{}", Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345))])));
    assert_eq!("(12345 abc)",
               &format!("{}",
                        Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345)),
                                         Sexp::Atom(Atom::Str("abc".to_string()))])));
    assert_eq!("(12345 (abc))",
               &format!("{}",
                        Sexp::Tuple(vec![Sexp::Atom(Atom::UInt(12345)),
                                         Sexp::Tuple(vec![
                                         Sexp::Atom(Atom::Str("abc".to_string()))
                                         ])])));

}

#[test]
fn test_from() {
    assert_eq!(Sexp::Atom(Atom::UInt(123)), Sexp::from(123u64));
    assert_eq!(Sexp::Atom(Atom::SInt(123)), Sexp::from(123i64));
    assert_eq!(Sexp::Atom(Atom::Str("test".to_string())),
               Sexp::from("test"));
    assert_eq!(Sexp::Atom(Atom::Float(123.45)), Sexp::from(123.45));
    assert_eq!(Sexp::Tuple(vec![Sexp::Atom(Atom::Float(123.45))]),
               Sexp::from((123.45,)));
    assert_eq!(Sexp::Array(vec![Sexp::Atom(Atom::Float(123.45))]),
               Sexp::from(vec![123.45]));

}

#[test]
fn test_parse() {
    assert_eq!(Ok(Sexp::from(("abc", 123u64, ("-", 123.43, 11.0)))),
               Sexp::parse("(abc 123 (- 123.43 11.0))"));
}

#[test]
fn test_parse_toplevel() {
    assert_eq!(Sexp::parse("{a 1 b 2}"), Sexp::parse_toplevel("a 1 b 2"));
}

#[test]
fn test_map() {
    let map = Sexp::parse("{a 1 b 2}").unwrap().into_map().unwrap();
    assert_eq!(true, map.contains_key("a"));
    assert_eq!(true, map.contains_key("b"));
    assert_eq!(false, map.contains_key("c"));

    assert_eq!(Err("duplicate key"),
               Sexp::parse("{a 1 b 2 a 1}").unwrap().into_map());
    assert_eq!(Err("key has to be a string"),
               Sexp::parse("{1 1 b 2 a 1}").unwrap().into_map());

}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Definitions and utilities for working with sinks.
//!
//! Sinks ("well-known flows" in terms of GRR nomenclature) are ever-existing
//! sessions on the GRR server that listen for various kinds of data. They are
//! a way to break away from the usual request-response workflow.
//!
//! For example, sinks can be used to notify the server about agent startup
//! (which is clearly not a response to a particular request) or to transfer
//! file blobs to a specialized storage.

use crate::action;
use crate::session;

/// Data sent to a server not belonging to a particular action call.
///
/// Sometimes the agent should send data to the server that is not connected
/// with a particular flow request. An example can be the agent startup data
/// sent to the server regardless of whether there was a request for it or not.
/// Another example can be file contents that are delivered to the server not
/// as part of the flow results but go to a separate store that has logic for
/// deduplicating data that we already collected in the past.
pub trait Parcel {
    /// Low-level Protocol Buffers type representing the parcel data.
    type Protobuf: protobuf::Message;

    /// A name of the corresponding RDF class in GRR.
    const RDF_NAME: &'static str;

    /// Converts the parcel to its low-level representation.
    fn into_proto(self) -> Self::Protobuf;

    /// Converts a Protocol Buffers message to high-level type.
    fn from_proto(message: Self::Protobuf) -> Self;
}

/// A parcel addressed to a particular server-side sink.
pub struct AddressedParcel<P: Parcel> {
    /// Destination of the parcel.
    dest: Sink,
    /// Actual parcel.
    parcel: P,
}

impl<P: Parcel> std::convert::TryInto<rrg_proto::jobs::GrrMessage> for AddressedParcel<P> {

    type Error = protobuf::ProtobufError;

    fn try_into(self) -> Result<rrg_proto::jobs::GrrMessage, protobuf::ProtobufError> {
        let mut message = rrg_proto::jobs::GrrMessage::new();
        message.set_session_id(String::from(self.dest.id));
        message.set_field_type(rrg_proto::jobs::GrrMessage_Type::MESSAGE);
        message.set_args_rdf_name(String::from(P::RDF_NAME));

        let proto = self.parcel.into_proto();
        message.set_args(protobuf::Message::write_to_bytes(&proto)?);

        Ok(message)
    }
}

/// Handle to a specific sink.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct Sink {
    /// An underlying identifier of the sink.
    id: &'static str,
}

impl Sink {

    // TODO: Refactor sinks to use custom `Message` type rather than `Response`
    // and make response always have `request_id` and `response_id` fields.

    /// Adresses a given `parcel` to this sink.
    pub fn address<P: Parcel>(&self, parcel: P) -> AddressedParcel<P> {
        AddressedParcel {
            dest: *self,
            parcel,
        }
    }

    // TODO: Remove the function below once only parcels are used.
    /// Wraps an action response to a sink-specific session response.
    pub fn wrap<R>(&self, response: R) -> session::Response<R>
    where
        R: action::Response,
    {
        session::Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }
    }
}

/// A handle to the sink expecting startup information.
pub const STARTUP: Sink = Sink { id: "/flows/F:Startup" };

/// A handle to the transfer store sink.
pub const TRANSFER_STORE: Sink = Sink { id: "/flows/F:TransferStore" };
<commit_msg>Adjust the parcel trait definition.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.

//! Definitions and utilities for working with sinks.
//!
//! Sinks ("well-known flows" in terms of GRR nomenclature) are ever-existing
//! sessions on the GRR server that listen for various kinds of data. They are
//! a way to break away from the usual request-response workflow.
//!
//! For example, sinks can be used to notify the server about agent startup
//! (which is clearly not a response to a particular request) or to transfer
//! file blobs to a specialized storage.

use crate::action;
use crate::session;

/// Data sent to a server not belonging to a particular action call.
///
/// Sometimes the agent should send data to the server that is not connected
/// with a particular flow request. An example can be the agent startup data
/// sent to the server regardless of whether there was a request for it or not.
/// Another example can be file contents that are delivered to the server not
/// as part of the flow results but go to a separate store that has logic for
/// deduplicating data that we already collected in the past.
pub trait Parcel {
    /// Low-level Protocol Buffers type representing the parcel data.
    type Proto: protobuf::Message;

    /// A name of the corresponding RDF class in GRR.
    const RDF_NAME: &'static str;

    /// Converts the parcel to its low-level representation.
    fn into_proto(self) -> Self::Proto;
}

/// A parcel addressed to a particular server-side sink.
pub struct AddressedParcel<P: Parcel> {
    /// Destination of the parcel.
    dest: Sink,
    /// Actual parcel.
    parcel: P,
}

impl<P: Parcel> std::convert::TryInto<rrg_proto::jobs::GrrMessage> for AddressedParcel<P> {

    type Error = protobuf::ProtobufError;

    fn try_into(self) -> Result<rrg_proto::jobs::GrrMessage, protobuf::ProtobufError> {
        let mut message = rrg_proto::jobs::GrrMessage::new();
        message.set_session_id(String::from(self.dest.id));
        message.set_field_type(rrg_proto::jobs::GrrMessage_Type::MESSAGE);
        message.set_args_rdf_name(String::from(P::RDF_NAME));

        let proto = self.parcel.into_proto();
        message.set_args(protobuf::Message::write_to_bytes(&proto)?);

        Ok(message)
    }
}

/// Handle to a specific sink.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct Sink {
    /// An underlying identifier of the sink.
    id: &'static str,
}

impl Sink {

    // TODO: Refactor sinks to use custom `Message` type rather than `Response`
    // and make response always have `request_id` and `response_id` fields.

    /// Adresses a given `parcel` to this sink.
    pub fn address<P: Parcel>(&self, parcel: P) -> AddressedParcel<P> {
        AddressedParcel {
            dest: *self,
            parcel,
        }
    }

    // TODO: Remove the function below once only parcels are used.
    /// Wraps an action response to a sink-specific session response.
    pub fn wrap<R>(&self, response: R) -> session::Response<R>
    where
        R: action::Response,
    {
        session::Response {
            session_id: String::from(self.id),
            request_id: None,
            response_id: None,
            data: response,
        }
    }
}

/// A handle to the sink expecting startup information.
pub const STARTUP: Sink = Sink { id: "/flows/F:Startup" };

/// A handle to the transfer store sink.
pub const TRANSFER_STORE: Sink = Sink { id: "/flows/F:TransferStore" };
<|endoftext|>


<commit_before>//! ARMv8 intrinsics.
//!
//! The reference is [ARMv8-A Reference Manual](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0487a.k_10775/index.html).

pub use super::v7::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Reverse the order of the bytes.
#[inline(always)]
#[cfg_attr(test, assert_instr(rev))]
pub unsafe fn _rev_u64(x: u64) -> u64 {
    x.swap_bytes() as u64
}

/// Count Leading Zeros.
#[inline(always)]
#[cfg_attr(test, assert_instr(clz))]
pub unsafe fn _clz_u64(x: u64) -> u64 {
    x.leading_zeros() as u64
}

#[allow(dead_code)]
extern "C" {
    #[link_name="llvm.bitreverse.i64"]
    fn rbit_u64(i: i64) -> i64;
}

/// Reverse the bit order.
#[inline(always)]
#[cfg_attr(test, assert_instr(rbit))]
pub unsafe fn _rbit_u64(x: u64) -> u64 {
    unsafe { rbit_u64(x as i64) as u64 }
}

/// Counts the leading most significant bits set.
///
/// When all bits of the operand are set it returns the size of the operand in
/// bits.
#[inline(always)]
// LLVM Bug (should be cls): https://bugs.llvm.org/show_bug.cgi?id=31802
#[cfg_attr(test, assert_instr(clz))]
pub unsafe fn _cls_u32(x: u32) -> u32 {
    u32::leading_zeros(!x) as u32
}

/// Counts the leading most significant bits set.
///
/// When all bits of the operand are set it returns the size of the operand in
/// bits.
#[inline(always)]
// LLVM Bug (should be cls): https://bugs.llvm.org/show_bug.cgi?id=31802
#[cfg_attr(test, assert_instr(clz))]
pub unsafe fn _cls_u64(x: u64) -> u64 {
    u64::leading_zeros(!x) as u64
}
<commit_msg>[arm] fix aarch64 cls intrinsic<commit_after>//! ARMv8 intrinsics.
//!
//! The reference is [ARMv8-A Reference Manual](http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0487a.k_10775/index.html).

pub use super::v7::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

/// Reverse the order of the bytes.
#[inline(always)]
#[cfg_attr(test, assert_instr(rev))]
pub unsafe fn _rev_u64(x: u64) -> u64 {
    x.swap_bytes() as u64
}

/// Count Leading Zeros.
#[inline(always)]
#[cfg_attr(test, assert_instr(clz))]
pub unsafe fn _clz_u64(x: u64) -> u64 {
    x.leading_zeros() as u64
}

#[allow(dead_code)]
extern "C" {
    #[link_name="llvm.bitreverse.i64"]
    fn rbit_u64(i: i64) -> i64;
}

/// Reverse the bit order.
#[inline(always)]
#[cfg_attr(test, assert_instr(rbit))]
pub unsafe fn _rbit_u64(x: u64) -> u64 {
    unsafe { rbit_u64(x as i64) as u64 }
}

/// Counts the leading most significant bits set.
///
/// When all bits of the operand are set it returns the size of the operand in
/// bits.
#[inline(always)]
#[cfg_attr(test, assert_instr(cls))]
pub unsafe fn _cls_u32(x: u32) -> u32 {
    u32::leading_zeros(((((((x as i32) >> 31) as u32) ^ x) << 1) | 1)) as u32
}

/// Counts the leading most significant bits set.
///
/// When all bits of the operand are set it returns the size of the operand in
/// bits.
#[inline(always)]
#[cfg_attr(test, assert_instr(cls))]
pub unsafe fn _cls_u64(x: u64) -> u64 {
    u64::leading_zeros(((((((x as i64) >> 63) as u64) ^ x) << 1) | 1)) as u64
}
<|endoftext|>


<commit_before>use std::result::Result as RResult;

use serde::Serialize;
use serde::Serializer;
use serde::Deserialize;
use serde::Deserializer;
use serde::de::Visitor;
use serde::de::Error as SerdeError;
use serde::ser::MapVisitor;
use serde::de::MapVisitor as DeserializeMapVisitor;
use uuid::Uuid;

use priority::TaskPriority;
use status::TaskStatus;
use project::Project;
use tag::Tag;
use date::Date;

#[derive(Debug, Clone)]
pub struct Task {
    status      : TaskStatus,
    uuid        : Uuid,
    entry       : Date,
    description : String,

    annotation  : Option<Vec<String>>,
    depends     : Option<String>,
    due         : Option<Date>,
    end         : Option<Date>,
    imask       : Option<i64>,
    mask        : Option<String>,
    modified    : Option<Date>,
    parent      : Option<Uuid>,
    priority    : Option<TaskPriority>,
    project     : Option<Project>,
    recur       : Option<String>,
    scheduled   : Option<Date>,
    start       : Option<Date>,
    tags        : Option<Vec<Tag>>,
    until       : Option<Date>,
    wait        : Option<Date>,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(
        status      : TaskStatus,
        uuid        : Uuid,
        entry       : Date,
        description : String,

        annotation  : Option<Vec<String>>,
        depends     : Option<String>,
        due         : Option<Date>,
        end         : Option<Date>,
        imask       : Option<i64>,
        mask        : Option<String>,
        modified    : Option<Date>,
        parent      : Option<Uuid>,
        priority    : Option<TaskPriority>,
        project     : Option<Project>,
        recur       : Option<String>,
        scheduled   : Option<Date>,
        start       : Option<Date>,
        tags        : Option<Vec<Tag>>,
        until       : Option<Date>,
        wait        : Option<Date>,
    ) -> Task
    {
        Task {
            status      : status,
            uuid        : uuid,
            entry       : entry,
            description : description,

            annotation  : annotation,
            depends     : depends,
            due         : due,
            end         : end,
            imask       : imask,
            mask        : mask,
            modified    : modified,
            parent      : parent,
            priority    : priority,
            project     : project,
            recur       : recur,
            scheduled   : scheduled,
            start       : start,
            tags        : tags,
            until       : until,
            wait        : wait,
        }
    }

    pub fn status(&self) -> &TaskStatus {
        &self.status
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn entry(&self) -> &Date {
        &self.entry
    }

    pub fn description(&self) -> &String {
        &self.description
    }

    pub fn annotation(&self) -> Option<&Vec<String>> {
        self.annotation.as_ref()
    }

    pub fn depends(&self) -> Option<&String> {
        self.depends.as_ref()
    }

    pub fn due(&self) -> Option<&Date> {
        self.due.as_ref()
    }

    pub fn end(&self) -> Option<&Date> {
        self.end.as_ref()
    }

    pub fn imask(&self) -> Option<&i64> {
        self.imask.as_ref()
    }

    pub fn mask(&self) -> Option<&String> {
        self.mask.as_ref()
    }

    pub fn modified(&self) -> Option<&Date> {
        self.modified.as_ref()
    }

    pub fn parent(&self) -> Option<&Uuid> {
        self.parent.as_ref()
    }

    pub fn priority(&self) -> Option<&TaskPriority> {
        self.priority.as_ref()
    }

    pub fn project(&self) -> Option<&Project> {
        self.project.as_ref()
    }

    pub fn recur(&self) -> Option<&String> {
        self.recur.as_ref()
    }

    pub fn scheduled(&self) -> Option<&Date> {
        self.scheduled.as_ref()
    }

    pub fn start(&self) -> Option<&Date> {
        self.start.as_ref()
    }

    pub fn tags(&self) -> Option<&Vec<Tag>> {
        self.tags.as_ref()
    }

    pub fn until(&self) -> Option<&Date> {
        self.until.as_ref()
    }

    pub fn wait(&self) -> Option<&Date> {
        self.wait.as_ref()
    }

}

impl Serialize for Task {

    fn serialize<S>(&self, serializer: &mut S) -> RResult<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_struct("Task", TaskVisitor {
            value: self,
            state: 0,
        })
    }

}

struct TaskVisitor<'a> {
    value: &'a Task,
    state: u8,
}

impl<'a> MapVisitor for TaskVisitor<'a> {

    fn visit<S>(&mut self, serializer: &mut S) -> RResult<Option<()>, S::Error>
        where S: Serializer
    {
        match self.state {
            0 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("status", &self.value.status))))
            },
            1 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("uuid", &self.value.uuid))))
            },
            2 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("entry", &self.value.entry))))
            },
            3 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("description", &self.value.description))))
            },
            4 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("annotation", &self.value.annotation))))
            },
            5 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("depends", &self.value.depends))))
            },
            6 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("due", &self.value.due))))
            },
            7 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("end", &self.value.end))))
            },
            8 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("imask", &self.value.imask))))
            },
            9 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("mask", &self.value.mask))))
            },
            10 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("modified", &self.value.modified))))
            },
            11 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("parent", &self.value.parent))))
            },
            12 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("priority", &self.value.priority))))
            },
            13 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("project", &self.value.project))))
            },
            14 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("recur", &self.value.recur))))
            },
            15 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("scheduled", &self.value.scheduled))))
            },
            16 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("start", &self.value.start))))
            },
            17 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("tags", &self.value.tags))))
            },
            18 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("until", &self.value.until))))
            },
            19 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("wait", &self.value.wait))))
            },
            _ => {
                Ok(None)
            }
        }
    }

}

impl Deserialize for Task {

    fn deserialize<D>(deserializer: &mut D) -> RResult<Task, D::Error>
        where D: Deserializer
    {
        static FIELDS: &'static [&'static str] = &[
            "status",
            "uuid",
            "entry",
            "description",

            "annotation",
            "depends",
            "due",
            "end",
            "imask",
            "mask",
            "modified",
            "parent",
            "priority",
            "project",
            "recur",
            "scheduled",
            "start",
            "tags",
            "until",
            "wait"
        ];
        deserializer.deserialize_struct("Task", FIELDS, TaskDeserializeVisitor)
    }

}

struct TaskDeserializeVisitor;

impl Visitor for TaskDeserializeVisitor {
    type Value = Task;

    fn visit_map<V>(&mut self, mut visitor: V) -> RResult<Task, V::Error>
        where V: DeserializeMapVisitor
    {
        let mut status      = None;
        let mut uuid        = None;
        let mut entry       = None;
        let mut description = None;

        let mut annotation  = None;
        let mut depends     = None;
        let mut due         = None;
        let mut end         = None;
        let mut imask       = None;
        let mut mask        = None;
        let mut modified    = None;
        let mut parent      = None;
        let mut priority    = None;
        let mut project     = None;
        let mut recur       = None;
        let mut scheduled   = None;
        let mut start       = None;
        let mut tags        = None;
        let mut until       = None;
        let mut wait        = None;

        loop {
            let key : Option<String> = try!(visitor.visit_key());
            if key.is_none() {
                break;
            }
            let key = key.unwrap();

            match &key[..] {
                "status" => {
                    status = Some(try!(visitor.visit_value()));
                },
                "uuid" => {
                    uuid = Some(try!(visitor.visit_value()));
                },
                "entry" => {
                    entry = Some(try!(visitor.visit_value()));
                },
                "description" => {
                    description = Some(try!(visitor.visit_value()));
                },

                "annotation" => {
                    annotation = Some(try!(visitor.visit_value()));
                },
                "depends" => {
                    depends = Some(try!(visitor.visit_value()));
                },
                "due" => {
                    due = Some(try!(visitor.visit_value()));
                },
                "end" => {
                    end = Some(try!(visitor.visit_value()));
                },
                "imask" => {
                    imask = Some(try!(visitor.visit_value()));
                },
                "mask" => {
                    mask = Some(try!(visitor.visit_value()));
                },
                "modified" => {
                    modified = Some(try!(visitor.visit_value()));
                },
                "parent" => {
                    parent = Some(try!(visitor.visit_value()));
                },
                "priority" => {
                    priority = Some(try!(visitor.visit_value()));
                },
                "project" => {
                    project = Some(try!(visitor.visit_value()));
                },
                "recur" => {
                    recur = Some(try!(visitor.visit_value()));
                },
                "scheduled" => {
                    scheduled = Some(try!(visitor.visit_value()));
                },
                "start" => {
                    start = Some(try!(visitor.visit_value()));
                },
                "tags" => {
                    tags = Some(try!(visitor.visit_value()));
                },
                "until" => {
                    until = Some(try!(visitor.visit_value()));
                },
                "wait" => {
                    wait = Some(try!(visitor.visit_value()));
                },

                field => {
                    debug!("field '{}' ignored", field);

                    use serde::de::impls::IgnoredAny;
                    let _: IgnoredAny = try!(visitor.visit_value());
                }
            }
        }

        let status = match status {
            Some(status) => status,
            None => try!(visitor.missing_field("status")),
        };

        let uuid = match uuid {
            Some(uuid) => uuid,
            None => try!(visitor.missing_field("uuid")),
        };

        let entry = match entry {
            Some(entry) => entry,
            None => try!(visitor.missing_field("entry")),
        };

        let description = match description {
            Some(description) => description,
            None => try!(visitor.missing_field("description")),
        };

        try!(visitor.end());

        let task = Task::new(
            status,
            uuid,
            entry,
            description,

            annotation,
            depends,
            due,
            end,
            imask,
            mask,
            modified,
            parent,
            priority,
            project,
            recur,
            scheduled,
            start,
            tags,
            until,
            wait
        );

        Ok(task)
    }
}

#[cfg(test)]
mod test {
    use date::Date;
    use date::TASKWARRIOR_DATETIME_TEMPLATE;
    use status::TaskStatus;
    use task::Task;

    use uuid::Uuid;
    use chrono::naive::datetime::NaiveDateTime;
    use serde_json;

    #[test]
    fn test_deser() {
        let s =
r#"{
"id": 1,
"description": "test",
"entry": "20150619T165438Z",
"status": "waiting",
"uuid": "8ca953d5-18b4-4eb9-bd56-18f2e5b752f0"
}"#;

        println!("{}", s);

        let task = serde_json::from_str(s);
        println!("{:?}", task);
        assert!(task.is_ok());
        let task : Task = task.unwrap();

        assert!(task.status().clone() == TaskStatus::Waiting);
        assert!(task.description() == "test");
        assert!(task.entry().clone() == Date::from(NaiveDateTime::parse_from_str("20150619T165438Z", TASKWARRIOR_DATETIME_TEMPLATE).unwrap()));
        assert!(task.uuid().clone() == Uuid::parse_str("8ca953d5-18b4-4eb9-bd56-18f2e5b752f0").unwrap());

        let back = serde_json::to_string(&task).unwrap();

        assert!(back.contains("description"));
        assert!(back.contains("test"));
        assert!(back.contains("entry"));
        assert!(back.contains("20150619T165438Z"));
        assert!(back.contains("status"));
        assert!(back.contains("waiting"));
        assert!(back.contains("uuid"));
        assert!(back.contains("8ca953d5-18b4-4eb9-bd56-18f2e5b752f0"));
    }

}

<commit_msg>Fix statement order<commit_after>use std::result::Result as RResult;

use serde::Serialize;
use serde::Serializer;
use serde::Deserialize;
use serde::Deserializer;
use serde::de::Visitor;
use serde::de::Error as SerdeError;
use serde::ser::MapVisitor;
use serde::de::MapVisitor as DeserializeMapVisitor;
use uuid::Uuid;

use priority::TaskPriority;
use status::TaskStatus;
use project::Project;
use tag::Tag;
use date::Date;

#[derive(Debug, Clone)]
pub struct Task {
    status      : TaskStatus,
    uuid        : Uuid,
    entry       : Date,
    description : String,

    annotation  : Option<Vec<String>>,
    depends     : Option<String>,
    due         : Option<Date>,
    end         : Option<Date>,
    imask       : Option<i64>,
    mask        : Option<String>,
    modified    : Option<Date>,
    parent      : Option<Uuid>,
    priority    : Option<TaskPriority>,
    project     : Option<Project>,
    recur       : Option<String>,
    scheduled   : Option<Date>,
    start       : Option<Date>,
    tags        : Option<Vec<Tag>>,
    until       : Option<Date>,
    wait        : Option<Date>,
}

/*
 * TODO: We do not fail if the JSON parsing fails. This panics. We rely on taskwarrior to be nice
 * to us. I guess this should be fixed.
 */
impl Task {

    pub fn new(
        status      : TaskStatus,
        uuid        : Uuid,
        entry       : Date,
        description : String,

        annotation  : Option<Vec<String>>,
        depends     : Option<String>,
        due         : Option<Date>,
        end         : Option<Date>,
        imask       : Option<i64>,
        mask        : Option<String>,
        modified    : Option<Date>,
        parent      : Option<Uuid>,
        priority    : Option<TaskPriority>,
        project     : Option<Project>,
        recur       : Option<String>,
        scheduled   : Option<Date>,
        start       : Option<Date>,
        tags        : Option<Vec<Tag>>,
        until       : Option<Date>,
        wait        : Option<Date>,
    ) -> Task
    {
        Task {
            status      : status,
            uuid        : uuid,
            entry       : entry,
            description : description,

            annotation  : annotation,
            depends     : depends,
            due         : due,
            end         : end,
            imask       : imask,
            mask        : mask,
            modified    : modified,
            parent      : parent,
            priority    : priority,
            project     : project,
            recur       : recur,
            scheduled   : scheduled,
            start       : start,
            tags        : tags,
            until       : until,
            wait        : wait,
        }
    }

    pub fn status(&self) -> &TaskStatus {
        &self.status
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn entry(&self) -> &Date {
        &self.entry
    }

    pub fn description(&self) -> &String {
        &self.description
    }

    pub fn annotation(&self) -> Option<&Vec<String>> {
        self.annotation.as_ref()
    }

    pub fn depends(&self) -> Option<&String> {
        self.depends.as_ref()
    }

    pub fn due(&self) -> Option<&Date> {
        self.due.as_ref()
    }

    pub fn end(&self) -> Option<&Date> {
        self.end.as_ref()
    }

    pub fn imask(&self) -> Option<&i64> {
        self.imask.as_ref()
    }

    pub fn mask(&self) -> Option<&String> {
        self.mask.as_ref()
    }

    pub fn modified(&self) -> Option<&Date> {
        self.modified.as_ref()
    }

    pub fn parent(&self) -> Option<&Uuid> {
        self.parent.as_ref()
    }

    pub fn priority(&self) -> Option<&TaskPriority> {
        self.priority.as_ref()
    }

    pub fn project(&self) -> Option<&Project> {
        self.project.as_ref()
    }

    pub fn recur(&self) -> Option<&String> {
        self.recur.as_ref()
    }

    pub fn scheduled(&self) -> Option<&Date> {
        self.scheduled.as_ref()
    }

    pub fn start(&self) -> Option<&Date> {
        self.start.as_ref()
    }

    pub fn tags(&self) -> Option<&Vec<Tag>> {
        self.tags.as_ref()
    }

    pub fn until(&self) -> Option<&Date> {
        self.until.as_ref()
    }

    pub fn wait(&self) -> Option<&Date> {
        self.wait.as_ref()
    }

}

impl Serialize for Task {

    fn serialize<S>(&self, serializer: &mut S) -> RResult<(), S::Error>
        where S: Serializer
    {
        serializer.serialize_struct("Task", TaskVisitor {
            value: self,
            state: 0,
        })
    }

}

struct TaskVisitor<'a> {
    value: &'a Task,
    state: u8,
}

impl<'a> MapVisitor for TaskVisitor<'a> {

    fn visit<S>(&mut self, serializer: &mut S) -> RResult<Option<()>, S::Error>
        where S: Serializer
    {
        match self.state {
            0 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("status", &self.value.status))))
            },
            1 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("uuid", &self.value.uuid))))
            },
            2 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("entry", &self.value.entry))))
            },
            3 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("description", &self.value.description))))
            },
            4 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("annotation", &self.value.annotation))))
            },
            5 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("depends", &self.value.depends))))
            },
            6 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("due", &self.value.due))))
            },
            7 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("end", &self.value.end))))
            },
            8 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("imask", &self.value.imask))))
            },
            9 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("mask", &self.value.mask))))
            },
            10 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("modified", &self.value.modified))))
            },
            11 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("parent", &self.value.parent))))
            },
            12 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("priority", &self.value.priority))))
            },
            13 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("project", &self.value.project))))
            },
            14 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("recur", &self.value.recur))))
            },
            15 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("scheduled", &self.value.scheduled))))
            },
            16 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("start", &self.value.start))))
            },
            17 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("tags", &self.value.tags))))
            },
            18 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("until", &self.value.until))))
            },
            19 => {
                self.state += 1;
                Ok(Some(try!(serializer.serialize_struct_elt("wait", &self.value.wait))))
            },
            _ => {
                Ok(None)
            }
        }
    }

}

impl Deserialize for Task {

    fn deserialize<D>(deserializer: &mut D) -> RResult<Task, D::Error>
        where D: Deserializer
    {
        static FIELDS: &'static [&'static str] = &[
            "status",
            "uuid",
            "entry",
            "description",

            "annotation",
            "depends",
            "due",
            "end",
            "imask",
            "mask",
            "modified",
            "parent",
            "priority",
            "project",
            "recur",
            "scheduled",
            "start",
            "tags",
            "until",
            "wait"
        ];
        deserializer.deserialize_struct("Task", FIELDS, TaskDeserializeVisitor)
    }

}

struct TaskDeserializeVisitor;

impl Visitor for TaskDeserializeVisitor {
    type Value = Task;

    fn visit_map<V>(&mut self, mut visitor: V) -> RResult<Task, V::Error>
        where V: DeserializeMapVisitor
    {
        let mut status      = None;
        let mut uuid        = None;
        let mut entry       = None;
        let mut description = None;

        let mut annotation  = None;
        let mut depends     = None;
        let mut due         = None;
        let mut end         = None;
        let mut imask       = None;
        let mut mask        = None;
        let mut modified    = None;
        let mut parent      = None;
        let mut priority    = None;
        let mut project     = None;
        let mut recur       = None;
        let mut scheduled   = None;
        let mut start       = None;
        let mut tags        = None;
        let mut until       = None;
        let mut wait        = None;

        loop {
            let key : Option<String> = try!(visitor.visit_key());
            if key.is_none() {
                break;
            }
            let key = key.unwrap();

            match &key[..] {
                "status" => {
                    status = Some(try!(visitor.visit_value()));
                },
                "uuid" => {
                    uuid = Some(try!(visitor.visit_value()));
                },
                "entry" => {
                    entry = Some(try!(visitor.visit_value()));
                },
                "description" => {
                    description = Some(try!(visitor.visit_value()));
                },

                "annotation" => {
                    annotation = Some(try!(visitor.visit_value()));
                },
                "depends" => {
                    depends = Some(try!(visitor.visit_value()));
                },
                "due" => {
                    due = Some(try!(visitor.visit_value()));
                },
                "end" => {
                    end = Some(try!(visitor.visit_value()));
                },
                "imask" => {
                    imask = Some(try!(visitor.visit_value()));
                },
                "mask" => {
                    mask = Some(try!(visitor.visit_value()));
                },
                "modified" => {
                    modified = Some(try!(visitor.visit_value()));
                },
                "parent" => {
                    parent = Some(try!(visitor.visit_value()));
                },
                "priority" => {
                    priority = Some(try!(visitor.visit_value()));
                },
                "project" => {
                    project = Some(try!(visitor.visit_value()));
                },
                "recur" => {
                    recur = Some(try!(visitor.visit_value()));
                },
                "scheduled" => {
                    scheduled = Some(try!(visitor.visit_value()));
                },
                "start" => {
                    start = Some(try!(visitor.visit_value()));
                },
                "tags" => {
                    tags = Some(try!(visitor.visit_value()));
                },
                "until" => {
                    until = Some(try!(visitor.visit_value()));
                },
                "wait" => {
                    wait = Some(try!(visitor.visit_value()));
                },

                field => {
                    use serde::de::impls::IgnoredAny;

                    debug!("field '{}' ignored", field);
                    let _: IgnoredAny = try!(visitor.visit_value());
                }
            }
        }

        let status = match status {
            Some(status) => status,
            None => try!(visitor.missing_field("status")),
        };

        let uuid = match uuid {
            Some(uuid) => uuid,
            None => try!(visitor.missing_field("uuid")),
        };

        let entry = match entry {
            Some(entry) => entry,
            None => try!(visitor.missing_field("entry")),
        };

        let description = match description {
            Some(description) => description,
            None => try!(visitor.missing_field("description")),
        };

        try!(visitor.end());

        let task = Task::new(
            status,
            uuid,
            entry,
            description,

            annotation,
            depends,
            due,
            end,
            imask,
            mask,
            modified,
            parent,
            priority,
            project,
            recur,
            scheduled,
            start,
            tags,
            until,
            wait
        );

        Ok(task)
    }
}

#[cfg(test)]
mod test {
    use date::Date;
    use date::TASKWARRIOR_DATETIME_TEMPLATE;
    use status::TaskStatus;
    use task::Task;

    use uuid::Uuid;
    use chrono::naive::datetime::NaiveDateTime;
    use serde_json;

    #[test]
    fn test_deser() {
        let s =
r#"{
"id": 1,
"description": "test",
"entry": "20150619T165438Z",
"status": "waiting",
"uuid": "8ca953d5-18b4-4eb9-bd56-18f2e5b752f0"
}"#;

        println!("{}", s);

        let task = serde_json::from_str(s);
        println!("{:?}", task);
        assert!(task.is_ok());
        let task : Task = task.unwrap();

        assert!(task.status().clone() == TaskStatus::Waiting);
        assert!(task.description() == "test");
        assert!(task.entry().clone() == Date::from(NaiveDateTime::parse_from_str("20150619T165438Z", TASKWARRIOR_DATETIME_TEMPLATE).unwrap()));
        assert!(task.uuid().clone() == Uuid::parse_str("8ca953d5-18b4-4eb9-bd56-18f2e5b752f0").unwrap());

        let back = serde_json::to_string(&task).unwrap();

        assert!(back.contains("description"));
        assert!(back.contains("test"));
        assert!(back.contains("entry"));
        assert!(back.contains("20150619T165438Z"));
        assert!(back.contains("status"));
        assert!(back.contains("waiting"));
        assert!(back.contains("uuid"));
        assert!(back.contains("8ca953d5-18b4-4eb9-bd56-18f2e5b752f0"));
    }

}

<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::f32::consts::{PI};
use std::num::{Float};
use cgmath::{perspective, rad, Matrix4, Vector, Vector3, Rad};
use common::types::{ZInt, Size2, ZFloat};
use common::misc::{clamp};
use zgl::{Zgl};
use types::{WorldPos};

pub struct Camera {
    x_angle: Rad<ZFloat>,
    z_angle: Rad<ZFloat>,
    pos: WorldPos,
    max_pos: WorldPos,
    zoom: ZFloat,
    projection_mat: Matrix4<ZFloat>,
}

fn get_projection_mat(win_size: &Size2<ZInt>) -> Matrix4<ZFloat> {
    let fov = rad(PI / 4.0);
    // let fov = rad((3.14 / 4.0) * 0.7);
    let ratio = win_size.w as ZFloat / win_size.h as ZFloat;
    let display_range_min = 0.1;
    let display_range_max = 100.0;
    perspective(
        fov, ratio, display_range_min, display_range_max)
}

impl Camera {
    pub fn new(win_size: &Size2<ZInt>) -> Camera {
        Camera {
            x_angle: rad(PI / 4.0),
            z_angle: rad(0.0),
            pos: WorldPos{v: Vector::from_value(0.0)},
            max_pos: WorldPos{v: Vector::from_value(0.0)},
            zoom: 16.0,
            projection_mat: get_projection_mat(win_size),
        }
    }

    pub fn mat(&self, zgl: &Zgl) -> Matrix4<ZFloat> {
        let mut m = self.projection_mat;
        m = zgl.tr(m, &Vector3{x: 0.0, y: 0.0, z: -self.zoom});
        m = zgl.rot_x(m, &-self.x_angle);
        m = zgl.rot_z(m, &-self.z_angle);
        m = zgl.tr(m, &self.pos.v);
        m
    }

    pub fn add_horizontal_angle(&mut self, angle: Rad<ZFloat>) {
        self.z_angle = self.z_angle + angle;
        while self.z_angle < rad(0.0) {
            self.z_angle = self.z_angle + rad(PI * 2.0);
        }
        while self.z_angle > rad(PI * 2.0) {
            self.z_angle = self.z_angle - rad(PI * 2.0);
        }
    }

    pub fn add_vertical_angle(&mut self, angle: Rad<ZFloat>) {
        self.x_angle = self.x_angle + angle;
        let min = rad(10.0.to_radians());
        let max = rad(50.0.to_radians());
        self.x_angle = clamp(self.x_angle, min, max);
    }

    fn clamp_pos(&mut self) {
        self.pos.v.x = clamp(self.pos.v.x, self.max_pos.v.x, 0.0);
        self.pos.v.y = clamp(self.pos.v.y, self.max_pos.v.y, 0.0);
    }

    pub fn set_pos(&mut self, pos: WorldPos) {
        self.pos = pos;
        self.clamp_pos();
    }

    pub fn set_max_pos(&mut self, max_pos: WorldPos) {
        self.max_pos = max_pos;
    }

    pub fn change_zoom(&mut self, ratio: ZFloat) {
        self.zoom *= ratio;
        self.zoom = clamp(self.zoom, 5.0, 40.0);
    }

    pub fn get_z_angle(&self) -> &Rad<ZFloat> {
        &self.z_angle
    }

    pub fn get_x_angle(&self) -> &Rad<ZFloat> {
        &self.x_angle
    }

    // TODO: rename to 'move'
    pub fn move_camera(&mut self, angle: Rad<ZFloat>, speed: ZFloat) {
        let diff = (self.z_angle - angle).s;
        let dx = diff.sin();
        let dy = diff.cos();
        // TODO: handle zoom
        // self.pos.v.x -= dy * speed * self.zoom;
        // self.pos.v.y -= dx * speed * self.zoom;
        self.pos.v.x -= dy * speed;
        self.pos.v.y -= dx * speed;
        self.clamp_pos();
    }

    pub fn regenerate_projection_mat(&mut self, win_size: &Size2<ZInt>) {
        self.projection_mat = get_projection_mat(win_size);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>camera.rs: Removed commented-out code for FOV setting<commit_after>// See LICENSE file for copyright and license details.

use std::f32::consts::{PI};
use std::num::{Float};
use cgmath::{perspective, rad, Matrix4, Vector, Vector3, Rad};
use common::types::{ZInt, Size2, ZFloat};
use common::misc::{clamp};
use zgl::{Zgl};
use types::{WorldPos};

pub struct Camera {
    x_angle: Rad<ZFloat>,
    z_angle: Rad<ZFloat>,
    pos: WorldPos,
    max_pos: WorldPos,
    zoom: ZFloat,
    projection_mat: Matrix4<ZFloat>,
}

fn get_projection_mat(win_size: &Size2<ZInt>) -> Matrix4<ZFloat> {
    let fov = rad(PI / 4.0);
    let ratio = win_size.w as ZFloat / win_size.h as ZFloat;
    let display_range_min = 0.1;
    let display_range_max = 100.0;
    perspective(
        fov, ratio, display_range_min, display_range_max)
}

impl Camera {
    pub fn new(win_size: &Size2<ZInt>) -> Camera {
        Camera {
            x_angle: rad(PI / 4.0),
            z_angle: rad(0.0),
            pos: WorldPos{v: Vector::from_value(0.0)},
            max_pos: WorldPos{v: Vector::from_value(0.0)},
            zoom: 16.0,
            projection_mat: get_projection_mat(win_size),
        }
    }

    pub fn mat(&self, zgl: &Zgl) -> Matrix4<ZFloat> {
        let mut m = self.projection_mat;
        m = zgl.tr(m, &Vector3{x: 0.0, y: 0.0, z: -self.zoom});
        m = zgl.rot_x(m, &-self.x_angle);
        m = zgl.rot_z(m, &-self.z_angle);
        m = zgl.tr(m, &self.pos.v);
        m
    }

    pub fn add_horizontal_angle(&mut self, angle: Rad<ZFloat>) {
        self.z_angle = self.z_angle + angle;
        while self.z_angle < rad(0.0) {
            self.z_angle = self.z_angle + rad(PI * 2.0);
        }
        while self.z_angle > rad(PI * 2.0) {
            self.z_angle = self.z_angle - rad(PI * 2.0);
        }
    }

    pub fn add_vertical_angle(&mut self, angle: Rad<ZFloat>) {
        self.x_angle = self.x_angle + angle;
        let min = rad(10.0.to_radians());
        let max = rad(50.0.to_radians());
        self.x_angle = clamp(self.x_angle, min, max);
    }

    fn clamp_pos(&mut self) {
        self.pos.v.x = clamp(self.pos.v.x, self.max_pos.v.x, 0.0);
        self.pos.v.y = clamp(self.pos.v.y, self.max_pos.v.y, 0.0);
    }

    pub fn set_pos(&mut self, pos: WorldPos) {
        self.pos = pos;
        self.clamp_pos();
    }

    pub fn set_max_pos(&mut self, max_pos: WorldPos) {
        self.max_pos = max_pos;
    }

    pub fn change_zoom(&mut self, ratio: ZFloat) {
        self.zoom *= ratio;
        self.zoom = clamp(self.zoom, 5.0, 40.0);
    }

    pub fn get_z_angle(&self) -> &Rad<ZFloat> {
        &self.z_angle
    }

    pub fn get_x_angle(&self) -> &Rad<ZFloat> {
        &self.x_angle
    }

    // TODO: rename to 'move'
    pub fn move_camera(&mut self, angle: Rad<ZFloat>, speed: ZFloat) {
        let diff = (self.z_angle - angle).s;
        let dx = diff.sin();
        let dy = diff.cos();
        // TODO: handle zoom
        // self.pos.v.x -= dy * speed * self.zoom;
        // self.pos.v.y -= dx * speed * self.zoom;
        self.pos.v.x -= dy * speed;
        self.pos.v.y -= dx * speed;
        self.clamp_pos();
    }

    pub fn regenerate_projection_mat(&mut self, win_size: &Size2<ZInt>) {
        self.projection_mat = get_projection_mat(win_size);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use hyper::Client;
use hyper::client::Body;

use std::io::Read;
use std::collections::BTreeMap;

use serde_json::{to_vec, from_reader};

use errors::{Result, HueError};
use ::hue::*;
use ::json::*;

/// Attempts to discover bridges using `https://www.meethue.com/api/nupnp`
#[cfg(feature = "nupnp")]
pub fn discover() -> Result<Vec<Discovery>> {
    use hyper::net::HttpsConnector;
    use hyper_openssl::OpensslClient;

    let ssl = OpensslClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);

    client.get("https://www.meethue.com/api/nupnp")
        .send()
        .map_err(HueError::from)
        .and_then(|ref mut r| from_reader(r).map_err(From::from))
}
/// Discovers bridge IP using UPnP
///
/// Waits for about 5 seconds to make sure it gets a response
#[cfg(feature = "ssdp")]
pub fn discover_upnp() -> ::std::result::Result<Vec<String>, ::ssdp::SSDPError> {
    use ssdp::header::{HeaderMut, Man, MX, ST};
    use ssdp::message::SearchRequest;
    use ssdp::FieldMap;
    use ssdp::message::Multicast;

    let mut request = SearchRequest::new();

    request.set(Man);
    request.set(MX(5));
    request.set(ST::Target(FieldMap::upnp("IpBridge")));

    request.multicast().map(|r| {
        r.into_iter()
            .map(|(_, src)| src.ip().to_string())
            .collect()
    })
}
/// Tries to register a user, returning the username if successful
///
/// This usually returns a `HueError::BridgeError` saying the link button needs to be pressed.
/// Therefore it recommended to call this function in a loop:
/// ## Example
/// ```no_run
/// use philipshue::errors::{HueError, HueErrorKind, BridgeError};
/// use philipshue::bridge::{self, Bridge};
///
/// let mut bridge = None;
/// // Discover a bridge
/// let bridge_ip = philipshue::bridge::discover().unwrap().pop().unwrap().into_ip();
/// let devicetype = "my_hue_app#homepc";
///
/// // Keep trying to register a user
/// loop{
///     match bridge::register_user(&bridge_ip, devicetype){
///         // A new user has succesfully been registered and the username is returned
///         Ok(username) => {
///             bridge = Some(Bridge::new(bridge_ip, username));
///             break;
///         },
///         // Prompt the user to press the link button
///         Err(HueError(HueErrorKind::BridgeError{error: BridgeError::LinkButtonNotPressed, ..}, _)) => {
///             println!("Please, press the link on the bridge. Retrying in 5 seconds");
///             std::thread::sleep(std::time::Duration::from_secs(5));
///         },
///         // Some other error happened
///         Err(e) => {
///             println!("Unexpected error occured: {:?}", e);
///             break
///         }
///     }
/// }
/// ```
pub fn register_user(ip: &str, devicetype: &str) -> Result<String> {
    let client = Client::new();

    let body = format!("{{\"devicetype\": {:?}}}", devicetype);
    let body = body.as_bytes();
    let url = format!("http://{}/api", ip);
    let mut resp = client.post(&url)
        .body(Body::BufBody(body, body.len()))
        .send()?;

    from_reader::<_, Vec<HueResponse<User>>>(&mut resp)?
        .pop()
        .unwrap()
        .into_result()
        .map(|u| u.username)
}

#[derive(Debug)]
/// The bridge connection
pub struct Bridge {
    client: Client,
    url: String,
}

fn send_with_body<'a, T>(rb: RequestBuilder<'a>, body: &'a [u8]) -> Result<T>
    where for<'de> T: Deserialize<'de>
{
    send(rb.body(Body::BufBody(body, body.len())))
}

fn send<T>(rb: RequestBuilder) -> Result<T>
    where for<'de> T: Deserialize<'de>
{
    rb.send()
        .map_err(HueError::from)
        .and_then(|ref mut resp| {
            let mut buf = Vec::new();
            resp.read_to_end(&mut buf)?;

            match from_reader::<_, T>(&mut &*buf) {
                Ok(t) => Ok(t),
                Err(_) => from_reader::<_, Vec<HueResponse<T>>>(&mut &*buf)?
                    .into_iter()
                    .next()
                    .ok_or_else(|| "Malformed response".into())
                    .and_then(HueResponse::into_result)
            }
        })
}

#[test]
fn get_ip_and_username() {
    let b = Bridge::new("test", "hello");
    assert_eq!(b.get_ip(), "test");
    assert_eq!(b.get_username(), "hello");
}

/// Many commands on the bridge return an array of things that were succesful.
/// This is a type alias for that type.
pub type SuccessVec = Vec<JsonMap<String, JsonValue>>;

use serde::Deserialize;
use hyper::client::RequestBuilder;

fn extract<'de, T>(responses: Vec<HueResponse<T>>) -> Result<Vec<T>>
    where T: Deserialize<'de>
{
    let mut res_v = Vec::with_capacity(responses.len());
    for val in responses {
        res_v.push(val.into_result()?)
    }
    Ok(res_v)
}

impl Bridge {
    /// Creates a `Bridge` on the given IP with the given username
    pub fn new<S: Into<String>, U: Into<String>>(ip: S, username: U) -> Self {
        Bridge {
            client: Client::new(),
            url: format!("http://{}/api/{}/", ip.into(), username.into()),
        }
    }
    /// Gets the IP of bridge
    pub fn get_ip(&self) -> &str {
        self.url.split('/').nth(2).unwrap()
    }
    /// Gets the username this `Bridge` uses
    pub fn get_username(&self) -> &str {
        self.url.split('/').nth(4).unwrap()
    }
    /// Gets all lights that are connected to the bridge
    pub fn get_all_lights(&self) -> Result<BTreeMap<usize, Light>> {
        send(self.client.get(&format!("{}lights", self.url)))
    }
    /// Gets the light with the specific id
    pub fn get_light(&self, id: usize) -> Result<Light> {
        send(self.client.get(&format!("{}lights/{}", self.url, id)))
    }
    /// Gets all the light that were found last time a search for new lights was done
    pub fn get_new_lights(&self) -> Result<BTreeMap<usize, Light>> {
        // TODO return lastscan too
        send(self.client.get(&format!("{}lights/new", self.url)))
    }
    /// Makes the bridge search for new lights (and switches).
    ///
    /// The found lights can be retrieved with `get_new_lights()`
    pub fn search_for_new_lights(&self) -> Result<SuccessVec> {
        // TODO Allow deviceids to be specified
        send(self.client.post(&format!("{}lights", self.url))).and_then(extract)
    }
    /// Sets the state of a light by sending a `LightCommand` to the bridge for this light
    pub fn set_light_state(&self, id: usize, command: &LightCommand) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}lights/{}/state", self.url, id)),
                       &to_vec(command)?)
            .and_then(extract)
    }
    /// Renames the light
    pub fn rename_light(&self, id: usize, name: String) -> Result<SuccessVec> {
        let mut name_map = BTreeMap::new();
        name_map.insert("name".to_owned(), name);
        send_with_body(self.client.put(&format!("{}lights/{}", self.url, id)),
                       &to_vec(&name_map)?)
            .and_then(extract)
    }
    /// Deletes a light from the bridge
    pub fn delete_light(&self, id: usize) -> Result<SuccessVec> {
        send(self.client.delete(&format!("{}lights/{}", self.url, id))).and_then(extract)
    }

    // GROUPS

    /// Gets all groups of the bridge
    pub fn get_all_groups(&self) -> Result<BTreeMap<usize, Group>> {
        send(self.client.get(&format!("{}groups", self.url)))
    }
    /// Creates a group and returns the ID of the group
    pub fn create_group(&self, name: String, lights: Vec<usize>, group_type: GroupType, room_class: Option<RoomClass>) -> Result<usize> {
        let g = Group {
            name: name,
            lights: lights,
            group_type: group_type,
            class: room_class,
            state: None,
            action: None,
        };
        let r: HueResponse<Id<usize>> = send_with_body(self.client.post(&format!("{}groups", self.url)),
                                                     &to_vec(&g)?)?;
        r.into_result().map(|g| g.id)
    }
    /// Gets extra information about a specific group
    pub fn get_group_attributes(&self, id: usize) -> Result<Group> {
        send(self.client.get(&format!("{}groups/{}", self.url, id)))
    }
    /// Set the name, light and class of a group
    pub fn set_group_attributes(&self, id: usize, attr: &GroupCommand) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}groups/{}", self.url, id)),
                       &to_vec(attr)?)
            .and_then(extract)
    }
    /// Sets the state of all lights in the group.
    ///
    /// ID 0 is a sepcial group containing all lights known to the bridge
    pub fn set_group_state(&self, id: usize, state: &LightCommand) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}groups/{}/action", self.url, id)),
                       &to_vec(state)?)
            .and_then(extract)
    }
    /// Deletes the specified group
    ///
    /// It's not allowed to delete groups of type `LightSource` or `Luminaire`.
    pub fn delete_group(&self, id: usize) -> Result<Vec<String>> {
        send(self.client.delete(&format!("{}groups/{}", self.url, id))).and_then(extract)
    }

    // CONFIGURATION

    /// Returns detailed information about the configuration of the bridge.
    pub fn get_configuration(&self) -> Result<Configuration> {
        send(self.client.get(&format!("{}config", self.url)))
    }
    /// Sets some configuration values.
    pub fn modify_configuration(&self, command: &ConfigurationModifier) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}config", self.url)),
                       &to_vec(command)?)
            .and_then(extract)
    }
    /// Deletes the specified user removing them from the whitelist.
    pub fn delete_user(&self, username: &str) -> Result<Vec<String>> {
        send(self.client.delete(&format!("{}config/whitelist/{}", self.url, username)))
            .and_then(extract)
    }
    /// Fetches the entire datastore from the bridge.
    ///
    /// This is a resource intensive command for the bridge, and should therefore be used sparingly.
    pub fn get_full_state(&self) -> Result<FullState> {
        send(self.client.get(&self.url))
    }

    /// Sets the state of lights in the group to the state in the scene
    ///
    /// Note that this will affect that are both in the group and in the scene.
    /// Using group 0 will set all the lights in the scene, since group 0 is a special
    /// group that contains all lights
    pub fn recall_scene_in_group(&self, group_id: usize, scene_id: &str) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}groups/{}/action", self.url, group_id)),
                       &to_vec(&SceneRecall{scene: scene_id})?)
            .and_then(extract)
    }

    // SCENES

    /// Gets all scenes of the bridge
    pub fn get_all_scenes(&self) -> Result<BTreeMap<String, Scene>> {
        send(self.client.get(&format!("{}scenes", self.url)))
    }
    /// Creates a scene on the bridge and returns the ID of the created scene.
    pub fn create_scene(&self, scene: &SceneCreater) -> Result<String> {
        let r: HueResponse<Id<String>> = send_with_body(self.client.post(&format!("{}scenes", self.url)),
                                                        &to_vec(scene)?)?;
        r.into_result().map(|g| g.id)
    }
    /// Sets general things in the specified scene
    pub fn modify_scene(&self, id: &str, scene: &SceneModifier) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}scenes/{}", self.url, id)), &to_vec(scene)?)
            .and_then(extract)
    }
    /// Sets the light state of the specified ID that is stored in the scene
    pub fn set_light_state_in_scene(&self, scene_id: &str, light_id: usize,
        state: &LightStateChange) -> Result<SuccessVec> {

        send_with_body(self.client.put(&format!("{}scenes/{}/lightstates/{}", self.url,
            scene_id, light_id)), &to_vec(state)?).and_then(extract)
    }
    /// Deletes the specified scene
    pub fn delete_scene(&self, id: &str) -> Result<Vec<String>> {
        send(self.client.delete(&format!("{}scenes/{}", self.url, id))).and_then(extract)
    }
    /// Gets the scene with the specified ID with its `lightstates`
    pub fn get_scene_with_states(&self, id: &str) -> Result<Scene> {
        send(self.client.get(&format!("{}scenes/{}", self.url, id)))
    }
}
<commit_msg>Refactor a bit<commit_after>use hyper::Client;
use hyper::client::Body;

use std::io::Read;
use std::collections::BTreeMap;

use serde::de::DeserializeOwned;
use serde_json::{to_vec, from_slice, from_reader};

use errors::{Result, HueError};
use ::hue::*;
use ::json::*;

/// Attempts to discover bridges using `https://www.meethue.com/api/nupnp`
#[cfg(feature = "nupnp")]
pub fn discover() -> Result<Vec<Discovery>> {
    use hyper::net::HttpsConnector;
    use hyper_openssl::OpensslClient;

    let ssl = OpensslClient::new().unwrap();
    let connector = HttpsConnector::new(ssl);
    let client = Client::with_connector(connector);

    client.get("https://www.meethue.com/api/nupnp")
        .send()
        .map_err(HueError::from)
        .and_then(|ref mut r| from_reader(r).map_err(From::from))
}
/// Discovers bridge IP using UPnP
///
/// Waits for about 5 seconds to make sure it gets a response
#[cfg(feature = "ssdp")]
pub fn discover_upnp() -> ::std::result::Result<Vec<String>, ::ssdp::SSDPError> {
    use ssdp::header::{HeaderMut, Man, MX, ST};
    use ssdp::message::SearchRequest;
    use ssdp::FieldMap;
    use ssdp::message::Multicast;

    let mut request = SearchRequest::new();

    request.set(Man);
    request.set(MX(5));
    request.set(ST::Target(FieldMap::upnp("IpBridge")));

    request.multicast().map(|r| {
        r.into_iter()
            .map(|(_, src)| src.ip().to_string())
            .collect()
    })
}
/// Tries to register a user, returning the username if successful
///
/// This usually returns a `HueError::BridgeError` saying the link button needs to be pressed.
/// Therefore it recommended to call this function in a loop:
/// ## Example
/// ```no_run
/// use philipshue::errors::{HueError, HueErrorKind, BridgeError};
/// use philipshue::bridge::{self, Bridge};
///
/// let mut bridge = None;
/// // Discover a bridge
/// let bridge_ip = philipshue::bridge::discover().unwrap().pop().unwrap().into_ip();
/// let devicetype = "my_hue_app#homepc";
///
/// // Keep trying to register a user
/// loop{
///     match bridge::register_user(&bridge_ip, devicetype){
///         // A new user has succesfully been registered and the username is returned
///         Ok(username) => {
///             bridge = Some(Bridge::new(bridge_ip, username));
///             break;
///         },
///         // Prompt the user to press the link button
///         Err(HueError(HueErrorKind::BridgeError{error: BridgeError::LinkButtonNotPressed, ..}, _)) => {
///             println!("Please, press the link on the bridge. Retrying in 5 seconds");
///             std::thread::sleep(std::time::Duration::from_secs(5));
///         },
///         // Some other error happened
///         Err(e) => {
///             println!("Unexpected error occured: {:?}", e);
///             break
///         }
///     }
/// }
/// ```
pub fn register_user(ip: &str, devicetype: &str) -> Result<String> {
    let client = Client::new();

    let body = format!("{{\"devicetype\": {:?}}}", devicetype);
    let body = body.as_bytes();
    let url = format!("http://{}/api", ip);
    let mut resp = client.post(&url)
        .body(Body::BufBody(body, body.len()))
        .send()?;

    from_reader::<_, Vec<HueResponse<User>>>(&mut resp)?
        .pop()
        .unwrap()
        .into_result()
        .map(|u| u.username)
}

#[derive(Debug)]
/// The bridge connection
pub struct Bridge {
    client: Client,
    url: String,
}

fn send_with_body<'a, T: DeserializeOwned>(rb: RequestBuilder<'a>, body: &'a [u8]) -> Result<T> {
    send(rb.body(Body::BufBody(body, body.len())))
}

fn send<T: DeserializeOwned>(rb: RequestBuilder) -> Result<T> {
    rb.send()
        .map_err(HueError::from)
        .and_then(|ref mut resp| {
            let mut buf = Vec::new();
            resp.read_to_end(&mut buf)?;

            from_slice(&buf).or_else(|e| {
                from_slice::<Vec<HueResponse<T>>>(&buf)?
                    .into_iter()
                    .next()
                    .ok_or_else(|| "Malformed response".into())
                    .and_then(HueResponse::into_result)
            })
        })
}

#[test]
fn get_ip_and_username() {
    let b = Bridge::new("test", "hello");
    assert_eq!(b.get_ip(), "test");
    assert_eq!(b.get_username(), "hello");
}

/// Many commands on the bridge return an array of things that were succesful.
/// This is a type alias for that type.
pub type SuccessVec = Vec<JsonMap<String, JsonValue>>;

use serde::Deserialize;
use hyper::client::RequestBuilder;

fn extract<'a, T: Deserialize<'a>>(responses: Vec<HueResponse<T>>) -> Result<Vec<T>> {
    let mut res_v = Vec::with_capacity(responses.len());
    for val in responses {
        res_v.push(val.into_result()?)
    }
    Ok(res_v)
}

impl Bridge {
    /// Creates a `Bridge` on the given IP with the given username
    pub fn new<S: Into<String>, U: Into<String>>(ip: S, username: U) -> Self {
        Bridge {
            client: Client::new(),
            url: format!("http://{}/api/{}/", ip.into(), username.into()),
        }
    }
    /// Gets the IP of bridge
    pub fn get_ip(&self) -> &str {
        self.url.split('/').nth(2).unwrap()
    }
    /// Gets the username this `Bridge` uses
    pub fn get_username(&self) -> &str {
        self.url.split('/').nth(4).unwrap()
    }
    /// Gets all lights that are connected to the bridge
    pub fn get_all_lights(&self) -> Result<BTreeMap<usize, Light>> {
        send(self.client.get(&format!("{}lights", self.url)))
    }
    /// Gets the light with the specific id
    pub fn get_light(&self, id: usize) -> Result<Light> {
        send(self.client.get(&format!("{}lights/{}", self.url, id)))
    }
    /// Gets all the light that were found last time a search for new lights was done
    pub fn get_new_lights(&self) -> Result<BTreeMap<usize, Light>> {
        // TODO return lastscan too
        send(self.client.get(&format!("{}lights/new", self.url)))
    }
    /// Makes the bridge search for new lights (and switches).
    ///
    /// The found lights can be retrieved with `get_new_lights()`
    pub fn search_for_new_lights(&self) -> Result<SuccessVec> {
        // TODO Allow deviceids to be specified
        send(self.client.post(&format!("{}lights", self.url))).and_then(extract)
    }
    /// Sets the state of a light by sending a `LightCommand` to the bridge for this light
    pub fn set_light_state(&self, id: usize, command: &LightCommand) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}lights/{}/state", self.url, id)),
                       &to_vec(command)?)
            .and_then(extract)
    }
    /// Renames the light
    pub fn rename_light(&self, id: usize, name: String) -> Result<SuccessVec> {
        let mut name_map = BTreeMap::new();
        name_map.insert("name".to_owned(), name);
        send_with_body(self.client.put(&format!("{}lights/{}", self.url, id)),
                       &to_vec(&name_map)?)
            .and_then(extract)
    }
    /// Deletes a light from the bridge
    pub fn delete_light(&self, id: usize) -> Result<SuccessVec> {
        send(self.client.delete(&format!("{}lights/{}", self.url, id))).and_then(extract)
    }

    // GROUPS

    /// Gets all groups of the bridge
    pub fn get_all_groups(&self) -> Result<BTreeMap<usize, Group>> {
        send(self.client.get(&format!("{}groups", self.url)))
    }
    /// Creates a group and returns the ID of the group
    pub fn create_group(&self, name: String, lights: Vec<usize>, group_type: GroupType, room_class: Option<RoomClass>) -> Result<usize> {
        let g = Group {
            name: name,
            lights: lights,
            group_type: group_type,
            class: room_class,
            recycle: None,
            state: None,
            action: None,
        };
        let r: HueResponse<Id<usize>> = send_with_body(self.client.post(&format!("{}groups", self.url)),
                                                     &to_vec(&g)?)?;
        r.into_result().map(|g| g.id)
    }
    /// Gets extra information about a specific group
    pub fn get_group_attributes(&self, id: usize) -> Result<Group> {
        send(self.client.get(&format!("{}groups/{}", self.url, id)))
    }
    /// Set the name, light and class of a group
    pub fn set_group_attributes(&self, id: usize, attr: &GroupCommand) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}groups/{}", self.url, id)),
                       &to_vec(attr)?)
            .and_then(extract)
    }
    /// Sets the state of all lights in the group.
    ///
    /// ID 0 is a sepcial group containing all lights known to the bridge
    pub fn set_group_state(&self, id: usize, state: &LightCommand) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}groups/{}/action", self.url, id)),
                       &to_vec(state)?)
            .and_then(extract)
    }
    /// Deletes the specified group
    ///
    /// It's not allowed to delete groups of type `LightSource` or `Luminaire`.
    pub fn delete_group(&self, id: usize) -> Result<Vec<String>> {
        send(self.client.delete(&format!("{}groups/{}", self.url, id))).and_then(extract)
    }

    // CONFIGURATION

    /// Returns detailed information about the configuration of the bridge.
    pub fn get_configuration(&self) -> Result<Configuration> {
        send(self.client.get(&format!("{}config", self.url)))
    }
    /// Sets some configuration values.
    pub fn modify_configuration(&self, command: &ConfigurationModifier) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}config", self.url)),
                       &to_vec(command)?)
            .and_then(extract)
    }
    /// Deletes the specified user removing them from the whitelist.
    pub fn delete_user(&self, username: &str) -> Result<Vec<String>> {
        send(self.client.delete(&format!("{}config/whitelist/{}", self.url, username)))
            .and_then(extract)
    }
    /// Fetches the entire datastore from the bridge.
    ///
    /// This is a resource intensive command for the bridge, and should therefore be used sparingly.
    pub fn get_full_state(&self) -> Result<FullState> {
        send(self.client.get(&self.url))
    }

    /// Sets the state of lights in the group to the state in the scene
    ///
    /// Note that this will affect that are both in the group and in the scene.
    /// Using group 0 will set all the lights in the scene, since group 0 is a special
    /// group that contains all lights
    pub fn recall_scene_in_group(&self, group_id: usize, scene_id: &str) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}groups/{}/action", self.url, group_id)),
                       &to_vec(&SceneRecall{scene: scene_id})?)
            .and_then(extract)
    }

    // SCENES

    /// Gets all scenes of the bridge
    pub fn get_all_scenes(&self) -> Result<BTreeMap<String, Scene>> {
        send(self.client.get(&format!("{}scenes", self.url)))
    }
    /// Creates a scene on the bridge and returns the ID of the created scene.
    pub fn create_scene(&self, scene: &SceneCreater) -> Result<String> {
        let r: HueResponse<Id<String>> = send_with_body(self.client.post(&format!("{}scenes", self.url)),
                                                        &to_vec(scene)?)?;
        r.into_result().map(|g| g.id)
    }
    /// Sets general things in the specified scene
    pub fn modify_scene(&self, id: &str, scene: &SceneModifier) -> Result<SuccessVec> {
        send_with_body(self.client.put(&format!("{}scenes/{}", self.url, id)), &to_vec(scene)?)
            .and_then(extract)
    }
    /// Sets the light state of the specified ID that is stored in the scene
    pub fn set_light_state_in_scene(&self, scene_id: &str, light_id: usize,
        state: &LightStateChange) -> Result<SuccessVec> {

        send_with_body(self.client.put(&format!("{}scenes/{}/lightstates/{}", self.url,
            scene_id, light_id)), &to_vec(state)?).and_then(extract)
    }
    /// Deletes the specified scene
    pub fn delete_scene(&self, id: &str) -> Result<Vec<String>> {
        send(self.client.delete(&format!("{}scenes/{}", self.url, id))).and_then(extract)
    }
    /// Gets the scene with the specified ID with its `lightstates`
    pub fn get_scene_with_states(&self, id: &str) -> Result<Scene> {
        send(self.client.get(&format!("{}scenes/{}", self.url, id)))
    }
}
<|endoftext|>