<commit_before>use collections::Vec;

use serde::ser::{Serialize, SerializeMap, SerializeStruct, SerializeStructVariant};

use byteorder::{ByteOrder, BigEndian};

use ser::Serializer;

use defs::*;
use error::*;

pub struct MapSerializer<'a, F: 'a + FnMut(&[u8]) -> Result<()>> {
    count: usize,
    size: Option<usize>,
    buffer: Vec<u8>,
    output: &'a mut F,
}

impl<'a, F: 'a + FnMut(&[u8]) -> Result<()>> MapSerializer<'a, F> {
    pub fn new(output: &'a mut F) -> MapSerializer<'a, F> {
        MapSerializer {
            count: 0,
            size: None,
            buffer: vec![],
            output: output,
        }
    }

    pub fn hint_size(&mut self, size: Option<usize>) -> Result<()> {
        self.size = size;

        if let Some(size) = self.size {
            // output this now because we know it
            self.output_map_header(size)
        } else {
            Ok(())
        }
    }

    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        self.count += 1;

        if self.should_serialize_directly() {
            self.serialize_directly(value)
        } else {
            self.serialize_into_buffer(value)
        }
    }

    fn finish(mut self) -> Result<()> {
        if let Some(size) = self.size {
            self.check_item_count_matches_size(size * 2);
            Ok(())
        } else {
            let count = self.get_item_count()?;
            self.output_map_header(count)?;
            (self.output)(&*self.buffer)
        }
    }

    fn output_map_header(&mut self, size: usize) -> Result<()> {
        if size <= MAX_FIXMAP {
            (self.output)(&[size as u8 | FIXMAP_MASK])
        } else if size <= MAX_MAP16 {
            let mut buf = [MAP16; U16_BYTES + 1];
            BigEndian::write_u16(&mut buf[1..], size as u16);
            (self.output)(&buf)
        } else if size <= MAX_MAP32 {
            let mut buf = [MAP32; U32_BYTES + 1];
            BigEndian::write_u32(&mut buf[1..], size as u32);
            (self.output)(&buf)
        } else {
            Err(Error::simple(Reason::TooBig))
        }
    }

    fn get_item_count(&self) -> Result<usize> {
        if self.count % 1 != 0 {
            Err(Error::simple(Reason::BadLength))
        } else {
            Ok(self.count / 2)
        }
    }

    fn check_item_count_matches_size(&self, size: usize) -> Result<()> {
        if size != self.count {
            Err(Error::simple(Reason::BadLength))
        } else {
            Ok(())
        }
    }

    fn should_serialize_directly(&mut self) -> bool {
        self.size.is_some()
    }

    fn serialize_into_buffer<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        let mut target = Serializer::new(|bytes| {
            self.buffer.extend_from_slice(bytes);
            Ok(())
        });

        value.serialize(&mut target)
    }

    fn serialize_directly<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        let mut target = Serializer::new(|bytes| (self.output)(bytes));

        value.serialize(&mut target)
    }
}

impl<'a, F: 'a + FnMut(&[u8]) -> Result<()>> SerializeMap for MapSerializer<'a, F> {
    type Ok = ();
    type Error = Error;

    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        MapSerializer::serialize_element(self, key)
    }

    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        MapSerializer::serialize_element(self, value)
    }

    fn end(self) -> Result<()> {
        MapSerializer::finish(self)
    }
}

impl<'a, F: 'a + FnMut(&[u8]) -> Result<()>> SerializeStruct for MapSerializer<'a, F> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        MapSerializer::serialize_entry(self, key, value)
    }

    fn end(self) -> Result<()> {
        MapSerializer::finish(self)
    }
}

impl<'a, F: 'a + FnMut(&[u8]) -> Result<()>> SerializeStructVariant for MapSerializer<'a, F> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        MapSerializer::serialize_entry(self, key, value)
    }

    fn end(self) -> Result<()> {
        MapSerializer::finish(self)
    }
}<commit_msg>fix(ser): Check result instead of ignoring it<commit_after>use collections::Vec;

use serde::ser::{Serialize, SerializeMap, SerializeStruct, SerializeStructVariant};

use byteorder::{ByteOrder, BigEndian};

use ser::Serializer;

use defs::*;
use error::*;

pub struct MapSerializer<'a, F: 'a + FnMut(&[u8]) -> Result<()>> {
    count: usize,
    size: Option<usize>,
    buffer: Vec<u8>,
    output: &'a mut F,
}

impl<'a, F: 'a + FnMut(&[u8]) -> Result<()>> MapSerializer<'a, F> {
    pub fn new(output: &'a mut F) -> MapSerializer<'a, F> {
        MapSerializer {
            count: 0,
            size: None,
            buffer: vec![],
            output: output,
        }
    }

    pub fn hint_size(&mut self, size: Option<usize>) -> Result<()> {
        self.size = size;

        if let Some(size) = self.size {
            // output this now because we know it
            self.output_map_header(size)
        } else {
            Ok(())
        }
    }

    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        self.count += 1;

        if self.should_serialize_directly() {
            self.serialize_directly(value)
        } else {
            self.serialize_into_buffer(value)
        }
    }

    fn finish(mut self) -> Result<()> {
        if let Some(size) = self.size {
            self.check_item_count_matches_size(size * 2)?;
            Ok(())
        } else {
            let count = self.get_item_count()?;
            self.output_map_header(count)?;
            (self.output)(&*self.buffer)
        }
    }

    fn output_map_header(&mut self, size: usize) -> Result<()> {
        if size <= MAX_FIXMAP {
            (self.output)(&[size as u8 | FIXMAP_MASK])
        } else if size <= MAX_MAP16 {
            let mut buf = [MAP16; U16_BYTES + 1];
            BigEndian::write_u16(&mut buf[1..], size as u16);
            (self.output)(&buf)
        } else if size <= MAX_MAP32 {
            let mut buf = [MAP32; U32_BYTES + 1];
            BigEndian::write_u32(&mut buf[1..], size as u32);
            (self.output)(&buf)
        } else {
            Err(Error::simple(Reason::TooBig))
        }
    }

    fn get_item_count(&self) -> Result<usize> {
        if self.count % 1 != 0 {
            Err(Error::simple(Reason::BadLength))
        } else {
            Ok(self.count / 2)
        }
    }

    fn check_item_count_matches_size(&self, size: usize) -> Result<()> {
        if size != self.count {
            Err(Error::simple(Reason::BadLength))
        } else {
            Ok(())
        }
    }

    fn should_serialize_directly(&mut self) -> bool {
        self.size.is_some()
    }

    fn serialize_into_buffer<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        let mut target = Serializer::new(|bytes| {
            self.buffer.extend_from_slice(bytes);
            Ok(())
        });

        value.serialize(&mut target)
    }

    fn serialize_directly<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        let mut target = Serializer::new(|bytes| (self.output)(bytes));

        value.serialize(&mut target)
    }
}

impl<'a, F: 'a + FnMut(&[u8]) -> Result<()>> SerializeMap for MapSerializer<'a, F> {
    type Ok = ();
    type Error = Error;

    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        MapSerializer::serialize_element(self, key)
    }

    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        MapSerializer::serialize_element(self, value)
    }

    fn end(self) -> Result<()> {
        MapSerializer::finish(self)
    }
}

impl<'a, F: 'a + FnMut(&[u8]) -> Result<()>> SerializeStruct for MapSerializer<'a, F> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        MapSerializer::serialize_entry(self, key, value)
    }

    fn end(self) -> Result<()> {
        MapSerializer::finish(self)
    }
}

impl<'a, F: 'a + FnMut(&[u8]) -> Result<()>> SerializeStructVariant for MapSerializer<'a, F> {
    type Ok = ();
    type Error = Error;

    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
        where T: ?Sized + Serialize
    {
        MapSerializer::serialize_entry(self, key, value)
    }

    fn end(self) -> Result<()> {
        MapSerializer::finish(self)
    }
}<|endoftext|>


<commit_before>//! Definition of Thinkerbell scripts.
//!
//! Typical applications will not interact with script
//! objects. Rather, they will use module `parse` to parse a script
//! and module `run` to execute it.

use foxbox_taxonomy::values::*;
use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::util::Phantom;

use serde::ser::{ Serialize, Serializer };
use serde::de::{ Deserialize, Deserializer, Error };

/// A thinkerbell script.
#[derive(Serialize, Deserialize)]
pub struct Script<Ctx> where Ctx: Context {
    /// A set of rules, stating what must be done in which circumstance.
    pub rules: Vec<Rule<Ctx>>,

    #[serde(default)]
    #[allow(dead_code)]
    pub phantom: Phantom<Ctx>,
}

/// A single rule, i.e. "when some condition becomes true, do
/// something".
#[derive(Serialize, Deserialize)]
pub struct Rule<Ctx> where Ctx: Context {
    /// The condition in which to execute the trigger. The condition
    /// is matched once *all* the `Match` branches are true. Whenever
    /// `conditions` was false and becomes true, we execute `execute`.
    pub conditions: Vec<Match<Ctx>>,

    /// Stuff to do once `condition` is met.
    pub execute: Vec<Statement<Ctx>>,

    #[serde(default)]
    #[allow(dead_code)]
    pub phantom: Phantom<Ctx>,
}

/// An individual match.
///
/// Matchs always take the form: "data received from getter channel
/// is in given range".
///
/// A condition is true if *any* of the corresponding getter channels
/// yielded a value that is in the given range.
#[derive(Serialize, Deserialize)]
pub struct Match<Ctx> where Ctx: Context {
    /// The set of getters to watch. Note that the set of getters may
    /// change (e.g. when devices are added/removed) without rebooting
    /// the script.
    pub source: Vec<GetterSelector>,

    /// The kind of channel expected from `source`, e.g. "the current
    /// time of day", "is the door opened?", etc. During compilation,
    /// we make sure that we restrict to the elements of `source` that
    /// offer `kind`.
    pub kind: ChannelKind,

    /// The range of values for which the condition is considered met.
    /// During compilation, we check that the type of `range` is
    /// compatible with that of `getter`.
    pub range: Range,

    /// If specified, the values must remain in the `range` for at least
    /// `duration` before the match is considered valid. This is useful
    /// for sensors that may oscillate around a threshold or for detecting
    /// e.g. that a door has been forgotten open.
    #[serde(default)]
    pub duration: Option<Duration>,

    #[serde(default)]
    #[allow(dead_code)]
    pub phantom: Phantom<Ctx>,
}

/// Stuff to actually do. In practice, this means placing calls to devices.
#[derive(Serialize, Deserialize)]
pub struct Statement<Ctx> where Ctx: Context {
    /// The set of setters to which to send a command. Note that the
    /// set of setters may change (e.g. when devices are
    /// added/removed) without rebooting the script.
    pub destination: Vec<SetterSelector>,

