<commit_before>
#![warn(missing_docs)]

//! This crate provides types `Nil` and `Cons<H, T>`, which together allow for creating lists consisting of multiple types.
//! The types in the list are present in the type of the list, so that `Cons<i32, Cons<i64, Nil>>` contains an `i32` and an `i64`.
//! If type `T` is present exactly once in an `HList`, it is usually possible to allow the compiler to find the `T` in the `HList` by using the `Find` trait.

/// The empty `HList`.
pub struct Nil;

/// An `HList` with `H` at position 0, and `T` as the rest of the list.
pub struct Cons<H, T>(pub H, pub T);

/// A marker trait that `Nil` and `Cons<H, T>` satisfies.
/// Not currently used to enforce proper hlists, although this may change.
/// Provides the `push()` method
pub trait HList: Sized {
    /// Consumes the `HList`, and returns a new HList with `item` at the beginning.
    fn push<N>(self, item: N) -> Cons<N, Self> {
        Cons(item, self)
    }
}

impl HList for Nil {}
impl<H, T> HList for Cons<H, T> {}

/// Used as an index into an `HList`.
///
/// `Here` is 0, pointing to the head of the HList.
///
/// Users should normally allow type inference to create this type
#[allow(dead_code)]
pub enum Here {}

/// Used as an index into an `HList`.
///
/// `There<T>` is 1 + `T`.
///
/// Users should normally allow type inference to create this type.
#[allow(dead_code)]
pub struct There<T>(std::marker::PhantomData<T>);

/// `Find<T, I>` is implemented for an `HList` if index `I` of the `HList` is a `T`
///
/// Rust's type inferencer can often produce a correct `I`
/// if there is exactly one `T` in the `HList`.
///
/// ```rust
/// use hlist::{HList, Nil, Find};
///
/// // The type of list is Cons<i64, Cons<i32, Nil>>
/// let list = Nil.push(0i32).push(1i64);
///
/// // Here list satisfies the trait Find<i64, Here>.
/// // The compiler infers the second type parameter.
/// let a: i64 = *list.get();
/// assert!(a == 1);
///
/// // Here list satisfies the trait Find<i32, There<Here>>.
/// let b: i32 = *list.get();
/// assert!(b == 0);
/// ```
///
/// Functions that need to look up values of a type in an HList given to them should get the index from the call site:
///
/// ```rust
/// fn foo<I, L: Find<i32, I>>(list: &L) -> i32 {
///     *list.get()
/// }
/// let list = Nil.push("foo").push(5i32).push("bar");
/// assert!(foo(&list) == 5);
/// ```
///
/// When `foo()` is called, the compiler figures out the appropriate value for `I`.
pub trait Find<T, I> {
    /// Retrieves a `&T`.
    ///
    /// Allows for type inferencing to act like type-directed search.
    ///
    /// ```rust
    /// use hlist::{HList, Nil, Find}
    ///
    /// let list = Nil.push(0i32).push(1i64);
    /// let a: i64 = *list.get();
    /// assert!(a == 1);
    fn get(&self) -> &T;

    /// Retrieves a `&mut T`.
    ///
    /// Allows for type inferencing to act like type-directed search.
    ///
    /// ```rust
    /// use hlist::{HList, Nil, Find}
    ///
    /// let mut list = Nil.push(0i32).push(1i64);
    /// *list.get_mut() = 5i32;
    /// let a: i32 = *list.get()
    /// assert!(a == 5);
    fn get_mut(&mut self) -> &mut T;
}

impl<T, Tail> Find<T, Here> for Cons<T, Tail> {
    fn get(&self) -> &T {
        &self.0
    }
    fn get_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

impl<Head, T, Tail, TailIndex> Find<T, There<TailIndex>> for Cons<Head, Tail>
    where Tail: Find<T, TailIndex> {
    fn get(&self) -> &T {
        self.1.get()
    }
    fn get_mut(&mut self) -> &mut T {
        self.1.get_mut()
    }
}

#[test]
fn test_get() {
    let list = Nil.push(5i32).push("Foo");
    let a: i32 = *list.get();
    let b: &str = *list.get();
    assert!(a == 5i32);
    assert!(b == "Foo");
}

#[test]
fn test_get_mut() {
    let mut list = Nil.push(5i32).push("Foo");
    *list.get_mut() = 6i32;
    *list.get_mut() = "Bar";
    let a: i32 = *list.get();
    let b: &str = *list.get();
    assert!(a == 6i32);
    assert!(b == "Bar");
}

#[test]
fn test_index_as_type_parameter() {
    fn foo<I, L: Find<i32, I>>(list: &L) -> i32 {
        *list.get()
    }
    let list = Nil.push("foo").push(5i32).push("bar");
    assert!(foo(&list) == 5);
}
<commit_msg>Fix doc tests/examples<commit_after>
#![warn(missing_docs)]

//! This crate provides types `Nil` and `Cons<H, T>`, which together allow for creating lists consisting of multiple types.
//! The types in the list are present in the type of the list, so that `Cons<i32, Cons<i64, Nil>>` contains an `i32` and an `i64`.
//! If type `T` is present exactly once in an `HList`, it is usually possible to allow the compiler to find the `T` in the `HList` by using the `Find` trait.

/// The empty `HList`.
pub struct Nil;

/// An `HList` with `H` at position 0, and `T` as the rest of the list.
pub struct Cons<H, T>(pub H, pub T);

/// A marker trait that `Nil` and `Cons<H, T>` satisfies.
/// Not currently used to enforce proper hlists, although this may change.
/// Provides the `push()` method
pub trait HList: Sized {
    /// Consumes the `HList`, and returns a new HList with `item` at the beginning.
    fn push<N>(self, item: N) -> Cons<N, Self> {
        Cons(item, self)
    }
}

impl HList for Nil {}
impl<H, T> HList for Cons<H, T> {}

/// Used as an index into an `HList`.
///
/// `Here` is 0, pointing to the head of the HList.
///
/// Users should normally allow type inference to create this type
#[allow(dead_code)]
pub enum Here {}

/// Used as an index into an `HList`.
///
/// `There<T>` is 1 + `T`.
///
/// Users should normally allow type inference to create this type.
#[allow(dead_code)]
pub struct There<T>(std::marker::PhantomData<T>);

/// `Find<T, I>` is implemented for an `HList` if index `I` of the `HList` is a `T`
///
/// Rust's type inferencer can often produce a correct `I`
/// if there is exactly one `T` in the `HList`.
///
/// ```rust
/// use hlist::{HList, Nil, Find};
///
/// // The type of list is Cons<i64, Cons<i32, Nil>>
/// let list = Nil.push(0i32).push(1i64);
///
/// // Here list satisfies the trait Find<i64, Here>.
/// // The compiler infers the second type parameter.
/// let a: i64 = *list.get();
/// assert!(a == 1);
///
/// // Here list satisfies the trait Find<i32, There<Here>>.
/// let b: i32 = *list.get();
/// assert!(b == 0);
/// ```
///
/// Functions that need to look up values of a type in an HList given to them should get the index from the call site:
///
/// ```rust
/// use hlist::{HList, Nil, Find};
///
/// fn foo<I, L: Find<i32, I>>(list: &L) -> i32 {
///     *list.get()
/// }
/// let list = Nil.push("foo").push(5i32).push("bar");
/// assert!(foo(&list) == 5);
/// ```
///
/// When `foo()` is called, the compiler figures out the appropriate value for `I`.
pub trait Find<T, I> {
    /// Retrieves a `&T`.
    ///
    /// Allows for type inferencing to act like type-directed search.
    ///
    /// ```rust
    /// use hlist::{HList, Nil, Find};
    ///
    /// let list = Nil.push(0i32).push(1i64);
    /// let a: i64 = *list.get();
    /// assert!(a == 1);
    fn get(&self) -> &T;

    /// Retrieves a `&mut T`.
    ///
    /// Allows for type inferencing to act like type-directed search.
    ///
    /// ```rust
    /// use hlist::{HList, Nil, Find};
    ///
    /// let mut list = Nil.push(0i32).push(1i64);
    /// *list.get_mut() = 5i32;
    /// let a: i32 = *list.get();
    /// assert!(a == 5);
    fn get_mut(&mut self) -> &mut T;
}

impl<T, Tail> Find<T, Here> for Cons<T, Tail> {
    fn get(&self) -> &T {
        &self.0
    }
    fn get_mut(&mut self) -> &mut T {
        &mut self.0
    }
}

impl<Head, T, Tail, TailIndex> Find<T, There<TailIndex>> for Cons<Head, Tail>
    where Tail: Find<T, TailIndex> {
    fn get(&self) -> &T {
        self.1.get()
    }
    fn get_mut(&mut self) -> &mut T {
        self.1.get_mut()
    }
}

#[test]
fn test_get() {
    let list = Nil.push(5i32).push("Foo");
    let a: i32 = *list.get();
    let b: &str = *list.get();
    assert!(a == 5i32);
    assert!(b == "Foo");
}

#[test]
fn test_get_mut() {
    let mut list = Nil.push(5i32).push("Foo");
    *list.get_mut() = 6i32;
    *list.get_mut() = "Bar";
    let a: i32 = *list.get();
    let b: &str = *list.get();
    assert!(a == 6i32);
    assert!(b == "Bar");
}

#[test]
fn test_index_as_type_parameter() {
    fn foo<I, L: Find<i32, I>>(list: &L) -> i32 {
        *list.get()
    }
    let list = Nil.push("foo").push(5i32).push("bar");
    assert!(foo(&list) == 5);
}
<|endoftext|>


<commit_before>//! Shiplift is a multi-transport utility for maneuvering [docker](https://www.docker.com/) containers
//!
//! # examples
//!
//! ```
//! extern crate shiplift;
//!
//! let mut docker = shiplift::Docker::new();
//! let mut images = docker.images().list().unwrap();
//! println!("docker images in stock");
//! for i in images {
//!   println!("{:?}", i.RepoTags);
//! }
//! ```

extern crate hyper;
extern crate jed;
extern crate openssl;
extern crate rustc_serialize;
extern crate unix_socket;
extern crate url;

pub mod builder;
pub mod rep;
pub mod transport;

use builder::{ ContainerBuilder, Events };
use hyper::{ Client, Url };
use hyper::method::Method;
use openssl::x509::X509FileType;
use rep::Image as ImageRep;
use rep::Container as ContainerRep;
use rep::{
  Change, ContainerDetails, Event, Exit, History,
  ImageDetails, Info, SearchResult, Stats, Status,
  Top, Version
};
use rustc_serialize::json::{ self, Json };
use std::env::{ self, VarError };
use std::io::{ Read, Result };
use std::iter::IntoIterator;
use std::path::Path;
use transport::{ Body, Transport };
use unix_socket::UnixStream;
use url::{ Host, RelativeSchemeData, SchemeData };

/// Entrypoint interface for communicating with docker daemon
pub struct Docker {
  transport: Box<Transport>
}

/// Interface for accessing and manipulating a named docker image
pub struct Image<'a, 'b> {
  docker: &'a mut Docker,
  name: &'b str
}

impl<'a, 'b> Image<'a, 'b> {
  /// Exports an interface for operations that may be performed against a named image
  pub fn new(docker: &'a mut Docker, name: &'b str) -> Image<'a, 'b> {
    Image { docker: docker, name: name }
  }

