<commit_before>// Copyright 2013 The rust-glib authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::libc;

pub type gchar = libc::c_char;
pub type gshort = libc::c_short;
pub type glong = libc::c_long;
pub type gint = libc::c_int;
pub type gboolean = gint;

pub type guchar = libc::c_uchar;
pub type gushort = libc::c_ushort;
pub type gulong = libc::c_ulong;
pub type guint = libc::c_uint;

pub type gfloat = libc::c_float;
pub type gdouble = libc::c_double;
<commit_msg>Add `gpointer` and `gconstpointer`<commit_after>// Copyright 2013 The rust-glib authors.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::libc;

pub type gchar = libc::c_char;
pub type gshort = libc::c_short;
pub type glong = libc::c_long;
pub type gint = libc::c_int;
pub type gboolean = gint;

pub type guchar = libc::c_uchar;
pub type gushort = libc::c_ushort;
pub type gulong = libc::c_ulong;
pub type guint = libc::c_uint;

pub type gfloat = libc::c_float;
pub type gdouble = libc::c_double;

pub type gpointer = *mut libc::c_void;
pub type gconstpointer = *libc::c_void;
<|endoftext|>


<commit_before>mod terminal;
mod ansi;

use std::io::{self, Write};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, cursor, style};
use rff::choice::Choice;

#[derive(Debug)]
pub enum Error {
    CtrlC,
    Write(io::Error),
    Reset(terminal::Error)
}

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

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    selected: usize,
    search: String,
    terminal: Terminal
}

impl Interface {
    /// Creates a new Interface with the provided input choices.
    pub fn with_choices(choices: Vec<String>) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: choices,
            matching: Vec::new(),
            selected: 0,
            search: String::new(),
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_choices();
        self.render()?;

        for event in self.terminal.events()? {
            match event? {
                Event::Key(Key::Ctrl('c')) => {
                    self.clear()?;
                    return Err(Error::CtrlC);
                },

                Event::Key(Key::Char('\n')) => {
                    break;
                },

                Event::Key(Key::Ctrl('n')) => {
                    self.selected += 1;
                    self.clamp_selected();
                    self.render()?;
                },

                Event::Key(Key::Ctrl('p')) => {
                    self.selected = self.selected.
                        checked_sub(1).
                        unwrap_or(0);

                    self.clamp_selected();
                    self.render()?;
                },

                Event::Key(Key::Char(ch)) => {
                    self.search.push(ch);
                    self.filter_choices();
                    self.render()?;
                },

                Event::Key(Key::Backspace) => {
                    self.search.pop();
                    self.filter_choices();
                    self.render()?;
                },

                _ => {}
            };
        }

        self.clear()?;
        Ok(self.result())
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            iter().
            cloned().
            filter_map(|choice| Choice::new(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        write!(self.terminal, "{}{}", clear::Screen, cursor::Column(1))?;
        write!(self.terminal, "> {}", self.search)?;

        let n = self.render_choices()?;

        if n > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(self.terminal, "{}{}", cursor::Up(n), cursor::Column(column + 1))?;
        }

        Ok(())
    }

    fn render_choices(&mut self) -> io::Result<u16> {
        let max_width = self.terminal.max_width as usize;

        let choices = self.matching.
            iter().
            map(|c| c.text()).
            map(|c| {
                c.chars().take(max_width).collect::<String>()
            }).take(10);

        let number_of_choices = choices.len() as u16;

        for (i, choice) in choices.enumerate() {
            write!(self.terminal, "\r\n")?;

            if i == self.selected {
                let invert = style::Invert;
                let reset = style::NoInvert;
                write!(self.terminal, "{}{}{}", invert, choice, reset)?;
            } else {
                write!(self.terminal, "{}", choice)?;
            }
        }

        Ok(number_of_choices)
    }

