<commit_before>/*!

Bart is a compile time templating language inspired by
[Mustache](https://mustache.github.io/mustache.5.html). It plays to Rust's
strengths by statically compiling the template into efficient code and
performing full variable resolution and type checking at compile time.

 1. [Cargo dependencies](#cargo-dependencies)
 2. [Example](#example)
    1. [Line-by-line](#line-by-line)

Cargo dependencies
==================
To use Bart, add these dependencies to your `Cargo.toml`:

```toml
[dependencies]
bart = "0.1.0"
bart_derive = "0.1.0"
```

Example
=======
Given the template file `hello_world.html`:

```text
Hello {{name}}
```

We can write the following program:

```
#[macro_use] extern crate bart_derive;

#[derive(BartDisplay)]
#[template = "examples/hello_world.html"]
struct HelloWorld<'a> {
    name: &'a str,
}

fn main() {
    print!("{}", &HelloWorld { name: "World" });
#   assert_eq!("Hello World\n", format!("{}", &HelloWorld { name: "World" }));
}
```

To compile this example program, you need to add both `bart` and `bart_derive` as dependencies in your `Cargo.toml`.

Running this program will output

```text
Hello World
```

You can run this example by cloning this repository and executing `cargo run --example hello_world`.

Line by line
------------
```ignore
#[macro_use] extern crate bart_derive;
```

The programmer interface to Bart is the procedural macro defined in the `bart_derive` crate, which implements support for `#[derive(BartDisplay)]`. It must be added as a dependency in your `Cargo.toml` and referenced like above. `bart_derive` generates code which is dependent on the `bart` crate, so you also need to pull this in as a dependency.

```ignore
#[derive(BartDisplay)]
```

Use `bart_derive` to generate an `impl` of the [`Display`][Display] trait based on the template and struct below.

```ignore
#[template = "hello_world.html"]
```

`bart_derive` will read `hello_world.html` and use it to generate the template rendering code. The given file name is relative to your crate root, so, for example, you have to specify `#[template = "src/hello_world.html"]` if you want your template to reside in the `src/` directory.

It is also possible to specify the template inline with `template_string`: `#[template_string = "Hello {{name}}"]`.

```ignore
struct HelloWorld<'a> {
    name: &'a str,
}
```

Values to be interpolated in the template will be resolved from the given `struct`. In this case `{{name}}` would be resolved to the `name` field of this struct. Fields to be interpolated must implement the [`Display`][Display] trait.

```ignore
fn main() {
    print!("{}", &HelloWorld { name: "World" });
}
```

As noted above, `bart_derive` has now generated an `impl` of [`Display`][Display] for `HelloWorld`. This means we can pass instances of `HelloWorld` to `print!`, `write!`, `format!` and so on. The template is rendered with the supplied data, generating `Hello World` to standard output.

[Display]: https://doc.rust-lang.org/std/fmt/trait.Display.html

*/

#![cfg_attr(feature = "specialization", feature(specialization))]

#[macro_use] extern crate nom;

mod display_html_safe;

// With specialization, DisplayHtmlSafe could be something that the
// user wants to deal with. But specialization is still unstable.
#[doc(hidden)]
pub use display_html_safe::DisplayHtmlSafe;

mod conditional;
pub use conditional::Conditional;

mod negative_iterator;
pub use negative_iterator::NegativeIterator;
<commit_msg>Started reference documentation for the templating language<commit_after>/*!

Bart is a compile time templating language inspired by
[Mustache](https://mustache.github.io/mustache.5.html). It plays to Rust's
strengths by statically compiling the template into efficient code and
performing full variable resolution and type checking at compile time.

 1. [Cargo dependencies](#cargo-dependencies)
 2. [Example](#example)
    1. [Line-by-line](#line-by-line)
 3. [Bart language reference](#bart-language-reference)

Cargo dependencies
==================
To use Bart, add these dependencies to your `Cargo.toml`:

```toml
[dependencies]
bart = "0.1.0"
bart_derive = "0.1.0"
```

Example
=======
Given the template file `hello_world.html`:

```text
Hello {{name}}
```

We can write the following program:

```
#[macro_use] extern crate bart_derive;

#[derive(BartDisplay)]
#[template = "examples/hello_world.html"]
struct HelloWorld<'a> {
    name: &'a str,
}

fn main() {
    print!("{}", &HelloWorld { name: "World" });
#   assert_eq!("Hello World\n", format!("{}", &HelloWorld { name: "World" }));
}
```

To compile this example program, you need to add both `bart` and `bart_derive` as dependencies in your `Cargo.toml`.

Running this program will output

```text
Hello World
```

You can run this example by cloning this repository and executing `cargo run --example hello_world`.

Line by line
------------
```ignore
#[macro_use] extern crate bart_derive;
```

The programmer interface to Bart is the procedural macro defined in the `bart_derive` crate, which implements support for `#[derive(BartDisplay)]`. It must be added as a dependency in your `Cargo.toml` and referenced like above. `bart_derive` generates code which is dependent on the `bart` crate, so you also need to pull this in as a dependency.

```ignore
#[derive(BartDisplay)]
```

Use `bart_derive` to generate an `impl` of the [`Display`][Display] trait based on the template and struct below.

```ignore
#[template = "hello_world.html"]
```

`bart_derive` will read `hello_world.html` and use it to generate the template rendering code. The given file name is relative to your crate root, so, for example, you have to specify `#[template = "src/hello_world.html"]` if you want your template to reside in the `src/` directory.

It is also possible to specify the template inline with `template_string`: `#[template_string = "Hello {{name}}"]`.

```ignore
struct HelloWorld<'a> {
    name: &'a str,
}
```

Values to be interpolated in the template will be resolved from the given `struct`. In this case `{{name}}` would be resolved to the `name` field of this struct. Fields to be interpolated must implement the [`Display`][Display] trait.

```ignore
fn main() {
    print!("{}", &HelloWorld { name: "World" });
}
```

As noted above, `bart_derive` has now generated an `impl` of [`Display`][Display] for `HelloWorld`. This means we can pass instances of `HelloWorld` to `print!`, `write!`, `format!` and so on. The template is rendered with the supplied data, generating `Hello World` to standard output.

[Display]: https://doc.rust-lang.org/std/fmt/trait.Display.html

Bart language reference
=======================
Bart supports: [interpolation](#interpolation), [verbatim
interpolation](#verbatim-interpolation), …

Interpolation
-------------
```
# #[macro_use] extern crate bart_derive;
# #[derive(BartDisplay)]
# #[template_string = "\
Hello {{name}}
# "]
# struct HelloWorld<'a> {
#     name: &'a str,
# }
#
# fn main() {
#     assert_eq!(
#         "Hello World < &\n",
#         format!("{}", &HelloWorld { name: "World < &" })
#     );
# }
```
Include fields by delegating to the [`Display`][Display] trait.

Interpolations are HTML escaped, so it is safe to include user input this way.

Verbatim interpolation
----------------------
```
# #[macro_use] extern crate bart_derive;
# #[derive(BartDisplay)]
# #[template_string = "\
Hello {{{name}}}
# "]
# struct HelloWorld<'a> {
#     name: &'a str,
# }
#
# fn main() {
#     assert_eq!(
#         "Hello World < &\n",
#         format!("{}", &HelloWorld { name: "World < &" })
#     );
# }
```
Include fields by delegating to the [`Display`][Display] trait.

Verbatim interpolations are not HTML escaped and are suitable for including
HTML content that is otherwise known to be safe.

It can be valuable to use verbatim interpolation to include other Bart
templates.

*/

#![cfg_attr(feature = "specialization", feature(specialization))]

#[macro_use] extern crate nom;

mod display_html_safe;

// With specialization, DisplayHtmlSafe could be something that the
// user wants to deal with. But specialization is still unstable.
#[doc(hidden)]
pub use display_html_safe::DisplayHtmlSafe;

mod conditional;
pub use conditional::Conditional;

mod negative_iterator;
pub use negative_iterator::NegativeIterator;
<|endoftext|>


<commit_before>extern crate hyper;
extern crate openssl;
extern crate unix_socket;
extern crate url;

use hyper::{ Client, Url };
use hyper::method::Method;
use hyper::net::NetworkConnector;
use openssl::x509::X509FileType;
use std::io::{ Read, Write };
use std::{ env, result };
use std::path::Path;
use std::io::Error;
use unix_socket::UnixStream;
use url::{ Host, RelativeSchemeData, SchemeData };

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

trait Transport {
  fn request(&mut self, method: Method, endpoint: &str) -> Result<String>;
}

pub struct Docker {
  transport: Box<Transport>
}

impl Transport for UnixStream {
  fn request(&mut self, method: Method, endpoint: &str) -> Result<String> {
     let method_str = match method {
       Method::Put    => "PUT",
       Method::Post   => "POST",
       Method::Delete => "DELETE",
                _     => "GET"
     };
     let req = format!("{} {} HTTP/1.0\r\n\r\n", method_str, endpoint);
     try!(self.write_all(req.as_bytes()));
     let mut result = String::new();
     self.read_to_string(&mut result).map(|_| result)
  }
}

impl<C: NetworkConnector> Transport for (Client<C>, String) {
  fn request(&mut self, method: Method, endpoint: &str) -> Result<String> {
    let uri = format!("{}{}", self.1, endpoint);
    let req = match method {
       Method::Put    => self.0.put(&uri[..]),
       Method::Post   => self.0.post(&uri[..]),
       Method::Delete => self.0.delete(&uri[..]),
                    _ => self.0.get(&uri[..])
    };
    let mut res = match req.send() {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    let mut body = String::new();
    res.read_to_string(&mut body).map(|_| body)
  }
}

pub struct Image<'a, 'b> {
  docker: &'a mut Docker,
  name: &'b str
}

impl<'a, 'b> Image<'a, 'b> {
  pub fn new(docker: &'a mut Docker, name: &'b str) -> Image<'a, 'b> {
    Image { docker: docker, name: name }
  }

  pub fn inspect(self) -> Result<String> {
    self.docker.get(&format!("/images/{}/json", self.name)[..])
  }

  pub fn history(self) -> Result<String> {
    self.docker.get(&format!("/images/{}/history", self.name)[..])
  }

  pub fn delete(self) -> Result<String> {
    self.docker.delete(&format!("/images/{}", self.name)[..])
  }
}

pub struct Images<'a> {
  docker: &'a mut Docker
}

impl<'a> Images<'a> {
  pub fn new(docker: &'a mut Docker) -> Images<'a> {
    Images { docker: docker }
  }

  pub fn list(self) -> Result<String> {
    self.docker.get("/images/json")
  }

  pub fn get(&'a mut self, name: &'a str) -> Image {
    Image::new(self.docker, name)
  }

  pub fn search(self, term: &str) -> Result<String> {
    self.docker.get(&format!("/images/search?term={}", term)[..])
  }
}

pub struct Container<'a, 'b> {
  docker: &'a mut Docker,
  id: &'b str
}

impl<'a, 'b> Container<'a, 'b> {
  pub fn new(docker: &'a mut Docker, id: &'b str) -> Container<'a, 'b> {
    Container { docker: docker, id: id }
  }

  pub fn inspect(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/json", self.id)[..])
  }

  pub fn top(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/top", self.id)[..])
  }

  pub fn logs(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/logs", self.id)[..])
  }

  pub fn changes(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/changes", self.id)[..])
  }

  pub fn stats(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/stats", self.id)[..])
  }

  pub fn start(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/start", self.id)[..])
  }

  pub fn stop(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/stop", self.id)[..])
  }

  pub fn restart(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/restart", self.id)[..])
  }

  pub fn kill(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/kill", self.id)[..])
  }

  pub fn rename(self, name: &str) -> Result<String> {
    self.docker.post(&format!("/containers/{}/rename?name={}", self.id, name)[..])
  }