  /// Inspects a named image's details
  pub fn inspect(self) -> Result<ImageDetails> {
    let raw = try!(self.docker.get(&format!("/images/{}/json", self.name)[..]));
    Ok(json::decode::<ImageDetails>(&raw).unwrap())
  }

  /// Lists the history of the images set of changes
  pub fn history(self) -> Result<Vec<History>> {
    let raw = try!(self.docker.get(&format!("/images/{}/history", self.name)[..]));
    Ok(json::decode::<Vec<History>>(&raw).unwrap())
  }

  /// Delete's an image
  pub fn delete(self) -> Result<Vec<Status>> {
    let raw = try!(self.docker.delete(&format!("/images/{}", self.name)[..]));
    Ok(match Json::from_str(&raw).unwrap() {
      Json::Array(ref xs) => xs.iter().map(|j| {
        let obj = j.as_object().unwrap();
        obj.get("Untagged").map(|sha| Status::Untagged(sha.as_string().unwrap().to_string()))
           .or(obj.get("Deleted").map(|sha| Status::Deleted(sha.as_string().unwrap().to_string())))
           .unwrap()
      }),
      _ => unreachable!("")
    }.collect())
  }
}

/// Interface for docker images
pub struct Images<'a> {
  docker: &'a mut Docker
}

impl<'a> Images<'a> {
  /// Exports an interface for interacting with docker images
  pub fn new(docker: &'a mut Docker) -> Images<'a> {
    Images { docker: docker }
  }

  /// Lists the docker images on the current docker host
  pub fn list(self) -> Result<Vec<ImageRep>> {
    let raw = try!(self.docker.get("/images/json"));
    Ok(json::decode::<Vec<ImageRep>>(&raw).unwrap())
  }

  /// Returns a reference to a set of operations available for a named image
  pub fn get(&'a mut self, name: &'a str) -> Image {
    Image::new(self.docker, name)
  }

  /// Search for docker images by term
  pub fn search(self, term: &str) -> Result<Vec<SearchResult>> {
    let raw = try!(self.docker.get(&format!("/images/search?term={}", term)[..]));
    Ok(json::decode::<Vec<SearchResult>>(&raw).unwrap())
  }

  /// Create a new docker images from an existing image
  pub fn create(self, from: &str) -> Result<Box<Read>> {
    self.docker.stream_post(&format!("/images/create?fromImage={}", from)[..])
  }
}

/// Interface for accessing and manipulating a docker container
pub struct Container<'a, 'b> {
  docker: &'a mut Docker,
  id: &'b str
}

impl<'a, 'b> Container<'a, 'b> {
  /// Exports an interface exposing operations against a container instance
  pub fn new(docker: &'a mut Docker, id: &'b str) -> Container<'a, 'b> {
    Container { docker: docker, id: id }
  }

  /// Inspects the current docker container instance's details
  pub fn inspect(self) -> Result<ContainerDetails> {
    let raw = try!(self.docker.get(&format!("/containers/{}/json", self.id)[..]));
    Ok(json::decode::<ContainerDetails>(&raw).unwrap())
  }

  /// Returns a `top` view of information about the container process
  pub fn top(self) -> Result<Top> {
    let raw = try!(self.docker.get(&format!("/containers/{}/top", self.id)[..]));
    Ok(json::decode::<Top>(&raw).unwrap())
  }

  /// Returns a stream of logs emitted but the container instance
  pub fn logs(self) -> Result<Box<Read>> {
    let query = format!(
      "follow={}&stdout={}&stderr={}&timestamps={}&tail={}",
      true, true, true, true, "all");
    self.docker.stream_get(&format!("/containers/{}/logs?{}", self.id, query)[..])
  }

  /// Returns a set of changes made to the container instance
  pub fn changes(self) -> Result<Vec<Change>> {
    let raw = try!(self.docker.get(&format!("/containers/{}/changes", self.id)[..]));
    Ok(json::decode::<Vec<Change>>(&raw).unwrap())
  }

  /// Exports the current docker container
  pub fn export(self) -> Result<Box<Read>> {
    self.docker.stream_get(&format!("/containers/{}/export", self.id)[..])
  }

  /// Returns a stream of stats specific to this container instance
  pub fn stats(self) -> Result<Box<Iterator<Item=Stats>>> {
    let raw = try!(self.docker.stream_get(&format!("/containers/{}/stats", self.id)[..]));
    let it = jed::Iter::new(raw).into_iter().map(|j| {
      let s = json::encode(&j).unwrap();
      json::decode::<Stats>(&s).unwrap()
    });
    Ok(Box::new(it))
  }

  /// Start the container instance
  pub fn start(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/start", self.id)[..], None).map(|_| ())
  }

  /// Stop the container instance
  pub fn stop(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/stop", self.id)[..], None).map(|_| ())
  }

  /// Restart the container instance
  pub fn restart(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/restart", self.id)[..], None).map(|_| ())
  }

  /// Kill the container instance
  pub fn kill(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/kill", self.id)[..], None).map(|_| ())
  }

  /// Rename the container instance
  pub fn rename(self, name: &str) -> Result<()> {
    self.docker.post(&format!("/containers/{}/rename?name={}", self.id, name)[..], None).map(|_| ())
  }

  /// Pause the container instance
  pub fn pause(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/pause", self.id)[..], None).map(|_| ())
  }

  /// Unpause the container instance
  pub fn unpause(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/unpause", self.id)[..], None).map(|_| ())
  }

  /// Wait until the container stops
  pub fn wait(self) -> Result<Exit> {
    let raw = try!(self.docker.post(&format!("/containers/{}/wait", self.id)[..], None));
    Ok(json::decode::<Exit>(&raw).unwrap())
  }

  /// Delete the container instance
  pub fn delete(self) -> Result<()> {
    self.docker.delete(&format!("/containers/{}", self.id)[..]).map(|_| ())
  }

  // todo attach, attach/ws,
}

/// Interface for docker containers
pub struct Containers<'a> {
  docker: &'a mut Docker
}

impl<'a> Containers<'a> {
  /// Exports an interface for interacting with docker containers
  pub fn new(docker: &'a mut Docker) -> Containers<'a> {
    Containers { docker: docker }
  }

  /// Lists the container instances on the docker host
  pub fn list(self) -> Result<Vec<ContainerRep>> {
    let raw = try!(self.docker.get("/containers/json"));
    Ok(json::decode::<Vec<ContainerRep>>(&raw).unwrap())
  }

  /// Returns a reference to a set of operations available to a specific container instance
  pub fn get(&'a mut self, name: &'a str) -> Container {
    Container::new(self.docker, name)
  }

  /// Returns a builder interface for creating a new container instance
  pub fn create(&'a mut self, image: &'a str) -> ContainerBuilder {
    ContainerBuilder::new(self.docker, image)
  }
}

// https://docs.docker.com/reference/api/docker_remote_api_v1.17/
impl Docker {
  /// constructs a new Docker instance for a docker host listening at a url specified by an env var `DOCKER_HOST`,
  /// falling back on unix:///var/run/docker.sock
  pub fn new() -> Docker {
    let fallback: std::result::Result<String, VarError> =
      Ok("unix:///var/run/docker.sock".to_string());
    let host = env::var("DOCKER_HOST")
        .or(fallback)
        .map(|h| Url::parse(&h).ok()
             .expect("invalid url"))
        .ok()
        .expect("expected host");
    Docker::host(host)
  }

  /// constructs a new Docker instance for docker host listening at the given host url
  pub fn host(host: Url) -> Docker {
    let domain = match host.scheme_data {
        SchemeData::NonRelative(s) => s,
        SchemeData::Relative(RelativeSchemeData { host: host, .. }) =>
          match host {
              Host::Domain(s) => s,
              Host::Ipv6(a)   => a.to_string()
          }
    };
    match &host.scheme[..] {
      "unix" => {
        let stream =
          match UnixStream::connect(domain) {
            Err(_) => panic!("failed to connect to socket"),
            Ok(s) => s
          };
        Docker { transport: Box::new(stream) }
      },
          _  => {
        let mut client = Client::new();
        client.set_ssl_verifier(Box::new(|ssl_ctx| {
          match env::var("DOCKER_CERT_PATH").ok() {
            Some(ref certs) => {
              let cert = &format!("{}/cert.pem", certs);
              let key = &format!("{}/key.pem", certs);
              ssl_ctx.set_certificate_file(&Path::new(cert), X509FileType::PEM);
              ssl_ctx.set_private_key_file(&Path::new(key), X509FileType::PEM);
              match env::var("DOCKER_TLS_VERIFY").ok() {
                Some(_) => {
                  let ca = &format!("{}/ca.pem", certs);
                  ssl_ctx.set_CA_file(&Path::new(ca));
                }, _ => ()
              };
              ()
            },  _ => ()
          }
        }));
        let tup = (client, format!("https:{}", domain.to_string()));
        Docker { transport: Box::new(tup) }
      }
    }
  }

  /// Exports an interface for interacting with docker images
  pub fn images<'a>(&'a mut self) -> Images {
    Images::new(self)
  }

  /// Exports an interface for interacting with docker containers
  pub fn containers<'a>(&'a mut self) -> Containers {
    Containers::new(self)
  }

  /// Returns version information associated with the docker daemon
  pub fn version(&mut self) -> Result<Version> {
    let raw = try!(self.get("/version"));
    Ok(json::decode::<Version>(&raw).unwrap())
  }

  /// Returns information associated with the docker daemon
  pub fn info(&mut self) -> Result<Info> {
    let raw = try!(self.get("/info"));
    Ok(json::decode::<Info>(&raw).unwrap())
  }

  /// Returns a simple ping response indicating the docker daemon is accessible
  pub fn ping(&mut self) -> Result<String> {
    self.get("/_ping")
  }

  /// Retruns a stream of events ocurring on the current docker host
  pub fn events(&mut self) -> Events {
    Events::new(self)
  }

  fn get(&mut self, endpoint: &str) -> Result<String> {
    (*self.transport).request(Method::Get, endpoint, None)
  }

  fn post(&mut self, endpoint: &str, body: Option<Body>) -> Result<String> {
    (*self.transport).request(Method::Post, endpoint, body)
  }

  fn delete(&mut self, endpoint: &str) -> Result<String> {
    (*self.transport).request(Method::Delete, endpoint, None)
  }

  fn stream_post(&mut self, endpoint: &str) -> Result<Box<Read>> {
    (*self.transport).stream(Method::Post, endpoint, None)
  }

  fn stream_get(&mut self, endpoint: &str) -> Result<Box<Read>> {
    (*self.transport).stream(Method::Get, endpoint, None)
  }
}
<commit_msg>spacing<commit_after>//! Shiplift is a multi-transport utility for maneuvering [docker](https://www.docker.com/) containers
//!
//! # examples
//!
//! ```
//! extern crate shiplift;
//!
//! let mut docker = shiplift::Docker::new();
//! let mut images = docker.images().list().unwrap();
//! println!("docker images in stock");
//! for i in images {
//!   println!("{:?}", i.RepoTags);
//! }
//! ```