    #[inline(always)]
    fn clamp_selected(&mut self) {
        let mut max = self.matching.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = max - 1;
        }
    }

    fn clear(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matching.iter().
            map(|c| c.text()).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<commit_msg>Simplify matching of key events<commit_after>mod terminal;
mod ansi;

use std::io::{self, Write};
use self::terminal::{Terminal, Event, Key};
use self::ansi::{clear, cursor, style};
use rff::choice::Choice;

#[derive(Debug)]
pub enum Error {
    CtrlC,
    Write(io::Error),
    Reset(terminal::Error)
}

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

impl From<terminal::Error> for Error {
    fn from(err: terminal::Error) -> Error {
        Error::Reset(err)
    }
}

pub struct Interface {
    choices: Vec<String>,
    matching: Vec<Choice>,
    selected: usize,
    search: String,
    terminal: Terminal
}

impl Interface {
    /// Creates a new Interface with the provided input choices.
    pub fn with_choices(choices: Vec<String>) -> Interface {
        let mut term = Terminal::from("/dev/tty").unwrap();
        term.set_raw_mode().unwrap();

        Interface {
            choices: choices,
            matching: Vec::new(),
            selected: 0,
            search: String::new(),
            terminal: term
        }
    }

    // Starts the interface
    pub fn run(&mut self) -> Result<&str, Error> {
        self.filter_choices();
        self.render()?;

        for event in self.terminal.events()? {
            if let Event::Key(key) = event? {
                match key {
                    Key::Ctrl('c') => {
                        self.clear()?;
                        return Err(Error::CtrlC);
                    }

                    Key::Char('\n') => {
                        break;
                    },

                    Key::Ctrl('n') => {
                        self.selected += 1;
                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Ctrl('p') => {
                        self.selected = self.selected.
                            checked_sub(1).
                            unwrap_or(0);

                        self.clamp_selected();
                        self.render()?;
                    },

                    Key::Char(ch) => {
                        self.search.push(ch);
                        self.filter_choices();
                        self.render()?;
                    },

                    Key::Backspace => {
                        self.search.pop();
                        self.filter_choices();
                        self.render()?;
                    }

                    _ => {}
                }
            };
        }

        self.clear()?;
        Ok(self.result())
    }

    fn filter_choices(&mut self) {
        let mut matches = self.choices.
            iter().
            cloned().
            filter_map(|choice| Choice::new(&self.search, choice)).
            collect::<Vec<_>>();

        matches.sort_by(|a, b| b.partial_cmp(a).unwrap());

        self.matching = matches;
    }

    fn render(&mut self) -> io::Result<()> {
        write!(self.terminal, "{}{}", clear::Screen, cursor::Column(1))?;
        write!(self.terminal, "> {}", self.search)?;

        let n = self.render_choices()?;

        if n > 0 {
            let column = format!("> {}", self.search).len() as u16;
            write!(self.terminal, "{}{}", cursor::Up(n), cursor::Column(column + 1))?;
        }

        Ok(())
    }

    fn render_choices(&mut self) -> io::Result<u16> {
        let max_width = self.terminal.max_width as usize;

        let choices = self.matching.
            iter().
            map(|c| c.text()).
            map(|c| {
                c.chars().take(max_width).collect::<String>()
            }).take(10);

        let number_of_choices = choices.len() as u16;

        for (i, choice) in choices.enumerate() {
            write!(self.terminal, "\r\n")?;

            if i == self.selected {
                let invert = style::Invert;
                let reset = style::NoInvert;
                write!(self.terminal, "{}{}{}", invert, choice, reset)?;
            } else {
                write!(self.terminal, "{}", choice)?;
            }
        }

        Ok(number_of_choices)
    }

    #[inline(always)]
    fn clamp_selected(&mut self) {
        let mut max = self.matching.len();
        if max > 10 { max = 10; }

        if self.selected >= max {
            self.selected = max - 1;
        }
    }

    fn clear(&mut self) -> Result<(), Error> {
        write!(self.terminal, "{}{}", cursor::Column(1), clear::Screen)?;
        self.terminal.reset()?;
        Ok(())
    }

    fn result(&mut self) -> &str {
        self.matching.iter().
            map(|c| c.text()).
            nth(self.selected).
            unwrap_or(&self.search)
    }
}
<|endoftext|>


<commit_before>pub fn of(haystack: &str, needle: &str) -> uint {
    let mut counter = 0;

    let mut haystack_vec = Vec::new();
    let mut needle_vec = Vec::new();

    let needlen = needle.len();
    let mut temp_str = "".to_string();

    for x in haystack.chars() {
        haystack_vec.push(x);
    }

    // New
    for x in needle.chars() {
        needle_vec.push(x);
    }

    let haystack_vec_len = haystack_vec.len() - 1;

    // New
    for x in range(0, haystack_vec_len) {
        // Check if the first letter of the needle is the same as the current haystack letter
        // we fast now
        if needle_vec[0] == haystack_vec[x] {
            for y in range(0, needlen) {
                temp_str.push(haystack_vec[x + y]);
            }

            if needle == temp_str {
                break;
            }
        }

        counter += 1;
        temp_str = "".to_string();
    }

    return counter
}
<commit_msg>Removed more unnecessary stuff and fixed who commited this shit<commit_after>pub fn of(haystack: &str, needle: &str) -> uint {
    let mut counter = 0;

    let mut haystack_vec = Vec::new();
    let mut needle_vec = Vec::new();

    let needlen = needle.len();
    let mut temp_str = "".to_string();

    for x in haystack.chars() {
        haystack_vec.push(x);
    }

    for x in needle.chars() {
        needle_vec.push(x);
    }

    let haystack_vec_len = haystack_vec.len() - 1;

    for x in range(0, haystack_vec_len) {
        // Check if the first letter of the needle is the same as the current haystack letter
        // we fast now
        if needle_vec[0] == haystack_vec[x] {
            for y in range(0, needlen) {
                temp_str.push(haystack_vec[x + y]);
            }

            if needle == temp_str {
                break;
            }
        }

        counter += 1;
        temp_str = "".to_string();
    }

    return counter
}
<|endoftext|>


<commit_before>//! The module contains the implementation of HTTP/2 frames.
<commit_msg>Implement unpacking HTTP/2 frame headers<commit_after>//! The module contains the implementation of HTTP/2 frames.

/// An alias for the 9-byte buffer that each HTTP/2 frame header must be stored
/// in.
type FrameHeaderBuffer = [u8; 9];
/// An alias for the 4-tuple representing the components of each HTTP/2 frame
/// header.
type FrameHeader = (u32, u8, u8, u32);

/// Deconstructs a `FrameHeader` into its corresponding 4 components,
/// represented as a 4-tuple: `(length, frame_type, flags, stream_id)`.
///
/// The frame `type` and `flags` components are returned as their original
/// octet representation, rather than reinterpreted.
fn unpack_header(header: &FrameHeaderBuffer) -> FrameHeader {
    let length: u32 = (
        ((header[0] as u32) << 16) |
        ((header[1] as u32) <<  8) |
        ((header[2] as u32) <<  0));
    let frame_type = header[3];
    let flags = header[4];
    let stream_id: u32 = (
        ((header[5] as u32) << 24) |
        ((header[6] as u32) << 16) |
        ((header[7] as u32) <<  8) |
        ((header[8] as u32) <<  0));

    (length, frame_type, flags, stream_id)
}

#[cfg(test)]
mod tests {
    use super::{
        unpack_header,
    };

    /// Tests that the `unpack_header` function correctly returns the
    /// components of HTTP/2 frame headers.
    #[test]
    fn test_unpack_header() {
        {
            let header = [0; 9];
            assert_eq!((0, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 2, 3, 0, 0, 0, 4];
            assert_eq!((1, 2, 3, 4), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 200, 100, 0, 0, 0, 4];
            assert_eq!((1, 200, 100, 4), unpack_header(&header));
        }
        {
            let header = [0, 0, 1, 0, 0, 0, 0, 0, 0];
            assert_eq!((1, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 1, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!((256, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [1, 0, 0, 0, 0, 0, 0, 0, 0];
            assert_eq!((256 * 256, 0, 0, 0), unpack_header(&header));
        }
        {
            let header = [0, 0, 0, 0, 0, 0, 0, 0, 1];
            assert_eq!((0, 0, 0, 1), unpack_header(&header));
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 0, 0, 0, 1];
            assert_eq!(((1 << 24) - 1, 0, 0, 1), unpack_header(&header));
        }
        {
            let header = [0xFF, 0xFF, 0xFF, 0, 0, 1, 1, 1, 1];
            assert_eq!(
                ((1 << 24) - 1, 0, 0, 1 + (1 << 8) + (1 << 16) + (1 << 24)),
                unpack_header(&header));
        }
    }
}
<|endoftext|>


<commit_before>use self::hyper::http::h1::Incoming;
use self::hyper::method::Method;
use self::hyper::uri::RequestUri;
use self::hyper::uri::RequestUri::AbsolutePath;
use super::hyper;

use futures::future::Future;
use std::fs::File;
use std::rc::Rc;

use options::StaticFile;
use trivial_peer::get_literal_peer_now;
use Peer;

use my_copy::{copy, CopyOptions};

const BAD_REQUEST :&[u8] = b"HTTP/1.1 400 Bad Reqeust\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nOnly WebSocket connections are welcome here\n";

const NOT_FOUND: &[u8] = b"HTTP/1.1 404 Not Found\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nURI does not match any -F option and is not a WebSocket connection.\n";

const NOT_FOUND2: &[u8] = b"HTTP/1.1 500 Not Found\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nFailed to open the file on server side.\n";

const BAD_METHOD :&[u8] = b"HTTP/1.1 400 Bad Reqeust\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nHTTP method should be GET\n";

const BAD_URI_FORMAT :&[u8] = b"HTTP/1.1 400 Bad Reqeust\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nURI should be an absolute path\n";

fn get_static_file_reply(len: Option<u64>, ct: &str) -> Vec<u8> {
    let mut q = Vec::with_capacity(256);
    q.extend_from_slice(b"HTTP/1.1 200 OK\r\nServer: websocat\r\nContent-Type: ");
    q.extend_from_slice(ct.as_bytes());
    q.extend_from_slice(b"\r\n");
    if let Some(x) = len {
        q.extend_from_slice(b"Content-Length: ");
        q.extend_from_slice(format!("{}", x).as_bytes());
        q.extend_from_slice(b"\r\n");
    }
    q.extend_from_slice(b"\r\n");
    q
}

#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
pub fn http_serve(
    p: Peer,
    incoming: Option<Incoming<(Method, RequestUri)>>,
    serve_static_files: Rc<Vec<StaticFile>>,
) -> Box<Future<Item = (), Error = ()>> {
    let mut serve_file = None;
    let content = if serve_static_files.is_empty() {
        BAD_REQUEST.to_vec()
    } else if let Some(inc) = incoming {
        info!("HTTP-serving {:?}", inc.subject);
        if inc.subject.0 == Method::Get {
            match inc.subject.1 {
                AbsolutePath(x) => {
                    let mut reply = None;
                    for sf in &*serve_static_files {
                        if sf.uri == x {
                            match File::open(&sf.file) {
                                Ok(f) => {
                                    let fs = match f.metadata() {
                                        Err(_) => None,
                                        Ok(x) => Some(x.len()),
                                    };
                                    reply = Some(get_static_file_reply(fs, &sf.content_type));
                                    serve_file = Some(f);
                                }
                                Err(_) => {
                                    reply = Some(NOT_FOUND2.to_vec());
                                }
                            }
                        }
                    }
                    reply.unwrap_or_else(|| NOT_FOUND.to_vec())
                }
                _ => BAD_URI_FORMAT.to_vec(),
            }
        } else {
            BAD_METHOD.to_vec()
        }
    } else {
        BAD_REQUEST.to_vec()
    };
    let reply = get_literal_peer_now(content);

    let co = CopyOptions {
        buffer_size: 1024,
        once: false,
        stop_on_reader_zero_read: true,
    };

    if let Some(f) = serve_file {
        Box::new(
            copy(reply, p.1, co)
                .map_err(drop)
                .and_then(move |(_len, _, conn)| {
                    let co2 = CopyOptions {
                        buffer_size: 65536,
                        once: false,
                        stop_on_reader_zero_read: true,
                    };
                    let wr = ::file_peer::ReadFileWrapper(f);
                    copy(wr, conn, co2).map(|_| ()).map_err(drop)
                }),
        )
    } else {
        Box::new(copy(reply, p.1, co).map(|_| ()).map_err(drop))
    }
}
<commit_msg>Typo fix: Reqeust -> Request<commit_after>use self::hyper::http::h1::Incoming;
use self::hyper::method::Method;
use self::hyper::uri::RequestUri;
use self::hyper::uri::RequestUri::AbsolutePath;
use super::hyper;

use futures::future::Future;
use std::fs::File;
use std::rc::Rc;

use options::StaticFile;
use trivial_peer::get_literal_peer_now;
use Peer;

use my_copy::{copy, CopyOptions};

const BAD_REQUEST :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nOnly WebSocket connections are welcome here\n";

const NOT_FOUND: &[u8] = b"HTTP/1.1 404 Not Found\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nURI does not match any -F option and is not a WebSocket connection.\n";

const NOT_FOUND2: &[u8] = b"HTTP/1.1 500 Not Found\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nFailed to open the file on server side.\n";

const BAD_METHOD :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nHTTP method should be GET\n";

const BAD_URI_FORMAT :&[u8] = b"HTTP/1.1 400 Bad Request\r\nServer: websocat\r\nContent-Type: text/plain\r\nConnection: close\r\n\r\nURI should be an absolute path\n";

fn get_static_file_reply(len: Option<u64>, ct: &str) -> Vec<u8> {
    let mut q = Vec::with_capacity(256);
    q.extend_from_slice(b"HTTP/1.1 200 OK\r\nServer: websocat\r\nContent-Type: ");
    q.extend_from_slice(ct.as_bytes());
    q.extend_from_slice(b"\r\n");
    if let Some(x) = len {
        q.extend_from_slice(b"Content-Length: ");
        q.extend_from_slice(format!("{}", x).as_bytes());
        q.extend_from_slice(b"\r\n");
    }
    q.extend_from_slice(b"\r\n");
    q
}

#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
pub fn http_serve(
    p: Peer,
    incoming: Option<Incoming<(Method, RequestUri)>>,
    serve_static_files: Rc<Vec<StaticFile>>,
) -> Box<Future<Item = (), Error = ()>> {
    let mut serve_file = None;
    let content = if serve_static_files.is_empty() {
        BAD_REQUEST.to_vec()
    } else if let Some(inc) = incoming {
        info!("HTTP-serving {:?}", inc.subject);
        if inc.subject.0 == Method::Get {
            match inc.subject.1 {
                AbsolutePath(x) => {
                    let mut reply = None;
                    for sf in &*serve_static_files {
                        if sf.uri == x {
                            match File::open(&sf.file) {
                                Ok(f) => {
                                    let fs = match f.metadata() {
                                        Err(_) => None,
                                        Ok(x) => Some(x.len()),
                                    };
                                    reply = Some(get_static_file_reply(fs, &sf.content_type));
                                    serve_file = Some(f);
                                }
                                Err(_) => {
                                    reply = Some(NOT_FOUND2.to_vec());
                                }
                            }
                        }
                    }
                    reply.unwrap_or_else(|| NOT_FOUND.to_vec())
                }
                _ => BAD_URI_FORMAT.to_vec(),
            }
        } else {
            BAD_METHOD.to_vec()
        }
    } else {
        BAD_REQUEST.to_vec()
    };
    let reply = get_literal_peer_now(content);

    let co = CopyOptions {
        buffer_size: 1024,
        once: false,
        stop_on_reader_zero_read: true,
    };

    if let Some(f) = serve_file {
        Box::new(
            copy(reply, p.1, co)
                .map_err(drop)
                .and_then(move |(_len, _, conn)| {
                    let co2 = CopyOptions {
                        buffer_size: 65536,
                        once: false,
                        stop_on_reader_zero_read: true,
                    };
                    let wr = ::file_peer::ReadFileWrapper(f);
                    copy(wr, conn, co2).map(|_| ()).map_err(drop)
                }),
        )
    } else {
        Box::new(copy(reply, p.1, co).map(|_| ()).map_err(drop))
    }
}
<|endoftext|>


<commit_before>use super::geom::*;

use std::sync::{Arc, Mutex};

use gfx;
use gfx::texture;
use gfx::traits::{Factory, FactoryExt};
use gfx::{Encoder, IntoIndexBuffer, PipelineState, Slice};
use gfx::memory::{Bind, Usage};
use gfx::buffer::Role;
use gfx::handle::{Buffer, DepthStencilView, RenderTargetView, Sampler, ShaderResourceView};
use gfx_text;
use gfx_device_gl as gl;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

gfx_defines! {
    vertex Vertex {
        pos: [f32; 2] = "a_Pos",
    }

    vertex ColoredRect {
        translate: [f32; 3] = "a_Translate",
        scale: [f32; 2] = "a_Scale",
        color: [f32; 3] = "a_Color",
    }

    pipeline rect_pipe {
        resolution: gfx::Global<[f32; 2]> = "i_Resolution",
        vertices: gfx::VertexBuffer<Vertex> = (),
        instances: gfx::InstanceBuffer<ColoredRect> = (),
        out: gfx::BlendTarget<ColorFormat> = ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
        depth: gfx::DepthTarget<DepthFormat> = gfx::state::Depth {
            fun: gfx::state::Comparison::LessEqual,
            write: true,
        },
    }

    vertex TexturedVertex {
        translate: [f32; 3] = "a_Translate",
        tex_coord: [f32; 2] = "a_TexCoord",
    }

    pipeline textured_rect_pipe {
        resolution: gfx::Global<[f32; 2]> = "i_Resolution",
        texture: gfx::TextureSampler<[f32; 4]> = "i_Texture",
        vertices: gfx::VertexBuffer<TexturedVertex> = (),
        out: gfx::BlendTarget<ColorFormat> = ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
        depth: gfx::DepthTarget<DepthFormat> = gfx::state::Depth {
            fun: gfx::state::Comparison::LessEqual,
            write: true,
        },
    }
}
pub struct Target {
    pub color: RenderTargetView<gl::Resources, ColorFormat>,
    pub depth: DepthStencilView<gl::Resources, DepthFormat>,
}

fn rect(x: f32, y: f32, w: f32, h: f32) -> [Vertex; 4] {
    [
        Vertex { pos: [x, y] },
        Vertex { pos: [x, y + h] },
        Vertex {
            pos: [x + w, y + h],
        },
        Vertex { pos: [x + w, y] },
    ]
}

const RECT_IDX: [u16; 6] = [0, 1, 2, 0, 2, 3];

#[derive(Clone)]
struct RectRenderer {
    factory: gl::Factory,
    pso: PipelineState<gl::Resources, rect_pipe::Meta>,
    slice: Slice<gl::Resources>,
    vertex_buffer: Buffer<gl::Resources, Vertex>,
    rects: Vec<ColoredRect>,
}
impl RectRenderer {
    fn new(mut factory: gl::Factory) -> RectRenderer {
        let pso = factory
            .create_pipeline_simple(
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/shaders/rect_150.glslv"
                )),
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/shaders/rect_150.glslf"
                )),
                rect_pipe::new(),
            )
            .unwrap();
        let vertex_buffer = factory
            .create_buffer_immutable(&rect(0.0, 0.0, 1.0, 1.0), Role::Vertex, Bind::empty())
            .unwrap();
        let index_buffer = RECT_IDX[..].into_index_buffer(&mut factory);
        let buffer_length = match index_buffer {
            gfx::IndexBuffer::Auto => vertex_buffer.len(),
            gfx::IndexBuffer::Index16(ref ib) => ib.len(),
            gfx::IndexBuffer::Index32(ref ib) => ib.len(),
        };
        let slice = Slice {
            start: 0,
            end: buffer_length as u32,
            base_vertex: 0,
            instances: Some((0, 0)),
            buffer: index_buffer,
        };
        RectRenderer {
            factory,
            pso,
            slice,
            vertex_buffer,
            rects: Vec::new(),
        }
    }
    fn push(&mut self, rect: ColoredRect) {
        self.rects.push(rect);
    }
    fn draw(&mut self, encoder: &mut Encoder<gl::Resources, gl::CommandBuffer>, target: &Target) {
        let instance_buffer = self.factory
            .create_buffer_immutable(&self.rects, Role::Vertex, Bind::empty())
            .unwrap();
        let data = rect_pipe::Data {
            resolution: target_dimensions(target),
            vertices: self.vertex_buffer.clone(),
            instances: instance_buffer,
            out: target.color.clone(),
            depth: target.depth.clone(),
        };
        self.slice.instances = Some((self.rects.len() as u32, 0));
        encoder.draw(&self.slice, &self.pso, &data);
        self.rects.clear();
    }
}

#[derive(Clone)]
struct TexturedRectRenderer {
    factory: gl::Factory,
    pso: PipelineState<gl::Resources, textured_rect_pipe::Meta>,
    sampler: Sampler<gl::Resources>,
    rects: Vec<(Rect3, ShaderResourceView<gl::Resources, [f32; 4]>)>,
}

impl TexturedRectRenderer {
    fn new(mut factory: gl::Factory) -> TexturedRectRenderer {
        let pso = factory
            .create_pipeline_simple(
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/shaders/textured_rect_150.glslv"
                )),
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/shaders/textured_rect_150.glslf"
                )),
                textured_rect_pipe::new(),
            )
            .unwrap();
        let sampler = factory.create_sampler_linear();
        TexturedRectRenderer {
            factory,
            pso,
            sampler,
            rects: Vec::new(),
        }
    }
    fn push(&mut self, rect: Rect3, texture: ShaderResourceView<gl::Resources, [f32; 4]>) {
        self.rects.push((rect, texture));
    }
    fn draw(&mut self, encoder: &mut Encoder<gl::Resources, gl::CommandBuffer>, target: &Target) {
        for (rect, texture) in self.rects.drain(..) {
            let vertices = [
                TexturedVertex {
                    translate: rect.pos.into(),
                    tex_coord: [0.0, 1.0],
                },
                TexturedVertex {
                    translate: (rect.pos + Pt3::new(0.0, rect.size.y, 0.0)).into(),
                    tex_coord: [0.0, 0.0],
                },
                TexturedVertex {
                    translate: (rect.pos + Pt3::new(rect.size.x, rect.size.y, 0.0)).into(),
                    tex_coord: [1.0, 0.0],
                },
                TexturedVertex {
                    translate: (rect.pos + Pt3::new(rect.size.x, 0.0, 0.0)).into(),
                    tex_coord: [1.0, 1.0],
                },
            ];
            let (vertex_buffer, slice) = self.factory
                .create_vertex_buffer_with_slice(&vertices, &RECT_IDX[..]);
            let data = textured_rect_pipe::Data {
                resolution: target_dimensions(target),
                texture: (texture, self.sampler.clone()),
                vertices: vertex_buffer,
                out: target.color.clone(),
                depth: target.depth.clone(),
            };
            encoder.draw(&slice, &self.pso, &data);
        }
    }
}

