<commit_before>//! Iron's HTTP Response representation and associated methods.

use std::io::{IoResult, File, MemReader};
use std::path::BytesContainer;

use http::status::{Status, InternalServerError, NotFound};
use http::headers::response::HeaderCollection;
use http::headers::content_type::MediaType;

pub use HttpResponse = http::server::response::ResponseWriter;

use contenttype::get_content_type;

/// The response representation given to `Middleware`
pub struct Response<'a, 'b> {
    http_res: &'a mut HttpResponse<'b>,

    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Box<Reader>,

    /// The headers of the response.
    pub headers: Box<HeaderCollection>,

    /// The response status-code.
    pub status: Option<Status>
}

impl<'a, 'b> Response<'a, 'b> {
    /// Construct a Response from an HttpResponse reference
    pub fn from_http(http_res: &'a mut HttpResponse<'b>) -> Response<'a, 'b> {
        Response {
            headers: http_res.headers.clone(),
            status: None, // Start with no response code.
            http_res: http_res,
            body: box MemReader::new(vec![]) as Box<Reader>
        }
    }

    /// Write the `Status` and data to the `Response`.
    pub fn serve<S: BytesContainer>(&mut self, status: Status, body: S) {
        self.status = Some(status);
        self.body = box MemReader::new(body.container_as_bytes().to_vec()) as Box<Reader>;
    }

    /// Serve the file located at `path`.
    ///
    /// This usually means a request has been handled, and `Middleware`
    /// may want to `Unwind` after a file is served. If the status should be
    /// anything other than `200`, `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will error if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. `Middleware` should handle this gracefully.
    pub fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let file = try!(File::open(path));
        self.headers.content_type = path.extension_str().and_then(get_content_type);
        self.body = box file as Box<Reader>;
        Ok(())
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(mut self) {
        self.http_res.headers = self.headers.clone();

        // Default to a 404 if no response code was set
        self.http_res.status = self.status.clone().unwrap_or(NotFound);

        // Read the body into the http_res body
        let _ = match self.body.read_to_string() {
            Ok(body) => {
                let plain_txt: MediaType = get_content_type("txt").unwrap();
                self.http_res.write_content_auto(
                    self.headers.content_type.clone().unwrap_or(plain_txt),
                    body
                )
            },
            Err(e) => Err(e)
        // Catch errors from reading + writing
        }.map_err(|e| {
            error!("Error reading/writing body: {}", e);
            self.http_res.status = InternalServerError;
            let _ = self.http_res.write(b"Internal Server Error")
                .map_err(|e| error!("Error writing error message: {}", e));
        });
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_content_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<commit_msg>(feat) Set the status to 200 on a succesful file read.<commit_after>//! Iron's HTTP Response representation and associated methods.

use std::io::{IoResult, File, MemReader};
use std::path::BytesContainer;

use http::status::{Status, InternalServerError, NotFound};
use OkStatus = http::status::Ok;
use http::headers::response::HeaderCollection;
use http::headers::content_type::MediaType;

pub use HttpResponse = http::server::response::ResponseWriter;

use contenttype::get_content_type;

/// The response representation given to `Middleware`
pub struct Response<'a, 'b> {
    http_res: &'a mut HttpResponse<'b>,

    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Box<Reader>,

    /// The headers of the response.
    pub headers: Box<HeaderCollection>,

    /// The response status-code.
    pub status: Option<Status>
}

impl<'a, 'b> Response<'a, 'b> {
    /// Construct a Response from an HttpResponse reference
    pub fn from_http(http_res: &'a mut HttpResponse<'b>) -> Response<'a, 'b> {
        Response {
            headers: http_res.headers.clone(),
            status: None, // Start with no response code.
            http_res: http_res,
            body: box MemReader::new(vec![]) as Box<Reader>
        }
    }

    /// Write the `Status` and data to the `Response`.
    pub fn serve<S: BytesContainer>(&mut self, status: Status, body: S) {
        self.status = Some(status);
        self.body = box MemReader::new(body.container_as_bytes().to_vec()) as Box<Reader>;
    }

    /// Serve the file located at `path`.
    ///
    /// This usually means a request has been handled, and `Middleware`
    /// may want to `Unwind` after a file is served. If the status should be
    /// anything other than `200`, `Middleware` must set it, including in
    /// the case of an `Err`.
    ///
    /// `serve_file` will error if the file does not exist, the process
    /// does not have correct permissions, or it has other issues in reading
    /// from the file. `Middleware` should handle this gracefully.
    pub fn serve_file(&mut self, path: &Path) -> IoResult<()> {
        let file = try!(File::open(path));
        self.headers.content_type = path.extension_str().and_then(get_content_type);
        self.body = box file as Box<Reader>;
        self.status = Some(OkStatus);
        Ok(())
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(mut self) {
        self.http_res.headers = self.headers.clone();

        // Default to a 404 if no response code was set
        self.http_res.status = self.status.clone().unwrap_or(NotFound);

        // Read the body into the http_res body
        let _ = match self.body.read_to_string() {
            Ok(body) => {
                let plain_txt: MediaType = get_content_type("txt").unwrap();
                self.http_res.write_content_auto(
                    self.headers.content_type.clone().unwrap_or(plain_txt),
                    body
                )
            },
            Err(e) => Err(e)
        // Catch errors from reading + writing
        }.map_err(|e| {
            error!("Error reading/writing body: {}", e);
            self.http_res.status = InternalServerError;
            let _ = self.http_res.write(b"Internal Server Error")
                .map_err(|e| error!("Error writing error message: {}", e));
        });
    }
}

#[test]
fn matches_content_type () {
    let path = &Path::new("test.txt");
    let content_type = path.extension_str().and_then(get_content_type).unwrap();

    assert_eq!(content_type.type_.as_slice(), "text");
    assert_eq!(content_type.subtype.as_slice(), "plain");
}
<|endoftext|>


<commit_before>//! Iron's HTTP Response representation and associated methods.

use std::io::{self, Write};
use std::fmt::{self, Debug};
use std::fs::File;

use typemap::TypeMap;
use plugin::Extensible;
use modifier::{Set, Modifier};
use hyper::header::Headers;

use status::{self, Status};
use {Plugin, headers};

pub use hyper::server::response::Response as HttpResponse;
use hyper::net::{Fresh, Streaming};

/// A `Write`r of HTTP response bodies.
pub struct ResponseBody<'a>(HttpResponse<'a, Streaming>);

impl<'a> Write for ResponseBody<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

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

/// A trait which writes the body of an HTTP response.
pub trait WriteBody {
    /// Writes the body to the provided `ResponseBody`.
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()>;
}

impl WriteBody for String {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        self.as_bytes().write_body(res)
    }
}

impl<'a> WriteBody for &'a str {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        self.as_bytes().write_body(res)
    }
}

impl WriteBody for Vec<u8> {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        res.write_all(self)
    }
}

impl<'a> WriteBody for &'a [u8] {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        res.write_all(self)
    }
}

impl WriteBody for File {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res).map(|_| ())
    }
}

/* Needs specialization :(
impl<R: Read> WriteBody for R {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res)
    }
}
*/

/// The response representation given to `Middleware`
pub struct Response {
    /// The response status-code.
    pub status: Option<Status>,

    /// The headers of the response.
    pub headers: Headers,

    /// A TypeMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: TypeMap,

    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Option<Box<WriteBody + Send>>
}

impl Response {
    /// Construct a blank Response
    pub fn new() -> Response {
        Response {
            status: None, // Start with no response code.
            body: None, // Start with no body.
            headers: Headers::new(),
            extensions: TypeMap::new()
        }
    }

    /// Construct a Response with the specified modifier pre-applied.
    pub fn with<M: Modifier<Response>>(m: M) -> Response {
        Response::new().set(m)
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, mut http_res: HttpResponse<Fresh>) {
        *http_res.headers_mut() = self.headers;

        // Default to a 404 if no response code was set
        *http_res.status_mut() = self.status.clone().unwrap_or(status::NotFound);

        let out = match self.body {
            Some(body) => write_with_body(http_res, body),
            None => {
                http_res.headers_mut().set(headers::ContentLength(0));
                http_res.start().and_then(|res| res.end())
            }
        };

        match out {
            Err(e) => {
                error!("Error writing response: {}", e);
            },
            _ => {}
        }
    }
}

fn write_with_body(mut res: HttpResponse<Fresh>, mut body: Box<WriteBody + Send>)
                   -> io::Result<()> {
    let content_type = res.headers().get::<headers::ContentType>()
                           .map(|cx| cx.clone())
                           .unwrap_or_else(|| headers::ContentType("text/plain".parse().unwrap()));
    res.headers_mut().set(content_type);

    let mut res = ResponseBody(try!(res.start()));
    try!(body.write_body(&mut res));
    res.0.end()
}

impl Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "HTTP/1.1 {} {}\n{}",
            self.status.unwrap_or(status::NotFound),
            self.status.unwrap_or(status::NotFound).canonical_reason().unwrap(),
            self.headers
        )
    }
}

impl fmt::Display for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

// Allow plugins to attach to responses.
impl Extensible for Response {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl Plugin for Response {}
impl Set for Response {}

<commit_msg>(feat) Tweak the representation of ResponseBody to allow mocking.<commit_after>//! Iron's HTTP Response representation and associated methods.

use std::io::{self, Write};
use std::fmt::{self, Debug};
use std::fs::File;

use typemap::TypeMap;
use plugin::Extensible;
use modifier::{Set, Modifier};
use hyper::header::Headers;

use status::{self, Status};
use {Plugin, headers};

pub use hyper::server::response::Response as HttpResponse;
use hyper::net::Fresh;

/// A `Write`r of HTTP response bodies.
pub struct ResponseBody<'a>(Box<Write + 'a>);

impl<'a> ResponseBody<'a> {
    /// Create a new ResponseBody, mostly for use in mocking.
    pub fn new<W: Write + 'a>(writer: W) -> ResponseBody<'a> {
        ResponseBody(Box::new(writer))
    }
}

impl<'a> Write for ResponseBody<'a> {
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.0.write(buf)
    }

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

/// A trait which writes the body of an HTTP response.
pub trait WriteBody {
    /// Writes the body to the provided `ResponseBody`.
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()>;
}

impl WriteBody for String {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        self.as_bytes().write_body(res)
    }
}

impl<'a> WriteBody for &'a str {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        self.as_bytes().write_body(res)
    }
}

impl WriteBody for Vec<u8> {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        res.write_all(self)
    }
}

impl<'a> WriteBody for &'a [u8] {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        res.write_all(self)
    }
}

impl WriteBody for File {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res).map(|_| ())
    }
}

/* Needs specialization :(
impl<R: Read> WriteBody for R {
    fn write_body(&mut self, res: &mut ResponseBody) -> io::Result<()> {
        io::copy(self, res)
    }
}
*/

/// The response representation given to `Middleware`
pub struct Response {
    /// The response status-code.
    pub status: Option<Status>,

    /// The headers of the response.
    pub headers: Headers,

    /// A TypeMap to be used as an extensible storage for data
    /// associated with this Response.
    pub extensions: TypeMap,

    /// The body of the response.
    ///
    /// This is a Reader for generality, most data should
    /// be sent using either `serve` or `serve_file`.
    ///
    /// Arbitrary Readers can be sent by assigning to body.
    pub body: Option<Box<WriteBody + Send>>
}

impl Response {
    /// Construct a blank Response
    pub fn new() -> Response {
        Response {
            status: None, // Start with no response code.
            body: None, // Start with no body.
            headers: Headers::new(),
            extensions: TypeMap::new()
        }
    }