extern crate hyper;
extern crate jed;
extern crate openssl;
extern crate rustc_serialize;
extern crate unix_socket;
extern crate url;

pub mod builder;
pub mod rep;
pub mod transport;

use builder::{ ContainerBuilder, Events };
use hyper::{ Client, Url };
use hyper::method::Method;
use openssl::x509::X509FileType;
use rep::Image as ImageRep;
use rep::Container as ContainerRep;
use rep::{
  Change, ContainerDetails, Event, Exit, History,
  ImageDetails, Info, SearchResult, Stats, Status,
  Top, Version
};
use rustc_serialize::json::{ self, Json };
use std::env::{ self, VarError };
use std::io::{ Read, Result };
use std::iter::IntoIterator;
use std::path::Path;
use transport::{ Body, Transport };
use unix_socket::UnixStream;
use url::{ Host, RelativeSchemeData, SchemeData };

/// Entrypoint interface for communicating with docker daemon
pub struct Docker {
  transport: Box<Transport>
}

/// Interface for accessing and manipulating a named docker image
pub struct Image<'a, 'b> {
  docker: &'a mut Docker,
  name: &'b str
}

impl<'a, 'b> Image<'a, 'b> {
  /// Exports an interface for operations that may be performed against a named image
  pub fn new(docker: &'a mut Docker, name: &'b str) -> Image<'a, 'b> {
    Image { docker: docker, name: name }
  }

  /// Inspects a named image's details
  pub fn inspect(self) -> Result<ImageDetails> {
    let raw = try!(self.docker.get(&format!("/images/{}/json", self.name)[..]));
    Ok(json::decode::<ImageDetails>(&raw).unwrap())
  }

  /// Lists the history of the images set of changes
  pub fn history(self) -> Result<Vec<History>> {
    let raw = try!(self.docker.get(&format!("/images/{}/history", self.name)[..]));
    Ok(json::decode::<Vec<History>>(&raw).unwrap())
  }

  /// Delete's an image
  pub fn delete(self) -> Result<Vec<Status>> {
    let raw = try!(self.docker.delete(&format!("/images/{}", self.name)[..]));
    Ok(match Json::from_str(&raw).unwrap() {
      Json::Array(ref xs) => xs.iter().map(|j| {
        let obj = j.as_object().unwrap();
        obj.get("Untagged").map(|sha| Status::Untagged(sha.as_string().unwrap().to_string()))
           .or(obj.get("Deleted").map(|sha| Status::Deleted(sha.as_string().unwrap().to_string())))
           .unwrap()
      }),
      _ => unreachable!("")
    }.collect())
  }
}

/// Interface for docker images
pub struct Images<'a> {
  docker: &'a mut Docker
}

impl<'a> Images<'a> {
  /// Exports an interface for interacting with docker images
  pub fn new(docker: &'a mut Docker) -> Images<'a> {
    Images { docker: docker }
  }

  /// Lists the docker images on the current docker host
  pub fn list(self) -> Result<Vec<ImageRep>> {
    let raw = try!(self.docker.get("/images/json"));
    Ok(json::decode::<Vec<ImageRep>>(&raw).unwrap())
  }

  /// Returns a reference to a set of operations available for a named image
  pub fn get(&'a mut self, name: &'a str) -> Image {
    Image::new(self.docker, name)
  }

  /// Search for docker images by term
  pub fn search(self, term: &str) -> Result<Vec<SearchResult>> {
    let raw = try!(self.docker.get(&format!("/images/search?term={}", term)[..]));
    Ok(json::decode::<Vec<SearchResult>>(&raw).unwrap())
  }

  /// Create a new docker images from an existing image
  pub fn create(self, from: &str) -> Result<Box<Read>> {
    self.docker.stream_post(&format!("/images/create?fromImage={}", from)[..])
  }
}

/// Interface for accessing and manipulating a docker container
pub struct Container<'a, 'b> {
  docker: &'a mut Docker,
  id: &'b str
}

impl<'a, 'b> Container<'a, 'b> {
  /// Exports an interface exposing operations against a container instance
  pub fn new(docker: &'a mut Docker, id: &'b str) -> Container<'a, 'b> {
    Container { docker: docker, id: id }
  }

  /// Inspects the current docker container instance's details
  pub fn inspect(self) -> Result<ContainerDetails> {
    let raw = try!(self.docker.get(&format!("/containers/{}/json", self.id)[..]));
    Ok(json::decode::<ContainerDetails>(&raw).unwrap())
  }

  /// Returns a `top` view of information about the container process
  pub fn top(self) -> Result<Top> {
    let raw = try!(self.docker.get(&format!("/containers/{}/top", self.id)[..]));
    Ok(json::decode::<Top>(&raw).unwrap())
  }

  /// Returns a stream of logs emitted but the container instance
  pub fn logs(self) -> Result<Box<Read>> {
    let query = format!(
      "follow={}&stdout={}&stderr={}&timestamps={}&tail={}",
      true, true, true, true, "all");
    self.docker.stream_get(&format!("/containers/{}/logs?{}", self.id, query)[..])
  }

  /// Returns a set of changes made to the container instance
  pub fn changes(self) -> Result<Vec<Change>> {
    let raw = try!(self.docker.get(&format!("/containers/{}/changes", self.id)[..]));
    Ok(json::decode::<Vec<Change>>(&raw).unwrap())
  }

  /// Exports the current docker container
  pub fn export(self) -> Result<Box<Read>> {
    self.docker.stream_get(&format!("/containers/{}/export", self.id)[..])
  }

  /// Returns a stream of stats specific to this container instance
  pub fn stats(self) -> Result<Box<Iterator<Item=Stats>>> {
    let raw = try!(self.docker.stream_get(&format!("/containers/{}/stats", self.id)[..]));
    let it = jed::Iter::new(raw).into_iter().map(|j| {
      let s = json::encode(&j).unwrap();
      json::decode::<Stats>(&s).unwrap()
    });
    Ok(Box::new(it))
  }

  /// Start the container instance
  pub fn start(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/start", self.id)[..], None).map(|_| ())
  }

  /// Stop the container instance
  pub fn stop(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/stop", self.id)[..], None).map(|_| ())
  }

  /// Restart the container instance
  pub fn restart(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/restart", self.id)[..], None).map(|_| ())
  }

  /// Kill the container instance
  pub fn kill(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/kill", self.id)[..], None).map(|_| ())
  }

  /// Rename the container instance
  pub fn rename(self, name: &str) -> Result<()> {
    self.docker.post(&format!("/containers/{}/rename?name={}", self.id, name)[..], None).map(|_| ())
  }

  /// Pause the container instance
  pub fn pause(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/pause", self.id)[..], None).map(|_| ())
  }

  /// Unpause the container instance
  pub fn unpause(self) -> Result<()> {
    self.docker.post(&format!("/containers/{}/unpause", self.id)[..], None).map(|_| ())
  }

  /// Wait until the container stops
  pub fn wait(self) -> Result<Exit> {
    let raw = try!(self.docker.post(&format!("/containers/{}/wait", self.id)[..], None));
    Ok(json::decode::<Exit>(&raw).unwrap())
  }

  /// Delete the container instance
  pub fn delete(self) -> Result<()> {
    self.docker.delete(&format!("/containers/{}", self.id)[..]).map(|_| ())
  }

  // todo attach, attach/ws,
}

/// Interface for docker containers
pub struct Containers<'a> {
  docker: &'a mut Docker
}

impl<'a> Containers<'a> {
  /// Exports an interface for interacting with docker containers
  pub fn new(docker: &'a mut Docker) -> Containers<'a> {
    Containers { docker: docker }
  }

  /// Lists the container instances on the docker host
  pub fn list(self) -> Result<Vec<ContainerRep>> {
    let raw = try!(self.docker.get("/containers/json"));
    Ok(json::decode::<Vec<ContainerRep>>(&raw).unwrap())
  }

  /// Returns a reference to a set of operations available to a specific container instance
  pub fn get(&'a mut self, name: &'a str) -> Container {
    Container::new(self.docker, name)
  }

  /// Returns a builder interface for creating a new container instance
  pub fn create(&'a mut self, image: &'a str) -> ContainerBuilder {
    ContainerBuilder::new(self.docker, image)
  }
}

// https://docs.docker.com/reference/api/docker_remote_api_v1.17/
impl Docker {
  /// constructs a new Docker instance for a docker host listening at a url specified by an env var `DOCKER_HOST`,
  /// falling back on unix:///var/run/docker.sock
  pub fn new() -> Docker {
    let fallback: std::result::Result<String, VarError> =
      Ok("unix:///var/run/docker.sock".to_string());
    let host = env::var("DOCKER_HOST")
        .or(fallback)
        .map(|h| Url::parse(&h).ok()
             .expect("invalid url"))
        .ok()
        .expect("expected host");
    Docker::host(host)
  }

  /// constructs a new Docker instance for docker host listening at the given host url
  pub fn host(host: Url) -> Docker {
    let domain = match host.scheme_data {
        SchemeData::NonRelative(s) => s,
        SchemeData::Relative(RelativeSchemeData { host: host, .. }) =>
          match host {
              Host::Domain(s) => s,
              Host::Ipv6(a)   => a.to_string()
          }
    };
    match &host.scheme[..] {
      "unix" => {
        let stream =
          match UnixStream::connect(domain) {
            Err(_) => panic!("failed to connect to socket"),
            Ok(s) => s
          };
        Docker { transport: Box::new(stream) }
      },
          _  => {
        let mut client = Client::new();
        client.set_ssl_verifier(Box::new(|ssl_ctx| {
          match env::var("DOCKER_CERT_PATH").ok() {
            Some(ref certs) => {
              let cert = &format!("{}/cert.pem", certs);
              let key = &format!("{}/key.pem", certs);
              ssl_ctx.set_certificate_file(&Path::new(cert), X509FileType::PEM);
              ssl_ctx.set_private_key_file(&Path::new(key), X509FileType::PEM);
              match env::var("DOCKER_TLS_VERIFY").ok() {
                Some(_) => {
                  let ca = &format!("{}/ca.pem", certs);
                  ssl_ctx.set_CA_file(&Path::new(ca));
                }, _ => ()
              };
              ()
            },  _ => ()
          }
        }));
        let tup = (client, format!("https:{}", domain.to_string()));
        Docker { transport: Box::new(tup) }
      }
    }
  }