#[derive(Clone)]
struct TextRenderer {
    renderer: Arc<Mutex<gfx_text::Renderer<gl::Resources, gl::Factory>>>,
    texts: Vec<(String, [f32; 2], [f32; 3])>,
}
impl TextRenderer {
    fn new(factory: gl::Factory) -> TextRenderer {
        let renderer = Arc::new(Mutex::new(gfx_text::new(factory.clone()).unwrap()));
        TextRenderer {
            renderer,
            texts: Vec::new(),
        }
    }
    fn push(&mut self, text: &str, pos: [f32; 2], color: [f32; 3]) {
        self.texts.push((text.into(), pos, color));
    }
    fn draw(&mut self, encoder: &mut Encoder<gl::Resources, gl::CommandBuffer>, target: &Target) {
        let mut renderer = self.renderer.lock().unwrap();
        for (text, pos, color) in self.texts.drain(..) {
            renderer.add(
                &text,
                [pos[0] as i32, pos[1] as i32],
                [color[0], color[1], color[2], 1.0],
            );
        }
        renderer.draw(encoder, &target.color).unwrap();
    }
}

pub struct DepthRange {
    pub near: f32,
    pub far: f32,
}

pub struct RenderContext {
    factory: gl::Factory,
    encoder: Encoder<gl::Resources, gl::CommandBuffer>,
    rects: RectRenderer,
    textured_rects: TexturedRectRenderer,
    texts: TextRenderer,
}
impl RenderContext {
    pub fn new(mut factory: gl::Factory) -> RenderContext {
        let encoder = factory.create_command_buffer().into();
        let rects = RectRenderer::new(factory.clone());
        let textured_rects = TexturedRectRenderer::new(factory.clone());
        let texts = TextRenderer::new(factory.clone());

        RenderContext {
            factory,
            encoder,
            rects,
            textured_rects,
            texts,
        }
    }
    pub fn begin_frame(&mut self, target: &Target) {
        self.encoder.clear(&target.color, [0.0; 4]);
        self.encoder.clear_depth(&target.depth, 1.0);
    }
    pub fn draw_text(&mut self, text: &str, pos: Pt3, color: [f32; 3]) {
        // for now we are discarding z because gfx_text can't handle it
        // TODO write better text renderer
        self.texts.push(text, [pos.x, pos.y], color);
    }
    pub fn draw_rect(&mut self, rect: Rect3, color: [f32; 3]) {
        self.rects.push(ColoredRect {
            translate: rect.pos.into(),
            scale: rect.size.into(),
            color,
        });
    }
    pub fn draw_textured_rect(&mut self, rect: Rect3, texture: ShaderResourceView<gl::Resources, [f32; 4]>) {
        self.textured_rects.push(rect, texture);
    }
    pub fn factory(&self) -> &gl::Factory {
        &self.factory
    }
    pub fn end_frame(&mut self, device: &mut gl::Device, target: &Target) {
        self.rects.draw(&mut self.encoder, target);
        self.textured_rects.draw(&mut self.encoder, target);
        self.texts.draw(&mut self.encoder, target);
        self.encoder.flush(device);
    }
}

impl Clone for RenderContext {
    fn clone(&self) -> RenderContext {
        let mut factory = self.factory.clone();
        let encoder = factory.create_command_buffer().into();
        RenderContext {
            factory: factory,
            encoder: encoder,
            rects: self.rects.clone(),
            textured_rects: self.textured_rects.clone(),
            texts: self.texts.clone(),
        }
    }
}

pub struct TextureTarget {
    ctx: RenderContext,
    //target_texture: Texture<gl::Resources, gfx::format::R8_G8_B8_A8>,
    //depth_texture: Texture<gl::Resources, gfx::format::D24_S8>,
    target_resource: ShaderResourceView<gl::Resources, [f32; 4]>,
    target: Target,
    size: Pt2,
}

