<commit_before>//! Low level and internal http and https implementation.

use std::collections::HashMap;
use std::time::Duration;

use async_std::io::{self, stderr, Read, Result as IoResult, Write};
use async_std::net::{SocketAddr, TcpStream};
use async_std::prelude::*;
use log::Level::Info;

use super::asynctls::TLSStream;
use super::constants;
use super::dns::Resolver;
use super::request::Request;
use super::results::{CabotError, CabotResult};

#[derive(Debug, PartialEq)]
enum TransferEncoding {
    ContentLength(usize),
    Chunked,
    Unkown,
    None,
}

#[derive(Debug, PartialEq)]
enum TransferEncodingStatus {
    ReadingHeader,
    ChunkHeader,
    ReadingBody(usize),
}

impl From<&[u8]> for TransferEncoding {
    fn from(hdr: &[u8]) -> Self {
        let hdr = String::from_utf8_lossy(hdr);
        let hdrup = hdr.to_ascii_uppercase();
        match hdrup.as_str() {
            "CHUNKED" => TransferEncoding::Chunked,
            _ => TransferEncoding::Unkown,
        }
    }
}

struct HttpDecoder<'a> {
    reader: &'a mut (dyn Read + Unpin), // tls require Write
    writer: &'a mut (dyn Write + Unpin),
    buffer: Vec<u8>,
    transfer_encoding: TransferEncoding,
    transfer_encoding_status: TransferEncodingStatus,
    read_timeout: Duration,
}

impl<'a> HttpDecoder<'a> {
    fn new(
        writer: &'a mut (dyn Write + Unpin),
        reader: &'a mut (dyn Read + Unpin),
        read_timeout: u64,
    ) -> Self {
        HttpDecoder {
            writer,
            reader,
            buffer: Vec::with_capacity(constants::BUFFER_PAGE_SIZE),
            transfer_encoding: TransferEncoding::None,
            transfer_encoding_status: TransferEncodingStatus::ReadingHeader,
            read_timeout: Duration::from_millis(read_timeout),
        }
    }

    async fn chunk_read(&mut self) -> IoResult<usize> {
        let ret = io::timeout(self.read_timeout, async {
            let mut buf = [0; constants::BUFFER_PAGE_SIZE];
            let ret = self.reader.read(&mut buf[..]).await;
            if let Ok(count) = ret {
                if count > 0 {
                    self.buffer.extend_from_slice(&buf[0..count]);
                }
            }
            ret
        });
        ret.await
    }
    async fn read_write_headers(&mut self) -> IoResult<()> {
        info!("Reading headers");
        loop {
            let _count = self.chunk_read().await?;
            if let Some(_) = self.process_headers().await {
                break;
            }
        }
        Ok(())
    }

    async fn read_write_no_transfer_encoding(&mut self) -> IoResult<()> {
        loop {
            self.writer.write(self.buffer.as_slice()).await.unwrap();
            self.buffer.clear();
            let cnt = self.chunk_read().await?;
            if cnt == 0 {
                break;
            }
        }

        Ok(())
    }

    async fn read_content_length(&mut self, size: usize) -> IoResult<()> {
        let mut read_count = self.buffer.len();
        loop {
            self.writer.write(self.buffer.as_slice()).await.unwrap();
            self.buffer.clear();

            if read_count >= size {
                break;
            }
            read_count = read_count + self.chunk_read().await?;
            warn!("< {}", read_count);
        }
        Ok(())
    }

    async fn read_write_chunk(&mut self) -> IoResult<()> {
        loop {
            let done = self.process_chunk().await?;
            if done {
                break;
            }
            let cnt = self.chunk_read().await?;
            if cnt == 0 {
                break;
            }
        }

        Ok(())
    }

    async fn read_write_body(&mut self) -> IoResult<()> {
        info!("Reading body");
        match self.transfer_encoding {
            TransferEncoding::ContentLength(size) => {
                self.read_content_length(size).await?;
            }
            TransferEncoding::Chunked => {
                self.read_write_chunk().await?;
            }
            _ => {
                warn!("Neither Content-Length, not chunk is response header");
                self.read_write_no_transfer_encoding().await?;
            }
        }

        if self.buffer.len() > 0 {
            let b = String::from_utf8_lossy(self.buffer.as_slice());
            error!("Buffer not clear: {}", b);
        }

        Ok(())
    }

    async fn read_write(&mut self) -> IoResult<()> {
        self.read_write_headers().await?;
        self.read_write_body().await?;
        self.writer.flush().await
    }

    async fn process_headers(&mut self) -> Option<usize> {
        let ret = {
            let resp_header: Vec<&[u8]> = constants::SPLIT_HEADERS_RE
                .splitn(self.buffer.as_slice(), 2)
                .collect();
            if resp_header.len() == 2 {
                // We have headers
                let headers = resp_header.get(0).unwrap();
                if let Some(header) = constants::TRANSFER_ENCODING.captures(headers) {
                    if let Some(tenc) = header.get(1) {
                        self.transfer_encoding = TransferEncoding::from(tenc.as_bytes());
                    }
                } else if let Some(header) = constants::CONTENT_LENGTH.captures(headers) {
                    if let Some(clength) = header.get(1) {
                        let clength = String::from_utf8_lossy(clength.as_bytes()).into_owned();
                        let clength = usize::from_str_radix(clength.as_str(), 10).unwrap();
                        self.transfer_encoding = TransferEncoding::ContentLength(clength);
                    }
                }
                let resp = headers.len();
                self.writer.write(headers).await.unwrap();
                Some(resp + 4) // + CRLF CRLF
            } else {
                None
            }
        };
        if let Some(to_drain) = ret {
            let buffer = self.buffer.drain(to_drain..).collect();
            self.buffer = buffer;
            info!("End of Headers readched");
            debug!("Transfer encoding: {:?}", self.transfer_encoding);
            debug!("{:?}", String::from_utf8_lossy(self.buffer.as_slice()));
        }
        ret
    }
    async fn process_chunk(&mut self) -> IoResult<bool> {
        debug!(
            "transfer_encoding_status: {:?}",
            self.transfer_encoding_status
        );
        let mut can_process_buffer = self.buffer.len() > 0;
        let mut body_chunk_size = 0;
        let mut header_len: usize;
        while can_process_buffer {
            header_len = 0;
            if self.transfer_encoding_status == TransferEncodingStatus::ReadingHeader {
                // we read the chunk size to drain
                let header: Vec<&[u8]> = constants::SPLIT_HEADER_BRE
                    .splitn(self.buffer.as_slice(), 2)
                    .collect();
                if header.len() == 2 {
                    if let Some(header) = constants::GET_CHUNK_SIZE.captures(header[0]) {
                        if let Some(size) = header.get(1) {
                            let size = size.as_bytes();
                            header_len = size.len() + 2;
                            let size = String::from_utf8_lossy(size).into_owned();
                            body_chunk_size = usize::from_str_radix(size.as_str(), 16).unwrap();
                            self.transfer_encoding_status = TransferEncodingStatus::ChunkHeader;
                        }
                    } else {
                        // else return Error
                        // break;
                    }
                } else {
                    debug!(
                        "Chunked not complete: {}",
                        String::from_utf8_lossy(self.buffer.as_slice())
                    );
                }
            }

            if self.transfer_encoding_status == TransferEncodingStatus::ChunkHeader {
                if body_chunk_size == 0 {
                    debug!(
                        "0 chunked size received: {}",
                        String::from_utf8_lossy(self.buffer.as_slice())
                    );
                    self.buffer.clear(); // should we check that it is '0\r\n' ?
                    return Ok(true);
                }

                debug!(
                    "Before header cleanup: {}",
                    String::from_utf8_lossy(self.buffer.as_slice())
                );
                let buffer: Vec<u8> = self.buffer.drain(header_len..).collect();
                self.buffer = buffer;
                debug!(
                    "After header cleanup: {}",
                    String::from_utf8_lossy(self.buffer.as_slice())
                );
                self.transfer_encoding_status =
                    TransferEncodingStatus::ReadingBody(body_chunk_size);
            }

            if let TransferEncodingStatus::ReadingBody(body_chunk_size) =
                self.transfer_encoding_status
            {
                error!("!! {} > {}", self.buffer.len(), body_chunk_size);
                if self.buffer.len() > body_chunk_size {
                    let mut buffer: Vec<u8> = self.buffer.drain(body_chunk_size..).collect();
                    self.writer.write(self.buffer.as_slice()).await?;

                    let buffer2 = buffer.drain(2..).collect(); // CRLF
                    self.buffer = buffer2;
                    self.transfer_encoding_status = TransferEncodingStatus::ReadingHeader;
                } else {
                    can_process_buffer = false;
                }
            } else {
                can_process_buffer = false;
            }
        }

        return Ok(false);
    }
}

async fn log_request(request: &[u8], verbose: bool) {
    if !log_enabled!(Info) && !verbose {
        return;
    }
    let request: Vec<&[u8]> = constants::SPLIT_HEADERS_RE.splitn(request, 2).collect();
    let headers = String::from_utf8_lossy(&request[0]);
    let headers: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
    let bodylen = if request.len() == 2 {
        let body = &request[1];
        body.len()
    } else {
        0
    };
    if log_enabled!(Info) {
        for header in headers {
            info!("> {}", header);
        }
        if bodylen > 0 {
            info!("> [{} bytes]", bodylen);
        }
        info!(">");
    } else if verbose {
        for header in headers {
            writeln!(&mut stderr(), "> {}", header).await.unwrap();
        }
        if bodylen > 0 {
            writeln!(&mut stderr(), "> [{} bytes]", bodylen)
                .await
                .unwrap();
        }
        writeln!(&mut stderr(), ">").await.unwrap();
    }
}

async fn from_http(
    request: &Request,
    client: &mut TcpStream,
    out: &mut (dyn Write + Unpin),
    verbose: bool,
    read_timeout: u64,
) -> CabotResult<()> {
    let request_bytes = request.to_bytes();
    let raw_request = request_bytes.as_slice();
    log_request(&raw_request, verbose).await;

    debug!("Sending request...");
    client.write_all(&raw_request).await?;

    debug!("Reading response headers...");

    let mut http_decoder = HttpDecoder::new(out, client, read_timeout);
    http_decoder.read_write().await?;
    Ok(())
}

