<commit_before>
use error::MpdResult;
use client::MpdClient;
use songs::MpdSong;
use playlists::MpdPlaylist;

pub struct MpdQueue;

pub trait MpdQueuePos {
    fn to_pos(self) -> String;
}

impl MpdQueuePos for uint {
    fn to_pos(self) -> String { self.to_string() }
}

impl MpdQueuePos for (uint, uint) {
    fn to_pos(self) -> String { format!("{}:{}", self.0, self.1) }
}

impl MpdQueue {
    pub fn clear<S: Stream>(client: &mut MpdClient<S>) -> MpdResult<()> {
        client.exec("clear").and_then(|_| client.ok())
    }

    pub fn push<S: Stream>(client: &mut MpdClient<S>, file: &str) -> MpdResult<()> {
        client.exec_arg("add", file).and_then(|_| client.ok())
    }

    pub fn insert<S: Stream>(client: &mut MpdClient<S>, index: uint, file: &str) -> MpdResult<uint> {
        let result = client.exec_arg2("addid", file, uint)
            .and_then(|_| client.iter().next().unwrap_or(Err(FromError::from_error(standard_error(IoErrorKind::InvalidInput)))))
            .and_then(|Ok(MpdPair(ref name, ref value))| if name[] == "Id" { Ok(value.parse()) } else {
                Err(FromError::from_error(standard_error(IoErrorKind::InvalidInput))) });
        try!(client.ok());
        result
    }

    pub fn swap<S: Stream>(client: &mut MpdClient<S>, index1: uint, index2: uint) -> MpdResult<uint> {
        client.exec_arg2("swap", index1, index2).and_then(|_| client.ok())
    }

    pub fn shift<S: Stream, I: MpdQueuePos>(client: &mut MpdClient<S>, index: I, target: uint) -> MpdResult<()> {
        client.exec_arg2("move", index.to_pos(), target).and_then(|_| client.ok())
    }

    pub fn get<S: Stream>(client: &mut MpdClient<S>, index: uint) -> MpdResult<MpdSong> {
        client.exec_arg("playlistinfo", index).and_then(|_| client.iter().collect())
    }

    pub fn slice<S: Stream>(client: &mut MpdClient<S>, slice: (uint, uint)) -> MpdResult<Vec<MpdSong>> {
        client.exec_arg("playlistinfo", format!("{}:{}", slice.0, slice.1)).and_then(|_| client.iter().collect())
    }

    pub fn remove<S: Stream, I: MpdQueuePos>(client: &mut MpdClient<S>, index: I) -> MpdResult<()> {
        client.exec_arg("delete", index.to_pos()).and_then(|_| client.ok())
    }

    pub fn removeid<S: Stream>(client: &mut MpdClient<S>, id: uint) -> MpdResult<()> {
        client.exec_arg("deleteid", id).and_then(|_| client.ok())
    }

    pub fn shiftid<S: Stream>(client: &mut MpdClient<S>, id: uint, target: uint) -> MpdResult<()> {
        client.exec_arg2("moveid", id, target).and_then(|_| client.ok())
    }

    pub fn getid<S: Stream>(client: &mut MpdClient<S>, id: uint) -> MpdResult<MpdSong> {
        client.exec_arg("playlistid", id).and_then(|_| client.iter().collect())
    }

    pub fn songs<S: Stream>(client: &mut MpdClient<S>) -> MpdResult<Vec<MpdSong>> {
        client.exec("playlistinfo").and_then(|_| client.iter().collect())
    }

    pub fn shuffle_slice<S: Stream>(client: &mut MpdClient<S>, slice: (uint, uint)) -> MpdResult<()> {
        client.exec_arg("shuffle", format!("{}:{}", slice.0, slice.1)).and_then(|_| client.ok())
    }

    pub fn shuffle<S: Stream>(client: &mut MpdClient<S>) -> MpdResult<()> {
        client.exec("shuffle").and_then(|_| client.ok())
    }

    pub fn load<S: Stream>(client: &mut MpdClient<S>, name: &str) -> MpdResult<()> {
        client.exec_arg("load", name).and_then(|_| client.ok())
    }

    pub fn load_slice<S: Stream>(client: &mut MpdClient<S>, name: &str, slice: (uint, uint)) -> MpdResult<()> {
        client.exec_arg2("load", name, format!("{}:{}", slice.0, slice.1)).and_then(|_| client.ok())
    }

    pub fn save<S: Stream>(client: &mut MpdClient<S>, name: &str) -> MpdResult<()> {
        client.exec_arg("save", name).and_then(|_| client.ok())
    }
}
<commit_msg>range and priority control<commit_after>
use error::MpdResult;
use client::MpdClient;
use songs::MpdSong;
use playlists::MpdPlaylist;

pub struct MpdQueue;

pub trait MpdQueuePos {
    fn to_pos(self) -> String;
}

impl MpdQueuePos for uint {
    fn to_pos(self) -> String { self.to_string() }
}

impl MpdQueuePos for (uint, uint) {
    fn to_pos(self) -> String { format!("{}:{}", self.0, self.1) }
}

impl MpdQueue {
    pub fn clear<S: Stream>(client: &mut MpdClient<S>) -> MpdResult<()> {
        client.exec("clear").and_then(|_| client.ok())
    }

    pub fn push<S: Stream>(client: &mut MpdClient<S>, file: &str) -> MpdResult<()> {
        client.exec_arg("add", file).and_then(|_| client.ok())
    }

    pub fn insert<S: Stream>(client: &mut MpdClient<S>, index: uint, file: &str) -> MpdResult<uint> {
        let result = client.exec_arg2("addid", file, uint)
            .and_then(|_| client.iter().next().unwrap_or(Err(FromError::from_error(standard_error(IoErrorKind::InvalidInput)))))
            .and_then(|Ok(MpdPair(ref name, ref value))| if name[] == "Id" { Ok(value.parse()) } else {
                Err(FromError::from_error(standard_error(IoErrorKind::InvalidInput))) });
        try!(client.ok());
        result
    }

    pub fn swap<S: Stream>(client: &mut MpdClient<S>, index1: uint, index2: uint) -> MpdResult<uint> {
        client.exec_arg2("swap", index1, index2).and_then(|_| client.ok())
    }

    pub fn shift<S: Stream, I: MpdQueuePos>(client: &mut MpdClient<S>, index: I, target: uint) -> MpdResult<()> {
        client.exec_arg2("move", index.to_pos(), target).and_then(|_| client.ok())
    }

    pub fn priority<S: Stream, I: MpdQueuePos>(client: &mut MpdClient<S>, index: I, prio: u8) -> MpdResult<()> {
        client.exec_arg2("prio", prio, index.to_pos()).and_then(|_| client.ok())
    }

    pub fn priorityid<S: Stream>(client: &mut MpdClient<S>, id: uint, prio: u8) -> MpdResult<()> {
        client.exec_arg2("prioid", prio, id).and_then(|_| client.ok())
    }

    pub fn rangeid<S: Stream>(client: &mut MpdClient<S>, id: uint, range: Option<(Duration, Duration)>) -> MpdResult<()> {
        client.exec_arg2("rangeid", id, range.map(format!("{}:{}", range.0.num_seconds(), range.1.num_seconds())).unwrap_or(":".to_string())).and_then(|_| client.ok())
    }

    pub fn get<S: Stream>(client: &mut MpdClient<S>, index: uint) -> MpdResult<MpdSong> {
        client.exec_arg("playlistinfo", index).and_then(|_| client.iter().collect())
    }

    pub fn slice<S: Stream>(client: &mut MpdClient<S>, slice: (uint, uint)) -> MpdResult<Vec<MpdSong>> {
        client.exec_arg("playlistinfo", format!("{}:{}", slice.0, slice.1)).and_then(|_| client.iter().collect())
    }

    pub fn remove<S: Stream, I: MpdQueuePos>(client: &mut MpdClient<S>, index: I) -> MpdResult<()> {
        client.exec_arg("delete", index.to_pos()).and_then(|_| client.ok())
    }

    pub fn removeid<S: Stream>(client: &mut MpdClient<S>, id: uint) -> MpdResult<()> {
        client.exec_arg("deleteid", id).and_then(|_| client.ok())
    }

    pub fn shiftid<S: Stream>(client: &mut MpdClient<S>, id: uint, target: uint) -> MpdResult<()> {
        client.exec_arg2("moveid", id, target).and_then(|_| client.ok())
    }

    pub fn getid<S: Stream>(client: &mut MpdClient<S>, id: uint) -> MpdResult<MpdSong> {
        client.exec_arg("playlistid", id).and_then(|_| client.iter().collect())
    }

    pub fn songs<S: Stream>(client: &mut MpdClient<S>) -> MpdResult<Vec<MpdSong>> {
        client.exec("playlistinfo").and_then(|_| client.iter().collect())
    }

    pub fn shuffle_slice<S: Stream>(client: &mut MpdClient<S>, slice: (uint, uint)) -> MpdResult<()> {
        client.exec_arg("shuffle", format!("{}:{}", slice.0, slice.1)).and_then(|_| client.ok())
    }

    pub fn shuffle<S: Stream>(client: &mut MpdClient<S>) -> MpdResult<()> {
        client.exec("shuffle").and_then(|_| client.ok())
    }

    pub fn load<S: Stream>(client: &mut MpdClient<S>, name: &str) -> MpdResult<()> {
        client.exec_arg("load", name).and_then(|_| client.ok())
    }

    pub fn load_slice<S: Stream>(client: &mut MpdClient<S>, name: &str, slice: (uint, uint)) -> MpdResult<()> {
        client.exec_arg2("load", name, format!("{}:{}", slice.0, slice.1)).and_then(|_| client.ok())
    }

    pub fn save<S: Stream>(client: &mut MpdClient<S>, name: &str) -> MpdResult<()> {
        client.exec_arg("save", name).and_then(|_| client.ok())
    }
}
<|endoftext|>


<commit_before>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

trait ToResponse {
    fn status(&self) -> StatusCode {
        StatusCode::Ok
    }

    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(0)
    }

    fn content(&self) -> &[u8] {
        &[]
    }
}

impl ToResponse for StatusCode {
    fn status(&self) -> StatusCode {
        *self
    }
}

impl ToResponse for String {
    fn content_type(&self) -> ContentType {
        ContentType::html()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.as_bytes()
    }
}

pub fn get(request: Request, mut response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status/") => status(path, response),
            path.starts_with("/test") => test(&request, response),
            true => notfound404(response),
        ];
    }
}