impl TextureTarget {
    pub fn new(ctx: RenderContext, size: Pt2) -> TextureTarget {
        let mut factory = ctx.factory().clone();
        let target_texture = factory
            .create_texture(
                texture::Kind::D2(size.x as u16, size.y as u16, texture::AaMode::Single),
                1, //levels
                Bind::RENDER_TARGET | Bind::SHADER_RESOURCE,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let color_target = factory
            .view_texture_as_render_target(
                &target_texture,
                0,    //level
                None, //layer
            )
            .unwrap();
        let target_resource = factory
            .view_texture_as_shader_resource::<gfx::format::Rgba8>(
                &target_texture,
                (0, 0), // levels
                gfx::format::Swizzle::new(),
            )
            .unwrap();
        let depth_texture = factory
            .create_texture(
                texture::Kind::D2(size.x as u16, size.y as u16, texture::AaMode::Single),
                1, //levels
                Bind::DEPTH_STENCIL,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let depth_target = factory
            .view_texture_as_depth_stencil(
                &depth_texture,
                0,    //level
                None, //layer
                texture::DepthStencilFlags::empty(),
            )
            .unwrap();
        let target = Target {
            color: color_target,
            depth: depth_target,
        };
        TextureTarget {
            ctx,
            target_resource,
            target,
            size,
        }
    }
    pub fn ctx(&mut self) -> &mut RenderContext {
        &mut self.ctx
    }
    pub fn target(&self) -> &Target {
        &self.target
    }
    pub fn shader_resource(&self) -> &ShaderResourceView<gl::Resources, [f32; 4]> {
        &self.target_resource
    }
    pub fn begin_frame(&mut self) {
        self.ctx.begin_frame(&self.target);
    }
    pub fn end_frame(&mut self, device: &mut gl::Device) {
        self.ctx.end_frame(device, &self.target);
    }
    pub fn size(&self) -> Pt2 {
        self.size
    }
}

fn target_dimensions(target: &Target) -> [f32; 2] {
    let dims = target.color.get_dimensions();
    [dims.0 as f32, dims.1 as f32]
}
<commit_msg>assert texture size won't overflow<commit_after>use super::geom::*;

use std::sync::{Arc, Mutex};

use gfx;
use gfx::texture;
use gfx::traits::{Factory, FactoryExt};
use gfx::{Encoder, IntoIndexBuffer, PipelineState, Slice};
use gfx::memory::{Bind, Usage};
use gfx::buffer::Role;
use gfx::handle::{Buffer, DepthStencilView, RenderTargetView, Sampler, ShaderResourceView};
use gfx_text;
use gfx_device_gl as gl;

pub type ColorFormat = gfx::format::Rgba8;
pub type DepthFormat = gfx::format::DepthStencil;

gfx_defines! {
    vertex Vertex {
        pos: [f32; 2] = "a_Pos",
    }

    vertex ColoredRect {
        translate: [f32; 3] = "a_Translate",
        scale: [f32; 2] = "a_Scale",
        color: [f32; 3] = "a_Color",
    }

    pipeline rect_pipe {
        resolution: gfx::Global<[f32; 2]> = "i_Resolution",
        vertices: gfx::VertexBuffer<Vertex> = (),
        instances: gfx::InstanceBuffer<ColoredRect> = (),
        out: gfx::BlendTarget<ColorFormat> = ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
        depth: gfx::DepthTarget<DepthFormat> = gfx::state::Depth {
            fun: gfx::state::Comparison::LessEqual,
            write: true,
        },
    }

    vertex TexturedVertex {
        translate: [f32; 3] = "a_Translate",
        tex_coord: [f32; 2] = "a_TexCoord",
    }

    pipeline textured_rect_pipe {
        resolution: gfx::Global<[f32; 2]> = "i_Resolution",
        texture: gfx::TextureSampler<[f32; 4]> = "i_Texture",
        vertices: gfx::VertexBuffer<TexturedVertex> = (),
        out: gfx::BlendTarget<ColorFormat> = ("Target0", gfx::state::ColorMask::all(), gfx::preset::blend::ALPHA),
        depth: gfx::DepthTarget<DepthFormat> = gfx::state::Depth {
            fun: gfx::state::Comparison::LessEqual,
            write: true,
        },
    }
}
pub struct Target {
    pub color: RenderTargetView<gl::Resources, ColorFormat>,
    pub depth: DepthStencilView<gl::Resources, DepthFormat>,
}

fn rect(x: f32, y: f32, w: f32, h: f32) -> [Vertex; 4] {
    [
        Vertex { pos: [x, y] },
        Vertex { pos: [x, y + h] },
        Vertex {
            pos: [x + w, y + h],
        },
        Vertex { pos: [x + w, y] },
    ]
}

const RECT_IDX: [u16; 6] = [0, 1, 2, 0, 2, 3];

#[derive(Clone)]
struct RectRenderer {
    factory: gl::Factory,
    pso: PipelineState<gl::Resources, rect_pipe::Meta>,
    slice: Slice<gl::Resources>,
    vertex_buffer: Buffer<gl::Resources, Vertex>,
    rects: Vec<ColoredRect>,
}
impl RectRenderer {
    fn new(mut factory: gl::Factory) -> RectRenderer {
        let pso = factory
            .create_pipeline_simple(
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/shaders/rect_150.glslv"
                )),
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/shaders/rect_150.glslf"
                )),
                rect_pipe::new(),
            )
            .unwrap();
        let vertex_buffer = factory
            .create_buffer_immutable(&rect(0.0, 0.0, 1.0, 1.0), Role::Vertex, Bind::empty())
            .unwrap();
        let index_buffer = RECT_IDX[..].into_index_buffer(&mut factory);
        let buffer_length = match index_buffer {
            gfx::IndexBuffer::Auto => vertex_buffer.len(),
            gfx::IndexBuffer::Index16(ref ib) => ib.len(),
            gfx::IndexBuffer::Index32(ref ib) => ib.len(),
        };
        let slice = Slice {
            start: 0,
            end: buffer_length as u32,
            base_vertex: 0,
            instances: Some((0, 0)),
            buffer: index_buffer,
        };
        RectRenderer {
            factory,
            pso,
            slice,
            vertex_buffer,
            rects: Vec::new(),
        }
    }
    fn push(&mut self, rect: ColoredRect) {
        self.rects.push(rect);
    }
    fn draw(&mut self, encoder: &mut Encoder<gl::Resources, gl::CommandBuffer>, target: &Target) {
        let instance_buffer = self.factory
            .create_buffer_immutable(&self.rects, Role::Vertex, Bind::empty())
            .unwrap();
        let data = rect_pipe::Data {
            resolution: target_dimensions(target),
            vertices: self.vertex_buffer.clone(),
            instances: instance_buffer,
            out: target.color.clone(),
            depth: target.depth.clone(),
        };
        self.slice.instances = Some((self.rects.len() as u32, 0));
        encoder.draw(&self.slice, &self.pso, &data);
        self.rects.clear();
    }
}

#[derive(Clone)]
struct TexturedRectRenderer {
    factory: gl::Factory,
    pso: PipelineState<gl::Resources, textured_rect_pipe::Meta>,
    sampler: Sampler<gl::Resources>,
    rects: Vec<(Rect3, ShaderResourceView<gl::Resources, [f32; 4]>)>,
}

impl TexturedRectRenderer {
    fn new(mut factory: gl::Factory) -> TexturedRectRenderer {
        let pso = factory
            .create_pipeline_simple(
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/shaders/textured_rect_150.glslv"
                )),
                include_bytes!(concat!(
                    env!("CARGO_MANIFEST_DIR"),
                    "/shaders/textured_rect_150.glslf"
                )),
                textured_rect_pipe::new(),
            )
            .unwrap();
        let sampler = factory.create_sampler_linear();
        TexturedRectRenderer {
            factory,
            pso,
            sampler,
            rects: Vec::new(),
        }
    }
    fn push(&mut self, rect: Rect3, texture: ShaderResourceView<gl::Resources, [f32; 4]>) {
        self.rects.push((rect, texture));
    }
    fn draw(&mut self, encoder: &mut Encoder<gl::Resources, gl::CommandBuffer>, target: &Target) {
        for (rect, texture) in self.rects.drain(..) {
            let vertices = [
                TexturedVertex {
                    translate: rect.pos.into(),
                    tex_coord: [0.0, 1.0],
                },
                TexturedVertex {
                    translate: (rect.pos + Pt3::new(0.0, rect.size.y, 0.0)).into(),
                    tex_coord: [0.0, 0.0],
                },
                TexturedVertex {
                    translate: (rect.pos + Pt3::new(rect.size.x, rect.size.y, 0.0)).into(),
                    tex_coord: [1.0, 0.0],
                },
                TexturedVertex {
                    translate: (rect.pos + Pt3::new(rect.size.x, 0.0, 0.0)).into(),
                    tex_coord: [1.0, 1.0],
                },
            ];
            let (vertex_buffer, slice) = self.factory
                .create_vertex_buffer_with_slice(&vertices, &RECT_IDX[..]);
            let data = textured_rect_pipe::Data {
                resolution: target_dimensions(target),
                texture: (texture, self.sampler.clone()),
                vertices: vertex_buffer,
                out: target.color.clone(),
                depth: target.depth.clone(),
            };
            encoder.draw(&slice, &self.pso, &data);
        }
    }
}

#[derive(Clone)]
struct TextRenderer {
    renderer: Arc<Mutex<gfx_text::Renderer<gl::Resources, gl::Factory>>>,
    texts: Vec<(String, [f32; 2], [f32; 3])>,
}
impl TextRenderer {
    fn new(factory: gl::Factory) -> TextRenderer {
        let renderer = Arc::new(Mutex::new(gfx_text::new(factory.clone()).unwrap()));
        TextRenderer {
            renderer,
            texts: Vec::new(),
        }
    }
    fn push(&mut self, text: &str, pos: [f32; 2], color: [f32; 3]) {
        self.texts.push((text.into(), pos, color));
    }
    fn draw(&mut self, encoder: &mut Encoder<gl::Resources, gl::CommandBuffer>, target: &Target) {
        let mut renderer = self.renderer.lock().unwrap();
        for (text, pos, color) in self.texts.drain(..) {
            renderer.add(
                &text,
                [pos[0] as i32, pos[1] as i32],
                [color[0], color[1], color[2], 1.0],
            );
        }
        renderer.draw(encoder, &target.color).unwrap();
    }
}

pub struct DepthRange {
    pub near: f32,
    pub far: f32,
}

pub struct RenderContext {
    factory: gl::Factory,
    encoder: Encoder<gl::Resources, gl::CommandBuffer>,
    rects: RectRenderer,
    textured_rects: TexturedRectRenderer,
    texts: TextRenderer,
}
impl RenderContext {
    pub fn new(mut factory: gl::Factory) -> RenderContext {
        let encoder = factory.create_command_buffer().into();
        let rects = RectRenderer::new(factory.clone());
        let textured_rects = TexturedRectRenderer::new(factory.clone());
        let texts = TextRenderer::new(factory.clone());

        RenderContext {
            factory,
            encoder,
            rects,
            textured_rects,
            texts,
        }
    }
    pub fn begin_frame(&mut self, target: &Target) {
        self.encoder.clear(&target.color, [0.0; 4]);
        self.encoder.clear_depth(&target.depth, 1.0);
    }
    pub fn draw_text(&mut self, text: &str, pos: Pt3, color: [f32; 3]) {
        // for now we are discarding z because gfx_text can't handle it
        // TODO write better text renderer
        self.texts.push(text, [pos.x, pos.y], color);
    }
    pub fn draw_rect(&mut self, rect: Rect3, color: [f32; 3]) {
        self.rects.push(ColoredRect {
            translate: rect.pos.into(),
            scale: rect.size.into(),
            color,
        });
    }
    pub fn draw_textured_rect(&mut self, rect: Rect3, texture: ShaderResourceView<gl::Resources, [f32; 4]>) {
        self.textured_rects.push(rect, texture);
    }
    pub fn factory(&self) -> &gl::Factory {
        &self.factory
    }
    pub fn end_frame(&mut self, device: &mut gl::Device, target: &Target) {
        self.rects.draw(&mut self.encoder, target);
        self.textured_rects.draw(&mut self.encoder, target);
        self.texts.draw(&mut self.encoder, target);
        self.encoder.flush(device);
    }
}

impl Clone for RenderContext {
    fn clone(&self) -> RenderContext {
        let mut factory = self.factory.clone();
        let encoder = factory.create_command_buffer().into();
        RenderContext {
            factory: factory,
            encoder: encoder,
            rects: self.rects.clone(),
            textured_rects: self.textured_rects.clone(),
            texts: self.texts.clone(),
        }
    }
}

pub struct TextureTarget {
    ctx: RenderContext,
    //target_texture: Texture<gl::Resources, gfx::format::R8_G8_B8_A8>,
    //depth_texture: Texture<gl::Resources, gfx::format::D24_S8>,
    target_resource: ShaderResourceView<gl::Resources, [f32; 4]>,
    target: Target,
    size: Pt2,
}