async fn from_https(
    request: &Request,
    client: &mut TcpStream,
    out: &mut (dyn Write + Unpin),
    verbose: bool,
    read_timeout: u64,
) -> CabotResult<()> {
    let request_bytes = request.to_bytes();
    let raw_request = request_bytes.as_slice();
    log_request(&raw_request, verbose).await;

    let mut tls_client = TLSStream::new(client, request.host())?;
    tls_client.starttls().await?;

    debug!("Sending request...");
    tls_client.write_all(&raw_request).await?;
    debug!("Request sent");

    debug!("Decoding response...");
    let mut http_decoder = HttpDecoder::new(out, &mut tls_client, read_timeout);
    http_decoder.read_write().await?;
    Ok(())
}

pub async fn http_query(
    request: &Request,
    mut out: &mut (dyn Write + Unpin),
    authorities: &HashMap<String, SocketAddr>,
    verbose: bool,
    ipv4: bool,
    ipv6: bool,
    dns_timeout: u64,
    connect_timeout: u64,
    read_timeout: u64,
) -> CabotResult<()> {
    debug!(
        "HTTP Query {} {}",
        request.http_method(),
        request.request_uri()
    );

    let authority = request.authority();

    let addr = match authorities.get(authority) {
        Some(val) => {
            info!("Fetch authority {} using autorities map", authority);
            *val
        }
        None => {
            info!("Fetch authority {} using resolver", authority);
            let resolver = Resolver::new(verbose);
            resolver
                .get_addr(authority, ipv4, ipv6, dns_timeout)
                .await?
        }
    };

    info!("Connecting to {}", addr);
    let mut client = io::timeout(Duration::from_millis(connect_timeout), async {
        TcpStream::connect(addr).await
    })
    .await
    .map_err(|err| match err.kind() {
        io::ErrorKind::TimedOut => io::Error::new(err.kind(), "Connection Timeout".to_owned()),
        _ => err,
    })?;

    match request.scheme() {
        "http" => from_http(request, &mut client, &mut out, verbose, read_timeout).await?,
        "https" => from_https(request, &mut client, &mut out, verbose, read_timeout).await?,
        _ => {
            return Err(CabotError::SchemeError(format!(
                "Unrecognized scheme {}",
                request.scheme()
            )))
        }
    };

    out.flush().await.unwrap();

    Ok(())
}
<commit_msg>Customize read timeout error message<commit_after>//! Low level and internal http and https implementation.

use std::collections::HashMap;
use std::time::Duration;

use async_std::io::{self, stderr, Read, Result as IoResult, Write};
use async_std::net::{SocketAddr, TcpStream};
use async_std::prelude::*;
use log::Level::Info;

use super::asynctls::TLSStream;
use super::constants;
use super::dns::Resolver;
use super::request::Request;
use super::results::{CabotError, CabotResult};

#[derive(Debug, PartialEq)]
enum TransferEncoding {
    ContentLength(usize),
    Chunked,
    Unkown,
    None,
}

#[derive(Debug, PartialEq)]
enum TransferEncodingStatus {
    ReadingHeader,
    ChunkHeader,
    ReadingBody(usize),
}

impl From<&[u8]> for TransferEncoding {
    fn from(hdr: &[u8]) -> Self {
        let hdr = String::from_utf8_lossy(hdr);
        let hdrup = hdr.to_ascii_uppercase();
        match hdrup.as_str() {
            "CHUNKED" => TransferEncoding::Chunked,
            _ => TransferEncoding::Unkown,
        }
    }
}

struct HttpDecoder<'a> {
    reader: &'a mut (dyn Read + Unpin), // tls require Write
    writer: &'a mut (dyn Write + Unpin),
    buffer: Vec<u8>,
    transfer_encoding: TransferEncoding,
    transfer_encoding_status: TransferEncodingStatus,
    read_timeout: Duration,
}

impl<'a> HttpDecoder<'a> {
    fn new(
        writer: &'a mut (dyn Write + Unpin),
        reader: &'a mut (dyn Read + Unpin),
        read_timeout: u64,
    ) -> Self {
        HttpDecoder {
            writer,
            reader,
            buffer: Vec::with_capacity(constants::BUFFER_PAGE_SIZE),
            transfer_encoding: TransferEncoding::None,
            transfer_encoding_status: TransferEncodingStatus::ReadingHeader,
            read_timeout: Duration::from_millis(read_timeout),
        }
    }

    async fn chunk_read(&mut self) -> IoResult<usize> {
        let ret = io::timeout(self.read_timeout, async {
            let mut buf = [0; constants::BUFFER_PAGE_SIZE];
            let ret = self.reader.read(&mut buf[..]).await;
            if let Ok(count) = ret {
                if count > 0 {
                    self.buffer.extend_from_slice(&buf[0..count]);
                }
            }
            ret
        });
        ret.await.map_err(|err| match err.kind() {
            io::ErrorKind::TimedOut => io::Error::new(err.kind(), "Read Timeout".to_owned()),
            _ => err,
        })
    }
    async fn read_write_headers(&mut self) -> IoResult<()> {
        info!("Reading headers");
        loop {
            let _count = self.chunk_read().await?;
            if let Some(_) = self.process_headers().await {
                break;
            }
        }
        Ok(())
    }

    async fn read_write_no_transfer_encoding(&mut self) -> IoResult<()> {
        loop {
            self.writer.write(self.buffer.as_slice()).await.unwrap();
            self.buffer.clear();
            let cnt = self.chunk_read().await?;
            if cnt == 0 {
                break;
            }
        }

        Ok(())
    }

    async fn read_content_length(&mut self, size: usize) -> IoResult<()> {
        let mut read_count = self.buffer.len();
        loop {
            self.writer.write(self.buffer.as_slice()).await.unwrap();
            self.buffer.clear();

            if read_count >= size {
                break;
            }
            read_count = read_count + self.chunk_read().await?;
            warn!("< {}", read_count);
        }
        Ok(())
    }

    async fn read_write_chunk(&mut self) -> IoResult<()> {
        loop {
            let done = self.process_chunk().await?;
            if done {
                break;
            }
            let cnt = self.chunk_read().await?;
            if cnt == 0 {
                break;
            }
        }

        Ok(())
    }

    async fn read_write_body(&mut self) -> IoResult<()> {
        info!("Reading body");
        match self.transfer_encoding {
            TransferEncoding::ContentLength(size) => {
                self.read_content_length(size).await?;
            }
            TransferEncoding::Chunked => {
                self.read_write_chunk().await?;
            }
            _ => {
                warn!("Neither Content-Length, not chunk is response header");
                self.read_write_no_transfer_encoding().await?;
            }
        }

        if self.buffer.len() > 0 {
            let b = String::from_utf8_lossy(self.buffer.as_slice());
            error!("Buffer not clear: {}", b);
        }

        Ok(())
    }

    async fn read_write(&mut self) -> IoResult<()> {
        self.read_write_headers().await?;
        self.read_write_body().await?;
        self.writer.flush().await
    }

    async fn process_headers(&mut self) -> Option<usize> {
        let ret = {
            let resp_header: Vec<&[u8]> = constants::SPLIT_HEADERS_RE
                .splitn(self.buffer.as_slice(), 2)
                .collect();
            if resp_header.len() == 2 {
                // We have headers
                let headers = resp_header.get(0).unwrap();
                if let Some(header) = constants::TRANSFER_ENCODING.captures(headers) {
                    if let Some(tenc) = header.get(1) {
                        self.transfer_encoding = TransferEncoding::from(tenc.as_bytes());
                    }
                } else if let Some(header) = constants::CONTENT_LENGTH.captures(headers) {
                    if let Some(clength) = header.get(1) {
                        let clength = String::from_utf8_lossy(clength.as_bytes()).into_owned();
                        let clength = usize::from_str_radix(clength.as_str(), 10).unwrap();
                        self.transfer_encoding = TransferEncoding::ContentLength(clength);
                    }
                }
                let resp = headers.len();
                self.writer.write(headers).await.unwrap();
                Some(resp + 4) // + CRLF CRLF
            } else {
                None
            }
        };
        if let Some(to_drain) = ret {
            let buffer = self.buffer.drain(to_drain..).collect();
            self.buffer = buffer;
            info!("End of Headers readched");
            debug!("Transfer encoding: {:?}", self.transfer_encoding);
            debug!("{:?}", String::from_utf8_lossy(self.buffer.as_slice()));
        }
        ret
    }
    async fn process_chunk(&mut self) -> IoResult<bool> {
        debug!(
            "transfer_encoding_status: {:?}",
            self.transfer_encoding_status
        );
        let mut can_process_buffer = self.buffer.len() > 0;
        let mut body_chunk_size = 0;
        let mut header_len: usize;
        while can_process_buffer {
            header_len = 0;
            if self.transfer_encoding_status == TransferEncodingStatus::ReadingHeader {
                // we read the chunk size to drain
                let header: Vec<&[u8]> = constants::SPLIT_HEADER_BRE
                    .splitn(self.buffer.as_slice(), 2)
                    .collect();
                if header.len() == 2 {
                    if let Some(header) = constants::GET_CHUNK_SIZE.captures(header[0]) {
                        if let Some(size) = header.get(1) {
                            let size = size.as_bytes();
                            header_len = size.len() + 2;
                            let size = String::from_utf8_lossy(size).into_owned();
                            body_chunk_size = usize::from_str_radix(size.as_str(), 16).unwrap();
                            self.transfer_encoding_status = TransferEncodingStatus::ChunkHeader;
                        }
                    } else {
                        // else return Error
                        // break;
                    }
                } else {
                    debug!(
                        "Chunked not complete: {}",
                        String::from_utf8_lossy(self.buffer.as_slice())
                    );
                }
            }

            if self.transfer_encoding_status == TransferEncodingStatus::ChunkHeader {
                if body_chunk_size == 0 {
                    debug!(
                        "0 chunked size received: {}",
                        String::from_utf8_lossy(self.buffer.as_slice())
                    );
                    self.buffer.clear(); // should we check that it is '0\r\n' ?
                    return Ok(true);
                }

                debug!(
                    "Before header cleanup: {}",
                    String::from_utf8_lossy(self.buffer.as_slice())
                );
                let buffer: Vec<u8> = self.buffer.drain(header_len..).collect();
                self.buffer = buffer;
                debug!(
                    "After header cleanup: {}",
                    String::from_utf8_lossy(self.buffer.as_slice())
                );
                self.transfer_encoding_status =
                    TransferEncodingStatus::ReadingBody(body_chunk_size);
            }

            if let TransferEncodingStatus::ReadingBody(body_chunk_size) =
                self.transfer_encoding_status
            {
                error!("!! {} > {}", self.buffer.len(), body_chunk_size);
                if self.buffer.len() > body_chunk_size {
                    let mut buffer: Vec<u8> = self.buffer.drain(body_chunk_size..).collect();
                    self.writer.write(self.buffer.as_slice()).await?;

                    let buffer2 = buffer.drain(2..).collect(); // CRLF
                    self.buffer = buffer2;
                    self.transfer_encoding_status = TransferEncodingStatus::ReadingHeader;
                } else {
                    can_process_buffer = false;
                }
            } else {
                can_process_buffer = false;
            }
        }

        return Ok(false);
    }
}