  pub fn pause(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/pause", self.id)[..])
  }

  pub fn unpause(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/unpause", self.id)[..])
  }
}

pub struct Containers<'a> {
  docker: &'a mut Docker
}

impl<'a> Containers<'a> {
  pub fn new(docker: &'a mut Docker) -> Containers<'a> {
    Containers { docker: docker }
  }

  pub fn list(self) -> Result<String> {
    self.docker.get("/containers/json")
  }

  pub fn get(&'a mut self, name: &'a str) -> Container {
    Container::new(self.docker, name)
  }
}

// https://docs.docker.com/reference/api/docker_remote_api_v1.17/
impl Docker {
  pub fn new() -> Docker {
    let host = env::var("DOCKER_HOST")
        .map(|h| Url::parse(&h).ok()
             .expect("invalid url"))
          .ok()
          .expect("expected host");
    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) }
      }
    }
  }

  pub fn images<'a>(&'a mut self) -> Images {
    Images::new(self)
  }

  pub fn containers<'a>(&'a mut self) -> Containers {
    Containers::new(self)
  }

  pub fn version(&mut self) -> Result<String> {
    self.get("/version")
  }

  pub fn info(&mut self) -> Result<String> {
    self.get("/info")
  }

  pub fn ping(&mut self) -> Result<String> {
    self.get("/_ping")
  }

  // todo stream
  pub fn events(&mut self) -> Result<String> {
    self.get("/events")
  }

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

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

  fn delete(&mut self, endpoint: &str) -> Result<String> {
     (*self.transport).request(Method::Delete, endpoint)
   }
}
<commit_msg>start thinking about streaming responses<commit_after>extern crate hyper;
extern crate openssl;
extern crate unix_socket;
extern crate url;

use hyper::{ Client, Url };
use hyper::method::Method;
use hyper::net::NetworkConnector;
use openssl::x509::X509FileType;
use std::io::{ Read, Write };
use std::io;
use std::{ env, result };
use std::path::Path;
use std::io::Error;
use unix_socket::UnixStream;
use url::{ Host, RelativeSchemeData, SchemeData };

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

trait Transport {
  fn request(&mut self, method: Method, endpoint: &str) -> Result<String>;
  fn stream(&mut self, method: Method, endpoint: &str) -> Result<Box<Read>>;
}

pub struct Docker {
  transport: Box<Transport>
}

impl Transport for UnixStream {
  fn request(&mut self, method: Method, endpoint: &str) -> Result<String> {
      let method_str = match method {
       Method::Put    => "PUT",
       Method::Post   => "POST",
       Method::Delete => "DELETE",
                _     => "GET"
     };
     let req = format!("{} {} HTTP/1.0\r\n\r\n", method_str, endpoint);
     try!(self.write_all(req.as_bytes()));
     let mut result = String::new();
     self.read_to_string(&mut result).map(|_| result)
  }

  fn stream(&mut self, method: Method, endpoint: &str) -> Result<Box<Read>> {
    Err(io::Error::new(io::ErrorKind::InvalidInput, "Not yet implemented", None))
  }
}

impl<C: NetworkConnector> Transport for (Client<C>, String) {
  fn request(&mut self, method: Method, endpoint: &str) -> Result<String> {
    let uri = format!("{}{}", self.1, endpoint);
    let req = match method {
       Method::Put    => self.0.put(&uri[..]),
       Method::Post   => self.0.post(&uri[..]),
       Method::Delete => self.0.delete(&uri[..]),
                    _ => self.0.get(&uri[..])
    };
    let mut res = match req.send() {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    let mut body = String::new();
    res.read_to_string(&mut body).map(|_| body)
  }

  fn stream(&mut self, method: Method, endpoint: &str) -> Result<Box<Read>> {
    let uri = format!("{}{}", self.1, endpoint);
    let req = match method {
       Method::Put    => self.0.put(&uri[..]),
       Method::Post   => self.0.post(&uri[..]),
       Method::Delete => self.0.delete(&uri[..]),
                    _ => self.0.get(&uri[..])
    };
    let mut res = match req.send() {
      Ok(r) => r,
      Err(e) => panic!("failed request {:?}", e)
    };
    Ok(Box::new(res))
  }
}

pub struct Image<'a, 'b> {
  docker: &'a mut Docker,
  name: &'b str
}

impl<'a, 'b> Image<'a, 'b> {
  pub fn new(docker: &'a mut Docker, name: &'b str) -> Image<'a, 'b> {
    Image { docker: docker, name: name }
  }

  pub fn inspect(self) -> Result<String> {
    self.docker.get(&format!("/images/{}/json", self.name)[..])
  }

  pub fn history(self) -> Result<String> {
    self.docker.get(&format!("/images/{}/history", self.name)[..])
  }

  pub fn delete(self) -> Result<String> {
    self.docker.delete(&format!("/images/{}", self.name)[..])
  }
}

pub struct Images<'a> {
  docker: &'a mut Docker
}

impl<'a> Images<'a> {
  pub fn new(docker: &'a mut Docker) -> Images<'a> {
    Images { docker: docker }
  }

  pub fn list(self) -> Result<String> {
    self.docker.get("/images/json")
  }

  pub fn get(&'a mut self, name: &'a str) -> Image {
    Image::new(self.docker, name)
  }

  pub fn search(self, term: &str) -> Result<String> {
    self.docker.get(&format!("/images/search?term={}", term)[..])
  }
}

pub struct Container<'a, 'b> {
  docker: &'a mut Docker,
  id: &'b str
}

impl<'a, 'b> Container<'a, 'b> {
  pub fn new(docker: &'a mut Docker, id: &'b str) -> Container<'a, 'b> {
    Container { docker: docker, id: id }
  }

  pub fn inspect(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/json", self.id)[..])
  }

  pub fn top(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/top", self.id)[..])
  }

  pub fn logs(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/logs", self.id)[..])
  }

  pub fn changes(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/changes", self.id)[..])
  }

  pub fn stats(self) -> Result<String> {
    self.docker.get(&format!("/containers/{}/stats", self.id)[..])
  }

  pub fn start(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/start", self.id)[..])
  }

  pub fn stop(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/stop", self.id)[..])
  }

  pub fn restart(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/restart", self.id)[..])
  }

  pub fn kill(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/kill", self.id)[..])
  }

  pub fn rename(self, name: &str) -> Result<String> {
    self.docker.post(&format!("/containers/{}/rename?name={}", self.id, name)[..])
  }

  pub fn pause(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/pause", self.id)[..])
  }

  pub fn unpause(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/unpause", self.id)[..])
  }

  pub fn wait(self) -> Result<String> {
    self.docker.post(&format!("/containers/{}/wait", self.id)[..])
  }

  pub fn delete(self) -> Result<String> {
    self.docker.delete(&format!("/containers/{}", self.id)[..])
  }
  // todo attach, attach/ws,
}

pub struct Containers<'a> {
  docker: &'a mut Docker
}

impl<'a> Containers<'a> {
  pub fn new(docker: &'a mut Docker) -> Containers<'a> {
    Containers { docker: docker }
  }

  pub fn list(self) -> Result<String> {
    self.docker.get("/containers/json")
  }

  pub fn get(&'a mut self, name: &'a str) -> Container {
    Container::new(self.docker, name)
  }
}

// https://docs.docker.com/reference/api/docker_remote_api_v1.17/
impl Docker {
  pub fn new() -> Docker {
    let host = env::var("DOCKER_HOST")
        .map(|h| Url::parse(&h).ok()
             .expect("invalid url"))
          .ok()
          .expect("expected host");
    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) }
      }
    }
  }

  pub fn images<'a>(&'a mut self) -> Images {
    Images::new(self)
  }

  pub fn containers<'a>(&'a mut self) -> Containers {
    Containers::new(self)
  }

  pub fn version(&mut self) -> Result<String> {
    self.get("/version")
  }

  pub fn info(&mut self) -> Result<String> {
    self.get("/info")
  }

  pub fn ping(&mut self) -> Result<String> {
    self.get("/_ping")
  }

  // todo stream
  pub fn events(&mut self) -> Result<String> {
    self.get("/events")
  }

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

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

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


<commit_before>//! Manipulations and data types that represent polynomial.

#![warn(bad_style, missing_docs,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

extern crate num;

use std::{cmp, fmt};
use std::ops::{Add, Mul, Neg, Sub};
use num::{Zero, One};

/// Polynomial expression
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Polynomial<T> {
    data: Vec<T>,
}

impl<T: Zero> Polynomial<T> {
    /// Creates new `Polynomial`.
    ///
    /// ```rust
    /// use polynomial::Polynomial;
    /// let poly = Polynomial::new(vec![1, 2, 3]);
    /// assert_eq!("1+2*x+3*x^2", poly.pretty("x"));
    /// ```
    #[inline]
    pub fn new(mut data: Vec<T>) -> Polynomial<T> {
        while let Some(true) = data.last().map(|x| x.is_zero()) {
            let _ = data.pop();
        }
        Polynomial { data: data }
    }
}

impl<T: Zero + One + Clone> Polynomial<T> {
    /// Evaluates the polynomial value.
    ///
    /// ```rust
    /// use polynomial::Polynomial;
    /// let poly = Polynomial::new(vec![1, 2, 3]);
    /// assert_eq!(1, poly.eval(0));
    /// assert_eq!(6, poly.eval(1));
    /// assert_eq!(17, poly.eval(2));
    /// ```
    #[inline]
    pub fn eval(&self, x: T) -> T {
        let mut sum: T = Zero::zero();
        let mut x_n: T = One::one();
        for n in self.data.iter() {
            sum = sum + n.clone() * x_n.clone();
            x_n = x_n * x.clone();
        }
        sum
    }
}

impl<T> Polynomial<T> {
    /// Gets the slice of internal data.
    #[inline]
    pub fn data(&self) -> &[T] {
        &self.data
    }
}

impl<T> Polynomial<T>
    where T: Zero + One + Eq + Neg<Output = T> + Ord + fmt::Display + Clone
{
    /// Pretty prints the polynomial.
    pub fn pretty(&self, x: &str) -> String {
        if self.is_zero() {
            return "0".to_string();
        }

        let one = One::one();
        let mut s = Vec::new();
        for (i, n) in self.data.iter().enumerate() {
            // output n*x^i / -n*x^i
            if n.is_zero() {
                continue;
            }

            let term = if i.is_zero() {
                n.to_string()
            } else if i == 1 {
                if (*n) == one {
                    x.to_string()
                } else if (*n) == -one.clone() {
                    format!("-{}", x)
                } else {
                    format!("{}*{}", n.to_string(), x)
                }
            } else {
                if (*n) == one {
                    format!("{}^{}", x, i)
                } else if (*n) == -one.clone() {
                    format!("-{}^{}", x, i)
                } else {
                    format!("{}*{}^{}", n.to_string(), x, i)
                }
            };

            if s.len() > 0 && (*n) > Zero::zero() {
                s.push("+".to_string());
            }
            s.push(term);
        }

        s.concat()
    }
}

impl<'a, T> Neg for Polynomial<T>
    where T: Neg + Zero + Clone, <T as Neg>::Output: Zero
{
    type Output = Polynomial<<T as Neg>::Output>;

    #[inline]
    fn neg(self) -> Polynomial<<T as Neg>::Output> {
        -&self
    }
}

impl<'a, T> Neg for &'a Polynomial<T>
    where T: Neg + Zero + Clone, <T as Neg>::Output: Zero
{
    type Output = Polynomial<<T as Neg>::Output>;

    #[inline]
    fn neg(self) -> Polynomial<<T as Neg>::Output> {
        Polynomial::new(self.data.iter().map(|x| -x.clone()).collect())
    }
}