impl TextureTarget {
    pub fn new(ctx: RenderContext, size: Pt2) -> TextureTarget {
        let mut factory = ctx.factory().clone();
        assert!(size.x >= 1.0 && size.y >= 1.0 && size.x <= 65535.0 && size.y <= 65535.0);
        let target_texture = factory
            .create_texture(
                texture::Kind::D2(size.x as u16, size.y as u16, texture::AaMode::Single),
                1, //levels
                Bind::RENDER_TARGET | Bind::SHADER_RESOURCE,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let color_target = factory
            .view_texture_as_render_target(
                &target_texture,
                0,    //level
                None, //layer
            )
            .unwrap();
        let target_resource = factory
            .view_texture_as_shader_resource::<gfx::format::Rgba8>(
                &target_texture,
                (0, 0), // levels
                gfx::format::Swizzle::new(),
            )
            .unwrap();
        let depth_texture = factory
            .create_texture(
                texture::Kind::D2(size.x as u16, size.y as u16, texture::AaMode::Single),
                1, //levels
                Bind::DEPTH_STENCIL,
                Usage::Data,
                Some(gfx::format::ChannelType::Unorm),
            )
            .unwrap();
        let depth_target = factory
            .view_texture_as_depth_stencil(
                &depth_texture,
                0,    //level
                None, //layer
                texture::DepthStencilFlags::empty(),
            )
            .unwrap();
        let target = Target {
            color: color_target,
            depth: depth_target,
        };
        TextureTarget {
            ctx,
            target_resource,
            target,
            size,
        }
    }
    pub fn ctx(&mut self) -> &mut RenderContext {
        &mut self.ctx
    }
    pub fn target(&self) -> &Target {
        &self.target
    }
    pub fn shader_resource(&self) -> &ShaderResourceView<gl::Resources, [f32; 4]> {
        &self.target_resource
    }
    pub fn begin_frame(&mut self) {
        self.ctx.begin_frame(&self.target);
    }
    pub fn end_frame(&mut self, device: &mut gl::Device) {
        self.ctx.end_frame(device, &self.target);
    }
    pub fn size(&self) -> Pt2 {
        self.size
    }
}

fn target_dimensions(target: &Target) -> [f32; 2] {
    let dims = target.color.get_dimensions();
    [dims.0 as f32, dims.1 as f32]
}
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_variables, dead_code)]
use std::fmt::Write as FmtWrite;
use std::io::Write;
use std::marker::PhantomData;
use std::str::FromStr;
use std::{cmp, fmt, io, mem};

use bytes::{BufMut, Bytes, BytesMut};
use http::header::{
    HeaderValue, ACCEPT_ENCODING, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
};
use http::{HeaderMap, Method, StatusCode, Version};

use crate::body::BodyLength;
use crate::config::ServiceConfig;
use crate::header::ContentEncoding;
use crate::helpers;
use crate::message::{ConnectionType, RequestHead, ResponseHead};
use crate::request::Request;
use crate::response::Response;

const AVERAGE_HEADER_SIZE: usize = 30;

#[derive(Debug)]
pub(crate) struct MessageEncoder<T: MessageType> {
    pub length: BodyLength,
    pub te: TransferEncoding,
    _t: PhantomData<T>,
}

impl<T: MessageType> Default for MessageEncoder<T> {
    fn default() -> Self {
        MessageEncoder {
            length: BodyLength::None,
            te: TransferEncoding::empty(),
            _t: PhantomData,
        }
    }
}

pub(crate) trait MessageType: Sized {
    fn status(&self) -> Option<StatusCode>;

    fn connection_type(&self) -> Option<ConnectionType>;

    fn headers(&self) -> &HeaderMap;

    fn chunked(&self) -> bool;

    fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()>;

    fn encode_headers(
        &mut self,
        dst: &mut BytesMut,
        version: Version,
        mut length: BodyLength,
        ctype: ConnectionType,
        config: &ServiceConfig,
    ) -> io::Result<()> {
        let chunked = self.chunked();
        let mut skip_len = length != BodyLength::Stream;

        // Content length
        if let Some(status) = self.status() {
            match status {
                StatusCode::NO_CONTENT
                | StatusCode::CONTINUE
                | StatusCode::PROCESSING => length = BodyLength::None,
                StatusCode::SWITCHING_PROTOCOLS => {
                    skip_len = true;
                    length = BodyLength::Stream;
                }
                _ => (),
            }
        }
        match length {
            BodyLength::Stream => {
                if chunked {
                    dst.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
                } else {
                    skip_len = false;
                }
            }
            BodyLength::Empty => {
                dst.extend_from_slice(b"\r\ncontent-length: 0\r\n");
            }
            BodyLength::Sized(len) => helpers::write_content_length(len, dst),
            BodyLength::Sized64(len) => {
                dst.extend_from_slice(b"\r\ncontent-length: ");
                write!(dst.writer(), "{}", len)?;
                dst.extend_from_slice(b"\r\n");
            }
            BodyLength::None => dst.extend_from_slice(b"\r\n"),
        }

        // Connection
        match ctype {
            ConnectionType::Upgrade => dst.extend_from_slice(b"connection: upgrade\r\n"),
            ConnectionType::KeepAlive if version < Version::HTTP_11 => {
                dst.extend_from_slice(b"connection: keep-alive\r\n")
            }
            ConnectionType::Close if version >= Version::HTTP_11 => {
                dst.extend_from_slice(b"connection: close\r\n")
            }
            _ => (),
        }

        // write headers
        let mut pos = 0;
        let mut has_date = false;
        let mut remaining = dst.remaining_mut();
        let mut buf = unsafe { &mut *(dst.bytes_mut() as *mut [u8]) };
        for (key, value) in self.headers() {
            match *key {
                CONNECTION => continue,
                TRANSFER_ENCODING | CONTENT_LENGTH if skip_len => continue,
                DATE => {
                    has_date = true;
                }
                _ => (),
            }

            let v = value.as_ref();
            let k = key.as_str().as_bytes();
            let len = k.len() + v.len() + 4;
            if len > remaining {
                unsafe {
                    dst.advance_mut(pos);
                }
                pos = 0;
                dst.reserve(len);
                remaining = dst.remaining_mut();
                unsafe {
                    buf = &mut *(dst.bytes_mut() as *mut _);
                }
            }

            buf[pos..pos + k.len()].copy_from_slice(k);
            pos += k.len();
            buf[pos..pos + 2].copy_from_slice(b": ");
            pos += 2;
            buf[pos..pos + v.len()].copy_from_slice(v);
            pos += v.len();
            buf[pos..pos + 2].copy_from_slice(b"\r\n");
            pos += 2;
            remaining -= len;
        }
        unsafe {
            dst.advance_mut(pos);
        }

        // optimized date header, set_date writes \r\n
        if !has_date {
            config.set_date(dst);
        } else {
            // msg eof
            dst.extend_from_slice(b"\r\n");
        }

        Ok(())
    }
}

impl MessageType for Response<()> {
    fn status(&self) -> Option<StatusCode> {
        Some(self.head().status)
    }

    fn chunked(&self) -> bool {
        !self.head().no_chunking
    }

    fn connection_type(&self) -> Option<ConnectionType> {
        self.head().ctype
    }

    fn headers(&self) -> &HeaderMap {
        &self.head().headers
    }

    fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()> {
        let head = self.head();
        let reason = head.reason().as_bytes();
        dst.reserve(256 + head.headers.len() * AVERAGE_HEADER_SIZE + reason.len());

        // status line
        helpers::write_status_line(head.version, head.status.as_u16(), dst);
        dst.extend_from_slice(reason);
        Ok(())
    }
}

impl MessageType for RequestHead {
    fn status(&self) -> Option<StatusCode> {
        None
    }

    fn connection_type(&self) -> Option<ConnectionType> {
        self.ctype
    }

    fn chunked(&self) -> bool {
        !self.no_chunking
    }

    fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()> {
        write!(
            Writer(dst),
            "{} {} {}",
            self.method,
            self.uri.path_and_query().map(|u| u.as_str()).unwrap_or("/"),
            match self.version {
                Version::HTTP_09 => "HTTP/0.9",
                Version::HTTP_10 => "HTTP/1.0",
                Version::HTTP_11 => "HTTP/1.1",
                Version::HTTP_2 => "HTTP/2.0",
            }
        )
        .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
    }
}

impl<T: MessageType> MessageEncoder<T> {
    /// Encode message
    pub fn encode_chunk(&mut self, msg: &[u8], buf: &mut BytesMut) -> io::Result<bool> {
        self.te.encode(msg, buf)
    }

    /// Encode eof
    pub fn encode_eof(&mut self, buf: &mut BytesMut) -> io::Result<()> {
        self.te.encode_eof(buf)
    }

    pub fn encode(
        &mut self,
        dst: &mut BytesMut,
        message: &mut T,
        head: bool,
        version: Version,
        length: BodyLength,
        ctype: ConnectionType,
        config: &ServiceConfig,
    ) -> io::Result<()> {
        // transfer encoding
        if !head {
            self.te = match length {
                BodyLength::Empty => TransferEncoding::empty(),
                BodyLength::Sized(len) => TransferEncoding::length(len as u64),
                BodyLength::Sized64(len) => TransferEncoding::length(len),
                BodyLength::Stream => {
                    if message.chunked() {
                        TransferEncoding::chunked()
                    } else {
                        TransferEncoding::eof()
                    }
                }
                BodyLength::None => TransferEncoding::empty(),
            };
        } else {
            self.te = TransferEncoding::empty();
        }

        message.encode_status(dst)?;
        message.encode_headers(dst, version, length, ctype, config)
    }
}

/// Encoders to handle different Transfer-Encodings.
#[derive(Debug)]
pub(crate) struct TransferEncoding {
    kind: TransferEncodingKind,
}

#[derive(Debug, PartialEq, Clone)]
enum TransferEncodingKind {
    /// An Encoder for when Transfer-Encoding includes `chunked`.
    Chunked(bool),
    /// An Encoder for when Content-Length is set.
    ///
    /// Enforces that the body is not longer than the Content-Length header.
    Length(u64),
    /// An Encoder for when Content-Length is not known.
    ///
    /// Application decides when to stop writing.
    Eof,
}

impl TransferEncoding {
    #[inline]
    pub fn empty() -> TransferEncoding {
        TransferEncoding {
            kind: TransferEncodingKind::Length(0),
        }
    }

    #[inline]
    pub fn eof() -> TransferEncoding {
        TransferEncoding {
            kind: TransferEncodingKind::Eof,
        }
    }

    #[inline]
    pub fn chunked() -> TransferEncoding {
        TransferEncoding {
            kind: TransferEncodingKind::Chunked(false),
        }
    }

    #[inline]
    pub fn length(len: u64) -> TransferEncoding {
        TransferEncoding {
            kind: TransferEncodingKind::Length(len),
        }
    }