  /// Exports an interface for interacting with docker images
  pub fn images<'a>(&'a mut self) -> Images {
    Images::new(self)
  }

  /// Exports an interface for interacting with docker containers
  pub fn containers<'a>(&'a mut self) -> Containers {
    Containers::new(self)
  }

  /// Returns version information associated with the docker daemon
  pub fn version(&mut self) -> Result<Version> {
    let raw = try!(self.get("/version"));
    Ok(json::decode::<Version>(&raw).unwrap())
  }

  /// Returns information associated with the docker daemon
  pub fn info(&mut self) -> Result<Info> {
    let raw = try!(self.get("/info"));
    Ok(json::decode::<Info>(&raw).unwrap())
  }

  /// Returns a simple ping response indicating the docker daemon is accessible
  pub fn ping(&mut self) -> Result<String> {
    self.get("/_ping")
  }

  /// Retruns a stream of events ocurring on the current docker host
  pub fn events(&mut self) -> Events {
    Events::new(self)
  }

  fn get(&mut self, endpoint: &str) -> Result<String> {
    (*self.transport).request(Method::Get, endpoint, None)
  }

  fn post(&mut self, endpoint: &str, body: Option<Body>) -> Result<String> {
    (*self.transport).request(Method::Post, endpoint, body)
  }

  fn delete(&mut self, endpoint: &str) -> Result<String> {
    (*self.transport).request(Method::Delete, endpoint, None)
  }

  fn stream_post(&mut self, endpoint: &str) -> Result<Box<Read>> {
    (*self.transport).stream(Method::Post, endpoint, None)
  }

  fn stream_get(&mut self, endpoint: &str) -> Result<Box<Read>> {
    (*self.transport).stream(Method::Get, endpoint, None)
  }
}
<|endoftext|>


<commit_before>extern crate hyper;
extern crate serde_json;

use std::io::Read;

use hyper::Client;
use hyper::header::Connection;

fn get<U: hyper::client::IntoUrl>(url: U) -> serde_json::Value {
    // Create a client.
    let client = Client::new();

    // Creating an outgoing request.
    let mut res = client.get(url)
        // set a header
        .header(Connection::close())
        // let 'er go!
        .send().unwrap();

    // Read the Response.
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let value: serde_json::Value = serde_json::from_str(&body).unwrap();
    value
}

pub fn test_api() {
    let value = get("http://api.stockfighter.io/ob/api/heartbeat");
    println!("Response: {}", value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap());
}

pub fn test_venue(venue: &str) {
    let url = format!("https://api.stockfighter.io/ob/api/venues/{}/heartbeat", venue);
    let value = get(&url);
    println!("Response: {}", value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap());
}
<commit_msg>Added quote API call<commit_after>#[macro_use]
extern crate hyper;
extern crate serde_json;

use std::io::Read;

use hyper::Client;
use hyper::header::Connection;

header! { (XStarfighterAuthorization, "X-Starfighter-Authorization") => [String] }

fn get<U: hyper::client::IntoUrl>(url: U) -> serde_json::Value {
    // Create a client.
    let client = Client::new();

    // Creating an outgoing request.
    let mut res = client.get(url)
        // set a header
        .header(Connection::close())
        // let 'er go!
        .send().unwrap();

    // Read the Response.
    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let value: serde_json::Value = serde_json::from_str(&body).unwrap();
    value
}

pub fn test_api() {
    let value = get("http://api.stockfighter.io/ob/api/heartbeat");
    println!("Response: {}", value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap());
}

pub fn test_venue(venue: &str) {
    let url = format!("https://api.stockfighter.io/ob/api/venues/{}/heartbeat", venue);
    let value = get(&url);
    println!("Response: {}", value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap());
}

pub fn quote(venue: &str, stock: &str) -> bool {

    let url = format!("https://api.stockfighter.io/ob/api/venues/{}/stocks/{}/quote", venue, stock);

    let client = Client::new();

    let mut res = client
        .get(&url)
        .header(XStarfighterAuthorization("b6eb6d0a2b606c02c8b027fca35383fb2dc741d3".to_owned()))
        .send()
        .unwrap();

    let mut body = String::new();
    res.read_to_string(&mut body).unwrap();

    let value: serde_json::Value = serde_json::from_str(&body).unwrap();
    value.as_object().unwrap().get("ok").unwrap().as_boolean().unwrap()
}

mod test {
    use super::*;

    #[test]
    fn test_quote() {
        assert_eq!(true, quote("TESTEX", "FOOBAR"));
    }
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate nix;

pub mod error;
mod buffer;
mod history;
mod parser;
mod instr;
mod term;

use std::os::unix::io::RawFd;

use error::Error;
use history::History;
use buffer::Buffer;
use term::Term;

fn readline_edit(term: &mut Term, history: &mut History, prompt: &str) -> Result<String, Error> {
    let mut buffer = Buffer::new();
    let mut seq: Vec<u8> = Vec::new();
    let mut history_cursor = history::Cursor::new(history);
    loop {
        try!(term.write(&buffer.get_line(prompt)));
        let byte = try!(try!(term.read_byte()).ok_or(Error::EndOfFile));
        seq.push(byte);

        match parser::parse(&seq) {
            parser::Result::Error => return Err(Error::InvalidUTF8),
            parser::Result::Incomplete => continue,
            parser::Result::Success(token) => {
                match instr::interpret_token(token) {
                    instr::Instr::Done                   => {
                        return Ok(buffer.to_string());
                    },
                    instr::Instr::DeleteCharLeftOfCursor => buffer.delete_char_left_of_cursor(),
                    instr::Instr::MoveCursorLeft         => buffer.move_left(),
                    instr::Instr::MoveCursorRight        => buffer.move_right(),
                    instr::Instr::MoveCursorStart        => buffer.move_start(),
                    instr::Instr::MoveCursorEnd          => buffer.move_end(),
                    instr::Instr::HistoryPrev            => {
                        if history_cursor.incr() {
                            buffer.swap()
                        }
                        history_cursor.get().map(|s| buffer.replace(s));
                    },
                    instr::Instr::HistoryNext            => {
                        if history_cursor.decr() {
                            buffer.swap()
                        }
                        history_cursor.get().map(|s| buffer.replace(s));
                    },
                    instr::Instr::Noop                   => (),
                    instr::Instr::Cancel                 => return Err(Error::EndOfFile),
                    instr::Instr::InsertAtCursor         => try!(buffer.insert_bytes_at_cursor(&seq))
                };
                seq.clear();
            }
        };
    }
}

pub struct Copperline {
    term: Term,
    history: History
}

impl Copperline {

    pub fn new() -> Copperline {
        Copperline::from_raw_fd(libc::STDIN_FILENO, libc::STDOUT_FILENO)
    }

    fn from_raw_fd(ifd: RawFd, ofd: RawFd) -> Copperline {
        Copperline {
            term: Term::new(ifd, ofd),
            history: History::new()
        }
    }

    pub fn readline(&mut self, prompt: &str) -> Result<String, Error> {
        if Term::is_unsupported_term() || !self.term.is_a_tty() {
            return Err(Error::UnsupportedTerm);
        }
        try!(self.term.enable_raw_mode());
        let result = readline_edit(&mut self.term, &mut self.history, prompt);
        try!(self.term.disable_raw_mode());
        println!("");
        result
    }

    pub fn history_add(&mut self, line: String) {
        self.history.push(line)
    }

}
<commit_msg>pass history as immutable<commit_after>extern crate libc;
extern crate nix;

pub mod error;
mod buffer;
mod history;
mod parser;
mod instr;
mod term;

use std::os::unix::io::RawFd;

use error::Error;
use history::History;
use buffer::Buffer;
use term::Term;

fn readline_edit(term: &mut Term, history: &History, prompt: &str) -> Result<String, Error> {
    let mut buffer = Buffer::new();
    let mut seq: Vec<u8> = Vec::new();
    let mut history_cursor = history::Cursor::new(history);
    loop {
        try!(term.write(&buffer.get_line(prompt)));
        let byte = try!(try!(term.read_byte()).ok_or(Error::EndOfFile));
        seq.push(byte);

        match parser::parse(&seq) {
            parser::Result::Error => return Err(Error::InvalidUTF8),
            parser::Result::Incomplete => continue,
            parser::Result::Success(token) => {
                match instr::interpret_token(token) {
                    instr::Instr::Done                   => {
                        return Ok(buffer.to_string());
                    },
                    instr::Instr::DeleteCharLeftOfCursor => buffer.delete_char_left_of_cursor(),
                    instr::Instr::MoveCursorLeft         => buffer.move_left(),
                    instr::Instr::MoveCursorRight        => buffer.move_right(),
                    instr::Instr::MoveCursorStart        => buffer.move_start(),
                    instr::Instr::MoveCursorEnd          => buffer.move_end(),
                    instr::Instr::HistoryPrev            => {
                        if history_cursor.incr() {
                            buffer.swap()
                        }
                        history_cursor.get().map(|s| buffer.replace(s));
                    },
                    instr::Instr::HistoryNext            => {
                        if history_cursor.decr() {
                            buffer.swap()
                        }
                        history_cursor.get().map(|s| buffer.replace(s));
                    },
                    instr::Instr::Noop                   => (),
                    instr::Instr::Cancel                 => return Err(Error::EndOfFile),
                    instr::Instr::InsertAtCursor         => try!(buffer.insert_bytes_at_cursor(&seq))
                };
                seq.clear();
            }
        };
    }
}

pub struct Copperline {
    term: Term,
    history: History
}

impl Copperline {

    pub fn new() -> Copperline {
        Copperline::from_raw_fd(libc::STDIN_FILENO, libc::STDOUT_FILENO)
    }

    fn from_raw_fd(ifd: RawFd, ofd: RawFd) -> Copperline {
        Copperline {
            term: Term::new(ifd, ofd),
            history: History::new()
        }
    }

    pub fn readline(&mut self, prompt: &str) -> Result<String, Error> {
        if Term::is_unsupported_term() || !self.term.is_a_tty() {
            return Err(Error::UnsupportedTerm);
        }
        try!(self.term.enable_raw_mode());
        let result = readline_edit(&mut self.term, &self.history, prompt);
        try!(self.term.disable_raw_mode());
        println!("");
        result
    }