async fn log_request(request: &[u8], verbose: bool) {
    if !log_enabled!(Info) && !verbose {
        return;
    }
    let request: Vec<&[u8]> = constants::SPLIT_HEADERS_RE.splitn(request, 2).collect();
    let headers = String::from_utf8_lossy(&request[0]);
    let headers: Vec<&str> = constants::SPLIT_HEADER_RE.split(&headers).collect();
    let bodylen = if request.len() == 2 {
        let body = &request[1];
        body.len()
    } else {
        0
    };
    if log_enabled!(Info) {
        for header in headers {
            info!("> {}", header);
        }
        if bodylen > 0 {
            info!("> [{} bytes]", bodylen);
        }
        info!(">");
    } else if verbose {
        for header in headers {
            writeln!(&mut stderr(), "> {}", header).await.unwrap();
        }
        if bodylen > 0 {
            writeln!(&mut stderr(), "> [{} bytes]", bodylen)
                .await
                .unwrap();
        }
        writeln!(&mut stderr(), ">").await.unwrap();
    }
}

async fn from_http(
    request: &Request,
    client: &mut TcpStream,
    out: &mut (dyn Write + Unpin),
    verbose: bool,
    read_timeout: u64,
) -> CabotResult<()> {
    let request_bytes = request.to_bytes();
    let raw_request = request_bytes.as_slice();
    log_request(&raw_request, verbose).await;

    debug!("Sending request...");
    client.write_all(&raw_request).await?;

    debug!("Reading response headers...");

    let mut http_decoder = HttpDecoder::new(out, client, read_timeout);
    http_decoder.read_write().await?;
    Ok(())
}

async fn from_https(
    request: &Request,
    client: &mut TcpStream,
    out: &mut (dyn Write + Unpin),
    verbose: bool,
    read_timeout: u64,
) -> CabotResult<()> {
    let request_bytes = request.to_bytes();
    let raw_request = request_bytes.as_slice();
    log_request(&raw_request, verbose).await;

    let mut tls_client = TLSStream::new(client, request.host())?;
    tls_client.starttls().await?;

    debug!("Sending request...");
    tls_client.write_all(&raw_request).await?;
    debug!("Request sent");

    debug!("Decoding response...");
    let mut http_decoder = HttpDecoder::new(out, &mut tls_client, read_timeout);
    http_decoder.read_write().await?;
    Ok(())
}

pub async fn http_query(
    request: &Request,
    mut out: &mut (dyn Write + Unpin),
    authorities: &HashMap<String, SocketAddr>,
    verbose: bool,
    ipv4: bool,
    ipv6: bool,
    dns_timeout: u64,
    connect_timeout: u64,
    read_timeout: u64,
) -> CabotResult<()> {
    debug!(
        "HTTP Query {} {}",
        request.http_method(),
        request.request_uri()
    );

    let authority = request.authority();

    let addr = match authorities.get(authority) {
        Some(val) => {
            info!("Fetch authority {} using autorities map", authority);
            *val
        }
        None => {
            info!("Fetch authority {} using resolver", authority);
            let resolver = Resolver::new(verbose);
            resolver
                .get_addr(authority, ipv4, ipv6, dns_timeout)
                .await?
        }
    };

    info!("Connecting to {}", addr);
    let mut client = io::timeout(Duration::from_millis(connect_timeout), async {
        TcpStream::connect(addr).await
    })
    .await
    .map_err(|err| match err.kind() {
        io::ErrorKind::TimedOut => io::Error::new(err.kind(), "Connection Timeout".to_owned()),
        _ => err,
    })?;

    match request.scheme() {
        "http" => from_http(request, &mut client, &mut out, verbose, read_timeout).await?,
        "https" => from_https(request, &mut client, &mut out, verbose, read_timeout).await?,
        _ => {
            return Err(CabotError::SchemeError(format!(
                "Unrecognized scheme {}",
                request.scheme()
            )))
        }
    };

    out.flush().await.unwrap();

    Ok(())
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::ljpeg::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct Cr2Decoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> Cr2Decoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> Cr2Decoder<'a> {
    Cr2Decoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for Cr2Decoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let (raw, offset) = {
      if let Some(raw) = self.tiff.find_first_ifd(Tag::Cr2Id) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(raw) = self.tiff.find_first_ifd(Tag::CFAPattern) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(off) = self.tiff.find_entry(Tag::Cr2OldOffset) {
        (&self.tiff, off.get_usize(0))
      } else {
        return Err("CR2: Couldn't find raw info".to_string())
      }
    };
    let src = &self.buffer[offset..];

    let (width, height, image) = {
      let decompressor = try!(LjpegDecompressor::new(src, true));
      let width = decompressor.width();
      let height = decompressor.height();
      let mut ljpegout = vec![0 as u16; width*height];
      try!(decompressor.decode(&mut ljpegout, 0, width, width, height));

      // Take each of the vertical fields and put them into the right location
      // FIXME: Doing this at the decode would reduce about 5% in runtime but I haven't
      //        been able to do it without hairy code
      if let Some(canoncol) = raw.find_entry(Tag::Cr2StripeWidths) {
        if canoncol.get_usize(0) == 0 {
          (width, height, ljpegout)
        } else {
          let mut out = vec![0 as u16; width*height];
          let mut fieldwidths = Vec::new();
          for _ in 0..canoncol.get_usize(0) {
            fieldwidths.push(canoncol.get_usize(1));
          }
          fieldwidths.push(canoncol.get_usize(2));

          let mut fieldstart = 0;
          let mut fieldpos = 0;
          for fieldwidth in fieldwidths {
            for row in 0..height {
              let outpos = row*width+fieldstart;
              let inpos = fieldpos+row*fieldwidth;
              let outb = &mut out[outpos..outpos+fieldwidth];
              let inb = &ljpegout[inpos..inpos+fieldwidth];
              outb.copy_from_slice(inb);
            }
            fieldstart += fieldwidth;
            fieldpos += fieldwidth*height;
          }

          (width, height, out)
        }
      } else if camera.find_hint("double_line") {
        (width/2, height*2, ljpegout)
      } else {
        (width, height, ljpegout)
      }
    };
    ok_image(camera, width, height, try!(self.get_wb(camera)), image)
  }
}