fn notfound404(mut response: Response) {
    let text = "<!DOCTYPE html>

            <title>404 Not Found</title>

Not Found

The requested URL was not found on the server.
        If you entered the URL manually please check your spelling and try again.

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <link
                rel=\"icon\"
                href=\"http://investorintel.com/wp-content/uploads/2014/03/tin-can.jpg\"/>
            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(path: &str, mut response: Response) {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    let code = match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    };
    *response.status_mut() = code;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<commit_msg>make response unmutable<commit_after>use std::io::Write;
use hyper::header::{ContentLength, ContentType};
use hyper::server::{Request, Response};
use hyper::status::StatusCode;
use hyper::uri::RequestUri;

macro_rules! dispatch {
    ($m0:expr => $h0:expr, $($m1:expr => $h1:expr,)*) => {{
        if $m0 { $h0 } $( else if $m1 { $h1 } )*
    }}
}

trait ToResponse {
    fn status(&self) -> StatusCode {
        StatusCode::Ok
    }

    fn content_type(&self) -> ContentType {
        ContentType::plaintext()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(0)
    }

    fn content(&self) -> &[u8] {
        &[]
    }
}

impl ToResponse for StatusCode {
    fn status(&self) -> StatusCode {
        *self
    }
}

impl ToResponse for String {
    fn content_type(&self) -> ContentType {
        ContentType::html()
    }

    fn content_length(&self) -> ContentLength {
        ContentLength(self.as_bytes().len() as u64)
    }

    fn content(&self) -> &[u8] {
        self.as_bytes()
    }
}

pub fn get(request: Request, response: Response) {
    println!("** Handling GET {}", request.uri);
    println!("** Incoming headers {:?}", request.headers);
    if let RequestUri::AbsolutePath(ref path) = request.uri {
        dispatch![
            path == "/" => index(&request, response),
            path == "/ip" => origin(&request, response),
            path.starts_with("/status/") => status(path, response),
            path.starts_with("/test") => test(&request, response),
            true => notfound404(response),
        ];
    }
}

fn notfound404(mut response: Response) {
    let text = "<!DOCTYPE html>

            <title>404 Not Found</title>

Not Found

The requested URL was not found on the server.
        If you entered the URL manually please check your spelling and try again.

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn index(request: &Request, mut response: Response) {
    let index = "<!DOCTYPE html>

            <link
                rel=\"icon\"
                href=\"http://investorintel.com/wp-content/uploads/2014/03/tin-can.jpg\"/>
            <title>HTTPTIN</title>

HTTPTIN - HTTP tester in Rust and Rocket

    ";

    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(index.len() as u64));
    response.start().unwrap().write(index.as_bytes()).unwrap();
}

fn status(path: &str, mut response: Response) {
    // /status/xx
    // 0123456789
    let (_, param) = path.split_at(8);
    let code = match param.parse::<u16>() {
        Ok(status) => StatusCode::from_u16(status),
        Err(_) => StatusCode::BadRequest,
    };
    *response.status_mut() = code;
}

fn origin(request: &Request, mut response: Response) {
    let text = "Remote address decoding is not implemented yet";
    response.headers_mut().set(ContentType::plaintext());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}

fn test(request: &Request, mut response: Response) {
    let text = format!("<!DOCTYPE html>

            <title>HTTPTIN TEST</title>

            Remote Address: {}

            Method: {}

            HTTPVersion: {}

            Headers: {}

            URI: {}

    ",
                       request.remote_addr,
                       request.method,
                       request.version,
                       request.headers,
                       request.uri);
    response.headers_mut().set(ContentType::html());
    response.headers_mut().set(ContentLength(text.len() as u64));
    response.start().unwrap().write(text.as_bytes()).unwrap();
}
<|endoftext|>


<commit_before>extern crate spaceapi_server;

use std::net::Ipv4Addr;
use std::net::TcpStream;
use std::io::ErrorKind;

use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::optional::Optional;

/// Create a new status object containing test data.
fn get_status() -> api::Status {
    api::Status::new(
        "ourspace",
        "https://example.com/logo.png",
        "https://example.com/",
        api::Location {
            address: Optional::Value("Street 1, Zürich, Switzerland".into()),
            lat: 47.123,
            lon: 8.88,
        },
        api::Contact {
            irc: Optional::Absent,
            twitter: Optional::Absent,
            foursquare: Optional::Absent,
            email: Optional::Value("hi@example.com".into()),
        },
        vec![
            "email".into(),
            "twitter".into(),
        ],
    )
}

/// Create a new SpaceapiServer instance listening on the specified port.
fn get_server(ip: Ipv4Addr, port: u16, status: api::Status) -> SpaceapiServer {
    // Start and return a server instance
    SpaceapiServer::new((ip, port), status, "redis://127.0.0.1/", vec![]).unwrap()
}

#[test]
fn server_starts() {
    //! Test that the spaceapi server starts at all.

    // Ip / port for test server
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let port = 3344;

    // Test data
    let status = get_status();

    // Connection to port should fail right now
    let connect_result = TcpStream::connect((ip, port));
    assert!(connect_result.is_err());
    assert_eq!(connect_result.unwrap_err().kind(), ErrorKind::ConnectionRefused);

    // Instantiate and start server
    let server = get_server(ip, port, status);
    let mut listening = server.serve().unwrap();

    // Connecting to server should work now
    let connect_result = TcpStream::connect((ip, port));
    assert!(connect_result.is_ok());

    // Close server
    listening.close().unwrap();
}
<commit_msg>Use Absent/Value directly<commit_after>extern crate spaceapi_server;

use std::net::Ipv4Addr;
use std::net::TcpStream;
use std::io::ErrorKind;

use spaceapi_server::SpaceapiServer;
use spaceapi_server::api;
use spaceapi_server::api::optional::Optional::{Absent, Value};

/// Create a new status object containing test data.
fn get_status() -> api::Status {
    api::Status::new(
        "ourspace",
        "https://example.com/logo.png",
        "https://example.com/",
        api::Location {
            address: Value("Street 1, Zürich, Switzerland".into()),
            lat: 47.123,
            lon: 8.88,
        },
        api::Contact {
            irc: Absent,
            twitter: Absent,
            foursquare: Absent,
            email: Value("hi@example.com".into()),
        },
        vec![
            "email".into(),
            "twitter".into(),
        ],
    )
}

/// Create a new SpaceapiServer instance listening on the specified port.
fn get_server(ip: Ipv4Addr, port: u16, status: api::Status) -> SpaceapiServer {
    // Start and return a server instance
    SpaceapiServer::new((ip, port), status, "redis://127.0.0.1/", vec![]).unwrap()
}

#[test]
fn server_starts() {
    //! Test that the spaceapi server starts at all.

    // Ip / port for test server
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let port = 3344;

    // Test data
    let status = get_status();

    // Connection to port should fail right now
    let connect_result = TcpStream::connect((ip, port));
    assert!(connect_result.is_err());
    assert_eq!(connect_result.unwrap_err().kind(), ErrorKind::ConnectionRefused);

    // Instantiate and start server
    let server = get_server(ip, port, status);
    let mut listening = server.serve().unwrap();

    // Connecting to server should work now
    let connect_result = TcpStream::connect((ip, port));
    assert!(connect_result.is_ok());

    // Close server
    listening.close().unwrap();
}
<|endoftext|>


<commit_before>extern crate nalgebra_lapack;
extern crate nalgebra as na;
extern crate num;

use nalgebra_lapack::{SVD, Eigensystem, Inverse, Cholesky};

use na::{DMatrix, DVector, Norm, ColumnSlice, Iterable, Eye, Transpose};
use num::complex::Complex;

#[test]
fn test_svd_wikipedia() {

    // Example from https://en.wikipedia.org/wiki/Singular_value_decomposition#Example

    let m = DMatrix::from_row_vector(4, 5,
                                     &[1.0, 0.0, 0.0, 0.0, 2.0,
                                       0.0, 0.0, 3.0, 0.0, 0.0,
                                       0.0, 0.0, 0.0, 0.0, 0.0,
                                       0.0, 4.0, 0.0, 0.0, 0.0]);

    let (u, s, vt) = m.svd().unwrap();

    let mut expected_u: DMatrix<f64> = DMatrix::new_zeros(4, 4);
    expected_u[(0, 2)] = 1.0;
    expected_u[(1, 1)] = 1.0;
    expected_u[(2, 3)] = -1.0;
    expected_u[(3, 0)] = 1.0;

    assert_eq!(u.nrows(), expected_u.nrows());
    assert_eq!(u.ncols(), expected_u.ncols());
    assert_eq!(u.as_vector(), expected_u.as_vector());

    let mut expected_s: DVector<f64> = DVector::from_element(4, 0.0);
    expected_s[0] = 4.0;
    expected_s[1] = 3.0;
    expected_s[2] = 5.0_f64.sqrt();

    assert_eq!(s.len(), expected_s.len());
    assert_eq!(s.as_ref(), expected_s.as_ref());

    let mut expected_vt: DMatrix<f64> = DMatrix::new_zeros(5, 5);
    expected_vt[(0, 1)] = 1.0;
    expected_vt[(1, 2)] = 1.0;
    expected_vt[(1, 2)] = 1.0;
    expected_vt[(2, 0)] = 0.2_f64.sqrt();
    expected_vt[(2, 4)] = 0.8_f64.sqrt();
    expected_vt[(3, 3)] = 1.0;
    expected_vt[(4, 0)] = -(0.8_f64.sqrt());
    expected_vt[(4, 4)] = 0.2_f64.sqrt();

    assert_eq!(vt.nrows(), expected_vt.nrows());
    assert_eq!(vt.ncols(), expected_vt.ncols());
    assert!(na::approx_eq(&vt, &expected_vt));
}

#[test]
fn test_svd_recomposition() {
    // The actual matrix contents and size should not matter.
    let m = DMatrix::from_row_vector(3, 5,
                                     &[-1.01, 0.86, -4.60, 3.31, -4.81,
                                        3.98, 0.53, -7.04, 5.29,  3.55,
                                        3.30, 8.26, -3.89, 8.20, -1.51]);
    let expected_m = m.clone(); // copy since original is moved into svd()
    let (u, s, vt) = m.svd().unwrap();

    let mut full_s = DMatrix::new_zeros(u.nrows(), vt.nrows());
    for i in 0..s.len() {
        full_s[(i, i)] = s[i];
    }
    let actual_m = u * (full_s * vt);

    assert!(na::approx_eq(&actual_m, &expected_m));
}

#[test]
fn test_svd_recomposition_complex() {

    // The actual matrix contents and size should not matter.
    let mr = DMatrix::from_row_vector(3, 5,
                                      &[-1.01, 0.86, -4.60, 3.31, -4.81,
                                         3.98, 0.53, -7.04, 5.29,  3.55,
                                         3.30, 8.26, -3.89, 8.20, -1.51]);

    let expected_m = mr.clone(); // copy since original is moved into svd()
    let m: DMatrix<Complex<f64>> =
        DMatrix::from_column_vector(mr.nrows(),
                                    mr.ncols(),
                                    &mr.as_vector()
                                        .iter()
                                        .map(|re| Complex { re: *re, im: 0.0 })
                                        .collect::<Vec<_>>());

    let (uc, s, vtc) = m.svd().unwrap();
    let u = real_only_mat(uc);
    let vt = real_only_mat(vtc);

    let mut full_s = DMatrix::new_zeros(u.nrows(), vt.nrows());
    for i in 0..s.len() {
        full_s[(i, i)] = s[i];
    }
    let actual_m = u * (full_s * vt);

    assert!(na::approx_eq(&actual_m, &expected_m));
}

fn real_only_mat(u: DMatrix<Complex<f64>>) -> DMatrix<f64> {
    DMatrix::from_column_vector(u.nrows(),
                                u.ncols(),
                                &u.as_vector()
                                    .iter()
                                    .map(|c| {
                                        assert!(c.im == 0.0);
                                        c.re
                                    })
                                    .collect::<Vec<_>>())
}

fn real_only(a: &DVector<Complex<f64>>) -> DVector<f64> {
    let v: Vec<_> = a.iter()
        .map(|cmplx| {
            assert!(cmplx.im == 0.0);
            cmplx.re
        })
        .collect();
    DVector { at: v }
}

fn na_position(a: &DVector<f64>, val: f64, eps: f64) -> Option<usize> {
    a.at.iter().position(|x| (*x - val).abs() < eps)
}

#[test]
fn test_eigenvalues_wikipedia_triangular() {

    // Based on example at
    // https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors#Triangular_matrices

    let n = 3;
    let mat = DMatrix::from_row_vector(n, n, &[1.0, 0.0, 0.0,
                                               1.0, 2.0, 0.0,
                                               2.0, 3.0, 3.0]);
    let (eigen_values, eigen_vectors) = mat.eigensystem().unwrap();

    assert!(eigen_values.len() == n);
    let ev = real_only(&eigen_values);
    let eps = 1e-16;

    // Check for eigvenvalue of 1.0 and corresponding eigenvector.
    if let Some(i) = na_position(&ev, 1.0, eps) {
        let expected = DVector { at: vec![1.0, -1.0, 0.5] }.normalize();
        let actual = real_only(&eigen_vectors.column_slice(i, 0, n));
        assert!(na::approx_eq(&expected, &actual));
    } else {
        panic!("expected value not found");
    }

    // Check for eigvenvalue of 2.0 and corresponding eigenvector.
    if let Some(i) = na_position(&ev, 2.0, eps) {
        let expected = DVector { at: vec![0.0, 1.0, -3.0] }.normalize();
        let actual = real_only(&eigen_vectors.column_slice(i, 0, n)).normalize();
        assert!(na::approx_eq(&expected, &actual));
    } else {
        panic!("expected value not found");
    }

    // Check for eigvenvalue of 3.0 and corresponding eigenvector.
    if let Some(i) = na_position(&ev, 3.0, eps) {
        let expected = DVector { at: vec![0.0, 0.0, 1.0] }.normalize();
        let actual = real_only(&eigen_vectors.column_slice(i, 0, n)).normalize();
        assert!(na::approx_eq(&expected, &actual));
    } else {
        panic!("expected value not found");
    }

}

#[test]
fn test_inverse_2d() {
    let a = DMatrix::from_row_vector(2, 2, &[1.0, 2.0, 3.0, 4.0]);
    let a_inv = a.clone().inv().unwrap();

    let eye_actual = a * a_inv;
    let eye_expected = DMatrix::new_identity(2);

    assert!(na::approx_eq(&eye_actual, &eye_expected));
}

#[test]
fn test_inverse_3d() {
    let a = DMatrix::from_row_vector(3, 3,
        &[1.0, 2.0, 0.0,
          0.0, 5.0, 6.0,
          7.0, 8.0, 9.0]);
    let a_inv = a.clone().inv().unwrap();

    let eye_actual = a * a_inv;
    let eye_expected = DMatrix::new_identity(3);

    assert!(na::approx_eq(&eye_actual, &eye_expected));
}

#[test]
fn test_complex_inverse_2d() {
    let ar = DMatrix::from_row_vector(2, 2,
        &[1.0, 2.0,
          3.0, 4.0]);
    let a: DMatrix<Complex<f64>> =
        DMatrix::from_column_vector(ar.nrows(),
                                    ar.ncols(),
                                    &ar.as_vector()
                                        .iter()
                                        .map(|re| Complex { re: *re, im: 0.0 })
                                        .collect::<Vec<_>>());
    let a_inv = a.clone().inv().unwrap();

    let eye_actual_complex = a * a_inv;
    let eye_actual = real_only_mat(eye_actual_complex);
    let eye_expected = DMatrix::new_identity(2);

    assert!(na::approx_eq(&eye_actual, &eye_expected));
}

#[test]
fn test_complex_inverse_3d() {
    let ar = DMatrix::from_row_vector(3, 3,
        &[1.0, 2.0, 0.0,
          0.0, 5.0, 6.0,
          7.0, 8.0, 9.0]);
    let a: DMatrix<Complex<f64>> =
        DMatrix::from_column_vector(ar.nrows(),
                                    ar.ncols(),
                                    &ar.as_vector()
                                        .iter()
                                        .map(|re| Complex { re: *re, im: 0.0 })
                                        .collect::<Vec<_>>());
    let a_inv = a.clone().inv().unwrap();

    let eye_actual_complex = a * a_inv;
    let eye_actual = real_only_mat(eye_actual_complex);
    let eye_expected = DMatrix::new_identity(3);

    assert!(na::approx_eq(&eye_actual, &eye_expected));
}

#[test]
fn test_cholesky() {
    let a = DMatrix::from_row_vector(3, 3,
        &[2.0, -1.0, 0.0,
         -1.0, 2.0, -1.0,
          0.0, -1.0, 2.0]);
    let lo = a.clone().cholesky().unwrap();
    let lot = lo.transpose(); // conjugate transpose for all real is simply the transpose
    let a_recomposed = &lo * &lot;
    assert!(na::approx_eq(&a, &a_recomposed));
}

fn conjugate_transpose(a: &DMatrix<Complex<f64>>) -> DMatrix<Complex<f64>> {
    let mut b = DMatrix::new_zeros(a.ncols(), a.nrows());
    for i in 0..a.nrows() {
        for j in 0..a.ncols() {
            let c = a[(i,j)];
            b[(j,i)] = Complex {re: c.re, im: -c.im};
        }
    }
    b
}

#[test]
fn test_cholesky_complex() {
    let ar = DMatrix::from_row_vector(3, 3,
        &[2.0, -1.0, 0.0,
         -1.0, 2.0, -1.0,
         0.0, -1.0, 2.0]);
    let a: DMatrix<Complex<f64>> =
        DMatrix::from_column_vector(ar.nrows(),
                                    ar.ncols(),
                                    &ar.as_vector()
                                        .iter()
                                        .map(|re| Complex { re: *re, im: 0.0 })
                                        .collect::<Vec<_>>());
    let lo = a.clone().cholesky().unwrap();
    let lot = conjugate_transpose(&lo);
    let a_recomposed_complex = &lo * &lot;
    let a_recomposed = real_only_mat(a_recomposed_complex);
    assert!(na::approx_eq(&ar, &a_recomposed));
}
<commit_msg>better format matrices in test<commit_after>extern crate nalgebra_lapack;
extern crate nalgebra as na;
extern crate num;

use nalgebra_lapack::{SVD, Eigensystem, Inverse, Cholesky};

use na::{DMatrix, DVector, Norm, ColumnSlice, Iterable, Eye, Transpose};
use num::complex::Complex;

#[test]
fn test_svd_wikipedia() {

    // Example from https://en.wikipedia.org/wiki/Singular_value_decomposition#Example

    let m = DMatrix::from_row_vector(4, 5,
                                     &[1.0, 0.0, 0.0, 0.0, 2.0,
                                       0.0, 0.0, 3.0, 0.0, 0.0,
                                       0.0, 0.0, 0.0, 0.0, 0.0,
                                       0.0, 4.0, 0.0, 0.0, 0.0]);

    let (u, s, vt) = m.svd().unwrap();

    let mut expected_u: DMatrix<f64> = DMatrix::new_zeros(4, 4);
    expected_u[(0, 2)] = 1.0;
    expected_u[(1, 1)] = 1.0;
    expected_u[(2, 3)] = -1.0;
    expected_u[(3, 0)] = 1.0;

    assert_eq!(u.nrows(), expected_u.nrows());
    assert_eq!(u.ncols(), expected_u.ncols());
    assert_eq!(u.as_vector(), expected_u.as_vector());

    let mut expected_s: DVector<f64> = DVector::from_element(4, 0.0);
    expected_s[0] = 4.0;
    expected_s[1] = 3.0;
    expected_s[2] = 5.0_f64.sqrt();

    assert_eq!(s.len(), expected_s.len());
    assert_eq!(s.as_ref(), expected_s.as_ref());

    let mut expected_vt: DMatrix<f64> = DMatrix::new_zeros(5, 5);
    expected_vt[(0, 1)] = 1.0;
    expected_vt[(1, 2)] = 1.0;
    expected_vt[(1, 2)] = 1.0;
    expected_vt[(2, 0)] = 0.2_f64.sqrt();
    expected_vt[(2, 4)] = 0.8_f64.sqrt();
    expected_vt[(3, 3)] = 1.0;
    expected_vt[(4, 0)] = -(0.8_f64.sqrt());
    expected_vt[(4, 4)] = 0.2_f64.sqrt();

    assert_eq!(vt.nrows(), expected_vt.nrows());
    assert_eq!(vt.ncols(), expected_vt.ncols());
    assert!(na::approx_eq(&vt, &expected_vt));
}

#[test]
fn test_svd_recomposition() {
    // The actual matrix contents and size should not matter.
    let m = DMatrix::from_row_vector(3, 5,
                                     &[-1.01, 0.86, -4.60, 3.31, -4.81,
                                        3.98, 0.53, -7.04, 5.29,  3.55,
                                        3.30, 8.26, -3.89, 8.20, -1.51]);
    let expected_m = m.clone(); // copy since original is moved into svd()
    let (u, s, vt) = m.svd().unwrap();

    let mut full_s = DMatrix::new_zeros(u.nrows(), vt.nrows());
    for i in 0..s.len() {
        full_s[(i, i)] = s[i];
    }
    let actual_m = u * (full_s * vt);

    assert!(na::approx_eq(&actual_m, &expected_m));
}

#[test]
fn test_svd_recomposition_complex() {

    // The actual matrix contents and size should not matter.
    let mr = DMatrix::from_row_vector(3, 5,
                                      &[-1.01, 0.86, -4.60, 3.31, -4.81,
                                         3.98, 0.53, -7.04, 5.29,  3.55,
                                         3.30, 8.26, -3.89, 8.20, -1.51]);

    let expected_m = mr.clone(); // copy since original is moved into svd()
    let m: DMatrix<Complex<f64>> =
        DMatrix::from_column_vector(mr.nrows(),
                                    mr.ncols(),
                                    &mr.as_vector()
                                        .iter()
                                        .map(|re| Complex { re: *re, im: 0.0 })
                                        .collect::<Vec<_>>());

    let (uc, s, vtc) = m.svd().unwrap();
    let u = real_only_mat(uc);
    let vt = real_only_mat(vtc);

    let mut full_s = DMatrix::new_zeros(u.nrows(), vt.nrows());
    for i in 0..s.len() {
        full_s[(i, i)] = s[i];
    }
    let actual_m = u * (full_s * vt);

    assert!(na::approx_eq(&actual_m, &expected_m));
}

fn real_only_mat(u: DMatrix<Complex<f64>>) -> DMatrix<f64> {
    DMatrix::from_column_vector(u.nrows(),
                                u.ncols(),
                                &u.as_vector()
                                    .iter()
                                    .map(|c| {
                                        assert!(c.im == 0.0);
                                        c.re
                                    })
                                    .collect::<Vec<_>>())
}

fn real_only(a: &DVector<Complex<f64>>) -> DVector<f64> {
    let v: Vec<_> = a.iter()
        .map(|cmplx| {
            assert!(cmplx.im == 0.0);
            cmplx.re
        })
        .collect();
    DVector { at: v }
}

fn na_position(a: &DVector<f64>, val: f64, eps: f64) -> Option<usize> {
    a.at.iter().position(|x| (*x - val).abs() < eps)
}

#[test]
fn test_eigenvalues_wikipedia_triangular() {

    // Based on example at
    // https://en.wikipedia.org/wiki/Eigenvalues_and_eigenvectors#Triangular_matrices

    let n = 3;
    let mat = DMatrix::from_row_vector(n, n, &[1.0, 0.0, 0.0,
                                               1.0, 2.0, 0.0,
                                               2.0, 3.0, 3.0]);
    let (eigen_values, eigen_vectors) = mat.eigensystem().unwrap();

    assert!(eigen_values.len() == n);
    let ev = real_only(&eigen_values);
    let eps = 1e-16;

    // Check for eigvenvalue of 1.0 and corresponding eigenvector.
    if let Some(i) = na_position(&ev, 1.0, eps) {
        let expected = DVector { at: vec![1.0, -1.0, 0.5] }.normalize();
        let actual = real_only(&eigen_vectors.column_slice(i, 0, n));
        assert!(na::approx_eq(&expected, &actual));
    } else {
        panic!("expected value not found");
    }

    // Check for eigvenvalue of 2.0 and corresponding eigenvector.
    if let Some(i) = na_position(&ev, 2.0, eps) {
        let expected = DVector { at: vec![0.0, 1.0, -3.0] }.normalize();
        let actual = real_only(&eigen_vectors.column_slice(i, 0, n)).normalize();
        assert!(na::approx_eq(&expected, &actual));
    } else {
        panic!("expected value not found");
    }

    // Check for eigvenvalue of 3.0 and corresponding eigenvector.
    if let Some(i) = na_position(&ev, 3.0, eps) {
        let expected = DVector { at: vec![0.0, 0.0, 1.0] }.normalize();
        let actual = real_only(&eigen_vectors.column_slice(i, 0, n)).normalize();
        assert!(na::approx_eq(&expected, &actual));
    } else {
        panic!("expected value not found");
    }

}

#[test]
fn test_inverse_2d() {
    let a = DMatrix::from_row_vector(2, 2,
        &[1.0, 2.0,
          3.0, 4.0]);
    let a_inv = a.clone().inv().unwrap();

    let eye_actual = a * a_inv;
    let eye_expected = DMatrix::new_identity(2);

    assert!(na::approx_eq(&eye_actual, &eye_expected));
}

#[test]
fn test_inverse_3d() {
    let a = DMatrix::from_row_vector(3, 3,
        &[1.0, 2.0, 0.0,
          0.0, 5.0, 6.0,
          7.0, 8.0, 9.0]);
    let a_inv = a.clone().inv().unwrap();

    let eye_actual = a * a_inv;
    let eye_expected = DMatrix::new_identity(3);

    assert!(na::approx_eq(&eye_actual, &eye_expected));
}

#[test]
fn test_complex_inverse_2d() {
    let ar = DMatrix::from_row_vector(2, 2,
        &[1.0, 2.0,
          3.0, 4.0]);
    let a: DMatrix<Complex<f64>> =
        DMatrix::from_column_vector(ar.nrows(),
                                    ar.ncols(),
                                    &ar.as_vector()
                                        .iter()
                                        .map(|re| Complex { re: *re, im: 0.0 })
                                        .collect::<Vec<_>>());
    let a_inv = a.clone().inv().unwrap();

    let eye_actual_complex = a * a_inv;
    let eye_actual = real_only_mat(eye_actual_complex);
    let eye_expected = DMatrix::new_identity(2);

    assert!(na::approx_eq(&eye_actual, &eye_expected));
}

#[test]
fn test_complex_inverse_3d() {
    let ar = DMatrix::from_row_vector(3, 3,
        &[1.0, 2.0, 0.0,
          0.0, 5.0, 6.0,
          7.0, 8.0, 9.0]);
    let a: DMatrix<Complex<f64>> =
        DMatrix::from_column_vector(ar.nrows(),
                                    ar.ncols(),
                                    &ar.as_vector()
                                        .iter()
                                        .map(|re| Complex { re: *re, im: 0.0 })
                                        .collect::<Vec<_>>());
    let a_inv = a.clone().inv().unwrap();

    let eye_actual_complex = a * a_inv;
    let eye_actual = real_only_mat(eye_actual_complex);
    let eye_expected = DMatrix::new_identity(3);

    assert!(na::approx_eq(&eye_actual, &eye_expected));
}

#[test]
fn test_cholesky() {
    let a = DMatrix::from_row_vector(3, 3,
        &[2.0, -1.0, 0.0,
         -1.0, 2.0, -1.0,
          0.0, -1.0, 2.0]);
    let lo = a.clone().cholesky().unwrap();
    let lot = lo.transpose(); // conjugate transpose for all real is simply the transpose
    let a_recomposed = &lo * &lot;
    assert!(na::approx_eq(&a, &a_recomposed));
}

fn conjugate_transpose(a: &DMatrix<Complex<f64>>) -> DMatrix<Complex<f64>> {
    let mut b = DMatrix::new_zeros(a.ncols(), a.nrows());
    for i in 0..a.nrows() {
        for j in 0..a.ncols() {
            let c = a[(i,j)];
            b[(j,i)] = Complex {re: c.re, im: -c.im};
        }
    }
    b
}

#[test]
fn test_cholesky_complex() {
    let ar = DMatrix::from_row_vector(3, 3,
        &[2.0, -1.0, 0.0,
         -1.0, 2.0, -1.0,
         0.0, -1.0, 2.0]);
    let a: DMatrix<Complex<f64>> =
        DMatrix::from_column_vector(ar.nrows(),
                                    ar.ncols(),
                                    &ar.as_vector()
                                        .iter()
                                        .map(|re| Complex { re: *re, im: 0.0 })
                                        .collect::<Vec<_>>());
    let lo = a.clone().cholesky().unwrap();
    let lot = conjugate_transpose(&lo);
    let a_recomposed_complex = &lo * &lot;
    let a_recomposed = real_only_mat(a_recomposed_complex);
    assert!(na::approx_eq(&ar, &a_recomposed));
}
<|endoftext|>


<commit_before>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

//! Test that every method gives the correct result for valid values.
//! Except iterators, which are stateful.

use std::char;
use std::str::{self,FromStr};
use std::hash::Hash;
use std::collections::hash_map::DefaultHasher;
use std::iter::FromIterator;
extern crate encode_unicode;
use encode_unicode::*;

#[test]
fn equal_defaults() {
    assert_eq!(Utf8Char::default().to_char(), char::default());
    assert_eq!(Utf16Char::default().to_char(), char::default());
}

#[test]
fn same_size_as_char() {
    use std::mem::size_of;
    assert_eq!(size_of::<Utf8Char>(), size_of::<char>());
    assert_eq!(size_of::<Utf16Char>(), size_of::<char>());
}

#[test]
#[cfg(feature="std")]
fn read_iterator() {
    use std::io::Read;
    use std::cmp::min;

    let uc = 'ä'.to_utf8();
    assert_eq!(uc.len(), 2);
    for chunk in 1..5 {
        let mut buf = [b'E'; 6];
        let mut iter = uc.into_iter();
        let mut written = 0;
        for _ in 0..4 {
            assert_eq!(iter.read(&mut buf[..0]).unwrap(), 0);
            let wrote = iter.read(&mut buf[written..written+chunk]).unwrap();
            assert_eq!(wrote, min(2-written, chunk));
            written += wrote;
            for &b in &buf[written..] {assert_eq!(b, b'E');}
            assert_eq!(buf[..written], AsRef::<[u8]>::as_ref(&uc)[..written]);
        }
        assert_eq!(written, 2);
    }
}

const EDGES_AND_BETWEEN: [u32;13] = [
    0x0,// min
    0x3b,// between
    0x7f,// max 1-byte UTF-8
    0x80,// min 2-byte UTF-8
    0x111,// between
    0x7ff,// max 2-byte UTF-8
    0x800,// min 3-byte UTF-8
    0xd7ff,// before reserved
    0xe000,// after reserved
    0xffff,// max UTF-16 single and 3-byte UTF-8
    0x10000,// min UTF-16 surrogate and 4-byte UTF-8
    0xabcde,// between
    0x10ffff,// max
];

fn eq_cmp_hash(c: char) -> (Utf8Char, Utf16Char) {
    let sh = &mut DefaultHasher::new();
    let u8c = c.to_utf8();
    assert_eq!(u8c.to_char(), c);
    assert_eq!(u8c.hash(sh), c.hash(sh));
    let u16c = c.to_utf16();
    assert_eq!(u16c.to_char(), c);
    assert_eq!(u16c.hash(sh), c.hash(sh));

    for other in &EDGES_AND_BETWEEN {
        let other = unsafe{ char::from_u32_unchecked(*other) };

        let u8other = other.to_utf8();
        assert_eq!(u8c == u8other,  c == other);
        assert_eq!(u8c.hash(sh)==other.hash(sh),  c.hash(sh)==u8other.hash(sh));
        assert_eq!(u8c.cmp(&u8other), c.cmp(&other));

        let u16other = other.to_utf16();
        assert_eq!(u16c == u16other,  c == other);
        assert_eq!(u16c.hash(sh)==other.hash(sh),  c.hash(sh)==u16other.hash(sh));
        assert_eq!(u16c.cmp(&u16other), c.cmp(&other));
    }
    (u8c, u16c)
}

fn iterators(c: char) {
    let mut iter = c.iter_utf8_bytes();
    let mut buf = [0; 4];
    let mut iter_ref = c.encode_utf8(&mut buf[..]).as_bytes().iter();
    for _ in 0..6 {
        assert_eq!(iter.size_hint(), iter_ref.size_hint());
        assert_eq!(format!("{:?}", iter), format!("{:?}", iter_ref.as_slice()));
        assert_eq!(iter.next(), iter_ref.next().cloned());
    }

    let mut iter = c.iter_utf16_units();
    let mut buf = [0; 2];
    let mut iter_ref = c.encode_utf16(&mut buf[..]).iter();
    for _ in 0..4 {
        assert_eq!(iter.size_hint(), iter_ref.size_hint());
        assert_eq!(format!("{:?}", iter), format!("{:?}", iter_ref.as_slice()));
        assert_eq!(iter.next(), iter_ref.next().cloned());
    }
}

fn test(c: u32) {
    let c = char::from_u32(c).expect(&format!("{:x} is not a valid char", c));
    assert_eq!(char::from_u32_detailed(c as u32), Ok(c));
    let (u8c, u16c) = eq_cmp_hash(c);
    iterators(c);
    assert_eq!(Utf16Char::from(u8c), u16c);
    assert_eq!(Utf8Char::from(u16c), u8c);

    // UTF-8
    let mut buf = [0; 4];
    let reference = c.encode_utf8(&mut buf[..]).as_bytes();
    let len = reference.len(); // short name because it is used in many places.
    assert_eq!(reference[0].extra_utf8_bytes(), Ok(len-1));
    assert_eq!(reference[0].extra_utf8_bytes_unchecked(), len-1);
    assert_eq!(AsRef::<[u8]>::as_ref(&u8c), reference);

    let (mut arr,arrlen) = u8c.to_array();
    assert_eq!(arrlen, len);
    assert_eq!(Utf8Char::from_array(arr), Ok(u8c));
    assert_eq!(c.to_utf8_array(),  (arr, len));

    let str_ = str::from_utf8(reference).unwrap();
    let ustr = Utf8Char::from_str(str_).unwrap();
    assert_eq!(ustr.to_array().0, arr);// bitwise equality
    assert_eq!(char::from_utf8_array(arr), Ok(c));
    assert_eq!(char::from_utf8_slice_start(reference), Ok((c,len)));
    for b in arr.iter_mut().skip(arrlen) {
        *b = b'F';// from_slice_start must not read these.
    }
    assert_eq!(Utf8Char::from_slice_start(&arr), Ok((u8c,len)));// Test that it doesn't read too much
    assert_eq!(Utf8Char::from_slice_start(reference), Ok((u8c,len)));
    unsafe {
        // Hopefully make bugs easier to catch by making reads into unallocated memory by filling
        // a jemalloc bin. See table on http://jemalloc.net/jemalloc.3.html for bin sizes.
        // I have no idea whether this works.
        let mut boxed = Box::new([0xffu8; 16]);
        let start = boxed.len()-len; // reach the end
        boxed[start..].copy_from_slice(reference);
        let slice = &boxed[start..start]; // length of slice should be ignored.
        assert_eq!(Utf8Char::from_slice_start_unchecked(slice), (u8c,len));
    }
    assert_eq!(&Vec::<u8>::from_iter(Some(u8c))[..], reference);
    assert_eq!(&String::from_iter(Some(u8c))[..], str_);

    // UTF-16
    let mut buf = [0; 2];
    let reference = c.encode_utf16(&mut buf[..]);
    let len = reference.len();
    assert_eq!(reference[0].utf16_needs_extra_unit(), Ok(len==2));
    assert_eq!(reference[0].is_utf16_leading_surrogate(), len==2);
    assert_eq!(u16c.as_ref(), reference);
    assert_eq!(char::from_utf16_slice_start(&reference[..len]), Ok((c,len)));
    unsafe {
        // Hopefully make bugs easier to catch by making reads into unallocated memory by filling
        // a jemalloc bin. See table on http://jemalloc.net/jemalloc.3.html for bin sizes.
        // I have no idea whether this works.
        let mut boxed = Box::new([0u16; 8]);
        let start = boxed.len()-len; // reach the end
        boxed[start..].copy_from_slice(reference);
        let slice = &boxed[start..start]; // length of slice should be ignored.
        assert_eq!(Utf16Char::from_slice_start_unchecked(slice), (u16c,len));
    }
    let tuple = c.to_utf16_tuple();
    assert_eq!(tuple, (reference[0],reference.get(1).cloned()));
    assert_eq!(char::from_utf16_tuple(tuple), Ok(c));
    assert_eq!(c.to_utf16().to_char(), c);
    assert_eq!(&Vec::<u16>::from_iter(Some(u16c))[..], reference);
}

#[test]
fn edges_middle() {
    for c in &EDGES_AND_BETWEEN {
        test(*c);
    }
}

#[test]
#[ignore]
fn all() {
    for c in std::iter::Iterator::chain(0..0xd800, 0xe000..0x110000) {
        test(c);
    }
}
<commit_msg>Test from_slice_start()s with both an exact and an always larger slice<commit_after>/* Copyright 2016 Torbjørn Birch Moltu
 *
 * Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
 * http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
 * http://opensource.org/licenses/MIT>, at your option. This file may not be
 * copied, modified, or distributed except according to those terms.
 */

//! Test that every method gives the correct result for valid values.
//! Except iterators, which are stateful.

use std::char;
use std::str::{self,FromStr};
use std::hash::Hash;
use std::collections::hash_map::DefaultHasher;
use std::iter::FromIterator;
extern crate encode_unicode;
use encode_unicode::*;

#[test]
fn equal_defaults() {
    assert_eq!(Utf8Char::default().to_char(), char::default());
    assert_eq!(Utf16Char::default().to_char(), char::default());
}

#[test]
fn same_size_as_char() {
    use std::mem::size_of;
    assert_eq!(size_of::<Utf8Char>(), size_of::<char>());
    assert_eq!(size_of::<Utf16Char>(), size_of::<char>());
}

#[test]
#[cfg(feature="std")]
fn read_iterator() {
    use std::io::Read;
    use std::cmp::min;

    let uc = 'ä'.to_utf8();
    assert_eq!(uc.len(), 2);
    for chunk in 1..5 {
        let mut buf = [b'E'; 6];
        let mut iter = uc.into_iter();
        let mut written = 0;
        for _ in 0..4 {
            assert_eq!(iter.read(&mut buf[..0]).unwrap(), 0);
            let wrote = iter.read(&mut buf[written..written+chunk]).unwrap();
            assert_eq!(wrote, min(2-written, chunk));
            written += wrote;
            for &b in &buf[written..] {assert_eq!(b, b'E');}
            assert_eq!(buf[..written], AsRef::<[u8]>::as_ref(&uc)[..written]);
        }
        assert_eq!(written, 2);
    }
}

const EDGES_AND_BETWEEN: [u32;13] = [
    0x0,// min
    0x3b,// between
    0x7f,// max 1-byte UTF-8
    0x80,// min 2-byte UTF-8
    0x111,// between
    0x7ff,// max 2-byte UTF-8
    0x800,// min 3-byte UTF-8
    0xd7ff,// before reserved
    0xe000,// after reserved
    0xffff,// max UTF-16 single and 3-byte UTF-8
    0x10000,// min UTF-16 surrogate and 4-byte UTF-8
    0xabcde,// between
    0x10ffff,// max
];

fn eq_cmp_hash(c: char) -> (Utf8Char, Utf16Char) {
    let sh = &mut DefaultHasher::new();
    let u8c = c.to_utf8();
    assert_eq!(u8c.to_char(), c);
    assert_eq!(u8c.hash(sh), c.hash(sh));
    let u16c = c.to_utf16();
    assert_eq!(u16c.to_char(), c);
    assert_eq!(u16c.hash(sh), c.hash(sh));

    for other in &EDGES_AND_BETWEEN {
        let other = unsafe{ char::from_u32_unchecked(*other) };

        let u8other = other.to_utf8();
        assert_eq!(u8c == u8other,  c == other);
        assert_eq!(u8c.hash(sh)==other.hash(sh),  c.hash(sh)==u8other.hash(sh));
        assert_eq!(u8c.cmp(&u8other), c.cmp(&other));

        let u16other = other.to_utf16();
        assert_eq!(u16c == u16other,  c == other);
        assert_eq!(u16c.hash(sh)==other.hash(sh),  c.hash(sh)==u16other.hash(sh));
        assert_eq!(u16c.cmp(&u16other), c.cmp(&other));
    }
    (u8c, u16c)
}

fn iterators(c: char) {
    let mut iter = c.iter_utf8_bytes();
    let mut buf = [0; 4];
    let mut iter_ref = c.encode_utf8(&mut buf[..]).as_bytes().iter();
    for _ in 0..6 {
        assert_eq!(iter.size_hint(), iter_ref.size_hint());
        assert_eq!(format!("{:?}", iter), format!("{:?}", iter_ref.as_slice()));
        assert_eq!(iter.next(), iter_ref.next().cloned());
    }

    let mut iter = c.iter_utf16_units();
    let mut buf = [0; 2];
    let mut iter_ref = c.encode_utf16(&mut buf[..]).iter();
    for _ in 0..4 {
        assert_eq!(iter.size_hint(), iter_ref.size_hint());
        assert_eq!(format!("{:?}", iter), format!("{:?}", iter_ref.as_slice()));
        assert_eq!(iter.next(), iter_ref.next().cloned());
    }
}

fn test(c: u32) {
    let c = char::from_u32(c).expect(&format!("{:x} is not a valid char", c));
    assert_eq!(char::from_u32_detailed(c as u32), Ok(c));
    let (u8c, u16c) = eq_cmp_hash(c);
    iterators(c);
    assert_eq!(Utf16Char::from(u8c), u16c);
    assert_eq!(Utf8Char::from(u16c), u8c);

    // UTF-8
    let mut buf = [0; 4];
    let reference = c.encode_utf8(&mut buf[..]).as_bytes();
    let len = reference.len(); // short name because it is used in many places.
    assert_eq!(reference[0].extra_utf8_bytes(), Ok(len-1));
    assert_eq!(reference[0].extra_utf8_bytes_unchecked(), len-1);
    assert_eq!(AsRef::<[u8]>::as_ref(&u8c), reference);

    let (arr,arrlen) = u8c.to_array();
    assert_eq!(arrlen, len);
    assert_eq!(Utf8Char::from_array(arr), Ok(u8c));
    assert_eq!(c.to_utf8_array(),  (arr, len));

    let str_ = str::from_utf8(reference).unwrap();
    let ustr = Utf8Char::from_str(str_).unwrap();
    assert_eq!(ustr.to_array().0, arr);// bitwise equality
    assert_eq!(char::from_utf8_array(arr), Ok(c));
    let mut longer = [0xff; 5]; // 0xff is never valid
    longer[..len].copy_from_slice(reference);
    assert_eq!(char::from_utf8_slice_start(reference), Ok((c,len)));
    assert_eq!(char::from_utf8_slice_start(&longer), Ok((c,len)));
    assert_eq!(Utf8Char::from_slice_start(reference), Ok((u8c,len)));
    assert_eq!(Utf8Char::from_slice_start(&longer), Ok((u8c,len)));
    unsafe {
        // Hopefully make bugs easier to catch by making reads into unallocated memory by filling
        // a jemalloc bin. See table on http://jemalloc.net/jemalloc.3.html for bin sizes.
        // I have no idea whether this works.
        let mut boxed = Box::new([0xffu8; 16]);
        let start = boxed.len()-len; // reach the end
        boxed[start..].copy_from_slice(reference);
        let slice = &boxed[start..start]; // length of slice should be ignored.
        assert_eq!(Utf8Char::from_slice_start_unchecked(slice), (u8c,len));
    }
    assert_eq!(&Vec::<u8>::from_iter(Some(u8c))[..], reference);
    assert_eq!(&String::from_iter(Some(u8c))[..], str_);

    // UTF-16
    let mut buf = [0; 2];
    let reference = c.encode_utf16(&mut buf[..]);
    let len = reference.len();
    assert_eq!(reference[0].utf16_needs_extra_unit(), Ok(len==2));
    assert_eq!(reference[0].is_utf16_leading_surrogate(), len==2);
    assert_eq!(u16c.as_ref(), reference);
    let mut longer = [0; 3];
    longer[..len].copy_from_slice(reference);
    assert_eq!(char::from_utf16_slice_start(reference), Ok((c,len)));
    assert_eq!(char::from_utf16_slice_start(&longer), Ok((c,len)));
    assert_eq!(Utf16Char::from_slice_start(reference), Ok((u16c,len)));
    assert_eq!(Utf16Char::from_slice_start(&longer), Ok((u16c,len)));
    unsafe {
        // Hopefully make bugs easier to catch by making reads into unallocated memory by filling
        // a jemalloc bin. See table on http://jemalloc.net/jemalloc.3.html for bin sizes.
        // I have no idea whether this works.
        let mut boxed = Box::new([0u16; 8]);
        let start = boxed.len()-len; // reach the end
        boxed[start..].copy_from_slice(reference);
        let slice = &boxed[start..start]; // length of slice should be ignored.
        assert_eq!(Utf16Char::from_slice_start_unchecked(slice), (u16c,len));
    }
    let tuple = c.to_utf16_tuple();
    assert_eq!(tuple, (reference[0],reference.get(1).cloned()));
    assert_eq!(char::from_utf16_tuple(tuple), Ok(c));
    assert_eq!(c.to_utf16().to_char(), c);
    assert_eq!(&Vec::<u16>::from_iter(Some(u16c))[..], reference);
}

#[test]
fn edges_middle() {
    for c in &EDGES_AND_BETWEEN {
        test(*c);
    }
}

#[test]
#[ignore]
fn all() {
    for c in std::iter::Iterator::chain(0..0xd800, 0xe000..0x110000) {
        test(c);
    }
}
<|endoftext|>


<commit_before>use filetime::FileTime;
use serde::{Deserialize, Serialize};

use std::{
    collections::{HashMap, HashSet},
    fs, io,
    path::{Path, PathBuf},
    vec,
};

/// Helps identify changes in a set of files.
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[serde(from = "DepGraphSerdeRepr", into = "DepGraphSerdeRepr")]
pub struct DepGraph {
    entries: HashMap<PathBuf, Option<DepGraphEntry>>,
}

#[derive(Debug, Clone, PartialEq)]
struct DepGraphEntry {
    mtime: FileTime,
    size: u64,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
struct DepGraphSerdeRepr {
    entries: Vec<DepGraphEntrySerdeRepr>,
}

impl From<DepGraphSerdeRepr> for DepGraph {
    fn from(from: DepGraphSerdeRepr) -> Self {
        DepGraph {
            entries: from
                .entries
                .iter()
                .map(|d| {
                    (
                        PathBuf::from(&d.path),
                        if d.has_graph_entry() {
                            Some(DepGraphEntry {
                                mtime: FileTime::from_unix_time(d.unix_seconds, d.nanos),
                                size: d.size,
                            })
                        } else {
                            None
                        },
                    )
                })
                .collect(),
        }
    }
}

impl From<DepGraph> for DepGraphSerdeRepr {
    fn from(dg: DepGraph) -> Self {
        DepGraphSerdeRepr {
            entries: dg
                .entries
                .iter()
                .map(|e| {
                    let path = e.0.to_str().expect("Only UTF names please").to_string();
                    if let Some(dep_entry) = e.1 {
                        DepGraphEntrySerdeRepr {
                            path,
                            unix_seconds: dep_entry.mtime.unix_seconds(),
                            nanos: dep_entry.mtime.nanoseconds(),
                            size: dep_entry.size,
                        }
                    } else {
                        DepGraphEntrySerdeRepr {
                            path,
                            unix_seconds: 0,
                            nanos: 0,
                            size: 0,
                        }
                    }
                })
                .collect(),
        }
    }
}

/// The serde-friendly representation of a DepGraphEntry.
///
/// SystemTime lacks a platform independent representation we can
/// depend on so use FileTime's unix_seconds,nanos.
/// unix_seconds = nanos = size = 0 is used to represent lack of a DepGraphEntry.
#[derive(Serialize, Deserialize, Debug, Clone)]
struct DepGraphEntrySerdeRepr {
    path: String,
    unix_seconds: i64,
    nanos: u32,
    size: u64,
}

impl DepGraphEntrySerdeRepr {
    fn has_graph_entry(&self) -> bool {
        !(self.unix_seconds == 0 && self.nanos == 0 && self.size == 0)
    }
}

pub struct Change {
    path: PathBuf,
    updated_entry: DepGraphEntry,
}

pub enum InitialState {
    NotChanged,
    Changed,
}

impl DepGraphEntry {
    fn new(path: &Path) -> Result<DepGraphEntry, io::Error> {
        let metadata = path.metadata()?;
        Ok(DepGraphEntry {
            mtime: FileTime::from_system_time(metadata.modified()?),
            size: metadata.len(),
        })
    }
}

impl DepGraph {
    pub fn new() -> DepGraph {
        Default::default()
    }
}

impl DepGraph {
    pub fn contains(&self, path: &PathBuf) -> bool {
        self.entries.contains_key(path)
    }

    pub fn track(&mut self, path: &PathBuf, default_state: InitialState) -> Result<(), io::Error> {
        if !self.entries.contains_key(path) {
            self.entries.insert(
                path.clone(),
                match default_state {
                    InitialState::NotChanged => Some(DepGraphEntry::new(path)?),
                    InitialState::Changed => None,
                },
            );

            // For a dir to register unchanged we need to add it's current contents
            if let InitialState::NotChanged = default_state {
                if path.is_dir() {
                    let mut dirs_visited = HashSet::new();
                    if let Some(new_paths) = self.new_files(&mut dirs_visited, path) {
                        for new_path in new_paths {
                            self.entries
                                .insert(new_path.clone(), Some(DepGraphEntry::new(&new_path)?));
                        }
                    }
                }
            }
        }
        Ok(())
    }

    pub fn has_changed(&self, change: &Change) -> bool {
        return self
            .entries
            .get(&change.path)
            // If we are tracking with different state or we're not tracking at all then you've changed
            .map(|maybe_entry| {
                maybe_entry
                    .as_ref()
                    .map(|entry| change.updated_entry != *entry)
                    .unwrap_or(true)
            })
            .unwrap_or(true);
    }

    pub fn update(&mut self, changes: &[Change]) {
        for change in changes {
            if self.has_changed(change) {
                self.entries
                    .insert(change.path.clone(), Some(change.updated_entry.clone()));
            }
        }
    }

    fn new_files(
        &self,
        dirs_visited: &mut HashSet<PathBuf>,
        dir: &PathBuf,
    ) -> Option<Vec<PathBuf>> {
        assert!(dir.is_dir());
        if dirs_visited.contains(dir) {
            return None;
        }

        let mut frontier = vec![dir.to_owned()];
        let mut results: Option<Vec<PathBuf>> = None;

        while let Some(dir) = frontier.pop() {
            let dir_entries = fs::read_dir(&dir).expect("Unable to iterate directory");
            for dir_entry in dir_entries {
                let dir_entry = dir_entry.expect("Cannot read dir entry").path();

                // Queue subdir for processing. Bravely assume lack of cycles.
                if dir_entry.is_dir() && !dirs_visited.contains(&dir_entry) {
                    frontier.push(dir_entry.to_owned());
                }

                // A file we've never seen before?!
                if !dir_entry.is_dir() && !self.entries.contains_key(&dir_entry) {
                    let new_files = results.get_or_insert_with(Vec::new);
                    new_files.push(dir_entry);
                }
            }
            dirs_visited.insert(dir.to_owned());
        }
        results
    }

    /// Set of files that have either changed themselves or had
    /// something they depend on change.
    ///
    /// Directories can be tracked but never report as changed.
    pub fn changed(&self) -> Result<Vec<Change>, io::Error> {
        let mut paths: Vec<&PathBuf> = self.entries.iter().map(|(k, _)| k).collect();

        let mut changes: Vec<Change> = Vec::new();

        // Add any new files in tracked dirs
        let mut dirs_visited: HashSet<PathBuf> = HashSet::new();
        let new_files: Vec<PathBuf> = paths
            .iter()
            .filter(|p| p.is_dir())
            .flat_map(|p| self.new_files(&mut dirs_visited, p).unwrap_or_default())
            .collect();
        new_files.iter().for_each(|p| paths.push(p));

        // Anything change 'round here?
        for path in paths {
            let updated_entry = DepGraphEntry::new(path)?;
            let has_changed = self
                .entries
                .get(path)
                .map(|maybe_current| maybe_current.as_ref() != Some(&updated_entry))
                .unwrap_or(true);

            if has_changed {
                changes.push(Change {
                    path: path.to_owned(),
                    updated_entry,
                });
            }
        }

        Ok(changes)
    }
}

#[cfg(test)]
mod tests {
    use std::{fs, ops::Add, path::PathBuf, time::Duration};

    use filetime::set_file_mtime;
    use tempfile::{tempdir, TempDir};

    use super::DepGraph;

    fn assert_no_changes(dg: &DepGraph) {
        assert_eq!(
            Vec::<&PathBuf>::new(),
            dg.changed()
                .unwrap()
                .iter()
                .map(|c| &c.path)
                .collect::<Vec<&PathBuf>>()
        )
    }

    #[test]
    fn detect_file_change() {
        let temp_dir = tempdir().unwrap();

        let file = temp_dir.path().join("a");
        fs::write(&file, "eh").unwrap();

        let mut dg = DepGraph::new();
        dg.track(&file, super::InitialState::NotChanged).unwrap();

        assert_no_changes(&dg);

        // Detect changed size
        fs::write(&file, "whoa").unwrap();
        let changes = dg.changed().unwrap();
        assert_eq!(
            vec![&file],
            changes.iter().map(|c| &c.path).collect::<Vec<&PathBuf>>()
        );

        // We're happy with that change
        dg.update(&changes);
        assert_no_changes(&dg);

        // Detect changed mtime
        let new_mtime = file
            .metadata()
            .unwrap()
            .modified()
            .unwrap()
            .add(Duration::from_secs(1));
        set_file_mtime(&file, new_mtime.into()).unwrap();
        let changes = dg.changed().unwrap();
        assert_eq!(
            vec![&file],
            changes.iter().map(|c| &c.path).collect::<Vec<&PathBuf>>()
        );
    }

    #[test]
    fn detect_dir_change() {
        let temp_dir = tempdir().unwrap();

        let subdir = temp_dir.path().join("glif");
        fs::create_dir(&subdir).unwrap();

        let f1 = temp_dir.path().join("fileA");
        let f2 = subdir.join("fileB");
        fs::write(&f1, "eh").unwrap();
        fs::write(&f2, "eh").unwrap();

        // Track the parent dir from it's current state
        let mut dg = DepGraph::new();
        dg.track(
            &temp_dir.path().to_path_buf(),
            super::InitialState::NotChanged,
        )
        .unwrap();

        // Notably, we should NOT report the files temp dir as changed
        // because we added the entire directory as unchanged and nothing
        // in it has changed since then
        assert_no_changes(&dg);

        // If we change or add files in the tracked dir that should count
        let f3 = subdir.join("fileC");
        fs::write(&f2, "eh+").unwrap();
        fs::write(&f3, "eh").unwrap();

        let changes = dg.changed().unwrap();
        assert_eq!(
            vec![&f2, &f3],
            changes.iter().map(|c| &c.path).collect::<Vec<&PathBuf>>()
        );
    }

    fn one_changed_file_one_not(temp_dir: &TempDir) -> (PathBuf, PathBuf, DepGraph) {
        let unchanged = temp_dir.path().join("a");
        let changed = temp_dir.path().join("b");

        fs::write(&unchanged, "eh").unwrap();
        fs::write(&changed, "eh").unwrap();

        let mut dg = DepGraph::new();
        dg.track(&unchanged, super::InitialState::NotChanged)
            .unwrap();
        dg.track(&changed, super::InitialState::Changed).unwrap();

        assert!(dg.contains(&changed));
        assert!(dg.contains(&unchanged));

        (changed, unchanged, dg)
    }

    #[test]
    fn track_with_initial_state() {
        let temp_dir = tempdir().unwrap();

        let (changed, _, mut dg) = one_changed_file_one_not(&temp_dir);

        let changes = dg.changed().unwrap();
        assert_eq!(
            vec![&changed],
            changes.iter().map(|c| &c.path).collect::<Vec<&PathBuf>>()
        );

        dg.update(&changes);
        let changes = dg.changed().unwrap();
        assert!(changes.is_empty());
    }

    #[test]
    fn read_write_bincode_entry() {}

    #[test]
    fn read_write_toml() {
        let temp_dir = tempdir().unwrap();

        let (changed, _, dg) = one_changed_file_one_not(&temp_dir);

        let toml = toml::ser::to_string_pretty(&dg).unwrap();
        let dg: DepGraph = toml::from_str(&toml).unwrap();

        assert_eq!(
            vec![&changed],
            dg.changed()
                .unwrap()
                .iter()
                .map(|c| &c.path)
                .collect::<Vec<&PathBuf>>()
        );
    }

    #[test]
    fn read_write_bincode() {
        let temp_dir = tempdir().unwrap();

        let (changed, _, dg) = one_changed_file_one_not(&temp_dir);

        let bc = bincode::serialize(&dg).unwrap();
        let dg: DepGraph = bincode::deserialize(&bc).unwrap();

        assert_eq!(
            vec![&changed],
            dg.changed()
                .unwrap()
                .iter()
                .map(|c| &c.path)
                .collect::<Vec<&PathBuf>>()
        );
    }
}
<commit_msg>Use an enum directly for state<commit_after>use filetime::FileTime;
use serde::{Deserialize, Serialize};

use std::{
    collections::{HashMap, HashSet},
    fs, io,
    path::{Path, PathBuf},
    vec,
};

/// Helps identify changes in a set of files.
#[derive(Serialize, Deserialize, Debug, Default, Clone)]
#[serde(from = "DepGraphSerdeRepr", into = "DepGraphSerdeRepr")]
pub struct DepGraph {
    entries: HashMap<PathBuf, PathState>,
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum PathState {
    Seen { mtime: FileTime, size: u64 },
    Unknown,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
struct DepGraphSerdeRepr {
    entries: Vec<PathStateSerdeRepr>,
}

impl From<DepGraphSerdeRepr> for DepGraph {
    fn from(from: DepGraphSerdeRepr) -> Self {
        DepGraph {
            entries: from
                .entries
                .iter()
                .map(|d| {
                    (
                        PathBuf::from(&d.path),
                        if d.has_graph_entry() {
                            PathState::Seen {
                                mtime: FileTime::from_unix_time(d.unix_seconds, d.nanos),
                                size: d.size,
                            }
                        } else {
                            PathState::Unknown
                        },
                    )
                })
                .collect(),
        }
    }
}

impl From<DepGraph> for DepGraphSerdeRepr {
    fn from(dg: DepGraph) -> Self {
        DepGraphSerdeRepr {
            entries: dg
                .entries
                .iter()
                .map(|e| {
                    let path = e.0.to_str().expect("Only UTF names please").to_string();
                    match e.1 {
                        PathState::Seen { mtime, size } => PathStateSerdeRepr {
                            path,
                            unix_seconds: mtime.unix_seconds(),
                            nanos: mtime.nanoseconds(),
                            size: *size,
                        },
                        PathState::Unknown => PathStateSerdeRepr {
                            path,
                            unix_seconds: 0,
                            nanos: 0,
                            size: 0,
                        },
                    }
                })
                .collect(),
        }
    }
}

/// The serde-friendly representation of a DepGraphEntry.
///
/// SystemTime lacks a platform independent representation we can
/// depend on so use FileTime's unix_seconds,nanos.
/// unix_seconds = nanos = size = 0 is used to represent lack of a DepGraphEntry.
#[derive(Serialize, Deserialize, Debug, Clone)]
struct PathStateSerdeRepr {
    path: String,
    unix_seconds: i64,
    nanos: u32,
    size: u64,
}

impl PathStateSerdeRepr {
    fn has_graph_entry(&self) -> bool {
        !(self.unix_seconds == 0 && self.nanos == 0 && self.size == 0)
    }
}

/// A new snapshot of the state of a file.
///
/// Always contains PathState::Seen.
pub struct Change {
    path: PathBuf,
    path_state: PathState,
}

pub enum InitialState {
    NotChanged,
    Changed,
}

impl PathState {
    fn of(path: &Path) -> Result<PathState, io::Error> {
        let metadata = path.metadata()?;
        Ok(PathState::Seen {
            mtime: FileTime::from_system_time(metadata.modified()?),
            size: metadata.len(),
        })
    }
}

impl DepGraph {
    pub fn new() -> DepGraph {
        Default::default()
    }
}

impl DepGraph {
    pub fn contains(&self, path: &PathBuf) -> bool {
        self.entries.contains_key(path)
    }

    pub fn track(&mut self, path: &PathBuf, default_state: InitialState) -> Result<(), io::Error> {
        if !self.entries.contains_key(path) {
            self.entries.insert(
                path.clone(),
                match default_state {
                    InitialState::NotChanged => PathState::of(path)?,
                    InitialState::Changed => PathState::Unknown,
                },
            );

            // For a dir to register unchanged we need to add it's current contents
            if let InitialState::NotChanged = default_state {
                if path.is_dir() {
                    let mut dirs_visited = HashSet::new();
                    if let Some(new_paths) = self.new_files(&mut dirs_visited, path) {
                        for new_path in new_paths {
                            self.entries
                                .insert(new_path.clone(), PathState::of(&new_path)?);
                        }
                    }
                }
            }
        }
        Ok(())
    }

    pub fn has_changed(&self, change: &Change) -> bool {
        // If we are tracking with different state or we're not tracking at all then you've changed
        let current_state = self
            .entries
            .get(&change.path)
            .unwrap_or(&PathState::Unknown);
        *current_state != change.path_state
    }

    pub fn update(&mut self, changes: &[Change]) {
        for change in changes {
            if self.has_changed(change) {
                self.entries.insert(change.path.clone(), change.path_state);
            }
        }
    }

    fn new_files(
        &self,
        dirs_visited: &mut HashSet<PathBuf>,
        dir: &PathBuf,
    ) -> Option<Vec<PathBuf>> {
        assert!(dir.is_dir());
        if dirs_visited.contains(dir) {
            return None;
        }

        let mut frontier = vec![dir.to_owned()];
        let mut results: Option<Vec<PathBuf>> = None;

        while let Some(dir) = frontier.pop() {
            let dir_entries = fs::read_dir(&dir).expect("Unable to iterate directory");
            for dir_entry in dir_entries {
                let dir_entry = dir_entry.expect("Cannot read dir entry").path();

                // Queue subdir for processing. Bravely assume lack of cycles.
                if dir_entry.is_dir() && !dirs_visited.contains(&dir_entry) {
                    frontier.push(dir_entry.to_owned());
                }

                // A file we've never seen before?!
                if !dir_entry.is_dir() && !self.entries.contains_key(&dir_entry) {
                    let new_files = results.get_or_insert_with(Vec::new);
                    new_files.push(dir_entry);
                }
            }
            dirs_visited.insert(dir.to_owned());
        }
        results
    }

    /// Set of files that have either changed themselves or had
    /// something they depend on change.
    ///
    /// Directories can be tracked but never report as changed.
    pub fn changed(&self) -> Result<Vec<Change>, io::Error> {
        let mut paths: Vec<&PathBuf> = self.entries.iter().map(|(k, _)| k).collect();

        let mut changes: Vec<Change> = Vec::new();

        // Add any new files in tracked dirs
        let mut dirs_visited: HashSet<PathBuf> = HashSet::new();
        let new_files: Vec<PathBuf> = paths
            .iter()
            .filter(|p| p.is_dir())
            .flat_map(|p| self.new_files(&mut dirs_visited, p).unwrap_or_default())
            .collect();
        new_files.iter().for_each(|p| paths.push(p));

        // Anything change 'round here?
        for path in paths {
            let path_state = PathState::of(path)?;
            let has_changed = self
                .entries
                .get(path)
                .map(|prior_state| *prior_state != path_state)
                .unwrap_or(true);

            if has_changed {
                changes.push(Change {
                    path: path.to_owned(),
                    path_state,
                });
            }
        }

        Ok(changes)
    }
}

#[cfg(test)]
mod tests {
    use std::{fs, ops::Add, path::PathBuf, time::Duration};

    use filetime::set_file_mtime;
    use tempfile::{tempdir, TempDir};

    use super::DepGraph;

    fn assert_no_changes(dg: &DepGraph) {
        assert_eq!(
            Vec::<&PathBuf>::new(),
            dg.changed()
                .unwrap()
                .iter()
                .map(|c| &c.path)
                .collect::<Vec<&PathBuf>>()
        )
    }

    #[test]
    fn detect_file_change() {
        let temp_dir = tempdir().unwrap();

        let file = temp_dir.path().join("a");
        fs::write(&file, "eh").unwrap();

        let mut dg = DepGraph::new();
        dg.track(&file, super::InitialState::NotChanged).unwrap();

        assert_no_changes(&dg);

        // Detect changed size
        fs::write(&file, "whoa").unwrap();
        let changes = dg.changed().unwrap();
        assert_eq!(
            vec![&file],
            changes.iter().map(|c| &c.path).collect::<Vec<&PathBuf>>()
        );

        // We're happy with that change
        dg.update(&changes);
        assert_no_changes(&dg);

        // Detect changed mtime
        let new_mtime = file
            .metadata()
            .unwrap()
            .modified()
            .unwrap()
            .add(Duration::from_secs(1));
        set_file_mtime(&file, new_mtime.into()).unwrap();
        let changes = dg.changed().unwrap();
        assert_eq!(
            vec![&file],
            changes.iter().map(|c| &c.path).collect::<Vec<&PathBuf>>()
        );
    }

    #[test]
    fn detect_dir_change() {
        let temp_dir = tempdir().unwrap();

        let subdir = temp_dir.path().join("glif");
        fs::create_dir(&subdir).unwrap();

        let f1 = temp_dir.path().join("fileA");
        let f2 = subdir.join("fileB");
        fs::write(&f1, "eh").unwrap();
        fs::write(&f2, "eh").unwrap();

        // Track the parent dir from it's current state
        let mut dg = DepGraph::new();
        dg.track(
            &temp_dir.path().to_path_buf(),
            super::InitialState::NotChanged,
        )
        .unwrap();

        // Notably, we should NOT report the files temp dir as changed
        // because we added the entire directory as unchanged and nothing
        // in it has changed since then
        assert_no_changes(&dg);

        // If we change or add files in the tracked dir that should count
        let f3 = subdir.join("fileC");
        fs::write(&f2, "eh+").unwrap();
        fs::write(&f3, "eh").unwrap();

        let changes = dg.changed().unwrap();
        assert_eq!(
            vec![&f2, &f3],
            changes.iter().map(|c| &c.path).collect::<Vec<&PathBuf>>()
        );
    }

    fn one_changed_file_one_not(temp_dir: &TempDir) -> (PathBuf, PathBuf, DepGraph) {
        let unchanged = temp_dir.path().join("a");
        let changed = temp_dir.path().join("b");

        fs::write(&unchanged, "eh").unwrap();
        fs::write(&changed, "eh").unwrap();

        let mut dg = DepGraph::new();
        dg.track(&unchanged, super::InitialState::NotChanged)
            .unwrap();
        dg.track(&changed, super::InitialState::Changed).unwrap();

        assert!(dg.contains(&changed));
        assert!(dg.contains(&unchanged));

        (changed, unchanged, dg)
    }

    #[test]
    fn track_with_initial_state() {
        let temp_dir = tempdir().unwrap();

        let (changed, _, mut dg) = one_changed_file_one_not(&temp_dir);

        let changes = dg.changed().unwrap();
        assert_eq!(
            vec![&changed],
            changes.iter().map(|c| &c.path).collect::<Vec<&PathBuf>>()
        );

        dg.update(&changes);
        let changes = dg.changed().unwrap();
        assert!(changes.is_empty());
    }

    #[test]
    fn read_write_bincode_entry() {}

    #[test]
    fn read_write_toml() {
        let temp_dir = tempdir().unwrap();

        let (changed, _, dg) = one_changed_file_one_not(&temp_dir);

        let toml = toml::ser::to_string_pretty(&dg).unwrap();
        let dg: DepGraph = toml::from_str(&toml).unwrap();

        assert_eq!(
            vec![&changed],
            dg.changed()
                .unwrap()
                .iter()
                .map(|c| &c.path)
                .collect::<Vec<&PathBuf>>()
        );
    }

    #[test]
    fn read_write_bincode() {
        let temp_dir = tempdir().unwrap();

        let (changed, _, dg) = one_changed_file_one_not(&temp_dir);

        let bc = bincode::serialize(&dg).unwrap();
        let dg: DepGraph = bincode::deserialize(&bc).unwrap();

        assert_eq!(
            vec![&changed],
            dg.changed()
                .unwrap()
                .iter()
                .map(|c| &c.path)
                .collect::<Vec<&PathBuf>>()
        );
    }
}
<|endoftext|>


<commit_before>use error::*;
use sysfs_pwm::Pwm;

const PERIOD: u32 = 20_000_000;
const MAX_DUTY_CYCLE: u32 = 2_000_000;
const MIN_DUTY_CYCLE: u32 = 1_000_000;

pub struct Rover {
    left: Pwm,
    right: Pwm,
}

impl Rover {
    /// Creates a new rovers with both motors enabled but stopped. The motors
    /// will be disabled and the underlying pwm drivers unexported when the
    /// rover is dropped.
    pub fn new(chip: u32, left_pin: u32, right_pin: u32) -> Result<Rover> {
        let left = Pwm::new(chip, left_pin).chain_err(|| "failed to create left motor")?;
        let right = Pwm::new(chip, right_pin).chain_err(|| "failed to create right motor")?;
        left.export().chain_err(|| "failed to export the left motor pwm channel")?;
        right.export().chain_err(|| "failed to export the right motor pwm channel")?;
        left.set_period_ns(PERIOD).chain_err(|| "failed to set period on left motor")?;
        right.set_period_ns(PERIOD).chain_err(|| "failed to set period on right motor")?;
        Ok(Rover {
            left: left,
            right: right,
        })
    }

    /// Enables/disables the motor. When disabled they keep their current
    /// speed and their speed can still be set but they will not move until
    /// enabled.
    pub fn enable(&self, enabled: bool) -> Result<()> {
        self.left.enable(enabled).chain_err(|| "failed to enable left motor")?;
        self.right.enable(enabled).chain_err(|| "failed to enable right motor")
    }

    /// Converts a speed between -100 (full reverse) and 100 (full forward)
    /// to a duty cycle.
    fn speed_to_duty_cycle(speed: i8) -> u32 {
        let duty_cycle = (((speed as i32 * 10000) + MIN_DUTY_CYCLE as i32) as u32 / 2) +
                         MIN_DUTY_CYCLE;
        if duty_cycle > MAX_DUTY_CYCLE {
            return MAX_DUTY_CYCLE;
        }
        if duty_cycle < MIN_DUTY_CYCLE {
            return MIN_DUTY_CYCLE;
        }
        duty_cycle
    }

    /// Sets the speed of the left motor. Can be any value between -100 (full
    /// reverse) and 100 (full forward), values above or below these limits will
    /// be to to the limit.
    pub fn set_left_speed(&self, speed: i8) -> Result<()> {
        self.left
            .set_duty_cycle_ns(Rover::speed_to_duty_cycle(-speed))
            .chain_err(|| "failed to set duty on left motor")
    }

    /// Sets the speed of the right motor. Can be any value between -100 (full
    /// reverse) and 100 (full forward), values above or below these limits will
    /// be to to the limit.
    pub fn set_right_speed(&self, speed: i8) -> Result<()> {
        self.right
            .set_duty_cycle_ns(Rover::speed_to_duty_cycle(speed))
            .chain_err(|| "failed to set duty on left motor")
    }

    /// Stops both the motors, equlivent to setting their speeds to 0.
    pub fn stop(&self) -> Result<()> {
        self.set_left_speed(0)?;
        self.set_right_speed(0)
    }

    /// Sets the speed of left and right motor. Can be any value between -100 (full
    /// reverse) and 100 (full forward), values above or below these limits will
    /// be to to the limit.
    pub fn set_speed(&self, left: i8, right: i8) -> Result<()> {
        self.set_left_speed(left)?;
        self.set_right_speed(right)
    }

    /// Unexports the motors so they can no longer be used
    pub fn unexport(self) -> Result<()> {
        self.left.enable(false).chain_err(|| "failed to disable left motor")?;
        self.right.enable(false).chain_err(|| "failed to disable right motor")?;
        self.left.unexport().chain_err(|| "failed to unexport left motor")?;
        self.right.unexport().chain_err(|| "failed to unexport right motor")
    }
}
<commit_msg>Refactors the rover<commit_after>use error::*;
use sysfs_pwm::Pwm;

const PERIOD: u32 = 20_000_000;
const MAX_DUTY_CYCLE: u32 = 2_000_000;
const MIN_DUTY_CYCLE: u32 = 1_000_000;

pub struct Rover {
    left: Pwm,
    right: Pwm,
}

impl Rover {
    /// Creates a new rovers with both motors enabled but stopped. The motors
    /// will be disabled and the underlying pwm drivers unexported when the
    /// rover is dropped.
    pub fn new(chip: u32, left_pin: u32, right_pin: u32) -> Result<Rover> {
        let left = Pwm::new(chip, left_pin).chain_err(|| "failed to create left motor")?;
        let right = Pwm::new(chip, right_pin).chain_err(|| "failed to create right motor")?;
        Ok(Rover {
            left: left,
            right: right,
        })
    }

    /// Exports and setup the period for the servos.
    pub fn export(&self) -> Result<()> {
        self.left.export().chain_err(|| "failed to export the left motor pwm channel")?;
        self.right.export().chain_err(|| "failed to export the right motor pwm channel")?;
        self.left.set_period_ns(PERIOD).chain_err(|| "failed to set period on left motor")?;
        self.right.set_period_ns(PERIOD).chain_err(|| "failed to set period on right motor")
    }

    /// Enables/disables the motor. When disabled they keep their current
    /// speed and their speed can still be set but they will not move until
    /// enabled.
    pub fn enable(&self, enabled: bool) -> Result<()> {
        self.left.enable(enabled).chain_err(|| "failed to enable left motor")?;
        self.right.enable(enabled).chain_err(|| "failed to enable right motor")
    }

    /// Converts a speed between -100 (full reverse) and 100 (full forward)
    /// to a duty cycle.
    fn speed_to_duty_cycle(speed: i8) -> u32 {
        let duty_cycle = (((speed as i32 * 10000) + MIN_DUTY_CYCLE as i32) as u32 / 2) +
                         MIN_DUTY_CYCLE;
        if duty_cycle > MAX_DUTY_CYCLE {
            return MAX_DUTY_CYCLE;
        }
        if duty_cycle < MIN_DUTY_CYCLE {
            return MIN_DUTY_CYCLE;
        }
        duty_cycle
    }

    /// Sets the speed of the left motor. Can be any value between -100 (full
    /// reverse) and 100 (full forward), values above or below these limits will
    /// be to to the limit.
    pub fn set_left_speed(&self, speed: i8) -> Result<()> {
        self.left
            .set_duty_cycle_ns(Rover::speed_to_duty_cycle(-speed))
            .chain_err(|| "failed to set duty on left motor")
    }

    /// Sets the speed of the right motor. Can be any value between -100 (full
    /// reverse) and 100 (full forward), values above or below these limits will
    /// be to to the limit.
    pub fn set_right_speed(&self, speed: i8) -> Result<()> {
        self.right
            .set_duty_cycle_ns(Rover::speed_to_duty_cycle(speed))
            .chain_err(|| "failed to set duty on left motor")
    }

    /// Stops both the motors, equlivent to setting their speeds to 0.
    pub fn stop(&self) -> Result<()> {
        self.set_left_speed(0)?;
        self.set_right_speed(0)
    }

    /// Sets the speed of left and right motor. Can be any value between -100 (full
    /// reverse) and 100 (full forward), values above or below these limits will
    /// be to to the limit.
    pub fn set_speed(&self, left: i8, right: i8) -> Result<()> {
        self.set_left_speed(left)?;
        self.set_right_speed(right)
    }

    /// Unexports the motors so they can no longer be used
    pub fn unexport(&self) -> Result<()> {
        self.left.unexport().chain_err(|| "failed to unexport left motor")?;
        self.right.unexport().chain_err(|| "failed to unexport right motor")
    }
}<|endoftext|>