    pub fn history_add(&mut self, line: String) {
        self.history.push(line)
    }

}
<|endoftext|>


<commit_before>extern crate futures;
extern crate tokio_core;

use std::mem;
use std::thread;
use std::sync::Arc;
use std::time::Duration;

use futures::{Stream, Future, Poll, Async};
use futures::sync::{mpsc, oneshot};
use tokio_core::reactor::Core;

#[derive(Clone, Debug)]
pub enum LoadError {
    Receiver,
    LoadCanceled,
    Custom(String),
}

impl LoadError {
    pub fn custom<S: Into<String>>(s: S) -> LoadError {
        LoadError::Custom(s.into())
    }
}

pub trait BatchFn<K, V> {
    type Error: Into<LoadError>;
    fn load(&self, keys: &Vec<K>) -> Box<Future<Item = Vec<V>, Error = Self::Error>>;

    fn max_batch_size(&self) -> usize {
        200
    }
}

#[derive(Clone)]
pub struct Loader<K, V> {
    tx: Arc<mpsc::UnboundedSender<Message<K, Result<V, LoadError>>>>,
}

impl<K, V> Loader<K, V> {
    pub fn load(&self, key: K) -> LoadFuture<K, V> {
        let (tx, rx) = oneshot::channel();
        let msg = Message::LoadOne {
            key: key,
            reply: tx,
        };
        // This call may not completed as thread are parked in Future
        self.tx.send(msg).unwrap();
        // TODO: fix it, make sure send completed
        thread::sleep(Duration::from_millis(50));
        LoadFuture {
            rx: rx,
            loader: Loader { tx: self.tx.clone() },
        }
    }

    /// Called when poll LoadFuture return NotReady
    fn dispatch_rest(&self) {
        // This call may not completed as thread are parked in Future
        self.tx.send(Message::LoadRest).unwrap();
        // TODO: fix it, make sure send completed
        thread::sleep(Duration::from_millis(50));
    }
}

impl<K, V> Loader<K, V>
    where K: 'static + Send,
          V: 'static + Send
{
    pub fn new<F>(batch_fn: F) -> Loader<K, V>
        where F: 'static + Send + BatchFn<K, V>
    {
        assert!(batch_fn.max_batch_size() > 0);

        let (tx, rx) = mpsc::unbounded();
        let inner_handle = Arc::new(tx);
        let loader = Loader { tx: inner_handle };

        // worker thread to call batch_fn for load requests
        thread::spawn(move || {
            let batch_fn = Arc::new(batch_fn);
            let mut core = Core::new().unwrap();
            let handle = core.handle();

            let inner = Inner {
                rx: rx,
                max_batch_size: batch_fn.max_batch_size(),
                items: Vec::with_capacity(batch_fn.max_batch_size()),
                err: None,
            };

            let load_batch = batch_fn.clone();
            let loader =
                inner.for_each(move |requests: Vec<(K, oneshot::Sender<Result<V, LoadError>>)>| {
                    let (keys, replys) = requests.into_iter()
                        .fold((Vec::new(), Vec::new()), |mut soa, i| {
                            soa.0.push(i.0);
                            soa.1.push(i.1);
                            soa
                        });
                    let batch_job = load_batch.load(&keys).then(move |x| {
                        match x {
                            Ok(values) => {
                                for r in replys.into_iter().zip(values) {
                                    r.0.complete(Ok(r.1));
                                }
                            }
                            Err(e) => {
                                let err = e.into();
                                for r in replys {
                                    r.complete(Err(err.clone()));
                                }
                            }
                        };
                        Ok(())
                    });
                    handle.spawn(batch_job);
                    Ok(())
                });
            core.run(loader).unwrap();

            // Run until all batch jobs completed
            core.turn(None);
        });

        loader
    }
}

pub struct LoadFuture<K, V> {
    rx: oneshot::Receiver<Result<V, LoadError>>,
    loader: Loader<K, V>,
}

impl<K, V> Future for LoadFuture<K, V> {
    type Item = V;
    type Error = LoadError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.rx.poll() {
            Ok(Async::NotReady) => {
                // request may pending in the queue, dispatch requests in the queue as batch
                self.loader.dispatch_rest();
                Ok(Async::NotReady)
            }
            Ok(Async::Ready(Ok(v))) => Ok(Async::Ready(v)),
            Ok(Async::Ready(Err(e))) => Err(e),
            Err(_) => Err(LoadError::LoadCanceled),
        }
    }
}

// Message pass between loader and worker thread
enum Message<K, V> {
    LoadOne { key: K, reply: oneshot::Sender<V> },
    LoadRest,
}

struct Inner<K, V> {
    rx: mpsc::UnboundedReceiver<Message<K, Result<V, LoadError>>>,
    max_batch_size: usize,
    items: Vec<(K, oneshot::Sender<Result<V, LoadError>>)>,
    err: Option<LoadError>,
}

impl<K, V> Stream for Inner<K, V> {
    type Item = Vec<(K, oneshot::Sender<Result<V, LoadError>>)>;
    type Error = LoadError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if let Some(err) = self.err.take() {
            return Err(err);
        }

        loop {
            match self.rx.poll() {

                Ok(Async::NotReady) => {
                    return Ok(Async::NotReady);
                }

                Ok(Async::Ready(Some(msg))) => {
                    match msg {
                        Message::LoadOne { key, reply } => {
                            //println!("get one request");
                            self.items.push((key, reply));
                            if self.items.len() >= self.max_batch_size {
                                //println!("get one batch");
                                let batch = mem::replace(&mut self.items,
                                                         Vec::with_capacity(self.max_batch_size));
                                return Ok(Some(batch).into());
                            }
                        }
                        Message::LoadRest => {
                            println!("LoadRest");
                            return if self.items.len() > 0 {
                                //println!("make request in queue into one batch");
                                let rest = mem::replace(&mut self.items, Vec::new());
                                Ok(Some(rest).into())
                            } else {
                                return Ok(Async::NotReady);
                            };
                        }
                    }
                }

                Ok(Async::Ready(None)) => {
                    return if self.items.len() > 0 {
                        let rest = mem::replace(&mut self.items, Vec::new());
                        Ok(Some(rest).into())
                    } else {
                        Ok(Async::Ready(None))
                    }
                }

                Err(_) => {
                    if self.items.len() == 0 {
                        return Err(LoadError::Receiver);
                    } else {
                        self.err = Some(LoadError::Receiver);
                        let rest = mem::replace(&mut self.items, Vec::new());
                        return Ok(Some(rest).into());
                    }
                }
            }
        }
    }
}
<commit_msg>comment out debug println<commit_after>extern crate futures;
extern crate tokio_core;

use std::mem;
use std::thread;
use std::sync::Arc;
use std::time::Duration;

use futures::{Stream, Future, Poll, Async};
use futures::sync::{mpsc, oneshot};
use tokio_core::reactor::Core;

#[derive(Clone, Debug)]
pub enum LoadError {
    Receiver,
    LoadCanceled,
    Custom(String),
}

impl LoadError {
    pub fn custom<S: Into<String>>(s: S) -> LoadError {
        LoadError::Custom(s.into())
    }
}

pub trait BatchFn<K, V> {
    type Error: Into<LoadError>;
    fn load(&self, keys: &Vec<K>) -> Box<Future<Item = Vec<V>, Error = Self::Error>>;

    fn max_batch_size(&self) -> usize {
        200
    }
}

#[derive(Clone)]
pub struct Loader<K, V> {
    tx: Arc<mpsc::UnboundedSender<Message<K, Result<V, LoadError>>>>,
}

impl<K, V> Loader<K, V> {
    pub fn load(&self, key: K) -> LoadFuture<K, V> {
        let (tx, rx) = oneshot::channel();
        let msg = Message::LoadOne {
            key: key,
            reply: tx,
        };
        // This call may not completed as thread are parked in Future
        self.tx.send(msg).unwrap();
        // TODO: fix it, make sure send completed
        thread::sleep(Duration::from_millis(50));
        LoadFuture {
            rx: rx,
            loader: Loader { tx: self.tx.clone() },
        }
    }

    /// Called when poll LoadFuture return NotReady
    fn dispatch_rest(&self) {
        // This call may not completed as thread are parked in Future
        self.tx.send(Message::LoadRest).unwrap();
        // TODO: fix it, make sure send completed
        thread::sleep(Duration::from_millis(50));
    }
}

impl<K, V> Loader<K, V>
    where K: 'static + Send,
          V: 'static + Send
{
    pub fn new<F>(batch_fn: F) -> Loader<K, V>
        where F: 'static + Send + BatchFn<K, V>
    {
        assert!(batch_fn.max_batch_size() > 0);

        let (tx, rx) = mpsc::unbounded();
        let inner_handle = Arc::new(tx);
        let loader = Loader { tx: inner_handle };

        // worker thread to call batch_fn for load requests
        thread::spawn(move || {
            let batch_fn = Arc::new(batch_fn);
            let mut core = Core::new().unwrap();
            let handle = core.handle();

            let inner = Inner {
                rx: rx,
                max_batch_size: batch_fn.max_batch_size(),
                items: Vec::with_capacity(batch_fn.max_batch_size()),
                err: None,
            };

            let load_batch = batch_fn.clone();
            let loader =
                inner.for_each(move |requests: Vec<(K, oneshot::Sender<Result<V, LoadError>>)>| {
                    let (keys, replys) = requests.into_iter()
                        .fold((Vec::new(), Vec::new()), |mut soa, i| {
                            soa.0.push(i.0);
                            soa.1.push(i.1);
                            soa
                        });
                    let batch_job = load_batch.load(&keys).then(move |x| {
                        match x {
                            Ok(values) => {
                                for r in replys.into_iter().zip(values) {
                                    r.0.complete(Ok(r.1));
                                }
                            }
                            Err(e) => {
                                let err = e.into();
                                for r in replys {
                                    r.complete(Err(err.clone()));
                                }
                            }
                        };
                        Ok(())
                    });
                    handle.spawn(batch_job);
                    Ok(())
                });
            core.run(loader).unwrap();

            // Run until all batch jobs completed
            core.turn(None);
        });

        loader
    }
}

pub struct LoadFuture<K, V> {
    rx: oneshot::Receiver<Result<V, LoadError>>,
    loader: Loader<K, V>,
}

