<commit_before>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Michael Gehring <mg@ebfe.org>
//  * (c) kwantam <kwantam@gmail.com>
//  *     * 2015-04-28 ~ created `expand` module to eliminate most allocs during setup
//  * (c) Sergey "Shnatsel" Davidoff <shnatsel@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) allocs bset dflag cflag sflag tflag

#[macro_use]
extern crate uucore;

mod expand;

use bit_set::BitSet;
use clap::{crate_version, App, Arg};
use fnv::FnvHashMap;
use std::io::{stdin, stdout, BufRead, BufWriter, Write};

use crate::expand::ExpandSet;
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "translate or delete characters";

const BUFFER_LEN: usize = 1024;

mod options {
    pub const COMPLEMENT: &str = "complement";
    pub const DELETE: &str = "delete";
    pub const SQUEEZE: &str = "squeeze-repeats";
    pub const TRUNCATE: &str = "truncate";
    pub const SETS: &str = "sets";
}

trait SymbolTranslator {
    fn translate(&self, c: char, prev_c: char) -> Option<char>;
}

struct DeleteOperation {
    bset: BitSet,
    complement: bool,
}

impl DeleteOperation {
    fn new(set: ExpandSet, complement: bool) -> DeleteOperation {
        DeleteOperation {
            bset: set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for DeleteOperation {
    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
        let uc = c as usize;
        if self.complement == self.bset.contains(uc) {
            Some(c)
        } else {
            None
        }
    }
}

struct SqueezeOperation {
    squeeze_set: BitSet,
    complement: bool,
}

impl SqueezeOperation {
    fn new(squeeze_set: ExpandSet, complement: bool) -> SqueezeOperation {
        SqueezeOperation {
            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for SqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        if prev_c == c && self.complement != self.squeeze_set.contains(c as usize) {
            None
        } else {
            Some(c)
        }
    }
}

struct DeleteAndSqueezeOperation {
    delete_set: BitSet,
    squeeze_set: BitSet,
    complement: bool,
}

impl DeleteAndSqueezeOperation {
    fn new(
        delete_set: ExpandSet,
        squeeze_set: ExpandSet,
        complement: bool,
    ) -> DeleteAndSqueezeOperation {
        DeleteAndSqueezeOperation {
            delete_set: delete_set.map(|c| c as usize).collect(),
            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for DeleteAndSqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        if self.complement != self.delete_set.contains(c as usize)
            || prev_c == c && self.squeeze_set.contains(c as usize)
        {
            None
        } else {
            Some(c)
        }
    }
}

struct TranslateOperation {
    translate_map: FnvHashMap<usize, char>,
    complement: bool,
    s2_last: char,
}

impl TranslateOperation {
    fn new(
        set1: ExpandSet,
        set2: &mut ExpandSet,
        truncate: bool,
        complement: bool,
    ) -> TranslateOperation {
        let mut map = FnvHashMap::default();
        let mut s2_prev = '_';
        for i in set1 {
            let s2_next = set2.next();

            if s2_next.is_none() && truncate {
                map.insert(i as usize, i);
            } else {
                s2_prev = s2_next.unwrap_or(s2_prev);
                map.insert(i as usize, s2_prev);
            }
        }
        TranslateOperation {
            translate_map: map,
            complement,
            s2_last: set2.last().unwrap_or(s2_prev),
        }
    }
}

impl SymbolTranslator for TranslateOperation {
    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
        if self.complement {
            Some(if self.translate_map.contains_key(&(c as usize)) {
                c
            } else {
                self.s2_last
            })
        } else {
            Some(*self.translate_map.get(&(c as usize)).unwrap_or(&c))
        }
    }
}

struct TranslateAndSqueezeOperation {
    translate: TranslateOperation,
    squeeze: SqueezeOperation,
}

impl TranslateAndSqueezeOperation {
    fn new(
        set1: ExpandSet,
        set2: &mut ExpandSet,
        set2_: ExpandSet,
        truncate: bool,
        complement: bool,
    ) -> TranslateAndSqueezeOperation {
        TranslateAndSqueezeOperation {
            translate: TranslateOperation::new(set1, set2, truncate, complement),
            squeeze: SqueezeOperation::new(set2_, complement),
        }
    }
}

impl SymbolTranslator for TranslateAndSqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        // `unwrap()` will never panic because `Translate.translate()`
        // always returns `Some`.
        self.squeeze
            .translate(self.translate.translate(c, 0 as char).unwrap(), prev_c)
    }
}

fn translate_input<T: SymbolTranslator>(
    input: &mut dyn BufRead,
    output: &mut dyn Write,
    translator: T,
) {
    let mut buf = String::with_capacity(BUFFER_LEN + 4);
    let mut output_buf = String::with_capacity(BUFFER_LEN + 4);

    while let Ok(length) = input.read_line(&mut buf) {
        let mut prev_c = 0 as char;
        if length == 0 {
            break;
        }
        {
            // isolation to make borrow checker happy
            let filtered = buf.chars().filter_map(|c| {
                let res = translator.translate(c, prev_c);
                // Set `prev_c` to the post-translate character. This
                // allows the squeeze operation to correctly function
                // after the translate operation.
                if let Some(rc) = res {
                    prev_c = rc;
                }
                res
            });

            output_buf.extend(filtered);
            output.write_all(output_buf.as_bytes()).unwrap();
        }
        buf.clear();
        output_buf.clear();
    }
}

fn get_usage() -> String {
    format!("{} [OPTION]... SET1 [SET2]", executable!())
}

fn get_long_usage() -> String {
    format!(
        "Translate, squeeze, and/or delete characters from standard input,
writing to standard output.",
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let delete_flag = matches.is_present(options::DELETE);
    let complement_flag = matches.is_present(options::COMPLEMENT) || matches.is_present("C");
    let squeeze_flag = matches.is_present(options::SQUEEZE);
    let truncate_flag = matches.is_present(options::TRUNCATE);

    let sets = match matches.values_of(options::SETS) {
        Some(v) => v.map(|v| v.to_string()).collect(),
        None => vec![],
    };

    if sets.is_empty() {
        show_error!(
            "missing operand\nTry `{} --help` for more information.",
            executable!()
        );
        return 1;
    }

    if !(delete_flag || squeeze_flag) && sets.len() < 2 {
        show_error!(
            "missing operand after '{}'\nTry `{} --help` for more information.",
            sets[0],
            executable!()
        );
        return 1;
    }

    let stdin = stdin();
    let mut locked_stdin = stdin.lock();
    let stdout = stdout();
    let locked_stdout = stdout.lock();
    let mut buffered_stdout = BufWriter::new(locked_stdout);

    let set1 = ExpandSet::new(sets[0].as_ref());
    if delete_flag {
        if squeeze_flag {
            let set2 = ExpandSet::new(sets[1].as_ref());
            let op = DeleteAndSqueezeOperation::new(set1, set2, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        } else {
            let op = DeleteOperation::new(set1, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        }
    } else if squeeze_flag {
        if sets.len() < 2 {
            let op = SqueezeOperation::new(set1, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        } else {
            let mut set2 = ExpandSet::new(sets[1].as_ref());
            let set2_ = ExpandSet::new(sets[1].as_ref());
            let op = TranslateAndSqueezeOperation::new(
                set1,
                &mut set2,
                set2_,
                complement_flag,
                truncate_flag,
            );
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        }
    } else {
        let mut set2 = ExpandSet::new(sets[1].as_ref());
        let op = TranslateOperation::new(set1, &mut set2, truncate_flag, complement_flag);
        translate_input(&mut locked_stdin, &mut buffered_stdout, op);
    }

    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::COMPLEMENT)
                // .visible_short_alias('C')  // TODO: requires clap "3.0.0-beta.2"
                .short("c")
                .long(options::COMPLEMENT)
                .help("use the complement of SET1"),
        )
        .arg(
            Arg::with_name("C") // work around for `Arg::visible_short_alias`
                .short("C")
                .help("same as -c"),
        )
        .arg(
            Arg::with_name(options::DELETE)
                .short("d")
                .long(options::DELETE)
                .help("delete characters in SET1, do not translate"),
        )
        .arg(
            Arg::with_name(options::SQUEEZE)
                .long(options::SQUEEZE)
                .short("s")
                .help(
                    "replace each sequence  of  a  repeated  character  that  is
  listed  in the last specified SET, with a single occurrence
  of that character",
                ),
        )
        .arg(
            Arg::with_name(options::TRUNCATE)
                .long(options::TRUNCATE)
                .short("t")
                .help("first truncate SET1 to length of SET2"),
        )
        .arg(
            Arg::with_name(options::SETS)
                .multiple(true)
                .takes_value(true)
                .max_values(2),
        )
}
<commit_msg>Removed manual checks to just using clap instead<commit_after>//  * This file is part of the uutils coreutils package.
//  *
//  * (c) Michael Gehring <mg@ebfe.org>
//  * (c) kwantam <kwantam@gmail.com>
//  *     * 2015-04-28 ~ created `expand` module to eliminate most allocs during setup
//  * (c) Sergey "Shnatsel" Davidoff <shnatsel@gmail.com>
//  *
//  * For the full copyright and license information, please view the LICENSE
//  * file that was distributed with this source code.

// spell-checker:ignore (ToDO) allocs bset dflag cflag sflag tflag

#[macro_use]
extern crate uucore;

mod expand;

use bit_set::BitSet;
use clap::{crate_version, App, Arg};
use fnv::FnvHashMap;
use std::io::{stdin, stdout, BufRead, BufWriter, Write};

use crate::expand::ExpandSet;
use uucore::InvalidEncodingHandling;

static ABOUT: &str = "translate or delete characters";

const BUFFER_LEN: usize = 1024;

mod options {
    pub const COMPLEMENT: &str = "complement";
    pub const DELETE: &str = "delete";
    pub const SQUEEZE: &str = "squeeze-repeats";
    pub const TRUNCATE: &str = "truncate";
    pub const SETS: &str = "sets";
}

trait SymbolTranslator {
    fn translate(&self, c: char, prev_c: char) -> Option<char>;
}

struct DeleteOperation {
    bset: BitSet,
    complement: bool,
}

impl DeleteOperation {
    fn new(set: ExpandSet, complement: bool) -> DeleteOperation {
        DeleteOperation {
            bset: set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for DeleteOperation {
    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
        let uc = c as usize;
        if self.complement == self.bset.contains(uc) {
            Some(c)
        } else {
            None
        }
    }
}

struct SqueezeOperation {
    squeeze_set: BitSet,
    complement: bool,
}

impl SqueezeOperation {
    fn new(squeeze_set: ExpandSet, complement: bool) -> SqueezeOperation {
        SqueezeOperation {
            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for SqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        if prev_c == c && self.complement != self.squeeze_set.contains(c as usize) {
            None
        } else {
            Some(c)
        }
    }
}

struct DeleteAndSqueezeOperation {
    delete_set: BitSet,
    squeeze_set: BitSet,
    complement: bool,
}

impl DeleteAndSqueezeOperation {
    fn new(
        delete_set: ExpandSet,
        squeeze_set: ExpandSet,
        complement: bool,
    ) -> DeleteAndSqueezeOperation {
        DeleteAndSqueezeOperation {
            delete_set: delete_set.map(|c| c as usize).collect(),
            squeeze_set: squeeze_set.map(|c| c as usize).collect(),
            complement,
        }
    }
}

impl SymbolTranslator for DeleteAndSqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        if self.complement != self.delete_set.contains(c as usize)
            || prev_c == c && self.squeeze_set.contains(c as usize)
        {
            None
        } else {
            Some(c)
        }
    }
}

struct TranslateOperation {
    translate_map: FnvHashMap<usize, char>,
    complement: bool,
    s2_last: char,
}

impl TranslateOperation {
    fn new(
        set1: ExpandSet,
        set2: &mut ExpandSet,
        truncate: bool,
        complement: bool,
    ) -> TranslateOperation {
        let mut map = FnvHashMap::default();
        let mut s2_prev = '_';
        for i in set1 {
            let s2_next = set2.next();

            if s2_next.is_none() && truncate {
                map.insert(i as usize, i);
            } else {
                s2_prev = s2_next.unwrap_or(s2_prev);
                map.insert(i as usize, s2_prev);
            }
        }
        TranslateOperation {
            translate_map: map,
            complement,
            s2_last: set2.last().unwrap_or(s2_prev),
        }
    }
}

impl SymbolTranslator for TranslateOperation {
    fn translate(&self, c: char, _prev_c: char) -> Option<char> {
        if self.complement {
            Some(if self.translate_map.contains_key(&(c as usize)) {
                c
            } else {
                self.s2_last
            })
        } else {
            Some(*self.translate_map.get(&(c as usize)).unwrap_or(&c))
        }
    }
}

struct TranslateAndSqueezeOperation {
    translate: TranslateOperation,
    squeeze: SqueezeOperation,
}

impl TranslateAndSqueezeOperation {
    fn new(
        set1: ExpandSet,
        set2: &mut ExpandSet,
        set2_: ExpandSet,
        truncate: bool,
        complement: bool,
    ) -> TranslateAndSqueezeOperation {
        TranslateAndSqueezeOperation {
            translate: TranslateOperation::new(set1, set2, truncate, complement),
            squeeze: SqueezeOperation::new(set2_, complement),
        }
    }
}

impl SymbolTranslator for TranslateAndSqueezeOperation {
    fn translate(&self, c: char, prev_c: char) -> Option<char> {
        // `unwrap()` will never panic because `Translate.translate()`
        // always returns `Some`.
        self.squeeze
            .translate(self.translate.translate(c, 0 as char).unwrap(), prev_c)
    }
}

fn translate_input<T: SymbolTranslator>(
    input: &mut dyn BufRead,
    output: &mut dyn Write,
    translator: T,
) {
    let mut buf = String::with_capacity(BUFFER_LEN + 4);
    let mut output_buf = String::with_capacity(BUFFER_LEN + 4);

    while let Ok(length) = input.read_line(&mut buf) {
        let mut prev_c = 0 as char;
        if length == 0 {
            break;
        }
        {
            // isolation to make borrow checker happy
            let filtered = buf.chars().filter_map(|c| {
                let res = translator.translate(c, prev_c);
                // Set `prev_c` to the post-translate character. This
                // allows the squeeze operation to correctly function
                // after the translate operation.
                if let Some(rc) = res {
                    prev_c = rc;
                }
                res
            });

            output_buf.extend(filtered);
            output.write_all(output_buf.as_bytes()).unwrap();
        }
        buf.clear();
        output_buf.clear();
    }
}

fn get_usage() -> String {
    format!("{} [OPTION]... SET1 [SET2]", executable!())
}

fn get_long_usage() -> String {
    format!(
        "Translate, squeeze, and/or delete characters from standard input,
writing to standard output.",
    )
}

pub fn uumain(args: impl uucore::Args) -> i32 {
    let args = args
        .collect_str(InvalidEncodingHandling::ConvertLossy)
        .accept_any();

    let usage = get_usage();
    let after_help = get_long_usage();

    let matches = uu_app()
        .usage(&usage[..])
        .after_help(&after_help[..])
        .get_matches_from(args);

    let delete_flag = matches.is_present(options::DELETE);
    let complement_flag = matches.is_present(options::COMPLEMENT) || matches.is_present("C");
    let squeeze_flag = matches.is_present(options::SQUEEZE);
    let truncate_flag = matches.is_present(options::TRUNCATE);

    let sets = match matches.values_of(options::SETS) {
        Some(v) => v.map(|v| v.to_string()).collect(),
        None => vec![],
    };

    if sets.is_empty() {
        show_error!(
            "missing operand\nTry `{} --help` for more information.",
            executable!()
        );
        return 1;
    }

    if !(delete_flag || squeeze_flag) && sets.len() < 2 {
        show_error!(
            "missing operand after '{}'\nTry `{} --help` for more information.",
            sets[0],
            executable!()
        );
        return 1;
    }

    let stdin = stdin();
    let mut locked_stdin = stdin.lock();
    let stdout = stdout();
    let locked_stdout = stdout.lock();
    let mut buffered_stdout = BufWriter::new(locked_stdout);

    let set1 = ExpandSet::new(sets[0].as_ref());
    if delete_flag {
        if squeeze_flag {
            let set2 = ExpandSet::new(sets[1].as_ref());
            let op = DeleteAndSqueezeOperation::new(set1, set2, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        } else {
            let op = DeleteOperation::new(set1, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        }
    } else if squeeze_flag {
        if sets.len() < 2 {
            let op = SqueezeOperation::new(set1, complement_flag);
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        } else {
            let mut set2 = ExpandSet::new(sets[1].as_ref());
            let set2_ = ExpandSet::new(sets[1].as_ref());
            let op = TranslateAndSqueezeOperation::new(
                set1,
                &mut set2,
                set2_,
                complement_flag,
                truncate_flag,
            );
            translate_input(&mut locked_stdin, &mut buffered_stdout, op);
        }
    } else {
        let mut set2 = ExpandSet::new(sets[1].as_ref());
        let op = TranslateOperation::new(set1, &mut set2, truncate_flag, complement_flag);
        translate_input(&mut locked_stdin, &mut buffered_stdout, op);
    }

    0
}

pub fn uu_app() -> App<'static, 'static> {
    App::new(executable!())
        .version(crate_version!())
        .about(ABOUT)
        .arg(
            Arg::with_name(options::COMPLEMENT)
                // .visible_short_alias('C')  // TODO: requires clap "3.0.0-beta.2"
                .short("c")
                .long(options::COMPLEMENT)
                .help("use the complement of SET1"),
        )
        .arg(
            Arg::with_name("C") // work around for `Arg::visible_short_alias`
                .short("C")
                .help("same as -c"),
        )
        .arg(
            Arg::with_name(options::DELETE)
                .short("d")
                .long(options::DELETE)
                .help("delete characters in SET1, do not translate"),
        )
        .arg(
            Arg::with_name(options::SQUEEZE)
                .long(options::SQUEEZE)
                .short("s")
                .help(
                    "replace each sequence  of  a  repeated  character  that  is
  listed  in the last specified SET, with a single occurrence
  of that character",
                ),
        )
        .arg(
            Arg::with_name(options::TRUNCATE)
                .long(options::TRUNCATE)
                .short("t")
                .help("first truncate SET1 to length of SET2"),
        )
        .arg(
            Arg::with_name(options::SETS)
                .multiple(true)
                .takes_value(true)
                .min_values(1)
                .max_values(2),
        )
}
<|endoftext|>


<commit_before>use async_std::io::{ReadExt, WriteExt};
use futures_io::AsyncWrite;

use super::bucket::Bucket;
use super::command::Command;
use chrono::{DateTime, Utc};

use crate::command::HttpMethod;
use crate::request_trait::Request;

use anyhow::{anyhow, Result};
use http::HeaderMap;
use maybe_async::maybe_async;
use surf::http::headers::{HeaderName, HeaderValue};
use surf::http::Method;

// Temporary structure for making a request
pub struct SurfRequest<'a> {
    pub bucket: &'a Bucket,
    pub path: &'a str,
    pub command: Command<'a>,
    pub datetime: DateTime<Utc>,
    pub sync: bool,
}

#[maybe_async]
impl<'a> Request for SurfRequest<'a> {
    type Response = surf::Response;
    type HeaderMap = HeaderMap;

    fn datetime(&self) -> DateTime<Utc> {
        self.datetime
    }

    fn bucket(&self) -> Bucket {
        self.bucket.clone()
    }

    fn command(&self) -> Command {
        self.command.clone()
    }

    fn path(&self) -> String {
        self.path.to_string()
    }

    async fn response(&self) -> Result<surf::Response> {
        // Build headers
        let headers = self.headers()?;

        let request = match self.command.http_verb() {
            HttpMethod::Get => surf::Request::builder(Method::Get, self.url()),
            HttpMethod::Delete => surf::Request::builder(Method::Delete, self.url()),
            HttpMethod::Put => surf::Request::builder(Method::Put, self.url()),
            HttpMethod::Post => surf::Request::builder(Method::Post, self.url()),
            HttpMethod::Head => surf::Request::builder(Method::Head, self.url()),
        };

        let mut request = request.body(self.request_body());

        for (name, value) in headers.iter() {
            request = request.header(
                HeaderName::from_bytes(AsRef::<[u8]>::as_ref(&name).to_vec()).unwrap(),
                HeaderValue::from_bytes(AsRef::<[u8]>::as_ref(&value).to_vec()).unwrap(),
            );
        }

        let response = request.send().await.unwrap();

        if cfg!(feature = "fail-on-err") && !response.status().is_success() {
            return Err(anyhow!("Request failed with code {}", response.status()));
        }

        Ok(response)
    }

    async fn response_data(&self, etag: bool) -> Result<(Vec<u8>, u16)> {
        let mut response = self.response().await?;
        let status_code = response.status();
        let body = response.body_bytes().await.unwrap();
        let mut body_vec = Vec::new();
        body_vec.extend_from_slice(&body[..]);
        if etag {
            if let Some(etag) = response.header("ETag") {
                body_vec = etag.as_str().to_string().as_bytes().to_vec();
            }
        }
        Ok((body_vec, status_code.into()))
    }

    async fn response_data_to_writer<T: AsyncWrite + Send + Unpin>(
        &self,
        writer: &mut T,
    ) -> Result<u16> {
        let mut buffer = Vec::new();

        let response = self.response().await?;

        let status_code = response.status();

        let mut stream = surf::http::Body::from_reader(response, None);

        stream.read_to_end(&mut buffer).await?;

        writer.write_all(&buffer).await?;

        Ok(status_code.into())
    }

    async fn response_header(&self) -> Result<(HeaderMap, u16)> {
        let mut header_map = HeaderMap::new();
        let response = self.response().await?;
        let status_code = response.status();

        for (name, value) in response.iter() {
            header_map.insert(
                http::header::HeaderName::from_lowercase(
                    name.to_string().to_ascii_lowercase().as_ref(),
                )
                .unwrap(),
                value.as_str().parse().unwrap(),
            );
        }
        Ok((header_map, status_code.into()))
    }
}

impl<'a> SurfRequest<'a> {
    pub fn new<'b>(bucket: &'b Bucket, path: &'b str, command: Command<'b>) -> SurfRequest<'b> {
        SurfRequest {
            bucket,
            path,
            command,
            datetime: Utc::now(),
            sync: false,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::bucket::Bucket;
    use crate::command::Command;
    use crate::request_trait::Request;
    use crate::surf_request::SurfRequest;
    use anyhow::Result;
    use awscreds::Credentials;

    // Fake keys - otherwise using Credentials::default will use actual user
    // credentials if they exist.
    fn fake_credentials() -> Credentials {
        let access_key = "AKIAIOSFODNN7EXAMPLE";
        let secert_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
        Credentials::new(Some(access_key), Some(secert_key), None, None, None).unwrap()
    }

    #[test]
    fn url_uses_https_by_default() -> Result<()> {
        let region = "custom-region".parse()?;
        let bucket = Bucket::new("my-first-bucket", region, fake_credentials())?;
        let path = "/my-first/path";
        let request = SurfRequest::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "https");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        assert_eq!(*host, "my-first-bucket.custom-region".to_string());
        Ok(())
    }

    #[test]
    fn url_uses_https_by_default_path_style() -> Result<()> {
        let region = "custom-region".parse()?;
        let bucket = Bucket::new_with_path_style("my-first-bucket", region, fake_credentials())?;
        let path = "/my-first/path";
        let request = SurfRequest::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "https");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        assert_eq!(*host, "custom-region".to_string());
        Ok(())
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined() -> Result<()> {
        let region = "http://custom-region".parse()?;
        let bucket = Bucket::new("my-second-bucket", region, fake_credentials())?;
        let path = "/my-second/path";
        let request = SurfRequest::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "http");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();
        assert_eq!(*host, "my-second-bucket.custom-region".to_string());
        Ok(())
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined_with_path_style() -> Result<()> {
        let region = "http://custom-region".parse()?;
        let bucket = Bucket::new_with_path_style("my-second-bucket", region, fake_credentials())?;
        let path = "/my-second/path";
        let request = SurfRequest::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "http");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();
        assert_eq!(*host, "custom-region".to_string());

        Ok(())
    }
}
<commit_msg>fix #241 (#242)<commit_after>use async_std::io::{ReadExt, WriteExt};
use futures_io::AsyncWrite;

use super::bucket::Bucket;
use super::command::Command;
use chrono::{DateTime, Utc};

use crate::command::HttpMethod;
use crate::request_trait::Request;

use anyhow::{anyhow, Result};
use http::HeaderMap;
use maybe_async::maybe_async;
use surf::http::headers::{HeaderName, HeaderValue};
use surf::http::Method;

// Temporary structure for making a request
pub struct SurfRequest<'a> {
    pub bucket: &'a Bucket,
    pub path: &'a str,
    pub command: Command<'a>,
    pub datetime: DateTime<Utc>,
    pub sync: bool,
}

#[maybe_async]
impl<'a> Request for SurfRequest<'a> {
    type Response = surf::Response;
    type HeaderMap = HeaderMap;

    fn datetime(&self) -> DateTime<Utc> {
        self.datetime
    }

    fn bucket(&self) -> Bucket {
        self.bucket.clone()
    }

    fn command(&self) -> Command {
        self.command.clone()
    }

    fn path(&self) -> String {
        self.path.to_string()
    }

    async fn response(&self) -> Result<surf::Response> {
        // Build headers
        let headers = self.headers()?;

        let request = match self.command.http_verb() {
            HttpMethod::Get => surf::Request::builder(Method::Get, self.url()),
            HttpMethod::Delete => surf::Request::builder(Method::Delete, self.url()),
            HttpMethod::Put => surf::Request::builder(Method::Put, self.url()),
            HttpMethod::Post => surf::Request::builder(Method::Post, self.url()),
            HttpMethod::Head => surf::Request::builder(Method::Head, self.url()),
        };

        let mut request = request.body(self.request_body());

        for (name, value) in headers.iter() {
            request = request.header(
                HeaderName::from_bytes(AsRef::<[u8]>::as_ref(&name).to_vec()).unwrap(),
                HeaderValue::from_bytes(AsRef::<[u8]>::as_ref(&value).to_vec()).unwrap(),
            );
        }

        let response = request.send().await.or_else(|e| Err(anyhow!("Request failed with {}", e.to_string())))?;

        if cfg!(feature = "fail-on-err") && !response.status().is_success() {
            return Err(anyhow!("Request failed with code {}", response.status()));
        }

        Ok(response)
    }

    async fn response_data(&self, etag: bool) -> Result<(Vec<u8>, u16)> {
        let mut response = self.response().await?;
        let status_code = response.status();
        let body = response.body_bytes().await.or_else(|e| Err(anyhow!("Request failed with {}", e.to_string())))?;
        let mut body_vec = Vec::new();
        body_vec.extend_from_slice(&body[..]);
        if etag {
            if let Some(etag) = response.header("ETag") {
                body_vec = etag.as_str().to_string().as_bytes().to_vec();
            }
        }
        Ok((body_vec, status_code.into()))
    }

    async fn response_data_to_writer<T: AsyncWrite + Send + Unpin>(
        &self,
        writer: &mut T,
    ) -> Result<u16> {
        let mut buffer = Vec::new();

        let response = self.response().await?;

        let status_code = response.status();

        let mut stream = surf::http::Body::from_reader(response, None);

        stream.read_to_end(&mut buffer).await?;

        writer.write_all(&buffer).await?;

        Ok(status_code.into())
    }

    async fn response_header(&self) -> Result<(HeaderMap, u16)> {
        let mut header_map = HeaderMap::new();
        let response = self.response().await?;
        let status_code = response.status();

        for (name, value) in response.iter() {
            header_map.insert(
                http::header::HeaderName::from_lowercase(
                    name.to_string().to_ascii_lowercase().as_ref(),
                )?,
                value.as_str().parse()?,
            );
        }
        Ok((header_map, status_code.into()))
    }
}

impl<'a> SurfRequest<'a> {
    pub fn new<'b>(bucket: &'b Bucket, path: &'b str, command: Command<'b>) -> SurfRequest<'b> {
        SurfRequest {
            bucket,
            path,
            command,
            datetime: Utc::now(),
            sync: false,
        }
    }
}