macro_rules! forward_val_val_binop {
    (impl $imp:ident, $method:ident) => {
        impl<Lhs, Rhs> $imp<Polynomial<Rhs>> for Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs> + Clone, Rhs: Zero + Clone,
                  <Lhs as $imp<Rhs>>::Output: Zero
        {
            type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;

            #[inline]
            fn $method(self, other: Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
                (&self).$method(&other)
            }
        }
    }
}

macro_rules! forward_ref_val_binop {
    (impl $imp:ident, $method:ident) => {
        impl<'a, Lhs, Rhs> $imp<Polynomial<Rhs>> for &'a Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs> + Clone, Rhs: Zero + Clone,
                  <Lhs as $imp<Rhs>>::Output: Zero
        {
            type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;

            #[inline]
            fn $method(self, other: Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
                self.$method(&other)
            }
        }
    }
}

macro_rules! forward_val_ref_binop {
    (impl $imp:ident, $method:ident) => {
        impl<'a, Lhs, Rhs> $imp<&'a Polynomial<Rhs>> for Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs> + Clone, Rhs: Zero + Clone,
                  <Lhs as $imp<Rhs>>::Output: Zero
        {
            type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;

            #[inline]
            fn $method(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
                (&self).$method(other)
            }
        }
    }
}

macro_rules! forward_all_binop {
    (impl $imp:ident, $method:ident) => {
        forward_val_val_binop!(impl $imp, $method);
        forward_ref_val_binop!(impl $imp, $method);
        forward_val_ref_binop!(impl $imp, $method);
    };
}

forward_all_binop!(impl Add, add);