    /// Encode message. Return `EOF` state of encoder
    #[inline]
    pub fn encode(&mut self, msg: &[u8], buf: &mut BytesMut) -> io::Result<bool> {
        match self.kind {
            TransferEncodingKind::Eof => {
                let eof = msg.is_empty();
                buf.extend_from_slice(msg);
                Ok(eof)
            }
            TransferEncodingKind::Chunked(ref mut eof) => {
                if *eof {
                    return Ok(true);
                }

                if msg.is_empty() {
                    *eof = true;
                    buf.extend_from_slice(b"0\r\n\r\n");
                } else {
                    writeln!(Writer(buf), "{:X}\r", msg.len())
                        .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

                    buf.reserve(msg.len() + 2);
                    buf.extend_from_slice(msg);
                    buf.extend_from_slice(b"\r\n");
                }
                Ok(*eof)
            }
            TransferEncodingKind::Length(ref mut remaining) => {
                if *remaining > 0 {
                    if msg.is_empty() {
                        return Ok(*remaining == 0);
                    }
                    let len = cmp::min(*remaining, msg.len() as u64);

                    buf.extend_from_slice(&msg[..len as usize]);

                    *remaining -= len as u64;
                    Ok(*remaining == 0)
                } else {
                    Ok(true)
                }
            }
        }
    }

    /// Encode eof. Return `EOF` state of encoder
    #[inline]
    pub fn encode_eof(&mut self, buf: &mut BytesMut) -> io::Result<()> {
        match self.kind {
            TransferEncodingKind::Eof => Ok(()),
            TransferEncodingKind::Length(rem) => {
                if rem != 0 {
                    Err(io::Error::new(io::ErrorKind::UnexpectedEof, ""))
                } else {
                    Ok(())
                }
            }
            TransferEncodingKind::Chunked(ref mut eof) => {
                if !*eof {
                    *eof = true;
                    buf.extend_from_slice(b"0\r\n\r\n");
                }
                Ok(())
            }
        }
    }
}

struct Writer<'a>(pub &'a mut BytesMut);

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

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

    #[test]
    fn test_chunked_te() {
        let mut bytes = BytesMut::new();
        let mut enc = TransferEncoding::chunked();
        {
            assert!(!enc.encode(b"test", &mut bytes).ok().unwrap());
            assert!(enc.encode(b"", &mut bytes).ok().unwrap());
        }
        assert_eq!(
            bytes.take().freeze(),
            Bytes::from_static(b"4\r\ntest\r\n0\r\n\r\n")
        );
    }
}
<commit_msg>add missing end of line<commit_after>#![allow(unused_imports, unused_variables, dead_code)]
use std::fmt::Write as FmtWrite;
use std::io::Write;
use std::marker::PhantomData;
use std::str::FromStr;
use std::{cmp, fmt, io, mem};

use bytes::{BufMut, Bytes, BytesMut};
use http::header::{
    HeaderValue, ACCEPT_ENCODING, CONNECTION, CONTENT_LENGTH, DATE, TRANSFER_ENCODING,
};
use http::{HeaderMap, Method, StatusCode, Version};

use crate::body::BodyLength;
use crate::config::ServiceConfig;
use crate::header::ContentEncoding;
use crate::helpers;
use crate::message::{ConnectionType, RequestHead, ResponseHead};
use crate::request::Request;
use crate::response::Response;

const AVERAGE_HEADER_SIZE: usize = 30;

#[derive(Debug)]
pub(crate) struct MessageEncoder<T: MessageType> {
    pub length: BodyLength,
    pub te: TransferEncoding,
    _t: PhantomData<T>,
}

impl<T: MessageType> Default for MessageEncoder<T> {
    fn default() -> Self {
        MessageEncoder {
            length: BodyLength::None,
            te: TransferEncoding::empty(),
            _t: PhantomData,
        }
    }
}

pub(crate) trait MessageType: Sized {
    fn status(&self) -> Option<StatusCode>;

    fn connection_type(&self) -> Option<ConnectionType>;

    fn headers(&self) -> &HeaderMap;

    fn chunked(&self) -> bool;

    fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()>;

    fn encode_headers(
        &mut self,
        dst: &mut BytesMut,
        version: Version,
        mut length: BodyLength,
        ctype: ConnectionType,
        config: &ServiceConfig,
    ) -> io::Result<()> {
        let chunked = self.chunked();
        let mut skip_len = length != BodyLength::Stream;

        // Content length
        if let Some(status) = self.status() {
            match status {
                StatusCode::NO_CONTENT
                | StatusCode::CONTINUE
                | StatusCode::PROCESSING => length = BodyLength::None,
                StatusCode::SWITCHING_PROTOCOLS => {
                    skip_len = true;
                    length = BodyLength::Stream;
                }
                _ => (),
            }
        }
        match length {
            BodyLength::Stream => {
                if chunked {
                    dst.extend_from_slice(b"\r\ntransfer-encoding: chunked\r\n")
                } else {
                    skip_len = false;
                    dst.extend_from_slice(b"\r\n");
                }
            }
            BodyLength::Empty => {
                dst.extend_from_slice(b"\r\ncontent-length: 0\r\n");
            }
            BodyLength::Sized(len) => helpers::write_content_length(len, dst),
            BodyLength::Sized64(len) => {
                dst.extend_from_slice(b"\r\ncontent-length: ");
                write!(dst.writer(), "{}", len)?;
                dst.extend_from_slice(b"\r\n");
            }
            BodyLength::None => dst.extend_from_slice(b"\r\n"),
        }

        // Connection
        match ctype {
            ConnectionType::Upgrade => dst.extend_from_slice(b"connection: upgrade\r\n"),
            ConnectionType::KeepAlive if version < Version::HTTP_11 => {
                dst.extend_from_slice(b"connection: keep-alive\r\n")
            }
            ConnectionType::Close if version >= Version::HTTP_11 => {
                dst.extend_from_slice(b"connection: close\r\n")
            }
            _ => (),
        }

        // write headers
        let mut pos = 0;
        let mut has_date = false;
        let mut remaining = dst.remaining_mut();
        let mut buf = unsafe { &mut *(dst.bytes_mut() as *mut [u8]) };
        for (key, value) in self.headers() {
            match *key {
                CONNECTION => continue,
                TRANSFER_ENCODING | CONTENT_LENGTH if skip_len => continue,
                DATE => {
                    has_date = true;
                }
                _ => (),
            }

            let v = value.as_ref();
            let k = key.as_str().as_bytes();
            let len = k.len() + v.len() + 4;
            if len > remaining {
                unsafe {
                    dst.advance_mut(pos);
                }
                pos = 0;
                dst.reserve(len);
                remaining = dst.remaining_mut();
                unsafe {
                    buf = &mut *(dst.bytes_mut() as *mut _);
                }
            }

            buf[pos..pos + k.len()].copy_from_slice(k);
            pos += k.len();
            buf[pos..pos + 2].copy_from_slice(b": ");
            pos += 2;
            buf[pos..pos + v.len()].copy_from_slice(v);
            pos += v.len();
            buf[pos..pos + 2].copy_from_slice(b"\r\n");
            pos += 2;
            remaining -= len;
        }
        unsafe {
            dst.advance_mut(pos);
        }

        // optimized date header, set_date writes \r\n
        if !has_date {
            config.set_date(dst);
        } else {
            // msg eof
            dst.extend_from_slice(b"\r\n");
        }

        Ok(())
    }
}

impl MessageType for Response<()> {
    fn status(&self) -> Option<StatusCode> {
        Some(self.head().status)
    }

    fn chunked(&self) -> bool {
        !self.head().no_chunking
    }

    fn connection_type(&self) -> Option<ConnectionType> {
        self.head().ctype
    }

    fn headers(&self) -> &HeaderMap {
        &self.head().headers
    }

    fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()> {
        let head = self.head();
        let reason = head.reason().as_bytes();
        dst.reserve(256 + head.headers.len() * AVERAGE_HEADER_SIZE + reason.len());

        // status line
        helpers::write_status_line(head.version, head.status.as_u16(), dst);
        dst.extend_from_slice(reason);
        Ok(())
    }
}

impl MessageType for RequestHead {
    fn status(&self) -> Option<StatusCode> {
        None
    }

    fn connection_type(&self) -> Option<ConnectionType> {
        self.ctype
    }

    fn chunked(&self) -> bool {
        !self.no_chunking
    }

    fn headers(&self) -> &HeaderMap {
        &self.headers
    }

    fn encode_status(&mut self, dst: &mut BytesMut) -> io::Result<()> {
        write!(
            Writer(dst),
            "{} {} {}",
            self.method,
            self.uri.path_and_query().map(|u| u.as_str()).unwrap_or("/"),
            match self.version {
                Version::HTTP_09 => "HTTP/0.9",
                Version::HTTP_10 => "HTTP/1.0",
                Version::HTTP_11 => "HTTP/1.1",
                Version::HTTP_2 => "HTTP/2.0",
            }
        )
        .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
    }
}

impl<T: MessageType> MessageEncoder<T> {
    /// Encode message
    pub fn encode_chunk(&mut self, msg: &[u8], buf: &mut BytesMut) -> io::Result<bool> {
        self.te.encode(msg, buf)
    }

    /// Encode eof
    pub fn encode_eof(&mut self, buf: &mut BytesMut) -> io::Result<()> {
        self.te.encode_eof(buf)
    }

    pub fn encode(
        &mut self,
        dst: &mut BytesMut,
        message: &mut T,
        head: bool,
        version: Version,
        length: BodyLength,
        ctype: ConnectionType,
        config: &ServiceConfig,
    ) -> io::Result<()> {
        // transfer encoding
        if !head {
            self.te = match length {
                BodyLength::Empty => TransferEncoding::empty(),
                BodyLength::Sized(len) => TransferEncoding::length(len as u64),
                BodyLength::Sized64(len) => TransferEncoding::length(len),
                BodyLength::Stream => {
                    if message.chunked() {
                        TransferEncoding::chunked()
                    } else {
                        TransferEncoding::eof()
                    }
                }
                BodyLength::None => TransferEncoding::empty(),
            };
        } else {
            self.te = TransferEncoding::empty();
        }

        message.encode_status(dst)?;
        message.encode_headers(dst, version, length, ctype, config)
    }
}

/// Encoders to handle different Transfer-Encodings.
#[derive(Debug)]
pub(crate) struct TransferEncoding {
    kind: TransferEncodingKind,
}

#[derive(Debug, PartialEq, Clone)]
enum TransferEncodingKind {
    /// An Encoder for when Transfer-Encoding includes `chunked`.
    Chunked(bool),
    /// An Encoder for when Content-Length is set.
    ///
    /// Enforces that the body is not longer than the Content-Length header.
    Length(u64),
    /// An Encoder for when Content-Length is not known.
    ///
    /// Application decides when to stop writing.
    Eof,
}

impl TransferEncoding {
    #[inline]
    pub fn empty() -> TransferEncoding {
        TransferEncoding {
            kind: TransferEncodingKind::Length(0),
        }
    }