#[cfg(test)]
mod tests {
    use crate::bucket::Bucket;
    use crate::command::Command;
    use crate::request_trait::Request;
    use crate::surf_request::SurfRequest;
    use anyhow::Result;
    use awscreds::Credentials;

    // Fake keys - otherwise using Credentials::default will use actual user
    // credentials if they exist.
    fn fake_credentials() -> Credentials {
        let access_key = "AKIAIOSFODNN7EXAMPLE";
        let secert_key = "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
        Credentials::new(Some(access_key), Some(secert_key), None, None, None).unwrap()
    }

    #[test]
    fn url_uses_https_by_default() -> Result<()> {
        let region = "custom-region".parse()?;
        let bucket = Bucket::new("my-first-bucket", region, fake_credentials())?;
        let path = "/my-first/path";
        let request = SurfRequest::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "https");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        assert_eq!(*host, "my-first-bucket.custom-region".to_string());
        Ok(())
    }

    #[test]
    fn url_uses_https_by_default_path_style() -> Result<()> {
        let region = "custom-region".parse()?;
        let bucket = Bucket::new_with_path_style("my-first-bucket", region, fake_credentials())?;
        let path = "/my-first/path";
        let request = SurfRequest::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "https");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();

        assert_eq!(*host, "custom-region".to_string());
        Ok(())
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined() -> Result<()> {
        let region = "http://custom-region".parse()?;
        let bucket = Bucket::new("my-second-bucket", region, fake_credentials())?;
        let path = "/my-second/path";
        let request = SurfRequest::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "http");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();
        assert_eq!(*host, "my-second-bucket.custom-region".to_string());
        Ok(())
    }

    #[test]
    fn url_uses_scheme_from_custom_region_if_defined_with_path_style() -> Result<()> {
        let region = "http://custom-region".parse()?;
        let bucket = Bucket::new_with_path_style("my-second-bucket", region, fake_credentials())?;
        let path = "/my-second/path";
        let request = SurfRequest::new(&bucket, path, Command::GetObject);

        assert_eq!(request.url().scheme(), "http");

        let headers = request.headers().unwrap();
        let host = headers.get("Host").unwrap();
        assert_eq!(*host, "custom-region".to_string());

        Ok(())
    }
}
<|endoftext|>