impl<'a, 'b, Lhs, Rhs> Add<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Add<Rhs> + Clone, Rhs: Zero + Clone,
          <Lhs as Add<Rhs>>::Output: Zero
{
    type Output = Polynomial<<Lhs as Add<Rhs>>::Output>;

    fn add(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Add<Rhs>>::Output> {
        let max_len = cmp::max(self.data.len(), other.data.len());
        let min_len = cmp::min(self.data.len(), other.data.len());

        let mut sum = Vec::with_capacity(max_len);
        for i in (0..min_len) {
            sum.push(self.data[i].clone() + other.data[i].clone());
        }

        if self.data.len() <= other.data.len() {
            for i in (min_len..max_len) {
                sum.push(num::zero::<Lhs>() + other.data[i].clone());
            }
        } else {
            for i in (min_len..max_len) {
                sum.push(self.data[i].clone() + num::zero::<Rhs>());
            }
        }

        Polynomial::new(sum)
    }
}

forward_all_binop!(impl Sub, sub);

impl<'a, 'b, Lhs, Rhs> Sub<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Sub<Rhs> + Clone, Rhs: Zero + Clone,
          <Lhs as Sub<Rhs>>::Output: Zero
{
    type Output = Polynomial<<Lhs as Sub<Rhs>>::Output>;

    fn sub(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Sub<Rhs>>::Output> {
        let min_len = cmp::min(self.data.len(), other.data.len());
        let max_len = cmp::max(self.data.len(), other.data.len());

        let mut sub = Vec::with_capacity(max_len);
        for i in (0..min_len) {
            sub.push(self.data[i].clone() - other.data[i].clone());
        }
        if self.data.len() <= other.data.len() {
            for i in (min_len..max_len) {
                sub.push(num::zero::<Lhs>() - other.data[i].clone())
            }
        } else {
            for i in (min_len..max_len) {
                sub.push(self.data[i].clone() - num::zero::<Rhs>())
            }
        }
        Polynomial::new(sub)
    }
}

forward_all_binop!(impl Mul, mul);

impl<'a, 'b, Lhs, Rhs> Mul<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Mul<Rhs> + Clone, Rhs: Zero + Clone,
          <Lhs as Mul<Rhs>>::Output: Zero
{
    type Output = Polynomial<<Lhs as Mul<Rhs>>::Output>;

    fn mul(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Mul<Rhs>>::Output> {
        if self.is_zero() || other.is_zero() {
            return Polynomial::new(vec![]);
        }

        let slen = self.data.len();
        let olen = other.data.len();
        let prod = (0..slen + olen - 1)
                       .map(|i| {
                           let mut p = num::zero::<<Lhs as Mul<Rhs>>::Output>();
                           let kstart = cmp::max(olen, i + 1) - olen;
                           let kend = cmp::min(slen, i + 1);
                           for k in kstart..kend {
                               p = p + self.data[k].clone() * other.data[i - k].clone();
                           }
                           p
                       })
                       .collect();
        Polynomial::new(prod)
    }
}

impl<T: Zero + Clone> Zero for Polynomial<T> {
    #[inline]
    fn zero() -> Polynomial<T> {
        Polynomial { data: vec![] }
    }
    #[inline]
    fn is_zero(&self) -> bool {
        self.data.is_empty()
    }
}

impl<T: Zero + One + Clone> One for Polynomial<T> {
    #[inline]
    fn one() -> Polynomial<T> {
        Polynomial { data: vec![One::one()] }
    }
}

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

    #[test]
    fn new() {
        fn check(dst: Vec<i32>, src: Vec<i32>) {
            assert_eq!(dst, Polynomial::new(src).data);
        }
        check(vec![1, 2, 3], vec![1, 2, 3]);
        check(vec![1, 2, 3], vec![1, 2, 3, 0, 0]);
        check(vec![], vec![0, 0, 0]);
    }

    #[test]
    fn neg_add_sub() {
        fn check(a: &[i32], b: &[i32], c: &[i32]) {
            fn check_eq(a: &Polynomial<i32>, b: &Polynomial<i32>) {
                assert_eq!(*a, *b);
                assert_eq!(-a, -b);
            }
            fn check_add(sum: &Polynomial<i32>, a: &Polynomial<i32>, b: &Polynomial<i32>) {
                check_eq(sum, &(a + b));
                check_eq(sum, &(b + a));
            }
            fn check_sub(sum: &Polynomial<i32>, a: &Polynomial<i32>, b: &Polynomial<i32>) {
                check_eq(a, &(sum - b));
                check_eq(b, &(sum - a));
            }

            let a = &Polynomial::new(a.to_vec());
            let b = &Polynomial::new(b.to_vec());
            let c = &Polynomial::new(c.to_vec());
            check_add(c, a, b);
            check_add(&(-c), &(-a), &(-b));
            check_sub(c, a, b);
            check_sub(&(-c), &(-a), &(-b));
        }
        check(&[], &[], &[]);
        check(&[], &[1], &[1]);
        check(&[1], &[1], &[2]);
        check(&[1, 0, 1], &[1], &[2, 0, 1]);
        check(&[1, 0, -1], &[-1, 0, 1], &[]);
    }

    #[test]
    fn mul() {
        fn check(a: &[i32], b: &[i32], c: &[i32]) {
            let a = Polynomial::new(a.to_vec());
            let b = Polynomial::new(b.to_vec());
            let c = Polynomial::new(c.to_vec());
            assert_eq!(c, &a * &b);
            assert_eq!(c, &b * &a);
        }
        check(&[], &[], &[]);
        check(&[0, 0], &[], &[]);
        check(&[0, 0], &[1], &[]);
        check(&[1, 0], &[1], &[1]);
        check(&[1, 0, 1], &[1], &[1, 0, 1]);
        check(&[1, 1], &[1, 1], &[1, 2, 1]);
        check(&[1, 1], &[1, 0, 1], &[1, 1, 1, 1]);
        check(&[0, 0, 1], &[0, 0, 1], &[0, 0, 0, 0, 1]);
    }

    #[test]
    fn eval() {
        fn check<F: Fn(i32) -> i32>(pol: &[i32], f: F) {
            for n in (-10..10) {
                assert_eq!(f(n), Polynomial::new(pol.to_vec()).eval(n));
            }
        }
        check(&[], |_x| 0);
        check(&[1], |_x| 1);
        check(&[1, 1], |x| x + 1);
        check(&[0, 1], |x| x);
        check(&[10, -10, 10], |x| 10 * x * x - 10 * x + 10);
    }

    #[test]
    fn pretty() {
        fn check(slice: &[i32], s: &str) {
            assert_eq!(s.to_string(), Polynomial::new(slice.to_vec()).pretty("x"));
        }
        check(&[0], "0");
        check(&[1], "1");
        check(&[1, 1], "1+x");
        check(&[1, 1, 1], "1+x+x^2");
        check(&[2, 2, 2], "2+2*x+2*x^2");
        check(&[0, 0, 0, 1], "x^3");
        check(&[0, 0, 0, -1], "-x^3");
        check(&[-1, 0, 0, -1], "-1-x^3");
        check(&[-1, 1, 0, -1], "-1+x-x^3");
        check(&[-1, 1, -1, -1], "-1+x-x^2-x^3");
    }
}
<commit_msg>fix warnings<commit_after>//! Manipulations and data types that represent polynomial.

#![warn(bad_style)]
#![warn(missing_docs)]
#![warn(trivial_casts)]
#![warn(trivial_numeric_casts)]
#![warn(unused)]
#![warn(unused_extern_crates)]
#![warn(unused_import_braces)]
#![warn(unused_qualifications)]
#![warn(unused_results)]

extern crate num;

use std::{cmp, fmt};
use std::ops::{Add, Mul, Neg, Sub};
use num::{Zero, One};

/// Polynomial expression
#[derive(Eq, PartialEq, Clone, Debug)]
pub struct Polynomial<T> {
    data: Vec<T>,
}

impl<T: Zero> Polynomial<T> {
    /// Creates new `Polynomial`.
    ///
    /// ```rust
    /// use polynomial::Polynomial;
    /// let poly = Polynomial::new(vec![1, 2, 3]);
    /// assert_eq!("1+2*x+3*x^2", poly.pretty("x"));
    /// ```
    #[inline]
    pub fn new(mut data: Vec<T>) -> Polynomial<T> {
        while let Some(true) = data.last().map(|x| x.is_zero()) {
            let _ = data.pop();
        }
        Polynomial { data: data }
    }
}

impl<T: Zero + One + Clone> Polynomial<T> {
    /// Evaluates the polynomial value.
    ///
    /// ```rust
    /// use polynomial::Polynomial;
    /// let poly = Polynomial::new(vec![1, 2, 3]);
    /// assert_eq!(1, poly.eval(0));
    /// assert_eq!(6, poly.eval(1));
    /// assert_eq!(17, poly.eval(2));
    /// ```
    #[inline]
    pub fn eval(&self, x: T) -> T {
        let mut sum: T = Zero::zero();
        let mut x_n: T = One::one();
        for n in self.data.iter() {
            sum = sum + n.clone() * x_n.clone();
            x_n = x_n * x.clone();
        }
        sum
    }
}

impl<T> Polynomial<T> {
    /// Gets the slice of internal data.
    #[inline]
    pub fn data(&self) -> &[T] {
        &self.data
    }
}

impl<T> Polynomial<T>
    where T: Zero + One + Eq + Neg<Output = T> + Ord + fmt::Display + Clone
{
    /// Pretty prints the polynomial.
    pub fn pretty(&self, x: &str) -> String {
        if self.is_zero() {
            return "0".to_string();
        }

        let one = One::one();
        let mut s = Vec::new();
        for (i, n) in self.data.iter().enumerate() {
            // output n*x^i / -n*x^i
            if n.is_zero() {
                continue;
            }

            let term = if i.is_zero() {
                n.to_string()
            } else if i == 1 {
                if (*n) == one {
                    x.to_string()
                } else if (*n) == -one.clone() {
                    format!("-{}", x)
                } else {
                    format!("{}*{}", n.to_string(), x)
                }
            } else {
                if (*n) == one {
                    format!("{}^{}", x, i)
                } else if (*n) == -one.clone() {
                    format!("-{}^{}", x, i)
                } else {
                    format!("{}*{}^{}", n.to_string(), x, i)
                }
            };

            if s.len() > 0 && (*n) > Zero::zero() {
                s.push("+".to_string());
            }
            s.push(term);
        }

        s.concat()
    }
}

impl<'a, T> Neg for Polynomial<T>
    where T: Neg + Zero + Clone, <T as Neg>::Output: Zero
{
    type Output = Polynomial<<T as Neg>::Output>;

    #[inline]
    fn neg(self) -> Polynomial<<T as Neg>::Output> {
        -&self
    }
}

impl<'a, T> Neg for &'a Polynomial<T>
    where T: Neg + Zero + Clone, <T as Neg>::Output: Zero
{
    type Output = Polynomial<<T as Neg>::Output>;

    #[inline]
    fn neg(self) -> Polynomial<<T as Neg>::Output> {
        Polynomial::new(self.data.iter().map(|x| -x.clone()).collect())
    }
}

macro_rules! forward_val_val_binop {
    (impl $imp:ident, $method:ident) => {
        impl<Lhs, Rhs> $imp<Polynomial<Rhs>> for Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs> + Clone, Rhs: Zero + Clone,
                  <Lhs as $imp<Rhs>>::Output: Zero
        {
            type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;

            #[inline]
            fn $method(self, other: Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
                (&self).$method(&other)
            }
        }
    }
}

macro_rules! forward_ref_val_binop {
    (impl $imp:ident, $method:ident) => {
        impl<'a, Lhs, Rhs> $imp<Polynomial<Rhs>> for &'a Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs> + Clone, Rhs: Zero + Clone,
                  <Lhs as $imp<Rhs>>::Output: Zero
        {
            type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;

            #[inline]
            fn $method(self, other: Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
                self.$method(&other)
            }
        }
    }
}

macro_rules! forward_val_ref_binop {
    (impl $imp:ident, $method:ident) => {
        impl<'a, Lhs, Rhs> $imp<&'a Polynomial<Rhs>> for Polynomial<Lhs>
            where Lhs: Zero + $imp<Rhs> + Clone, Rhs: Zero + Clone,
                  <Lhs as $imp<Rhs>>::Output: Zero
        {
            type Output = Polynomial<<Lhs as $imp<Rhs>>::Output>;

            #[inline]
            fn $method(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as $imp<Rhs>>::Output> {
                (&self).$method(other)
            }
        }
    }
}

macro_rules! forward_all_binop {
    (impl $imp:ident, $method:ident) => {
        forward_val_val_binop!(impl $imp, $method);
        forward_ref_val_binop!(impl $imp, $method);
        forward_val_ref_binop!(impl $imp, $method);
    };
}

forward_all_binop!(impl Add, add);

impl<'a, 'b, Lhs, Rhs> Add<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Add<Rhs> + Clone, Rhs: Zero + Clone,
          <Lhs as Add<Rhs>>::Output: Zero
{
    type Output = Polynomial<<Lhs as Add<Rhs>>::Output>;

    fn add(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Add<Rhs>>::Output> {
        let max_len = cmp::max(self.data.len(), other.data.len());
        let min_len = cmp::min(self.data.len(), other.data.len());

        let mut sum = Vec::with_capacity(max_len);
        for i in 0..min_len {
            sum.push(self.data[i].clone() + other.data[i].clone());
        }

        if self.data.len() <= other.data.len() {
            for i in min_len..max_len {
                sum.push(num::zero::<Lhs>() + other.data[i].clone());
            }
        } else {
            for i in min_len..max_len {
                sum.push(self.data[i].clone() + num::zero::<Rhs>());
            }
        }

        Polynomial::new(sum)
    }
}

forward_all_binop!(impl Sub, sub);

impl<'a, 'b, Lhs, Rhs> Sub<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Sub<Rhs> + Clone, Rhs: Zero + Clone,
          <Lhs as Sub<Rhs>>::Output: Zero
{
    type Output = Polynomial<<Lhs as Sub<Rhs>>::Output>;

    fn sub(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Sub<Rhs>>::Output> {
        let min_len = cmp::min(self.data.len(), other.data.len());
        let max_len = cmp::max(self.data.len(), other.data.len());

        let mut sub = Vec::with_capacity(max_len);
        for i in 0..min_len {
            sub.push(self.data[i].clone() - other.data[i].clone());
        }
        if self.data.len() <= other.data.len() {
            for i in min_len..max_len {
                sub.push(num::zero::<Lhs>() - other.data[i].clone())
            }
        } else {
            for i in min_len..max_len {
                sub.push(self.data[i].clone() - num::zero::<Rhs>())
            }
        }
        Polynomial::new(sub)
    }
}

forward_all_binop!(impl Mul, mul);

impl<'a, 'b, Lhs, Rhs> Mul<&'b Polynomial<Rhs>> for &'a Polynomial<Lhs>
    where Lhs: Zero + Mul<Rhs> + Clone, Rhs: Zero + Clone,
          <Lhs as Mul<Rhs>>::Output: Zero
{
    type Output = Polynomial<<Lhs as Mul<Rhs>>::Output>;

    fn mul(self, other: &Polynomial<Rhs>) -> Polynomial<<Lhs as Mul<Rhs>>::Output> {
        if self.is_zero() || other.is_zero() {
            return Polynomial::new(vec![]);
        }

        let slen = self.data.len();
        let olen = other.data.len();
        let prod = (0..slen + olen - 1)
                       .map(|i| {
                           let mut p = num::zero::<<Lhs as Mul<Rhs>>::Output>();
                           let kstart = cmp::max(olen, i + 1) - olen;
                           let kend = cmp::min(slen, i + 1);
                           for k in kstart..kend {
                               p = p + self.data[k].clone() * other.data[i - k].clone();
                           }
                           p
                       })
                       .collect();
        Polynomial::new(prod)
    }
}

impl<T: Zero + Clone> Zero for Polynomial<T> {
    #[inline]
    fn zero() -> Polynomial<T> {
        Polynomial { data: vec![] }
    }
    #[inline]
    fn is_zero(&self) -> bool {
        self.data.is_empty()
    }
}

impl<T: Zero + One + Clone> One for Polynomial<T> {
    #[inline]
    fn one() -> Polynomial<T> {
        Polynomial { data: vec![One::one()] }
    }
}

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

    #[test]
    fn new() {
        fn check(dst: Vec<i32>, src: Vec<i32>) {
            assert_eq!(dst, Polynomial::new(src).data);
        }
        check(vec![1, 2, 3], vec![1, 2, 3]);
        check(vec![1, 2, 3], vec![1, 2, 3, 0, 0]);
        check(vec![], vec![0, 0, 0]);
    }

    #[test]
    fn neg_add_sub() {
        fn check(a: &[i32], b: &[i32], c: &[i32]) {
            fn check_eq(a: &Polynomial<i32>, b: &Polynomial<i32>) {
                assert_eq!(*a, *b);
                assert_eq!(-a, -b);
            }
            fn check_add(sum: &Polynomial<i32>, a: &Polynomial<i32>, b: &Polynomial<i32>) {
                check_eq(sum, &(a + b));
                check_eq(sum, &(b + a));
            }
            fn check_sub(sum: &Polynomial<i32>, a: &Polynomial<i32>, b: &Polynomial<i32>) {
                check_eq(a, &(sum - b));
                check_eq(b, &(sum - a));
            }

            let a = &Polynomial::new(a.to_vec());
            let b = &Polynomial::new(b.to_vec());
            let c = &Polynomial::new(c.to_vec());
            check_add(c, a, b);
            check_add(&(-c), &(-a), &(-b));
            check_sub(c, a, b);
            check_sub(&(-c), &(-a), &(-b));
        }
        check(&[], &[], &[]);
        check(&[], &[1], &[1]);
        check(&[1], &[1], &[2]);
        check(&[1, 0, 1], &[1], &[2, 0, 1]);
        check(&[1, 0, -1], &[-1, 0, 1], &[]);
    }

    #[test]
    fn mul() {
        fn check(a: &[i32], b: &[i32], c: &[i32]) {
            let a = Polynomial::new(a.to_vec());
            let b = Polynomial::new(b.to_vec());
            let c = Polynomial::new(c.to_vec());
            assert_eq!(c, &a * &b);
            assert_eq!(c, &b * &a);
        }
        check(&[], &[], &[]);
        check(&[0, 0], &[], &[]);
        check(&[0, 0], &[1], &[]);
        check(&[1, 0], &[1], &[1]);
        check(&[1, 0, 1], &[1], &[1, 0, 1]);
        check(&[1, 1], &[1, 1], &[1, 2, 1]);
        check(&[1, 1], &[1, 0, 1], &[1, 1, 1, 1]);
        check(&[0, 0, 1], &[0, 0, 1], &[0, 0, 0, 0, 1]);
    }

    #[test]
    fn eval() {
        fn check<F: Fn(i32) -> i32>(pol: &[i32], f: F) {
            for n in -10..10 {
                assert_eq!(f(n), Polynomial::new(pol.to_vec()).eval(n));
            }
        }
        check(&[], |_x| 0);
        check(&[1], |_x| 1);
        check(&[1, 1], |x| x + 1);
        check(&[0, 1], |x| x);
        check(&[10, -10, 10], |x| 10 * x * x - 10 * x + 10);
    }

    #[test]
    fn pretty() {
        fn check(slice: &[i32], s: &str) {
            assert_eq!(s.to_string(), Polynomial::new(slice.to_vec()).pretty("x"));
        }
        check(&[0], "0");
        check(&[1], "1");
        check(&[1, 1], "1+x");
        check(&[1, 1, 1], "1+x+x^2");
        check(&[2, 2, 2], "2+2*x+2*x^2");
        check(&[0, 0, 0, 1], "x^3");
        check(&[0, 0, 0, -1], "-x^3");
        check(&[-1, 0, 0, -1], "-1-x^3");
        check(&[-1, 1, 0, -1], "-1+x-x^3");
        check(&[-1, 1, -1, -1], "-1+x-x^2-x^3");
    }
}
<|endoftext|>


<commit_before>#![cfg_attr(feature="nightly", feature(duration))]
#![doc(html_root_url = "http://ogeon.github.io/docs/rust-wiringpi/master/")]

extern crate libc;

use std::marker::PhantomData;

use pin::{Pin, RequiresRoot};

macro_rules! impl_pins {
    ($($name:ident),+) => (
        $(
            #[derive(Clone, Copy)]
            pub struct $name;

            impl Pin for $name {}
        )+
    )
}

macro_rules! require_root {
    ($($name:ident: $pwm:expr),+) => (
        $(
            impl RequiresRoot for $name {
                #[inline]
                fn pwm_pin() -> PwmPin<$name> {
                    PwmPin::new($pwm)
                }
            }
        )+
    )
}

mod bindings;

pub mod time {
    use bindings;
    #[cfg(feature="nightly")]
    use std::time::Duration;

    ///This causes program execution to pause for at least the provided
    ///duration in milliseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer or approximately 49
    ///days.
    #[cfg(feature="nightly")]
    pub fn delay(duration: Duration) {
        use libc;

        let duration = (duration.secs() * 1000) as u32 + duration.extra_nanos() / 1_000_000;
        if duration <= 0 {
            return;
        }

        unsafe {
            bindings::delay(duration as libc::c_uint);
        }
    }

    ///This causes program execution to pause for at least the provided number
    ///of milliseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer or approximately 49
    ///days.
    #[cfg(not(feature="nightly"))]
    pub fn delay(duration: u32) {
        unsafe {
            bindings::delay(duration);
        }
    }

    ///This causes program execution to pause for at least the provided number
    ///of microseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer microseconds or
    ///approximately 71 minutes.
    pub fn delay_microseconds(microseconds: u32) {
        unsafe {
            bindings::delayMicroseconds(microseconds);
        }
    }
}

pub mod thread {
    use bindings;
    use libc;

    ///This attempts to shift your program (or thread in a multi-threaded
    ///program) to a higher priority and enables a real-time scheduling.
    ///
    ///The priority parameter should be from 0 (the default) to 99 (the
    ///maximum). This won’t make your program go any faster, but it will give
    ///it a bigger slice of time when other programs are running. The priority
    ///parameter works relative to others – so you can make one program
    ///priority 1 and another priority 2 and it will have the same effect as
    ///setting one to 10 and the other to 90 (as long as no other programs are
    ///running with elevated priorities)
    ///
    ///The return value is `true` for success and `false` for error. If an
    ///error is returned, the program should then consult the _errno_ global
    ///variable, as per the usual conventions.
    ///
    ///_Note_: Only programs running as root can change their priority. If
    ///called from a non-root program then nothing happens.
    pub fn priority(priority: u8) -> bool {
        unsafe {
            bindings::piHiPri(priority as libc::c_int) >= 0
        }
    }
}

pub mod pin {
    use bindings;
    use libc;
    use self::Value::{Low, High};

    use std::marker::PhantomData;

    impl_pins!(WiringPi, Gpio, Phys, Sys);
    require_root!(WiringPi: 1, Gpio: 18, Phys: 12);

    pub trait Pin {}

    pub trait RequiresRoot: Pin {
        fn pwm_pin() -> PwmPin<Self>;
    }

    #[derive(Clone, Copy)]
    pub enum Value {
        Low = 0,
        High
    }

    #[derive(Clone, Copy)]
    pub enum Pull {
        Off = 0,
        Down,
        Up
    }

    #[derive(Clone, Copy)]
    pub enum PwmMode {
        MarkSpace = 0,
        Balanced
    }

    pub struct InputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> InputPin<P> {
        pub fn new(pin: libc::c_int) -> InputPin<P> {
            unsafe {
                bindings::pinMode(pin, 0);
            }

            InputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &InputPin(number, _) = self;
            number
        }

        pub fn into_output(self) -> OutputPin<P> {
            let InputPin(number, _) = self;
            OutputPin::new(number)
        }

        ///This function returns the value read at the given pin.
        ///
        ///It will be `High` or `Low` (1 or 0) depending on the logic level at the pin.
        pub fn digital_read(&self) -> Value {
            let value = unsafe {
                bindings::digitalRead(self.number())
            };

            if value == 0 {
                Low
            } else {
                High
            }
        }
    }

    impl<P: Pin + RequiresRoot> InputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let InputPin(number, _) = self;
            PwmPin::new(number)
        }

        ///This sets the pull-up or pull-down resistor mode on the given pin.
        ///
        ///Unlike the Arduino, the BCM2835 has both pull-up an down internal
        ///resistors. The parameter pud should be; `Off`, (no pull up/down),
        ///`Down` (pull to ground) or `Up` (pull to 3.3v)
        pub fn pull_up_dn_control(&self, pud: Pull) {
            unsafe {
                bindings::pullUpDnControl(self.number(), pud as libc::c_int);
            }
        }
    }

    pub struct OutputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> OutputPin<P> {
        pub fn new(pin: libc::c_int) -> OutputPin<P> {
            unsafe {
                bindings::pinMode(pin, 1);
            }

            OutputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &OutputPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let OutputPin(number, _) = self;
            InputPin::new(number)
        }

        ///Writes the value `High` or `Low` (1 or 0) to the given pin which must have been previously set as an output.
        pub fn digital_write(&self, value: Value) {
            unsafe {
                bindings::digitalWrite(self.number(), value as libc::c_int);
            }
        }
    }

    impl<P: Pin + RequiresRoot> OutputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let OutputPin(number, _) = self;
            PwmPin::new(number)
        }
    }

    ///To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual.
    pub struct PwmPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin + RequiresRoot> PwmPin<P> {
        pub fn new(pin: libc::c_int) -> PwmPin<P> {
            unsafe {
                bindings::pinMode(pin, 2);
            }

            PwmPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &PwmPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let PwmPin(number, _) = self;
            InputPin::new(number)
        }

        pub fn into_output(self) -> OutputPin<P> {
            let PwmPin(number, _) = self;
            OutputPin::new(number)
        }

        ///Writes the value to the PWM register for the given pin.
        ///
        ///The value must be between 0 and 1024.
        pub fn write(&self, value: u16) {
            unsafe {
                bindings::pwmWrite(self.number(), value as libc::c_int);
            }
        }

        ///The PWM generator can run in 2 modes – "balanced" and "mark:space".
        ///
        ///The mark:space mode is traditional, however the default mode in the
        ///Pi is "balanced". You can switch modes by supplying the parameter:
        ///`Balanced` or `MarkSpace`.
        pub fn set_mode(&self, mode: PwmMode) {
            unsafe {
                bindings::pwmSetMode(mode as libc::c_int);
            }
        }

        ///This sets the range register in the PWM generator. The default is 1024.
        pub fn set_range(&self, value: u16) {
            unsafe {
                bindings::pwmSetRange(value as libc::c_uint);
            }
        }

        ///This sets the divisor for the PWM clock.
        pub fn set_clock(&self, value: u16) {
            unsafe {
                bindings::pwmSetClock(value as libc::c_int);
            }
        }
    }
}