    /// Data to send to the resource. During compilation, we check
    /// that the type of `value` is compatible with that of
    /// `destination`.
    pub value: Value,

    /// The kind of channel expected from `destination`, e.g. "close
    /// the door", "set the temperature", etc. During compilation, we
    /// make sure that we restrict to the elements of `destination` that
    /// offer `kind`.
    pub kind: ChannelKind,

    #[serde(default)]
    #[allow(dead_code)]
    pub phantom: Phantom<Ctx>,
}

/// A manner of representing internal nodes.
///
/// Two data structures implement `Context`:
///
/// - `UncheckedCtx`, designed to mark the fact that a script has not
/// been compiled/checked yet and must not be executed;
/// - `compile::CompiledCtx`, designed to mark the fact that a script
/// has been compiled and can be executed.
pub trait Context: Serialize + Deserialize + Default {
}

/// A Context used to represent a script that hasn't been compiled
/// yet.
#[derive(Default, Serialize, Deserialize)]
pub struct UncheckedCtx;
impl Context for UncheckedCtx {
}
<commit_msg>Removed Serialize from ast<commit_after>//! Definition of Thinkerbell scripts.
//!
//! Typical applications will not interact with script
//! objects. Rather, they will use module `parse` to parse a script
//! and module `run` to execute it.

use foxbox_taxonomy::values::*;
use foxbox_taxonomy::selector::*;
use foxbox_taxonomy::services::*;
use foxbox_taxonomy::util::Phantom;

use serde::de::{ Deserialize, Deserializer, Error };

/// A thinkerbell script.
#[derive(Deserialize)]
pub struct Script<Ctx> where Ctx: Context {
    /// A set of rules, stating what must be done in which circumstance.
    pub rules: Vec<Rule<Ctx>>,

    #[serde(default)]
    #[allow(dead_code)]
    pub phantom: Phantom<Ctx>,
}

/// A single rule, i.e. "when some condition becomes true, do
/// something".
#[derive(Deserialize)]
pub struct Rule<Ctx> where Ctx: Context {
    /// The condition in which to execute the trigger. The condition
    /// is matched once *all* the `Match` branches are true. Whenever
    /// `conditions` was false and becomes true, we execute `execute`.
    pub conditions: Vec<Match<Ctx>>,

    /// Stuff to do once `condition` is met.
    pub execute: Vec<Statement<Ctx>>,

    #[serde(default)]
    #[allow(dead_code)]
    pub phantom: Phantom<Ctx>,
}

/// An individual match.
///
/// Matchs always take the form: "data received from getter channel
/// is in given range".
///
/// A condition is true if *any* of the corresponding getter channels
/// yielded a value that is in the given range.
#[derive(Deserialize)]
pub struct Match<Ctx> where Ctx: Context {
    /// The set of getters to watch. Note that the set of getters may
    /// change (e.g. when devices are added/removed) without rebooting
    /// the script.
    pub source: Vec<GetterSelector>,

    /// The kind of channel expected from `source`, e.g. "the current
    /// time of day", "is the door opened?", etc. During compilation,
    /// we make sure that we restrict to the elements of `source` that
    /// offer `kind`.
    pub kind: ChannelKind,

    /// The range of values for which the condition is considered met.
    /// During compilation, we check that the type of `range` is
    /// compatible with that of `getter`.
    pub range: Range,

    /// If specified, the values must remain in the `range` for at least
    /// `duration` before the match is considered valid. This is useful
    /// for sensors that may oscillate around a threshold or for detecting
    /// e.g. that a door has been forgotten open.
    #[serde(default)]
    pub duration: Option<Duration>,

    #[serde(default)]
    #[allow(dead_code)]
    pub phantom: Phantom<Ctx>,
}

/// Stuff to actually do. In practice, this means placing calls to devices.
#[derive(Deserialize)]
pub struct Statement<Ctx> where Ctx: Context {
    /// The set of setters to which to send a command. Note that the
    /// set of setters may change (e.g. when devices are
    /// added/removed) without rebooting the script.
    pub destination: Vec<SetterSelector>,

    /// Data to send to the resource. During compilation, we check
    /// that the type of `value` is compatible with that of
    /// `destination`.
    pub value: Value,

    /// The kind of channel expected from `destination`, e.g. "close
    /// the door", "set the temperature", etc. During compilation, we
    /// make sure that we restrict to the elements of `destination` that
    /// offer `kind`.
    pub kind: ChannelKind,

    #[serde(default)]
    #[allow(dead_code)]
    pub phantom: Phantom<Ctx>,
}

/// A manner of representing internal nodes.
///
/// Two data structures implement `Context`:
///
/// - `UncheckedCtx`, designed to mark the fact that a script has not
/// been compiled/checked yet and must not be executed;
/// - `compile::CompiledCtx`, designed to mark the fact that a script
/// has been compiled and can be executed.
pub trait Context: Deserialize + Default {
}

/// A Context used to represent a script that hasn't been compiled
/// yet.
#[derive(Default, Deserialize)]
pub struct UncheckedCtx;
impl Context for UncheckedCtx {
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate log;

extern crate pretty_env_logger;

extern crate clap;
extern crate cabot;

use std::fmt::Arguments;
use std::fs::OpenOptions;
use std::io::{self, Write, stderr};

use log::LogLevel::Info;

use clap::{App, Arg};

use cabot::results::{CabotResult, CabotError};
use cabot::http;
use cabot::request::RequestBuilder;

const VERSION: &'static str = "0.1.0";

pub fn run() -> CabotResult<()> {
    let matches = App::new("cabot")
        .version(VERSION)
        .author("Guillaume Gauvrit <guillaume@gauvr.it>")
        .about("http(s) client")
        .arg(Arg::with_name("URL")
            .index(1)
            .required(true)
            .help("URL to request"))
        .arg(Arg::with_name("REQUEST")
            .short("X")
            .long("request")
            .default_value("GET")
            .help("Specify request command to use"))
        .arg(Arg::with_name("LINE")
            .short("H")
            .long("header")
            .takes_value(true)
            .multiple(true)
            .help("Pass custom header LINE to server"))
        .arg(Arg::with_name("FILE")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Write to FILE instead of stdout"))
        .arg(Arg::with_name("VERBOSE")
            .short("v")
            .long("verbose")
            .help("Make the operation more talkative"))
        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");

    let headers: Vec<&str> = match matches.values_of("LINE") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let request = RequestBuilder::new(url).set_http_method(http_method)
        .add_headers(&headers.as_slice())
        .build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path).unwrap();
        http::http_query(&request, &mut CabotBinWrite::new(&mut f, verbose), verbose)?;
    } else {
        http::http_query(&request, &mut CabotBinWrite::new(&mut io::stdout(), verbose), verbose)?;
    };

    Ok(())
}

fn main() {
    pretty_env_logger::init().unwrap();
    debug!("Starting cabot");
    match run() {
        Ok(()) => {
            debug!("Command cabot ended succesfully");
        }
        Err(CabotError::SchemeError(scheme)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unamanaged scheme: {}", scheme);
            std::process::exit(1);
        }
        Err(CabotError::OpaqueUrlError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "Opaque URL Error: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::UrlParseError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "URL Parse Error: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::IOError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "IOError: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::CertificateError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "CertificateError: {}", err);
            std::process::exit(1);
        }
        // Unexpexcted Error, not used
        Err(CabotError::HttpResponseParseError(_)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unexpected error");
            std::process::exit(1);
        }
        Err(CabotError::EncodingError(_)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unexpected error");
            std::process::exit(1);
        }
    }
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut Write,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut Write, verbose: bool) -> Self {
        CabotBinWrite{ out: out, verbose: verbose}
    }
}

impl<'a> Write for CabotBinWrite<'a> {

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {

        let response = String::from_utf8_lossy(buf);
        let response: Vec<&str> = response.splitn(2, "\r\n\r\n").collect();

        // If there is headers and we logged them
        if response.len() == 2 && (log_enabled!(Info) || self.verbose) {
            let headers = response.get(0).unwrap();
            let split = headers.split("\n");
            if log_enabled!(Info) {
                for part in split {
                    info!("< {}", part);
                }
            }
            else if self.verbose {
                for part in split {
                    writeln!(&mut stderr(), "< {}", part).unwrap();
                }
            }
        }

        let body = if response.len() == 2 {
            response.get(1).unwrap()
        } else {
            response.get(0).unwrap()
        };

        if log_enabled!(Info) {
            info!("< [[{} bytes]]", body.len());
        }
        else if self.verbose {
            writeln!(&mut stderr(), "< [[{} bytes]]", body.len()).unwrap();
        }

        self.out.write_all(body.as_bytes()).unwrap();
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> {
        stderr().flush()
    }

    // Don't implemented unused method

    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }

    fn write_fmt(&mut self, _: Arguments) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }

}
<commit_msg>Implement the -d option<commit_after>#[macro_use]
extern crate log;

extern crate pretty_env_logger;

extern crate clap;
extern crate cabot;

use std::fmt::Arguments;
use std::fs::OpenOptions;
use std::io::{self, Write, stderr};

use log::LogLevel::Info;

use clap::{App, Arg};

use cabot::results::{CabotResult, CabotError};
use cabot::http;
use cabot::request::RequestBuilder;

const VERSION: &'static str = "0.1.0";

pub fn run() -> CabotResult<()> {
    let matches = App::new("cabot")
        .version(VERSION)
        .author("Guillaume Gauvrit <guillaume@gauvr.it>")
        .about("http(s) client")
        .arg(Arg::with_name("URL")
            .index(1)
            .required(true)
            .help("URL to request"))
        .arg(Arg::with_name("REQUEST")
            .short("X")
            .long("request")
            .default_value("GET")
            .help("Specify request command to use"))
        .arg(Arg::with_name("LINE")
            .short("H")
            .long("header")
            .takes_value(true)
            .multiple(true)
            .help("Pass custom header LINE to server"))
        .arg(Arg::with_name("FILE")
            .short("o")
            .long("output")
            .takes_value(true)
            .help("Write to FILE instead of stdout"))
        .arg(Arg::with_name("VERBOSE")
            .short("v")
            .long("verbose")
            .help("Make the operation more talkative"))
        .arg(Arg::with_name("BODY")
            .short("d")
            .long("data")
            .takes_value(true)
            .help("Post Data (Using utf-8 encoding)"))

        .get_matches();

    let url = matches.value_of("URL").unwrap();
    let http_method = matches.value_of("REQUEST").unwrap();
    let verbose = matches.is_present("VERBOSE");
    let body = matches.value_of("BODY");

    let headers: Vec<&str> = match matches.values_of("LINE") {
        Some(headers) => headers.collect(),
        None => Vec::new(),
    };

    let mut builder = RequestBuilder::new(url)
        .set_http_method(http_method)
        .add_headers(&headers.as_slice());

    if body.is_some() {
        builder = builder.set_body_as_str(body.unwrap());
    }

    let request = builder.build()?;

    if let Some(path) = matches.value_of("FILE") {
        let mut f = OpenOptions::new()
            .write(true)
            .create(true)
            .truncate(true)
            .open(path).unwrap();
        http::http_query(&request, &mut CabotBinWrite::new(&mut f, verbose), verbose)?;
    } else {
        http::http_query(&request, &mut CabotBinWrite::new(&mut io::stdout(), verbose), verbose)?;
    };

    Ok(())
}