<commit_before>use extra::treemap::TreeMap;
use super::methods::Method;
use super::status;
use super::server::TcpStream;
use std::rt::io::Reader;
use std::{str, uint};
use super::rfc2616::{CR, LF, SP, HT, COLON};
use super::headers::{Headers, normalise_header_name};

pub enum HeaderLineErr { EndOfFile, EndOfHeaders, MalformedHeader }

////////////////////////////////////////////////////////////////////////////////////////////////////
pub struct RequestBuffer<'self> {
    priv stream: &'self mut TcpStream,
    priv bytes: ~[u8],
    priv peeked_byte: Option<u8>,
}

static SIZE: uint = 1024;

impl<'self> RequestBuffer<'self> {
    pub fn new<'a> (stream: &'a mut TcpStream) -> RequestBuffer<'a> {
        RequestBuffer {
            stream: stream,
            bytes: ~[0u8, ..SIZE],
            peeked_byte: None,
        }
    }

    /*pub fn peek_byte(&mut self) -> Option<u8> {
        if self.peeked_byte.is_some() {
            fail!("Already called peek_byte() without having called read_byte()");
            // ... sorry, VERY nasty quick hack.
        }
    }*/

    pub fn read_byte(&mut self) -> Option<u8> {
        match self.peeked_byte {
            Some(byte) => {
                self.peeked_byte = None;
                Some(byte)
            },
            None => {
                let mut buf = ~[0];
                match self.stream.read(buf) {
                    None => return None,
                    Some(1) => Some(buf[0]),
                    Some(i) => fail!("TcpStream.read() returned %u!?", i),
                }
            },
        }
    }

    /// Read a line ending in CRLF
    pub fn read_crlf_line(&mut self) -> ~str {
        self.bytes.clear();

        enum State { Normal, GotCR };
        let mut state = Normal;

        loop {
            state = match self.read_byte() {
                None => fail!("EOF"),
                Some(b) => match state {
                    Normal if b == CR => {
                        GotCR
                    },
                    GotCR if b == LF => {
                        break;
                    },
                    GotCR => {
                        self.bytes.push(CR);
                        self.bytes.push(b);
                        Normal
                    },
                    Normal => {
                        self.bytes.push(b);
                        Normal
                    }
                }
            };
        }
        str::from_bytes(self.bytes)
    }

    /// Read a header (name, value) pair.
    ///
    /// This is not necessarily just a line ending with CRLF; there are much fancier rules at work.
    /// Where appropriate (TODO, it's everywhere at present) linear whitespace is collapsed into a
    /// single space.
    ///
    /// # Error values
    ///
    /// - `EndOfHeaders`: I have no more headers to give; go forth and conquer on the body!
    /// - `EndOfFile`: socket was closed unexpectedly; probable best behavour is to drop the request
    /// - `MalformedHeader`: request is bad; you could drop it or try returning 400 Bad Request
    pub fn read_header_line(&mut self) -> Result<(~str, ~str), HeaderLineErr> {
        enum State2 { Normal, CompactingLWS, GotCR, GotCRLF };
        // XXX: not called State because of https://github.com/mozilla/rust/issues/7770
        // TODO: investigate quoted strings

        let mut state = Normal;
        let mut in_name = true;
        let mut header_name = ~"";
        self.bytes.clear();

        loop {
            state = match self.read_byte() {
                None => return Err(EndOfFile),
                Some(b) => match state {
                    Normal | CompactingLWS if b == CR => {
                        // It's OK to go to GotCR on CompactingLWS: if it ends up CRLFSP it'll get
                        // back to CompactingLWS, and if it ends up CRLF we didn't need the trailing
                        // whitespace anyway.
                        GotCR
                    },
                    Normal | CompactingLWS if in_name && b == COLON => {
                        // As above, don't worry about trailing whitespace.
                        // Found the colon, so switch across to value.
                        in_name = false;
                        header_name = str::from_bytes(self.bytes);
                        self.bytes.clear();
                        Normal
                    },
                    GotCR if b == LF && in_name && self.bytes.len() == 0 => {
                        return Err(EndOfHeaders);
                    },
                    GotCR if b == LF => {
                        GotCRLF
                    },
                    GotCR => {
                        // False alarm, CR without LF
                        self.bytes.push(CR);
                        self.bytes.push(b);
                        Normal
                    },
                    GotCRLF if b == SP || b == HT => {
                        // CR LF SP is a suitable linear whitespace, so don't stop yet
                        CompactingLWS
                    },
                    GotCRLF if in_name => {
                        // Don't worry about poking b; the request is being aborted
                        return Err(MalformedHeader);
                    },
                    GotCRLF => {
                        // Ooh! We got to a genuine end of line, so we're done
                        // But sorry, we don't want that byte after all...
                        self.peeked_byte = Some(b);
                        break;
                    },
                    Normal | CompactingLWS if b == SP || b == HT => {
                        // Start or continue to compact linear whitespace
                        CompactingLWS
                    },
                    CompactingLWS => {
                        // End of LWS, compact it down to a single space, unless it's at the start
                        // (saves a trim_left() call later)
                        if self.bytes.len() > 0 {
                            self.bytes.push(SP);
                        }
                        self.bytes.push(b);
                        Normal
                    },
                    Normal => {
                        self.bytes.push(b);
                        Normal
                    }
                },
            };
        }
        return Ok((header_name, str::from_bytes(self.bytes)));
    }
}
////////////////////////////////////////////////////////////////////////////////////////////////////