impl<'a> Cr2Decoder<'a> {
  fn get_wb(&self, cam: &Camera) -> Result<[f32;4], String> {
    if let Some(levels) = self.tiff.find_entry(Tag::Cr2ColorData) {
      let offset = if cam.wb_offset != 0 {cam.wb_offset} else {63};
      Ok([levels.get_force_u16(offset) as f32, levels.get_force_u16(offset+1) as f32,
          levels.get_force_u16(offset+3) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2PowerShotWB) {
      Ok([levels.get_force_u32(3) as f32, levels.get_force_u32(2) as f32,
          levels.get_force_u32(4) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2OldWB) {
      Ok([levels.get_f32(0), levels.get_f32(1), levels.get_f32(2), NAN])
    } else {
      Err("CR2: Couldn't find WB".to_string())
    }
  }
}
<commit_msg>CR2: accep no WB as at least the D2000 has none<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::ljpeg::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct Cr2Decoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> Cr2Decoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> Cr2Decoder<'a> {
    Cr2Decoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for Cr2Decoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let (raw, offset) = {
      if let Some(raw) = self.tiff.find_first_ifd(Tag::Cr2Id) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(raw) = self.tiff.find_first_ifd(Tag::CFAPattern) {
        (raw, fetch_tag!(raw, Tag::StripOffsets).get_usize(0))
      } else if let Some(off) = self.tiff.find_entry(Tag::Cr2OldOffset) {
        (&self.tiff, off.get_usize(0))
      } else {
        return Err("CR2: Couldn't find raw info".to_string())
      }
    };
    let src = &self.buffer[offset..];

    let (width, height, image) = {
      let decompressor = try!(LjpegDecompressor::new(src, true));
      let width = decompressor.width();
      let height = decompressor.height();
      let mut ljpegout = vec![0 as u16; width*height];
      try!(decompressor.decode(&mut ljpegout, 0, width, width, height));

      // Take each of the vertical fields and put them into the right location
      // FIXME: Doing this at the decode would reduce about 5% in runtime but I haven't
      //        been able to do it without hairy code
      if let Some(canoncol) = raw.find_entry(Tag::Cr2StripeWidths) {
        if canoncol.get_usize(0) == 0 {
          (width, height, ljpegout)
        } else {
          let mut out = vec![0 as u16; width*height];
          let mut fieldwidths = Vec::new();
          for _ in 0..canoncol.get_usize(0) {
            fieldwidths.push(canoncol.get_usize(1));
          }
          fieldwidths.push(canoncol.get_usize(2));

          let mut fieldstart = 0;
          let mut fieldpos = 0;
          for fieldwidth in fieldwidths {
            for row in 0..height {
              let outpos = row*width+fieldstart;
              let inpos = fieldpos+row*fieldwidth;
              let outb = &mut out[outpos..outpos+fieldwidth];
              let inb = &ljpegout[inpos..inpos+fieldwidth];
              outb.copy_from_slice(inb);
            }
            fieldstart += fieldwidth;
            fieldpos += fieldwidth*height;
          }

          (width, height, out)
        }
      } else if camera.find_hint("double_line") {
        (width/2, height*2, ljpegout)
      } else {
        (width, height, ljpegout)
      }
    };
    ok_image(camera, width, height, try!(self.get_wb(camera)), image)
  }
}

impl<'a> Cr2Decoder<'a> {
  fn get_wb(&self, cam: &Camera) -> Result<[f32;4], String> {
    if let Some(levels) = self.tiff.find_entry(Tag::Cr2ColorData) {
      let offset = if cam.wb_offset != 0 {cam.wb_offset} else {63};
      Ok([levels.get_force_u16(offset) as f32, levels.get_force_u16(offset+1) as f32,
          levels.get_force_u16(offset+3) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2PowerShotWB) {
      Ok([levels.get_force_u32(3) as f32, levels.get_force_u32(2) as f32,
          levels.get_force_u32(4) as f32, NAN])
    } else if let Some(levels) = self.tiff.find_entry(Tag::Cr2OldWB) {
      Ok([levels.get_f32(0), levels.get_f32(1), levels.get_f32(2), NAN])
    } else {
      // At least the D2000 has no WB
      Ok([NAN,NAN,NAN,NAN])
    }
  }
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use decoders::cfa::*;
use std::f32::NAN;
use std::cmp;

#[derive(Debug, Clone)]
pub struct DngDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> DngDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> DngDecoder<'a> {
    DngDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for DngDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let ifds = self.tiff.find_ifds_with_tag(Tag::Compression).into_iter().filter(|ifd| {
      let compression = (**ifd).find_entry(Tag::Compression).unwrap().get_u32(0);
      let subsampled = match (**ifd).find_entry(Tag::NewSubFileType) {
        Some(e) => e.get_u32(0) & 1 != 0,
        None => false,
      };
      !subsampled && (compression == 7 || compression == 1 || compression == 0x884c)
    }).collect::<Vec<&TiffIFD>>();
    let raw = ifds[0];
    let width = fetch_tag!(raw, Tag::ImageWidth).get_u32(0);
    let height = fetch_tag!(raw, Tag::ImageLength).get_u32(0);

    let image = match fetch_tag!(raw, Tag::Compression).get_u32(0) {
      1 => try!(self.decode_uncompressed(raw, width as usize, height as usize)),
      7 => try!(self.decode_compressed(raw, width as usize, height as usize)),
      c => return Err(format!("Don't know how to read DNGs with compression {}", c).to_string()),
    };

    let (make, model, canonical_make, canonical_model) = {
      match self.rawloader.check_supported(&self.tiff) {
        Ok(cam) => {
          (cam.make.clone(), cam.model.clone(),
           cam.canonical_make.clone(),cam.canonical_model.clone())
        },
        Err(_) => {
          let make = fetch_tag!(self.tiff, Tag::Make).get_str();
          let model = fetch_tag!(self.tiff, Tag::Model).get_str();
          (make.to_string(), model.to_string(), make.to_string(), model.to_string())
        },
      }
    };

    Ok(Image {
      make: make,
      model: model,
      canonical_make: canonical_make,
      canonical_model: canonical_model,
      width: width as usize,
      height: height as usize,
      wb_coeffs: try!(self.get_wb()),
      data: image.into_boxed_slice(),
      blacklevels: try!(self.get_blacklevels(raw)),
      whitelevels: try!(self.get_whitelevels(raw)),
      xyz_to_cam: try!(self.get_color_matrix()),
      cfa: try!(self.get_cfa(raw)),
      crops: try!(self.get_crops(raw, width as usize, height as usize)),
    })
  }
}

impl<'a> DngDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    let levels = fetch_tag!(self.tiff, Tag::AsShotNeutral);
    Ok([1.0/levels.get_f32(0),1.0/levels.get_f32(1),1.0/levels.get_f32(2),NAN])
  }

  fn get_blacklevels(&self, raw: &TiffIFD) -> Result<[u16;4], String> {
    let levels = fetch_tag!(raw, Tag::BlackLevels);
    Ok([levels.get_f32(0) as u16,levels.get_f32(1) as u16,
        levels.get_f32(2) as u16,levels.get_f32(3) as u16])
  }

  fn get_whitelevels(&self, raw: &TiffIFD) -> Result<[u16;4], String> {
    let level = fetch_tag!(raw, Tag::WhiteLevel).get_u32(0) as u16;
    Ok([level,level,level,level])
  }

  fn get_cfa(&self, raw: &TiffIFD) -> Result<CFA,String> {
    let pattern = fetch_tag!(raw, Tag::CFAPattern);
    Ok(CFA::new_from_tag(pattern))
  }

  fn get_crops(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<[usize;4],String> {
    if let Some(crops) = raw.find_entry(Tag::ActiveArea) {
      Ok([crops.get_u32(0) as usize, width - crops.get_u32(3) as usize,
          height - crops.get_u32(2) as usize, crops.get_u32(1) as usize])
    } else {
      // Ignore missing crops, at least some pentax DNGs don't have it
      Ok([0,0,0,0])
    }
  }

  fn get_color_matrix(&self) -> Result<[[f32;3];4],String> {
    let mut matrix: [[f32;3];4] = [[0.0;3];4];
    let cmatrix = fetch_tag!(self.tiff, Tag::ColorMatrix2);
    if cmatrix.count() > 12 {
      Err(format!("color matrix supposedly has {} components",cmatrix.count()).to_string())
    } else {
      for i in 0..(cmatrix.count() as usize) {
        matrix[i/3][i%3] = cmatrix.get_f32(i);
      }
      Ok(matrix)
    }
  }

  pub fn decode_uncompressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    let offset = fetch_tag!(raw, Tag::StripOffsets).get_u32(0) as usize;
    let src = &self.buffer[offset..];

    match fetch_tag!(raw, Tag::BitsPerSample).get_u32(0) {
      16  => Ok(decode_16le(src, width, height)),
      12  => Ok(decode_12be(src, width, height)),
      bps => Err(format!("DNG: Don't know about {} bps images", bps).to_string()),
    }
  }

  pub fn decode_compressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    if let Some(offsets) = raw.find_entry(Tag::StripOffsets) { // We're in a normal offset situation
      if offsets.count() != 1 {
        return Err("DNG: files with more than one slice not supported yet".to_string())
      }
      let offset = offsets.get_u32(0) as usize;
      let src = &self.buffer[offset..];
      let mut out = vec![0 as u16; width*height];
      let decompressor = try!(LjpegDecompressor::new(src, true));
      try!(decompressor.decode(&mut out, 0, width, width, height));
      Ok(out)
    } else if let Some(offsets) = raw.find_entry(Tag::TileOffsets) {
      // They've gone with tiling
      let twidth = fetch_tag!(raw, Tag::TileWidth).get_u32(0) as usize;
      let tlength = fetch_tag!(raw, Tag::TileLength).get_u32(0) as usize;
      let coltiles = (width-1)/twidth + 1;
      let rowtiles = (height-1)/tlength + 1;
      if coltiles*rowtiles != offsets.count() as usize {
        return Err(format!("DNG: trying to decode {} tiles from {} offsets",
                           coltiles*rowtiles, offsets.count()).to_string())
      }

      Ok(decode_threaded_multiline(width, height, tlength, &(|strip: &mut [u16], row| {
        let row = row / tlength;
        for col in 0..coltiles {
          let offset = offsets.get_u32(row*coltiles+col) as usize;
          let src = &self.buffer[offset..];
          // We don't use bigtable here as the tiles are two small to amortize the setup cost
          let decompressor = LjpegDecompressor::new(src, true).unwrap();
          let bwidth = cmp::min(width, (col+1)*twidth) - col*twidth;
          let blength = cmp::min(height, (row+1)*tlength) - row*tlength;
          decompressor.decode(strip, col*twidth, width, bwidth, blength).unwrap();
        }
      })))
    } else {
      Err("DNG: didn't find tiles or strips".to_string())
    }
  }
}
<commit_msg>DNG: Be more liberal in parsing BlackLevel<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::basics::*;
use decoders::ljpeg::*;
use decoders::cfa::*;
use std::f32::NAN;
use std::cmp;

#[derive(Debug, Clone)]
pub struct DngDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> DngDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> DngDecoder<'a> {
    DngDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for DngDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let ifds = self.tiff.find_ifds_with_tag(Tag::Compression).into_iter().filter(|ifd| {
      let compression = (**ifd).find_entry(Tag::Compression).unwrap().get_u32(0);
      let subsampled = match (**ifd).find_entry(Tag::NewSubFileType) {
        Some(e) => e.get_u32(0) & 1 != 0,
        None => false,
      };
      !subsampled && (compression == 7 || compression == 1 || compression == 0x884c)
    }).collect::<Vec<&TiffIFD>>();
    let raw = ifds[0];
    let width = fetch_tag!(raw, Tag::ImageWidth).get_u32(0);
    let height = fetch_tag!(raw, Tag::ImageLength).get_u32(0);

    let image = match fetch_tag!(raw, Tag::Compression).get_u32(0) {
      1 => try!(self.decode_uncompressed(raw, width as usize, height as usize)),
      7 => try!(self.decode_compressed(raw, width as usize, height as usize)),
      c => return Err(format!("Don't know how to read DNGs with compression {}", c).to_string()),
    };

    let (make, model, canonical_make, canonical_model) = {
      match self.rawloader.check_supported(&self.tiff) {
        Ok(cam) => {
          (cam.make.clone(), cam.model.clone(),
           cam.canonical_make.clone(),cam.canonical_model.clone())
        },
        Err(_) => {
          let make = fetch_tag!(self.tiff, Tag::Make).get_str();
          let model = fetch_tag!(self.tiff, Tag::Model).get_str();
          (make.to_string(), model.to_string(), make.to_string(), model.to_string())
        },
      }
    };

    Ok(Image {
      make: make,
      model: model,
      canonical_make: canonical_make,
      canonical_model: canonical_model,
      width: width as usize,
      height: height as usize,
      wb_coeffs: try!(self.get_wb()),
      data: image.into_boxed_slice(),
      blacklevels: try!(self.get_blacklevels(raw)),
      whitelevels: try!(self.get_whitelevels(raw)),
      xyz_to_cam: try!(self.get_color_matrix()),
      cfa: try!(self.get_cfa(raw)),
      crops: try!(self.get_crops(raw, width as usize, height as usize)),
    })
  }
}