impl<K, V> Future for LoadFuture<K, V> {
    type Item = V;
    type Error = LoadError;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        match self.rx.poll() {
            Ok(Async::NotReady) => {
                // request may pending in the queue, dispatch requests in the queue as batch
                self.loader.dispatch_rest();
                Ok(Async::NotReady)
            }
            Ok(Async::Ready(Ok(v))) => Ok(Async::Ready(v)),
            Ok(Async::Ready(Err(e))) => Err(e),
            Err(_) => Err(LoadError::LoadCanceled),
        }
    }
}

// Message pass between loader and worker thread
enum Message<K, V> {
    LoadOne { key: K, reply: oneshot::Sender<V> },
    LoadRest,
}

struct Inner<K, V> {
    rx: mpsc::UnboundedReceiver<Message<K, Result<V, LoadError>>>,
    max_batch_size: usize,
    items: Vec<(K, oneshot::Sender<Result<V, LoadError>>)>,
    err: Option<LoadError>,
}

impl<K, V> Stream for Inner<K, V> {
    type Item = Vec<(K, oneshot::Sender<Result<V, LoadError>>)>;
    type Error = LoadError;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        if let Some(err) = self.err.take() {
            return Err(err);
        }
        loop {
            match self.rx.poll() {
                Ok(Async::NotReady) => {
                    return Ok(Async::NotReady);
                }
                Ok(Async::Ready(Some(msg))) => {
                    match msg {
                        Message::LoadOne { key, reply } => {
                            //println!("get one request");
                            self.items.push((key, reply));
                            if self.items.len() >= self.max_batch_size {
                                //println!("get one batch");
                                let batch = mem::replace(&mut self.items,
                                                         Vec::with_capacity(self.max_batch_size));
                                return Ok(Some(batch).into());
                            }
                        }
                        Message::LoadRest => {
                            // println!("LoadRest");
                            return if self.items.len() > 0 {
                                //println!("make request in queue into one batch");
                                let rest = mem::replace(&mut self.items, Vec::new());
                                Ok(Some(rest).into())
                            } else {
                                return Ok(Async::NotReady);
                            };
                        }
                    }
                }
                Ok(Async::Ready(None)) => {
                    return if self.items.len() > 0 {
                        let rest = mem::replace(&mut self.items, Vec::new());
                        Ok(Some(rest).into())
                    } else {
                        Ok(Async::Ready(None))
                    }
                }
                Err(_) => {
                    if self.items.len() == 0 {
                        return Err(LoadError::Receiver);
                    } else {
                        self.err = Some(LoadError::Receiver);
                        let rest = mem::replace(&mut self.items, Vec::new());
                        return Ok(Some(rest).into());
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate rustc_serialize as rustc_serialize;
extern crate bincode;
extern crate bufstream;

use std::{io, fmt, error, result};
use bincode::{EncodingError, DecodingError};

#[macro_export]
macro_rules! urpc {
    (
        pub interface $mod_name:ident {
            $(
                fn $fn_name:ident (
                    $(
                        $arg:ident: $arg_ty:ty
                    ),*
                ) -> $ret_ty:ty {}
            )*
        }
    ) => { pub mod $mod_name {
        pub trait Methods {
            $(
                fn $fn_name(&mut self, $( $arg: $arg_ty ),*)
                    -> $crate::Result<$ret_ty>;
            )*
        }

        #[allow(non_camel_case_types)]
        #[derive(RustcEncodable, RustcDecodable)]
        pub enum Request {
            _SHUTDOWN,
            $(
                $fn_name($( $arg_ty ),*),
            )*
        }

        pub struct Client<Stream: $crate::rt::Stream> {
            stream: $crate::rt::BufStream<Stream>,
        }

        impl<Stream> Client<Stream>
            where Stream: $crate::rt::Stream,
        {
            pub fn new(stream: Stream) -> Client<Stream> {
                Client {
                    stream: $crate::rt::BufStream::new(stream),
                }
            }
        }

        #[unsafe_destructor]
        impl<Stream> Drop for Client<Stream>
            where Stream: $crate::rt::Stream,
        {
            fn drop(&mut self) {
                let _ = $crate::rt::send(&mut self.stream, &Request::_SHUTDOWN);
            }
        }

        impl<Stream> Methods for Client<Stream>
            where Stream: $crate::rt::Stream,
        {
            $(
                fn $fn_name(&mut self, $( $arg: $arg_ty ),*)
                    -> $crate::Result<$ret_ty>
                {
                    let req = Request::$fn_name($( $arg ),*);
                    try!($crate::rt::send(&mut self.stream, &req));
                    let ret = try!($crate::rt::recv(&mut self.stream));
                    Ok(ret)
                }
            )*
        }

        pub fn serve<Impl, Stream>(mut handler: Impl, mut stream: Stream)
            -> $crate::Result<()>
            where Stream: $crate::rt::Stream,
                  Impl: Methods,
        {
            loop {
                match try!($crate::rt::recv(&mut stream)) {
                    Request::_SHUTDOWN => return Ok(()),
                    $(
                        Request::$fn_name($( $arg ),*) => {
                            let ret = try!(handler.$fn_name($( $arg ),*));
                            try!($crate::rt::send(&mut stream, &ret));
                        }
                    )*
                };
            }
        }
    }}
}

// Run-time helpers for macro-generated code
#[doc(hidden)]
pub mod rt {
    use std::io::{Read, Write};
    use rustc_serialize::{Encodable, Decodable};
    use bincode::{self, SizeLimit};

    use super::Result;

    pub use bufstream::BufStream;

    pub trait Stream: Read + Write { }
    impl<T: Read + Write> Stream for T { }

    pub fn send<W, T>(w: &mut W, t: &T) -> Result<()>
        where W: Write, T: Encodable
    {
        try!(bincode::encode_into(t, w, SizeLimit::Infinite));
        try!(w.flush());
        Ok(())
    }

    pub fn recv<R, T>(r: &mut R) -> Result<T>
        where R: Read, T: Decodable
    {
        let r = try!(bincode::decode_from(r, SizeLimit::Infinite));
        Ok(r)
    }
}

#[derive(Debug)]
pub enum Error {
    IoError(io::Error),
    ProtocolError,
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        <Self as fmt::Debug>::fmt(self, fmt)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::IoError(ref e) => error::Error::description(e),
            Error::ProtocolError => "urpc protocol error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::IoError(ref e) => Some(e),
            Error::ProtocolError => None,
        }
    }
}

impl error::FromError<io::Error> for Error {
    fn from_error(e: io::Error) -> Error {
        Error::IoError(e)
    }
}

impl error::FromError<EncodingError> for Error {
    fn from_error(e: EncodingError) -> Error {
        match e {
            EncodingError::IoError(e) => Error::IoError(e),
            EncodingError::SizeLimit => unreachable!(),
        }
    }
}

impl error::FromError<DecodingError> for Error {
    fn from_error(e: DecodingError) -> Error {
        match e {
            DecodingError::IoError(e) => Error::IoError(e),
            DecodingError::InvalidEncoding(_) => Error::ProtocolError,
            DecodingError::SizeLimit => unreachable!(),
        }
    }
}

pub type Result<T> = result::Result<T, Error>;
<commit_msg>Rust updates: fix error::FromError and #[unsafe_destructor]<commit_after>extern crate rustc_serialize as rustc_serialize;
extern crate bincode;
extern crate bufstream;

use std::{io, fmt, error, result, convert};
use bincode::{EncodingError, DecodingError};

#[macro_export]
macro_rules! urpc {
    (
        pub interface $mod_name:ident {
            $(
                fn $fn_name:ident (
                    $(
                        $arg:ident: $arg_ty:ty
                    ),*
                ) -> $ret_ty:ty {}
            )*
        }
    ) => { pub mod $mod_name {
        pub trait Methods {
            $(
                fn $fn_name(&mut self, $( $arg: $arg_ty ),*)
                    -> $crate::Result<$ret_ty>;
            )*
        }

        #[allow(non_camel_case_types)]
        #[derive(RustcEncodable, RustcDecodable)]
        pub enum Request {
            _SHUTDOWN,
            $(
                $fn_name($( $arg_ty ),*),
            )*
        }

        pub struct Client<Stream: $crate::rt::Stream> {
            stream: $crate::rt::BufStream<Stream>,
        }

        impl<Stream> Client<Stream>
            where Stream: $crate::rt::Stream,
        {
            pub fn new(stream: Stream) -> Client<Stream> {
                Client {
                    stream: $crate::rt::BufStream::new(stream),
                }
            }
        }

        impl<Stream> Drop for Client<Stream>
            where Stream: $crate::rt::Stream,
        {
            fn drop(&mut self) {
                let _ = $crate::rt::send(&mut self.stream, &Request::_SHUTDOWN);
            }
        }

        impl<Stream> Methods for Client<Stream>
            where Stream: $crate::rt::Stream,
        {
            $(
                fn $fn_name(&mut self, $( $arg: $arg_ty ),*)
                    -> $crate::Result<$ret_ty>
                {
                    let req = Request::$fn_name($( $arg ),*);
                    try!($crate::rt::send(&mut self.stream, &req));
                    let ret = try!($crate::rt::recv(&mut self.stream));
                    Ok(ret)
                }
            )*
        }

        pub fn serve<Impl, Stream>(mut handler: Impl, mut stream: Stream)
            -> $crate::Result<()>
            where Stream: $crate::rt::Stream,
                  Impl: Methods,
        {
            loop {
                match try!($crate::rt::recv(&mut stream)) {
                    Request::_SHUTDOWN => return Ok(()),
                    $(
                        Request::$fn_name($( $arg ),*) => {
                            let ret = try!(handler.$fn_name($( $arg ),*));
                            try!($crate::rt::send(&mut stream, &ret));
                        }
                    )*
                };
            }
        }
    }}
}

// Run-time helpers for macro-generated code
#[doc(hidden)]
pub mod rt {
    use std::io::{Read, Write};
    use rustc_serialize::{Encodable, Decodable};
    use bincode::{self, SizeLimit};

    use super::Result;

    pub use bufstream::BufStream;

    pub trait Stream: Read + Write { }
    impl<T: Read + Write> Stream for T { }

    pub fn send<W, T>(w: &mut W, t: &T) -> Result<()>
        where W: Write, T: Encodable
    {
        try!(bincode::encode_into(t, w, SizeLimit::Infinite));
        try!(w.flush());
        Ok(())
    }

    pub fn recv<R, T>(r: &mut R) -> Result<T>
        where R: Read, T: Decodable
    {
        let r = try!(bincode::decode_from(r, SizeLimit::Infinite));
        Ok(r)
    }
}

#[derive(Debug)]
pub enum Error {
    IoError(io::Error),
    ProtocolError,
}

impl fmt::Display for Error {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        <Self as fmt::Debug>::fmt(self, fmt)
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::IoError(ref e) => error::Error::description(e),
            Error::ProtocolError => "urpc protocol error",
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            Error::IoError(ref e) => Some(e),
            Error::ProtocolError => None,
        }
    }
}

impl convert::From<io::Error> for Error {
    fn from(e: io::Error) -> Error {
        Error::IoError(e)
    }
}

impl convert::From<EncodingError> for Error {
    fn from(e: EncodingError) -> Error {
        match e {
            EncodingError::IoError(e) => Error::IoError(e),
            EncodingError::SizeLimit => unreachable!(),
        }
    }
}

impl convert::From<DecodingError> for Error {
    fn from(e: DecodingError) -> Error {
        match e {
            DecodingError::IoError(e) => Error::IoError(e),
            DecodingError::InvalidEncoding(_) => Error::ProtocolError,
            DecodingError::SizeLimit => unreachable!(),
        }
    }
}

pub type Result<T> = result::Result<T, Error>;
<|endoftext|>


<commit_before>// TODO
// !#[warn(missing_docs)]

use std::collections::HashMap;

use js_int::UInt;
use ruma_events::EventType;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;

#[derive(Deserialize, Serialize)]
pub struct RoomV3Pdu {
    pub room_id: RoomId,
    pub sender: UserId,
    pub origin: String,
    pub origin_server_ts: UInt,