/// A HTTP request.
///
/// * `host`: The originating IP of the request
/// * `headers`: The headers of the request
/// * `body`: The body of the request as a string
/// * `method`: The method of the request
/// * `path`: The path of the request
/// * `close_connection`: whether the connection should be closed (or kept open waiting for more requests)
/// * `version`: The HTTP version
pub struct Request {
    //host: ip::IpAddr,
    headers: ~Headers,
    body: ~str,
    method: Method,
    path: ~str,
    close_connection: bool,
    version: (uint, uint)
}

/// Parse an HTTP request line into its parts.
///
/// `parse_request_line("GET /foo HTTP/1.1") == Ok((methods::GET, "/foo", (1, 1)))`
fn parse_request_line(line: ~str) -> Option<(Method, ~str, (uint, uint))> {
    // TODO: this probably isn't compliant
    /* * /let words : ~[&str] = line.word_iter().collect();
    if words.len() != 3 {
        return None;
    }
    let method = Method::from_str_or_new(words[0]);
    let path = words[1].to_owned();
    let http_version = parse_http_version(words[2]);
    match http_version {
        None => None,
        Some(v) => Some((method, path, v)),
    }
    /*/
    let mut words = line.word_iter();
    let method = match words.next() {
        Some(s) => Method::from_str_or_new(s),
        None => return None,
    };
    let path = match words.next() {
        Some(s) => s.to_owned(),
        None => return None,
    };
    let http_version = match words.next() {
        Some(s) => parse_http_version(s),
        None => return None,
    };
    match (words.next(), http_version) {
        (None, Some(v)) => Some((method, path, v)),
        _ => None,  // More words or invalid HTTP version
    }
    /**/
}

/// Parse an HTTP version string into the two X.Y parts.
///
/// At present, HTTP versions the server does not know about are rejected.
///
/// ~~~ {.rust}
/// assert_eq!(parse_http_version(~"HTTP/1.0"), Some((1, 0)))
/// assert_eq!(parse_http_version(~"HTTP/1.1"), Some((1, 1)))
/// assert_eq!(parse_http_version(~"HTTP/2.0"), Some((2, 0)))
/// ~~~
fn parse_http_version(version: &str) -> Option<(uint, uint)> {
    match version {
        // These two are efficiency shortcuts; they're expected to be all that we ever receive,
        // but naturally we mustn't let it crash on other inputs.
        "HTTP/1.0" => Some((1, 0)),
        "HTTP/1.1" => Some((1, 1)),
        v if v.starts_with("HTTP/") => {
            // This commented-out variant would fail! if given non-integers
            //let ints: ~[uint] = v.slice_from(5).split_iter('.').map(
            //    |&num| uint::from_str_radix(num, 10).get()).collect();
            let mut ints = [0u, 0u];
            for v.slice_from(5).split_iter('.').enumerate().advance |(i, strnum)| {
                if i > 1 {
                    // More than two numbers, e.g. HTTP/1.2.3
                    return None;
                }
                match uint::from_str_radix(strnum, 10) {
                    Some(num) => ints[i] = num,
                    None => return None,
                }
            }
            Some((ints[0], ints[1]))
        }
        _ => None
    }
}

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

    #[test]
    fn test_parse_http_version() {
        assert_eq!(parse_http_version(~"HTTP/1.1"), Ok((1, 1)));
        assert_eq!(parse_http_version(~"HTTP/1.0"), Ok((1, 0)));
        assert_eq!(parse_http_version(~"HTTP/2.0"), Err(()));
    }

    #[test]
    fn test_parse_request_line() {
        assert_eq!(parse_request_line(~"GET /foo HTTP/1.1"), Ok((methods::GET, "/foo", (1, 1))));
        assert_eq!(parse_request_line(~"POST / HTTP/1.0"), Ok((methods::POST, "/", (1, 0))));
        assert_eq!(parse_request_line(~"POST / HTTP/2.0"), Err(()));
    }
}

/**/
impl Request {

    /// Get a response from an open socket.
    pub fn get(buffer: &mut RequestBuffer) -> Result<Request, status::Status> {

        let (method, path, version) = match parse_request_line(buffer.read_crlf_line()) {
            Some(vals) => vals,
            None => return Err(status::BadRequest),
        };

        let close_connection = match version {
            (1, 0) => true,
            (1, 1) => false,
            _ => return Err(status::HttpVersionNotSupported),
        };

        let mut headers = TreeMap::new();

        loop {
            match buffer.read_header_line() {
                Err(EndOfFile) => fail!("client disconnected, nowhere to send response"),
                Err(EndOfHeaders) => break,
                Err(MalformedHeader) => return Err(status::BadRequest),
                Ok((name, value)) => { headers.insert(normalise_header_name(name), value); },
            }
        }

        let close_connection = match headers.find(&~"Connection") {
            Some(s) => match s.to_ascii().to_lower().to_str_ascii() {
                ~"close" => true,
                ~"keep-alive" => false,
                _ => close_connection,
            },
            None => close_connection,
        };

        Ok(Request {
            //host: socket.get_peer_addr(),
            headers: ~headers,
            body: ~"",
            //body: str::connect_slices(lines, "\r\n"),
            method: method,
            path: path.to_owned(),
            close_connection: close_connection,
            version: version
        })
    }
}
/**/