///This initialises the wiringPi system and assumes that the calling program
///is going to be using the **wiringPi** pin numbering scheme.
///
///This is a simplified numbering scheme which provides a mapping from virtual
///pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers.
///See the pins page for a table which maps the **wiringPi** pin number to the
///Broadcom GPIO pin number to the physical location on the edge connector.
///
///This function needs to be called with root privileges.
pub fn setup() -> WiringPi<pin::WiringPi> {
    unsafe { bindings::wiringPiSetup(); }
    WiringPi(PhantomData)
}

///This is identical to `setup()`, however it allows the calling programs to
///use the Broadcom GPIO pin numbers directly with no re-mapping.
///
///This function needs to be called with root privileges.
pub fn setup_gpio() -> WiringPi<pin::Gpio> {
    unsafe { bindings::wiringPiSetupGpio(); }
    WiringPi(PhantomData)
}

///This is identical to `setup()`, however it allows the calling programs to
///use the physical pin numbers _on the P1 connector only_.
///
///This function needs to be called with root privileges.
pub fn setup_phys() -> WiringPi<pin::Phys> {
    unsafe { bindings::wiringPiSetupPhys(); }
    WiringPi(PhantomData)
}

///This initialises the wiringPi system but uses the /sys/class/gpio interface
///rather than accessing the hardware directly.
///
///This can be called as a non-root user provided the GPIO pins have been
///exported before-hand using the gpio program. Pin number in this mode is the
///native Broadcom GPIO numbers.
///
///_Note_: In this mode you can only use the pins which have been exported via
///the /sys/class/gpio interface. You must export these pins before you call
///your program. You can do this in a separate shell-script, or by using the
///system() function from inside your program.
///
///Also note that some functions have no effect when using this mode as
///they’re not currently possible to action unless called with root
///privileges.
pub fn setup_sys() -> WiringPi<pin::Sys> {
    unsafe { bindings::wiringPiSetupSys(); }
    WiringPi(PhantomData)
}

///This returns the board revision of the Raspberry Pi.
///
///It will be either 1 or 2. Some of the BCM_GPIO pins changed number and
///function when moving from board revision 1 to 2, so if you are using
///BCM_GPIO pin numbers, then you need to be aware of the differences.
pub fn board_revision() -> i32 {
    unsafe {
        bindings::piBoardRev()
    }
}

///This returns the BCM_GPIO pin number of the supplied **wiringPi** pin.
///
///It takes the board revision into account.
pub fn to_gpio_number(wpi_number: u16) -> u16 {
    unsafe {
        bindings::wpiPinToGpio(wpi_number as libc::c_int) as u16
    }
}

pub struct WiringPi<Pin>(PhantomData<Pin>);

impl<P: Pin> WiringPi<P> {
    pub fn input_pin(&self, pin: u16) -> pin::InputPin<P> {
        let pin = pin as libc::c_int;
        pin::InputPin::new(pin)
    }

    pub fn output_pin(&self, pin: u16) -> pin::OutputPin<P> {
        let pin = pin as libc::c_int;
        pin::OutputPin::new(pin)
    }

    ///This returns a number representing the number if milliseconds since
    ///your program called one of the setup functions.
    ///
    ///It returns an unsigned 32-bit number which wraps after 49 days.
    pub fn millis(&self) -> u32 {
        unsafe {
            bindings::millis()
        }
    }

    ///This returns a number representing the number if microseconds since
    ///your program called one of the setup functions.
    ///
    ///It returns an unsigned 32-bit number which wraps after 71 minutes.

    pub fn micros(&self) -> u32 {
        unsafe {
            bindings::micros()
        }
    }
}

impl<P: RequiresRoot + Pin> WiringPi<P> {
    pub fn pwm_pin(&self) -> pin::PwmPin<P> {
        RequiresRoot::pwm_pin()
    }
}<commit_msg>Move pin number convertion into pin module and add phys->gpio convertion<commit_after>#![cfg_attr(feature="nightly", feature(duration))]
#![doc(html_root_url = "http://ogeon.github.io/docs/rust-wiringpi/master/")]

extern crate libc;

use std::marker::PhantomData;

use pin::{Pin, RequiresRoot};

macro_rules! impl_pins {
    ($($name:ident),+) => (
        $(
            #[derive(Clone, Copy)]
            pub struct $name;

            impl Pin for $name {}
        )+
    )
}

macro_rules! require_root {
    ($($name:ident: $pwm:expr),+) => (
        $(
            impl RequiresRoot for $name {
                #[inline]
                fn pwm_pin() -> PwmPin<$name> {
                    PwmPin::new($pwm)
                }
            }
        )+
    )
}

mod bindings;

pub mod time {
    use bindings;
    #[cfg(feature="nightly")]
    use std::time::Duration;

    ///This causes program execution to pause for at least the provided
    ///duration in milliseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer or approximately 49
    ///days.
    #[cfg(feature="nightly")]
    pub fn delay(duration: Duration) {
        use libc;

        let duration = (duration.secs() * 1000) as u32 + duration.extra_nanos() / 1_000_000;
        if duration <= 0 {
            return;
        }

        unsafe {
            bindings::delay(duration as libc::c_uint);
        }
    }

    ///This causes program execution to pause for at least the provided number
    ///of milliseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer or approximately 49
    ///days.
    #[cfg(not(feature="nightly"))]
    pub fn delay(duration: u32) {
        unsafe {
            bindings::delay(duration);
        }
    }

    ///This causes program execution to pause for at least the provided number
    ///of microseconds.
    ///
    ///Due to the multi-tasking nature of Linux it could be longer. Note that
    ///the maximum delay is an unsigned 32-bit integer microseconds or
    ///approximately 71 minutes.
    pub fn delay_microseconds(microseconds: u32) {
        unsafe {
            bindings::delayMicroseconds(microseconds);
        }
    }
}

pub mod thread {
    use bindings;
    use libc;

    ///This attempts to shift your program (or thread in a multi-threaded
    ///program) to a higher priority and enables a real-time scheduling.
    ///
    ///The priority parameter should be from 0 (the default) to 99 (the
    ///maximum). This won’t make your program go any faster, but it will give
    ///it a bigger slice of time when other programs are running. The priority
    ///parameter works relative to others – so you can make one program
    ///priority 1 and another priority 2 and it will have the same effect as
    ///setting one to 10 and the other to 90 (as long as no other programs are
    ///running with elevated priorities)
    ///
    ///The return value is `true` for success and `false` for error. If an
    ///error is returned, the program should then consult the _errno_ global
    ///variable, as per the usual conventions.
    ///
    ///_Note_: Only programs running as root can change their priority. If
    ///called from a non-root program then nothing happens.
    pub fn priority(priority: u8) -> bool {
        unsafe {
            bindings::piHiPri(priority as libc::c_int) >= 0
        }
    }
}

pub mod pin {
    use bindings;
    use libc;
    use self::Value::{Low, High};

    use std::marker::PhantomData;