fn main() {
    pretty_env_logger::init().unwrap();
    debug!("Starting cabot");
    match run() {
        Ok(()) => {
            debug!("Command cabot ended succesfully");
        }
        Err(CabotError::SchemeError(scheme)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unamanaged scheme: {}", scheme);
            std::process::exit(1);
        }
        Err(CabotError::OpaqueUrlError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "Opaque URL Error: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::UrlParseError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "URL Parse Error: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::IOError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "IOError: {}", err);
            std::process::exit(1);
        }
        Err(CabotError::CertificateError(err)) => {
            let _ = writeln!(&mut std::io::stderr(), "CertificateError: {}", err);
            std::process::exit(1);
        }
        // Unexpexcted Error, not used
        Err(CabotError::HttpResponseParseError(_)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unexpected error");
            std::process::exit(1);
        }
        Err(CabotError::EncodingError(_)) => {
            let _ = writeln!(&mut std::io::stderr(), "Unexpected error");
            std::process::exit(1);
        }
    }
}

// Internal Of the Binary

struct CabotBinWrite<'a> {
    out: &'a mut Write,
    verbose: bool,
}

impl<'a> CabotBinWrite<'a> {
    pub fn new(out: &'a mut Write, verbose: bool) -> Self {
        CabotBinWrite{ out: out, verbose: verbose}
    }
}

impl<'a> Write for CabotBinWrite<'a> {

    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {

        let response = String::from_utf8_lossy(buf);
        let response: Vec<&str> = response.splitn(2, "\r\n\r\n").collect();

        // If there is headers and we logged them
        if response.len() == 2 && (log_enabled!(Info) || self.verbose) {
            let headers = response.get(0).unwrap();
            let split = headers.split("\n");
            if log_enabled!(Info) {
                for part in split {
                    info!("< {}", part);
                }
            }
            else if self.verbose {
                for part in split {
                    writeln!(&mut stderr(), "< {}", part).unwrap();
                }
            }
        }

        let body = if response.len() == 2 {
            response.get(1).unwrap()
        } else {
            response.get(0).unwrap()
        };

        if log_enabled!(Info) {
            info!("< [[{} bytes]]", body.len());
        }
        else if self.verbose {
            writeln!(&mut stderr(), "< [[{} bytes]]", body.len()).unwrap();
        }

        self.out.write_all(body.as_bytes()).unwrap();
        Ok(())
    }

    fn flush(&mut self) -> io::Result<()> {
        stderr().flush()
    }

    // Don't implemented unused method

    fn write(&mut self, _: &[u8]) -> io::Result<usize> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }

    fn write_fmt(&mut self, _: Arguments) -> io::Result<()> {
        Err(io::Error::new(io::ErrorKind::Other, "Not Implemented"))
    }

}
<|endoftext|>


<commit_before>use std::hashmap::HashSet;
use std::util;

use arith::isqrt;

pub fn sqrt(n: uint) -> (uint, ~[uint]) {
    let mut a0 = 0;
    let mut an = ~[];
    let mut set = HashSet::new();

    for (a, pqr) in A::new(n) {
        if a == 0 || set.contains(&(a, pqr)) {
            break;
        }

        set.insert((a, pqr));
        if set.len() == 1 {
            a0 = a;
        } else {
            an.push(a);
        }
    }
    return (a0, an);

    struct A {
        n: uint,
        sqn: uint,
        pqr: (uint, uint, uint)
    }
    impl A {
        fn new(n: uint) -> A {
            A { n: n, sqn: isqrt(n), pqr: (1, 0, 1) }
        }

        // a <= f_n(p, q, r) < a + 1
        // r a - q <= p sqrt(n) < r (a + 1) - pq
        // (ar - q)^2 <= np^2 < ((a+1)r - q)^2
        fn calc_a(&self) -> uint {
            // g(a, r, q) := (ar - q)^2
            #[inline]
            fn g(a: uint, r: uint, q: uint) -> uint {
                let s = a * r - q;
                return s * s;
            }

            let &A { n, sqn, pqr: (p, q, r) } = self;
            let np2 = n * p * p;
            let estim_a = (p * sqn + q) / r;
            let mut a = estim_a;
            while g(a + 1, r, q) <= np2 {
                a = a + 1;
            }
            return a;
        }
    }

    impl Iterator<(uint, (uint, uint, uint))> for A {
        // f_n (p, q, r) := (p sqrt(n) + q)/ r
        //                = a + (1 / (rp sqrt(n) + rb) / (np^2 - b^2))
        // a := |f_n(p, q, r)|
        // b := ar - q
        // (p, q, r) := (rp / m, rb / m, (np^2 - b^2) / m)
        #[inline]
        fn next(&mut self) -> Option<(uint, (uint, uint, uint))> {
            let a = self.calc_a();
            let &A { n, pqr: (p, q, r), ..} = self;

            self.pqr = if a * a == n || p == 0 {
                (0, 0, 1)
            } else {
                let b = a * r - q;
                let (p2, q2, r2) = (r*p, r*b, n*p*p - b*b);
                let m = p2.gcd(&q2).gcd(&r2);
                (p2 / m, q2 / m, r2 / m)
            };

            Some((a, self.pqr))
        }
    }
}

pub fn fold<T: FromPrimitive + Add<T, T> + Mul<T, T>>(an: &[uint]) -> (T, T) {
    let mut numer: T = FromPrimitive::from_int(1).unwrap();
    let mut denom: T = FromPrimitive::from_int(0).unwrap();

    for &a in an.rev_iter() {
        util::swap(&mut numer, &mut denom);
        let num: T = FromPrimitive::from_int(a as int).unwrap();
        numer = numer + num * denom;
    }

    return (numer, denom);
}

/// solve pel equation x^2 - d y^2 = 1
pub fn solve_pel<T: FromPrimitive + Add<T, T> + Mul<T, T>>(d: uint) -> (T, T) {
    let (a0, an) = sqrt(d);
    if an.is_empty() {
        fail!("{} is square", d)
    } else if an.len() % 2 == 0 {
        fold::<T>(~[a0] + an.init())
    } else {
        fold::<T>(~[a0] + an + an.init())
    }
}

/// solve pel equation x^2 - d y^2 = -1
pub fn solve_pel_neg<T: FromPrimitive + Add<T, T> + Mul<T, T>>(d: uint) -> (T, T) {
    let (a0, an) = sqrt(d);
    if an.len() % 2 == 0 {
        return fold::<T>(~[a0] + an + an.init());
    } else {
        return fold::<T>(~[a0] + an.init());
    }
}

/// iterates all (x, y) sufficient x^2 - d y^2 = 1
pub struct PelIterator<T> {
    d: T,
    x1y1: (T, T),
    xy: (T, T)
}

impl<T: Clone + FromPrimitive + Add<T, T> + Mul<T, T>> PelIterator<T> {
    #[inline]
    pub fn new(d: uint) -> PelIterator<T> {
        let x1y1 = solve_pel(d);
        let xy   = x1y1.clone();
        PelIterator {
            d: FromPrimitive::from_uint(d).unwrap(),
            x1y1: x1y1, xy: xy
        }
    }
}

impl<T: Add<T, T> + Mul<T, T>> Iterator<(T, T)> for PelIterator<T> {
    // x[k] + y[k]sqrt(n) = (x[1] + y[1]*sqrt(n))^k
    // x[k+1] + y[k+1]sqrt(n) = (x[k] + y[k]sqrt(n)) * (x[1] + y[1]*sqrt(n))
    //                        = (x[k]x[1] + n*y[k]y[1]) + (x[1]y[k] + x[k]y[1])sqrt(n)
    #[inline]
    fn next(&mut self) -> Option<(T, T)> {
        let next = {
            let ref d = self.d;
            let (ref x1, ref y1) = self.x1y1;
            let (ref xk, ref yk) = self.xy;
            ((*xk) * (*x1) + d * (*yk) * (*y1),
             (*yk) * (*x1) +     (*xk) * (*y1))
        };

        Some(util::replace(&mut self.xy, next))
    }
}

/// iterates all (x, y) sufficient x^2 - d y^2 = -1
pub struct PelNegIterator<T> {
    d: T,
    x1y1: (T, T),
    xy: (T, T)
}

impl<T: Clone + FromPrimitive + Add<T, T> + Mul<T, T>> PelNegIterator<T> {
    #[inline]
    pub fn new(d: uint) -> PelNegIterator<T> {
        let x1y1 = solve_pel_neg(d);
        let xy   = x1y1.clone();
        PelNegIterator {
            d: FromPrimitive::from_uint(d).unwrap(),
            x1y1: x1y1, xy: xy
        }
    }
}