impl<'a> DngDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    let levels = fetch_tag!(self.tiff, Tag::AsShotNeutral);
    Ok([1.0/levels.get_f32(0),1.0/levels.get_f32(1),1.0/levels.get_f32(2),NAN])
  }

  fn get_blacklevels(&self, raw: &TiffIFD) -> Result<[u16;4], String> {
    if let Some(levels) = raw.find_entry(Tag::BlackLevels) {
      if levels.count() < 4 {
        let black = levels.get_u32(0) as u16;
        Ok([black, black, black, black])
      } else {
        Ok([levels.get_u32(0) as u16,levels.get_u32(1) as u16,
            levels.get_u32(2) as u16,levels.get_u32(3) as u16])
      }
    } else {
      Ok([0,0,0,0])
    }
  }

  fn get_whitelevels(&self, raw: &TiffIFD) -> Result<[u16;4], String> {
    let level = fetch_tag!(raw, Tag::WhiteLevel).get_u32(0) as u16;
    Ok([level,level,level,level])
  }

  fn get_cfa(&self, raw: &TiffIFD) -> Result<CFA,String> {
    let pattern = fetch_tag!(raw, Tag::CFAPattern);
    Ok(CFA::new_from_tag(pattern))
  }

  fn get_crops(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<[usize;4],String> {
    if let Some(crops) = raw.find_entry(Tag::ActiveArea) {
      Ok([crops.get_u32(0) as usize, width - crops.get_u32(3) as usize,
          height - crops.get_u32(2) as usize, crops.get_u32(1) as usize])
    } else {
      // Ignore missing crops, at least some pentax DNGs don't have it
      Ok([0,0,0,0])
    }
  }

  fn get_color_matrix(&self) -> Result<[[f32;3];4],String> {
    let mut matrix: [[f32;3];4] = [[0.0;3];4];
    let cmatrix = fetch_tag!(self.tiff, Tag::ColorMatrix2);
    if cmatrix.count() > 12 {
      Err(format!("color matrix supposedly has {} components",cmatrix.count()).to_string())
    } else {
      for i in 0..(cmatrix.count() as usize) {
        matrix[i/3][i%3] = cmatrix.get_f32(i);
      }
      Ok(matrix)
    }
  }

  pub fn decode_uncompressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    let offset = fetch_tag!(raw, Tag::StripOffsets).get_u32(0) as usize;
    let src = &self.buffer[offset..];

    match fetch_tag!(raw, Tag::BitsPerSample).get_u32(0) {
      16  => Ok(decode_16le(src, width, height)),
      12  => Ok(decode_12be(src, width, height)),
      bps => Err(format!("DNG: Don't know about {} bps images", bps).to_string()),
    }
  }

  pub fn decode_compressed(&self, raw: &TiffIFD, width: usize, height: usize) -> Result<Vec<u16>,String> {
    if let Some(offsets) = raw.find_entry(Tag::StripOffsets) { // We're in a normal offset situation
      if offsets.count() != 1 {
        return Err("DNG: files with more than one slice not supported yet".to_string())
      }
      let offset = offsets.get_u32(0) as usize;
      let src = &self.buffer[offset..];
      let mut out = vec![0 as u16; width*height];
      let decompressor = try!(LjpegDecompressor::new(src, true));
      try!(decompressor.decode(&mut out, 0, width, width, height));
      Ok(out)
    } else if let Some(offsets) = raw.find_entry(Tag::TileOffsets) {
      // They've gone with tiling
      let twidth = fetch_tag!(raw, Tag::TileWidth).get_u32(0) as usize;
      let tlength = fetch_tag!(raw, Tag::TileLength).get_u32(0) as usize;
      let coltiles = (width-1)/twidth + 1;
      let rowtiles = (height-1)/tlength + 1;
      if coltiles*rowtiles != offsets.count() as usize {
        return Err(format!("DNG: trying to decode {} tiles from {} offsets",
                           coltiles*rowtiles, offsets.count()).to_string())
      }

      Ok(decode_threaded_multiline(width, height, tlength, &(|strip: &mut [u16], row| {
        let row = row / tlength;
        for col in 0..coltiles {
          let offset = offsets.get_u32(row*coltiles+col) as usize;
          let src = &self.buffer[offset..];
          // We don't use bigtable here as the tiles are two small to amortize the setup cost
          let decompressor = LjpegDecompressor::new(src, true).unwrap();
          let bwidth = cmp::min(width, (col+1)*twidth) - col*twidth;
          let blength = cmp::min(height, (row+1)*tlength) - row*tlength;
          decompressor.decode(strip, col*twidth, width, bwidth, blength).unwrap();
        }
      })))
    } else {
      Err("DNG: didn't find tiles or strips".to_string())
    }
  }
}
<|endoftext|>


<commit_before>use decoders::*;
use decoders::tiff::*;
use decoders::ljpeg::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct TfrDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> TfrDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> TfrDecoder<'a> {
    TfrDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for TfrDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let raw = fetch_ifd!(&self.tiff, Tag::WhiteLevel);
    let width = fetch_tag!(raw, Tag::ImageWidth).get_usize(0);
    let height = fetch_tag!(raw, Tag::ImageLength).get_usize(0);
    let offset = fetch_tag!(raw, Tag::StripOffsets).get_usize(0);
    let src = &self.buffer[offset..];

    let image = try!(self.decode_compressed(src, width, height));
    ok_image(camera, width, height, try!(self.get_wb()), image)
  }
}

impl<'a> TfrDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    let levels = fetch_tag!(self.tiff, Tag::AsShotNeutral);
    Ok([1.0/levels.get_f32(0),1.0/levels.get_f32(1),1.0/levels.get_f32(2),NAN])
  }

  fn decode_compressed(&self, src: &[u8], width: usize, height: usize) -> Result<Vec<u16>,String> {
    let mut out = vec![0 as u16; width*height];
    let decompressor = try!(LjpegDecompressor::new(src, true));
    try!(decompressor.decode(&mut out, 0, width, width, height));
    Ok(out)
  }
}
<commit_msg>3FR: no point generating big table to not use it<commit_after>use decoders::*;
use decoders::tiff::*;
use decoders::ljpeg::*;
use std::f32::NAN;

#[derive(Debug, Clone)]
pub struct TfrDecoder<'a> {
  buffer: &'a [u8],
  rawloader: &'a RawLoader,
  tiff: TiffIFD<'a>,
}

impl<'a> TfrDecoder<'a> {
  pub fn new(buf: &'a [u8], tiff: TiffIFD<'a>, rawloader: &'a RawLoader) -> TfrDecoder<'a> {
    TfrDecoder {
      buffer: buf,
      tiff: tiff,
      rawloader: rawloader,
    }
  }
}

impl<'a> Decoder for TfrDecoder<'a> {
  fn image(&self) -> Result<Image,String> {
    let camera = try!(self.rawloader.check_supported(&self.tiff));
    let raw = fetch_ifd!(&self.tiff, Tag::WhiteLevel);
    let width = fetch_tag!(raw, Tag::ImageWidth).get_usize(0);
    let height = fetch_tag!(raw, Tag::ImageLength).get_usize(0);
    let offset = fetch_tag!(raw, Tag::StripOffsets).get_usize(0);
    let src = &self.buffer[offset..];

    let image = try!(self.decode_compressed(src, width, height));
    ok_image(camera, width, height, try!(self.get_wb()), image)
  }
}

impl<'a> TfrDecoder<'a> {
  fn get_wb(&self) -> Result<[f32;4], String> {
    let levels = fetch_tag!(self.tiff, Tag::AsShotNeutral);
    Ok([1.0/levels.get_f32(0),1.0/levels.get_f32(1),1.0/levels.get_f32(2),NAN])
  }

  fn decode_compressed(&self, src: &[u8], width: usize, height: usize) -> Result<Vec<u16>,String> {
    let mut out = vec![0 as u16; width*height];
    let decompressor = try!(LjpegDecompressor::new(src, false));
    try!(decompressor.decode(&mut out, 0, width, width, height));
    Ok(out)
  }
}
<|endoftext|>


<commit_before>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

// allow ItemType to be cloned/copied
#[derive(Clone)]
enum ItemType {
   Dir,
   File,
   Other,
}

// allow FoundItem to be cloned/copied
#[derive(Clone)]
struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

impl FoundItem {
   fn dump(self: FoundItem) {
      match self.item_type {
         // use .unwrap() to get the contents of the Option returned by
         // file_name()
         ItemType::Dir   => println!("d {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::File  => println!("f {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::Other => println!("o {:?}",
            self.item_path.file_name().unwrap()),
      }
   }
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

   let mut items_v = Vec::new();
   let mut recurse_stack = Vec::new();
   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   // returns an array of DirEntry objects
   if let Ok(entries) = fs::read_dir(idg_dir.clone()) {
      // for each DirEntry object...
      for dir_entry in entries {

         // the item being tested/checked
         let item;

         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
                  recurse_stack.push(item.clone());
               }
               else {
                  item = FoundItem {
                     item_type: ItemType::Other,
                     item_path: dir_entry.path()
                  };

               }
               // push this items onto a Vec
               items_v.push(item);
            }
         }
      }
   }

   println!("Dumping items in {:?}", idg_dir);
   for item in items_v {
      // dump each item
      item.dump();
   }
/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

}
<commit_msg>src/main.rs: fixed up comments/whitespace<commit_after>// fs.rs
use std::env; // env::home_dir()
use std::fs; // fs::read_dir()
//use std::path::Path;
use std::path::PathBuf;

// allow ItemType to be cloned
#[derive(Clone)]
enum ItemType {
   Dir,
   File,
   Other,
}

// allow FoundItem to be cloned
// 'PathBuf' only allows cloning, not copying
#[derive(Clone)]
struct FoundItem {
   item_type: ItemType,
   item_path: PathBuf,
}

impl FoundItem {
   fn dump(self: FoundItem) {
      match self.item_type {
         // use .unwrap() to get the contents of the Option returned by
         // file_name()
         ItemType::Dir   => println!("d {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::File  => println!("f {:?}",
            self.item_path.file_name().unwrap()),
         ItemType::Other => println!("o {:?}",
            self.item_path.file_name().unwrap()),
      }
   }
}