    ///This returns the BCM_GPIO pin number of the supplied **wiringPi** pin.
    ///
    ///It takes the board revision into account.
    pub fn wpi_to_gpio_number(wpi_number: u16) -> u16 {
        unsafe {
            bindings::wpiPinToGpio(wpi_number as libc::c_int) as u16
        }
    }

    ///This returns the BCM_GPIO pin number of the supplied physical pin on
    ///the P1 connector.
    pub fn phys_to_gpio_number(phys_number: u16) -> u16 {
        unsafe {
            bindings::physPinToGpio(phys_number as libc::c_int) as u16
        }
    }

    impl_pins!(WiringPi, Gpio, Phys, Sys);
    require_root!(WiringPi: 1, Gpio: 18, Phys: 12);

    pub trait Pin {}

    pub trait RequiresRoot: Pin {
        fn pwm_pin() -> PwmPin<Self>;
    }

    #[derive(Clone, Copy)]
    pub enum Value {
        Low = 0,
        High
    }

    #[derive(Clone, Copy)]
    pub enum Pull {
        Off = 0,
        Down,
        Up
    }

    #[derive(Clone, Copy)]
    pub enum PwmMode {
        MarkSpace = 0,
        Balanced
    }

    pub struct InputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> InputPin<P> {
        pub fn new(pin: libc::c_int) -> InputPin<P> {
            unsafe {
                bindings::pinMode(pin, 0);
            }

            InputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &InputPin(number, _) = self;
            number
        }

        pub fn into_output(self) -> OutputPin<P> {
            let InputPin(number, _) = self;
            OutputPin::new(number)
        }

        ///This function returns the value read at the given pin.
        ///
        ///It will be `High` or `Low` (1 or 0) depending on the logic level at the pin.
        pub fn digital_read(&self) -> Value {
            let value = unsafe {
                bindings::digitalRead(self.number())
            };

            if value == 0 {
                Low
            } else {
                High
            }
        }
    }

    impl<P: Pin + RequiresRoot> InputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let InputPin(number, _) = self;
            PwmPin::new(number)
        }

        ///This sets the pull-up or pull-down resistor mode on the given pin.
        ///
        ///Unlike the Arduino, the BCM2835 has both pull-up an down internal
        ///resistors. The parameter pud should be; `Off`, (no pull up/down),
        ///`Down` (pull to ground) or `Up` (pull to 3.3v)
        pub fn pull_up_dn_control(&self, pud: Pull) {
            unsafe {
                bindings::pullUpDnControl(self.number(), pud as libc::c_int);
            }
        }
    }

    pub struct OutputPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin> OutputPin<P> {
        pub fn new(pin: libc::c_int) -> OutputPin<P> {
            unsafe {
                bindings::pinMode(pin, 1);
            }

            OutputPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &OutputPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let OutputPin(number, _) = self;
            InputPin::new(number)
        }

        ///Writes the value `High` or `Low` (1 or 0) to the given pin which must have been previously set as an output.
        pub fn digital_write(&self, value: Value) {
            unsafe {
                bindings::digitalWrite(self.number(), value as libc::c_int);
            }
        }
    }

    impl<P: Pin + RequiresRoot> OutputPin<P> {
        pub fn into_pwm(self) -> PwmPin<P> {
            let OutputPin(number, _) = self;
            PwmPin::new(number)
        }
    }

    ///To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual.
    pub struct PwmPin<Pin>(libc::c_int, PhantomData<Pin>);

    impl<P: Pin + RequiresRoot> PwmPin<P> {
        pub fn new(pin: libc::c_int) -> PwmPin<P> {
            unsafe {
                bindings::pinMode(pin, 2);
            }

            PwmPin(pin, PhantomData)
        }

        #[inline]
        pub fn number(&self) -> libc::c_int {
            let &PwmPin(number, _) = self;
            number
        }

        pub fn into_input(self) -> InputPin<P> {
            let PwmPin(number, _) = self;
            InputPin::new(number)
        }

        pub fn into_output(self) -> OutputPin<P> {
            let PwmPin(number, _) = self;
            OutputPin::new(number)
        }

        ///Writes the value to the PWM register for the given pin.
        ///
        ///The value must be between 0 and 1024.
        pub fn write(&self, value: u16) {
            unsafe {
                bindings::pwmWrite(self.number(), value as libc::c_int);
            }
        }

        ///The PWM generator can run in 2 modes – "balanced" and "mark:space".
        ///
        ///The mark:space mode is traditional, however the default mode in the
        ///Pi is "balanced". You can switch modes by supplying the parameter:
        ///`Balanced` or `MarkSpace`.
        pub fn set_mode(&self, mode: PwmMode) {
            unsafe {
                bindings::pwmSetMode(mode as libc::c_int);
            }
        }

        ///This sets the range register in the PWM generator. The default is 1024.
        pub fn set_range(&self, value: u16) {
            unsafe {
                bindings::pwmSetRange(value as libc::c_uint);
            }
        }

        ///This sets the divisor for the PWM clock.
        pub fn set_clock(&self, value: u16) {
            unsafe {
                bindings::pwmSetClock(value as libc::c_int);
            }
        }
    }
}

///This initialises the wiringPi system and assumes that the calling program
///is going to be using the **wiringPi** pin numbering scheme.
///
///This is a simplified numbering scheme which provides a mapping from virtual
///pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers.
///See the pins page for a table which maps the **wiringPi** pin number to the
///Broadcom GPIO pin number to the physical location on the edge connector.
///
///This function needs to be called with root privileges.
pub fn setup() -> WiringPi<pin::WiringPi> {
    unsafe { bindings::wiringPiSetup(); }
    WiringPi(PhantomData)
}

///This is identical to `setup()`, however it allows the calling programs to
///use the Broadcom GPIO pin numbers directly with no re-mapping.
///
///This function needs to be called with root privileges.
pub fn setup_gpio() -> WiringPi<pin::Gpio> {
    unsafe { bindings::wiringPiSetupGpio(); }
    WiringPi(PhantomData)
}

///This is identical to `setup()`, however it allows the calling programs to
///use the physical pin numbers _on the P1 connector only_.
///
///This function needs to be called with root privileges.
pub fn setup_phys() -> WiringPi<pin::Phys> {
    unsafe { bindings::wiringPiSetupPhys(); }
    WiringPi(PhantomData)
}

///This initialises the wiringPi system but uses the /sys/class/gpio interface
///rather than accessing the hardware directly.
///
///This can be called as a non-root user provided the GPIO pins have been
///exported before-hand using the gpio program. Pin number in this mode is the
///native Broadcom GPIO numbers.
///
///_Note_: In this mode you can only use the pins which have been exported via
///the /sys/class/gpio interface. You must export these pins before you call
///your program. You can do this in a separate shell-script, or by using the
///system() function from inside your program.
///
///Also note that some functions have no effect when using this mode as
///they’re not currently possible to action unless called with root
///privileges.
pub fn setup_sys() -> WiringPi<pin::Sys> {
    unsafe { bindings::wiringPiSetupSys(); }
    WiringPi(PhantomData)
}

///This returns the board revision of the Raspberry Pi.
///
///It will be either 1 or 2. Some of the BCM_GPIO pins changed number and
///function when moving from board revision 1 to 2, so if you are using
///BCM_GPIO pin numbers, then you need to be aware of the differences.
pub fn board_revision() -> i32 {
    unsafe {
        bindings::piBoardRev()
    }
}

pub struct WiringPi<Pin>(PhantomData<Pin>);

impl<P: Pin> WiringPi<P> {
    pub fn input_pin(&self, pin: u16) -> pin::InputPin<P> {
        let pin = pin as libc::c_int;
        pin::InputPin::new(pin)
    }

    pub fn output_pin(&self, pin: u16) -> pin::OutputPin<P> {
        let pin = pin as libc::c_int;
        pin::OutputPin::new(pin)
    }

    ///This returns a number representing the number if milliseconds since
    ///your program called one of the setup functions.
    ///
    ///It returns an unsigned 32-bit number which wraps after 49 days.
    pub fn millis(&self) -> u32 {
        unsafe {
            bindings::millis()
        }
    }

    ///This returns a number representing the number if microseconds since
    ///your program called one of the setup functions.
    ///
    ///It returns an unsigned 32-bit number which wraps after 71 minutes.

    pub fn micros(&self) -> u32 {
        unsafe {
            bindings::micros()
        }
    }
}

impl<P: RequiresRoot + Pin> WiringPi<P> {
    pub fn pwm_pin(&self) -> pin::PwmPin<P> {
        RequiresRoot::pwm_pin()
    }
}<|endoftext|>


<commit_before>#![feature(struct_variant)]

extern crate serialize;

use std::io::MemWriter;
use std::io::MemReader;
use std::io::IoError;
use serialize::Encodable;
use serialize::Decodable;

pub use writer::EncoderWriter;
pub use reader::DecoderReader;

mod writer;
mod reader;

pub fn encode<T: Encodable<EncoderWriter<MemWriter>, IoError>>(t: &T) ->
Result<Vec<u8>, IoError> {
    match encode_into(t, MemWriter::new()) {
        Ok(w) => Ok(w.unwrap()),
        Err((_, e)) => Err(e)
    }
}

pub fn decode<T: Decodable<DecoderReader<MemReader>, IoError>>(b: Vec<u8>) ->
Result<T, (IoError, Vec<u8>)> {
    match decode_from(MemReader::new(b)) {
        Ok((t, _)) => Ok(t),
        Err((e, r)) => Err((e, r.unwrap()))
    }
}

pub fn encode_into<W: Writer, T: Encodable<EncoderWriter<W>, IoError>>
(t: &T, w: W)
-> Result<W, (W, IoError)> {
    let mut writer = writer::EncoderWriter::new(w);
    match t.encode(&mut writer) {
        Ok(()) => Ok(writer.unwrap()),
        Err(e) => Err((writer.unwrap(), e))
    }
}

pub fn decode_from<R: Reader, T: Decodable<DecoderReader<R>, IoError>>(r: R) ->
Result<(T, R), (IoError, R)> {
    let mut reader = reader::DecoderReader::new(r);
    let x: Result<T, IoError> = Decodable::decode(&mut reader);
    let mem = reader.unwrap();

    match x {
        Ok(t) => Ok((t, mem)),
        Err(e) => Err((e, mem))
    }
}

#[cfg(test)]
mod test;
<commit_msg>add todo for when higher order lifetimes land<commit_after>#![feature(struct_variant)]

extern crate serialize;

use std::io::MemWriter;
use std::io::MemReader;
use std::io::IoError;
use serialize::Encodable;
use serialize::Decodable;

pub use writer::EncoderWriter;
pub use reader::DecoderReader;

mod writer;
mod reader;

pub fn encode<T: Encodable<EncoderWriter<MemWriter>, IoError>>(t: &T) ->
Result<Vec<u8>, IoError> {
    match encode_into(t, MemWriter::new()) {
        Ok(w) => Ok(w.unwrap()),
        Err((_, e)) => Err(e)
    }
}

pub fn decode<T: Decodable<DecoderReader<MemReader>, IoError>>(b: Vec<u8>) ->
Result<T, (IoError, Vec<u8>)> {
    match decode_from(MemReader::new(b)) {
        Ok((t, _)) => Ok(t),
        Err((e, r)) => Err((e, r.unwrap()))
    }
}

pub fn encode_into<W: Writer, T: Encodable<EncoderWriter<W>, IoError>>
(t: &T, w: W)
-> Result<W, (W, IoError)> {
    let mut writer = writer::EncoderWriter::new(w);
    match t.encode(&mut writer) {
        Ok(()) => Ok(writer.unwrap()),
        Err(e) => Err((writer.unwrap(), e))
    }
}