    /// Construct a Response with the specified modifier pre-applied.
    pub fn with<M: Modifier<Response>>(m: M) -> Response {
        Response::new().set(m)
    }

    // `write_back` is used to put all the data added to `self`
    // back onto an `HttpResponse` so that it is sent back to the
    // client.
    //
    // `write_back` consumes the `Response`.
    #[doc(hidden)]
    pub fn write_back(self, mut http_res: HttpResponse<Fresh>) {
        *http_res.headers_mut() = self.headers;

        // Default to a 404 if no response code was set
        *http_res.status_mut() = self.status.clone().unwrap_or(status::NotFound);

        let out = match self.body {
            Some(body) => write_with_body(http_res, body),
            None => {
                http_res.headers_mut().set(headers::ContentLength(0));
                http_res.start().and_then(|res| res.end())
            }
        };

        match out {
            Err(e) => {
                error!("Error writing response: {}", e);
            },
            _ => {}
        }
    }
}

fn write_with_body(mut res: HttpResponse<Fresh>, mut body: Box<WriteBody + Send>)
                   -> io::Result<()> {
    let content_type = res.headers().get::<headers::ContentType>()
                           .map(|cx| cx.clone())
                           .unwrap_or_else(|| headers::ContentType("text/plain".parse().unwrap()));
    res.headers_mut().set(content_type);

    let mut raw_res = try!(res.start());
    try!(body.write_body(&mut ResponseBody::new(&mut raw_res)));
    raw_res.end()
}

impl Debug for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        writeln!(f, "HTTP/1.1 {} {}\n{}",
            self.status.unwrap_or(status::NotFound),
            self.status.unwrap_or(status::NotFound).canonical_reason().unwrap(),
            self.headers
        )
    }
}

impl fmt::Display for Response {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        Debug::fmt(self, f)
    }
}

// Allow plugins to attach to responses.
impl Extensible for Response {
    fn extensions(&self) -> &TypeMap {
        &self.extensions
    }

    fn extensions_mut(&mut self) -> &mut TypeMap {
        &mut self.extensions
    }
}

impl Plugin for Response {}
impl Set for Response {}

<|endoftext|>


<commit_before>use std::num::ParseIntError;

use super::results::{CabotResult, CabotError};

pub struct Response {
    status_code: usize,
    status_line: String,
    headers: Vec<String>,
    body: Option<Vec<u8>>,
}

impl Response {
    fn new(status_code: usize,
           status_line: String,
           headers: Vec<String>,
           body: Option<Vec<u8>>)
           -> Response {
        Response {
            status_code: status_code,
            status_line: status_line,
            headers: headers,
            body: body,
        }
    }

    pub fn status_code(&self) -> usize {
        self.status_code
    }

    pub fn status_line(&self) -> &str {
        self.status_line.as_str()
    }

    pub fn headers(&self) -> Vec<&str> {
        let headers: Vec<&str> = self.headers.iter().map(|s| s.as_ref()).collect();
        headers
    }

    pub fn body(&self) -> Option<&[u8]> {
        match self.body {
            None => None,
            Some(ref body) => {
                Some(body.as_slice())
            }
        }
    }

    pub fn body_as_string(&self) -> CabotResult<String> {
        let body = match self.body {
            None => "".to_owned(),
            Some(ref body) => {
                let mut body_vec: Vec<u8> = Vec::new();
                body_vec.extend_from_slice(body);
                let body_str = String::from_utf8(body_vec);
                if body_str.is_err() {
                    return Err(CabotError::EncodingError(format!("Cannot decode utf8: {}", body_str.unwrap_err())))
                }
                body_str.unwrap()
            }
        };
        Ok(body)
    }
}

#[derive(Debug)]
pub struct ResponseBuilder {
    status_line: Option<String>,
    headers: Vec<String>,
    body: Option<Vec<u8>>,
}

impl ResponseBuilder {
    pub fn new() -> Self {
        ResponseBuilder {
            status_line: None,
            headers: Vec::new(),
            body: None,
        }
    }

    pub fn set_status_line(mut self, status_line: &str) -> Self {
        self.status_line = Some(status_line.to_string());
        self
    }

    pub fn add_header(mut self, header: &str) -> Self {
        self.headers.push(header.to_owned());
        self
    }

    pub fn set_body(mut self, buf: &[u8]) -> Self {
        let mut body = Vec::with_capacity(buf.len());
        body.extend_from_slice(buf);
        self.body = Some(body);
        self
    }

    pub fn build(&self) -> CabotResult<Response> {
        if self.status_line.is_none() {
            return Err(CabotError::HttpResponseParseError("No Status Line".to_owned()));
        }

        let status_line = self.status_line.as_ref().unwrap();
        let mut vec_status_line: Vec<&str> = status_line.splitn(3, " ").collect();

        if vec_status_line.len() != 3 {
            return Err(CabotError::HttpResponseParseError(format!("Malformed Status Line: {}", status_line)));
        }

        let http_version = vec_status_line.remove(0);
        if !http_version.starts_with("HTTP/") {
            return Err(CabotError::HttpResponseParseError(format!("Unkown Protocol in Status Line: {}", status_line)));
        }

        let status_code = vec_status_line.get(0).unwrap();
        let status_code: Result<usize, ParseIntError> = status_code.parse();
        if status_code.is_err() {
            return Err(CabotError::HttpResponseParseError(format!("Malformed status code: {}", status_line)));
        }
        let status_code = status_code.unwrap();
        let status_line = vec_status_line.as_slice().join(" ");

        Ok(Response::new(status_code,
                         status_line,
                         self.headers.to_owned(),
                         self.body.to_owned()))
    }
}
<commit_msg>Add tests for response<commit_after>use std::num::ParseIntError;

use super::results::{CabotResult, CabotError};

#[derive(Debug)]
pub struct Response {
    status_code: usize,
    status_line: String,
    headers: Vec<String>,
    body: Option<Vec<u8>>,
}

impl Response {
    fn new(status_code: usize,
           status_line: String,
           headers: Vec<String>,
           body: Option<Vec<u8>>)
           -> Response {
        Response {
            status_code: status_code,
            status_line: status_line,
            headers: headers,
            body: body,
        }
    }

    pub fn status_code(&self) -> usize {
        self.status_code
    }

    pub fn status_line(&self) -> &str {
        self.status_line.as_str()
    }

    pub fn headers(&self) -> Vec<&str> {
        let headers: Vec<&str> = self.headers.iter().map(|s| s.as_ref()).collect();
        headers
    }

    pub fn body(&self) -> Option<&[u8]> {
        match self.body {
            None => None,
            Some(ref body) => {
                Some(body.as_slice())
            }
        }
    }

    pub fn body_as_string(&self) -> CabotResult<String> {
        let body = match self.body {
            None => "".to_owned(),
            Some(ref body) => {
                let mut body_vec: Vec<u8> = Vec::new();
                body_vec.extend_from_slice(body);
                let body_str = String::from_utf8(body_vec);
                if body_str.is_err() {
                    return Err(CabotError::EncodingError(format!("Cannot decode utf8: {}", body_str.unwrap_err())))
                }
                body_str.unwrap()
            }
        };
        Ok(body)
    }
}

#[derive(Debug)]
pub struct ResponseBuilder {
    status_line: Option<String>,
    headers: Vec<String>,
    body: Option<Vec<u8>>,
}

impl ResponseBuilder {
    pub fn new() -> Self {
        ResponseBuilder {
            status_line: None,
            headers: Vec::new(),
            body: None,
        }
    }

    pub fn set_status_line(mut self, status_line: &str) -> Self {
        self.status_line = Some(status_line.to_string());
        self
    }

    pub fn add_header(mut self, header: &str) -> Self {
        self.headers.push(header.to_owned());
        self
    }

    pub fn set_body(mut self, buf: &[u8]) -> Self {
        let mut body = Vec::with_capacity(buf.len());
        body.extend_from_slice(buf);
        self.body = Some(body);
        self
    }

    pub fn build(&self) -> CabotResult<Response> {
        if self.status_line.is_none() {
            return Err(CabotError::HttpResponseParseError("No Status Line".to_owned()));
        }

        let status_line = self.status_line.as_ref().unwrap();
        let mut vec_status_line: Vec<&str> = status_line.splitn(3, " ").collect();

        if vec_status_line.len() != 3 {
            return Err(CabotError::HttpResponseParseError(format!("Malformed Status Line: {}", status_line)));
        }

        let http_version = vec_status_line.remove(0);
        if !http_version.starts_with("HTTP/") {
            return Err(CabotError::HttpResponseParseError(format!("Unkown Protocol in Status Line: {}", status_line)));
        }

        let status_code = vec_status_line.get(0).unwrap();
        let status_code: Result<usize, ParseIntError> = status_code.parse();
        if status_code.is_err() {
            return Err(CabotError::HttpResponseParseError(format!("Malformed status code: {}", status_line)));
        }
        let status_code = status_code.unwrap();
        let status_line = vec_status_line.as_slice().join(" ");

        Ok(Response::new(status_code,
                         status_line,
                         self.headers.to_owned(),
                         self.body.to_owned()))
    }
}

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

    #[test]
    fn test_response_ok() {
        let response = Response::new(
            200,
            "200 Ok".to_owned(),
            vec!["Content-Type: application/json".to_owned()],
            Some(vec![123, 125]));

        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        assert_eq!(response.headers(), &["Content-Type: application/json"]);
        let body: &[u8] = &[123, 125];
        assert_eq!(response.body(), Some(body));
        assert_eq!(response.body_as_string().unwrap(), "{}");
    }

    #[test]
    fn test_response_ok_no_body() {
        let response = Response::new(
            204,
            "204 No Content".to_owned(),
            vec![],
            None);

        assert_eq!(response.status_code(), 204);
        assert_eq!(response.status_line(), "204 No Content");
        let headers: &[&str] = &[];
        assert_eq!(response.headers(), headers);
        assert_eq!(response.body(), None);
        assert_eq!(response.body_as_string().unwrap(), "".to_string());
    }

    #[test]
    fn test_build_response_ok() {
        let response = ResponseBuilder::new()
            .set_status_line("HTTP/1.1 200 Ok")
            .add_header("Content-Type: application/json")
            .set_body(&[123, 125])
            .build()
            .unwrap();

        assert_eq!(response.status_code(), 200);
        assert_eq!(response.status_line(), "200 Ok");
        assert_eq!(response.headers(), &["Content-Type: application/json"]);
        let body: &[u8] = &[123, 125];
        assert_eq!(response.body(), Some(body));
        assert_eq!(response.body_as_string().unwrap(), "{}");
    }

}<|endoftext|>


<commit_before>//! Generic functions for working with (primarily nucleic acid) sequences
use std::borrow::Cow;

use memchr::memchr2;

use crate::bitkmer::BitNuclKmer;
use crate::kmer::{CanonicalKmers, Kmers};