fn main() {
   //let mut idg_dir_path = PathBuf::from("~/Files/Doom/idgames");
   // create an empty PathBuf
   let mut idg_dir = PathBuf::new();
   // call `home_dir()` and act on what it returns
   match env::home_dir() {
      //Some(idg_dir) => println!("{}", idg_dir.display()),
      // home_dir() returned something
      Some(home_dir) => idg_dir = home_dir,
      // home_dir() returned nothing
      None => println!("Can't obtain home directory path!"),
   }

   // append more directories on to idg_dir
   idg_dir.push("Files");
   idg_dir.push("Doom");
   idg_dir.push("idgames");

   let mut items_v = Vec::new();
   let mut recurse_stack = Vec::new();
   // working example from:
   // https://doc.rust-lang.org/std/fs/struct.DirEntry.html#method.file_name
   // returns an array of DirEntry objects
   if let Ok(entries) = fs::read_dir(idg_dir.clone()) {
      // for each DirEntry object...
      for dir_entry in entries {

         // the item being tested/checked
         let item;

         if let Ok(dir_entry) = dir_entry {
            //let path = dir_entry.path();
            // get the metadata object for this DirEntry
            if let Ok(metadata) = dir_entry.metadata() {
               // below, `dir_entry` is a `DirEntry`.
               if metadata.is_file() {
                  item = FoundItem {
                     item_type: ItemType::File,
                     item_path: dir_entry.path()
                  };
               }
               else if metadata.is_dir() {
                  item = FoundItem {
                     item_type: ItemType::Dir,
                     item_path: dir_entry.path()
                  };
                  recurse_stack.push(item.clone());
               }
               else {
                  item = FoundItem {
                     item_type: ItemType::Other,
                     item_path: dir_entry.path()
                  };

               }
               // push this items onto a Vec
               items_v.push(item);
            }
         }
      }
   }

   println!("Dumping items in {:?}", idg_dir);
   for item in items_v {
      // dump each item
      item.dump();
   }
/*
// doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
       let dir = try!(entry);
       println!("{:?}", dir.path());
   }
*/

/*
   // try and read the contents of idg_dir/
   // - doesn't work, try!() won't handle _Result_ objects
   for entry in try!(fs::read_dir(idg_dir)) {
      let dir = try!(entry);
      // 'entry' is still a _Result_, so this is broken
      let metadata = try!(entry.metadata());
      // 'dir' is still a _DirEntry_
      if dir.is_dir() {
         println!("d {:?}", dir.path());
      } else {
         println!("! {:?}", dir.path());
      }
   }
*/

/*
   if let Ok(entries) = fs::read_dir(idg_dir) {
      for entry in entries {
         // 'item' is a Result, unwrap it to get access to Metadata
         if let Ok(entry) = entry {
               if let Ok(metadata) = entry.metadata() {};
               // entry.path() returns a _Result_
               if let Ok(path) = entry.path() {};
               // 'entry' is a _DirEntry_, and doesn't have an 'is_dir()'
               // method
               if entry.is_dir() {
                  println!("d {:?} {:?}",
                     // 'metadata' isn't available here
                     metadata.file_type(),
                     // the compiler doesn't know what 'path' is here
                     path);
            }
         }
      }
   }
*/

/*
   // working example
   println!("Updated іdgames/ path: {}", idg_dir.display());
   // read the contents of idg_dir/
   match fs::read_dir(idg_dir) {
      Err(why) => println!("! {:?}", why.kind()),
      Ok(paths) => for path in paths {
         println!("> {:?}", path.unwrap().path());
      }
   }
*/

}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(phase, slicing_syntax)]

#[phase(plugin, link)] extern crate log;
extern crate criterion;
extern crate serialize;

use criterion::Criterion;
use std::io::{USER_DIR, Command, File, fs};
use std::str;

use executable::Executable;
use problem::Problem;
use solution::Solution;

mod compiler;
mod executable;
mod interpreter;
mod language;
mod problem;
mod solution;

fn lscpu() {
    match Command::new("lscpu").output() {
        Err(_) => fail!("Couldn't spawn `lscpu`"),
        Ok(po) => match str::from_utf8(po.output[]) {
            None => fail!("Couldn't parse the output of `lscpu`"),
            Some(output) => {
                let s = output.lines().filter(|line| {
                    !line.starts_with("CPU MHz:")
                }).collect::<Vec<_>>().connect("\n");

                match File::create(&Path::new("lscpu")).write_str(s.as_slice()) {
                    Err(_) => fail!("Couln't write to the cpu file"),
                    Ok(_) => {},
                }
            }
        },
    }
}

fn main() {
    let languages = language::all();

    lscpu();

    for problem in fs::readdir(&Path::new("problems")).unwrap().into_iter().filter_map(|dir| {
        Problem::new(dir)
    }) {
        let mut processed = 0u;

        for solution in languages.iter().filter_map(|language| {
            Solution::new(language, &problem)
        }) {
            match Executable::new(&solution) {
                Some(executable) => if executable.validate() == Some(true) {
                    executable.bench();
                    processed += 1;
                },
                None => {},
            }
        }

        if processed > 0 {
            Criterion::default().summarize(problem.id());

            let pid = problem.id();
            let summary_plot = Path::new(".criterion").join(pid).join("summary/new/medians.svg");
            let plots_dir = Path::new("plots");

            fs::mkdir_recursive(&plots_dir, USER_DIR).ok().
                expect("Couldn't create the plots directory");
            fs::copy(&summary_plot, &plots_dir.join(pid).with_extension("svg")).ok().
                expect("Couldn't copy summary plot to the plots directory");
        }
    }
}
<commit_msg>feat(summary): use violin plot as summary image<commit_after>#![deny(warnings)]
#![feature(phase, slicing_syntax)]

#[phase(plugin, link)] extern crate log;
extern crate criterion;
extern crate serialize;

use criterion::Criterion;
use std::io::{USER_DIR, Command, File, fs};
use std::str;

use executable::Executable;
use problem::Problem;
use solution::Solution;

mod compiler;
mod executable;
mod interpreter;
mod language;
mod problem;
mod solution;

fn lscpu() {
    match Command::new("lscpu").output() {
        Err(_) => fail!("Couldn't spawn `lscpu`"),
        Ok(po) => match str::from_utf8(po.output[]) {
            None => fail!("Couldn't parse the output of `lscpu`"),
            Some(output) => {
                let s = output.lines().filter(|line| {
                    !line.starts_with("CPU MHz:")
                }).collect::<Vec<_>>().connect("\n");

                match File::create(&Path::new("lscpu")).write_str(s.as_slice()) {
                    Err(_) => fail!("Couln't write to the cpu file"),
                    Ok(_) => {},
                }
            }
        },
    }
}

fn main() {
    let languages = language::all();

    lscpu();

    for problem in fs::readdir(&Path::new("problems")).unwrap().into_iter().filter_map(|dir| {
        Problem::new(dir)
    }) {
        let mut processed = 0u;

        for solution in languages.iter().filter_map(|language| {
            Solution::new(language, &problem)
        }) {
            match Executable::new(&solution) {
                Some(executable) => if executable.validate() == Some(true) {
                    executable.bench();
                    processed += 1;
                },
                None => {},
            }
        }

        if processed > 0 {
            Criterion::default().summarize(problem.id());

            let pid = problem.id();
            let summary_plot =
                Path::new(format!(".criterion/{}/summary/new/violin_plot.svg", pid));
            let plots_dir = Path::new("plots");

            fs::mkdir_recursive(&plots_dir, USER_DIR).ok().
                expect("Couldn't create the plots directory");
            fs::copy(&summary_plot, &plots_dir.join(pid).with_extension("svg")).ok().
                expect("Couldn't copy summary plot to the plots directory");
        }
    }
}
<|endoftext|>


<commit_before>#![windows_subsystem = "windows"]

#[cfg(windows)] extern crate winrt;
#[macro_use]    extern crate error_chain;
extern crate chrono;

#[macro_use] mod util;
mod config;
mod error;
mod feed;
mod math;
mod notify;

use config::Config;
use chrono::{Utc, Timelike};
use feed::Feed;
use feed::statistics::{AverageData, ListenerStats};
use std::time::Duration;
use std::path::PathBuf;

error_chain! {
    links {
        Config(config::Error, config::ErrorKind);
        Feed(feed::Error, feed::ErrorKind);
        Statistics(feed::statistics::Error, feed::statistics::ErrorKind);
        Notify(notify::Error, notify::ErrorKind);
    }

    foreign_links {
        Io(std::io::Error);
    }
}

fn main() {
    #[cfg(windows)]
    let rt = winrt::RuntimeContext::init();

    match start() {
        Ok(_) => (),
        Err(err) => eprintln!("fatal error: {:?}", err),
    }

    #[cfg(windows)]
    rt.uninit();
}

fn start() -> Result<()> {
    let exe_dir = get_exe_directory()?;
    let config_path = exe_dir.clone().join("config.yaml");

    let mut averages = AverageData::new(exe_dir.join("averages.csv"));

    if averages.path.exists() {
        averages.load()?;
    }

    loop {
        let config = Config::from_file(&config_path)?;

        match perform_update(&mut averages, &config) {
            Ok(_) => (),
            Err(err) => error::display(&err),
        }

        std::thread::sleep(Duration::from_secs((config.misc.update_time * 60.0) as u64));
    }
}

fn perform_update(averages: &mut AverageData, config: &Config) -> Result<()> {
    let hour = Utc::now().hour();
    let mut display_feeds = Vec::new();

    for feed in Feed::download_and_scrape(&config)? {
        if feed.listeners < config.misc.minimum_listeners {
            continue
        }

        let stats = update_feed_stats(hour, &feed, &config, averages);

        if cfg!(feature = "print-feed-data") {
            print_info(&feed, &stats);
        }

        if stats.has_spiked || feed.alert.is_some() {
            display_feeds.push((feed, stats.clone()));
        }
    }

    show_feeds(display_feeds)?;

    averages.save()?;
    Ok(())
}

fn update_feed_stats<'a>(hour: u32, feed: &Feed, config: &Config, averages: &'a mut AverageData)
    -> &'a ListenerStats {

    let stats = averages.data
        .entry(feed.id)
        .or_insert(ListenerStats::new());

    stats.update(hour as usize, feed, &config);
    stats
}

fn show_feeds(mut feeds: Vec<(Feed, ListenerStats)>) -> Result<()> {
    feeds.sort_by_key(|&(ref f, _)| f.listeners);

    let total = feeds.len() as i32;

    for (i, (feed, stats)) in feeds.into_iter().enumerate() {
        notify::create_update(1 + i as i32, total, &feed, &stats)?;
    }

    Ok(())
}

fn print_info(feed: &Feed, stats: &ListenerStats) {
    println!("[{}] {}", feed.id, feed.name);
    println!("\tlisteners    | {}", feed.listeners);

    println!("\taverage lis. | cur: {} last: {} samples: {:?}",
        stats.average.current,
        stats.average.last,
        stats.average.data);

    println!("\tunskewed avg | {:?}", stats.unskewed_average);
    println!("\thas spiked   | {}", stats.has_spiked);
    println!("\ttimes spiked | {}", stats.spike_count);
}