// TODO: When higher order lifetimes land, make this so that the
// reader is passed in by &mut instead of by ownership.
pub fn decode_from<R: Reader, T: Decodable<DecoderReader<R>, IoError>>(r: R) ->
Result<(T, R), (IoError, R)> {
    let mut reader = reader::DecoderReader::new(r);
    let x: Result<T, IoError> = Decodable::decode(&mut reader);
    let mem = reader.unwrap();

    match x {
        Ok(t) => Ok((t, mem)),
        Err(e) => Err((e, mem))
    }
}

#[cfg(test)]
mod test;
<|endoftext|>


<commit_before>//! Multi-dimensional arrays with per-dimension specifiable lower bounds
#![doc(html_root_url="https://sfackler.github.io/rust-postgres-array/doc")]

#[macro_use(to_sql_checked)]
extern crate postgres;
extern crate byteorder;

use std::mem;

#[doc(inline)]
pub use base::ArrayBase;

pub mod base;
mod impls;

/// Information about a dimension of an array
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct DimensionInfo {
    /// The size of the dimension
    pub len: usize,
    /// The index of the first element of the dimension
    pub lower_bound: isize,
}

/// Specifies methods that can be performed on multi-dimensional arrays
pub trait Array<T> {
    /// Returns information about the dimensions of this array
    fn dimension_info<'a>(&'a self) -> &'a [DimensionInfo];

    /// Slices into this array, returning an immutable view of a subarray.
    ///
    /// ## Failure
    ///
    /// Fails if the array is one-dimensional or the index is out of bounds.
    fn slice<'a>(&'a self, idx: isize) -> ArraySlice<'a, T>;

    /// Retrieves an immutable reference to a value in this array.
    ///
    ///
    /// ## Failure
    ///
    /// Fails if the array is multi-dimensional or the index is out of bounds.
    fn get<'a>(&'a self, idx: isize) -> &'a T;
}

/// Specifies methods that can be performed on mutable multi-dimensional arrays
pub trait MutableArray<T> : Array<T> {
    /// Slices into this array, returning a mutable view of a subarray.
    ///
    /// ## Failure
    ///
    /// Fails if the array is one-dimensional or the index is out of bounds.
    fn slice_mut<'a>(&'a mut self, idx: isize) -> MutArraySlice<'a, T>;

    /// Retrieves a mutable reference to a value in this array.
    ///
    ///
    /// ## Failure
    ///
    /// Fails if the array is multi-dimensional or the index is out of bounds.
    fn get_mut<'a>(&'a mut self, idx: isize) -> &'a mut T;
}

#[doc(hidden)]
trait InternalArray<T>: Array<T> {
    fn shift_idx(&self, idx: isize) -> usize {
        let shifted_idx = idx - self.dimension_info()[0].lower_bound;
        assert!(shifted_idx >= 0 &&
                    shifted_idx < self.dimension_info()[0].len as isize,
                "Out of bounds array access");
        shifted_idx as usize
    }

    fn raw_get<'a>(&'a self, idx: usize, size: usize) -> &'a T;
}

#[doc(hidden)]
trait InternalMutableArray<T>: MutableArray<T> {
    fn raw_get_mut<'a>(&'a mut self, idx: usize, size: usize) -> &'a mut T;
}

enum ArrayParent<'parent, T:'parent> {
    Slice(&'parent ArraySlice<'parent, T>),
    MutSlice(&'parent MutArraySlice<'parent, T>),
    Base(&'parent ArrayBase<T>),
}

/// An immutable slice of a multi-dimensional array
pub struct ArraySlice<'parent, T:'parent> {
    parent: ArrayParent<'parent, T>,
    idx: usize,
}

impl<'parent, T> Array<T> for ArraySlice<'parent, T> {
    fn dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        let info = match self.parent {
            ArrayParent::Slice(p) => p.dimension_info(),
            ArrayParent::MutSlice(p) => p.dimension_info(),
            ArrayParent::Base(p) => p.dimension_info()
        };
        &info[1..]
    }

    fn slice<'a>(&'a self, idx: isize) -> ArraySlice<'a, T> {
        assert!(self.dimension_info().len() != 1,
                "Attempted to slice a one-dimensional array");
        unsafe {
            ArraySlice {
                parent: ArrayParent::Slice(mem::transmute(self)),
                idx: self.shift_idx(idx),
            }
        }
    }

    fn get<'a>(&'a self, idx: isize) -> &'a T {
        assert!(self.dimension_info().len() == 1,
                "Attempted to get from a multi-dimensional array");
        self.raw_get(self.shift_idx(idx), 1)
    }
}

impl<'parent, T> InternalArray<T> for ArraySlice<'parent, T> {
    fn raw_get<'a>(&'a self, idx: usize, size: usize) -> &'a T {
        let size = size * self.dimension_info()[0].len;
        let idx = size * self.idx + idx;
        match self.parent {
            ArrayParent::Slice(p) => p.raw_get(idx, size),
            ArrayParent::MutSlice(p) => p.raw_get(idx, size),
            ArrayParent::Base(p) => p.raw_get(idx, size)
        }
    }
}

enum MutArrayParent<'parent, T:'parent> {
    Slice(&'parent mut MutArraySlice<'parent, T>),
    Base(&'parent mut ArrayBase<T>),
}

/// A mutable slice of a multi-dimensional array
pub struct MutArraySlice<'parent, T:'parent> {
    parent: MutArrayParent<'parent, T>,
    idx: usize,
}

impl<'parent, T> Array<T> for MutArraySlice<'parent, T> {
    fn dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        let info : &'a [DimensionInfo] = unsafe {
            match self.parent {
                MutArrayParent::Slice(ref p) => mem::transmute(p.dimension_info()),
                MutArrayParent::Base(ref p) => mem::transmute(p.dimension_info()),
            }
        };
        &info[1..]
    }

    fn slice<'a>(&'a self, idx: isize) -> ArraySlice<'a, T> {
        assert!(self.dimension_info().len() != 1,
                "Attempted to slice a one-dimensional array");
        unsafe {
            ArraySlice {
                parent: ArrayParent::MutSlice(mem::transmute(self)),
                idx: self.shift_idx(idx),
            }
        }
    }

    fn get<'a>(&'a self, idx: isize) -> &'a T {
        assert!(self.dimension_info().len() == 1,
                "Attempted to get from a multi-dimensional array");
        self.raw_get(self.shift_idx(idx), 1)
    }
}

impl<'parent, T> MutableArray<T> for MutArraySlice<'parent, T> {
    fn slice_mut<'a>(&'a mut self, idx: isize) -> MutArraySlice<'a, T> {
        assert!(self.dimension_info().len() != 1,
                "Attempted to slice_mut a one-dimensional array");
        unsafe {
            MutArraySlice {
                idx: self.shift_idx(idx),
                parent: MutArrayParent::Slice(mem::transmute(self)),
            }
        }
    }

    fn get_mut<'a>(&'a mut self, idx: isize) -> &'a mut T {
        assert!(self.dimension_info().len() == 1,
                "Attempted to get_mut from a multi-dimensional array");
        let idx = self.shift_idx(idx);
        self.raw_get_mut(idx, 1)
    }
}

impl<'parent, T> InternalArray<T> for MutArraySlice<'parent, T> {
    fn raw_get<'a>(&'a self, idx: usize, size: usize) -> &'a T {
        let size = size * self.dimension_info()[0].len;
        let idx = size * self.idx + idx;
        unsafe {
            match self.parent {
                MutArrayParent::Slice(ref p) => mem::transmute(p.raw_get(idx, size)),
                MutArrayParent::Base(ref p) => mem::transmute(p.raw_get(idx, size))
            }
        }
    }
}

impl<'parent, T> InternalMutableArray<T> for MutArraySlice<'parent, T> {
    fn raw_get_mut<'a>(&'a mut self, idx: usize, size: usize) -> &'a mut T {
        let size = size * self.dimension_info()[0].len;
        let idx = size * self.idx + idx;
        unsafe {
            match self.parent {
                MutArrayParent::Slice(ref mut p) => mem::transmute(p.raw_get_mut(idx, size)),
                MutArrayParent::Base(ref mut p) => mem::transmute(p.raw_get_mut(idx, size))
            }
        }
    }
}

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

    #[test]
    fn test_from_vec() {
        let a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        assert!(&[DimensionInfo { len: 3, lower_bound: -1 }][..] ==
                a.dimension_info());
        assert_eq!(&0, a.get(-1));
        assert_eq!(&1, a.get(0));
        assert_eq!(&2, a.get(1));
    }

    #[test]
    #[should_panic]
    fn test_get_2d_fail() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        a.wrap(1);
        a.get(1);
    }

    #[test]
    #[should_panic]
    fn test_2d_slice_range_fail_low() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        a.wrap(1);
        a.slice(0);
    }

    #[test]
    #[should_panic]
    fn test_2d_slice_range_fail_high() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        a.wrap(1);
        a.slice(2);
    }

    #[test]
    fn test_2d_slice_get() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        a.wrap(1);
        let s = a.slice(1);
        assert_eq!(&0, s.get(-1));
        assert_eq!(&1, s.get(0));
        assert_eq!(&2, s.get(1));
    }

    #[test]
    #[should_panic]
    fn test_push_move_wrong_lower_bound() {
        let mut a = ArrayBase::from_vec(vec!(1i32), -1);
        a.push_move(ArrayBase::from_vec(vec!(2), 0));
    }

    #[test]
    #[should_panic]
    fn test_push_move_wrong_dims() {
        let mut a = ArrayBase::from_vec(vec!(1i32), -1);
        a.wrap(1);
        a.push_move(ArrayBase::from_vec(vec!(1, 2), -1));
    }

    #[test]
    #[should_panic]
    fn test_push_move_wrong_dim_count() {
        let mut a = ArrayBase::from_vec(vec!(1i32), -1);
        a.wrap(1);
        let mut b = ArrayBase::from_vec(vec!(2), -1);
        b.wrap(1);
        a.push_move(b);
    }

    #[test]
    fn test_push_move_ok() {
        let mut a = ArrayBase::from_vec(vec!(1i32, 2), 0);
        a.wrap(0);
        a.push_move(ArrayBase::from_vec(vec!(3, 4), 0));
        let s = a.slice(0);
        assert_eq!(&1, s.get(0));
        assert_eq!(&2, s.get(1));
        let s = a.slice(1);
        assert_eq!(&3, s.get(0));
        assert_eq!(&4, s.get(1));
    }

    #[test]
    fn test_3d() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1), 0);
        a.wrap(0);
        a.push_move(ArrayBase::from_vec(vec!(2, 3), 0));
        a.wrap(0);
        let mut b = ArrayBase::from_vec(vec!(4, 5), 0);
        b.wrap(0);
        b.push_move(ArrayBase::from_vec(vec!(6, 7), 0));
        a.push_move(b);
        let s1 = a.slice(0);
        let s2 = s1.slice(0);
        assert_eq!(&0, s2.get(0));
        assert_eq!(&1, s2.get(1));
        let s2 = s1.slice(1);
        assert_eq!(&2, s2.get(0));
        assert_eq!(&3, s2.get(1));
        let s1 = a.slice(1);
        let s2 = s1.slice(0);
        assert_eq!(&4, s2.get(0));
        assert_eq!(&5, s2.get(1));
        let s2 = s1.slice(1);
        assert_eq!(&6, s2.get(0));
        assert_eq!(&7, s2.get(1));
    }

    #[test]
    fn test_mut() {
        let mut a = ArrayBase::from_vec(vec!(1i32, 2), 0);
        a.wrap(0);
        {
            let mut s = a.slice_mut(0);
            *s.get_mut(0) = 3;
        }
        let s = a.slice(0);
        assert_eq!(&3, s.get(0));
    }

    #[test]
    #[should_panic]
    fn test_base_overslice() {
        let a = ArrayBase::from_vec(vec!(1i32), 0);
        a.slice(0);
    }

    #[test]
    #[should_panic]
    fn test_slice_overslice() {
        let mut a = ArrayBase::from_vec(vec!(1i32), 0);
        a.wrap(0);
        let s = a.slice(0);
        s.slice(0);
    }
}
<commit_msg>Remove many transmute calls<commit_after>//! Multi-dimensional arrays with per-dimension specifiable lower bounds
#![doc(html_root_url="https://sfackler.github.io/rust-postgres-array/doc")]