/* What follows is most of Go's net/http module's definition of Request.

pub struct Request {
    // GET, POST, etc.
    method: ~Method,

    // The URL requested, constructed from the request line and (if available)
    // the Host header.
    url: ~Url,

    // The HTTP protocol version used; typically (1, 1)
    protocol: (uint, uint),

    // Request headers, all nicely and correctly parsed.
    headers: ~Headers,

    // The message body.
    body: Reader,

    // ContentLength records the length of the associated content.
    // The value -1 indicates that the length is unknown.
    // Values >= 0 indicate that the given number of bytes may
    // be read from Body.
    // For outgoing requests, a value of 0 means unknown if Body is not nil.
    content_length: i64,

    // TransferEncoding lists the transfer encodings from outermost to
    // innermost. An empty list denotes the "identity" encoding.
    // TransferEncoding can usually be ignored; chunked encoding is
    // automatically added and removed as necessary when sending and
    // receiving requests.
    transfer_encoding: ~[~str],

    // Close indicates whether to close the connection after
    // replying to this request.
    close: bool,

    // The host on which the URL is sought.
    // Per RFC 2616, this is either the value of the Host: header
    // or the host name given in the URL itself.
    // It may be of the form "host:port".
    host: ~str,

    // Form contains the parsed form data, including both the URL
    // field's query parameters and the POST or PUT form data.
    // This field is only available after ParseForm is called.
    // The HTTP client ignores Form and uses Body instead.
    form: url.Values,

    // PostForm contains the parsed form data from POST or PUT
    // body parameters.
    // This field is only available after ParseForm is called.
    // The HTTP client ignores PostForm and uses Body instead.
    post_form: url.Values,

    // MultipartForm is the parsed multipart form, including file uploads.
    // This field is only available after ParseMultipartForm is called.
    // The HTTP client ignores MultipartForm and uses Body instead.
    multipart_form: *multipart.Form,

    // Trailer maps trailer keys to values.  Like for Header, if the
    // response has multiple trailer lines with the same key, they will be
    // concatenated, delimited by commas.
    // For server requests, Trailer is only populated after Body has been
    // closed or fully consumed.
    // Trailer support is only partially complete.
    trailer: ~Headers,

    // RemoteAddr allows HTTP servers and other software to record
    // the network address that sent the request, usually for
    // logging. This field is not filled in by ReadRequest and
    // has no defined format. The HTTP server in this package
    // sets RemoteAddr to an "IP:port" address before invoking a
    // handler.
    // This field is ignored by the HTTP client.
    remote_addr: string,

    // RequestURI is the unmodified Request-URI of the
    // Request-Line (RFC 2616, Section 5.1) as sent by the client
    // to a server. Usually the URL field should be used instead.
    // It is an error to set this field in an HTTP client request.
    request_uri: string,

    // TLS allows HTTP servers and other software to record
    // information about the TLS connection on which the request
    // was received. This field is not filled in by ReadRequest.
    // The HTTP server in this package sets the field for
    // TLS-enabled connections before invoking a handler;
    // otherwise it leaves the field nil.
    // This field is ignored by the HTTP client.
    tls: *tls.ConnectionState,
}*/
<commit_msg>Improve request read performance by removing an allocation.<commit_after>use extra::treemap::TreeMap;
use super::methods::Method;
use super::status;
use super::server::TcpStream;
use std::rt::io::Reader;
use std::{str, uint};
use super::rfc2616::{CR, LF, SP, HT, COLON};
use super::headers::{Headers, normalise_header_name};

pub enum HeaderLineErr { EndOfFile, EndOfHeaders, MalformedHeader }

////////////////////////////////////////////////////////////////////////////////////////////////////
pub struct RequestBuffer<'self> {
    priv stream: &'self mut TcpStream,
    priv bytes: ~[u8],
    priv peeked_byte: Option<u8>,
    priv read_buf: [u8, ..1],
}

static SIZE: uint = 1024;

impl<'self> RequestBuffer<'self> {
    pub fn new<'a> (stream: &'a mut TcpStream) -> RequestBuffer<'a> {
        RequestBuffer {
            stream: stream,
            bytes: ~[0u8, ..SIZE],
            peeked_byte: None,
            read_buf: [0u8],
        }
    }

    /*pub fn peek_byte(&mut self) -> Option<u8> {
        if self.peeked_byte.is_some() {
            fail!("Already called peek_byte() without having called read_byte()");
            // ... sorry, VERY nasty quick hack.
        }
    }*/

    pub fn read_byte(&mut self) -> Option<u8> {
        match self.peeked_byte {
            Some(byte) => {
                self.peeked_byte = None;
                Some(byte)
            },
            None => {
                match self.stream.read(self.read_buf) {
                    None => return None,
                    Some(1) => Some(self.read_buf[0]),
                    Some(i) => fail!("TcpStream.read() returned %u!?", i),
                }
            },
        }
    }

    /// Read a line ending in CRLF
    pub fn read_crlf_line(&mut self) -> ~str {
        self.bytes.clear();

        enum State { Normal, GotCR };
        let mut state = Normal;

        loop {
            state = match self.read_byte() {
                None => fail!("EOF"),
                Some(b) => match state {
                    Normal if b == CR => {
                        GotCR
                    },
                    GotCR if b == LF => {
                        break;
                    },
                    GotCR => {
                        self.bytes.push(CR);
                        self.bytes.push(b);
                        Normal
                    },
                    Normal => {
                        self.bytes.push(b);
                        Normal
                    }
                }
            };
        }
        str::from_bytes(self.bytes)
    }

    /// Read a header (name, value) pair.
    ///
    /// This is not necessarily just a line ending with CRLF; there are much fancier rules at work.
    /// Where appropriate (TODO, it's everywhere at present) linear whitespace is collapsed into a
    /// single space.
    ///
    /// # Error values
    ///
    /// - `EndOfHeaders`: I have no more headers to give; go forth and conquer on the body!
    /// - `EndOfFile`: socket was closed unexpectedly; probable best behavour is to drop the request
    /// - `MalformedHeader`: request is bad; you could drop it or try returning 400 Bad Request
    pub fn read_header_line(&mut self) -> Result<(~str, ~str), HeaderLineErr> {
        enum State2 { Normal, CompactingLWS, GotCR, GotCRLF };
        // XXX: not called State because of https://github.com/mozilla/rust/issues/7770
        // TODO: investigate quoted strings

        let mut state = Normal;
        let mut in_name = true;
        let mut header_name = ~"";
        self.bytes.clear();

        loop {
            state = match self.read_byte() {
                None => return Err(EndOfFile),
                Some(b) => match state {
                    Normal | CompactingLWS if b == CR => {
                        // It's OK to go to GotCR on CompactingLWS: if it ends up CRLFSP it'll get
                        // back to CompactingLWS, and if it ends up CRLF we didn't need the trailing
                        // whitespace anyway.
                        GotCR
                    },
                    Normal | CompactingLWS if in_name && b == COLON => {
                        // As above, don't worry about trailing whitespace.
                        // Found the colon, so switch across to value.
                        in_name = false;
                        header_name = str::from_bytes(self.bytes);
                        self.bytes.clear();
                        Normal
                    },
                    GotCR if b == LF && in_name && self.bytes.len() == 0 => {
                        return Err(EndOfHeaders);
                    },
                    GotCR if b == LF => {
                        GotCRLF
                    },
                    GotCR => {
                        // False alarm, CR without LF
                        self.bytes.push(CR);
                        self.bytes.push(b);
                        Normal
                    },
                    GotCRLF if b == SP || b == HT => {
                        // CR LF SP is a suitable linear whitespace, so don't stop yet
                        CompactingLWS
                    },
                    GotCRLF if in_name => {
                        // Don't worry about poking b; the request is being aborted
                        return Err(MalformedHeader);
                    },
                    GotCRLF => {
                        // Ooh! We got to a genuine end of line, so we're done
                        // But sorry, we don't want that byte after all...
                        self.peeked_byte = Some(b);
                        break;
                    },
                    Normal | CompactingLWS if b == SP || b == HT => {
                        // Start or continue to compact linear whitespace
                        CompactingLWS
                    },
                    CompactingLWS => {
                        // End of LWS, compact it down to a single space, unless it's at the start
                        // (saves a trim_left() call later)
                        if self.bytes.len() > 0 {
                            self.bytes.push(SP);
                        }
                        self.bytes.push(b);
                        Normal
                    },
                    Normal => {
                        self.bytes.push(b);
                        Normal
                    }
                },
            };
        }
        return Ok((header_name, str::from_bytes(self.bytes)));
    }
}
////////////////////////////////////////////////////////////////////////////////////////////////////

/// A HTTP request.
///
/// * `host`: The originating IP of the request
/// * `headers`: The headers of the request
/// * `body`: The body of the request as a string
/// * `method`: The method of the request
/// * `path`: The path of the request
/// * `close_connection`: whether the connection should be closed (or kept open waiting for more requests)
/// * `version`: The HTTP version
pub struct Request {
    //host: ip::IpAddr,
    headers: ~Headers,
    body: ~str,
    method: Method,
    path: ~str,
    close_connection: bool,
    version: (uint, uint)
}

/// Parse an HTTP request line into its parts.
///
/// `parse_request_line("GET /foo HTTP/1.1") == Ok((methods::GET, "/foo", (1, 1)))`
fn parse_request_line(line: ~str) -> Option<(Method, ~str, (uint, uint))> {
    // TODO: this probably isn't compliant
    /* * /let words : ~[&str] = line.word_iter().collect();
    if words.len() != 3 {
        return None;
    }
    let method = Method::from_str_or_new(words[0]);
    let path = words[1].to_owned();
    let http_version = parse_http_version(words[2]);
    match http_version {
        None => None,
        Some(v) => Some((method, path, v)),
    }
    /*/
    let mut words = line.word_iter();
    let method = match words.next() {
        Some(s) => Method::from_str_or_new(s),
        None => return None,
    };
    let path = match words.next() {
        Some(s) => s.to_owned(),
        None => return None,
    };
    let http_version = match words.next() {
        Some(s) => parse_http_version(s),
        None => return None,
    };
    match (words.next(), http_version) {
        (None, Some(v)) => Some((method, path, v)),
        _ => None,  // More words or invalid HTTP version
    }
    /**/
}