fn get_exe_directory() -> Result<PathBuf> {
    let mut path = std::env::current_exe()?;
    path.pop();
    Ok(path)
}<commit_msg>Add back feed sorting<commit_after>#![windows_subsystem = "windows"]

#[cfg(windows)] extern crate winrt;
#[macro_use]    extern crate error_chain;
extern crate chrono;

#[macro_use] mod util;
mod config;
mod error;
mod feed;
mod math;
mod notify;

use config::Config;
use chrono::{Utc, Timelike};
use feed::Feed;
use feed::statistics::{AverageData, ListenerStats};
use std::time::Duration;
use std::path::PathBuf;

error_chain! {
    links {
        Config(config::Error, config::ErrorKind);
        Feed(feed::Error, feed::ErrorKind);
        Statistics(feed::statistics::Error, feed::statistics::ErrorKind);
        Notify(notify::Error, notify::ErrorKind);
    }

    foreign_links {
        Io(std::io::Error);
    }
}

fn main() {
    #[cfg(windows)]
    let rt = winrt::RuntimeContext::init();

    match start() {
        Ok(_) => (),
        Err(err) => eprintln!("fatal error: {:?}", err),
    }

    #[cfg(windows)]
    rt.uninit();
}

fn start() -> Result<()> {
    let exe_dir = get_exe_directory()?;
    let config_path = exe_dir.clone().join("config.yaml");

    let mut averages = AverageData::new(exe_dir.join("averages.csv"));

    if averages.path.exists() {
        averages.load()?;
    }

    loop {
        let config = Config::from_file(&config_path)?;

        match perform_update(&mut averages, &config) {
            Ok(_) => (),
            Err(err) => error::display(&err),
        }

        std::thread::sleep(Duration::from_secs((config.misc.update_time * 60.0) as u64));
    }
}

fn perform_update(averages: &mut AverageData, config: &Config) -> Result<()> {
    let hour = Utc::now().hour();
    let mut display_feeds = Vec::new();

    for feed in Feed::download_and_scrape(&config)? {
        if feed.listeners < config.misc.minimum_listeners {
            continue
        }

        let stats = update_feed_stats(hour, &feed, &config, averages);

        if cfg!(feature = "print-feed-data") {
            print_info(&feed, &stats);
        }

        if stats.has_spiked || feed.alert.is_some() {
            display_feeds.push((feed, stats.clone()));
        }
    }

    show_feeds(display_feeds, &config)?;

    averages.save()?;
    Ok(())
}

fn update_feed_stats<'a>(hour: u32, feed: &Feed, config: &Config, averages: &'a mut AverageData)
    -> &'a ListenerStats {

    let stats = averages.data
        .entry(feed.id)
        .or_insert(ListenerStats::new());

    stats.update(hour as usize, feed, &config);
    stats
}

fn sort_feeds(feeds: &mut Vec<(Feed, ListenerStats)>, config: &Config) {
    use config::SortOrder;

    feeds.sort_unstable_by(|&(ref x, _), &(ref y, _)| {
        match config.misc.sort_order {
            SortOrder::Ascending  => x.listeners.cmp(&y.listeners),
            SortOrder::Descending => y.listeners.cmp(&x.listeners),
        }
    });
}

fn show_feeds(mut feeds: Vec<(Feed, ListenerStats)>, config: &Config) -> Result<()> {
    sort_feeds(&mut feeds, &config);

    let total = feeds.len() as i32;

    for (i, (feed, stats)) in feeds.into_iter().enumerate() {
        notify::create_update(1 + i as i32, total, &feed, &stats)?;
    }

    Ok(())
}

fn print_info(feed: &Feed, stats: &ListenerStats) {
    println!("[{}] {}", feed.id, feed.name);
    println!("\tlisteners    | {}", feed.listeners);

    println!("\taverage lis. | cur: {} last: {} samples: {:?}",
        stats.average.current,
        stats.average.last,
        stats.average.data);

    println!("\tunskewed avg | {:?}", stats.unskewed_average);
    println!("\thas spiked   | {}", stats.has_spiked);
    println!("\ttimes spiked | {}", stats.spike_count);
}

fn get_exe_directory() -> Result<PathBuf> {
    let mut path = std::env::current_exe()?;
    path.pop();
    Ok(path)
}<|endoftext|>


<commit_before>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::interface::*;
use rustwlc::input::{pointer, keyboard};

/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: Some(output_created),
            destroyed: Some(output_destroyed),
            focus: Some(output_focus),
            resolution: Some(output_resolution),

            render: OutputRenderInterface {
                pre: Some(output_render_pre),
                post: Some(output_render_post)
            }
        },
        view: ViewInterface {
            created: Some(view_created),
            destroyed: Some(view_destroyed),
            focus: Some(view_focus),
            move_to_output: Some(view_move_to_output),
            request: RequestInterface {
                geometry: Some(view_request_geometry),
                state: Some(view_request_state),
                move_: Some(view_request_move),
                resize: Some(view_request_resize),
                render: ViewRenderInterface {
                    pre: Some(view_request_render_pre),
                    post: Some(view_request_render_post)
                }
            }
        },
        keyboard: KeyboardInterface {
            key: Some(keyboard_key)
        },
        pointer: PointerInterface {
            button: Some(pointer_button),
            scroll: Some(pointer_scroll),
            motion: Some(pointer_motion)
        },
        touch: TouchInterface {
            touch: Some(touch_touch)
        },
        compositor: CompositorInterface {
            ready: Some(compositor_ready)
        },
        input: InputInterface {
            created: Some(input_created),
            destroyed: Some(input_destroyed)
        }
    };

    rustwlc::log_set_handler(log_callback);

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

extern fn log_callback(log_type: LogType, text: *const libc::c_char) {
    let string_text = rustwlc::pointer_to_string(text);
    println!("Wlc Log {:?}: {}", log_type, string_text);
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    use std::cmp;
    let resolution = output.get_resolution();
    let views = output.get_views();
    println!("Rendering {} views for {} (resolution = {:?})", views.len(), output.get_name(), resolution);

    if views.len() == 0 { println!("Didn't find any views to render :/"); }

    for view in views {
        println!("Setting {:?}", view);
        println!("\tIts type: {}", view.get_type());
        println!("\tIts output: {}", view.get_output().get_name());
        println!("\tIts geometry: {:?}", view.get_geometry());
        println!("\tIts state: {}", view.get_state());
        println!("\tIts parent: {:?}", view.get_parent());
        println!("\tIts title: {}", view.get_title());
        // get_class doesn't work but maybe it's not supposed to
        //println!("\tIts class: {}", view.get_class());
        view.set_geometry(0,
                          &Geometry {
                              size: Size {
                                  w: 200 as u32,
                                  h: 200 as u32
                              },
                              origin: Point {
                                  x: resolution.w as i32,
                                  y: resolution.h as i32
                              }
                          });
        println!("Attempted to set geometry, got {:?}", view.get_geometry());
    }

    /*
    let mut toggle = false;
    let mut y = 0u32;
//    use std::cmp;

    let w: u32 = resolution.w as u32 / 2u32;
    let h: u32 = resolution.h as u32 / cmp::max((1u32 + views.len() as u32) / 2u32, 1);

    for view in views {
        let g = Geometry {
            size: Size {
                w: if toggle { w } else { 0 },
                h: y
            },
            origin: Point {
                x: if !toggle { resolution.w as i32 } else { w as i32 },
                y: h as i32
            }
        };
        view.set_geometry(0, g);
        toggle = !toggle;
        y = y + if !toggle { h } else { 0 };
    }*/
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    println!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created: {:?}", view);
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    render_output(output);
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed: {:?}", view);
    render_output(view.get_output());
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {:?} {}", current, focused);
    current.set_state(ViewState::Activated, focused);
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output: {:?}, {:?}, {:?}", current, q1, q2);
}

extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    println!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(0, geometry);
    render_output(view.get_output());
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    view.set_state(state, handled);
}

extern fn view_request_move(view: WlcView, dest: &Point) {
    //println!("view_request_move: to {}, start interactive mode.", *dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: &Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, *location);
}

extern fn view_request_render_pre(view: WlcView) {
}

extern fn view_request_render_post(view: WlcView) {
}

extern fn keyboard_key(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    use std::process::{Command};
    println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
             time, *mods_ptr, key, state);
    if state == KeyState::Pressed { return false; }
    if key == 67 {
        println!("Preparing to open the terminal...");
        rustwlc::exec("/bin/weston-terminal".to_string(),
                      vec!["/bin/weston-terminal".to_string()]);
    }
    false
}

extern fn pointer_button(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                         key: u32, state: ButtonState, point_ptr: &Point) -> bool {
    println!("pointer_button: pressed {} at {}", key, *point_ptr);
    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point: &Point) {
    pointer::set_position(point);
}

extern fn touch_touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: &LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: &LibinputDevice) {
    println!("input_destroyed");
}
<commit_msg>Removed unnecessary log handler setting. No more unsafe code<commit_after>#![feature(libc)]
extern crate libc;
use std::ffi;

extern crate rustwlc;

use rustwlc::types;
use rustwlc::types::*;
use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::interface::*;
use rustwlc::input::{pointer, keyboard};

/*
struct CompositorAction {
    view: WlcView,
    grab: Point,
    edges: u32
}

static mut compositor: CompositorAction = CompositorAction {
    view: WlcView(0),
    grab: Point{ x: 0, y: 0},
    edges: 0
};
*/
fn main() {
    let interface: WlcInterface = WlcInterface {
        output: OutputInterface {
            created: Some(output_created),
            destroyed: Some(output_destroyed),
            focus: Some(output_focus),
            resolution: Some(output_resolution),

            render: OutputRenderInterface {
                pre: Some(output_render_pre),
                post: Some(output_render_post)
            }
        },
        view: ViewInterface {
            created: Some(view_created),
            destroyed: Some(view_destroyed),
            focus: Some(view_focus),
            move_to_output: Some(view_move_to_output),
            request: RequestInterface {
                geometry: Some(view_request_geometry),
                state: Some(view_request_state),
                move_: Some(view_request_move),
                resize: Some(view_request_resize),
                render: ViewRenderInterface {
                    pre: Some(view_request_render_pre),
                    post: Some(view_request_render_post)
                }
            }
        },
        keyboard: KeyboardInterface {
            key: Some(keyboard_key)
        },
        pointer: PointerInterface {
            button: Some(pointer_button),
            scroll: Some(pointer_scroll),
            motion: Some(pointer_motion)
        },
        touch: TouchInterface {
            touch: Some(touch_touch)
        },
        compositor: CompositorInterface {
            ready: Some(compositor_ready)
        },
        input: InputInterface {
            created: Some(input_created),
            destroyed: Some(input_destroyed)
        }
    };

    if !rustwlc::init(interface) {
        panic!("Unable to initialize wlc!");
    }
    rustwlc::run_wlc();
}