    // TODO: Replace with event content collection from ruma-events once that exists
    #[serde(rename = "type")]
    pub kind: EventType,
    pub content: JsonValue,

    #[serde(skip_serializing_if = "Option::is_none")]
    pub state_key: Option<String>,
    pub prev_events: Vec<EventId>,
    pub depth: UInt,
    pub auth_events: Vec<EventId>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redacts: Option<EventId>,
    #[serde(default, skip_serializing_if = "serde_json::Map::is_empty")]
    pub unsigned: serde_json::Map<String, JsonValue>,
    pub hashes: EventHash,
    pub signatures: HashMap<String, HashMap<String, String>>,
}

#[derive(Deserialize, Serialize)]
pub struct EventHash {
    pub sha256: String,
}
<commit_msg>Add docs<commit_after>//! (De)serializable types for the matrix server-server protocol.

#![warn(missing_docs)]

use std::collections::HashMap;

use js_int::UInt;
use ruma_events::EventType;
use ruma_identifiers::{EventId, RoomId, UserId};
use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue;

/// A 'persistent data unit' (event) for room versions 3 and beyond.
#[derive(Deserialize, Serialize)]
pub struct RoomV3Pdu {
    /// The room this event belongs to.
    pub room_id: RoomId,
    /// The user id of the user who sent this event.
    pub sender: UserId,
    /// The `server_name` of the homeserver that created this event.
    pub origin: String,
    /// Timestamp (milliseconds since the UNIX epoch) on originating homeserver
    /// of when this event was created.
    pub origin_server_ts: UInt,

    // TODO: Replace with event content collection from ruma-events once that exists
    /// The event's type.
    #[serde(rename = "type")]
    pub kind: EventType,
    /// The event's content.
    pub content: JsonValue,

    /// A key that determines which piece of room state the event represents.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub state_key: Option<String>,
    /// Event IDs for the most recent events in the room that the homeserver was
    /// aware of when it created this event.
    pub prev_events: Vec<EventId>,
    /// The maximum depth of the `prev_events`, plus one.
    pub depth: UInt,
    /// Event IDs for the authorization events that would allow this event to be
    /// in the room.
    pub auth_events: Vec<EventId>,
    /// For redaction events, the ID of the event being redacted.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub redacts: Option<EventId>,
    /// Additional data added by the origin server but not covered by the
    /// signatures.
    #[serde(default, skip_serializing_if = "serde_json::Map::is_empty")]
    pub unsigned: serde_json::Map<String, JsonValue>,
    /// Content hashes of the PDU.
    pub hashes: EventHash,
    /// Signatures for the PDU.
    pub signatures: HashMap<String, HashMap<String, String>>,
}

/// Content hashes of a PDU.
#[derive(Deserialize, Serialize)]
pub struct EventHash {
    /// The SHA-256 hash.
    pub sha256: String,
}
<|endoftext|>


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

//! A cache that holds a limited number of key-value pairs. When the
//! capacity of the cache is exceeded, the least-recently-used
//! (where "used" means a look-up or putting the pair into the cache)
//! pair is automatically removed.
//!
//! # Example
//!
//! ```
//! # extern crate "lru-cache" as lru_cache;
//! # fn main() {
//! use lru_cache::LruCache;
//!
//! let mut cache = LruCache::new(2);
//! cache.insert(1, 10);
//! cache.insert(2, 20);
//! cache.insert(3, 30);
//! assert!(cache.get(&1).is_none());
//! assert_eq!(*cache.get(&2).unwrap(), 20);
//! assert_eq!(*cache.get(&3).unwrap(), 30);
//!
//! cache.insert(2, 22);
//! assert_eq!(*cache.get(&2).unwrap(), 22);
//!
//! cache.insert(6, 60);
//! assert!(cache.get(&3).is_none());
//!
//! cache.set_capacity(1);
//! assert!(cache.get(&2).is_none());
//! # }
//! ```

#![feature(core)]

extern crate "linked-hash-map" as linked_hash_map;

use std::fmt;
use std::hash::Hash;
use std::iter::{range, IntoIterator, Extend};

use linked_hash_map::LinkedHashMap;

// FIXME(conventions): implement iterators?
// FIXME(conventions): implement indexing?

/// An LRU Cache.
pub struct LruCache<K, V> {
    map: LinkedHashMap<K, V>,
    max_size: usize,
}

impl<K: Hash + Eq, V> LruCache<K, V> {
    /// Create an LRU Cache that holds at most `capacity` items.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache: LruCache<i32, &str> = LruCache::new(10);
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn new(capacity: usize) -> LruCache<K, V> {
        LruCache {
            map: LinkedHashMap::new(),
            max_size: capacity,
        }
    }

    /// Inserts a key-value pair into the cache. If the key already existed, the old value is
    /// returned.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// assert_eq!(cache.get(&1), Some(&"a"));
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        let old_val = self.map.insert(k, v);
        if self.len() > self.capacity() {
            self.remove_lru();
        }
        old_val
    }

    /// Return a value corresponding to the key in the cache.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// cache.insert(2, "c");
    /// cache.insert(3, "d");
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), Some(&"c"));
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn get(&mut self, k: &K) -> Option<&V> {
        self.map.get_refresh(k)
    }

    /// Remove and return a value corresponding to the key from the cache.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(2, "a");
    ///
    /// assert_eq!(cache.remove(&1), None);
    /// assert_eq!(cache.remove(&2), Some("a"));
    /// assert_eq!(cache.remove(&2), None);
    /// assert_eq!(cache.len(), 0);
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Return the maximum number of key-value pairs the cache can hold.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache: LruCache<i32, &str> = LruCache::new(2);
    /// assert_eq!(cache.capacity(), 2);
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn capacity(&self) -> usize {
        self.max_size
    }

    /// Change the number of key-value pairs the cache can hold. Remove
    /// least-recently-used key-value pairs if necessary.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// cache.insert(3, "c");
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// assert_eq!(cache.get(&3), Some(&"c"));
    ///
    /// cache.set_capacity(3);
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    ///
    /// assert_eq!(cache.get(&1), Some(&"a"));
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// assert_eq!(cache.get(&3), Some(&"c"));
    ///
    /// cache.set_capacity(1);
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), None);
    /// assert_eq!(cache.get(&3), Some(&"c"));
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn set_capacity(&mut self, capacity: usize) {
        for _ in range(capacity, self.len()) {
            self.remove_lru();
        }
        self.max_size = capacity;
    }

    #[inline]
    fn remove_lru(&mut self) {
        self.map.pop_front()
    }

    /// Return the number of key-value pairs in the cache.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn len(&self) -> usize { self.map.len() }

    /// Returns whether the cache is currently empty.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_empty(&self) -> bool { self.map.is_empty() }

    /// Clear the cache of all key-value pairs.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn clear(&mut self) { self.map.clear(); }

}

impl<K: Hash + Eq, V> Extend<(K, V)> for LruCache<K, V> {
    fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) {
        for (k, v) in iter {
            self.insert(k, v);
        }
    }
}

impl<A: fmt::Debug + Hash + Eq, B: fmt::Debug> fmt::Debug for LruCache<A, B> {
    /// Return a string that lists the key-value pairs from most-recently
    /// used to least-recently used.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{{"));

        for (i, (k, v)) in self.map.iter().rev().enumerate() {
            if i != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{:?}: {:?}", *k, *v));
        }

        write!(f, "}}")
    }
}

unsafe impl<K: Send, V: Send> Send for LruCache<K, V> {}