/// Parse an HTTP version string into the two X.Y parts.
///
/// At present, HTTP versions the server does not know about are rejected.
///
/// ~~~ {.rust}
/// assert_eq!(parse_http_version(~"HTTP/1.0"), Some((1, 0)))
/// assert_eq!(parse_http_version(~"HTTP/1.1"), Some((1, 1)))
/// assert_eq!(parse_http_version(~"HTTP/2.0"), Some((2, 0)))
/// ~~~
fn parse_http_version(version: &str) -> Option<(uint, uint)> {
    match version {
        // These two are efficiency shortcuts; they're expected to be all that we ever receive,
        // but naturally we mustn't let it crash on other inputs.
        "HTTP/1.0" => Some((1, 0)),
        "HTTP/1.1" => Some((1, 1)),
        v if v.starts_with("HTTP/") => {
            // This commented-out variant would fail! if given non-integers
            //let ints: ~[uint] = v.slice_from(5).split_iter('.').map(
            //    |&num| uint::from_str_radix(num, 10).get()).collect();
            let mut ints = [0u, 0u];
            for v.slice_from(5).split_iter('.').enumerate().advance |(i, strnum)| {
                if i > 1 {
                    // More than two numbers, e.g. HTTP/1.2.3
                    return None;
                }
                match uint::from_str_radix(strnum, 10) {
                    Some(num) => ints[i] = num,
                    None => return None,
                }
            }
            Some((ints[0], ints[1]))
        }
        _ => None
    }
}

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

    #[test]
    fn test_parse_http_version() {
        assert_eq!(parse_http_version(~"HTTP/1.1"), Ok((1, 1)));
        assert_eq!(parse_http_version(~"HTTP/1.0"), Ok((1, 0)));
        assert_eq!(parse_http_version(~"HTTP/2.0"), Err(()));
    }

    #[test]
    fn test_parse_request_line() {
        assert_eq!(parse_request_line(~"GET /foo HTTP/1.1"), Ok((methods::GET, "/foo", (1, 1))));
        assert_eq!(parse_request_line(~"POST / HTTP/1.0"), Ok((methods::POST, "/", (1, 0))));
        assert_eq!(parse_request_line(~"POST / HTTP/2.0"), Err(()));
    }
}

/**/
impl Request {

    /// Get a response from an open socket.
    pub fn get(buffer: &mut RequestBuffer) -> Result<Request, status::Status> {

        let (method, path, version) = match parse_request_line(buffer.read_crlf_line()) {
            Some(vals) => vals,
            None => return Err(status::BadRequest),
        };

        let close_connection = match version {
            (1, 0) => true,
            (1, 1) => false,
            _ => return Err(status::HttpVersionNotSupported),
        };

        let mut headers = TreeMap::new();

        loop {
            match buffer.read_header_line() {
                Err(EndOfFile) => fail!("client disconnected, nowhere to send response"),
                Err(EndOfHeaders) => break,
                Err(MalformedHeader) => return Err(status::BadRequest),
                Ok((name, value)) => { headers.insert(normalise_header_name(name), value); },
            }
        }

        let close_connection = match headers.find(&~"Connection") {
            Some(s) => match s.to_ascii().to_lower().to_str_ascii() {
                ~"close" => true,
                ~"keep-alive" => false,
                _ => close_connection,
            },
            None => close_connection,
        };

        Ok(Request {
            //host: socket.get_peer_addr(),
            headers: ~headers,
            body: ~"",
            //body: str::connect_slices(lines, "\r\n"),
            method: method,
            path: path.to_owned(),
            close_connection: close_connection,
            version: version
        })
    }
}
/**/

/* What follows is most of Go's net/http module's definition of Request.

pub struct Request {
    // GET, POST, etc.
    method: ~Method,

    // The URL requested, constructed from the request line and (if available)
    // the Host header.
    url: ~Url,

    // The HTTP protocol version used; typically (1, 1)
    protocol: (uint, uint),

    // Request headers, all nicely and correctly parsed.
    headers: ~Headers,

    // The message body.
    body: Reader,

    // ContentLength records the length of the associated content.
    // The value -1 indicates that the length is unknown.
    // Values >= 0 indicate that the given number of bytes may
    // be read from Body.
    // For outgoing requests, a value of 0 means unknown if Body is not nil.
    content_length: i64,

    // TransferEncoding lists the transfer encodings from outermost to
    // innermost. An empty list denotes the "identity" encoding.
    // TransferEncoding can usually be ignored; chunked encoding is
    // automatically added and removed as necessary when sending and
    // receiving requests.
    transfer_encoding: ~[~str],

    // Close indicates whether to close the connection after
    // replying to this request.
    close: bool,

    // The host on which the URL is sought.
    // Per RFC 2616, this is either the value of the Host: header
    // or the host name given in the URL itself.
    // It may be of the form "host:port".
    host: ~str,

    // Form contains the parsed form data, including both the URL
    // field's query parameters and the POST or PUT form data.
    // This field is only available after ParseForm is called.
    // The HTTP client ignores Form and uses Body instead.
    form: url.Values,

    // PostForm contains the parsed form data from POST or PUT
    // body parameters.
    // This field is only available after ParseForm is called.
    // The HTTP client ignores PostForm and uses Body instead.
    post_form: url.Values,

    // MultipartForm is the parsed multipart form, including file uploads.
    // This field is only available after ParseMultipartForm is called.
    // The HTTP client ignores MultipartForm and uses Body instead.
    multipart_form: *multipart.Form,

    // Trailer maps trailer keys to values.  Like for Header, if the
    // response has multiple trailer lines with the same key, they will be
    // concatenated, delimited by commas.
    // For server requests, Trailer is only populated after Body has been
    // closed or fully consumed.
    // Trailer support is only partially complete.
    trailer: ~Headers,

    // RemoteAddr allows HTTP servers and other software to record
    // the network address that sent the request, usually for
    // logging. This field is not filled in by ReadRequest and
    // has no defined format. The HTTP server in this package
    // sets RemoteAddr to an "IP:port" address before invoking a
    // handler.
    // This field is ignored by the HTTP client.
    remote_addr: string,

    // RequestURI is the unmodified Request-URI of the
    // Request-Line (RFC 2616, Section 5.1) as sent by the client
    // to a server. Usually the URL field should be used instead.
    // It is an error to set this field in an HTTP client request.
    request_uri: string,

    // TLS allows HTTP servers and other software to record
    // information about the TLS connection on which the request
    // was received. This field is not filled in by ReadRequest.
    // The HTTP server in this package sets the field for
    // TLS-enabled connections before invoking a handler;
    // otherwise it leaves the field nil.
    // This field is ignored by the HTTP client.
    tls: *tls.ConnectionState,
}*/
<|endoftext|>


<commit_before><commit_msg>remove slashs<commit_after><|endoftext|>


<commit_before>//! Contains result and error type for FBX reader.

extern crate byteorder;

use std::io;

/// A specialized `std::result::Result` type for FBX exporting.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An FBX parsing error.
#[derive(Debug)]
pub enum Error {
    /// I/O error.
    Io(io::Error),
    /// FBX not started but an event other than `StartFbx` is given.
    FbxNotStarted,
    /// FBX is already started but `StartFbx` is given.
    FbxAlreadyStarted,
    /// Unimplemented feature.
    Unimplemented(String),
}

impl Clone for Error {
    fn clone(&self) -> Self {
        use self::Error::*;
        use std::error::Error;
        match *self {
            Io(ref e) => Io(io::Error::new(e.kind(), e.description())),
            FbxNotStarted => FbxNotStarted,
            FbxAlreadyStarted => FbxAlreadyStarted,
            Unimplemented(ref e) => Unimplemented(e.clone()),
        }
    }
}

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

impl From<byteorder::Error> for Error {
    fn from(err: byteorder::Error) -> Error {
        match err {
            byteorder::Error::UnexpectedEOF => panic!("byteorder::Error::UnexpectedEOF shouldn't happen on write"),
            byteorder::Error::Io(err) => Error::Io(err),
        }
    }
}
<commit_msg>Add `writer::error::Error::UnwritableEvent`<commit_after>//! Contains result and error type for FBX reader.

extern crate byteorder;

use std::io;

/// A specialized `std::result::Result` type for FBX exporting.
pub type Result<T> = ::std::result::Result<T, Error>;

/// An FBX parsing error.
#[derive(Debug)]
pub enum Error {
    /// I/O error.
    Io(io::Error),
    /// FBX not started but an event other than `StartFbx` is given.
    FbxNotStarted,
    /// FBX is already started but `StartFbx` is given.
    FbxAlreadyStarted,
    /// Given event is not writable in current format.
    UnwritableEvent,
    /// Unimplemented feature.
    Unimplemented(String),
}

impl Clone for Error {
    fn clone(&self) -> Self {
        use self::Error::*;
        use std::error::Error;
        match *self {
            Io(ref e) => Io(io::Error::new(e.kind(), e.description())),
            FbxNotStarted => FbxNotStarted,
            FbxAlreadyStarted => FbxAlreadyStarted,
            UnwritableEvent => UnwritableEvent,
            Unimplemented(ref e) => Unimplemented(e.clone()),
        }
    }
}

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