impl<T: Add<T, T> + Mul<T, T>> Iterator<(T, T)> for PelNegIterator<T> {
    #[inline]
    fn next(&mut self) -> Option<(T, T)> {
        let next = {
            let ref d = self.d;
            let (ref x1, ref y1) = self.x1y1;
            let (ref xk, ref yk) = self.xy;
            let (xk, yk) = ((*xk) * (*x1) + d * (*yk) * (*y1),
                            (*yk) * (*x1) +     (*xk) * (*y1));
            (xk * (*x1) + d * yk * (*y1),
             yk * (*x1) +     xk * (*y1))
        };

        Some(util::replace(&mut self.xy, next))
    }
}

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

    #[test]
    fn test_sqrt() {
        assert_eq!(sqrt(1), (1, ~[]));
        assert_eq!(sqrt(2), (1, ~[2]));
        assert_eq!(sqrt(3), (1, ~[1,2]));
        assert_eq!(sqrt(4), (2, ~[]));
        assert_eq!(sqrt(5), (2, ~[4]));
        assert_eq!(sqrt(6), (2, ~[2,4]));
        assert_eq!(sqrt(7), (2, ~[1,1,1,4]));
        assert_eq!(sqrt(8), (2, ~[1,4]));
        assert_eq!(sqrt(9), (3, ~[]));
        assert_eq!(sqrt(10), (3, ~[6]));
        assert_eq!(sqrt(11), (3, ~[3,6]));
        assert_eq!(sqrt(12), (3, ~[2,6]));
        assert_eq!(sqrt(13), (3, ~[1,1,1,1,6]));
    }

    #[deriving(Eq)]
    struct Uint(uint);

    impl FromPrimitive for Uint {
        fn from_i64(n: i64) -> Option<Uint> { FromPrimitive::from_i64(n).map(Uint) }
        fn from_u64(n: u64) -> Option<Uint> { FromPrimitive::from_u64(n).map(Uint) }
    }
    impl Add<Uint, Uint> for Uint {
        fn add(&self, other: &Uint) -> Uint { Uint(**self + **other) }
    }
    impl Mul<Uint, Uint> for Uint {
        fn mul(&self, other: &Uint) -> Uint { Uint(**self * **other) }
    }

    #[test]
    fn test_fold() {

        fn test(an: &[uint], (n, d): (uint, uint)) {
            assert_eq!(fold::<Uint>(an), (Uint(n), Uint(d)));
        }
        test([1, 2], (3, 2));
        test([1, 2, 2], (7, 5));
        test([1, 2, 2, 2], (17, 12));
        test([1, 2, 2, 2, 2], (41, 29));

        test([2], (2, 1));
        test([2, 1], (3, 1));
        test([2, 1, 2], (8, 3));
        test([2, 1, 2, 1], (11, 4));
        test([2, 1, 2, 1, 1], (19, 7));
        test([2, 1, 2, 1, 1, 4], (87, 32));
        test([2, 1, 2, 1, 1, 4, 1], (106, 39));
        test([2, 1, 2, 1, 1, 4, 1, 1], (193, 71));
        test([2, 1, 2, 1, 1, 4, 1, 1, 6], (1264, 465));
        test([2, 1, 2, 1, 1, 4, 1, 1, 6, 1], (1457, 536));
    }

    #[test]
    fn test_solve_pel() {
        assert_eq!(solve_pel(2), (3, 2));
        assert_eq!(solve_pel(3), (2, 1));
        assert_eq!(solve_pel(5), (9, 4));
        assert_eq!(solve_pel(6), (5, 2));
        assert_eq!(solve_pel(7), (8, 3));
    }
    #[test] #[should_fail]
    fn test_solve_pel_1() { solve_pel::<uint>(1); }
    #[test] #[should_fail]
    fn test_solve_pel_4() { solve_pel::<uint>(4); }
}
<commit_msg>ユニットテストが実行できなくなっていたのを修正<commit_after>use std::hashmap::HashSet;
use std::util;

use arith::isqrt;

pub fn sqrt(n: uint) -> (uint, ~[uint]) {
    let mut a0 = 0;
    let mut an = ~[];
    let mut set = HashSet::new();

    for (a, pqr) in A::new(n) {
        if a == 0 || set.contains(&(a, pqr)) {
            break;
        }

        set.insert((a, pqr));
        if set.len() == 1 {
            a0 = a;
        } else {
            an.push(a);
        }
    }
    return (a0, an);

    struct A {
        n: uint,
        sqn: uint,
        pqr: (uint, uint, uint)
    }
    impl A {
        fn new(n: uint) -> A {
            A { n: n, sqn: isqrt(n), pqr: (1, 0, 1) }
        }

        // a <= f_n(p, q, r) < a + 1
        // r a - q <= p sqrt(n) < r (a + 1) - pq
        // (ar - q)^2 <= np^2 < ((a+1)r - q)^2
        fn calc_a(&self) -> uint {
            // g(a, r, q) := (ar - q)^2
            #[inline]
            fn g(a: uint, r: uint, q: uint) -> uint {
                let s = a * r - q;
                return s * s;
            }

            let &A { n, sqn, pqr: (p, q, r) } = self;
            let np2 = n * p * p;
            let estim_a = (p * sqn + q) / r;
            let mut a = estim_a;
            while g(a + 1, r, q) <= np2 {
                a = a + 1;
            }
            return a;
        }
    }

    impl Iterator<(uint, (uint, uint, uint))> for A {
        // f_n (p, q, r) := (p sqrt(n) + q)/ r
        //                = a + (1 / (rp sqrt(n) + rb) / (np^2 - b^2))
        // a := |f_n(p, q, r)|
        // b := ar - q
        // (p, q, r) := (rp / m, rb / m, (np^2 - b^2) / m)
        #[inline]
        fn next(&mut self) -> Option<(uint, (uint, uint, uint))> {
            let a = self.calc_a();
            let &A { n, pqr: (p, q, r), ..} = self;

            self.pqr = if a * a == n || p == 0 {
                (0, 0, 1)
            } else {
                let b = a * r - q;
                let (p2, q2, r2) = (r*p, r*b, n*p*p - b*b);
                let m = p2.gcd(&q2).gcd(&r2);
                (p2 / m, q2 / m, r2 / m)
            };

            Some((a, self.pqr))
        }
    }
}

pub fn fold<T: FromPrimitive + Add<T, T> + Mul<T, T>>(an: &[uint]) -> (T, T) {
    let mut numer: T = FromPrimitive::from_int(1).unwrap();
    let mut denom: T = FromPrimitive::from_int(0).unwrap();

    for &a in an.rev_iter() {
        util::swap(&mut numer, &mut denom);
        let num: T = FromPrimitive::from_int(a as int).unwrap();
        numer = numer + num * denom;
    }

    return (numer, denom);
}

/// solve pel equation x^2 - d y^2 = 1
pub fn solve_pel<T: FromPrimitive + Add<T, T> + Mul<T, T>>(d: uint) -> (T, T) {
    let (a0, an) = sqrt(d);
    if an.is_empty() {
        fail!("{} is square", d)
    } else if an.len() % 2 == 0 {
        fold::<T>(~[a0] + an.init())
    } else {
        fold::<T>(~[a0] + an + an.init())
    }
}

/// solve pel equation x^2 - d y^2 = -1
pub fn solve_pel_neg<T: FromPrimitive + Add<T, T> + Mul<T, T>>(d: uint) -> (T, T) {
    let (a0, an) = sqrt(d);
    if an.len() % 2 == 0 {
        return fold::<T>(~[a0] + an + an.init());
    } else {
        return fold::<T>(~[a0] + an.init());
    }
}

/// iterates all (x, y) sufficient x^2 - d y^2 = 1
pub struct PelIterator<T> {
    d: T,
    x1y1: (T, T),
    xy: (T, T)
}

impl<T: Clone + FromPrimitive + Add<T, T> + Mul<T, T>> PelIterator<T> {
    #[inline]
    pub fn new(d: uint) -> PelIterator<T> {
        let x1y1 = solve_pel(d);
        let xy   = x1y1.clone();
        PelIterator {
            d: FromPrimitive::from_uint(d).unwrap(),
            x1y1: x1y1, xy: xy
        }
    }
}

impl<T: Add<T, T> + Mul<T, T>> Iterator<(T, T)> for PelIterator<T> {
    // x[k] + y[k]sqrt(n) = (x[1] + y[1]*sqrt(n))^k
    // x[k+1] + y[k+1]sqrt(n) = (x[k] + y[k]sqrt(n)) * (x[1] + y[1]*sqrt(n))
    //                        = (x[k]x[1] + n*y[k]y[1]) + (x[1]y[k] + x[k]y[1])sqrt(n)
    #[inline]
    fn next(&mut self) -> Option<(T, T)> {
        let next = {
            let ref d = self.d;
            let (ref x1, ref y1) = self.x1y1;
            let (ref xk, ref yk) = self.xy;
            ((*xk) * (*x1) + d * (*yk) * (*y1),
             (*yk) * (*x1) +     (*xk) * (*y1))
        };

        Some(util::replace(&mut self.xy, next))
    }
}

/// iterates all (x, y) sufficient x^2 - d y^2 = -1
pub struct PelNegIterator<T> {
    d: T,
    x1y1: (T, T),
    xy: (T, T)
}

impl<T: Clone + FromPrimitive + Add<T, T> + Mul<T, T>> PelNegIterator<T> {
    #[inline]
    pub fn new(d: uint) -> PelNegIterator<T> {
        let x1y1 = solve_pel_neg(d);
        let xy   = x1y1.clone();
        PelNegIterator {
            d: FromPrimitive::from_uint(d).unwrap(),
            x1y1: x1y1, xy: xy
        }
    }
}

impl<T: Add<T, T> + Mul<T, T>> Iterator<(T, T)> for PelNegIterator<T> {
    #[inline]
    fn next(&mut self) -> Option<(T, T)> {
        let next = {
            let ref d = self.d;
            let (ref x1, ref y1) = self.x1y1;
            let (ref xk, ref yk) = self.xy;
            let (xk, yk) = ((*xk) * (*x1) + d * (*yk) * (*y1),
                            (*yk) * (*x1) +     (*xk) * (*y1));
            (xk * (*x1) + d * yk * (*y1),
             yk * (*x1) +     xk * (*y1))
        };

        Some(util::replace(&mut self.xy, next))
    }
}

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

    #[test]
    fn test_sqrt() {
        assert_eq!(sqrt(1), (1, ~[]));
        assert_eq!(sqrt(2), (1, ~[2]));
        assert_eq!(sqrt(3), (1, ~[1,2]));
        assert_eq!(sqrt(4), (2, ~[]));
        assert_eq!(sqrt(5), (2, ~[4]));
        assert_eq!(sqrt(6), (2, ~[2,4]));
        assert_eq!(sqrt(7), (2, ~[1,1,1,4]));
        assert_eq!(sqrt(8), (2, ~[1,4]));
        assert_eq!(sqrt(9), (3, ~[]));
        assert_eq!(sqrt(10), (3, ~[6]));
        assert_eq!(sqrt(11), (3, ~[3,6]));
        assert_eq!(sqrt(12), (3, ~[2,6]));
        assert_eq!(sqrt(13), (3, ~[1,1,1,1,6]));
    }

    #[deriving(Eq)]
    struct Uint(uint);

    impl Uint {
        fn unwrap(&self) -> uint {
            let Uint(n) = *self;
            n
        }
    }

    impl FromPrimitive for Uint {
        fn from_i64(n: i64) -> Option<Uint> { FromPrimitive::from_i64(n).map(Uint) }
        fn from_u64(n: u64) -> Option<Uint> { FromPrimitive::from_u64(n).map(Uint) }
    }
    impl Add<Uint, Uint> for Uint {
        fn add(&self, other: &Uint) -> Uint { Uint(self.unwrap() + other.unwrap()) }
    }
    impl Mul<Uint, Uint> for Uint {
        fn mul(&self, other: &Uint) -> Uint { Uint(self.unwrap() * other.unwrap()) }
    }

    #[test]
    fn test_fold() {

        fn test(an: &[uint], (n, d): (uint, uint)) {
            assert_eq!(fold::<Uint>(an), (Uint(n), Uint(d)));
        }
        test([1, 2], (3, 2));
        test([1, 2, 2], (7, 5));
        test([1, 2, 2, 2], (17, 12));
        test([1, 2, 2, 2, 2], (41, 29));

        test([2], (2, 1));
        test([2, 1], (3, 1));
        test([2, 1, 2], (8, 3));
        test([2, 1, 2, 1], (11, 4));
        test([2, 1, 2, 1, 1], (19, 7));
        test([2, 1, 2, 1, 1, 4], (87, 32));
        test([2, 1, 2, 1, 1, 4, 1], (106, 39));
        test([2, 1, 2, 1, 1, 4, 1, 1], (193, 71));
        test([2, 1, 2, 1, 1, 4, 1, 1, 6], (1264, 465));
        test([2, 1, 2, 1, 1, 4, 1, 1, 6, 1], (1457, 536));
    }

    #[test]
    fn test_solve_pel() {
        assert_eq!(solve_pel(2), (3, 2));
        assert_eq!(solve_pel(3), (2, 1));
        assert_eq!(solve_pel(5), (9, 4));
        assert_eq!(solve_pel(6), (5, 2));
        assert_eq!(solve_pel(7), (8, 3));
    }
    #[test] #[should_fail]
    fn test_solve_pel_1() { solve_pel::<uint>(1); }
    #[test] #[should_fail]
    fn test_solve_pel_4() { solve_pel::<uint>(4); }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use rustc_serialize::json::{ToJson, Json};