/// Transform a nucleic acid sequence into its "normalized" form.
///
/// The normalized form is:
///  - only AGCTN and possibly - (for gaps)
///  - strip out any whitespace or line endings
///  - lowercase versions of these are uppercased
///  - U is converted to T (make everything a DNA sequence)
///  - some other punctuation is converted to gaps
///  - IUPAC bases may be converted to N's depending on the parameter passed in
///  - everything else is considered a N
pub fn normalize(seq: &[u8], allow_iupac: bool) -> Option<Vec<u8>> {
    let mut buf: Vec<u8> = Vec::with_capacity(seq.len());
    let mut changed: bool = false;

    for n in seq.iter() {
        let (new_char, char_changed) = match (*n, allow_iupac) {
            c @ (b'A', _)
            | c @ (b'C', _)
            | c @ (b'G', _)
            | c @ (b'T', _)
            | c @ (b'N', _)
            | c @ (b'-', _) => (c.0, false),
            (b'a', _) => (b'A', true),
            (b'c', _) => (b'C', true),
            (b'g', _) => (b'G', true),
            // normalize uridine to thymine
            (b't', _) | (b'u', _) | (b'U', _) => (b'T', true),
            // normalize gaps
            (b'.', _) | (b'~', _) => (b'-', true),
            // logic for IUPAC bases (a little messy)
            c @ (b'B', true)
            | c @ (b'D', true)
            | c @ (b'H', true)
            | c @ (b'V', true)
            | c @ (b'R', true)
            | c @ (b'Y', true)
            | c @ (b'S', true)
            | c @ (b'W', true)
            | c @ (b'K', true)
            | c @ (b'M', true) => (c.0, false),
            (b'b', true) => (b'B', true),
            (b'd', true) => (b'D', true),
            (b'h', true) => (b'H', true),
            (b'v', true) => (b'V', true),
            (b'r', true) => (b'R', true),
            (b'y', true) => (b'Y', true),
            (b's', true) => (b'S', true),
            (b'w', true) => (b'W', true),
            (b'k', true) => (b'K', true),
            (b'm', true) => (b'M', true),
            // remove all whitespace and line endings
            (b' ', _) | (b'\t', _) | (b'\r', _) | (b'\n', _) => (b' ', true),
            // everything else is an N
            _ => (b'N', true),
        };
        changed = changed || char_changed;
        if new_char != b' ' {
            buf.push(new_char);
        }
    }
    if changed {
        Some(buf)
    } else {
        None
    }
}

/// Returns the complementary base for a given IUPAC base code.
///
/// Does not work for RNA sequences (maybe we should raise an error or something?)
#[inline]
pub fn complement(n: u8) -> u8 {
    match n {
        b'a' => b't',
        b'A' => b'T',
        b'c' => b'g',
        b'C' => b'G',
        b'g' => b'c',
        b'G' => b'C',
        b't' => b'a',
        b'T' => b'A',

        // IUPAC codes
        b'r' => b'y',
        b'y' => b'r',
        b'k' => b'm',
        b'm' => b'k',
        b'b' => b'v',
        b'v' => b'b',
        b'd' => b'h',
        b'h' => b'd',
        b's' => b's',
        b'w' => b'w',
        b'R' => b'Y',
        b'Y' => b'R',
        b'K' => b'M',
        b'M' => b'K',
        b'B' => b'V',
        b'V' => b'B',
        b'D' => b'H',
        b'H' => b'D',
        b'S' => b'S',
        b'W' => b'W',

        // anything else just pass through
        // 'u' | 'U' => panic!("Does not support complements of U"),
        x => x,
    }
}

/// Taking in a sequence string, return the canonical form of the sequence
/// (e.g. the lexigraphically lowest of either the original sequence or its
/// reverse complement)
pub fn canonical(seq: &[u8]) -> Cow<[u8]> {
    let mut buf: Vec<u8> = Vec::with_capacity(seq.len());
    // enough just keeps our comparisons from happening after they need to
    let mut enough = false;
    let mut original_was_canonical = false;

    // loop through the kmer and its reverse complement simultaneously
    for (rn, n) in seq.iter().rev().map(|n| complement(*n)).zip(seq.iter()) {
        buf.push(rn);
        if !enough && (*n < rn) {
            original_was_canonical = true;
            break;
        } else if !enough && (rn < *n) {
            enough = true;
        }
        // unstated if branch: if rn == n, keep comparing
    }
    match (original_was_canonical, enough) {
        (true, true) => panic!("Bug: should never set original_was_canonical if enough == true"),
        (true, false) => seq.into(),
        (false, true) => buf.into(),
        // the sequences were completely equal, return the ref
        (false, false) => seq.into(),
    }
}

/// Find the lexigraphically smallest substring of `seq` of length `length`
///
/// There's probably a faster algorithm for this somewhere...
pub fn minimizer(seq: &[u8], length: usize) -> Cow<[u8]> {
    let reverse_complement: Vec<u8> = seq.iter().rev().map(|n| complement(*n)).collect();
    let mut minmer = Cow::Borrowed(&seq[..length]);

    for (kmer, rc_kmer) in seq.windows(length).zip(reverse_complement.windows(length)) {
        if *kmer < minmer[..] {
            minmer = kmer.into();
        }
        if *rc_kmer < minmer[..] {
            minmer = rc_kmer.to_vec().into();
        }
    }
    minmer
}