impl From<byteorder::Error> for Error {
    fn from(err: byteorder::Error) -> Error {
        match err {
            byteorder::Error::UnexpectedEOF => panic!("byteorder::Error::UnexpectedEOF shouldn't happen on write"),
            byteorder::Error::Io(err) => Error::Io(err),
        }
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate nom;

use nom::{IResult, Needed, alphanumeric, is_alphanumeric};

named!(certain_length<&[u8], &[u8]>, take!(10));

named!(value<&[u8], &[u8]>,
       take_while!(is_alphanumeric));

named!(comment<&[u8], &[u8]>,
      do_parse!(
          tag!("/") >>
              comment: alphanumeric >>
              (comment)
      ));

named!(record<&[u8], (&[u8], Option<&[u8]>)>,
       do_parse!(
           v: value >>
               c: opt!(comment) >>
               ((v, c))
       ));

named!(certain_length_record<&[u8], (&[u8], Option<&[u8]>)>,
       flat_map!(certain_length, record));

#[test]
fn certain_length_test() {
    assert_eq!(certain_length(&b"0123456789"[..]), IResult::Done(&b""[..], &b"0123456789"[..]));
    assert_eq!(certain_length(&b"012345678"[..]), IResult::Incomplete(Needed::Size(10)));
    assert_eq!(certain_length(&b"abcdefghijk"[..]), IResult::Done(&b"k"[..], &b"abcdefghij"[..]));
}

#[test]
fn value_test() {
    assert_eq!(value(&b""[..]),
               IResult::Done(&b""[..], &b""[..]));
    assert_eq!(value(&b"a"[..]),
               IResult::Done(&b""[..], &b"a"[..]));
    assert_eq!(value(&b"ab"[..]),
               IResult::Done(&b""[..], &b"ab"[..]));
    assert_eq!(value(&b"abc"[..]),
               IResult::Done(&b""[..], &b"abc"[..]));
}

#[test]
fn comment_test() {
    assert_eq!(comment(&b"/a"[..]), IResult::Done(&b""[..], &b"a"[..]));
    assert_eq!(comment(&b"/ab"[..]), IResult::Done(&b""[..], &b"ab"[..]));
    assert_eq!(comment(&b"/abc"[..]), IResult::Done(&b""[..], &b"abc"[..]));
}

#[test]
fn record_test() {
    assert_eq!(record(&b"abcd/123"[..]),
               IResult::Done(&b""[..], (&b"abcd"[..], Option::Some(&b"123"[..]))));
    assert_eq!(record(&b"abcd/123  "[..]),
               IResult::Done(&b"  "[..], (&b"abcd"[..], Option::Some(&b"123"[..]))));
    assert_eq!(record(&b"abcd  "[..]),
               IResult::Done(&b"  "[..], (&b"abcd"[..], Option::None)));
}

#[test]
fn certain_length_record_test() {
    assert_eq!(certain_length_record(&b"01234/abcd"[..]),
               IResult::Done(&b""[..], (&b"01234"[..], Option::Some(&b"abcd"[..]))));
}
<commit_msg>Show that length is adhered to<commit_after>#[macro_use]
extern crate nom;

use nom::{IResult, Needed, alphanumeric, is_alphanumeric};

named!(certain_length<&[u8], &[u8]>, take!(10));

named!(value<&[u8], &[u8]>,
       take_while!(is_alphanumeric));

named!(comment<&[u8], &[u8]>,
      do_parse!(
          tag!("/") >>
              comment: alphanumeric >>
              (comment)
      ));

named!(record<&[u8], (&[u8], Option<&[u8]>)>,
       do_parse!(
           v: value >>
               c: opt!(comment) >>
               ((v, c))
       ));

named!(certain_length_record<&[u8], (&[u8], Option<&[u8]>)>,
       flat_map!(certain_length, record));

#[test]
fn certain_length_test() {
    assert_eq!(certain_length(&b"0123456789"[..]), IResult::Done(&b""[..], &b"0123456789"[..]));
    assert_eq!(certain_length(&b"012345678"[..]), IResult::Incomplete(Needed::Size(10)));
    assert_eq!(certain_length(&b"abcdefghijk"[..]), IResult::Done(&b"k"[..], &b"abcdefghij"[..]));
}

#[test]
fn value_test() {
    assert_eq!(value(&b""[..]),
               IResult::Done(&b""[..], &b""[..]));
    assert_eq!(value(&b"a"[..]),
               IResult::Done(&b""[..], &b"a"[..]));
    assert_eq!(value(&b"ab"[..]),
               IResult::Done(&b""[..], &b"ab"[..]));
    assert_eq!(value(&b"abc"[..]),
               IResult::Done(&b""[..], &b"abc"[..]));
}

#[test]
fn comment_test() {
    assert_eq!(comment(&b"/a"[..]), IResult::Done(&b""[..], &b"a"[..]));
    assert_eq!(comment(&b"/ab"[..]), IResult::Done(&b""[..], &b"ab"[..]));
    assert_eq!(comment(&b"/abc"[..]), IResult::Done(&b""[..], &b"abc"[..]));
}

#[test]
fn record_test() {
    assert_eq!(record(&b"abcd/123"[..]),
               IResult::Done(&b""[..], (&b"abcd"[..], Option::Some(&b"123"[..]))));
    assert_eq!(record(&b"abcd/123  "[..]),
               IResult::Done(&b"  "[..], (&b"abcd"[..], Option::Some(&b"123"[..]))));
    assert_eq!(record(&b"abcd  "[..]),
               IResult::Done(&b"  "[..], (&b"abcd"[..], Option::None)));
}

#[test]
fn certain_length_record_test() {
    assert_eq!(certain_length_record(&b"01234/abcd"[..]),
               IResult::Done(&b""[..], (&b"01234"[..], Option::Some(&b"abcd"[..]))));
    assert_eq!(certain_length_record(&b"01234/abcdABC"[..]),
               IResult::Done(&b"ABC"[..], (&b"01234"[..], Option::Some(&b"abcd"[..]))));
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use wayland_client::{EventQueue, EventQueueHandle, Init};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};

use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
use platform::MonitorId as PlatformMonitorId;

use super::WaylandContext;
use super::wayland_window;
use super::wayland_window::DecoratedSurface;

#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

pub struct Window {
    ctxt: Arc<WaylandContext>,
    evq: Mutex<EventQueue>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
    surface: Arc<wl_surface::WlSurface>,
    size: Mutex<(u32, u32)>,
    handler_id: usize,
    decorated_id: usize
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(false)
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(true)
    }
}

impl Window {
    pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes)  -> Result<Window, CreationError>
    {
        let (width, height) = attributes.dimensions.unwrap_or((800,600));

        let mut evq = ctxt.display.create_event_queue();

        let (surface, eviter, decorated) = ctxt.create_window::<DecoratedHandler>();

        // init DecoratedSurface
        let decorated_id = evq.add_handler_with_init(decorated);
        {
            let mut state = evq.state();
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
            *(decorated.handler()) = Some(DecoratedHandler::new());

            if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor {
                ctxt.with_output(monitor_id.clone(), |output| {
                    decorated.set_fullscreen(
                        wl_shell_surface::FullscreenMethod::Default,
                        0,
                        Some(output)
                    )
                });
            } else if attributes.decorations {
                decorated.set_decorate(true);
            }
        }

        // init general handler
        let handler = WindowHandler::new();
        let handler_id = evq.add_handler_with_init(handler);

        Ok(Window {
            ctxt: ctxt,
            evq: Mutex::new(evq),
            eviter: eviter,
            surface: surface,
            size: Mutex::new((width, height)),
            handler_id: handler_id,
            decorated_id: decorated_id
        })
    }

    fn process_resize(&self) {
        use std::cmp::max;
        let mut evq_guard = self.evq.lock().unwrap();
        let mut state = evq_guard.state();
        let newsize = {
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
            let newsize = decorated.handler().as_mut().and_then(|h| h.take_newsize());
            if let Some((w, h)) = newsize {
                decorated.resize(w as i32, h as i32);
                *self.size.lock().unwrap() = (w, h);
            }
            newsize
        };
        // callback_resize if any
        if let Some((w, h)) = newsize {
            let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
            if let Some(ref callback) = handler.resize_callback {
                callback(w, h);
            }
            self.eviter.lock().unwrap().push_back(Event::Resized(w,h));
        }
    }

    fn next_event(&self, block: bool) -> Option<Event> {
        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };
        if evt.is_some() { return evt }

        // try a pending dispatch
        // TODO: insert a non-blocking read from socket, overwise no new events will ever come
        {
            self.ctxt.dispatch_pending();
            let mut guard = self.evq.lock().unwrap().dispatch_pending();
            // some events were dispatched, need to process a potential resising
            self.process_resize();
        }

        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };

        while block && evt.is_none() {
            // no event waiting, need to repopulate!
            {
                self.ctxt.flush();
                self.ctxt.dispatch();
                let mut guard = self.evq.lock().unwrap().dispatch();
                // some events were dispatched, need to process a potential resising
                self.process_resize();
            }
            // try again
            let mut guard = self.eviter.lock().unwrap();
            evt = guard.pop_front()
        }
        evt
    }

    pub fn set_title(&self, title: &str) {
        // TODO
    }

    #[inline]
    pub fn show(&self) {
        // TODO
    }

    #[inline]
    pub fn hide(&self) {
        // TODO
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        // Not possible with wayland
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
        // Not possible with wayland
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        // TODO
        None
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        // TODO
        None
    }

    #[inline]
    pub fn set_inner_size(&self, x: u32, y: u32) {
        // TODO
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
        handler.resize_callback = callback;
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        // TODO
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        use CursorState::{Grab, Normal, Hide};
        // TODO : not yet possible on wayland to grab cursor
        match state {
            Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()),
            Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()),
            Normal => Ok(())
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        // TODO
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        // TODO: not yet possible on wayland
        Err(())
    }

    pub fn get_display(&self) -> &wl_display::WlDisplay {
        &self.ctxt.display
    }

    pub fn get_surface(&self) -> &wl_surface::WlSurface {
        &self.surface
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        self.surface.destroy();
        self.ctxt.prune_dead_windows();
    }
}

struct DecoratedHandler {
    newsize: Option<(u32, u32)>
}

impl DecoratedHandler {
    fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }}
    fn take_newsize(&mut self) -> Option<(u32, u32)> {
        self.newsize.take()
    }
}

impl wayland_window::Handler for DecoratedHandler {
    fn configure(&mut self,
                 _: &mut EventQueueHandle,
                 _: wl_shell_surface::Resize,
                 width: i32, height: i32)
    {
        use std::cmp::max;
        self.newsize = Some((max(width,1) as u32, max(height,1) as u32));
    }
}

struct WindowHandler {
    my_id: usize,
    resize_callback: Option<fn(u32,u32)>,
}

impl WindowHandler {
    fn new() -> WindowHandler {
        WindowHandler {
            my_id: 0,
            resize_callback: None
        }
    }
}

impl Init for WindowHandler {
    fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) {
        self.my_id = index;
    }
}
<commit_msg>wayland: Some Window methods<commit_after>use std::collections::VecDeque;
use std::sync::{Arc, Mutex};

use wayland_client::{EventQueue, EventQueueHandle, Init};
use wayland_client::protocol::{wl_display,wl_surface,wl_shell_surface};

use {CreationError, MouseCursor, CursorState, Event, WindowAttributes};
use platform::MonitorId as PlatformMonitorId;