// Important rendering functions copied from wlc/example/example.c

fn start_interactive_action(view: WlcView, origin: Point) -> bool {
    true
}

fn stop_interactive_action() {

}

fn start_interactive_move(view: WlcView, origin: Point) {

}

fn start_interactive_resize(view: WlcView, edges: u32, origin: Point) {

}

fn get_topmost_view(output: WlcOutput, offset: Size) {

}

/// From example.c:
/// very simple layout function
/// you probably don't want to layout certain type of windows in wm
fn render_output(output: WlcOutput) {
    use std::cmp;
    let resolution = output.get_resolution();
    let views = output.get_views();
    println!("Rendering {} views for {} (resolution = {:?})", views.len(), output.get_name(), resolution);

    if views.len() == 0 { println!("Didn't find any views to render :/"); }

    for view in views {
        println!("Setting {:?}", view);
        println!("\tIts type: {}", view.get_type());
        println!("\tIts output: {}", view.get_output().get_name());
        println!("\tIts geometry: {:?}", view.get_geometry());
        println!("\tIts state: {}", view.get_state());
        println!("\tIts parent: {:?}", view.get_parent());
        println!("\tIts title: {}", view.get_title());
        // get_class doesn't work but maybe it's not supposed to
        //println!("\tIts class: {}", view.get_class());
        view.set_geometry(0,
                          &Geometry {
                              size: Size {
                                  w: 200 as u32,
                                  h: 200 as u32
                              },
                              origin: Point {
                                  x: resolution.w as i32,
                                  y: resolution.h as i32
                              }
                          });
        println!("Attempted to set geometry, got {:?}", view.get_geometry());
    }

    /*
    let mut toggle = false;
    let mut y = 0u32;
//    use std::cmp;

    let w: u32 = resolution.w as u32 / 2u32;
    let h: u32 = resolution.h as u32 / cmp::max((1u32 + views.len() as u32) / 2u32, 1);

    for view in views {
        let g = Geometry {
            size: Size {
                w: if toggle { w } else { 0 },
                h: y
            },
            origin: Point {
                x: if !toggle { resolution.w as i32 } else { w as i32 },
                y: h as i32
            }
        };
        view.set_geometry(0, g);
        toggle = !toggle;
        y = y + if !toggle { h } else { 0 };
    }*/
}

// Hook up basic callbacks

extern fn output_created(output: WlcOutput) -> bool {
    println!("output_created: {:?}: {}", output, output.get_name());
    return true;
}

extern fn output_destroyed(output: WlcOutput) {
    println!("output_destroyed");
}

extern fn output_focus(output: WlcOutput, focused: bool) {
    println!("output_focus: {}", focused);
}

extern fn output_resolution(output: WlcOutput,
                            old_size_ptr: &Size, new_size_ptr: &Size) {
    println!("output_resolution: {:?} from  {:?} to {:?}",
             output, *old_size_ptr, *new_size_ptr);
}

extern fn output_render_pre(output: WlcOutput) {
    //println!("output_render_pre");
}

extern fn output_render_post(output: WlcOutput) {
    //println!("output_render_post");
}

extern fn view_created(view: WlcView) -> bool {
    println!("view_created: {:?}", view);
    let output = view.get_output();
    view.set_mask(output.get_mask());
    view.bring_to_front();
    view.focus();
    render_output(output);
    true
}

extern fn view_destroyed(view: WlcView) {
    println!("view_destroyed: {:?}", view);
    render_output(view.get_output());
}

extern fn view_focus(current: WlcView, focused: bool) {
    println!("view_focus: {:?} {}", current, focused);
    current.set_state(ViewState::Activated, focused);
}

extern fn view_move_to_output(current: WlcView, q1: WlcView, q2: WlcView) {
    println!("view_move_to_output: {:?}, {:?}, {:?}", current, q1, q2);
}

extern fn view_request_geometry(view: WlcView, geometry: &Geometry) {
    println!("view_request_geometry: {:?} wants {:?}", view, geometry);
    view.set_geometry(0, geometry);
    render_output(view.get_output());
}

extern fn view_request_state(view: WlcView, state: ViewState, handled: bool) {
    view.set_state(state, handled);
}

extern fn view_request_move(view: WlcView, dest: &Point) {
    //println!("view_request_move: to {}, start interactive mode.", *dest);
}

extern fn view_request_resize(view: WlcView, edge: ResizeEdge, location: &Point) {
    println!("view_request_resize: size {:?}, to {}, start interactive mode.",
             edge, *location);
}

extern fn view_request_render_pre(view: WlcView) {
}

extern fn view_request_render_post(view: WlcView) {
}

extern fn keyboard_key(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
                       key: u32, state: KeyState) -> bool {
    use std::process::{Command};
    println!("keyboard_key: time {}, mods {:?}, key {:?}, state {:?}",
             time, *mods_ptr, key, state);
    if state == KeyState::Pressed { return false; }
    if key == 67 {
        println!("Preparing to open the terminal...");
        rustwlc::exec("/bin/weston-terminal".to_string(),
                      vec!["/bin/weston-terminal".to_string()]);
    }
    false
}

extern fn pointer_button(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                         key: u32, state: ButtonState, point_ptr: &Point) -> bool {
    println!("pointer_button: pressed {} at {}", key, *point_ptr);
    if state == ButtonState::Pressed {
        view.focus();
    }
    false
}

extern fn pointer_scroll(view: WlcView, button: u32, mods_ptr: &KeyboardModifiers,
                  axis: ScrollAxis, heights: [u64; 2]) -> bool {
    println!("pointer_scroll");
    false
}

extern fn pointer_motion(view: WlcView, time: u32, point: &Point) {
    pointer::set_position(point);
}

extern fn touch_touch(view: WlcView, time: u32, mods_ptr: &KeyboardModifiers,
               touch: TouchType, key: i32, point_ptr: &Point) -> bool {
    false
}

extern fn compositor_ready() {
    println!("Preparing compositor!");
}

extern fn input_created(device: &LibinputDevice) -> bool {
    println!("input_created");
    false
}

extern fn input_destroyed(device: &LibinputDevice) {
    println!("input_destroyed");
}
<|endoftext|>


<commit_before>extern crate hyper;

use std::io;
use std::fs::File;
use std::path::Path;

use std::net::{Ipv4Addr, SocketAddrV4};

use hyper::Server;
use hyper::server::Request;
use hyper::server::Response;
use hyper::header::ContentLength;
use hyper::net::Fresh;
use hyper::uri::RequestUri::AbsolutePath;

fn handle_request(req: Request, mut resp: Response<Fresh>) {
    if let AbsolutePath(abs_path) = req.uri {
        if let Ok(file) = File::open(extract_path(&abs_path)) {
            file_response(file, resp).unwrap();
        } else {
            *resp.status_mut() = hyper::NotFound;
            resp.send(b"
Not Found
").unwrap();
        }
    }
}

fn file_response(mut file: File, mut resp: Response<Fresh>) -> io::Result<u64> {
    let metadata = try!(file.metadata());
    resp.headers_mut().set(ContentLength(metadata.len()));
    resp.start().and_then(|mut res| io::copy(&mut file, &mut res))
}

fn extract_path(uri: &String) -> &Path {
    let first_question = uri.find('?').unwrap_or(uri.len());
    let slice = &uri[1 .. first_question];
    Path::new(slice)
}

fn main() {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let port = std::env::args().nth(1).and_then(|p| p.parse::<u16>().ok()).unwrap_or(3000);

    let addr = SocketAddrV4::new(ip, port);

    match Server::http(addr) {
        Ok(server) => {
            println!("Server is listening at http://{}", addr);
            server.handle(handle_request).unwrap();
        },
        Err(error) => {
            panic!("Unable to start server: {}", error);
        }
    }
}
<commit_msg>Better error handling<commit_after>extern crate hyper;

use std::io;
use std::io::Write;
use std::fs::File;
use std::path::Path;

use std::net::{Ipv4Addr, SocketAddrV4};

use hyper::Server;
use hyper::server::Request;
use hyper::server::Response;
use hyper::header::ContentLength;
use hyper::net::Fresh;
use hyper::uri::RequestUri::AbsolutePath;

macro_rules! println_err {
    ($fmt: expr, $($arg:tt)*) => {
        match writeln!(&mut std::io::stderr(), $fmt,  $($arg)*) {
            Ok(_) => {},
            Err(_) => {}
        }
    };
}

macro_rules! try_return {
    ($e: expr) => {{
        match $e {
            Ok(v) => v,
            Err(e) => {
                println_err!("Error: {}", e);
                return;
            }
        }
    }}
}

fn handle_request(req: Request, mut resp: Response<Fresh>) {
    if let AbsolutePath(abs_path) = req.uri {
        if let Ok(file) = File::open(extract_path(&abs_path)) {
            try_return!(file_response(file, resp));
        } else {
            *resp.status_mut() = hyper::NotFound;
            try_return!(resp.send(b"
Not Found
"));
        }
    }
}

fn file_response(mut file: File, mut resp: Response<Fresh>) -> io::Result<u64> {
    let metadata = try!(file.metadata());
    resp.headers_mut().set(ContentLength(metadata.len()));
    resp.start().and_then(|mut res| io::copy(&mut file, &mut res))
}

fn extract_path(uri: &String) -> &Path {
    let first_question = uri.find('?').unwrap_or(uri.len());
    let slice = &uri[1 .. first_question];
    Path::new(slice)
}

fn main() {
    let ip = Ipv4Addr::new(127, 0, 0, 1);
    let port = std::env::args().nth(1).and_then(|p| p.parse::<u16>().ok()).unwrap_or(3000);

    let addr = SocketAddrV4::new(ip, port);

    match Server::http(addr) {
        Ok(server) => {
            println!("Server is listening at http://{}", addr);
            server.handle(handle_request).unwrap();
        },
        Err(error) => {
            println_err!("Unable to start server: {}", error);
            std::process::exit(1);
        }
    }
}
<|endoftext|>