/// A generic FASTX record that also abstracts over several logical operations
/// that can be performed on nucleic acid sequences.
pub trait Sequence<'a> {
    fn sequence(&'a self) -> &'a [u8];

    /// Remove newlines from the sequence; this handles `\r`, `\n`, and `\r\n`
    /// and removes internal newlines in addition to ones at the end.
    /// Primarily used for FASTA multiline records, but can also help process
    /// (the much rarer) multiline FASTQs. Always use before iteration methods
    /// below to ensure no newlines are being returned with e.g. `.kmers`.
    fn strip_returns(&'a self) -> Cow<'a, [u8]> {
        let seq = self.sequence();

        // first part is a fast check to see if we need to do any allocations
        let mut i;
        match memchr2(b'\r', b'\n', &seq) {
            Some(break_loc) => i = break_loc,
            None => return seq.into(),
        }
        // we found a newline; create a new buffer and stripping out newlines
        // and writing into it
        let mut new_buf = Vec::with_capacity(seq.len() - 1);
        new_buf.extend_from_slice(&seq[..i]);
        while i < seq.len() {
            match memchr2(b'\r', b'\n', &seq[i..]) {
                None => {
                    new_buf.extend_from_slice(&seq[i..]);
                    break;
                }
                Some(match_pos) => {
                    new_buf.extend_from_slice(&seq[i..i + match_pos]);
                    i += match_pos + 1;
                }
            }
        }
        new_buf.into()
    }

    /// Returns the reverse complement of a sequence. Biologically this is
    /// equivalent to the sequence of the strand opposite the one you pass
    /// in.
    ///
    /// ```
    /// use needletail::Sequence;
    ///
    /// assert_eq!(b"AACC".reverse_complement(), b"GGTT");
    /// ```
    fn reverse_complement(&'a self) -> Vec<u8> {
        self.sequence()
            .iter()
            .rev()
            .map(|n| complement(*n))
            .collect()
    }

    /// [Nucleic Acids] Normalizes the sequence. See documentation for
    /// `needletail::sequence::normalize`. Do not use on amino acid
    /// sequences. Note that this returns a Cow so you may have to coerce
    /// to a Vec<u8> or &[u8] as necessary.
    ///
    /// ```
    /// use needletail::Sequence;
    ///
    /// // IUPAC bases are coerced to N's if `false`
    /// assert_eq!(b"ADGH".normalize(false).as_ref(), b"ANGN");
    /// // otherwise they're preserved
    /// assert_eq!(b"ADGH".normalize(true).as_ref(), b"ADGH");
    ///
    /// // Uridine residues are converted to thymidine
    /// assert_eq!(b"ACGU".normalize(true).as_ref(), b"ACGT");
    /// ```
    fn normalize(&'a self, iupac: bool) -> Cow<'a, [u8]> {
        if let Some(s) = normalize(&self.sequence(), iupac) {
            s.into()
        } else {
            self.sequence().into()
        }
    }

    /// [Nucleic Acids] Returns an iterator over the sequence that skips
    /// non-ACGT bases and returns a tuple containing (position, the
    /// canonicalized kmer, if the sequence is the complement of the original).
    fn canonical_kmers(&'a self, k: u8, reverse_complement: &'a [u8]) -> CanonicalKmers<'a> {
        CanonicalKmers::new(self.sequence().as_ref(), reverse_complement, k)
    }

    /// Returns an iterator that returns a sliding window of k-sized
    /// sequences (k-mers). Does not skip whitespace or correct bases in the
    /// original sequence so `.normalize` or `.strip_returns` may be
    /// appropriate to use first.
    fn kmers(&'a self, k: u8) -> Kmers<'a> {
        Kmers::new(self.sequence().as_ref(), k)
    }

    /// Return an iterator that returns valid kmers in 4-bit form
    fn bit_kmers(&'a self, k: u8, canonical: bool) -> BitNuclKmer<'a> {
        BitNuclKmer::new(self.sequence(), k, canonical)
    }
}

impl<'a> Sequence<'a> for &'a [u8] {
    fn sequence(&'a self) -> &'a [u8] {
        &self
    }
}

impl<'a> Sequence<'a> for [u8] {
    fn sequence(&'a self) -> &'a [u8] {
        &self
    }
}

impl<'a> Sequence<'a> for Cow<'a, [u8]> {
    fn sequence(&'a self) -> &'a [u8] {
        &self
    }
}

/// [⚠Unstable] A trait to wrap over sequence data that has associated
/// quality information.
///
/// Will be stabilized once we figure out a good way to handle sequences that
/// have _optional_ quality information (like SequenceRecord) because the
/// return trait requires a slice from an immutable reference and
/// SequenceRecords can't return that without modifying themselves.
pub trait QualitySequence<'a>: Sequence<'a> {
    fn quality(&'a self) -> &'a [u8];

    /// Given a SeqRecord and a quality cutoff, mask out low-quality bases with
    /// `N` characters.
    fn quality_mask(&'a self, score: u8) -> Cow<'a, [u8]> {
        let qual = self.quality();
        // could maybe speed this up by doing a copy of base and then
        // iterating though qual and masking?
        let seq: Vec<u8> = self
            .sequence()
            .iter()
            .zip(qual.iter())
            .map(|(base, qual)| if *qual < score { b'N' } else { *base })
            .collect();
        seq.into()
    }
}

impl<'a> Sequence<'a> for (&'a [u8], &'a [u8]) {
    fn sequence(&'a self) -> &'a [u8] {
        &self.0
    }
}

impl<'a> QualitySequence<'a> for (&'a [u8], &'a [u8]) {
    fn quality(&'a self) -> &'a [u8] {
        &self.1
    }
}

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

    #[test]
    fn test_normalize() {
        assert_eq!(normalize(b"ACGTU", false), Some(b"ACGTT".to_vec()));
        assert_eq!(normalize(b"acgtu", false), Some(b"ACGTT".to_vec()));

        assert_eq!(normalize(b"N.N-N~N N", false), Some(b"N-N-N-NN".to_vec()));

        assert_eq!(normalize(b"BDHVRYSWKM", true), None);
        assert_eq!(normalize(b"bdhvryswkm", true), Some(b"BDHVRYSWKM".to_vec()));
        assert_eq!(
            normalize(b"BDHVRYSWKM", false),
            Some(b"NNNNNNNNNN".to_vec())
        );
        assert_eq!(
            normalize(b"bdhvryswkm", false),
            Some(b"NNNNNNNNNN".to_vec())
        );
    }

    #[test]
    fn test_complement() {
        assert_eq!(complement(b'a'), b't');
        assert_eq!(complement(b'c'), b'g');
        assert_eq!(complement(b'g'), b'c');
        assert_eq!(complement(b'n'), b'n');
    }

    #[test]
    fn can_canonicalize() {
        assert!(canonical(b"A") == Cow::Borrowed(b"A"));
        assert!(canonical(b"T") == Cow::Owned::<[u8]>(b"A".to_vec()));
        assert!(canonical(b"AAGT") == Cow::Borrowed(b"AAGT"));
        assert!(canonical(b"ACTT") == Cow::Owned::<[u8]>(b"AAGT".to_vec()));
        assert!(canonical(b"GC") == Cow::Borrowed(b"GC"));
    }

    #[test]
    fn can_minimize() {
        let minmer = minimizer(&b"ATTTCG"[..], 3);
        assert_eq!(&minmer[..], b"AAA");
    }

    #[test]
    fn test_quality_mask() {
        let seq_rec = (&b"AGCT"[..], &b"AAA0"[..]);
        let filtered_rec = seq_rec.quality_mask(b'5');
        assert_eq!(&filtered_rec[..], &b"AGCN"[..]);
    }
}
<commit_msg>assert -> assert_eq<commit_after>//! Generic functions for working with (primarily nucleic acid) sequences
use std::borrow::Cow;

use memchr::memchr2;

use crate::bitkmer::BitNuclKmer;
use crate::kmer::{CanonicalKmers, Kmers};

/// Transform a nucleic acid sequence into its "normalized" form.
///
/// The normalized form is:
///  - only AGCTN and possibly - (for gaps)
///  - strip out any whitespace or line endings
///  - lowercase versions of these are uppercased
///  - U is converted to T (make everything a DNA sequence)
///  - some other punctuation is converted to gaps
///  - IUPAC bases may be converted to N's depending on the parameter passed in
///  - everything else is considered a N
pub fn normalize(seq: &[u8], allow_iupac: bool) -> Option<Vec<u8>> {
    let mut buf: Vec<u8> = Vec::with_capacity(seq.len());
    let mut changed: bool = false;

    for n in seq.iter() {
        let (new_char, char_changed) = match (*n, allow_iupac) {
            c @ (b'A', _)
            | c @ (b'C', _)
            | c @ (b'G', _)
            | c @ (b'T', _)
            | c @ (b'N', _)
            | c @ (b'-', _) => (c.0, false),
            (b'a', _) => (b'A', true),
            (b'c', _) => (b'C', true),
            (b'g', _) => (b'G', true),
            // normalize uridine to thymine
            (b't', _) | (b'u', _) | (b'U', _) => (b'T', true),
            // normalize gaps
            (b'.', _) | (b'~', _) => (b'-', true),
            // logic for IUPAC bases (a little messy)
            c @ (b'B', true)
            | c @ (b'D', true)
            | c @ (b'H', true)
            | c @ (b'V', true)
            | c @ (b'R', true)
            | c @ (b'Y', true)
            | c @ (b'S', true)
            | c @ (b'W', true)
            | c @ (b'K', true)
            | c @ (b'M', true) => (c.0, false),
            (b'b', true) => (b'B', true),
            (b'd', true) => (b'D', true),
            (b'h', true) => (b'H', true),
            (b'v', true) => (b'V', true),
            (b'r', true) => (b'R', true),
            (b'y', true) => (b'Y', true),
            (b's', true) => (b'S', true),
            (b'w', true) => (b'W', true),
            (b'k', true) => (b'K', true),
            (b'm', true) => (b'M', true),
            // remove all whitespace and line endings
            (b' ', _) | (b'\t', _) | (b'\r', _) | (b'\n', _) => (b' ', true),
            // everything else is an N
            _ => (b'N', true),
        };
        changed = changed || char_changed;
        if new_char != b' ' {
            buf.push(new_char);
        }
    }
    if changed {
        Some(buf)
    } else {
        None
    }
}

/// Returns the complementary base for a given IUPAC base code.
///
/// Does not work for RNA sequences (maybe we should raise an error or something?)
#[inline]
pub fn complement(n: u8) -> u8 {
    match n {
        b'a' => b't',
        b'A' => b'T',
        b'c' => b'g',
        b'C' => b'G',
        b'g' => b'c',
        b'G' => b'C',
        b't' => b'a',
        b'T' => b'A',

        // IUPAC codes
        b'r' => b'y',
        b'y' => b'r',
        b'k' => b'm',
        b'm' => b'k',
        b'b' => b'v',
        b'v' => b'b',
        b'd' => b'h',
        b'h' => b'd',
        b's' => b's',
        b'w' => b'w',
        b'R' => b'Y',
        b'Y' => b'R',
        b'K' => b'M',
        b'M' => b'K',
        b'B' => b'V',
        b'V' => b'B',
        b'D' => b'H',
        b'H' => b'D',
        b'S' => b'S',
        b'W' => b'W',

        // anything else just pass through
        // 'u' | 'U' => panic!("Does not support complements of U"),
        x => x,
    }
}

/// Taking in a sequence string, return the canonical form of the sequence
/// (e.g. the lexigraphically lowest of either the original sequence or its
/// reverse complement)
pub fn canonical(seq: &[u8]) -> Cow<[u8]> {
    let mut buf: Vec<u8> = Vec::with_capacity(seq.len());
    // enough just keeps our comparisons from happening after they need to
    let mut enough = false;
    let mut original_was_canonical = false;

    // loop through the kmer and its reverse complement simultaneously
    for (rn, n) in seq.iter().rev().map(|n| complement(*n)).zip(seq.iter()) {
        buf.push(rn);
        if !enough && (*n < rn) {
            original_was_canonical = true;
            break;
        } else if !enough && (rn < *n) {
            enough = true;
        }
        // unstated if branch: if rn == n, keep comparing
    }
    match (original_was_canonical, enough) {
        (true, true) => panic!("Bug: should never set original_was_canonical if enough == true"),
        (true, false) => seq.into(),
        (false, true) => buf.into(),
        // the sequences were completely equal, return the ref
        (false, false) => seq.into(),
    }
}

/// Find the lexigraphically smallest substring of `seq` of length `length`
///
/// There's probably a faster algorithm for this somewhere...
pub fn minimizer(seq: &[u8], length: usize) -> Cow<[u8]> {
    let reverse_complement: Vec<u8> = seq.iter().rev().map(|n| complement(*n)).collect();
    let mut minmer = Cow::Borrowed(&seq[..length]);

    for (kmer, rc_kmer) in seq.windows(length).zip(reverse_complement.windows(length)) {
        if *kmer < minmer[..] {
            minmer = kmer.into();
        }
        if *rc_kmer < minmer[..] {
            minmer = rc_kmer.to_vec().into();
        }
    }
    minmer
}

/// A generic FASTX record that also abstracts over several logical operations
/// that can be performed on nucleic acid sequences.
pub trait Sequence<'a> {
    fn sequence(&'a self) -> &'a [u8];

    /// Remove newlines from the sequence; this handles `\r`, `\n`, and `\r\n`
    /// and removes internal newlines in addition to ones at the end.
    /// Primarily used for FASTA multiline records, but can also help process
    /// (the much rarer) multiline FASTQs. Always use before iteration methods
    /// below to ensure no newlines are being returned with e.g. `.kmers`.
    fn strip_returns(&'a self) -> Cow<'a, [u8]> {
        let seq = self.sequence();

        // first part is a fast check to see if we need to do any allocations
        let mut i;
        match memchr2(b'\r', b'\n', &seq) {
            Some(break_loc) => i = break_loc,
            None => return seq.into(),
        }
        // we found a newline; create a new buffer and stripping out newlines
        // and writing into it
        let mut new_buf = Vec::with_capacity(seq.len() - 1);
        new_buf.extend_from_slice(&seq[..i]);
        while i < seq.len() {
            match memchr2(b'\r', b'\n', &seq[i..]) {
                None => {
                    new_buf.extend_from_slice(&seq[i..]);
                    break;
                }
                Some(match_pos) => {
                    new_buf.extend_from_slice(&seq[i..i + match_pos]);
                    i += match_pos + 1;
                }
            }
        }
        new_buf.into()
    }

    /// Returns the reverse complement of a sequence. Biologically this is
    /// equivalent to the sequence of the strand opposite the one you pass
    /// in.
    ///
    /// ```
    /// use needletail::Sequence;
    ///
    /// assert_eq!(b"AACC".reverse_complement(), b"GGTT");
    /// ```
    fn reverse_complement(&'a self) -> Vec<u8> {
        self.sequence()
            .iter()
            .rev()
            .map(|n| complement(*n))
            .collect()
    }

    /// [Nucleic Acids] Normalizes the sequence. See documentation for
    /// `needletail::sequence::normalize`. Do not use on amino acid
    /// sequences. Note that this returns a Cow so you may have to coerce
    /// to a Vec<u8> or &[u8] as necessary.
    ///
    /// ```
    /// use needletail::Sequence;
    ///
    /// // IUPAC bases are coerced to N's if `false`
    /// assert_eq!(b"ADGH".normalize(false).as_ref(), b"ANGN");
    /// // otherwise they're preserved
    /// assert_eq!(b"ADGH".normalize(true).as_ref(), b"ADGH");
    ///
    /// // Uridine residues are converted to thymidine
    /// assert_eq!(b"ACGU".normalize(true).as_ref(), b"ACGT");
    /// ```
    fn normalize(&'a self, iupac: bool) -> Cow<'a, [u8]> {
        if let Some(s) = normalize(&self.sequence(), iupac) {
            s.into()
        } else {
            self.sequence().into()
        }
    }

    /// [Nucleic Acids] Returns an iterator over the sequence that skips
    /// non-ACGT bases and returns a tuple containing (position, the
    /// canonicalized kmer, if the sequence is the complement of the original).
    fn canonical_kmers(&'a self, k: u8, reverse_complement: &'a [u8]) -> CanonicalKmers<'a> {
        CanonicalKmers::new(self.sequence().as_ref(), reverse_complement, k)
    }

    /// Returns an iterator that returns a sliding window of k-sized
    /// sequences (k-mers). Does not skip whitespace or correct bases in the
    /// original sequence so `.normalize` or `.strip_returns` may be
    /// appropriate to use first.
    fn kmers(&'a self, k: u8) -> Kmers<'a> {
        Kmers::new(self.sequence().as_ref(), k)
    }

    /// Return an iterator that returns valid kmers in 4-bit form
    fn bit_kmers(&'a self, k: u8, canonical: bool) -> BitNuclKmer<'a> {
        BitNuclKmer::new(self.sequence(), k, canonical)
    }
}

impl<'a> Sequence<'a> for &'a [u8] {
    fn sequence(&'a self) -> &'a [u8] {
        &self
    }
}

impl<'a> Sequence<'a> for [u8] {
    fn sequence(&'a self) -> &'a [u8] {
        &self
    }
}

impl<'a> Sequence<'a> for Cow<'a, [u8]> {
    fn sequence(&'a self) -> &'a [u8] {
        &self
    }
}

/// [⚠Unstable] A trait to wrap over sequence data that has associated
/// quality information.
///
/// Will be stabilized once we figure out a good way to handle sequences that
/// have _optional_ quality information (like SequenceRecord) because the
/// return trait requires a slice from an immutable reference and
/// SequenceRecords can't return that without modifying themselves.
pub trait QualitySequence<'a>: Sequence<'a> {
    fn quality(&'a self) -> &'a [u8];

    /// Given a SeqRecord and a quality cutoff, mask out low-quality bases with
    /// `N` characters.
    fn quality_mask(&'a self, score: u8) -> Cow<'a, [u8]> {
        let qual = self.quality();
        // could maybe speed this up by doing a copy of base and then
        // iterating though qual and masking?
        let seq: Vec<u8> = self
            .sequence()
            .iter()
            .zip(qual.iter())
            .map(|(base, qual)| if *qual < score { b'N' } else { *base })
            .collect();
        seq.into()
    }
}

impl<'a> Sequence<'a> for (&'a [u8], &'a [u8]) {
    fn sequence(&'a self) -> &'a [u8] {
        &self.0
    }
}

impl<'a> QualitySequence<'a> for (&'a [u8], &'a [u8]) {
    fn quality(&'a self) -> &'a [u8] {
        &self.1
    }
}

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

    #[test]
    fn test_normalize() {
        assert_eq!(normalize(b"ACGTU", false), Some(b"ACGTT".to_vec()));
        assert_eq!(normalize(b"acgtu", false), Some(b"ACGTT".to_vec()));

        assert_eq!(normalize(b"N.N-N~N N", false), Some(b"N-N-N-NN".to_vec()));

        assert_eq!(normalize(b"BDHVRYSWKM", true), None);
        assert_eq!(normalize(b"bdhvryswkm", true), Some(b"BDHVRYSWKM".to_vec()));
        assert_eq!(
            normalize(b"BDHVRYSWKM", false),
            Some(b"NNNNNNNNNN".to_vec())
        );
        assert_eq!(
            normalize(b"bdhvryswkm", false),
            Some(b"NNNNNNNNNN".to_vec())
        );
    }

    #[test]
    fn test_complement() {
        assert_eq!(complement(b'a'), b't');
        assert_eq!(complement(b'c'), b'g');
        assert_eq!(complement(b'g'), b'c');
        assert_eq!(complement(b'n'), b'n');
    }

    #[test]
    fn can_canonicalize() {
        assert_eq!(canonical(b"A"), Cow::Borrowed(b"A"));
        assert_eq!(canonical(b"T"), Cow::Owned::<[u8]>(b"A".to_vec()));
        assert_eq!(canonical(b"AAGT"), Cow::Borrowed(b"AAGT"));
        assert_eq!(canonical(b"ACTT"), Cow::Owned::<[u8]>(b"AAGT".to_vec()));
        assert_eq!(canonical(b"GC"), Cow::Borrowed(b"GC"));
    }

    #[test]
    fn can_minimize() {
        let minmer = minimizer(&b"ATTTCG"[..], 3);
        assert_eq!(&minmer[..], b"AAA");
    }

    #[test]
    fn test_quality_mask() {
        let seq_rec = (&b"AGCT"[..], &b"AAA0"[..]);
        let filtered_rec = seq_rec.quality_mask(b'5');
        assert_eq!(&filtered_rec[..], &b"AGCN"[..]);
    }
}
<|endoftext|>


<commit_before>//! Useful traits for manipulating sequences of data stored in `GenericArray`s

use super::*;
use core::{mem, ptr};
use core::ops::{Add, Sub};
use typenum::operator_aliases::*;

/// Defines some `GenericArray` sequence with an associated length.
///
/// This is useful for passing N-length generic arrays as generics.
pub unsafe trait GenericSequence<T>: Sized {
    /// `GenericArray` associated length
    type Length: ArrayLength<T>;
}

unsafe impl<T, N: ArrayLength<T>> GenericSequence<T> for GenericArray<T, N> {
    type Length = N;
}

/// Defines any `GenericSequence` which can be lengthened or extended by appending
/// or prepending an element to it.
///
/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back`
pub unsafe trait Lengthen<T>: GenericSequence<T> {
    /// `GenericSequence` that has one more element than `Self`
    type Longer: Shorten<T, Shorter = Self>;

    /// Returns a new array with the given element appended to the end of it.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3];
    ///
    /// let b = a.append(4);
    ///
    /// assert_eq!(b, arr![i32; 1, 2, 3, 4]);
    /// ```
    fn append(self, last: T) -> Self::Longer;

    /// Returns a new array with the given element prepended to the front of it.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3];
    ///
    /// let b = a.prepend(4);
    ///
    /// assert_eq!(b, arr![i32; 4, 1, 2, 3]);
    /// ```
    fn prepend(self, first: T) -> Self::Longer;
}

/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it.
///
/// Additionally, any shortened sequence can be lengthened by
/// appending or prepending an element to it.
pub unsafe trait Shorten<T>: GenericSequence<T> {
    /// `GenericSequence` that has one less element than `Self`
    type Shorter: Lengthen<T, Longer = Self>;

    /// Returns a new array without the last element, and the last element.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3, 4];
    ///
    /// let (init, last) = a.pop_back();
    ///
    /// assert_eq!(init, arr![i32; 1, 2, 3]);
    /// assert_eq!(last, 4);
    /// ```
    fn pop_back(self) -> (Self::Shorter, T);

    /// Returns a new array without the first element, and the first element.
        /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3, 4];
    ///
    /// let (head, tail) = a.pop_front();
    ///
    /// assert_eq!(head, 1);
    /// assert_eq!(tail, arr![i32; 2, 3, 4]);
    /// ```
    fn pop_front(self) -> (T, Self::Shorter);
}

unsafe impl<T, N: ArrayLength<T>> Lengthen<T> for GenericArray<T, N>
where
    N: Add<B1>,
    Add1<N>: ArrayLength<T>,
    Add1<N>: Sub<B1, Output = N>,
    Sub1<Add1<N>>: ArrayLength<T>,
{
    type Longer = GenericArray<T, Add1<N>>;

    fn append(self, last: T) -> Self::Longer {
        let mut longer: Self::Longer = unsafe { mem::uninitialized() };

        unsafe {
            ptr::write(longer.as_mut_ptr() as *mut _, self);
            ptr::write(&mut longer[N::to_usize()], last);
        }

        longer
    }

    fn prepend(self, first: T) -> Self::Longer {
        let mut longer: Self::Longer = unsafe { mem::uninitialized() };

        let longer_ptr = longer.as_mut_ptr();

        unsafe {
            ptr::write(longer_ptr as *mut _, first);
            ptr::write(longer_ptr.offset(1) as *mut _, self);
        }

        longer
    }
}

unsafe impl<T, N: ArrayLength<T>> Shorten<T> for GenericArray<T, N>
where
    N: Sub<B1>,
    Sub1<N>: ArrayLength<T>,
    Sub1<N>: Add<B1, Output = N>,
    Add1<Sub1<N>>: ArrayLength<T>,
{
    type Shorter = GenericArray<T, Sub1<N>>;

    fn pop_back(self) -> (Self::Shorter, T) {
        let init_ptr = self.as_ptr();
        let last_ptr = unsafe { init_ptr.offset(Sub1::<N>::to_usize() as isize) };

        let init = unsafe { ptr::read(init_ptr as _) };
        let last = unsafe { ptr::read(last_ptr as _) };

        mem::forget(self);

        (init, last)
    }

    fn pop_front(self) -> (T, Self::Shorter) {
        let head_ptr = self.as_ptr();
        let tail_ptr = unsafe { head_ptr.offset(1) };

        let head = unsafe { ptr::read(head_ptr as _) };
        let tail = unsafe { ptr::read(tail_ptr as _) };

        mem::forget(self);

        (head, tail)
    }
}

/// Defines a `GenericSequence` that can be split into two parts at a given pivot index.
pub unsafe trait Split<T, K>: GenericSequence<T>
where
    K: ArrayLength<T>,
{
    /// First part of the resulting split array
    type Head: GenericSequence<T>;
    /// Second part of the resulting split array
    type Tail: GenericSequence<T>;

    /// Splits an array at the given index, returning the head and tail arrays.
    fn split(self) -> (Self::Head, Self::Tail);
}

unsafe impl<T, N, K> Split<T, K> for GenericArray<T, N>
where
    N: ArrayLength<T>,
    K: ArrayLength<T>,
    N: Sub<K>,
    Diff<N, K>: ArrayLength<T>,
{
    type Head = GenericArray<T, K>;
    type Tail = GenericArray<T, Diff<N, K>>;

    fn split(self) -> (Self::Head, Self::Tail) {
        let head_ptr = self.as_ptr();
        let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) };

        let head = unsafe { ptr::read(head_ptr as _) };
        let tail = unsafe { ptr::read(tail_ptr as _) };

        mem::forget(self);

        (head, tail)
    }
}

/// Defines `GenericSequence`s which can be joined together, forming a larger array.
pub unsafe trait Concat<T, M>: GenericSequence<T>
where
    M: ArrayLength<T>,
{
    /// Sequence to be concatenated with `self`
    type Rest: GenericSequence<T, Length = M>;

    /// Resulting sequence formed by the concatenation.
    type Output: GenericSequence<T>;

    /// Concatenate, or join, two sequences.
    fn concat(self, rest: Self::Rest) -> Self::Output;
}

unsafe impl<T, N, M> Concat<T, M> for GenericArray<T, N>
where
    N: ArrayLength<T> + Add<M>,
    M: ArrayLength<T>,
    Sum<N, M>: ArrayLength<T>,
{
    type Rest = GenericArray<T, M>;
    type Output = GenericArray<T, Sum<N, M>>;

    fn concat(self, rest: Self::Rest) -> Self::Output {
        let mut output: Self::Output = unsafe { mem::uninitialized() };

        let output_ptr = output.as_mut_ptr();

        unsafe {
            ptr::write(output_ptr as *mut _, self);
            ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest);
        }

        output
    }
}
<commit_msg>Rename Head/Tail in Split trait to First/Second<commit_after>//! Useful traits for manipulating sequences of data stored in `GenericArray`s

use super::*;
use core::{mem, ptr};
use core::ops::{Add, Sub};
use typenum::operator_aliases::*;

/// Defines some `GenericArray` sequence with an associated length.
///
/// This is useful for passing N-length generic arrays as generics.
pub unsafe trait GenericSequence<T>: Sized {
    /// `GenericArray` associated length
    type Length: ArrayLength<T>;
}

unsafe impl<T, N: ArrayLength<T>> GenericSequence<T> for GenericArray<T, N> {
    type Length = N;
}

/// Defines any `GenericSequence` which can be lengthened or extended by appending
/// or prepending an element to it.
///
/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back`
pub unsafe trait Lengthen<T>: GenericSequence<T> {
    /// `GenericSequence` that has one more element than `Self`
    type Longer: Shorten<T, Shorter = Self>;

    /// Returns a new array with the given element appended to the end of it.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3];
    ///
    /// let b = a.append(4);
    ///
    /// assert_eq!(b, arr![i32; 1, 2, 3, 4]);
    /// ```
    fn append(self, last: T) -> Self::Longer;

    /// Returns a new array with the given element prepended to the front of it.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3];
    ///
    /// let b = a.prepend(4);
    ///
    /// assert_eq!(b, arr![i32; 4, 1, 2, 3]);
    /// ```
    fn prepend(self, first: T) -> Self::Longer;
}

/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it.
///
/// Additionally, any shortened sequence can be lengthened by
/// appending or prepending an element to it.
pub unsafe trait Shorten<T>: GenericSequence<T> {
    /// `GenericSequence` that has one less element than `Self`
    type Shorter: Lengthen<T, Longer = Self>;

    /// Returns a new array without the last element, and the last element.
    ///
    /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3, 4];
    ///
    /// let (init, last) = a.pop_back();
    ///
    /// assert_eq!(init, arr![i32; 1, 2, 3]);
    /// assert_eq!(last, 4);
    /// ```
    fn pop_back(self) -> (Self::Shorter, T);

    /// Returns a new array without the first element, and the first element.
        /// Example:
    ///
    /// ```ignore
    /// let a = arr![i32; 1, 2, 3, 4];
    ///
    /// let (head, tail) = a.pop_front();
    ///
    /// assert_eq!(head, 1);
    /// assert_eq!(tail, arr![i32; 2, 3, 4]);
    /// ```
    fn pop_front(self) -> (T, Self::Shorter);
}

unsafe impl<T, N: ArrayLength<T>> Lengthen<T> for GenericArray<T, N>
where
    N: Add<B1>,
    Add1<N>: ArrayLength<T>,
    Add1<N>: Sub<B1, Output = N>,
    Sub1<Add1<N>>: ArrayLength<T>,
{
    type Longer = GenericArray<T, Add1<N>>;

    fn append(self, last: T) -> Self::Longer {
        let mut longer: Self::Longer = unsafe { mem::uninitialized() };

        unsafe {
            ptr::write(longer.as_mut_ptr() as *mut _, self);
            ptr::write(&mut longer[N::to_usize()], last);
        }

        longer
    }

    fn prepend(self, first: T) -> Self::Longer {
        let mut longer: Self::Longer = unsafe { mem::uninitialized() };

        let longer_ptr = longer.as_mut_ptr();

        unsafe {
            ptr::write(longer_ptr as *mut _, first);
            ptr::write(longer_ptr.offset(1) as *mut _, self);
        }

        longer
    }
}

unsafe impl<T, N: ArrayLength<T>> Shorten<T> for GenericArray<T, N>
where
    N: Sub<B1>,
    Sub1<N>: ArrayLength<T>,
    Sub1<N>: Add<B1, Output = N>,
    Add1<Sub1<N>>: ArrayLength<T>,
{
    type Shorter = GenericArray<T, Sub1<N>>;

    fn pop_back(self) -> (Self::Shorter, T) {
        let init_ptr = self.as_ptr();
        let last_ptr = unsafe { init_ptr.offset(Sub1::<N>::to_usize() as isize) };

        let init = unsafe { ptr::read(init_ptr as _) };
        let last = unsafe { ptr::read(last_ptr as _) };

        mem::forget(self);

        (init, last)
    }

    fn pop_front(self) -> (T, Self::Shorter) {
        let head_ptr = self.as_ptr();
        let tail_ptr = unsafe { head_ptr.offset(1) };

        let head = unsafe { ptr::read(head_ptr as _) };
        let tail = unsafe { ptr::read(tail_ptr as _) };

        mem::forget(self);

        (head, tail)
    }
}

/// Defines a `GenericSequence` that can be split into two parts at a given pivot index.
pub unsafe trait Split<T, K>: GenericSequence<T>
where
    K: ArrayLength<T>,
{
    /// First part of the resulting split array
    type First: GenericSequence<T>;
    /// Second part of the resulting split array
    type Second: GenericSequence<T>;

    /// Splits an array at the given index, returning the separate parts of the array.
    fn split(self) -> (Self::First, Self::Second);
}

unsafe impl<T, N, K> Split<T, K> for GenericArray<T, N>
where
    N: ArrayLength<T>,
    K: ArrayLength<T>,
    N: Sub<K>,
    Diff<N, K>: ArrayLength<T>,
{
    type First = GenericArray<T, K>;
    type Second = GenericArray<T, Diff<N, K>>;

    fn split(self) -> (Self::First, Self::Second) {
        let head_ptr = self.as_ptr();
        let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) };

        let head = unsafe { ptr::read(head_ptr as _) };
        let tail = unsafe { ptr::read(tail_ptr as _) };

        mem::forget(self);

        (head, tail)
    }
}

/// Defines `GenericSequence`s which can be joined together, forming a larger array.
pub unsafe trait Concat<T, M>: GenericSequence<T>
where
    M: ArrayLength<T>,
{
    /// Sequence to be concatenated with `self`
    type Rest: GenericSequence<T, Length = M>;

    /// Resulting sequence formed by the concatenation.
    type Output: GenericSequence<T>;

    /// Concatenate, or join, two sequences.
    fn concat(self, rest: Self::Rest) -> Self::Output;
}

unsafe impl<T, N, M> Concat<T, M> for GenericArray<T, N>
where
    N: ArrayLength<T> + Add<M>,
    M: ArrayLength<T>,
    Sum<N, M>: ArrayLength<T>,
{
    type Rest = GenericArray<T, M>;
    type Output = GenericArray<T, Sum<N, M>>;

    fn concat(self, rest: Self::Rest) -> Self::Output {
        let mut output: Self::Output = unsafe { mem::uninitialized() };

        let output_ptr = output.as_mut_ptr();

        unsafe {
            ptr::write(output_ptr as *mut _, self);
            ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest);
        }

        output
    }
}
<|endoftext|>


<commit_before>/*
 * UpdateHub
 * Copyright (C) 2017
 * O.S. Systems Sofware LTDA: contact@ossystems.com.br
 *
 * SPDX-License-Identifier:     GPL-2.0
 */

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

use std::io;
use std::time::Duration;

const SYSTEM_SETTINGS_PATH: &'static str = "/etc/updatehub.conf";

#[derive(Default, PartialEq, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Settings {
    pub polling: Polling,
    pub storage: Storage,
    pub update: Update,
    pub network: Network,
    pub firmware: Firmware,
}

impl Settings {
    pub fn new() -> Self {
        Settings::default()
    }

    pub fn load(self) -> Result<Self, SettingsError> {
        use std::path::Path;
        use std::fs::File;
        use std::io::Read;

        let path = Path::new(SYSTEM_SETTINGS_PATH);

        if path.exists() {
            info!(
                "Loading system settings from '{}'...",
                path.to_string_lossy()
            );

            let mut content = String::new();
            File::open(path)?.read_to_string(&mut content)?;

            Ok(self.parse(&content)?)
        } else {
            debug!(
                "System settings file {} does not exists.",
                path.to_string_lossy()
            );
            info!("Using default system settings...");
            Ok(self)
        }
    }

    fn parse(self, content: &str) -> Result<Self, SettingsError> {
        fn has_protocol_prefix(server: &str) -> bool {
            server.starts_with("http://") || server.starts_with("https://")
        }

        fn has_valid_polling_interval(interval: &Duration) -> bool {
            if *interval < Duration::new(60, 0) {
                false
            } else {
                true
            }
        }

        let settings = serde_ini::from_str::<Settings>(&content)?;

        if !has_valid_polling_interval(&settings.polling.interval) {
            error!("Invalid setting for polling interval. The interval cannot be less than 60 seconds");
            return Err(SettingsError::InvalidInterval);
        }

        if !has_protocol_prefix(&settings.network.server_address) {
            error!("Invalid setting for server address. The server address must use the protocol prefix");
            return Err(SettingsError::InvalidServerAddress);
        }

        Ok(settings)
    }
}

#[derive(Debug)]
pub enum SettingsError {
    Io(io::Error),
    Ini(serde_ini::de::Error),
    InvalidInterval,
    InvalidServerAddress,
}

impl From<io::Error> for SettingsError {
    fn from(err: io::Error) -> SettingsError {
        SettingsError::Io(err)
    }
}

impl From<serde_ini::de::Error> for SettingsError {
    fn from(err: serde_ini::de::Error) -> SettingsError {
        SettingsError::Ini(err)
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Polling {
    #[serde(deserialize_with = "ini_de_duration_from_str")]
    pub interval: Duration,
    #[serde(deserialize_with = "ini_de_bool_from_str")]
    pub enabled: bool,
}

impl Default for Polling {
    fn default() -> Self {
        Polling {
            interval: Duration::new(86_400, 0), // 1 day
            enabled: true,
        }
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Storage {
    #[serde(deserialize_with = "ini_de_bool_from_str")]
    pub read_only: bool,
    pub runtime_settings: String,
}

impl Default for Storage {
    fn default() -> Self {
        Storage {
            read_only: false,
            runtime_settings: "/var/lib/updatehub.conf".to_string(),
        }
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Update {
    pub download_dir: String,
    #[serde(rename = "SupportedInstallModes")]
    #[serde(deserialize_with = "ini_de_vec_from_str")]
    pub install_modes: Vec<String>,
}

impl Default for Update {
    fn default() -> Self {
        Update {
            download_dir: "/tmp/updatehub".to_string(),
            install_modes: [
                "dry-run",
                "copy",
                "flash",
                "imxkobs",
                "raw",
                "tarball",
                "ubifs",
            ].iter()
                .map(|i| i.to_string())
                .collect(),
        }
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Network {
    pub server_address: String,
}

impl Default for Network {
    fn default() -> Self {
        Network { server_address: "https://api.updatehub.io".to_string() }
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Firmware {
    pub metadata_path: String,
}

impl Default for Firmware {
    fn default() -> Self {
        Firmware { metadata_path: "/usr/share/updatehub".to_string() }
    }
}

fn ini_de_duration_from_str<'de, D>(deserializer: D) -> Result<Duration, D::Error>
where
    D: Deserializer<'de>,
{
    use parse_duration::parse;

    let s = String::deserialize(deserializer)?;
    parse(&s).map_err(de::Error::custom)
}

fn ini_de_bool_from_str<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
    D: Deserializer<'de>,
{
    use std::str::FromStr;

    let s = String::deserialize(deserializer)?;
    bool::from_str(&s).map_err(de::Error::custom)
}

fn ini_de_vec_from_str<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
    D: Deserializer<'de>,
{
    Ok(
        String::deserialize(deserializer)?
            .split(",")
            .map(|s| s.to_string())
            .collect(),
    )
}

/*
extern crate chrono;
use self::chrono::{DateTime, Utc};

#[derive(Deserialize)]
struct PersistentSettings {
    polling: PersistentPolling,
}

struct PersistentPolling {
    last: DateTime<Utc>,
    first: DateTime<Utc>,
    extra_interval: usize,
    retries: usize,
    now: bool,
}

struct PersistentUpdate {
    upgrading_to: i8,
}
impl Default for PersistentPolling {
    fn default() -> Self {
        PersistentPolling {
            last: Utc::now(),
            first: Utc::now(),
            extra_interval: 0,
            retries: 0,
            now: false,
        }
    }
}
*/

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

    #[test]
    fn ok() {
        let ini = r"
[Polling]
Interval=60s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=http://localhost

[Firmware]
MetadataPath=/tmp/metadata
";

        let expected = Settings {
            polling: Polling {
                interval: Duration::new(60, 0),
                enabled: false,
            },
            storage: Storage {
                read_only: true,
                runtime_settings: "/run/updatehub/state".to_string(),
            },
            update: Update {
                download_dir: "/tmp/download".to_string(),
                install_modes: ["mode1", "mode2"].iter().map(|i| i.to_string()).collect(),
            },
            network: Network { server_address: "http://localhost".to_string() },
            firmware: Firmware { metadata_path: "/tmp/metadata".to_string() },
        };

        assert!(
            serde_ini::from_str::<Settings>(&ini)
                .map_err(|e| println!("{}", e))
                .ok() == Some(expected)
        );
    }

    #[test]
    fn invalid_polling_interval() {
        let ini = r"
[Polling]
Interval=59s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=http://localhost

[Firmware]
MetadataPath=/tmp/metadata
";
        assert!(Settings::new().parse(&ini).is_err());
    }

    #[test]
    fn invalid_network_server_address() {
        let ini = r"
[Polling]
Interval=60s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=localhost

[Firmware]
MetadataPath=/tmp/metadata
";
        assert!(Settings::new().parse(&ini).is_err());
    }

    #[test]
    fn default() {
        let settings = Settings::default();
        let expected = Settings {
            polling: Polling {
                interval: Duration::new(86_400, 0),
                enabled: true,
            },
            storage: Storage {
                read_only: false,
                runtime_settings: "/var/lib/updatehub.conf".to_string(),
            },
            update: Update {
                download_dir: "/tmp/updatehub".to_string(),
                install_modes: [
                    "dry-run",
                    "copy",
                    "flash",
                    "imxkobs",
                    "raw",
                    "tarball",
                    "ubifs",
                ].iter()
                    .map(|i| i.to_string())
                    .collect(),
            },
            network: Network { server_address: "https://api.updatehub.io".to_string() },
            firmware: Firmware { metadata_path: "/usr/share/updatehub".to_string() },
        };

        assert!(Some(settings) == Some(expected));
    }
}
<commit_msg>settings: Remove commented code<commit_after>/*
 * UpdateHub
 * Copyright (C) 2017
 * O.S. Systems Sofware LTDA: contact@ossystems.com.br
 *
 * SPDX-License-Identifier:     GPL-2.0
 */

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

use std::io;
use std::time::Duration;

const SYSTEM_SETTINGS_PATH: &'static str = "/etc/updatehub.conf";

#[derive(Default, PartialEq, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Settings {
    pub polling: Polling,
    pub storage: Storage,
    pub update: Update,
    pub network: Network,
    pub firmware: Firmware,
}

impl Settings {
    pub fn new() -> Self {
        Settings::default()
    }

    pub fn load(self) -> Result<Self, SettingsError> {
        use std::path::Path;
        use std::fs::File;
        use std::io::Read;

        let path = Path::new(SYSTEM_SETTINGS_PATH);

        if path.exists() {
            info!(
                "Loading system settings from '{}'...",
                path.to_string_lossy()
            );

            let mut content = String::new();
            File::open(path)?.read_to_string(&mut content)?;

            Ok(self.parse(&content)?)
        } else {
            debug!(
                "System settings file {} does not exists.",
                path.to_string_lossy()
            );
            info!("Using default system settings...");
            Ok(self)
        }
    }

    fn parse(self, content: &str) -> Result<Self, SettingsError> {
        fn has_protocol_prefix(server: &str) -> bool {
            server.starts_with("http://") || server.starts_with("https://")
        }

        fn has_valid_polling_interval(interval: &Duration) -> bool {
            if *interval < Duration::new(60, 0) {
                false
            } else {
                true
            }
        }

        let settings = serde_ini::from_str::<Settings>(&content)?;

        if !has_valid_polling_interval(&settings.polling.interval) {
            error!("Invalid setting for polling interval. The interval cannot be less than 60 seconds");
            return Err(SettingsError::InvalidInterval);
        }

        if !has_protocol_prefix(&settings.network.server_address) {
            error!("Invalid setting for server address. The server address must use the protocol prefix");
            return Err(SettingsError::InvalidServerAddress);
        }

        Ok(settings)
    }
}

#[derive(Debug)]
pub enum SettingsError {
    Io(io::Error),
    Ini(serde_ini::de::Error),
    InvalidInterval,
    InvalidServerAddress,
}

impl From<io::Error> for SettingsError {
    fn from(err: io::Error) -> SettingsError {
        SettingsError::Io(err)
    }
}

impl From<serde_ini::de::Error> for SettingsError {
    fn from(err: serde_ini::de::Error) -> SettingsError {
        SettingsError::Ini(err)
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Polling {
    #[serde(deserialize_with = "ini_de_duration_from_str")]
    pub interval: Duration,
    #[serde(deserialize_with = "ini_de_bool_from_str")]
    pub enabled: bool,
}

impl Default for Polling {
    fn default() -> Self {
        Polling {
            interval: Duration::new(86_400, 0), // 1 day
            enabled: true,
        }
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Storage {
    #[serde(deserialize_with = "ini_de_bool_from_str")]
    pub read_only: bool,
    pub runtime_settings: String,
}

impl Default for Storage {
    fn default() -> Self {
        Storage {
            read_only: false,
            runtime_settings: "/var/lib/updatehub.conf".to_string(),
        }
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Update {
    pub download_dir: String,
    #[serde(rename = "SupportedInstallModes")]
    #[serde(deserialize_with = "ini_de_vec_from_str")]
    pub install_modes: Vec<String>,
}

impl Default for Update {
    fn default() -> Self {
        Update {
            download_dir: "/tmp/updatehub".to_string(),
            install_modes: [
                "dry-run",
                "copy",
                "flash",
                "imxkobs",
                "raw",
                "tarball",
                "ubifs",
            ].iter()
                .map(|i| i.to_string())
                .collect(),
        }
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Network {
    pub server_address: String,
}

impl Default for Network {
    fn default() -> Self {
        Network { server_address: "https://api.updatehub.io".to_string() }
    }
}

#[derive(Deserialize, PartialEq)]
#[serde(rename_all = "PascalCase")]
pub struct Firmware {
    pub metadata_path: String,
}

impl Default for Firmware {
    fn default() -> Self {
        Firmware { metadata_path: "/usr/share/updatehub".to_string() }
    }
}

fn ini_de_duration_from_str<'de, D>(deserializer: D) -> Result<Duration, D::Error>
where
    D: Deserializer<'de>,
{
    use parse_duration::parse;

    let s = String::deserialize(deserializer)?;
    parse(&s).map_err(de::Error::custom)
}

fn ini_de_bool_from_str<'de, D>(deserializer: D) -> Result<bool, D::Error>
where
    D: Deserializer<'de>,
{
    use std::str::FromStr;

    let s = String::deserialize(deserializer)?;
    bool::from_str(&s).map_err(de::Error::custom)
}

fn ini_de_vec_from_str<'de, D>(deserializer: D) -> Result<Vec<String>, D::Error>
where
    D: Deserializer<'de>,
{
    Ok(
        String::deserialize(deserializer)?
            .split(",")
            .map(|s| s.to_string())
            .collect(),
    )
}

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

    #[test]
    fn ok() {
        let ini = r"
[Polling]
Interval=60s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=http://localhost

[Firmware]
MetadataPath=/tmp/metadata
";

        let expected = Settings {
            polling: Polling {
                interval: Duration::new(60, 0),
                enabled: false,
            },
            storage: Storage {
                read_only: true,
                runtime_settings: "/run/updatehub/state".to_string(),
            },
            update: Update {
                download_dir: "/tmp/download".to_string(),
                install_modes: ["mode1", "mode2"].iter().map(|i| i.to_string()).collect(),
            },
            network: Network { server_address: "http://localhost".to_string() },
            firmware: Firmware { metadata_path: "/tmp/metadata".to_string() },
        };

        assert!(
            serde_ini::from_str::<Settings>(&ini)
                .map_err(|e| println!("{}", e))
                .ok() == Some(expected)
        );
    }

    #[test]
    fn invalid_polling_interval() {
        let ini = r"
[Polling]
Interval=59s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=http://localhost

[Firmware]
MetadataPath=/tmp/metadata
";
        assert!(Settings::new().parse(&ini).is_err());
    }

    #[test]
    fn invalid_network_server_address() {
        let ini = r"
[Polling]
Interval=60s
Enabled=false

[Storage]
ReadOnly=true
RuntimeSettings=/run/updatehub/state

[Update]
DownloadDir=/tmp/download
SupportedInstallModes=mode1,mode2

[Network]
ServerAddress=localhost

[Firmware]
MetadataPath=/tmp/metadata
";
        assert!(Settings::new().parse(&ini).is_err());
    }

    #[test]
    fn default() {
        let settings = Settings::default();
        let expected = Settings {
            polling: Polling {
                interval: Duration::new(86_400, 0),
                enabled: true,
            },
            storage: Storage {
                read_only: false,
                runtime_settings: "/var/lib/updatehub.conf".to_string(),
            },
            update: Update {
                download_dir: "/tmp/updatehub".to_string(),
                install_modes: [
                    "dry-run",
                    "copy",
                    "flash",
                    "imxkobs",
                    "raw",
                    "tarball",
                    "ubifs",
                ].iter()
                    .map(|i| i.to_string())
                    .collect(),
            },
            network: Network { server_address: "https://api.updatehub.io".to_string() },
            firmware: Firmware { metadata_path: "/usr/share/updatehub".to_string() },
        };

        assert!(Some(settings) == Some(expected));
    }
}
<|endoftext|>


<commit_before>use console;
use std::marker::PhantomData;
use sdl2::keyboard::Keycode;
// Might just rename this to settings.rs

pub const R_MAX_FPS: console::CVar<i64> = console::CVar {
    ty: PhantomData,
    name: "r_max_fps",
    description: "fps_max caps the maximum FPS for the rendering engine",
    mutable: true,
    serializable: true,
    default: &|| 60,
};

pub const R_FOV: console::CVar<i64> = console::CVar {
    ty: PhantomData,
    name: "r_fov",
    description: "Setting for controlling the client field of view",
    mutable: true,
    serializable: true,
    default: &|| 90,
};

pub const R_VSYNC: console::CVar<bool> = console::CVar {
    ty: PhantomData,
    name: "r_vsync",
    description: "Toggle to enable/disable vsync",
    mutable: true,
    serializable: true,
    default: &|| true,
};

pub const CL_MASTER_VOLUME: console::CVar<i64> = console::CVar {
    ty: PhantomData,
    name: "cl_master_volume",
    description: "Main volume control",
    mutable: true,
    serializable: true,
    default: &|| 100,
};

macro_rules! create_keybind {
    ($keycode:ident, $name:expr, $description:expr) => (console::CVar {
        ty: PhantomData,
        name: $name,
        description: $description,
        mutable: true,
        serializable: true,
        default: &|| Keycode::$keycode as i64
    })
}

pub const CL_KEYBIND_FORWARD: console::CVar<i64> = create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward");
pub const CL_KEYBIND_BACKWARD: console::CVar<i64> = create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward");
pub const CL_KEYBIND_LEFT: console::CVar<i64> = create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left");
pub const CL_KEYBIND_RIGHT: console::CVar<i64> = create_keybind!(D, "cl_keybind_right", "Keybinding for moving to the right");
pub const CL_KEYBIND_OPEN_INV: console::CVar<i64> = create_keybind!(E, "cl_keybind_open_inv", "Keybinding for opening the inventory");
pub const CL_KEYBIND_SNEAK: console::CVar<i64> = create_keybind!(LShift, "cl_keybind_sneak", "Keybinding for sneaking");
pub const CL_KEYBIND_SPRINT: console::CVar<i64> = create_keybind!(LCtrl, "cl_keybind_sprint", "Keybinding for sprinting");
pub const CL_KEYBIND_JUMP: console::CVar<i64> = create_keybind!(Space, "cl_keybind_jump", "Keybinding for jumping");

pub fn register_vars(console: &mut console::Console) {
    console.register(R_MAX_FPS);
    console.register(R_FOV);
    console.register(R_VSYNC);
    console.register(CL_MASTER_VOLUME);
    console.register(CL_KEYBIND_FORWARD);
    console.register(CL_KEYBIND_BACKWARD);
    console.register(CL_KEYBIND_LEFT);
    console.register(CL_KEYBIND_RIGHT);
    console.register(CL_KEYBIND_OPEN_INV);
    console.register(CL_KEYBIND_SNEAK);
    console.register(CL_KEYBIND_SPRINT);
    console.register(CL_KEYBIND_JUMP);
}

#[derive(Hash, PartialEq, Eq)]
pub enum Stevenkey {
    Forward,
    Backward,
    Left,
    Right,
    OpenInv,
    Sneak,
    Sprint,
    Jump,
}

impl Stevenkey {
    pub fn values() -> Vec<Stevenkey> {
        vec!(Stevenkey::Forward, Stevenkey::Backward, Stevenkey::Left,
            Stevenkey::Right, Stevenkey::OpenInv, Stevenkey::Sneak,
            Stevenkey::Sprint, Stevenkey::Jump)
    }

    pub fn get_by_keycode(keycode: Keycode, console: &console::Console) -> Option<Stevenkey> {
        for steven_key in Stevenkey::values() {
            if keycode as i64 == *console.get(steven_key.get_cvar()) {
                return Some(steven_key)
            }
        }
        None
    }

    pub fn get_cvar(&self) -> console::CVar<i64> {
        match *self {
            Stevenkey::Forward => CL_KEYBIND_FORWARD,
            Stevenkey::Backward => CL_KEYBIND_BACKWARD,
            Stevenkey::Left => CL_KEYBIND_LEFT,
            Stevenkey::Right => CL_KEYBIND_RIGHT,
            Stevenkey::OpenInv => CL_KEYBIND_OPEN_INV,
            Stevenkey::Sneak => CL_KEYBIND_SNEAK,
            Stevenkey::Sprint => CL_KEYBIND_SPRINT,
            Stevenkey::Jump => CL_KEYBIND_JUMP
        }
    }
}
<commit_msg>Default vsync to disabled<commit_after>use console;
use std::marker::PhantomData;
use sdl2::keyboard::Keycode;
// Might just rename this to settings.rs

pub const R_MAX_FPS: console::CVar<i64> = console::CVar {
    ty: PhantomData,
    name: "r_max_fps",
    description: "fps_max caps the maximum FPS for the rendering engine",
    mutable: true,
    serializable: true,
    default: &|| 60,
};

pub const R_FOV: console::CVar<i64> = console::CVar {
    ty: PhantomData,
    name: "r_fov",
    description: "Setting for controlling the client field of view",
    mutable: true,
    serializable: true,
    default: &|| 90,
};

pub const R_VSYNC: console::CVar<bool> = console::CVar {
    ty: PhantomData,
    name: "r_vsync",
    description: "Toggle to enable/disable vsync",
    mutable: true,
    serializable: true,
    default: &|| false,
};

pub const CL_MASTER_VOLUME: console::CVar<i64> = console::CVar {
    ty: PhantomData,
    name: "cl_master_volume",
    description: "Main volume control",
    mutable: true,
    serializable: true,
    default: &|| 100,
};

macro_rules! create_keybind {
    ($keycode:ident, $name:expr, $description:expr) => (console::CVar {
        ty: PhantomData,
        name: $name,
        description: $description,
        mutable: true,
        serializable: true,
        default: &|| Keycode::$keycode as i64
    })
}

pub const CL_KEYBIND_FORWARD: console::CVar<i64> = create_keybind!(W, "cl_keybind_forward", "Keybinding for moving forward");
pub const CL_KEYBIND_BACKWARD: console::CVar<i64> = create_keybind!(S, "cl_keybind_backward", "Keybinding for moving backward");
pub const CL_KEYBIND_LEFT: console::CVar<i64> = create_keybind!(A, "cl_keybind_left", "Keybinding for moving the left");
pub const CL_KEYBIND_RIGHT: console::CVar<i64> = create_keybind!(D, "cl_keybind_right", "Keybinding for moving to the right");
pub const CL_KEYBIND_OPEN_INV: console::CVar<i64> = create_keybind!(E, "cl_keybind_open_inv", "Keybinding for opening the inventory");
pub const CL_KEYBIND_SNEAK: console::CVar<i64> = create_keybind!(LShift, "cl_keybind_sneak", "Keybinding for sneaking");
pub const CL_KEYBIND_SPRINT: console::CVar<i64> = create_keybind!(LCtrl, "cl_keybind_sprint", "Keybinding for sprinting");
pub const CL_KEYBIND_JUMP: console::CVar<i64> = create_keybind!(Space, "cl_keybind_jump", "Keybinding for jumping");

pub fn register_vars(console: &mut console::Console) {
    console.register(R_MAX_FPS);
    console.register(R_FOV);
    console.register(R_VSYNC);
    console.register(CL_MASTER_VOLUME);
    console.register(CL_KEYBIND_FORWARD);
    console.register(CL_KEYBIND_BACKWARD);
    console.register(CL_KEYBIND_LEFT);
    console.register(CL_KEYBIND_RIGHT);
    console.register(CL_KEYBIND_OPEN_INV);
    console.register(CL_KEYBIND_SNEAK);
    console.register(CL_KEYBIND_SPRINT);
    console.register(CL_KEYBIND_JUMP);
}

#[derive(Hash, PartialEq, Eq)]
pub enum Stevenkey {
    Forward,
    Backward,
    Left,
    Right,
    OpenInv,
    Sneak,
    Sprint,
    Jump,
}

impl Stevenkey {
    pub fn values() -> Vec<Stevenkey> {
        vec!(Stevenkey::Forward, Stevenkey::Backward, Stevenkey::Left,
            Stevenkey::Right, Stevenkey::OpenInv, Stevenkey::Sneak,
            Stevenkey::Sprint, Stevenkey::Jump)
    }

    pub fn get_by_keycode(keycode: Keycode, console: &console::Console) -> Option<Stevenkey> {
        for steven_key in Stevenkey::values() {
            if keycode as i64 == *console.get(steven_key.get_cvar()) {
                return Some(steven_key)
            }
        }
        None
    }

    pub fn get_cvar(&self) -> console::CVar<i64> {
        match *self {
            Stevenkey::Forward => CL_KEYBIND_FORWARD,
            Stevenkey::Backward => CL_KEYBIND_BACKWARD,
            Stevenkey::Left => CL_KEYBIND_LEFT,
            Stevenkey::Right => CL_KEYBIND_RIGHT,
            Stevenkey::OpenInv => CL_KEYBIND_OPEN_INV,
            Stevenkey::Sneak => CL_KEYBIND_SNEAK,
            Stevenkey::Sprint => CL_KEYBIND_SPRINT,
            Stevenkey::Jump => CL_KEYBIND_JUMP
        }
    }
}
<|endoftext|>


<commit_before>use std::os::unix::io::RawFd;
use std::sync::RwLock;
use std::ptr;

use nix::sys::mman;

pub struct Pool {
    map: RwLock<MemMap>
}

pub enum ResizeError {
    InvalidSize,
    MremapFailed
}

impl Pool {
    pub fn new(fd: RawFd, size: usize) -> Result<Pool,()> {
        let memmap = MemMap::new(fd, size)?;
        Ok(Pool {
            map: RwLock::new(memmap)
        })
    }

    pub fn resize(&self, newsize: i32) -> Result<(),ResizeError> {
        let mut guard = self.map.write().unwrap();
        if newsize <= 0 || guard.size() > (newsize as usize) {
            return Err(ResizeError::InvalidSize)
        }
        guard.remap(newsize as usize).map_err(|()| ResizeError::MremapFailed)
    }

    pub fn with_data_slice<F: FnOnce(&[u8])>(&self, f: F) -> Result<(),()> {
        // TODO: handle SIGBUS
        let guard = self.map.read().unwrap();

        let slice = guard.get_slice();
        f(slice);

        Ok(())
    }
}

struct MemMap {
    ptr: *mut u8,
    fd: RawFd,
    size: usize
}

impl MemMap {
    fn new(fd: RawFd, size: usize) -> Result<MemMap,()> {
        Ok(MemMap {
            ptr: map(fd, size)?,
            fd: fd,
            size: size
        })
    }

    fn remap(&mut self, newsize: usize) -> Result<(),()> {
        unmap(self.ptr, self.size)?;
        self.ptr = map(self.fd, newsize)?;
        self.size = newsize;
        Ok(())
    }

    fn size(&self) -> usize {
        self.size
    }

    fn get_slice(&self) -> &[u8] {
        unsafe { ::std::slice::from_raw_parts(self.ptr, self.size) }
    }
}

// mman::mmap should really be unsafe... why isn't it?
#[allow(unused_unsafe)]
fn map(fd: RawFd, size: usize) -> Result<*mut u8, ()> {
    let ret = unsafe { mman::mmap(
        ptr::null_mut(),
        size,
        mman::PROT_READ,
        mman::MAP_SHARED,
        fd,
        0
    ) };
    ret.map(|p| p as *mut u8).map_err(|_| ())
}

// mman::munmap should really be unsafe... why isn't it?
#[allow(unused_unsafe)]
fn unmap(ptr: *mut u8, size: usize) -> Result<(),()> {
    let ret = unsafe { mman::munmap(ptr as *mut _, size) };
    ret.map_err(|_| ())
}
<commit_msg>shm: add a proper Drop implementation to MemMap<commit_after>use std::os::unix::io::RawFd;
use std::sync::RwLock;
use std::ptr;

use nix::sys::mman;

pub struct Pool {
    map: RwLock<MemMap>
}

pub enum ResizeError {
    InvalidSize,
    MremapFailed
}

impl Pool {
    pub fn new(fd: RawFd, size: usize) -> Result<Pool,()> {
        let memmap = MemMap::new(fd, size)?;
        Ok(Pool {
            map: RwLock::new(memmap)
        })
    }

    pub fn resize(&self, newsize: i32) -> Result<(),ResizeError> {
        let mut guard = self.map.write().unwrap();
        if newsize <= 0 || guard.size() > (newsize as usize) {
            return Err(ResizeError::InvalidSize)
        }
        guard.remap(newsize as usize).map_err(|()| ResizeError::MremapFailed)
    }

    pub fn with_data_slice<F: FnOnce(&[u8])>(&self, f: F) -> Result<(),()> {
        // TODO: handle SIGBUS
        let guard = self.map.read().unwrap();

        let slice = guard.get_slice();
        f(slice);

        Ok(())
    }
}

struct MemMap {
    ptr: *mut u8,
    fd: RawFd,
    size: usize
}

impl MemMap {
    fn new(fd: RawFd, size: usize) -> Result<MemMap,()> {
        Ok(MemMap {
            ptr: unsafe { map(fd, size) }?,
            fd: fd,
            size: size
        })
    }

    fn remap(&mut self, newsize: usize) -> Result<(),()> {
        if self.ptr.is_null() {
            return Err(())
        }
        // memunmap cannot fail, as we are unmapping a pre-existing map
        let _ = unsafe { unmap(self.ptr, self.size) };
        // remap the fd with the new size
        match unsafe { map(self.fd, newsize) } {
            Ok(ptr) => {
                // update the parameters
                self.ptr = ptr;
                self.size = newsize;
                Ok(())
            },
            Err(()) => {
                // set ourselves in an empty state
                self.ptr = ptr::null_mut();
                self.size = 0;
                self.fd = -1;
                Err(())
            }
        }
    }

    fn size(&self) -> usize {
        self.size
    }

    fn get_slice(&self) -> &[u8] {
        // if we are in the 'invalid state', self.size == 0 and we return &[]
        // which is perfectly safe even if self.ptr is null
        unsafe { ::std::slice::from_raw_parts(self.ptr, self.size) }
    }
}

impl Drop for MemMap {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            let _ = unsafe { unmap(self.ptr, self.size) };
        }
    }
}

// mman::mmap should really be unsafe... why isn't it?
unsafe fn map(fd: RawFd, size: usize) -> Result<*mut u8, ()> {
    let ret = mman::mmap(
        ptr::null_mut(),
        size,
        mman::PROT_READ,
        mman::MAP_SHARED,
        fd,
        0
    );
    ret.map(|p| p as *mut u8).map_err(|_| ())
}

// mman::munmap should really be unsafe... why isn't it?
unsafe fn unmap(ptr: *mut u8, size: usize) -> Result<(),()> {
    let ret = mman::munmap(ptr as *mut _, size);
    ret.map_err(|_| ())
}
<|endoftext|>