use super::WaylandContext;
use super::wayland_window;
use super::wayland_window::DecoratedSurface;

#[derive(Clone)]
pub struct WindowProxy;

impl WindowProxy {
    #[inline]
    pub fn wakeup_event_loop(&self) {
        unimplemented!()
    }
}

pub struct Window {
    ctxt: Arc<WaylandContext>,
    evq: Mutex<EventQueue>,
    eviter: Arc<Mutex<VecDeque<Event>>>,
    surface: Arc<wl_surface::WlSurface>,
    size: Mutex<(u32, u32)>,
    handler_id: usize,
    decorated_id: usize
}

pub struct PollEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for PollEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(false)
    }
}

pub struct WaitEventsIterator<'a> {
    window: &'a Window,
}

impl<'a> Iterator for WaitEventsIterator<'a> {
    type Item = Event;

    fn next(&mut self) -> Option<Event> {
        self.window.next_event(true)
    }
}

impl Window {
    pub fn new(ctxt: Arc<WaylandContext>, attributes: &WindowAttributes)  -> Result<Window, CreationError>
    {
        let (width, height) = attributes.dimensions.unwrap_or((800,600));

        let mut evq = ctxt.display.create_event_queue();

        let (surface, eviter, decorated) = ctxt.create_window::<DecoratedHandler>();

        // init DecoratedSurface
        let decorated_id = evq.add_handler_with_init(decorated);
        {
            let mut state = evq.state();
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(decorated_id);
            *(decorated.handler()) = Some(DecoratedHandler::new());

            if let Some(PlatformMonitorId::Wayland(ref monitor_id)) = attributes.monitor {
                ctxt.with_output(monitor_id.clone(), |output| {
                    decorated.set_fullscreen(
                        wl_shell_surface::FullscreenMethod::Default,
                        0,
                        Some(output)
                    )
                });
            } else if attributes.decorations {
                decorated.set_decorate(true);
            }
        }

        // init general handler
        let handler = WindowHandler::new();
        let handler_id = evq.add_handler_with_init(handler);

        Ok(Window {
            ctxt: ctxt,
            evq: Mutex::new(evq),
            eviter: eviter,
            surface: surface,
            size: Mutex::new((width, height)),
            handler_id: handler_id,
            decorated_id: decorated_id
        })
    }

    fn process_resize(&self) {
        use std::cmp::max;
        let mut evq_guard = self.evq.lock().unwrap();
        let mut state = evq_guard.state();
        let newsize = {
            let decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
            let newsize = decorated.handler().as_mut().and_then(|h| h.take_newsize());
            if let Some((w, h)) = newsize {
                decorated.resize(w as i32, h as i32);
                *self.size.lock().unwrap() = (w, h);
            }
            newsize
        };
        // callback_resize if any
        if let Some((w, h)) = newsize {
            let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
            if let Some(ref callback) = handler.resize_callback {
                callback(w, h);
            }
            self.eviter.lock().unwrap().push_back(Event::Resized(w,h));
        }
    }

    fn next_event(&self, block: bool) -> Option<Event> {
        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };
        if evt.is_some() { return evt }

        // try a pending dispatch
        // TODO: insert a non-blocking read from socket, overwise no new events will ever come
        {
            self.ctxt.dispatch_pending();
            let mut guard = self.evq.lock().unwrap().dispatch_pending();
            // some events were dispatched, need to process a potential resising
            self.process_resize();
        }

        let mut evt = {
            let mut guard = self.eviter.lock().unwrap();
            guard.pop_front()
        };

        while block && evt.is_none() {
            // no event waiting, need to repopulate!
            {
                self.ctxt.flush();
                self.ctxt.dispatch();
                let mut guard = self.evq.lock().unwrap().dispatch();
                // some events were dispatched, need to process a potential resising
                self.process_resize();
            }
            // try again
            let mut guard = self.eviter.lock().unwrap();
            evt = guard.pop_front()
        }
        evt
    }

    pub fn set_title(&self, title: &str) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.set_title(title.into())
    }

    #[inline]
    pub fn show(&self) {
        // TODO
    }

    #[inline]
    pub fn hide(&self) {
        // TODO
    }

    #[inline]
    pub fn get_position(&self) -> Option<(i32, i32)> {
        // Not possible with wayland
        None
    }

    #[inline]
    pub fn set_position(&self, _x: i32, _y: i32) {
        // Not possible with wayland
    }

    pub fn get_inner_size(&self) -> Option<(u32, u32)> {
        Some(self.size.lock().unwrap().clone())
    }

    #[inline]
    pub fn get_outer_size(&self) -> Option<(u32, u32)> {
        let (w, h) = self.size.lock().unwrap().clone();
        let (w, h) = super::wayland_window::add_borders(w as i32, h as i32);
        Some((w as u32, h as u32))
    }

    #[inline]
    // NOTE: This will only resize the borders, the contents must be updated by the user
    pub fn set_inner_size(&self, x: u32, y: u32) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut decorated = state.get_mut_handler::<DecoratedSurface<DecoratedHandler>>(self.decorated_id);
        decorated.resize(x as i32, y as i32);
    }

    #[inline]
    pub fn create_window_proxy(&self) -> WindowProxy {
        WindowProxy
    }

    #[inline]
    pub fn poll_events(&self) -> PollEventsIterator {
        PollEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn wait_events(&self) -> WaitEventsIterator {
        WaitEventsIterator {
            window: self
        }
    }

    #[inline]
    pub fn set_window_resize_callback(&mut self, callback: Option<fn(u32, u32)>) {
        let mut guard = self.evq.lock().unwrap();
        let mut state = guard.state();
        let mut handler = state.get_mut_handler::<WindowHandler>(self.handler_id);
        handler.resize_callback = callback;
    }

    #[inline]
    pub fn set_cursor(&self, _cursor: MouseCursor) {
        // TODO
    }

    #[inline]
    pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> {
        use CursorState::{Grab, Normal, Hide};
        // TODO : not yet possible on wayland to grab cursor
        match state {
            Grab => Err("Cursor cannot be grabbed on wayland yet.".to_string()),
            Hide => Err("Cursor cannot be hidden on wayland yet.".to_string()),
            Normal => Ok(())
        }
    }

    #[inline]
    pub fn hidpi_factor(&self) -> f32 {
        // TODO
        1.0
    }

    #[inline]
    pub fn set_cursor_position(&self, _x: i32, _y: i32) -> Result<(), ()> {
        // TODO: not yet possible on wayland
        Err(())
    }

    pub fn get_display(&self) -> &wl_display::WlDisplay {
        &self.ctxt.display
    }

    pub fn get_surface(&self) -> &wl_surface::WlSurface {
        &self.surface
    }
}

impl Drop for Window {
    fn drop(&mut self) {
        self.surface.destroy();
        self.ctxt.prune_dead_windows();
    }
}

struct DecoratedHandler {
    newsize: Option<(u32, u32)>
}

impl DecoratedHandler {
    fn new() -> DecoratedHandler { DecoratedHandler { newsize: None }}
    fn take_newsize(&mut self) -> Option<(u32, u32)> {
        self.newsize.take()
    }
}

impl wayland_window::Handler for DecoratedHandler {
    fn configure(&mut self,
                 _: &mut EventQueueHandle,
                 _: wl_shell_surface::Resize,
                 width: i32, height: i32)
    {
        use std::cmp::max;
        self.newsize = Some((max(width,1) as u32, max(height,1) as u32));
    }
}

struct WindowHandler {
    my_id: usize,
    resize_callback: Option<fn(u32,u32)>,
}

impl WindowHandler {
    fn new() -> WindowHandler {
        WindowHandler {
            my_id: 0,
            resize_callback: None
        }
    }
}

impl Init for WindowHandler {
    fn init(&mut self, evqh: &mut EventQueueHandle, index: usize) {
        self.my_id = index;
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::str::FromStr;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Visibility {
    Public,
    Crate,
    Super,
    Private,
}

impl Visibility {
    pub fn is_public(&self) -> bool {
        matches!(self, Self::Public)
    }

    pub fn export_visibility(&self) -> String {
        match self {
            Self::Public => "pub",
            Self::Private => "",
            Self::Crate => "pub(crate)",
            Self::Super => "pub(super)",
        }
        .to_owned()
    }
}

impl Default for Visibility {
    fn default() -> Self {
        Self::Public
    }
}

impl fmt::Display for Visibility {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::Public => write!(f, "pub"),
            Self::Crate => write!(f, "pub(crate)"),
            Self::Private => write!(f, ""),
            Self::Super => write!(f, "pub(super)"),
        }
    }
}

#[derive(Debug)]
pub struct ParseVisibilityError(String);

impl std::error::Error for ParseVisibilityError {}

impl fmt::Display for ParseVisibilityError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl FromStr for Visibility {
    type Err = ParseVisibilityError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "pub" => Ok(Self::Public),
            "super" => Ok(Self::Super),
            "private" => Ok(Self::Private),
            "crate" => Ok(Self::Crate),
            e => Err(ParseVisibilityError(format!(
                "Wrong visibility type '{}'",
                e
            ))),
        }
    }
}
<commit_msg>codegen/visibility: Reduce duplicate code, allocation for literals<commit_after>use std::fmt;
use std::str::FromStr;

#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum Visibility {
    Public,
    Crate,
    Super,
    Private,
}

impl Visibility {
    pub fn is_public(self) -> bool {
        self == Self::Public
    }

    pub fn export_visibility(self) -> &'static str {
        match self {
            Self::Public => "pub",
            Self::Private => "",
            Self::Crate => "pub(crate)",
            Self::Super => "pub(super)",
        }
    }
}

impl Default for Visibility {
    fn default() -> Self {
        Self::Public
    }
}

impl fmt::Display for Visibility {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(self.export_visibility())
    }
}

#[derive(Debug)]
pub struct ParseVisibilityError(String);

impl std::error::Error for ParseVisibilityError {}

impl fmt::Display for ParseVisibilityError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl FromStr for Visibility {
    type Err = ParseVisibilityError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "pub" => Ok(Self::Public),
            "super" => Ok(Self::Super),
            "private" => Ok(Self::Private),
            "crate" => Ok(Self::Crate),
            e => Err(ParseVisibilityError(format!(
                "Wrong visibility type '{}'",
                e
            ))),
        }
    }
}
<|endoftext|>