unsafe impl<K: Sync, V: Sync> Sync for LruCache<K, V> {}

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

    fn assert_opt_eq<V: PartialEq>(opt: Option<&V>, v: V) {
        assert!(opt.is_some());
        assert!(opt.unwrap() == &v);
    }

    #[test]
    fn test_put_and_get() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        assert_opt_eq(cache.get(&1), 10);
        assert_opt_eq(cache.get(&2), 20);
        assert_eq!(cache.len(), 2);
    }

    #[test]
    fn test_put_update() {
        let mut cache: LruCache<String, Vec<u8>> = LruCache::new(1);
        cache.insert("1".to_string(), vec![10, 10]);
        cache.insert("1".to_string(), vec![10, 19]);
        assert_opt_eq(cache.get(&"1".to_string()), vec![10, 19]);
        assert_eq!(cache.len(), 1);
    }

    #[test]
    fn test_expire_lru() {
        let mut cache: LruCache<String, String> = LruCache::new(2);
        cache.insert("foo1".to_string(), "bar1".to_string());
        cache.insert("foo2".to_string(), "bar2".to_string());
        cache.insert("foo3".to_string(), "bar3".to_string());
        assert!(cache.get(&"foo1".to_string()).is_none());
        cache.insert("foo2".to_string(), "bar2update".to_string());
        cache.insert("foo4".to_string(), "bar4".to_string());
        assert!(cache.get(&"foo3".to_string()).is_none());
    }

    #[test]
    fn test_pop() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        assert_eq!(cache.len(), 2);
        let opt1 = cache.remove(&1);
        assert!(opt1.is_some());
        assert_eq!(opt1.unwrap(), 10);
        assert!(cache.get(&1).is_none());
        assert_eq!(cache.len(), 1);
    }

    #[test]
    fn test_change_capacity() {
        let mut cache = LruCache::new(2);
        assert_eq!(cache.capacity(), 2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.set_capacity(1);
        assert!(cache.get(&1).is_none());
        assert_eq!(cache.capacity(), 1);
    }

    #[test]
    fn test_debug() {
        let mut cache: LruCache<i32, i32> = LruCache::new(3);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.insert(3, 30);
        assert_eq!(format!("{:?}", cache), "{3: 30, 2: 20, 1: 10}");
        cache.insert(2, 22);
        assert_eq!(format!("{:?}", cache), "{2: 22, 3: 30, 1: 10}");
        cache.insert(6, 60);
        assert_eq!(format!("{:?}", cache), "{6: 60, 2: 22, 3: 30}");
        cache.get(&3);
        assert_eq!(format!("{:?}", cache), "{3: 30, 6: 60, 2: 22}");
        cache.set_capacity(2);
        assert_eq!(format!("{:?}", cache), "{3: 30, 6: 60}");
    }

    #[test]
    fn test_remove() {
        let mut cache = LruCache::new(3);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.insert(3, 30);
        cache.insert(4, 40);
        cache.insert(5, 50);
        cache.remove(&3);
        cache.remove(&4);
        assert!(cache.get(&3).is_none());
        assert!(cache.get(&4).is_none());
        cache.insert(6, 60);
        cache.insert(7, 70);
        cache.insert(8, 80);
        assert!(cache.get(&5).is_none());
        assert_opt_eq(cache.get(&6), 60);
        assert_opt_eq(cache.get(&7), 70);
        assert_opt_eq(cache.get(&8), 80);
    }

    #[test]
    fn test_clear() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.clear();
        assert!(cache.get(&1).is_none());
        assert!(cache.get(&2).is_none());
        assert_eq!(format!("{:?}", cache), "{}");
    }
}
<commit_msg>replace `range` function with range syntax<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A cache that holds a limited number of key-value pairs. When the
//! capacity of the cache is exceeded, the least-recently-used
//! (where "used" means a look-up or putting the pair into the cache)
//! pair is automatically removed.
//!
//! # Example
//!
//! ```
//! # extern crate "lru-cache" as lru_cache;
//! # fn main() {
//! use lru_cache::LruCache;
//!
//! let mut cache = LruCache::new(2);
//! cache.insert(1, 10);
//! cache.insert(2, 20);
//! cache.insert(3, 30);
//! assert!(cache.get(&1).is_none());
//! assert_eq!(*cache.get(&2).unwrap(), 20);
//! assert_eq!(*cache.get(&3).unwrap(), 30);
//!
//! cache.insert(2, 22);
//! assert_eq!(*cache.get(&2).unwrap(), 22);
//!
//! cache.insert(6, 60);
//! assert!(cache.get(&3).is_none());
//!
//! cache.set_capacity(1);
//! assert!(cache.get(&2).is_none());
//! # }
//! ```

extern crate "linked-hash-map" as linked_hash_map;

use std::fmt;
use std::hash::Hash;
use std::iter::{IntoIterator, Extend};

use linked_hash_map::LinkedHashMap;

// FIXME(conventions): implement iterators?
// FIXME(conventions): implement indexing?

/// An LRU Cache.
pub struct LruCache<K, V> {
    map: LinkedHashMap<K, V>,
    max_size: usize,
}

impl<K: Hash + Eq, V> LruCache<K, V> {
    /// Create an LRU Cache that holds at most `capacity` items.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache: LruCache<i32, &str> = LruCache::new(10);
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn new(capacity: usize) -> LruCache<K, V> {
        LruCache {
            map: LinkedHashMap::new(),
            max_size: capacity,
        }
    }

    /// Inserts a key-value pair into the cache. If the key already existed, the old value is
    /// returned.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// assert_eq!(cache.get(&1), Some(&"a"));
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
        let old_val = self.map.insert(k, v);
        if self.len() > self.capacity() {
            self.remove_lru();
        }
        old_val
    }

    /// Return a value corresponding to the key in the cache.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// cache.insert(2, "c");
    /// cache.insert(3, "d");
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), Some(&"c"));
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn get(&mut self, k: &K) -> Option<&V> {
        self.map.get_refresh(k)
    }

    /// Remove and return a value corresponding to the key from the cache.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(2, "a");
    ///
    /// assert_eq!(cache.remove(&1), None);
    /// assert_eq!(cache.remove(&2), Some("a"));
    /// assert_eq!(cache.remove(&2), None);
    /// assert_eq!(cache.len(), 0);
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn remove(&mut self, k: &K) -> Option<V> {
        self.map.remove(k)
    }

    /// Return the maximum number of key-value pairs the cache can hold.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache: LruCache<i32, &str> = LruCache::new(2);
    /// assert_eq!(cache.capacity(), 2);
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn capacity(&self) -> usize {
        self.max_size
    }

    /// Change the number of key-value pairs the cache can hold. Remove
    /// least-recently-used key-value pairs if necessary.
    ///
    /// # Example
    ///
    /// ```
    /// # extern crate "lru-cache" as lru_cache;
    /// # fn main() {
    /// use lru_cache::LruCache;
    /// let mut cache = LruCache::new(2);
    ///
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    /// cache.insert(3, "c");
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// assert_eq!(cache.get(&3), Some(&"c"));
    ///
    /// cache.set_capacity(3);
    /// cache.insert(1, "a");
    /// cache.insert(2, "b");
    ///
    /// assert_eq!(cache.get(&1), Some(&"a"));
    /// assert_eq!(cache.get(&2), Some(&"b"));
    /// assert_eq!(cache.get(&3), Some(&"c"));
    ///
    /// cache.set_capacity(1);
    ///
    /// assert_eq!(cache.get(&1), None);
    /// assert_eq!(cache.get(&2), None);
    /// assert_eq!(cache.get(&3), Some(&"c"));
    /// # }
    /// ```
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn set_capacity(&mut self, capacity: usize) {
        for _ in capacity..self.len() {
            self.remove_lru();
        }
        self.max_size = capacity;
    }

    #[inline]
    fn remove_lru(&mut self) {
        self.map.pop_front()
    }

    /// Return the number of key-value pairs in the cache.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn len(&self) -> usize { self.map.len() }

    /// Returns whether the cache is currently empty.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn is_empty(&self) -> bool { self.map.is_empty() }

    /// Clear the cache of all key-value pairs.
    #[unstable = "matches collection reform specification, waiting for dust to settle"]
    pub fn clear(&mut self) { self.map.clear(); }

}

impl<K: Hash + Eq, V> Extend<(K, V)> for LruCache<K, V> {
    fn extend<T: IntoIterator<Item=(K, V)>>(&mut self, iter: T) {
        for (k, v) in iter {
            self.insert(k, v);
        }
    }
}

impl<A: fmt::Debug + Hash + Eq, B: fmt::Debug> fmt::Debug for LruCache<A, B> {
    /// Return a string that lists the key-value pairs from most-recently
    /// used to least-recently used.
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "{{"));

        for (i, (k, v)) in self.map.iter().rev().enumerate() {
            if i != 0 { try!(write!(f, ", ")); }
            try!(write!(f, "{:?}: {:?}", *k, *v));
        }

        write!(f, "}}")
    }
}

unsafe impl<K: Send, V: Send> Send for LruCache<K, V> {}

unsafe impl<K: Sync, V: Sync> Sync for LruCache<K, V> {}

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

    fn assert_opt_eq<V: PartialEq>(opt: Option<&V>, v: V) {
        assert!(opt.is_some());
        assert!(opt.unwrap() == &v);
    }

    #[test]
    fn test_put_and_get() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        assert_opt_eq(cache.get(&1), 10);
        assert_opt_eq(cache.get(&2), 20);
        assert_eq!(cache.len(), 2);
    }

    #[test]
    fn test_put_update() {
        let mut cache: LruCache<String, Vec<u8>> = LruCache::new(1);
        cache.insert("1".to_string(), vec![10, 10]);
        cache.insert("1".to_string(), vec![10, 19]);
        assert_opt_eq(cache.get(&"1".to_string()), vec![10, 19]);
        assert_eq!(cache.len(), 1);
    }

    #[test]
    fn test_expire_lru() {
        let mut cache: LruCache<String, String> = LruCache::new(2);
        cache.insert("foo1".to_string(), "bar1".to_string());
        cache.insert("foo2".to_string(), "bar2".to_string());
        cache.insert("foo3".to_string(), "bar3".to_string());
        assert!(cache.get(&"foo1".to_string()).is_none());
        cache.insert("foo2".to_string(), "bar2update".to_string());
        cache.insert("foo4".to_string(), "bar4".to_string());
        assert!(cache.get(&"foo3".to_string()).is_none());
    }

    #[test]
    fn test_pop() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        assert_eq!(cache.len(), 2);
        let opt1 = cache.remove(&1);
        assert!(opt1.is_some());
        assert_eq!(opt1.unwrap(), 10);
        assert!(cache.get(&1).is_none());
        assert_eq!(cache.len(), 1);
    }

    #[test]
    fn test_change_capacity() {
        let mut cache = LruCache::new(2);
        assert_eq!(cache.capacity(), 2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.set_capacity(1);
        assert!(cache.get(&1).is_none());
        assert_eq!(cache.capacity(), 1);
    }

    #[test]
    fn test_debug() {
        let mut cache: LruCache<i32, i32> = LruCache::new(3);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.insert(3, 30);
        assert_eq!(format!("{:?}", cache), "{3: 30, 2: 20, 1: 10}");
        cache.insert(2, 22);
        assert_eq!(format!("{:?}", cache), "{2: 22, 3: 30, 1: 10}");
        cache.insert(6, 60);
        assert_eq!(format!("{:?}", cache), "{6: 60, 2: 22, 3: 30}");
        cache.get(&3);
        assert_eq!(format!("{:?}", cache), "{3: 30, 6: 60, 2: 22}");
        cache.set_capacity(2);
        assert_eq!(format!("{:?}", cache), "{3: 30, 6: 60}");
    }

    #[test]
    fn test_remove() {
        let mut cache = LruCache::new(3);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.insert(3, 30);
        cache.insert(4, 40);
        cache.insert(5, 50);
        cache.remove(&3);
        cache.remove(&4);
        assert!(cache.get(&3).is_none());
        assert!(cache.get(&4).is_none());
        cache.insert(6, 60);
        cache.insert(7, 70);
        cache.insert(8, 80);
        assert!(cache.get(&5).is_none());
        assert_opt_eq(cache.get(&6), 60);
        assert_opt_eq(cache.get(&7), 70);
        assert_opt_eq(cache.get(&8), 80);
    }

    #[test]
    fn test_clear() {
        let mut cache = LruCache::new(2);
        cache.insert(1, 10);
        cache.insert(2, 20);
        cache.clear();
        assert!(cache.get(&1).is_none());
        assert!(cache.get(&2).is_none());
        assert_eq!(format!("{:?}", cache), "{}");
    }
}
<|endoftext|>