    #[inline]
    pub fn eof() -> TransferEncoding {
        TransferEncoding {
            kind: TransferEncodingKind::Eof,
        }
    }

    #[inline]
    pub fn chunked() -> TransferEncoding {
        TransferEncoding {
            kind: TransferEncodingKind::Chunked(false),
        }
    }

    #[inline]
    pub fn length(len: u64) -> TransferEncoding {
        TransferEncoding {
            kind: TransferEncodingKind::Length(len),
        }
    }

    /// Encode message. Return `EOF` state of encoder
    #[inline]
    pub fn encode(&mut self, msg: &[u8], buf: &mut BytesMut) -> io::Result<bool> {
        match self.kind {
            TransferEncodingKind::Eof => {
                let eof = msg.is_empty();
                buf.extend_from_slice(msg);
                Ok(eof)
            }
            TransferEncodingKind::Chunked(ref mut eof) => {
                if *eof {
                    return Ok(true);
                }

                if msg.is_empty() {
                    *eof = true;
                    buf.extend_from_slice(b"0\r\n\r\n");
                } else {
                    writeln!(Writer(buf), "{:X}\r", msg.len())
                        .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

                    buf.reserve(msg.len() + 2);
                    buf.extend_from_slice(msg);
                    buf.extend_from_slice(b"\r\n");
                }
                Ok(*eof)
            }
            TransferEncodingKind::Length(ref mut remaining) => {
                if *remaining > 0 {
                    if msg.is_empty() {
                        return Ok(*remaining == 0);
                    }
                    let len = cmp::min(*remaining, msg.len() as u64);

                    buf.extend_from_slice(&msg[..len as usize]);

                    *remaining -= len as u64;
                    Ok(*remaining == 0)
                } else {
                    Ok(true)
                }
            }
        }
    }

    /// Encode eof. Return `EOF` state of encoder
    #[inline]
    pub fn encode_eof(&mut self, buf: &mut BytesMut) -> io::Result<()> {
        match self.kind {
            TransferEncodingKind::Eof => Ok(()),
            TransferEncodingKind::Length(rem) => {
                if rem != 0 {
                    Err(io::Error::new(io::ErrorKind::UnexpectedEof, ""))
                } else {
                    Ok(())
                }
            }
            TransferEncodingKind::Chunked(ref mut eof) => {
                if !*eof {
                    *eof = true;
                    buf.extend_from_slice(b"0\r\n\r\n");
                }
                Ok(())
            }
        }
    }
}

struct Writer<'a>(pub &'a mut BytesMut);

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

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

    #[test]
    fn test_chunked_te() {
        let mut bytes = BytesMut::new();
        let mut enc = TransferEncoding::chunked();
        {
            assert!(!enc.encode(b"test", &mut bytes).ok().unwrap());
            assert!(enc.encode(b"", &mut bytes).ok().unwrap());
        }
        assert_eq!(
            bytes.take().freeze(),
            Bytes::from_static(b"4\r\ntest\r\n0\r\n\r\n")
        );
    }
}
<|endoftext|>


<commit_before>// Two-way interleave:
// Given [[T]] where the major order is 2
//
// n x T vectors A and B for each channel
//
// Interleave in LLVM IR:
//  <result> = shufflevector <4 x i32> %A, <4 x i32> %B,
//                      <8 x i32> <i32 0, i32 4, i32 1, i32 5,
//                                 i32 2, i32 6, i32 3, i32 7>

#[cfg(target_arch = "arm")] use std::cmp;
use std::ptr;
#[cfg(target_arch="x86_64")] use super::cpu;

/*
#[simd]
#[allow(non_camel_case_types)]
/// 64-bit vector
struct i16x4(i16, i16, i16, i16);
*/
#[simd]
#[allow(non_camel_case_types, dead_code)]
/// 128-bit vector
struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
#[simd]
#[allow(non_camel_case_types, dead_code)]
/// 256-bit vector
struct i16x16(i16, i16, i16, i16, i16, i16, i16, i16,
              i16, i16, i16, i16, i16, i16, i16, i16);

fn interleave_arbitrary<T: Copy>(channels: &[&[T]], out: &mut [T]) {
    let width = channels.len();
    for (i, p) in out.iter_mut().enumerate() {
        unsafe {
            ptr::write(p as *mut _, channels[i % width][i / width]);
        }
    }
}

/// Types which can be interleaved.
///
/// Interleaving two slices `[a0, a1, a2]` and `[b0, b1, b2]` yields the output slice
/// `[a0, b0, a1, b1, a2, b2]` and so forth. The native format for the library is interleaved, but
/// most input and output formats expect an interleaved stream. This trait is used for those
/// conversions.
pub trait Interleave : Copy {
    /// Interleaves all channels in `input` into output.
    ///
    /// `out`'s contents must not require `drop`ping -- it is expected that the values there on entry
    /// are uninitialized.
    fn interleave(channels: &[&[Self]], out: &mut [Self]) {
        Interleave::validate(channels, out);
        interleave_arbitrary(channels, out);
    }
    /// Convenience method to sanity check parameters.
    ///
    /// Ensures that all channels are the same length and the output slice's length is equal to the
    /// product of the number of channels and the length of each channel.
    ///
    /// This function shouldn't be needed for external users; only for implementations of this
    /// trait.
    fn validate(channels: &[&[Self]], out: &mut [Self]) {
        let len = channels[0].len();
        for channel in channels.iter() {
            assert_eq!(channel.len(), len);
        }
        assert_eq!(len * channels.len(), out.len());
    }

}

#[cfg(target_arch = "x86_64")]
static FEATURES: [cpu::Feature, ..2] = [
    cpu::AVX,
    cpu::Baseline
];
#[cfg(target_arch = "x86_64")]
fn prioritize_features() -> cpu::Feature {
    for &feature in FEATURES.iter() {
        if cpu::cpu_supports(feature) {
            info!("Detected best CPU feature is {}", feature);
            return feature;
        }
    }
    unreachable!()
}

#[cfg(target_arch = "x86_64")]
lazy_static!(
    static ref CPU_BEST_FEATURE: cpu::Feature = prioritize_features();
)

impl Interleave for i16 {
    #[cfg(target_arch = "x86_64")]
    fn interleave(channels: &[&[i16]], out: &mut [i16]) {
        Interleave::validate(channels, out);

        match (*CPU_BEST_FEATURE, channels) {
            (cpu::AVX, [left, right]) => {
                // No particular alignment restrictions here
                unsafe {
                    i16x2_fast_avx(left, right, out);
                }
            }
            (_, channels) => {
                interleave_arbitrary(channels, out)
            }
        }
    }

    #[cfg(target_arch = "arm")]
    /// ARM doesn't support runtime feature detection because LLVM enforces that we only use
    /// supported extensions. Build with -C target-feature to select the vector features
    /// available, and flag it to this code by also defining 'arm_vector' at compile time.
    ///
    /// For example, `rustc -C target-feature=+neon --cfg arm_vector=\"neon\"`.
    fn interleave(channels: &[&[i16]], out: &mut [i16]) {
        Interleave::validate(channels, out);

        match channels {
            [left, right] => {
                // Buffers must have same alignment to even have a chance of
                // permitting 128-bit loads.
                let left_align = left.as_ptr() as uint & 7;
                let right_align = right.as_ptr() as uint & 7;
                let out_align = out.as_ptr() as uint & 7;
                if left_align == right_align && right_align == out_align {
                    i16x2_fast_arm(left, right, out);
                } else {
                    interleave_arbitrary(&[left, right], out);
                }
            }
            channels => {
                interleave_arbitrary(channels, out);
            }
        }
    }
}

impl Interleave for i8 { }
// i16 optimized
impl Interleave for i32 { }
impl Interleave for f32 { }
impl Interleave for f64 { }

#[cfg(target_arch = "x86_64")]
unsafe fn i16x2_fast_avx(xs: &[i16], ys: &[i16], zs: &mut [i16]) {
    let n = xs.len();
    let a = xs.as_ptr();
    let b = ys.as_ptr();
    let out = zs.as_mut_ptr();

    // Take vectors 8 samples at a time from each channel
    for i in range(0, n / 8) {
        let left: *const i16x8 = (a as *const i16x8).offset(i as int);
        let right: *const i16x8 = (b as *const i16x8).offset(i as int);
        let mixed: *mut i16x16 = (out as *mut i16x16).offset(i as int);

        // vmovdqa would be better, but requires 256-bit memory alignment.
        // Same for vmovaps, but that's more reasonable since it's a 256-bit store.
        asm!{
            "vmovdqu ($0), %xmm0
             vmovdqu ($1), %xmm1
             vpunpckhwd %xmm1, %xmm0, %xmm2
             vpunpcklwd %xmm1, %xmm0, %xmm0
             vinsertf128 $$1, %xmm2, %ymm0, %ymm0
             vmovups %ymm0, ($2)"
            :                                   // Output
            : "r"(left), "r"(right), "r"(mixed) // Input
            : "{ymm0}", "{xmm1}", "{xmm2}"      // Clobbers
        };
    }

    // Non-multiple of 8 tail
    interleave_arbitrary(&[xs.slice_from(n & !7), ys.slice_from(n & !7)],
                         zs.slice_from_mut(2 * (n & !7)));
}

#[cfg(all(target_arch = "arm", arm_vector = "neon"))]
fn i16x2_fast_arm(xs: &[i16], ys: &[i16], zs: &mut [i16]) {
    let n = xs.len();

    // Three parts: head to get 128-bit alignment, mid where we can do 128-bit loads and stores,
    // tail for trailing non-multiples of 8.
    // TODO VLDM appears to only need 64-bit alignment because Q-register loads are implemented as
    // a pair of D-register loads. Can relax alignment constraints.
    let n_head = cmp::max(xs.as_ptr() as uint & 7, xs.len());
    let n_tail = (n - n_head) & 7;
    let n_mid = n - n_head - n_tail;

    if n_head > 0 {
        interleave_arbitrary(&[xs.slice_to(n_head - 1), ys.slice_to(n_head - 1)],
                             zs.mut_slice_to(2 * (n_head - 1)));
    }
    // Now for the vectorization
    {
        unsafe {
            let mut a = xs.slice(n_head, n - n_tail).as_ptr() as *const i16x8;
            let mut b = ys.slice(n_head, n - n_tail).as_ptr() as *const i16x8;
            let mut out = zs.mut_slice(n_head * 2, (n - n_tail) * 2).as_mut_ptr() as *mut i16x8;

            for i in range(0, n_mid / 8) {
                asm!{
                    "vldmia $1!, {Q0}
                     vldmia $2!, {Q1}
                     vzip.16 Q0, Q1
                     vstm $0!, {Q0, Q1}"
                    : "+r"(out), "+r"(a), "+r"(b)
                    :
                    : "{Q0}", "{Q1}"
                }
            }
        }
    }
    if n_tail > 0 {
        interleave_arbitrary(&[xs.slice_from(n_head + n_mid), ys.slice_from(n_head + n_mid)],
                             zs.mut_slice_from(2 * (n_head + n_mid)));
    }
}