#[macro_use(to_sql_checked)]
extern crate postgres;
extern crate byteorder;

use std::mem;

#[doc(inline)]
pub use base::ArrayBase;

pub mod base;
mod impls;

/// Information about a dimension of an array
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct DimensionInfo {
    /// The size of the dimension
    pub len: usize,
    /// The index of the first element of the dimension
    pub lower_bound: isize,
}

/// Specifies methods that can be performed on multi-dimensional arrays
pub trait Array<T> {
    /// Returns information about the dimensions of this array
    fn dimension_info<'a>(&'a self) -> &'a [DimensionInfo];

    /// Slices into this array, returning an immutable view of a subarray.
    ///
    /// ## Failure
    ///
    /// Fails if the array is one-dimensional or the index is out of bounds.
    fn slice<'a>(&'a self, idx: isize) -> ArraySlice<'a, T>;

    /// Retrieves an immutable reference to a value in this array.
    ///
    ///
    /// ## Failure
    ///
    /// Fails if the array is multi-dimensional or the index is out of bounds.
    fn get<'a>(&'a self, idx: isize) -> &'a T;
}

/// Specifies methods that can be performed on mutable multi-dimensional arrays
pub trait MutableArray<T> : Array<T> {
    /// Slices into this array, returning a mutable view of a subarray.
    ///
    /// ## Failure
    ///
    /// Fails if the array is one-dimensional or the index is out of bounds.
    fn slice_mut<'a>(&'a mut self, idx: isize) -> MutArraySlice<'a, T>;

    /// Retrieves a mutable reference to a value in this array.
    ///
    ///
    /// ## Failure
    ///
    /// Fails if the array is multi-dimensional or the index is out of bounds.
    fn get_mut<'a>(&'a mut self, idx: isize) -> &'a mut T;
}

#[doc(hidden)]
trait InternalArray<T>: Array<T> {
    fn shift_idx(&self, idx: isize) -> usize {
        let shifted_idx = idx - self.dimension_info()[0].lower_bound;
        assert!(shifted_idx >= 0 &&
                    shifted_idx < self.dimension_info()[0].len as isize,
                "Out of bounds array access");
        shifted_idx as usize
    }

    fn raw_get<'a>(&'a self, idx: usize, size: usize) -> &'a T;
}

#[doc(hidden)]
trait InternalMutableArray<T>: MutableArray<T> {
    fn raw_get_mut<'a>(&'a mut self, idx: usize, size: usize) -> &'a mut T;
}

enum ArrayParent<'parent, T:'parent> {
    Slice(&'parent ArraySlice<'parent, T>),
    MutSlice(&'parent MutArraySlice<'parent, T>),
    Base(&'parent ArrayBase<T>),
}

/// An immutable slice of a multi-dimensional array
pub struct ArraySlice<'parent, T:'parent> {
    parent: ArrayParent<'parent, T>,
    idx: usize,
}

impl<'parent, T> Array<T> for ArraySlice<'parent, T> {
    fn dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        let info = match self.parent {
            ArrayParent::Slice(p) => p.dimension_info(),
            ArrayParent::MutSlice(p) => p.dimension_info(),
            ArrayParent::Base(p) => p.dimension_info()
        };
        &info[1..]
    }

    fn slice<'a>(&'a self, idx: isize) -> ArraySlice<'a, T> {
        assert!(self.dimension_info().len() != 1,
                "Attempted to slice a one-dimensional array");
        unsafe {
            ArraySlice {
                parent: ArrayParent::Slice(mem::transmute(self)),
                idx: self.shift_idx(idx),
            }
        }
    }

    fn get<'a>(&'a self, idx: isize) -> &'a T {
        assert!(self.dimension_info().len() == 1,
                "Attempted to get from a multi-dimensional array");
        self.raw_get(self.shift_idx(idx), 1)
    }
}

impl<'parent, T> InternalArray<T> for ArraySlice<'parent, T> {
    fn raw_get<'a>(&'a self, idx: usize, size: usize) -> &'a T {
        let size = size * self.dimension_info()[0].len;
        let idx = size * self.idx + idx;
        match self.parent {
            ArrayParent::Slice(p) => p.raw_get(idx, size),
            ArrayParent::MutSlice(p) => p.raw_get(idx, size),
            ArrayParent::Base(p) => p.raw_get(idx, size)
        }
    }
}

enum MutArrayParent<'parent, T:'parent> {
    Slice(&'parent mut MutArraySlice<'parent, T>),
    Base(&'parent mut ArrayBase<T>),
}

/// A mutable slice of a multi-dimensional array
pub struct MutArraySlice<'parent, T:'parent> {
    parent: MutArrayParent<'parent, T>,
    idx: usize,
}

impl<'parent, T> Array<T> for MutArraySlice<'parent, T> {
    fn dimension_info<'a>(&'a self) -> &'a [DimensionInfo] {
        let info : &'a [DimensionInfo] = match self.parent {
            MutArrayParent::Slice(ref p) => p.dimension_info(),
            MutArrayParent::Base(ref p) => p.dimension_info(),
        };
        &info[1..]
    }

    fn slice<'a>(&'a self, idx: isize) -> ArraySlice<'a, T> {
        assert!(self.dimension_info().len() != 1,
                "Attempted to slice a one-dimensional array");
        unsafe {
            ArraySlice {
                parent: ArrayParent::MutSlice(mem::transmute(self)),
                idx: self.shift_idx(idx),
            }
        }
    }

    fn get<'a>(&'a self, idx: isize) -> &'a T {
        assert!(self.dimension_info().len() == 1,
                "Attempted to get from a multi-dimensional array");
        self.raw_get(self.shift_idx(idx), 1)
    }
}

impl<'parent, T> MutableArray<T> for MutArraySlice<'parent, T> {
    fn slice_mut<'a>(&'a mut self, idx: isize) -> MutArraySlice<'a, T> {
        assert!(self.dimension_info().len() != 1,
                "Attempted to slice_mut a one-dimensional array");
        unsafe {
            MutArraySlice {
                idx: self.shift_idx(idx),
                parent: MutArrayParent::Slice(mem::transmute(self)),
            }
        }
    }

    fn get_mut<'a>(&'a mut self, idx: isize) -> &'a mut T {
        assert!(self.dimension_info().len() == 1,
                "Attempted to get_mut from a multi-dimensional array");
        let idx = self.shift_idx(idx);
        self.raw_get_mut(idx, 1)
    }
}

impl<'parent, T> InternalArray<T> for MutArraySlice<'parent, T> {
    fn raw_get<'a>(&'a self, idx: usize, size: usize) -> &'a T {
        let size = size * self.dimension_info()[0].len;
        let idx = size * self.idx + idx;
        match self.parent {
            MutArrayParent::Slice(ref p) => p.raw_get(idx, size),
            MutArrayParent::Base(ref p) => p.raw_get(idx, size)
        }
    }
}

impl<'parent, T> InternalMutableArray<T> for MutArraySlice<'parent, T> {
    fn raw_get_mut<'a>(&'a mut self, idx: usize, size: usize) -> &'a mut T {
        let size = size * self.dimension_info()[0].len;
        let idx = size * self.idx + idx;
        match self.parent {
            MutArrayParent::Slice(ref mut p) => p.raw_get_mut(idx, size),
            MutArrayParent::Base(ref mut p) => p.raw_get_mut(idx, size)
        }
    }
}

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

    #[test]
    fn test_from_vec() {
        let a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        assert!(&[DimensionInfo { len: 3, lower_bound: -1 }][..] ==
                a.dimension_info());
        assert_eq!(&0, a.get(-1));
        assert_eq!(&1, a.get(0));
        assert_eq!(&2, a.get(1));
    }

    #[test]
    #[should_panic]
    fn test_get_2d_fail() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        a.wrap(1);
        a.get(1);
    }

    #[test]
    #[should_panic]
    fn test_2d_slice_range_fail_low() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        a.wrap(1);
        a.slice(0);
    }

    #[test]
    #[should_panic]
    fn test_2d_slice_range_fail_high() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        a.wrap(1);
        a.slice(2);
    }

    #[test]
    fn test_2d_slice_get() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1, 2), -1);
        a.wrap(1);
        let s = a.slice(1);
        assert_eq!(&0, s.get(-1));
        assert_eq!(&1, s.get(0));
        assert_eq!(&2, s.get(1));
    }

    #[test]
    #[should_panic]
    fn test_push_move_wrong_lower_bound() {
        let mut a = ArrayBase::from_vec(vec!(1i32), -1);
        a.push_move(ArrayBase::from_vec(vec!(2), 0));
    }

    #[test]
    #[should_panic]
    fn test_push_move_wrong_dims() {
        let mut a = ArrayBase::from_vec(vec!(1i32), -1);
        a.wrap(1);
        a.push_move(ArrayBase::from_vec(vec!(1, 2), -1));
    }

    #[test]
    #[should_panic]
    fn test_push_move_wrong_dim_count() {
        let mut a = ArrayBase::from_vec(vec!(1i32), -1);
        a.wrap(1);
        let mut b = ArrayBase::from_vec(vec!(2), -1);
        b.wrap(1);
        a.push_move(b);
    }

    #[test]
    fn test_push_move_ok() {
        let mut a = ArrayBase::from_vec(vec!(1i32, 2), 0);
        a.wrap(0);
        a.push_move(ArrayBase::from_vec(vec!(3, 4), 0));
        let s = a.slice(0);
        assert_eq!(&1, s.get(0));
        assert_eq!(&2, s.get(1));
        let s = a.slice(1);
        assert_eq!(&3, s.get(0));
        assert_eq!(&4, s.get(1));
    }

    #[test]
    fn test_3d() {
        let mut a = ArrayBase::from_vec(vec!(0i32, 1), 0);
        a.wrap(0);
        a.push_move(ArrayBase::from_vec(vec!(2, 3), 0));
        a.wrap(0);
        let mut b = ArrayBase::from_vec(vec!(4, 5), 0);
        b.wrap(0);
        b.push_move(ArrayBase::from_vec(vec!(6, 7), 0));
        a.push_move(b);
        let s1 = a.slice(0);
        let s2 = s1.slice(0);
        assert_eq!(&0, s2.get(0));
        assert_eq!(&1, s2.get(1));
        let s2 = s1.slice(1);
        assert_eq!(&2, s2.get(0));
        assert_eq!(&3, s2.get(1));
        let s1 = a.slice(1);
        let s2 = s1.slice(0);
        assert_eq!(&4, s2.get(0));
        assert_eq!(&5, s2.get(1));
        let s2 = s1.slice(1);
        assert_eq!(&6, s2.get(0));
        assert_eq!(&7, s2.get(1));
    }

    #[test]
    fn test_mut() {
        let mut a = ArrayBase::from_vec(vec!(1i32, 2), 0);
        a.wrap(0);
        {
            let mut s = a.slice_mut(0);
            *s.get_mut(0) = 3;
        }
        let s = a.slice(0);
        assert_eq!(&3, s.get(0));
    }

    #[test]
    #[should_panic]
    fn test_base_overslice() {
        let a = ArrayBase::from_vec(vec!(1i32), 0);
        a.slice(0);
    }

    #[test]
    #[should_panic]
    fn test_slice_overslice() {
        let mut a = ArrayBase::from_vec(vec!(1i32), 0);
        a.wrap(0);
        let s = a.slice(0);
        s.slice(0);
    }
}
<|endoftext|>