use postgres;
use uuid::Uuid;
use std::fmt;
use chrono::{NaiveDateTime, UTC, DateTime};

use apple_music;
use youtube;
use youtube::HasThumbnail;
use soundcloud;
use spotify;
use error::Error;
use super::{conn, PaginatedCollection};
use model::provider::Provider;
use model::state::State;

static PROPS: [&'static str; 12]  = ["id",
                                     "provider",
                                     "identifier",
                                     "url",
                                     "title",
                                     "description",
                                     "thumbnail_url",
                                     "artwork_url",
                                     "published_at",
                                     "created_at",
                                     "updated_at",
                                     "state"];

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Playlist {
    pub id:            Uuid,
    pub provider:      Provider,
    pub identifier:    String,
    pub url:           String,
    pub title:         String,
    pub description:   Option<String>,
    pub thumbnail_url: Option<String>,
    pub artwork_url:   Option<String>,
    pub published_at:  NaiveDateTime,
    pub created_at:    NaiveDateTime,
    pub updated_at:    NaiveDateTime,
    pub state:         State,
}

fn props_str(prefix: &str) -> String {
    PROPS
        .iter()
        .map(|&p| format!("{}{}", prefix, p))
        .collect::<Vec<String>>().join(",")
}

impl PartialEq for Playlist {
    fn eq(&self, p: &Playlist) -> bool {
        return self.identifier == p.identifier && self.provider == p.provider
    }
}

impl ToJson for Playlist {
    fn to_json(&self) -> Json {
        let published_at = DateTime::<UTC>::from_utc(self.published_at, UTC);
        let created_at   = DateTime::<UTC>::from_utc(self.created_at  , UTC);
        let updated_at   = DateTime::<UTC>::from_utc(self.updated_at  , UTC);
        let mut d = BTreeMap::new();
        d.insert("id".to_string()           , self.id.to_string().to_json());
        d.insert("provider".to_string()     , self.provider.to_json());
        d.insert("identifier".to_string()   , self.identifier.to_json());
        d.insert("url".to_string()          , self.url.to_json());
        d.insert("title".to_string()        , self.title.to_json());
        d.insert("description".to_string()  , self.description.to_json());
        d.insert("thumbnail_url".to_string(), self.thumbnail_url.to_json());
        d.insert("artwork_url".to_string()  , self.artwork_url.to_json());
        d.insert("published_at".to_string() , published_at.to_rfc3339().to_json());
        d.insert("created_at".to_string()   , created_at.to_rfc3339().to_json());
        d.insert("updated_at".to_string()   , updated_at.to_rfc3339().to_json());
        d.insert("state".to_string()        , self.state.to_json());
        Json::Object(d)
    }
}

impl fmt::Display for Playlist {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.provider, self.identifier)
    }
}

impl Playlist {
    pub fn new(provider: Provider, identifier: String) -> Playlist {
        Playlist {
            id:            Uuid::new_v4(),
            provider:      provider,
            identifier:    identifier,
            url:           "".to_string(),
            title:         "".to_string(),
            description:   None,
            thumbnail_url: None,
            artwork_url:   None,
            published_at:  UTC::now().naive_utc(),
            created_at:    UTC::now().naive_utc(),
            updated_at:    UTC::now().naive_utc(),
            state:         State::Alive,
        }
    }

    pub fn from_yt_playlist(playlist: &youtube::Playlist) -> Playlist {
        Playlist::new(Provider::YouTube, (*playlist).id.to_string())
            .update_with_yt_playlist(playlist)
            .clone()
    }

    pub fn from_sp_playlist(playlist: &spotify::Playlist) -> Playlist {
        Playlist::new(Provider::Spotify, (*playlist).id.to_string())
            .update_with_sp_playlist(playlist)
            .clone()
    }

    pub fn from_sc_playlist(playlist: &soundcloud::Playlist) -> Playlist {
        Playlist::new(Provider::SoundCloud, (*playlist).id.to_string())
            .update_with_sc_playlist(playlist)
            .clone()
    }

    pub fn from_am_playlist(playlist: &apple_music::Playlist) -> Playlist {
        Playlist::new(Provider::AppleMusic, (*playlist).id.to_string())
            .update_with_am_playlist(playlist)
            .clone()
    }