#[cfg(all(target_arch = "arm", not(arm_vector = "neon")))]
fn i16x2_fast_arm(xs: &[i16], ys: &[i16], zs: &mut [i16]) {
    interleave_arbitrary(&[xs, ys], zs)
}

#[cfg(test)]
mod test {
    extern crate test;
    use self::test::Bencher;
    use super::Interleave;

    #[test]
    fn test_interleave_2x2x1024() {
        let mut a = [0i16, ..1024];
        for (i, p) in a.mut_iter().enumerate() {
            *p = i as i16;
        }
        let b = a;

        let mut i = unsafe {
            ::std::mem::uninitialized::<[i16, ..2048]>()
        };
        Interleave::interleave(&[&a, &b], &mut i);

        for idx in ::std::iter::range(0, i.len() / 2) {
            assert_eq!(i[idx * 2], idx as i16);
            assert_eq!(i[idx * 2 + 1], idx as i16);
        }
    }

    #[bench]
    fn bench_interleave_2x2(bencher: &mut Bencher) {
        let mut a = [0i16, ..2048];
        for (i, p) in a.mut_iter().enumerate() {
            *p = i as i16;
        }
        let mut b = a;

        let mut i = unsafe {
            ::std::mem::uninitialized::<[i16, ..4096]>()
        };

        bencher.iter(|| Interleave::interleave(&[&mut a, &mut b], &mut i));
        bencher.bytes = 4096;
    }
}
<commit_msg>mut_iter -> iter_mut in tests.<commit_after>// Two-way interleave:
// Given [[T]] where the major order is 2
//
// n x T vectors A and B for each channel
//
// Interleave in LLVM IR:
//  <result> = shufflevector <4 x i32> %A, <4 x i32> %B,
//                      <8 x i32> <i32 0, i32 4, i32 1, i32 5,
//                                 i32 2, i32 6, i32 3, i32 7>

#[cfg(target_arch = "arm")] use std::cmp;
use std::ptr;
#[cfg(target_arch="x86_64")] use super::cpu;

/*
#[simd]
#[allow(non_camel_case_types)]
/// 64-bit vector
struct i16x4(i16, i16, i16, i16);
*/
#[simd]
#[allow(non_camel_case_types, dead_code)]
/// 128-bit vector
struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16);
#[simd]
#[allow(non_camel_case_types, dead_code)]
/// 256-bit vector
struct i16x16(i16, i16, i16, i16, i16, i16, i16, i16,
              i16, i16, i16, i16, i16, i16, i16, i16);

fn interleave_arbitrary<T: Copy>(channels: &[&[T]], out: &mut [T]) {
    let width = channels.len();
    for (i, p) in out.iter_mut().enumerate() {
        unsafe {
            ptr::write(p as *mut _, channels[i % width][i / width]);
        }
    }
}

/// Types which can be interleaved.
///
/// Interleaving two slices `[a0, a1, a2]` and `[b0, b1, b2]` yields the output slice
/// `[a0, b0, a1, b1, a2, b2]` and so forth. The native format for the library is interleaved, but
/// most input and output formats expect an interleaved stream. This trait is used for those
/// conversions.
pub trait Interleave : Copy {
    /// Interleaves all channels in `input` into output.
    ///
    /// `out`'s contents must not require `drop`ping -- it is expected that the values there on entry
    /// are uninitialized.
    fn interleave(channels: &[&[Self]], out: &mut [Self]) {
        Interleave::validate(channels, out);
        interleave_arbitrary(channels, out);
    }
    /// Convenience method to sanity check parameters.
    ///
    /// Ensures that all channels are the same length and the output slice's length is equal to the
    /// product of the number of channels and the length of each channel.
    ///
    /// This function shouldn't be needed for external users; only for implementations of this
    /// trait.
    fn validate(channels: &[&[Self]], out: &mut [Self]) {
        let len = channels[0].len();
        for channel in channels.iter() {
            assert_eq!(channel.len(), len);
        }
        assert_eq!(len * channels.len(), out.len());
    }

}

#[cfg(target_arch = "x86_64")]
static FEATURES: [cpu::Feature, ..2] = [
    cpu::AVX,
    cpu::Baseline
];
#[cfg(target_arch = "x86_64")]
fn prioritize_features() -> cpu::Feature {
    for &feature in FEATURES.iter() {
        if cpu::cpu_supports(feature) {
            info!("Detected best CPU feature is {}", feature);
            return feature;
        }
    }
    unreachable!()
}

#[cfg(target_arch = "x86_64")]
lazy_static!(
    static ref CPU_BEST_FEATURE: cpu::Feature = prioritize_features();
)

impl Interleave for i16 {
    #[cfg(target_arch = "x86_64")]
    fn interleave(channels: &[&[i16]], out: &mut [i16]) {
        Interleave::validate(channels, out);

        match (*CPU_BEST_FEATURE, channels) {
            (cpu::AVX, [left, right]) => {
                // No particular alignment restrictions here
                unsafe {
                    i16x2_fast_avx(left, right, out);
                }
            }
            (_, channels) => {
                interleave_arbitrary(channels, out)
            }
        }
    }

    #[cfg(target_arch = "arm")]
    /// ARM doesn't support runtime feature detection because LLVM enforces that we only use
    /// supported extensions. Build with -C target-feature to select the vector features
    /// available, and flag it to this code by also defining 'arm_vector' at compile time.
    ///
    /// For example, `rustc -C target-feature=+neon --cfg arm_vector=\"neon\"`.
    fn interleave(channels: &[&[i16]], out: &mut [i16]) {
        Interleave::validate(channels, out);

        match channels {
            [left, right] => {
                // Buffers must have same alignment to even have a chance of
                // permitting 128-bit loads.
                let left_align = left.as_ptr() as uint & 7;
                let right_align = right.as_ptr() as uint & 7;
                let out_align = out.as_ptr() as uint & 7;
                if left_align == right_align && right_align == out_align {
                    i16x2_fast_arm(left, right, out);
                } else {
                    interleave_arbitrary(&[left, right], out);
                }
            }
            channels => {
                interleave_arbitrary(channels, out);
            }
        }
    }
}

impl Interleave for i8 { }
// i16 optimized
impl Interleave for i32 { }
impl Interleave for f32 { }
impl Interleave for f64 { }

#[cfg(target_arch = "x86_64")]
unsafe fn i16x2_fast_avx(xs: &[i16], ys: &[i16], zs: &mut [i16]) {
    let n = xs.len();
    let a = xs.as_ptr();
    let b = ys.as_ptr();
    let out = zs.as_mut_ptr();

    // Take vectors 8 samples at a time from each channel
    for i in range(0, n / 8) {
        let left: *const i16x8 = (a as *const i16x8).offset(i as int);
        let right: *const i16x8 = (b as *const i16x8).offset(i as int);
        let mixed: *mut i16x16 = (out as *mut i16x16).offset(i as int);

        // vmovdqa would be better, but requires 256-bit memory alignment.
        // Same for vmovaps, but that's more reasonable since it's a 256-bit store.
        asm!{
            "vmovdqu ($0), %xmm0
             vmovdqu ($1), %xmm1
             vpunpckhwd %xmm1, %xmm0, %xmm2
             vpunpcklwd %xmm1, %xmm0, %xmm0
             vinsertf128 $$1, %xmm2, %ymm0, %ymm0
             vmovups %ymm0, ($2)"
            :                                   // Output
            : "r"(left), "r"(right), "r"(mixed) // Input
            : "{ymm0}", "{xmm1}", "{xmm2}"      // Clobbers
        };
    }

    // Non-multiple of 8 tail
    interleave_arbitrary(&[xs.slice_from(n & !7), ys.slice_from(n & !7)],
                         zs.slice_from_mut(2 * (n & !7)));
}

#[cfg(all(target_arch = "arm", arm_vector = "neon"))]
fn i16x2_fast_arm(xs: &[i16], ys: &[i16], zs: &mut [i16]) {
    let n = xs.len();

    // Three parts: head to get 128-bit alignment, mid where we can do 128-bit loads and stores,
    // tail for trailing non-multiples of 8.
    // TODO VLDM appears to only need 64-bit alignment because Q-register loads are implemented as
    // a pair of D-register loads. Can relax alignment constraints.
    let n_head = cmp::max(xs.as_ptr() as uint & 7, xs.len());
    let n_tail = (n - n_head) & 7;
    let n_mid = n - n_head - n_tail;

    if n_head > 0 {
        interleave_arbitrary(&[xs.slice_to(n_head - 1), ys.slice_to(n_head - 1)],
                             zs.mut_slice_to(2 * (n_head - 1)));
    }
    // Now for the vectorization
    {
        unsafe {
            let mut a = xs.slice(n_head, n - n_tail).as_ptr() as *const i16x8;
            let mut b = ys.slice(n_head, n - n_tail).as_ptr() as *const i16x8;
            let mut out = zs.mut_slice(n_head * 2, (n - n_tail) * 2).as_mut_ptr() as *mut i16x8;

            for i in range(0, n_mid / 8) {
                asm!{
                    "vldmia $1!, {Q0}
                     vldmia $2!, {Q1}
                     vzip.16 Q0, Q1
                     vstm $0!, {Q0, Q1}"
                    : "+r"(out), "+r"(a), "+r"(b)
                    :
                    : "{Q0}", "{Q1}"
                }
            }
        }
    }
    if n_tail > 0 {
        interleave_arbitrary(&[xs.slice_from(n_head + n_mid), ys.slice_from(n_head + n_mid)],
                             zs.mut_slice_from(2 * (n_head + n_mid)));
    }
}

#[cfg(all(target_arch = "arm", not(arm_vector = "neon")))]
fn i16x2_fast_arm(xs: &[i16], ys: &[i16], zs: &mut [i16]) {
    interleave_arbitrary(&[xs, ys], zs)
}

#[cfg(test)]
mod test {
    extern crate test;
    use self::test::Bencher;
    use super::Interleave;

    #[test]
    fn test_interleave_2x2x1024() {
        let mut a = [0i16, ..1024];
        for (i, p) in a.iter_mut().enumerate() {
            *p = i as i16;
        }
        let b = a;

        let mut i = unsafe {
            ::std::mem::uninitialized::<[i16, ..2048]>()
        };
        Interleave::interleave(&[&a, &b], &mut i);

        for idx in ::std::iter::range(0, i.len() / 2) {
            assert_eq!(i[idx * 2], idx as i16);
            assert_eq!(i[idx * 2 + 1], idx as i16);
        }
    }

    #[bench]
    fn bench_interleave_2x2(bencher: &mut Bencher) {
        let mut a = [0i16, ..2048];
        for (i, p) in a.iter_mut().enumerate() {
            *p = i as i16;
        }
        let mut b = a;

        let mut i = unsafe {
            ::std::mem::uninitialized::<[i16, ..4096]>()
        };

        bencher.iter(|| Interleave::interleave(&[&mut a, &mut b], &mut i));
        bencher.bytes = 4096;
    }
}
<|endoftext|>