    pub fn update_with_yt_playlist(&mut self, playlist: &youtube::Playlist) -> &mut Playlist {
        self.provider      = Provider::YouTube;
        self.identifier    = playlist.id.to_string();
        self.url           = format!("https://www.youtube.com/watch/?v={}", playlist.id);
        self.title         = playlist.snippet.title.to_string();
        self.description   = Some(playlist.snippet.description.to_string());
        self.thumbnail_url = playlist.snippet.get_thumbnail_url();
        self.artwork_url   = playlist.snippet.get_artwork_url();
        self.state         = State::Alive;
        match DateTime::parse_from_rfc3339(&playlist.snippet.publishedAt) {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn update_with_sp_playlist(&mut self, playlist: &spotify::Playlist) -> &mut Playlist {
        self.provider       = Provider::Spotify;
        self.identifier     = playlist.id.to_string();
        self.url            = playlist.uri.clone();
        self.title          = playlist.name.clone();
        self.description    = None;
        self.state          = State::Alive;
        self.published_at   = UTC::now().naive_utc();
        if playlist.images.len() > 0 {
            self.artwork_url   = Some(playlist.images[0].url.clone());
            self.thumbnail_url = Some(playlist.images[0].url.clone());
        }
        if playlist.images.len() > 1 {
            self.thumbnail_url = Some(playlist.images[1].url.clone());
        }
        self
    }

    pub fn update_with_sc_playlist(&mut self, playlist: &soundcloud::Playlist) -> &mut Playlist {
        self.provider      = Provider::SoundCloud;
        self.identifier    = playlist.id.to_string();
        self.url           = playlist.permalink_url.to_string();
        self.title         = playlist.title.to_string();
        self.description   = None;
        self.thumbnail_url = playlist.artwork_url.clone();
        self.artwork_url   = playlist.artwork_url.clone();
        self.state         = State::Alive;
        match DateTime::parse_from_str(&playlist.created_at, "%Y/%m/%d %H:%M:%S %z") {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn update_with_am_playlist(&mut self, playlist: &apple_music::Playlist) -> &mut Playlist {
        self.provider      = Provider::AppleMusic;
        self.identifier    = playlist.id.to_string();
        self.url           = playlist.music_url.to_string();
        self.title         = playlist.title.to_string();
        self.description   = Some(playlist.description.to_string());
        self.thumbnail_url = Some(playlist.artwork_url.to_string());
        self.artwork_url   = Some(playlist.artwork_url.to_string());
        self.state         = State::Alive;
        self
    }

    pub fn disable(&mut self) -> &mut Playlist {
        self.state = State::Dead;
        self
    }

    fn rows_to_playlists(rows: postgres::rows::Rows) -> Vec<Playlist> {
        let mut playlists = Vec::new();
        for row in rows.iter() {
            let playlist = Playlist {
                id:            row.get(0),
                provider:      Provider::new(row.get(1)),
                identifier:    row.get(2),
                url:           row.get(3),
                title:         row.get(4),
                description:   row.get(5),
                thumbnail_url: row.get(6),
                artwork_url:   row.get(7),
                published_at:  row.get(8),
                created_at:    row.get(9),
                updated_at:    row.get(10),
                state:         State::new(row.get(11)),
            };
            playlists.push(playlist)
        }
        playlists
    }

    pub fn find_by_id(id: &str) -> Result<Playlist, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM playlists
                        WHERE id = $1", props_str(""))).unwrap();
        let uuid      = try!(Uuid::parse_str(id).map_err(|_| Error::Unprocessable));
        let rows      = stmt.query(&[&uuid]).unwrap();
        let playlists = Playlist::rows_to_playlists(rows);
        if playlists.len() > 0 {
            return Ok(playlists[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find_by(provider: &Provider, identifier: &str) -> Result<Playlist, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM playlists
                     WHERE provider = $1 AND identifier = $2
                     ORDER BY published_at DESC", props_str(""))).unwrap();
        let rows      = stmt.query(&[&(*provider).to_string(), &identifier]).unwrap();
        let playlists = Playlist::rows_to_playlists(rows);
        if playlists.len() > 0 {
            return Ok(playlists[0].clone());
        }
        return Err(Error::NotFound)
    }

    pub fn find_by_entry_id(entry_id: Uuid) -> Vec<Playlist> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM playlists p LEFT JOIN playlist_entries pe
                        ON p.id = pe.playlist_id
                        WHERE pe.entry_id = $1
                        ORDER BY p.published_at DESC", props_str("p."))).unwrap();
        let rows = stmt.query(&[&entry_id]).unwrap();
        Playlist::rows_to_playlists(rows)
    }

    pub fn find(page: i64, per_page: i64) -> PaginatedCollection<Playlist> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(&format!("SELECT {}  FROM playlists
                                            ORDER BY published_at DESC
                                            LIMIT $2 OFFSET $1", props_str(""))).unwrap();
        let offset    = page * per_page;
        let rows      = stmt.query(&[&offset, &per_page]).unwrap();
        let playlists = Playlist::rows_to_playlists(rows);
        let mut total: i64 = 0;
        for row in conn.query("SELECT COUNT(*) FROM playlists", &[]).unwrap().iter() {
            total = row.get(0);
        }
        PaginatedCollection {
            page:     page,
            per_page: per_page,
            total:    total,
            items:    playlists,
        }
    }

    pub fn create(&self) -> Result<Playlist, Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("INSERT INTO playlists (provider, identifier, url, title)
                                 VALUES ($1, $2, $3, $4) RETURNING id").unwrap();
        let rows = try!(stmt.query(&[&self.provider.to_string(), &self.identifier, &self.url, &self.title]));
        let mut playlist = self.clone();
        for row in rows.iter() {
            playlist.id = row.get(0);
        }
        Ok(playlist)
    }

    pub fn find_or_create(provider: Provider, identifier: String) -> Result<Playlist, Error> {
        return match Playlist::find_by(&provider, &identifier) {
            Ok(playlist) => Ok(playlist),
            Err(_)    => Playlist::new(provider, identifier).create()
        }
    }

    pub fn save(&mut self) -> Result<(), Error> {
        self.updated_at = UTC::now().naive_utc();
        let conn = conn().unwrap();
        let stmt = conn.prepare("UPDATE playlists SET
                                 provider      = $2,
                                 identifier    = $3,
                                 url           = $4,
                                 title         = $5,
                                 description   = $6,
                                 thumbnail_url = $7,
                                 artwork_url   = $8,
                                 published_at  = $9,
                                 created_at    = $10,
                                 updated_at    = $11,
                                 state         = $12
                                 WHERE id = $1").unwrap();
        let result = stmt.query(&[&self.id,
                                  &self.provider.to_string(),
                                  &self.identifier,
                                  &self.url,
                                  &self.title,
                                  &self.description,
                                  &self.thumbnail_url,
                                  &self.artwork_url,
                                  &self.published_at,
                                  &self.created_at,
                                  &self.updated_at,
                                  &self.state.to_string(),
        ]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected),
        }
    }

    pub fn delete(&self) -> Result<(), Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("DELETE FROM playlists WHERE id=$1").unwrap();
        let result = stmt.query(&[&self.id]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected)
        }
    }
}

#[cfg(test)]
mod test {
    use super::Playlist;
    use Provider;
    #[test]
    fn test_new() {
        let playlist = Playlist::new(Provider::YouTube,
                                     "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string());
        assert_eq!(playlist.provider, Provider::YouTube);
        assert_eq!(&playlist.identifier, "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX")
    }
    #[test]
    fn test_find_of_create() {
        let identifier = "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string();
        let result     = Playlist::find_or_create(Provider::YouTube, identifier);
        assert!(result.is_ok());
    }
    #[test]
    fn test_delete() {
        let identifier = "test_delete".to_string();
        let playlist   = Playlist::find_or_create(Provider::YouTube, identifier).unwrap();
        let result     = playlist.delete();
        assert!(result.is_ok());
    }
    #[test]
    fn test_save() {
        let id = "test_save";
        let mut playlist = Playlist::find_or_create(Provider::YouTube, id.to_string()).unwrap();
        playlist.title = "title".to_string();
        let result = playlist.save();
        assert!(result.is_ok());
        let playlist = Playlist::find_or_create(Provider::YouTube, id.to_string()).unwrap();
        assert_eq!(&playlist.title, "title");
    }
}
<commit_msg>Playlist conforms Model and Enclosure traits<commit_after>use std::collections::BTreeMap;
use rustc_serialize::json::{ToJson, Json};
use postgres;
use uuid::Uuid;
use std::fmt;
use chrono::{NaiveDateTime, UTC, DateTime};

use apple_music;
use youtube;
use youtube::HasThumbnail;
use soundcloud;
use spotify;
use error::Error;
use super::{conn, Model};
use model::provider::Provider;
use model::state::State;
use model::enclosure::Enclosure;

static PROPS: [&'static str; 12]  = ["id",
                                     "provider",
                                     "identifier",
                                     "url",
                                     "title",
                                     "description",
                                     "thumbnail_url",
                                     "artwork_url",
                                     "published_at",
                                     "created_at",
                                     "updated_at",
                                     "state"];

#[derive(Debug, Clone, RustcDecodable, RustcEncodable)]
pub struct Playlist {
    pub id:            Uuid,
    pub provider:      Provider,
    pub identifier:    String,
    pub url:           String,
    pub title:         String,
    pub description:   Option<String>,
    pub thumbnail_url: Option<String>,
    pub artwork_url:   Option<String>,
    pub published_at:  NaiveDateTime,
    pub created_at:    NaiveDateTime,
    pub updated_at:    NaiveDateTime,
    pub state:         State,
}

impl PartialEq for Playlist {
    fn eq(&self, p: &Playlist) -> bool {
        return self.identifier == p.identifier && self.provider == p.provider
    }
}

impl ToJson for Playlist {
    fn to_json(&self) -> Json {
        let published_at = DateTime::<UTC>::from_utc(self.published_at, UTC);
        let created_at   = DateTime::<UTC>::from_utc(self.created_at  , UTC);
        let updated_at   = DateTime::<UTC>::from_utc(self.updated_at  , UTC);
        let mut d = BTreeMap::new();
        d.insert("id".to_string()           , self.id.to_string().to_json());
        d.insert("provider".to_string()     , self.provider.to_json());
        d.insert("identifier".to_string()   , self.identifier.to_json());
        d.insert("url".to_string()          , self.url.to_json());
        d.insert("title".to_string()        , self.title.to_json());
        d.insert("description".to_string()  , self.description.to_json());
        d.insert("thumbnail_url".to_string(), self.thumbnail_url.to_json());
        d.insert("artwork_url".to_string()  , self.artwork_url.to_json());
        d.insert("published_at".to_string() , published_at.to_rfc3339().to_json());
        d.insert("created_at".to_string()   , created_at.to_rfc3339().to_json());
        d.insert("updated_at".to_string()   , updated_at.to_rfc3339().to_json());
        d.insert("state".to_string()        , self.state.to_json());
        Json::Object(d)
    }
}

impl fmt::Display for Playlist {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}:{}", self.provider, self.identifier)
    }
}

impl Model for Playlist {
    fn table_name() -> String { "playlists".to_string() }
    fn props_str(prefix: &str) -> String {
        PROPS
            .iter()
            .map(|&p| format!("{}{}", prefix, p))
            .collect::<Vec<String>>().join(",")
    }
    fn rows_to_items(rows: postgres::rows::Rows) -> Vec<Playlist> {
        let mut playlists = Vec::new();
        for row in rows.iter() {
            let playlist = Playlist {
                id:            row.get(0),
                provider:      Provider::new(row.get(1)),
                identifier:    row.get(2),
                url:           row.get(3),
                title:         row.get(4),
                description:   row.get(5),
                thumbnail_url: row.get(6),
                artwork_url:   row.get(7),
                published_at:  row.get(8),
                created_at:    row.get(9),
                updated_at:    row.get(10),
                state:         State::new(row.get(11)),
            };
            playlists.push(playlist)
        }
        playlists
    }

    fn create(&self) -> Result<Playlist, Error> {
        let conn = try!(conn());
        let stmt = try!(conn.prepare("INSERT INTO playlists (provider, identifier, url, title)
                                 VALUES ($1, $2, $3, $4) RETURNING id"));
        let rows = try!(stmt.query(&[&self.provider.to_string(), &self.identifier, &self.url, &self.title]));
        let mut playlist = self.clone();
        for row in rows.iter() {
            playlist.id = row.get(0);
        }
        Ok(playlist)
    }

    fn save(&mut self) -> Result<(), Error> {
        self.updated_at = UTC::now().naive_utc();
        let conn = conn().unwrap();
        let stmt = conn.prepare("UPDATE playlists SET
                                 provider      = $2,
                                 identifier    = $3,
                                 url           = $4,
                                 title         = $5,
                                 description   = $6,
                                 thumbnail_url = $7,
                                 artwork_url   = $8,
                                 published_at  = $9,
                                 created_at    = $10,
                                 updated_at    = $11,
                                 state         = $12
                                 WHERE id = $1").unwrap();
        let result = stmt.query(&[&self.id,
                                  &self.provider.to_string(),
                                  &self.identifier,
                                  &self.url,
                                  &self.title,
                                  &self.description,
                                  &self.thumbnail_url,
                                  &self.artwork_url,
                                  &self.published_at,
                                  &self.created_at,
                                  &self.updated_at,
                                  &self.state.to_string(),
        ]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected),
        }
    }
}

impl Enclosure for Playlist {
    fn new(provider: Provider, identifier: String) -> Playlist {
        Playlist {
            id:            Uuid::new_v4(),
            provider:      provider,
            identifier:    identifier,
            url:           "".to_string(),
            title:         "".to_string(),
            description:   None,
            thumbnail_url: None,
            artwork_url:   None,
            published_at:  UTC::now().naive_utc(),
            created_at:    UTC::now().naive_utc(),
            updated_at:    UTC::now().naive_utc(),
            state:         State::Alive,
        }
    }
    fn find_by_entry_id(entry_id: Uuid) -> Vec<Playlist> {
        let conn = conn().unwrap();
        let stmt = conn.prepare(
            &format!("SELECT {} FROM playlists p LEFT JOIN playlist_entries pe
                        ON p.id = pe.playlist_id
                        WHERE pe.entry_id = $1
                        ORDER BY p.published_at DESC",
                     Playlist::props_str("p."))).unwrap();
        let rows = stmt.query(&[&entry_id]).unwrap();
        Playlist::rows_to_items(rows)
    }
}

impl Playlist {
    pub fn from_yt_playlist(playlist: &youtube::Playlist) -> Playlist {
        Playlist::new(Provider::YouTube, (*playlist).id.to_string())
            .update_with_yt_playlist(playlist)
            .clone()
    }

    pub fn from_sp_playlist(playlist: &spotify::Playlist) -> Playlist {
        Playlist::new(Provider::Spotify, (*playlist).id.to_string())
            .update_with_sp_playlist(playlist)
            .clone()
    }

    pub fn from_sc_playlist(playlist: &soundcloud::Playlist) -> Playlist {
        Playlist::new(Provider::SoundCloud, (*playlist).id.to_string())
            .update_with_sc_playlist(playlist)
            .clone()
    }

    pub fn from_am_playlist(playlist: &apple_music::Playlist) -> Playlist {
        Playlist::new(Provider::AppleMusic, (*playlist).id.to_string())
            .update_with_am_playlist(playlist)
            .clone()
    }

    pub fn update_with_yt_playlist(&mut self, playlist: &youtube::Playlist) -> &mut Playlist {
        self.provider      = Provider::YouTube;
        self.identifier    = playlist.id.to_string();
        self.url           = format!("https://www.youtube.com/watch/?v={}", playlist.id);
        self.title         = playlist.snippet.title.to_string();
        self.description   = Some(playlist.snippet.description.to_string());
        self.thumbnail_url = playlist.snippet.get_thumbnail_url();
        self.artwork_url   = playlist.snippet.get_artwork_url();
        self.state         = State::Alive;
        match DateTime::parse_from_rfc3339(&playlist.snippet.publishedAt) {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn update_with_sp_playlist(&mut self, playlist: &spotify::Playlist) -> &mut Playlist {
        self.provider       = Provider::Spotify;
        self.identifier     = playlist.id.to_string();
        self.url            = playlist.uri.clone();
        self.title          = playlist.name.clone();
        self.description    = None;
        self.state          = State::Alive;
        self.published_at   = UTC::now().naive_utc();
        if playlist.images.len() > 0 {
            self.artwork_url   = Some(playlist.images[0].url.clone());
            self.thumbnail_url = Some(playlist.images[0].url.clone());
        }
        if playlist.images.len() > 1 {
            self.thumbnail_url = Some(playlist.images[1].url.clone());
        }
        self
    }

    pub fn update_with_sc_playlist(&mut self, playlist: &soundcloud::Playlist) -> &mut Playlist {
        self.provider      = Provider::SoundCloud;
        self.identifier    = playlist.id.to_string();
        self.url           = playlist.permalink_url.to_string();
        self.title         = playlist.title.to_string();
        self.description   = None;
        self.thumbnail_url = playlist.artwork_url.clone();
        self.artwork_url   = playlist.artwork_url.clone();
        self.state         = State::Alive;
        match DateTime::parse_from_str(&playlist.created_at, "%Y/%m/%d %H:%M:%S %z") {
            Ok(published_at) => self.published_at = published_at.naive_utc(),
            Err(_)           => (),
        }
        self
    }

    pub fn update_with_am_playlist(&mut self, playlist: &apple_music::Playlist) -> &mut Playlist {
        self.provider      = Provider::AppleMusic;
        self.identifier    = playlist.id.to_string();
        self.url           = playlist.music_url.to_string();
        self.title         = playlist.title.to_string();
        self.description   = Some(playlist.description.to_string());
        self.thumbnail_url = Some(playlist.artwork_url.to_string());
        self.artwork_url   = Some(playlist.artwork_url.to_string());
        self.state         = State::Alive;
        self
    }

    pub fn disable(&mut self) -> &mut Playlist {
        self.state = State::Dead;
        self
    }

    pub fn delete(&self) -> Result<(), Error> {
        let conn = conn().unwrap();
        let stmt = conn.prepare("DELETE FROM playlists WHERE id=$1").unwrap();
        let result = stmt.query(&[&self.id]);
        match result {
            Ok(_)  => Ok(()),
            Err(_) => Err(Error::Unexpected)
        }
    }
}

#[cfg(test)]
mod test {
    use model::enclosure::Enclosure;
    use model::Model;
    use super::Playlist;
    use Provider;
    #[test]
    fn test_new() {
        let playlist = Playlist::new(Provider::YouTube,
                                     "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string());
        assert_eq!(playlist.provider, Provider::YouTube);
        assert_eq!(&playlist.identifier, "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX")
    }
    #[test]
    fn test_find_of_create() {
        let identifier = "PLy8LZ8FM-o0ViuGAF68RAaXkQ8V-3dbTX".to_string();
        let result     = Playlist::find_or_create(Provider::YouTube, identifier);
        assert!(result.is_ok());
    }
    #[test]
    fn test_delete() {
        let identifier = "test_delete".to_string();
        let playlist   = Playlist::find_or_create(Provider::YouTube, identifier).unwrap();
        let result     = playlist.delete();
        assert!(result.is_ok());
    }
    #[test]
    fn test_save() {
        let id = "test_save";
        let mut playlist = Playlist::find_or_create(Provider::YouTube, id.to_string()).unwrap();
        playlist.title = "title".to_string();
        let result = playlist.save();
        assert!(result.is_ok());
        let playlist = Playlist::find_or_create(Provider::YouTube, id.to_string()).unwrap();
        assert_eq!(&playlist.title, "title");
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use {success,Matcher,MatchResult};

pub struct EqualTo<T> {
  expected: T
}

impl<T: fmt::Debug> fmt::Display for EqualTo<T> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      self.expected.fmt(f)
  }
}

impl<T : PartialEq + fmt::Debug> Matcher<T> for EqualTo<T> {
  fn matches(&self, actual: T) -> MatchResult {
    if self.expected.eq(&actual) {
      success()
    }
    else {
      Err(format!("was {:?}", actual))
    }
  }
}

pub fn equal_to<T : PartialEq + fmt::Debug>(expected: T) -> EqualTo<T> {
  EqualTo { expected: expected }
}

#[cfg(test)]
mod test {
    use std::thread;
    use {assert_that,is,equal_to};

    #[test]
    fn test_equality_of_ints() {
        // Successful match
        assert_that(&1, is(equal_to(&1i)));

        // Unsuccessful match
        let res = thread::spawn(|| {
          assert_that(&2, is(equal_to(&1i)));
        }).join();

        assert!(res.is_err());
    }
}
<commit_msg>Remove integral suffixes<commit_after>use std::fmt;
use {success,Matcher,MatchResult};

pub struct EqualTo<T> {
  expected: T
}

impl<T: fmt::Debug> fmt::Display for EqualTo<T> {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
      self.expected.fmt(f)
  }
}

impl<T : PartialEq + fmt::Debug> Matcher<T> for EqualTo<T> {
  fn matches(&self, actual: T) -> MatchResult {
    if self.expected.eq(&actual) {
      success()
    }
    else {
      Err(format!("was {:?}", actual))
    }
  }
}

pub fn equal_to<T : PartialEq + fmt::Debug>(expected: T) -> EqualTo<T> {
  EqualTo { expected: expected }
}

#[cfg(test)]
mod test {
    use std::thread;
    use {assert_that,is,equal_to};

    #[test]
    fn test_equality_of_ints() {
        // Successful match
        assert_that(&1, is(equal_to(&1)));

        // Unsuccessful match
        let res = thread::spawn(|| {
          assert_that(&2, is(equal_to(&1)));
        }).join();

        assert!(res.is_err());
    }
}
<|endoftext|>


<commit_before>//! Simple graphviz dot file format output

use std::fmt::{self, Display, Write};
use {
    Graph,
    EdgeType,
    GraphMap,
};
use super::graph::IndexType;
use graphmap::NodeTrait;
use std::collections::HashMap;

/// `Dot` implements output to graphviz .dot format for a graph.
///
/// Formatting and options are rather simple, this is mostly intended
/// for debugging. Exact output may change.
pub struct Dot<'a, G: 'a> {
    graph: &'a G,
    config: &'a [Config],
}

static TYPE: [&'static str; 2] = ["graph", "digraph"];
static EDGE: [&'static str; 2] = ["--", "->"];
static INDENT: &'static str = "    ";

impl<'a, G> Dot<'a, G> {
    pub fn new(graph: &'a G) -> Self {
        Self::with_config(graph, &[])
    }

    pub fn with_config(graph: &'a G, config: &'a [Config]) -> Self {
        Dot {
            graph: graph,
            config: config,
        }
    }
}

/// `Dot` configuration.
///
/// This enum does not have an exhaustive definition (will be expanded)
#[derive(Debug, PartialEq, Eq)]
pub enum Config {
    NodeIndexLabel,
    EdgeIndexLabel,
    EdgeNoLabel,
    #[doc(hidden)]
    Other
}

impl<'a, N, E, Ty, Ix> Dot<'a, Graph<N, E, Ty, Ix>>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn graph_fmt<F, G>(&self, f: &mut fmt::Formatter,
                       mut node_fmt: F, mut edge_fmt: G) -> fmt::Result
        where F: FnMut(&N, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
              G: FnMut(&E, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
{
        let g = self.graph;
        try!(writeln!(f, "{} {{", TYPE[g.is_directed() as usize]));

        // output all labels
        for index in g.node_indices() {
            try!(write!(f, "{}N{}", INDENT, index.index()));
            if self.config.contains(&Config::NodeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", index.index()));
            } else {
                try!(write!(f, " [label=\""));
                try!(node_fmt(&g[index], &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }

        }
        // output all edges
        for (i, edge) in g.raw_edges().iter().enumerate() {
            try!(write!(f, "{}N{} {} N{}",
                        INDENT,
                        edge.source().index(),
                        EDGE[g.is_directed() as usize],
                        edge.target().index()));
            if self.config.contains(&Config::EdgeNoLabel) {
                try!(writeln!(f, ""));
            } else if self.config.contains(&Config::EdgeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(edge_fmt(&edge.weight, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }

        try!(writeln!(f, "}}"));
        Ok(())
    }
}

impl<'a, N, E, Ty, Ix> fmt::Display for Dot<'a, Graph<N, E, Ty, Ix>>
    where N: fmt::Display,
          E: fmt::Display,
          Ty: EdgeType,
          Ix: IndexType,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graph_fmt(f, |n, cb| cb(n), |e, cb| cb(e))
    }
}

impl<'a, N, E, Ty, Ix> fmt::Debug for Dot<'a, Graph<N, E, Ty, Ix>>
    where N: fmt::Debug,
          E: fmt::Debug,
          Ty: EdgeType,
          Ix: IndexType,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graph_fmt(f,
                       |n, cb| cb(&format_args!("{:?}", n)),
                       |e, cb| cb(&format_args!("{:?}", e)))
    }
}

impl<'a, N, E> Dot<'a, GraphMap<N, E>>
    where N: NodeTrait,
{
    fn graphmap_fmt<F, G>(&self, f: &mut fmt::Formatter,
                          mut node_fmt: F, mut edge_fmt: G) -> fmt::Result
        where F: FnMut(&N, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
              G: FnMut(&E, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
    {
        let g = self.graph;
        try!(writeln!(f, "{} {{", TYPE[0]));

        let mut labels = HashMap::new();

        // output all labels
        for (i, node) in g.nodes().enumerate() {
            labels.insert(node, i);
            try!(write!(f, "{}N{}", INDENT, i));
            if self.config.contains(&Config::NodeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(node_fmt(&node, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }
        // output all edges
        for (i, ((a, b), edge_weight)) in g.all_edges().enumerate() {
            try!(write!(f, "{}N{} {} N{}",
                        INDENT,
                        labels[&a],
                        EDGE[0],
                        labels[&b]));
            if self.config.contains(&Config::EdgeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(edge_fmt(&edge_weight, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }

        try!(writeln!(f, "}}"));
        Ok(())
    }
}
impl<'a, N, E> fmt::Display for Dot<'a, GraphMap<N, E>>
    where N: fmt::Display + NodeTrait,
          E: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graphmap_fmt(f, |n, cb| cb(n), |e, cb| cb(e))
    }
}

impl<'a, N, E> fmt::Debug for Dot<'a, GraphMap<N, E>>
    where N: fmt::Debug + NodeTrait,
          E: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graphmap_fmt(f,
                          |n, cb| cb(&format_args!("{:?}", n)),
                          |e, cb| cb(&format_args!("{:?}", e)))
    }
}

/// For Graphviz, we only need to escape double quotes in labels
struct Escaper<W>(W);

impl<W> fmt::Write for Escaper<W>
    where W: fmt::Write
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        for c in s.chars() {
            try!(self.write_char(c));
        }
        Ok(())
    }

    fn write_char(&mut self, c: char) -> fmt::Result {
        match c {
            '"' => try!(self.0.write_char('\\')),
            _   => { }
        }
        self.0.write_char(c)
    }
}

/// Pass Display and Debug through simple escaping filter
struct Escaped<T>(T);

impl<T> fmt::Display for Escaped<T>
    where T: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(&mut Escaper(f), "{}", &self.0)
    }
}

impl<T> fmt::Debug for Escaped<T>
    where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(&mut Escaper(f), "{:?}", &self.0)
    }
}
<commit_msg>Use plain integers as node identifiers in graphviz<commit_after>//! Simple graphviz dot file format output

use std::fmt::{self, Display, Write};
use {
    Graph,
    EdgeType,
    GraphMap,
};
use super::graph::IndexType;
use graphmap::NodeTrait;
use std::collections::HashMap;

/// `Dot` implements output to graphviz .dot format for a graph.
///
/// Formatting and options are rather simple, this is mostly intended
/// for debugging. Exact output may change.
pub struct Dot<'a, G: 'a> {
    graph: &'a G,
    config: &'a [Config],
}

static TYPE: [&'static str; 2] = ["graph", "digraph"];
static EDGE: [&'static str; 2] = ["--", "->"];
static INDENT: &'static str = "    ";

impl<'a, G> Dot<'a, G> {
    pub fn new(graph: &'a G) -> Self {
        Self::with_config(graph, &[])
    }

    pub fn with_config(graph: &'a G, config: &'a [Config]) -> Self {
        Dot {
            graph: graph,
            config: config,
        }
    }
}

/// `Dot` configuration.
///
/// This enum does not have an exhaustive definition (will be expanded)
#[derive(Debug, PartialEq, Eq)]
pub enum Config {
    NodeIndexLabel,
    EdgeIndexLabel,
    EdgeNoLabel,
    #[doc(hidden)]
    Other
}

impl<'a, N, E, Ty, Ix> Dot<'a, Graph<N, E, Ty, Ix>>
    where Ty: EdgeType,
          Ix: IndexType,
{
    fn graph_fmt<F, G>(&self, f: &mut fmt::Formatter,
                       mut node_fmt: F, mut edge_fmt: G) -> fmt::Result
        where F: FnMut(&N, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
              G: FnMut(&E, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
{
        let g = self.graph;
        try!(writeln!(f, "{} {{", TYPE[g.is_directed() as usize]));

        // output all labels
        for index in g.node_indices() {
            try!(write!(f, "{}{}", INDENT, index.index()));
            if self.config.contains(&Config::NodeIndexLabel) {
                try!(writeln!(f, ""));
            } else {
                try!(write!(f, " [label=\""));
                try!(node_fmt(&g[index], &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }

        }
        // output all edges
        for (i, edge) in g.raw_edges().iter().enumerate() {
            try!(write!(f, "{}{} {} {}",
                        INDENT,
                        edge.source().index(),
                        EDGE[g.is_directed() as usize],
                        edge.target().index()));
            if self.config.contains(&Config::EdgeNoLabel) {
                try!(writeln!(f, ""));
            } else if self.config.contains(&Config::EdgeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(edge_fmt(&edge.weight, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }

        try!(writeln!(f, "}}"));
        Ok(())
    }
}

impl<'a, N, E, Ty, Ix> fmt::Display for Dot<'a, Graph<N, E, Ty, Ix>>
    where N: fmt::Display,
          E: fmt::Display,
          Ty: EdgeType,
          Ix: IndexType,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graph_fmt(f, |n, cb| cb(n), |e, cb| cb(e))
    }
}

impl<'a, N, E, Ty, Ix> fmt::Debug for Dot<'a, Graph<N, E, Ty, Ix>>
    where N: fmt::Debug,
          E: fmt::Debug,
          Ty: EdgeType,
          Ix: IndexType,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graph_fmt(f,
                       |n, cb| cb(&format_args!("{:?}", n)),
                       |e, cb| cb(&format_args!("{:?}", e)))
    }
}

impl<'a, N, E> Dot<'a, GraphMap<N, E>>
    where N: NodeTrait,
{
    fn graphmap_fmt<F, G>(&self, f: &mut fmt::Formatter,
                          mut node_fmt: F, mut edge_fmt: G) -> fmt::Result
        where F: FnMut(&N, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
              G: FnMut(&E, &mut FnMut(&Display) -> fmt::Result) -> fmt::Result,
    {
        let g = self.graph;
        try!(writeln!(f, "{} {{", TYPE[0]));

        let mut labels = HashMap::new();

        // output all labels
        for (i, node) in g.nodes().enumerate() {
            labels.insert(node, i);
            try!(write!(f, "{}{}", INDENT, i));
            if self.config.contains(&Config::NodeIndexLabel) {
                try!(writeln!(f, ""));
            } else {
                try!(write!(f, " [label=\""));
                try!(node_fmt(&node, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }
        // output all edges
        for (i, ((a, b), edge_weight)) in g.all_edges().enumerate() {
            try!(write!(f, "{}{} {} {}",
                        INDENT,
                        labels[&a],
                        EDGE[0],
                        labels[&b]));
            if self.config.contains(&Config::EdgeIndexLabel) {
                try!(writeln!(f, " [label=\"{}\"]", i));
            } else {
                try!(write!(f, " [label=\""));
                try!(edge_fmt(&edge_weight, &mut |d| write!(f, "{}", Escaped(d))));
                try!(writeln!(f, "\"]"));
            }
        }

        try!(writeln!(f, "}}"));
        Ok(())
    }
}
impl<'a, N, E> fmt::Display for Dot<'a, GraphMap<N, E>>
    where N: fmt::Display + NodeTrait,
          E: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graphmap_fmt(f, |n, cb| cb(n), |e, cb| cb(e))
    }
}

impl<'a, N, E> fmt::Debug for Dot<'a, GraphMap<N, E>>
    where N: fmt::Debug + NodeTrait,
          E: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.graphmap_fmt(f,
                          |n, cb| cb(&format_args!("{:?}", n)),
                          |e, cb| cb(&format_args!("{:?}", e)))
    }
}

/// For Graphviz, we only need to escape double quotes in labels
struct Escaper<W>(W);

impl<W> fmt::Write for Escaper<W>
    where W: fmt::Write
{
    fn write_str(&mut self, s: &str) -> fmt::Result {
        for c in s.chars() {
            try!(self.write_char(c));
        }
        Ok(())
    }

    fn write_char(&mut self, c: char) -> fmt::Result {
        match c {
            '"' => try!(self.0.write_char('\\')),
            _   => { }
        }
        self.0.write_char(c)
    }
}

/// Pass Display and Debug through simple escaping filter
struct Escaped<T>(T);

impl<T> fmt::Display for Escaped<T>
    where T: fmt::Display
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(&mut Escaper(f), "{}", &self.0)
    }
}

impl<T> fmt::Debug for Escaped<T>
    where T: fmt::Debug
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(&mut Escaper(f), "{:?}", &self.0)
    }
}
<|endoftext|>


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

//! Implementations of specific ElasticSearch operations
//!
//! The various methods on [`Client`](../struct.Client.html) are entry points to
//! ElasticSearch's set of operations.  This module, and it's child modules are
//! the implementation of those operations.

use ::util::StrJoin;

// Specific operations
#[macro_use]
pub mod common;

pub mod bulk;
pub mod delete;
pub mod delete_index;
pub mod get;
pub mod index;
pub mod refresh;
pub mod search;
pub mod analyze;
pub mod mapping;
pub mod version;

// Common utility functions

/// A repeating convention in the ElasticSearch REST API is parameters that can
/// take multiple values
fn format_multi(parts: &[&str]) -> String {
    if parts.is_empty() {
        return "_all".to_owned()
    } else {
        parts.iter().join(",")
    }
}

/// Multiple operations require indexes and types to be specified, there are
/// rules for combining the two however.  E.g. all indexes is specified with
/// `_all`, but all types are specified by omitting type entirely.
fn format_indexes_and_types(indexes: &[&str], types: &[&str]) -> String {
    if types.len() == 0 {
        format!("{}", format_multi(indexes))
    } else {
        format!("{}/{}", format_multi(indexes), format_multi(types))
    }
}

// Results

/// Shared struct for operations that include counts of success/failed shards.
/// This is returned within various other result structs.
#[derive(Debug, Deserialize)]
pub struct ShardCountResult {
    pub total:      u64,
    pub successful: u64,
    pub failed:     u64
}

#[derive(Debug, Deserialize)]
pub struct GenericResult {
    pub acknowledged: bool
}
<commit_msg>Use Cow for cases where String or str might be both options<commit_after>/*
 * Copyright 2015-2016 Ben Ashford
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! Implementations of specific ElasticSearch operations
//!
//! The various methods on [`Client`](../struct.Client.html) are entry points to
//! ElasticSearch's set of operations.  This module, and it's child modules are
//! the implementation of those operations.

use std::borrow::Cow;

use ::util::StrJoin;

// Specific operations
#[macro_use]
pub mod common;

pub mod bulk;
pub mod delete;
pub mod delete_index;
pub mod get;
pub mod index;
pub mod refresh;
pub mod search;
pub mod analyze;
pub mod mapping;
pub mod version;

// Common utility functions

/// A repeating convention in the ElasticSearch REST API is parameters that can
/// take multiple values
fn format_multi(parts: &[&str]) -> Cow<'static, str> {
    if parts.is_empty() {
        Cow::Borrowed("_all")
    } else {
        Cow::Owned(parts.iter().join(","))
    }
}

/// Multiple operations require indexes and types to be specified, there are
/// rules for combining the two however.  E.g. all indexes is specified with
/// `_all`, but all types are specified by omitting type entirely.
fn format_indexes_and_types(indexes: &[&str], types: &[&str]) -> Cow<'static, str> {
    if types.is_empty() {
        format_multi(indexes)
    } else {
        Cow::Owned(format!("{}/{}", format_multi(indexes), format_multi(types)))
    }
}

// Results

/// Shared struct for operations that include counts of success/failed shards.
/// This is returned within various other result structs.
#[derive(Debug, Deserialize)]
pub struct ShardCountResult {
    pub total:      u64,
    pub successful: u64,
    pub failed:     u64
}

#[derive(Debug, Deserialize)]
pub struct GenericResult {
    pub acknowledged: bool
}
<|endoftext|>


<commit_before><commit_msg>clippy for cli<commit_after><|endoftext|>