<commit_before>use std::cell::{RefCell, Ref};

use opencl;
use opencl::mem::{Buffer, CLBuffer};

use context::Context;
use matrix::Matrix;
use num::Num;

pub enum ClMatrixMode {
    In,
    Out,
    Mut,
}

pub struct ClMatrix<T: Num> {
    rows: usize,
    columns: usize,
    buffer: CLBuffer<T>,
    event: RefCell<Option<Event>>,
}

impl<T: Num> ClMatrix<T> {
    pub fn new(ctx: &Context, rows: usize, columns: usize, mode: ClMatrixMode) -> ClMatrix<T> {
        let cl_mem_mode =
            match mode {
                ClMatrixMode::In => { opencl::cl::CL_MEM_READ_ONLY },
                ClMatrixMode::Out => { opencl::cl::CL_MEM_WRITE_ONLY },
                ClMatrixMode::Mut => { opencl::cl::CL_MEM_READ_WRITE},
            };
        ClMatrix {
            rows: rows,
            columns: columns,
            buffer: ctx.ctx.create_buffer(rows*columns, cl_mem_mode),
            event: RefCell::new(None),
        }
    }

    pub fn from_matrix(ctx: &Context,
                       matrix: &Matrix<T>,
                       mode: ClMatrixMode) -> ClMatrix<T> {
        let cl_mem_mode =
            match mode {
                ClMatrixMode::In => { opencl::cl::CL_MEM_READ_ONLY },
                ClMatrixMode::Out => { opencl::cl::CL_MEM_WRITE_ONLY },
                ClMatrixMode::Mut => { opencl::cl::CL_MEM_READ_WRITE},
            };
        let cl_matrix =
            ClMatrix {
                rows: matrix.rows(),
                columns: matrix.columns(),
                buffer: ctx.ctx.create_buffer(matrix.rows()*matrix.columns(), cl_mem_mode),
                event: RefCell::new(None),
            };

        ctx.queue.write(&cl_matrix.buffer, &&matrix.buffer()[..], ());
        cl_matrix
    }

    pub fn get(&self, ctx: &Context) -> Matrix<T> {
        let vec = ctx.queue.get(&self.buffer, &*self.get_event().unwrap());
        Matrix::from_vec(self.rows, self.columns, vec)
    }

    pub fn set(&self, ctx: &Context, matrix: &Matrix<T>) {
        ctx.queue.write(&self.buffer, &&matrix.buffer()[..], ());
    }

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

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

    fn set_event(&self, e: Event) {
        *self.event.borrow_mut() = Some(e);
    }

    fn get_event(&self) -> Option<Ref<Event>> {
        if self.event.borrow().is_some() {
            //Some(Ref::map(&self.event.borrow(), |x| x.unwrap().as_ref().unwrap()))
            Ref::filter_map(self.event.borrow(), |o| o.as_ref())
        } else {
            None
        }
    }

    pub fn copy_to(&self, ctx: &Context, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_copy_to_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn add(&self, ctx: &Context, other: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_add_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &other.buffer);
        kernel.set_arg(2, &output.buffer);

        let event_list: &[Option<Ref<Event>>] = &[self.get_event(), other.get_event()];
        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, event_list));
    }

    pub fn sub(&self, ctx: &Context, other: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_sub_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &other.buffer);
        kernel.set_arg(2, &output.buffer);

        let event_list: &[Option<Ref<Event>>] = &[self.get_event(), other.get_event()];
        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, event_list));
    }

    pub fn multiply(&self, ctx: &Context, other: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_multiply_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &other.buffer);
        kernel.set_arg(2, &output.buffer);

        let event_list: &[Option<Ref<Event>>] = &[self.get_event(), other.get_event()];
        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, event_list));
    }

    pub fn transpose(&self, ctx: &Context, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_transpose_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &self.rows);
        kernel.set_arg(3, &self.columns);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, (self.rows, self.columns),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn dot(&self, ctx: &Context, other: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_dot_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &other.buffer);
        kernel.set_arg(2, &output.buffer);
        kernel.set_arg(3, &self.columns);
        kernel.set_arg(4, &other.columns);

        let new_event = {
            let event_list: &[Option<Ref<Event>>] = &[self.get_event(), other.get_event()];
            ctx.queue.enqueue_async_kernel(&kernel,
                                           (self.rows, other.columns),
                                           None, event_list)
        };
        output.set_event(new_event);
    }

    pub fn max(&self, ctx: &Context, threshold: T, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_max_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &threshold);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn min(&self, ctx: &Context, threshold: T, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_min_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &threshold);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn dmax(&self, ctx: &Context, threshold: T, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_dmax_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &threshold);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn dmin(&self, ctx: &Context, threshold: T, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_dmin_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &threshold);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn mse(&self, ctx: &Context, train: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_mse_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &train.buffer);
        kernel.set_arg(2, &output.buffer);
        kernel.set_arg(3, &self.rows);
        kernel.set_arg(4, &self.columns);

        let new_event = {
            let event_list: &[Option<Ref<Event>>] = &[self.get_event(), train.get_event()];
            ctx.queue.enqueue_async_kernel(&kernel,
                                           self.columns,
                                           None, event_list)
        };
        output.set_event(new_event);
    }

    pub fn dmse(&self, ctx: &Context, train: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_dmse_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &train.buffer);
        kernel.set_arg(2, &output.buffer);
        kernel.set_arg(3, &self.rows);
        kernel.set_arg(4, &self.columns);

        let new_event = {
            let event_list: &[Option<Ref<Event>>] = &[self.get_event(), train.get_event()];
            ctx.queue.enqueue_async_kernel(&kernel,
                                           self.columns,
                                           None, event_list)
        };
        output.set_event(new_event);
    }
}

pub type Event = opencl::hl::Event;

#[test]
fn cl_matrix_add() {
    let ref ctx = Context::new();

    let a = Matrix::from_vec(1, 10000, (0..10000).collect());
    let b = Matrix::from_vec(1, 10000, (0..10000).map(|x| x*2).collect());

    let a_cl = ClMatrix::from_matrix(ctx, &a, ClMatrixMode::In);
    let b_cl = ClMatrix::from_matrix(ctx, &b, ClMatrixMode::In);
    let mut c_cl: ClMatrix<i32> = ClMatrix::new(ctx, 1, 10000, ClMatrixMode::Out);

    a_cl.add(ctx, &b_cl, &mut c_cl);

    let c = c_cl.get(ctx);

    for i in 0..10000 {
        assert!(c[(0, i)] == a[(0, i)] + b[(0, i)]);
    }
}
<commit_msg>Fixed for reals now, added unit tests<commit_after>use std::cell::{RefCell, Ref};

use opencl;
use opencl::mem::{Buffer, CLBuffer};

use context::Context;
use matrix::Matrix;
use num::Num;

pub enum ClMatrixMode {
    In,
    Out,
    Mut,
}

pub struct ClMatrix<T: Num> {
    rows: usize,
    columns: usize,
    buffer: CLBuffer<T>,
    event: RefCell<Option<Event>>,
}

impl<T: Num> ClMatrix<T> {
    pub fn new(ctx: &Context, rows: usize, columns: usize, mode: ClMatrixMode) -> ClMatrix<T> {
        let cl_mem_mode =
            match mode {
                ClMatrixMode::In => { opencl::cl::CL_MEM_READ_ONLY },
                ClMatrixMode::Out => { opencl::cl::CL_MEM_WRITE_ONLY },
                ClMatrixMode::Mut => { opencl::cl::CL_MEM_READ_WRITE},
            };
        ClMatrix {
            rows: rows,
            columns: columns,
            buffer: ctx.ctx.create_buffer(rows*columns, cl_mem_mode),
            event: RefCell::new(None),
        }
    }

    pub fn from_matrix(ctx: &Context,
                       matrix: &Matrix<T>,
                       mode: ClMatrixMode) -> ClMatrix<T> {
        let cl_mem_mode =
            match mode {
                ClMatrixMode::In => { opencl::cl::CL_MEM_READ_ONLY },
                ClMatrixMode::Out => { opencl::cl::CL_MEM_WRITE_ONLY },
                ClMatrixMode::Mut => { opencl::cl::CL_MEM_READ_WRITE},
            };
        let cl_matrix =
            ClMatrix {
                rows: matrix.rows(),
                columns: matrix.columns(),
                buffer: ctx.ctx.create_buffer(matrix.rows()*matrix.columns(), cl_mem_mode),
                event: RefCell::new(None),
            };

        ctx.queue.write(&cl_matrix.buffer, &&matrix.buffer()[..], ());
        cl_matrix
    }

    pub fn get(&self, ctx: &Context) -> Matrix<T> {
        let vec = ctx.queue.get(&self.buffer, &*self.get_event().unwrap());
        Matrix::from_vec(self.rows, self.columns, vec)
    }

    pub fn set(&self, ctx: &Context, matrix: &Matrix<T>) {
        ctx.queue.write(&self.buffer, &&matrix.buffer()[..], ());
    }

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

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

    fn set_event(&self, e: Event) {
        *self.event.borrow_mut() = Some(e);
    }

    fn get_event(&self) -> Option<Ref<Event>> {
        if self.event.borrow().is_some() {
            //Some(Ref::map(&self.event.borrow(), |x| x.unwrap().as_ref().unwrap()))
            Ref::filter_map(self.event.borrow(), |o| o.as_ref())
        } else {
            None
        }
    }

    pub fn copy_to(&self, ctx: &Context, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_copy_to_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn add(&self, ctx: &Context, other: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_add_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &other.buffer);
        kernel.set_arg(2, &output.buffer);

        let new_event = {
            let event_list: &[Option<Ref<Event>>] = &[self.get_event(), other.get_event()];
            ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                           None, event_list)
        };
        output.set_event(new_event);
    }

    pub fn sub(&self, ctx: &Context, other: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_sub_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &other.buffer);
        kernel.set_arg(2, &output.buffer);

        let event_list: &[Option<Ref<Event>>] = &[self.get_event(), other.get_event()];
        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, event_list));
    }

    pub fn multiply(&self, ctx: &Context, other: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_multiply_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &other.buffer);
        kernel.set_arg(2, &output.buffer);

        let event_list: &[Option<Ref<Event>>] = &[self.get_event(), other.get_event()];
        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, event_list));
    }

    pub fn transpose(&self, ctx: &Context, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_transpose_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &self.rows);
        kernel.set_arg(3, &self.columns);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, (self.rows, self.columns),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn dot(&self, ctx: &Context, other: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_dot_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &other.buffer);
        kernel.set_arg(2, &output.buffer);
        kernel.set_arg(3, &self.columns);
        kernel.set_arg(4, &other.columns);

        let new_event = {
            let event_list: &[Option<Ref<Event>>] = &[self.get_event(), other.get_event()];
            ctx.queue.enqueue_async_kernel(&kernel,
                                           (self.rows, other.columns),
                                           None, event_list)
        };
        output.set_event(new_event);
    }

    pub fn max(&self, ctx: &Context, threshold: T, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_max_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &threshold);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn min(&self, ctx: &Context, threshold: T, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_min_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &threshold);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn dmax(&self, ctx: &Context, threshold: T, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_dmax_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &threshold);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn dmin(&self, ctx: &Context, threshold: T, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_dmin_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &output.buffer);
        kernel.set_arg(2, &threshold);

        output.set_event(ctx.queue.enqueue_async_kernel(&kernel, self.buffer.len(),
                                                        None, &*self.get_event().unwrap()));
    }

    pub fn mse(&self, ctx: &Context, train: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_mse_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &train.buffer);
        kernel.set_arg(2, &output.buffer);
        kernel.set_arg(3, &self.rows);
        kernel.set_arg(4, &self.columns);

        let new_event = {
            let event_list: &[Option<Ref<Event>>] = &[self.get_event(), train.get_event()];
            ctx.queue.enqueue_async_kernel(&kernel,
                                           self.columns,
                                           None, event_list)
        };
        output.set_event(new_event);
    }

    pub fn dmse(&self, ctx: &Context, train: &ClMatrix<T>, output: &ClMatrix<T>) {
        let kernel = ctx.program.create_kernel(format!("vector_dmse_{}", T::name()).as_str());

        kernel.set_arg(0, &self.buffer);
        kernel.set_arg(1, &train.buffer);
        kernel.set_arg(2, &output.buffer);
        kernel.set_arg(3, &self.rows);
        kernel.set_arg(4, &self.columns);

        let new_event = {
            let event_list: &[Option<Ref<Event>>] = &[self.get_event(), train.get_event()];
            ctx.queue.enqueue_async_kernel(&kernel,
                                           self.columns,
                                           None, event_list)
        };
        output.set_event(new_event);
    }
}

pub type Event = opencl::hl::Event;

#[test]
fn cl_matrix_add() {
    let ref ctx = Context::new();

    let a = Matrix::from_vec(1, 10000, (0..10000).collect());
    let b = Matrix::from_vec(1, 10000, (0..10000).map(|x| x*2).collect());

    let a_cl = ClMatrix::from_matrix(ctx, &a, ClMatrixMode::In);
    let b_cl = ClMatrix::from_matrix(ctx, &b, ClMatrixMode::In);
    let c_cl: ClMatrix<i32> = ClMatrix::new(ctx, 1, 10000, ClMatrixMode::Out);

    a_cl.add(ctx, &b_cl, &c_cl);

    let c = c_cl.get(ctx);

    for i in 0..10000 {
        assert!(c[(0, i)] == a[(0, i)] + b[(0, i)]);
    }
}

#[test]
fn cl_matrix_add_reuse() {
    let ref ctx = Context::new();

    let a = Matrix::from_vec(1, 10000, (0..10000).collect());
    let b = Matrix::from_vec(1, 10000, (0..10000).map(|x| x*2).collect());

    let a_cl = ClMatrix::from_matrix(ctx, &a, ClMatrixMode::In);
    let b_cl = ClMatrix::from_matrix(ctx, &b, ClMatrixMode::In);

    a_cl.add(ctx, &b_cl, &b_cl); // b = a+b
}
<|endoftext|>


<commit_before>extern crate http;
extern crate iron;
extern crate session;

use std::io::net::ip::{SocketAddr, Ipv4Addr};
use iron::{Iron, ServerT, Request, Response, Alloy};
use iron::mixin::Serve;
use session::{Sessions, Session, SessionStore};

// Echo the sessioned count to the client
fn get_count(req: &mut Request, res: &mut Response, alloy: &mut Alloy) {
    // Retrieve our session from the store
    let session = alloy.find_mut::<Session<SocketAddr, u32>>().unwrap();
    // Store or increase the sessioned count
    let count = session.upsert(1u32, |v: &mut u32| { *v = *v + 1; } );

    println!("{} hits from\t{}", count, req.remote_addr.unwrap())
    let _ = res.serve(::http::status::Ok, format!("Sessioned count: {}", count).as_slice());
}

fn main() {
    let mut server: ServerT = Iron::new();
    server.link(Sessions::new(id_from_socket_addr, Session::<SocketAddr, u32>::new()));
    server.link(get_count);
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}

fn id_from_socket_addr(req: &Request, _: &Alloy) -> SocketAddr {
    req.remote_addr.unwrap()
}
<commit_msg>(refactor) Fixed example for HashSessionStore.<commit_after>extern crate http;
extern crate iron;
extern crate session;

use std::io::net::ip::{SocketAddr, Ipv4Addr};
use iron::{Iron, ServerT, Request, Response, Alloy};
use iron::mixin::Serve;
use session::{Sessions, SessionStore, HashSessionStore, Session};

// Echo the sessioned count to the client
fn get_count(req: &mut Request, res: &mut Response, alloy: &mut Alloy) {
    // Retrieve our session from the store
    let session = alloy.find_mut::<Session<SocketAddr, u32>>().unwrap();
    // Store or increase the sessioned count
    let count = session.upsert(1u32, |v: &mut u32| { *v = *v + 1; } );

    println!("{} hits from\t{}", count, req.remote_addr.unwrap())
    let _ = res.serve(::http::status::Ok, format!("Sessioned count: {}", count).as_slice());
}

fn main() {
    let mut server: ServerT = Iron::new();
    server.link(Sessions::new(id_from_socket_addr, HashSessionStore::<SocketAddr, u32>::new()));
    server.link(get_count);
    server.listen(Ipv4Addr(127, 0, 0, 1), 3000);
}

fn id_from_socket_addr(req: &Request, _: &Alloy) -> SocketAddr {
    req.remote_addr.unwrap()
}
<|endoftext|>


<commit_before>extern crate euclid;
#[macro_use]
extern crate glium;

extern crate vitral;

use std::mem;
use std::rc::Rc;

use glium::{Surface, GlObject};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::{Rect, Point2D, Size2D};

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Texture(GliumTexture);

impl PartialEq<Texture> for Texture {
    fn eq(&self, other: &Texture) -> bool {
        self.0.get_id() == other.0.get_id()
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct GliumVertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(GliumVertex, pos, color, tex);

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    let image = glium::texture::RawImage2d::from_raw_rgba(vec![0xffffffffu32], (1, 1));
    let opengl_texture = Rc::new(Texture(glium::texture::CompressedSrgbTexture2d::new(&display, image)
                                     .unwrap()));

    // compiling shaders and linking them together
    let program = program!(&display,
        150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex;

                out vec4 vColor;
                out vec2 vTexcoord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    vColor = color;
                    vTexcoord = tex;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 vColor;
                in vec2 vTexcoord;
                out vec4 f_color;

                void main() {
                    f_color = vColor * texture(tex, vTexcoord);
                }
            "
        },
    )
                      .unwrap();

    let mut context = Context::new(opengl_texture.clone());

    // the main loop
    loop {
        context.begin_frame();
        let area = Rect::new(Point2D::new(10.0, 10.0), Size2D::new(128.0, 128.0));
        context.fill_rect(area.inflate(2.0, 2.0), [0.0, 0.0, 0.0, 1.0]);
        context.fill_rect(area, [1.0, 0.0, 0.0, 1.0]);

        // drawing a frame

        let mut target = display.draw();
        target.clear_color(1.0, 1.0, 1.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [1.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -1.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: &(*batch.texture).0,
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&display,
                                         // XXX: Have to do the unsafe switcheroo here to get a
                                         // vertex type with Glium traits derived for it.
                                         &unsafe {
                                             mem::transmute::<Vec<vitral::Vertex>,
                                                              Vec<GliumVertex>>(batch.vertices)
                                         })
                    .unwrap()
            };

            // building the index buffer
            let index_buffer = glium::IndexBuffer::new(&display,
                                                       PrimitiveType::TrianglesList,
                                                       &batch.triangle_indices)
                                   .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                ..Default::default()
            };

            target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &params).unwrap();
        }

        target.finish().unwrap();

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => (),
            }
        }
    }
}
<commit_msg>Fix projection<commit_after>extern crate euclid;
#[macro_use]
extern crate glium;

extern crate vitral;

use std::mem;
use std::rc::Rc;

use glium::{Surface, GlObject};
use glium::glutin;
use glium::index::PrimitiveType;
use euclid::{Rect, Point2D, Size2D};

use vitral::Context;

type GliumTexture = glium::texture::CompressedSrgbTexture2d;

struct Texture(GliumTexture);

impl PartialEq<Texture> for Texture {
    fn eq(&self, other: &Texture) -> bool {
        self.0.get_id() == other.0.get_id()
    }
}

// XXX: An exact copy of Vitral vertex struct, just so that I can derive a
// Glium vertex implementatino for it.
#[derive(Copy, Clone)]
pub struct GliumVertex {
    pub pos: [f32; 2],
    pub color: [f32; 4],
    pub tex: [f32; 2],
}
implement_vertex!(GliumVertex, pos, color, tex);

fn main() {
    use glium::DisplayBuild;

    // building the display, ie. the main object
    let display = glutin::WindowBuilder::new()
                      .build_glium()
                      .unwrap();

    let image = glium::texture::RawImage2d::from_raw_rgba(vec![0xffffffffu32], (1, 1));
    let opengl_texture = Rc::new(Texture(glium::texture::CompressedSrgbTexture2d::new(&display, image)
                                     .unwrap()));

    // compiling shaders and linking them together
    let program = program!(&display,
        150 => {
            vertex: "
                #version 150 core

                uniform mat4 matrix;

                in vec2 pos;
                in vec4 color;
                in vec2 tex;

                out vec4 vColor;
                out vec2 vTexcoord;

                void main() {
                    gl_Position = vec4(pos, 0.0, 1.0) * matrix;
                    vColor = color;
                    vTexcoord = tex;
                }
            ",

            fragment: "
                #version 150 core
                uniform sampler2D tex;
                in vec4 vColor;
                in vec2 vTexcoord;
                out vec4 f_color;

                void main() {
                    f_color = vColor * texture(tex, vTexcoord);
                }
            "
        },
    )
                      .unwrap();

    let mut context = Context::new(opengl_texture.clone());

    // the main loop
    loop {
        context.begin_frame();
        let area = Rect::new(Point2D::new(10.0, 10.0), Size2D::new(128.0, 128.0));
        context.fill_rect(area.inflate(2.0, 2.0), [0.0, 0.0, 0.0, 1.0]);
        context.fill_rect(area, [1.0, 0.0, 0.0, 1.0]);

        // drawing a frame

        let mut target = display.draw();
        target.clear_color(1.0, 1.0, 1.0, 0.0);
        let (w, h) = target.get_dimensions();

        for batch in context.end_frame() {
            // building the uniforms
            let uniforms = uniform! {
                matrix: [
                    [2.0 / w as f32, 0.0, 0.0, -1.0],
                    [0.0, -2.0 / h as f32, 0.0, 1.0],
                    [0.0, 0.0, 1.0, 0.0],
                    [0.0, 0.0, 0.0, 1.0f32]
                ],
                tex: &(*batch.texture).0,
            };

            let vertex_buffer = {
                glium::VertexBuffer::new(&display,
                                         // XXX: Have to do the unsafe switcheroo here to get a
                                         // vertex type with Glium traits derived for it.
                                         &unsafe {
                                             mem::transmute::<Vec<vitral::Vertex>,
                                                              Vec<GliumVertex>>(batch.vertices)
                                         })
                    .unwrap()
            };

            // building the index buffer
            let index_buffer = glium::IndexBuffer::new(&display,
                                                       PrimitiveType::TrianglesList,
                                                       &batch.triangle_indices)
                                   .unwrap();

            let params = glium::draw_parameters::DrawParameters {
                scissor: batch.clip.map(|clip| {
                    glium::Rect {
                        left: clip.origin.x as u32,
                        bottom: h - (clip.origin.y + clip.size.height) as u32,
                        width: clip.size.width as u32,
                        height: clip.size.height as u32,
                    }
                }),
                ..Default::default()
            };

            target.draw(&vertex_buffer, &index_buffer, &program, &uniforms, &params).unwrap();
        }

        target.finish().unwrap();

        // polling and handling the events received by the window
        for event in display.poll_events() {
            match event {
                glutin::Event::Closed => return,
                _ => (),
            }
        }
    }
}
<|endoftext|>


<commit_before>pub use self::close::close;
pub use self::data::data;
pub use self::init::init;
pub use self::status::Status;
use antidote::Mutex;
use std::collections::HashMap;

mod close;
mod data;
mod init;
mod status;

lazy_static! {
    pub static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}
<commit_msg>rearrange usage/mod defs<commit_after>mod close;
mod data;
mod init;
mod status;

pub use self::close::close;
pub use self::data::data;
pub use self::init::init;
pub use self::status::Status;
use antidote::Mutex;
use std::collections::HashMap;

lazy_static! {
    pub static ref MAP: Mutex<HashMap<u16, u16>> = Mutex::new(HashMap::new());
}
<|endoftext|>


<commit_before>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::elastic;
use crate::importer::Importer;
use crate::server::api;
use crate::server::session::Session;
use crate::sqlite::eventstore::SQLiteEventStore;
use serde_json::Value as JsonValue;
use std::sync::Arc;
use thiserror::Error;

type DateTime = chrono::DateTime<chrono::Utc>;

#[derive(Default, Debug)]
pub struct EventQueryParams {
    pub query_string: Option<String>,
    pub order: Option<String>,
    pub min_timestamp: Option<chrono::DateTime<chrono::Utc>>,
    pub max_timestamp: Option<chrono::DateTime<chrono::Utc>>,
    pub event_type: Option<String>,
    pub size: Option<u64>,
    pub sort_by: Option<String>,
}

pub enum Datastore {
    None,
    Elastic(crate::elastic::EventStore),
    SQLite(SQLiteEventStore),
}

#[derive(Error, Debug)]
pub enum DatastoreError {
    #[error("unimplemented")]
    Unimplemented,
    #[error("event not found")]
    EventNotFound,
    #[error("sqlite error: {0}")]
    SQLiteError(rusqlite::Error),
    #[error("generic datastore error")]
    GenericError(Box<dyn std::error::Error + Sync + Send>),
    #[error("elastic search error")]
    ElasticSearchError(String),
    #[error("elasticsearch: {0}")]
    ElasticError(elastic::ElasticError),
    #[error("failed to parse timestamp")]
    TimestampParseError(chrono::format::ParseError),
    #[error("failed to parse event")]
    EventParseError,
    #[error("failed to parse histogram interval: {0}")]
    HistogramIntervalParseError(String),
}

impl warp::reject::Reject for DatastoreError {}

impl From<DatastoreError> for warp::Rejection {
    fn from(err: DatastoreError) -> Self {
        warp::reject::custom(err)
    }
}

impl From<Box<dyn std::error::Error + Sync + Send>> for DatastoreError {
    fn from(err: Box<dyn std::error::Error + Sync + Send>) -> Self {
        DatastoreError::GenericError(err)
    }
}

impl From<chrono::format::ParseError> for DatastoreError {
    fn from(err: chrono::format::ParseError) -> Self {
        DatastoreError::TimestampParseError(err)
    }
}

#[allow(unreachable_patterns)]
impl Datastore {
    pub fn get_importer(&self) -> Option<Importer> {
        match self {
            Datastore::Elastic(ds) => Some(Importer::Elastic(ds.get_importer())),
            Datastore::SQLite(ds) => Some(Importer::SQLite(ds.get_importer())),
            _ => None,
        }
    }

    pub async fn archive_event_by_id(&self, event_id: String) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.archive_event_by_id(event_id).await,
            Datastore::SQLite(ds) => ds.archive_event_by_id(event_id).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn escalate_event_by_id(&self, event_id: String) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.escalate_event_by_id(event_id).await,
            Datastore::SQLite(ds) => ds.escalate_event_by_id(event_id).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn deescalate_event_by_id(&self, event_id: String) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.deescalate_event_by_id(event_id).await,
            Datastore::SQLite(ds) => ds.deescalate_event_by_id(event_id).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn get_event_by_id(
        &self,
        event_id: String,
    ) -> Result<Option<serde_json::Value>, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.get_event_by_id(event_id).await,
            Datastore::SQLite(ds) => ds.get_event_by_id(event_id).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn alert_query(
        &self,
        options: elastic::AlertQueryOptions,
    ) -> Result<serde_json::Value, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.alert_query(options).await,
            Datastore::SQLite(ds) => ds.alert_query(options).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn archive_by_alert_group(
        &self,
        alert_group: api::AlertGroupSpec,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.archive_by_alert_group(alert_group).await,
            Datastore::SQLite(ds) => ds.archive_by_alert_group(alert_group).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn escalate_by_alert_group(
        &self,
        alert_group: api::AlertGroupSpec,
        session: Arc<Session>,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.escalate_by_alert_group(alert_group, session).await,
            Datastore::SQLite(ds) => ds.escalate_by_alert_group(alert_group).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn deescalate_by_alert_group(
        &self,
        alert_group: api::AlertGroupSpec,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.deescalate_by_alert_group(alert_group).await,
            Datastore::SQLite(ds) => ds.deescalate_by_alert_group(alert_group).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn comment_by_alert_group(
        &self,
        alert_group: api::AlertGroupSpec,
        comment: String,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.comment_by_alert_group(alert_group, comment).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn event_query(
        &self,
        params: EventQueryParams,
    ) -> Result<serde_json::Value, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.event_query(params).await,
            Datastore::SQLite(ds) => ds.event_query(params).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn comment_event_by_id(
        &self,
        event_id: String,
        comment: String,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.comment_event_by_id(event_id, comment).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn histogram(
        &self,
        params: HistogramParameters,
    ) -> Result<serde_json::Value, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.histogram(params).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn agg(&self, params: AggParameters) -> Result<JsonValue, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.agg(params).await,
            //Datastore::SQLite(ds) => ds.agg(params).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn flow_histogram(
        &self,
        params: FlowHistogramParameters,
    ) -> Result<JsonValue, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.flow_histogram(params).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }
}

#[derive(Default, Debug)]
pub struct HistogramParameters {
    pub min_timestamp: Option<chrono::DateTime<chrono::Utc>>,
    pub max_timestamp: Option<chrono::DateTime<chrono::Utc>>,
    pub interval: Option<HistogramInterval>,
    pub event_type: Option<String>,
    pub dns_type: Option<String>,
    pub address_filter: Option<String>,
    pub query_string: Option<String>,
    pub sensor_name: Option<String>,
}

#[derive(Debug, PartialEq)]
pub enum HistogramInterval {
    Minute,
    Hour,
    Day,
}

impl HistogramInterval {
    pub fn from_str(s: &str) -> Result<HistogramInterval, DatastoreError> {
        match s {
            "minute" => Ok(HistogramInterval::Minute),
            "hour" => Ok(HistogramInterval::Hour),
            "day" => Ok(HistogramInterval::Day),
            _ => Err(DatastoreError::HistogramIntervalParseError(s.to_string())),
        }
    }
}

#[derive(Default, Debug)]
pub struct AggParameters {
    pub event_type: Option<String>,
    pub dns_type: Option<String>,
    pub query_string: Option<String>,
    pub address_filter: Option<String>,
    pub min_timestamp: Option<DateTime>,
    pub agg: String,
    pub size: u64,
}

pub struct FlowHistogramParameters {
    pub mints: Option<DateTime>,
    pub interval: Option<String>,
    pub query_string: Option<String>,
}

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

    #[test]
    fn test_histogram_interval_from_str() {
        let r = HistogramInterval::from_str("minute");
        assert!(r.is_ok());
        assert_eq!(r.unwrap(), HistogramInterval::Minute);
        assert!(HistogramInterval::from_str("bad").is_err());
    }
}
<commit_msg>elastic: print underlying error for ElasticSearchError<commit_after>// Copyright (C) 2020 Jason Ish
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use crate::elastic;
use crate::importer::Importer;
use crate::server::api;
use crate::server::session::Session;
use crate::sqlite::eventstore::SQLiteEventStore;
use serde_json::Value as JsonValue;
use std::sync::Arc;
use thiserror::Error;

type DateTime = chrono::DateTime<chrono::Utc>;

#[derive(Default, Debug)]
pub struct EventQueryParams {
    pub query_string: Option<String>,
    pub order: Option<String>,
    pub min_timestamp: Option<chrono::DateTime<chrono::Utc>>,
    pub max_timestamp: Option<chrono::DateTime<chrono::Utc>>,
    pub event_type: Option<String>,
    pub size: Option<u64>,
    pub sort_by: Option<String>,
}

pub enum Datastore {
    None,
    Elastic(crate::elastic::EventStore),
    SQLite(SQLiteEventStore),
}

#[derive(Error, Debug)]
pub enum DatastoreError {
    #[error("unimplemented")]
    Unimplemented,
    #[error("event not found")]
    EventNotFound,
    #[error("sqlite error: {0}")]
    SQLiteError(rusqlite::Error),
    #[error("generic datastore error")]
    GenericError(Box<dyn std::error::Error + Sync + Send>),
    #[error("elasticsearch: {0}")]
    ElasticSearchError(String),
    #[error("elasticsearch: {0}")]
    ElasticError(elastic::ElasticError),
    #[error("failed to parse timestamp")]
    TimestampParseError(chrono::format::ParseError),
    #[error("failed to parse event")]
    EventParseError,
    #[error("failed to parse histogram interval: {0}")]
    HistogramIntervalParseError(String),
}

impl warp::reject::Reject for DatastoreError {}

impl From<DatastoreError> for warp::Rejection {
    fn from(err: DatastoreError) -> Self {
        warp::reject::custom(err)
    }
}

impl From<Box<dyn std::error::Error + Sync + Send>> for DatastoreError {
    fn from(err: Box<dyn std::error::Error + Sync + Send>) -> Self {
        DatastoreError::GenericError(err)
    }
}

impl From<chrono::format::ParseError> for DatastoreError {
    fn from(err: chrono::format::ParseError) -> Self {
        DatastoreError::TimestampParseError(err)
    }
}

#[allow(unreachable_patterns)]
impl Datastore {
    pub fn get_importer(&self) -> Option<Importer> {
        match self {
            Datastore::Elastic(ds) => Some(Importer::Elastic(ds.get_importer())),
            Datastore::SQLite(ds) => Some(Importer::SQLite(ds.get_importer())),
            _ => None,
        }
    }

    pub async fn archive_event_by_id(&self, event_id: String) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.archive_event_by_id(event_id).await,
            Datastore::SQLite(ds) => ds.archive_event_by_id(event_id).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn escalate_event_by_id(&self, event_id: String) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.escalate_event_by_id(event_id).await,
            Datastore::SQLite(ds) => ds.escalate_event_by_id(event_id).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn deescalate_event_by_id(&self, event_id: String) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.deescalate_event_by_id(event_id).await,
            Datastore::SQLite(ds) => ds.deescalate_event_by_id(event_id).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn get_event_by_id(
        &self,
        event_id: String,
    ) -> Result<Option<serde_json::Value>, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.get_event_by_id(event_id).await,
            Datastore::SQLite(ds) => ds.get_event_by_id(event_id).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn alert_query(
        &self,
        options: elastic::AlertQueryOptions,
    ) -> Result<serde_json::Value, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.alert_query(options).await,
            Datastore::SQLite(ds) => ds.alert_query(options).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn archive_by_alert_group(
        &self,
        alert_group: api::AlertGroupSpec,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.archive_by_alert_group(alert_group).await,
            Datastore::SQLite(ds) => ds.archive_by_alert_group(alert_group).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn escalate_by_alert_group(
        &self,
        alert_group: api::AlertGroupSpec,
        session: Arc<Session>,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.escalate_by_alert_group(alert_group, session).await,
            Datastore::SQLite(ds) => ds.escalate_by_alert_group(alert_group).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn deescalate_by_alert_group(
        &self,
        alert_group: api::AlertGroupSpec,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.deescalate_by_alert_group(alert_group).await,
            Datastore::SQLite(ds) => ds.deescalate_by_alert_group(alert_group).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn comment_by_alert_group(
        &self,
        alert_group: api::AlertGroupSpec,
        comment: String,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.comment_by_alert_group(alert_group, comment).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn event_query(
        &self,
        params: EventQueryParams,
    ) -> Result<serde_json::Value, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.event_query(params).await,
            Datastore::SQLite(ds) => ds.event_query(params).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn comment_event_by_id(
        &self,
        event_id: String,
        comment: String,
    ) -> Result<(), DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.comment_event_by_id(event_id, comment).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn histogram(
        &self,
        params: HistogramParameters,
    ) -> Result<serde_json::Value, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.histogram(params).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn agg(&self, params: AggParameters) -> Result<JsonValue, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.agg(params).await,
            //Datastore::SQLite(ds) => ds.agg(params).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }

    pub async fn flow_histogram(
        &self,
        params: FlowHistogramParameters,
    ) -> Result<JsonValue, DatastoreError> {
        match self {
            Datastore::Elastic(ds) => ds.flow_histogram(params).await,
            _ => Err(DatastoreError::Unimplemented),
        }
    }
}

#[derive(Default, Debug)]
pub struct HistogramParameters {
    pub min_timestamp: Option<chrono::DateTime<chrono::Utc>>,
    pub max_timestamp: Option<chrono::DateTime<chrono::Utc>>,
    pub interval: Option<HistogramInterval>,
    pub event_type: Option<String>,
    pub dns_type: Option<String>,
    pub address_filter: Option<String>,
    pub query_string: Option<String>,
    pub sensor_name: Option<String>,
}

#[derive(Debug, PartialEq)]
pub enum HistogramInterval {
    Minute,
    Hour,
    Day,
}

impl HistogramInterval {
    pub fn from_str(s: &str) -> Result<HistogramInterval, DatastoreError> {
        match s {
            "minute" => Ok(HistogramInterval::Minute),
            "hour" => Ok(HistogramInterval::Hour),
            "day" => Ok(HistogramInterval::Day),
            _ => Err(DatastoreError::HistogramIntervalParseError(s.to_string())),
        }
    }
}

#[derive(Default, Debug)]
pub struct AggParameters {
    pub event_type: Option<String>,
    pub dns_type: Option<String>,
    pub query_string: Option<String>,
    pub address_filter: Option<String>,
    pub min_timestamp: Option<DateTime>,
    pub agg: String,
    pub size: u64,
}

pub struct FlowHistogramParameters {
    pub mints: Option<DateTime>,
    pub interval: Option<String>,
    pub query_string: Option<String>,
}

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

    #[test]
    fn test_histogram_interval_from_str() {
        let r = HistogramInterval::from_str("minute");
        assert!(r.is_ok());
        assert_eq!(r.unwrap(), HistogramInterval::Minute);
        assert!(HistogramInterval::from_str("bad").is_err());
    }
}
<|endoftext|>


<commit_before>#![crate_name = "echo"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

use std::str::from_utf8;

#[path = "../common/util.rs"]
mod util;

#[allow(dead_code)]
static NAME: &'static str = "echo";
static VERSION: &'static str = "1.0.0";

#[derive(Clone)]
struct EchoOptions {
    newline: bool,
    escape: bool
}

#[inline(always)]
fn to_char(bytes: &Vec<u8>, base: u32) -> char {
    usize::from_str_radix(from_utf8(bytes.as_ref()).unwrap(), base).unwrap() as u8 as char
}

#[inline(always)]
fn isxdigit(c: u8) -> bool {
    match c as char {
        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
        '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' => true,
        _ => false
    }
}

#[inline(always)]
fn isodigit(c: u8) -> bool {
    match c as char {
        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => true,
        _ => false
    }
}

fn convert_str(string: &[u8], index: usize, base: u32) -> (char, usize) {
    let (max_digits, is_legal_digit) : (usize, fn(u8) -> bool) = match base {
        8 => (3, isodigit),
        16 => (2, isxdigit),
        _ => panic!(),
    };

    let mut bytes = vec!();
    for offset in (0usize .. max_digits) {
        if string.len() <= index + offset as usize {
            break;
        }
        let c = string[index + offset as usize];
        if is_legal_digit(c) {
            bytes.push(c as u8);
        } else {
            break;
        }
    }

    if bytes.len() == 0 {
        (' ', 0)
    } else {
        (to_char(&bytes, base), bytes.len())
    }
}

fn parse_options(args: Vec<String>, options: &mut EchoOptions) -> Option<Vec<String>> {
    let mut echo_args = vec!();
    'argloop: for arg in args.into_iter().skip(1) {
        match arg.as_ref() {
            "--help" | "-h" => {
                print_help();
                return None;
            }
            "--version" | "-V" => {
                print_version();
                return None;
            }
            "-n" => options.newline = true,
            "-e" => options.escape = true,
            "-E" => options.escape = false,
            _ => {
                if arg.len() > 1 && arg.chars().next().unwrap_or('_') == '-' {
                    let mut newopts = options.clone();
                    for ch in arg.chars().skip(1) {
                        match ch {
                            'h' => {
                                print_help();
                                return None;
                            }
                            'V' => {
                                print_version();
                                return None;
                            }
                            'n' => newopts.newline = true,
                            'e' => newopts.escape = true,
                            'E' => newopts.escape = false,
                            _ => {
                                echo_args.push(arg.clone());
                                continue 'argloop;
                            }
                        }
                    }
                    *options = newopts;
                } else {
                    echo_args.push(arg);
                }
            }
        }
    }
    Some(echo_args)
}

fn print_help() {
    let mut opts = getopts::Options::new();
    opts.optflag("n", "", "do not output the trailing newline");
    opts.optflag("e", "", "enable interpretation of backslash escapes");
    opts.optflag("E", "", "disable interpretation of backslash escapes (default)");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let msg = format!("{0} {1} - display a line of text

Usage:
  {0} [SHORT-OPTION]... [STRING]...
  {0} LONG-OPTION

Echo the STRING(s) to standard output.
If -e is in effect, the following sequences are recognized:

\\\\      backslash
\\a      alert (BEL)
\\b      backspace
\\c      produce no further output
\\e      escape
\\f      form feed
\\n      new line
\\r      carriage return
\\t      horizontal tab
\\v      vertical tab
\\0NNN   byte with octal value NNN (1 to 3 digits)
\\xHH    byte with hexadecimal value HH (1 to 2 digits)", NAME, VERSION);

    print!("{}", opts.usage(&msg));
}

fn print_version() {
    println!("{} {}", NAME, VERSION);
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut options = EchoOptions {
        newline: false,
        escape: false
    };

    let free = match parse_options(args, &mut options) {
        Some(vec) => vec,
        None => return 0
    };

    if !free.is_empty() {
        let string = free.connect(" ");
        if options.escape {
            let mut prev_was_slash = false;
            let mut iter = string.chars().enumerate();
            loop {
                match iter.next() {
                    Some((index, c)) => {
                        if !prev_was_slash {
                            if c != '\\' {
                                print!("{}", c);
                            } else {
                                prev_was_slash = true;
                            }
                        } else {
                            prev_was_slash = false;
                            match c {
                                '\\' => print!("\\"),
                                'a' => print!("\x07"),
                                'b' => print!("\x08"),
                                'c' => break,
                                'e' => print!("\x1B"),
                                'f' => print!("\x0C"),
                                'n' => print!("\n"),
                                'r' => print!("\r"),
                                't' => print!("\t"),
                                'v' => print!("\x0B"),
                                'x' => {
                                    let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 16);
                                    if num_char_used == 0 {
                                        print!("\\x");
                                    } else {
                                        print!("{}", c);
                                        for _ in (0 .. num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                },
                                '0' => {
                                    let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 8);
                                    if num_char_used == 0 {
                                        print!("\0");
                                    } else {
                                        print!("{}", c);
                                        for _ in (0 .. num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                }
                                _ => {
                                    let (esc_c, num_char_used) = convert_str(string.as_bytes(), index, 8);
                                    if num_char_used == 0 {
                                        print!("\\{}", c);
                                    } else {
                                        print!("{}", esc_c);
                                        for _ in (1 .. num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                }
                            }
                        }
                    }
                    None => break
                }
            }
        } else {
            print!("{}", string);
        }
    }

    if !options.newline {
        println!("")
    }

    0
}
<commit_msg>Fix failure to print stdout for echo.<commit_after>#![crate_name = "echo"]

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Derek Chiang <derekchiang93@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern crate getopts;
extern crate libc;

use std::io::{stdout, Write};
use std::str::from_utf8;

#[path = "../common/util.rs"]
mod util;

#[allow(dead_code)]
static NAME: &'static str = "echo";
static VERSION: &'static str = "1.0.0";

#[derive(Clone)]
struct EchoOptions {
    newline: bool,
    escape: bool
}

#[inline(always)]
fn to_char(bytes: &Vec<u8>, base: u32) -> char {
    usize::from_str_radix(from_utf8(bytes.as_ref()).unwrap(), base).unwrap() as u8 as char
}

#[inline(always)]
fn isxdigit(c: u8) -> bool {
    match c as char {
        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' |
        '8' | '9' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F' => true,
        _ => false
    }
}

#[inline(always)]
fn isodigit(c: u8) -> bool {
    match c as char {
        '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' => true,
        _ => false
    }
}

fn convert_str(string: &[u8], index: usize, base: u32) -> (char, usize) {
    let (max_digits, is_legal_digit) : (usize, fn(u8) -> bool) = match base {
        8 => (3, isodigit),
        16 => (2, isxdigit),
        _ => panic!(),
    };

    let mut bytes = vec!();
    for offset in (0usize .. max_digits) {
        if string.len() <= index + offset as usize {
            break;
        }
        let c = string[index + offset as usize];
        if is_legal_digit(c) {
            bytes.push(c as u8);
        } else {
            break;
        }
    }

    if bytes.len() == 0 {
        (' ', 0)
    } else {
        (to_char(&bytes, base), bytes.len())
    }
}

fn parse_options(args: Vec<String>, options: &mut EchoOptions) -> Option<Vec<String>> {
    let mut echo_args = vec!();
    'argloop: for arg in args.into_iter().skip(1) {
        match arg.as_ref() {
            "--help" | "-h" => {
                print_help();
                return None;
            }
            "--version" | "-V" => {
                print_version();
                return None;
            }
            "-n" => options.newline = true,
            "-e" => options.escape = true,
            "-E" => options.escape = false,
            _ => {
                if arg.len() > 1 && arg.chars().next().unwrap_or('_') == '-' {
                    let mut newopts = options.clone();
                    for ch in arg.chars().skip(1) {
                        match ch {
                            'h' => {
                                print_help();
                                return None;
                            }
                            'V' => {
                                print_version();
                                return None;
                            }
                            'n' => newopts.newline = true,
                            'e' => newopts.escape = true,
                            'E' => newopts.escape = false,
                            _ => {
                                echo_args.push(arg.clone());
                                continue 'argloop;
                            }
                        }
                    }
                    *options = newopts;
                } else {
                    echo_args.push(arg);
                }
            }
        }
    }
    Some(echo_args)
}

fn print_help() {
    let mut opts = getopts::Options::new();
    opts.optflag("n", "", "do not output the trailing newline");
    opts.optflag("e", "", "enable interpretation of backslash escapes");
    opts.optflag("E", "", "disable interpretation of backslash escapes (default)");
    opts.optflag("h", "help", "display this help and exit");
    opts.optflag("V", "version", "output version information and exit");

    let msg = format!("{0} {1} - display a line of text

Usage:
  {0} [SHORT-OPTION]... [STRING]...
  {0} LONG-OPTION

Echo the STRING(s) to standard output.
If -e is in effect, the following sequences are recognized:

\\\\      backslash
\\a      alert (BEL)
\\b      backspace
\\c      produce no further output
\\e      escape
\\f      form feed
\\n      new line
\\r      carriage return
\\t      horizontal tab
\\v      vertical tab
\\0NNN   byte with octal value NNN (1 to 3 digits)
\\xHH    byte with hexadecimal value HH (1 to 2 digits)", NAME, VERSION);

    print!("{}", opts.usage(&msg));
}

fn print_version() {
    println!("{} {}", NAME, VERSION);
}

pub fn uumain(args: Vec<String>) -> i32 {
    let mut options = EchoOptions {
        newline: false,
        escape: false
    };

    let free = match parse_options(args, &mut options) {
        Some(vec) => vec,
        None => return 0
    };

    if !free.is_empty() {
        let string = free.connect(" ");
        if options.escape {
            let mut prev_was_slash = false;
            let mut iter = string.chars().enumerate();
            loop {
                match iter.next() {
                    Some((index, c)) => {
                        if !prev_was_slash {
                            if c != '\\' {
                                print!("{}", c);
                            } else {
                                prev_was_slash = true;
                            }
                        } else {
                            prev_was_slash = false;
                            match c {
                                '\\' => print!("\\"),
                                'a' => print!("\x07"),
                                'b' => print!("\x08"),
                                'c' => break,
                                'e' => print!("\x1B"),
                                'f' => print!("\x0C"),
                                'n' => print!("\n"),
                                'r' => print!("\r"),
                                't' => print!("\t"),
                                'v' => print!("\x0B"),
                                'x' => {
                                    let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 16);
                                    if num_char_used == 0 {
                                        print!("\\x");
                                    } else {
                                        print!("{}", c);
                                        for _ in (0 .. num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                },
                                '0' => {
                                    let (c, num_char_used) = convert_str(string.as_bytes(), index + 1, 8);
                                    if num_char_used == 0 {
                                        print!("\0");
                                    } else {
                                        print!("{}", c);
                                        for _ in (0 .. num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                }
                                _ => {
                                    let (esc_c, num_char_used) = convert_str(string.as_bytes(), index, 8);
                                    if num_char_used == 0 {
                                        print!("\\{}", c);
                                    } else {
                                        print!("{}", esc_c);
                                        for _ in (1 .. num_char_used) {
                                            iter.next(); // consume used characters
                                        }
                                    }
                                }
                            }
                        }
                    }
                    None => break
                }
            }
        } else {
            print!("{}", string);
        }
    }

    if options.newline {
        let _ = stdout().flush();
    } else {
        println!("")
    }

    0
}
<|endoftext|>


<commit_before>//! Amazon MWS Feeds API - Version 2010-10-01
//!
//! [Documentation](http://docs.developer.amazonservices.com/en_CA/feeds/Feeds_Overview.html)

use chrono::{DateTime, Utc};
use client::{Client, Method, Response, ContentType};
use xmlhelper::{encode, decode};
use std::io::{Read, Write};
use super::types::ToIso8601;

mod inventory;

error_chain! {
  links {
    Client(super::client::Error, super::client::ErrorKind);
    Decode(decode::Error, decode::ErrorKind);
  }

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

static PATH: &'static str = "/";
static VERSION: &'static str = "2009-01-01";

/// Enumerates all the feed types that are available through the Feeds API section.
string_map_enum! {
  pub enum FeedType {
    Product = "_POST_PRODUCT_DATA_",
    Inventory = "_POST_INVENTORY_AVAILABILITY_DATA_",
    Overrides = "_POST_PRODUCT_OVERRIDES_DATA_",
    Pricing = "_POST_PRODUCT_PRICING_DATA_",
    ProductImages = "_POST_PRODUCT_IMAGE_DATA_",
    Relationships = "_POST_PRODUCT_RELATIONSHIP_DATA_",
    FlatFileInventoryLoader = "_POST_FLAT_FILE_INVLOADER_DATA_",
    FlatFileListings = "_POST_FLAT_FILE_LISTINGS_DATA_",
    FlatFileBookLoader = "_POST_FLAT_FILE_BOOKLOADER_DATA_",
    FlatFileMusicLoader = "_POST_FLAT_FILE_CONVERGENCE_LISTINGS_DATA_",
    // FlatFileVideoLoader = "_POST_FLAT_FILE_LISTINGS_DATA_",
    FlatFilePriceAndQuantityUpdate = "_POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_",
    UIEEInventory = "_POST_UIEE_BOOKLOADER_DATA_",
    AutomotivePartFinder = "_POST_STD_ACES_DATA_",
  }
}

/// The optional OperationType element can be used to specify the type of operation (Update, Delete
/// or PartialUpdate) to be performed on the data. The OperationType is only applicable to productrelated
/// feeds (Product, Inventory, Price, etc) and will be ignored for non-applicable feeds.
#[derive(Debug, PartialEq)]
pub enum OperationType {
  /// All specified information overwrites any existing information. Any
  /// unspecified information is erased.
  Update,

  /// All information is removed
  Delete,

  /// For Product feeds only: If you use PartialUpdate for a Product feed, all specified
  /// information overwrites any existing information, but unspecified information is
  /// unaffected. Caution: This operation type is only valid for Product feeds. If this operation
  /// type is used for any other feed type, such as Inventory and Price feeds, unpredictable
  /// data loss can occur.
  PartialUpdate,
}

pub trait Message {
  fn get_message_type() -> &'static str;
}

#[allow(non_snake_case)]
#[derive(Debug, PartialEq)]
pub struct EnvelopeMessage<M: Message> {
  pub data: M,
  pub operation_type: Option<OperationType>,
}

#[allow(non_snake_case)]
#[derive(Debug, PartialEq)]
pub struct Envelope<M: Message> {
  pub MerchantIdentifier: String,
  messages: Vec<EnvelopeMessage<M>>,
}

impl<M: Message> Envelope<M> {
  pub fn new(merchant_identifier: String) -> Self {
    Envelope::<M> {
      MerchantIdentifier: merchant_identifier,
      messages: vec![],
    }
  }

  pub fn add_message(&mut self, m: M, operation_type: Option<OperationType>) -> &mut Self {
    self.messages.push(EnvelopeMessage::<M> {
      data: m,
      operation_type: operation_type,
    });
    self
  }

  pub fn write_envelope_xml<W: encode::XmlEventWriter, F: FnMut(&mut W) -> encode::Result<()>>(&self, w: &mut W, mut f: F) -> encode::Result<()> {
    w.write(
      encode::XmlEvent::start_element("AmazonEnvelope")
        .ns("xsi", "http://www.w3.org/2001/XMLSchema-instance")
        .attr("xsi:noNamespaceSchemaLocation", "amznenvelope.xsd")
        .into()
    )?;

    let mid: &str = self.MerchantIdentifier.as_ref();
    let message_type: &str = M::get_message_type();

    write_xml!(w,
      Header[][
        DocumentVersion[]["1.01"]
        MerchantIdentifier[][mid]
      ]
      MessageType[][message_type]
      Messages[][
        [{ f(w) }]
      ]
    )?;

    w.write(
      encode::XmlEvent::end_element().into()
    )
  }
}

impl<W: encode::XmlEventWriter> encode::XmlWrite<W> for Envelope<inventory::InventoryMessage> {
  fn write_xml(&self, w: &mut W) -> encode::Result<()> {
    self.write_envelope_xml(w, |w: &mut W| {
      for message in self.messages.iter() {
        let sku: &str = message.data.SKU.as_ref();
        let quantity = message.data.Quantity.to_string();
        let fulfillment_latency = message.data.FulfillmentLatency.to_string();
        write_xml!(w,
          Message[][
            SKU[][sku]
            Quantity[][(&quantity)]
            FulfillmentLatency[][(&fulfillment_latency)]
          ]
        )?;
      }
      Ok(())
    })
  }
}

#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct SubmitFeedParameters {
  pub FeedType: String,

  pub MarketplaceIdList: Option<Vec<String>>,
  pub PurgeAndReplace: Option<bool>,
}

impl Into<Vec<(String, String)>> for SubmitFeedParameters {
  fn into(self) -> Vec<(String, String)> {
    let mut result = vec![];

    result.push(("FeedType".to_owned(), self.FeedType));

    if let Some(list) = self.MarketplaceIdList {
      for (i, id) in list.into_iter().enumerate() {
        result.push((format!("MarketplaceIdList.Id.{}", i + 1), id));
      }
    }

    if let Some(v) = self.PurgeAndReplace {
      result.push(("PurgeAndReplace".to_owned(), if v { "true".to_owned() } else { "false".to_owned() }))
    }

    result
  }
}

#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct SubmitFeedResponse {
  pub RequestId: String,
  pub FeedType: String,
  pub FeedSubmissionId: String,
  pub SubmittedDate: Option<DateTime<Utc>>,
  pub FeedProcessingStatus: String,
}

impl<S: decode::XmlEventStream> decode::FromXMLStream<S> for SubmitFeedResponse {
  fn from_xml(s: &mut S) -> decode::Result<SubmitFeedResponse> {
    use self::decode::{start_document, element, fold_elements, characters};
    start_document(s)?;
    element(s, "SubmitFeedResponse", |s| {
      fold_elements(s, SubmitFeedResponse::default(), |s, response| {
        match s.local_name() {
          "FeedSubmissionInfo" => {
            fold_elements(s, (), |s, _| {
              match s.local_name() {
                "FeedSubmissionId" => {
                  response.FeedSubmissionId = characters(s)?;
                },
                "FeedType" => {
                  response.FeedType = characters(s)?;
                },
                "SubmittedDate" => {
                  response.SubmittedDate = Some(characters(s)?);
                },
                "FeedProcessingStatus" => {
                  response.FeedProcessingStatus = characters(s)?;
                },
                _ => {},
              }
              Ok(())
            })
          },
          "ResponseMetadata" => {
            response.RequestId = element(s, "RequestId", |s| {
              characters(s)
            })?;
            Ok(())
          },
          _ => { Ok(()) }
        }
      })
    })
  }
}

#[allow(non_snake_case)]
pub fn SubmitFeed<R>(client: &Client, parameters: SubmitFeedParameters, content: R, content_md5: String, content_type: ContentType) -> Result<Response<SubmitFeedResponse>>
  where R: Read + Send + 'static
{
  client.request_xml_with_body(Method::Post, PATH, VERSION, "SubmitFeed", parameters, content, content_md5, content_type)
    .map_err(Into::into)
}

#[allow(non_snake_case)]
pub fn GetFeedSubmissionResult<W: Write>(client: &Client, FeedSubmissionId: String, out: &mut W) -> Result<u64> {
  let params = vec![("FeedSubmissionId".to_string(), FeedSubmissionId)];
  let mut resp = client.request(Method::Post, PATH, VERSION, "GetFeedSubmissionResult", params)?;
  let size = ::std::io::copy(&mut resp, out)?;
  Ok(size)
}

/// Parameters for `GetFeedSubmissionList`
#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct GetFeedSubmissionListParameters {
  pub FeedSubmissionIdList: Option<Vec<String>>,
  pub MaxCount: Option<i32>,
  pub FeedTypeList: Option<Vec<String>>,
  pub FeedProcessingStatusList: Option<Vec<String>>,
  pub SubmittedFromDate: Option<DateTime<Utc>>,
  pub SubmittedToDate: Option<DateTime<Utc>>,
}

impl Into<Vec<(String, String)>> for GetFeedSubmissionListParameters {
  fn into(self) -> Vec<(String, String)> {
    let mut result = vec![];
    if let Some(list) = self.FeedSubmissionIdList {
      for (i, id) in list.into_iter().enumerate() {
        result.push((format!("FeedSubmissionIdList.Id.{}", i + 1), id));
      }
    }

    if let Some(v) = self.MaxCount {
      result.push(("MaxCount".to_string(), v.to_string()));
    }

    if let Some(list) = self.FeedTypeList {
      for (i, v) in list.into_iter().enumerate() {
        result.push((format!("FeedTypeList.Type.{}", i + 1), v));
      }
    }

    if let Some(list) = self.FeedProcessingStatusList {
      for (i, v) in list.into_iter().enumerate() {
        result.push((format!("FeedProcessingStatusList.Status.{}", i + 1), v));
      }
    }

    if let Some(date) = self.SubmittedFromDate {
      result.push(("SubmittedFromDate".to_string(), date.to_iso8601()));
    }

    if let Some(date) = self.SubmittedToDate {
      result.push(("SubmittedToDate".to_string(), date.to_iso8601()));
    }

    result
  }
}

#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct FeedSubmissionInfo {
  pub FeedProcessingStatus: String,
  pub FeedType: String,
  pub FeedSubmissionId: String,
  pub StartedProcessingDate: Option<DateTime<Utc>>,
  pub SubmittedDate: Option<DateTime<Utc>>,
  pub CompletedProcessingDate: Option<DateTime<Utc>>,
}

#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct GetFeedSubmissionListResponse {
  pub RequestId: String,
  pub FeedSubmissionInfo: Vec<FeedSubmissionInfo>,
  pub NextToken: Option<String>,
}

impl<S: decode::XmlEventStream> decode::FromXMLStream<S> for GetFeedSubmissionListResponse {
  fn from_xml(s: &mut S) -> decode::Result<GetFeedSubmissionListResponse> {
    use self::decode::{start_document, element, fold_elements, characters};
    start_document(s)?;
    element(s, vec!["GetFeedSubmissionListResponse", "GetFeedSubmissionListByNextTokenResponse"], |s| {
      fold_elements(s, GetFeedSubmissionListResponse::default(), |s, response| {
        match s.local_name() {
          "GetFeedSubmissionListResult" | "GetFeedSubmissionListByNextTokenResult" => {
            fold_elements(s, (), |s, _| {
              match s.local_name() {
                "FeedSubmissionInfo" => {
                  response.FeedSubmissionInfo.push(fold_elements(s, FeedSubmissionInfo::default(), |s, item| {
                    match s.local_name() {
                      "FeedProcessingStatus" => {
                        item.FeedProcessingStatus = characters(s)?;
                      },
                      "FeedType" => {
                        item.FeedType = characters(s)?;
                      },
                      "FeedSubmissionId" => {
                        item.FeedSubmissionId = characters(s)?;
                      },
                      "StartedProcessingDate" => {
                        item.StartedProcessingDate = Some(characters(s)?);
                      },
                      "SubmittedDate" => {
                        item.SubmittedDate = Some(characters(s)?);
                      },
                      "CompletedProcessingDate" => {
                        item.CompletedProcessingDate = Some(characters(s)?);
                      },
                      _ => {}
                    }
                    Ok(())
                  })?);
                },
                "NextToken" => {
                  response.NextToken = Some(characters(s)?);
                },
                _ => {},
              }
              Ok(())
            })
          },
          "ResponseMetadata" => {
            response.RequestId = element(s, "RequestId", |s| {
              characters(s)
            })?;
            Ok(())
          },
          _ => { Ok(()) }
        }
      })
    })
  }
}

#[allow(non_snake_case)]
pub fn GetFeedSubmissionList(client: &Client, parameters: GetFeedSubmissionListParameters) -> Result<Response<GetFeedSubmissionListResponse>> {
  client.request_xml(Method::Post, PATH, VERSION, "GetFeedSubmissionList", parameters).map_err(|err| err.into())
}

#[allow(non_snake_case)]
pub fn GetFeedSubmissionListByNextToken(client: &Client, next_token: String) -> Result<Response<GetFeedSubmissionListResponse>> {
  let params = vec![
    ("NextToken".to_string(), next_token)
  ];
  client.request_xml(Method::Post, PATH, VERSION, "GetFeedSubmissionListByNextToken", params).map_err(|err| err.into())
}

#[cfg(test)]
mod tests {
  use super::*;
  use xmlhelper::encode::{EventWriter, EmitterConfig};
  use xmlhelper::encode::XmlWrite;

  #[test]
  fn test_envelope_write_xml() {
    let mut writer = EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));

    {
      let w = &mut writer;
      let mut e = Envelope::<inventory::InventoryMessage>::new("1234567890".to_owned());
      e.add_message(inventory::InventoryMessage {
        SKU: "p1".to_owned(),
        Quantity: 100,
        FulfillmentLatency: 0,
      }, Some(OperationType::PartialUpdate))
      .add_message(inventory::InventoryMessage {
        SKU: "p2".to_owned(),
        Quantity: 200,
        FulfillmentLatency: 0,
      }, Some(OperationType::PartialUpdate));
      e.write_xml(w).unwrap();
    }

    let xml = String::from_utf8(writer.into_inner()).unwrap();
    assert_eq!(xml, r#"<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amznenvelope.xsd">
  <Header>
    <DocumentVersion>1.01</DocumentVersion>
    <MerchantIdentifier>1234567890</MerchantIdentifier>
  </Header>
  <MessageType>Inventory</MessageType>
  <Messages>
    <Message>
      <SKU>p1</SKU>
      <Quantity>100</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
    <Message>
      <SKU>p2</SKU>
      <Quantity>200</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
  </Messages>
</AmazonEnvelope>"#);
  }
}<commit_msg>SubmitFeed accepts string as content type<commit_after>//! Amazon MWS Feeds API - Version 2010-10-01
//!
//! [Documentation](http://docs.developer.amazonservices.com/en_CA/feeds/Feeds_Overview.html)

use chrono::{DateTime, Utc};
use client::{Client, Method, Response, ContentType};
use xmlhelper::{encode, decode};
use std::io::{Read, Write};
use super::types::ToIso8601;

mod inventory;

error_chain! {
  links {
    Client(super::client::Error, super::client::ErrorKind);
    Decode(decode::Error, decode::ErrorKind);
  }

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

static PATH: &'static str = "/";
static VERSION: &'static str = "2009-01-01";

/// Enumerates all the feed types that are available through the Feeds API section.
string_map_enum! {
  pub enum FeedType {
    Product = "_POST_PRODUCT_DATA_",
    Inventory = "_POST_INVENTORY_AVAILABILITY_DATA_",
    Overrides = "_POST_PRODUCT_OVERRIDES_DATA_",
    Pricing = "_POST_PRODUCT_PRICING_DATA_",
    ProductImages = "_POST_PRODUCT_IMAGE_DATA_",
    Relationships = "_POST_PRODUCT_RELATIONSHIP_DATA_",
    FlatFileInventoryLoader = "_POST_FLAT_FILE_INVLOADER_DATA_",
    FlatFileListings = "_POST_FLAT_FILE_LISTINGS_DATA_",
    FlatFileBookLoader = "_POST_FLAT_FILE_BOOKLOADER_DATA_",
    FlatFileMusicLoader = "_POST_FLAT_FILE_CONVERGENCE_LISTINGS_DATA_",
    // FlatFileVideoLoader = "_POST_FLAT_FILE_LISTINGS_DATA_",
    FlatFilePriceAndQuantityUpdate = "_POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA_",
    UIEEInventory = "_POST_UIEE_BOOKLOADER_DATA_",
    AutomotivePartFinder = "_POST_STD_ACES_DATA_",
  }
}

/// The optional OperationType element can be used to specify the type of operation (Update, Delete
/// or PartialUpdate) to be performed on the data. The OperationType is only applicable to productrelated
/// feeds (Product, Inventory, Price, etc) and will be ignored for non-applicable feeds.
#[derive(Debug, PartialEq)]
pub enum OperationType {
  /// All specified information overwrites any existing information. Any
  /// unspecified information is erased.
  Update,

  /// All information is removed
  Delete,

  /// For Product feeds only: If you use PartialUpdate for a Product feed, all specified
  /// information overwrites any existing information, but unspecified information is
  /// unaffected. Caution: This operation type is only valid for Product feeds. If this operation
  /// type is used for any other feed type, such as Inventory and Price feeds, unpredictable
  /// data loss can occur.
  PartialUpdate,
}

pub trait Message {
  fn get_message_type() -> &'static str;
}

#[allow(non_snake_case)]
#[derive(Debug, PartialEq)]
pub struct EnvelopeMessage<M: Message> {
  pub data: M,
  pub operation_type: Option<OperationType>,
}

#[allow(non_snake_case)]
#[derive(Debug, PartialEq)]
pub struct Envelope<M: Message> {
  pub MerchantIdentifier: String,
  messages: Vec<EnvelopeMessage<M>>,
}

impl<M: Message> Envelope<M> {
  pub fn new(merchant_identifier: String) -> Self {
    Envelope::<M> {
      MerchantIdentifier: merchant_identifier,
      messages: vec![],
    }
  }

  pub fn add_message(&mut self, m: M, operation_type: Option<OperationType>) -> &mut Self {
    self.messages.push(EnvelopeMessage::<M> {
      data: m,
      operation_type: operation_type,
    });
    self
  }

  pub fn write_envelope_xml<W: encode::XmlEventWriter, F: FnMut(&mut W) -> encode::Result<()>>(&self, w: &mut W, mut f: F) -> encode::Result<()> {
    w.write(
      encode::XmlEvent::start_element("AmazonEnvelope")
        .ns("xsi", "http://www.w3.org/2001/XMLSchema-instance")
        .attr("xsi:noNamespaceSchemaLocation", "amznenvelope.xsd")
        .into()
    )?;

    let mid: &str = self.MerchantIdentifier.as_ref();
    let message_type: &str = M::get_message_type();

    write_xml!(w,
      Header[][
        DocumentVersion[]["1.01"]
        MerchantIdentifier[][mid]
      ]
      MessageType[][message_type]
      Messages[][
        [{ f(w) }]
      ]
    )?;

    w.write(
      encode::XmlEvent::end_element().into()
    )
  }
}

impl<W: encode::XmlEventWriter> encode::XmlWrite<W> for Envelope<inventory::InventoryMessage> {
  fn write_xml(&self, w: &mut W) -> encode::Result<()> {
    self.write_envelope_xml(w, |w: &mut W| {
      for message in self.messages.iter() {
        let sku: &str = message.data.SKU.as_ref();
        let quantity = message.data.Quantity.to_string();
        let fulfillment_latency = message.data.FulfillmentLatency.to_string();
        write_xml!(w,
          Message[][
            SKU[][sku]
            Quantity[][(&quantity)]
            FulfillmentLatency[][(&fulfillment_latency)]
          ]
        )?;
      }
      Ok(())
    })
  }
}

#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct SubmitFeedParameters {
  pub FeedType: String,

  pub MarketplaceIdList: Option<Vec<String>>,
  pub PurgeAndReplace: Option<bool>,
}

impl Into<Vec<(String, String)>> for SubmitFeedParameters {
  fn into(self) -> Vec<(String, String)> {
    let mut result = vec![];

    result.push(("FeedType".to_owned(), self.FeedType));

    if let Some(list) = self.MarketplaceIdList {
      for (i, id) in list.into_iter().enumerate() {
        result.push((format!("MarketplaceIdList.Id.{}", i + 1), id));
      }
    }

    if let Some(v) = self.PurgeAndReplace {
      result.push(("PurgeAndReplace".to_owned(), if v { "true".to_owned() } else { "false".to_owned() }))
    }

    result
  }
}

#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct SubmitFeedResponse {
  pub RequestId: String,
  pub FeedType: String,
  pub FeedSubmissionId: String,
  pub SubmittedDate: Option<DateTime<Utc>>,
  pub FeedProcessingStatus: String,
}

impl<S: decode::XmlEventStream> decode::FromXMLStream<S> for SubmitFeedResponse {
  fn from_xml(s: &mut S) -> decode::Result<SubmitFeedResponse> {
    use self::decode::{start_document, element, fold_elements, characters};
    start_document(s)?;
    element(s, "SubmitFeedResponse", |s| {
      fold_elements(s, SubmitFeedResponse::default(), |s, response| {
        match s.local_name() {
          "FeedSubmissionInfo" => {
            fold_elements(s, (), |s, _| {
              match s.local_name() {
                "FeedSubmissionId" => {
                  response.FeedSubmissionId = characters(s)?;
                },
                "FeedType" => {
                  response.FeedType = characters(s)?;
                },
                "SubmittedDate" => {
                  response.SubmittedDate = Some(characters(s)?);
                },
                "FeedProcessingStatus" => {
                  response.FeedProcessingStatus = characters(s)?;
                },
                _ => {},
              }
              Ok(())
            })
          },
          "ResponseMetadata" => {
            response.RequestId = element(s, "RequestId", |s| {
              characters(s)
            })?;
            Ok(())
          },
          _ => { Ok(()) }
        }
      })
    })
  }
}

#[allow(non_snake_case)]
pub fn SubmitFeed<R>(client: &Client, parameters: SubmitFeedParameters, content: R, content_md5: String, content_type: String) -> Result<Response<SubmitFeedResponse>>
  where R: Read + Send + 'static
{
  client.request_xml_with_body(Method::Post, PATH, VERSION, "SubmitFeed", parameters, content, content_md5, ContentType(
    content_type.parse().unwrap()
  ))
    .map_err(Into::into)
}

#[allow(non_snake_case)]
pub fn GetFeedSubmissionResult<W: Write>(client: &Client, FeedSubmissionId: String, out: &mut W) -> Result<u64> {
  let params = vec![("FeedSubmissionId".to_string(), FeedSubmissionId)];
  let mut resp = client.request(Method::Post, PATH, VERSION, "GetFeedSubmissionResult", params)?;
  let size = ::std::io::copy(&mut resp, out)?;
  Ok(size)
}

/// Parameters for `GetFeedSubmissionList`
#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct GetFeedSubmissionListParameters {
  pub FeedSubmissionIdList: Option<Vec<String>>,
  pub MaxCount: Option<i32>,
  pub FeedTypeList: Option<Vec<String>>,
  pub FeedProcessingStatusList: Option<Vec<String>>,
  pub SubmittedFromDate: Option<DateTime<Utc>>,
  pub SubmittedToDate: Option<DateTime<Utc>>,
}

impl Into<Vec<(String, String)>> for GetFeedSubmissionListParameters {
  fn into(self) -> Vec<(String, String)> {
    let mut result = vec![];
    if let Some(list) = self.FeedSubmissionIdList {
      for (i, id) in list.into_iter().enumerate() {
        result.push((format!("FeedSubmissionIdList.Id.{}", i + 1), id));
      }
    }

    if let Some(v) = self.MaxCount {
      result.push(("MaxCount".to_string(), v.to_string()));
    }

    if let Some(list) = self.FeedTypeList {
      for (i, v) in list.into_iter().enumerate() {
        result.push((format!("FeedTypeList.Type.{}", i + 1), v));
      }
    }

    if let Some(list) = self.FeedProcessingStatusList {
      for (i, v) in list.into_iter().enumerate() {
        result.push((format!("FeedProcessingStatusList.Status.{}", i + 1), v));
      }
    }

    if let Some(date) = self.SubmittedFromDate {
      result.push(("SubmittedFromDate".to_string(), date.to_iso8601()));
    }

    if let Some(date) = self.SubmittedToDate {
      result.push(("SubmittedToDate".to_string(), date.to_iso8601()));
    }

    result
  }
}

#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct FeedSubmissionInfo {
  pub FeedProcessingStatus: String,
  pub FeedType: String,
  pub FeedSubmissionId: String,
  pub StartedProcessingDate: Option<DateTime<Utc>>,
  pub SubmittedDate: Option<DateTime<Utc>>,
  pub CompletedProcessingDate: Option<DateTime<Utc>>,
}

#[allow(non_snake_case)]
#[derive(Debug, Default)]
pub struct GetFeedSubmissionListResponse {
  pub RequestId: String,
  pub FeedSubmissionInfo: Vec<FeedSubmissionInfo>,
  pub NextToken: Option<String>,
}

impl<S: decode::XmlEventStream> decode::FromXMLStream<S> for GetFeedSubmissionListResponse {
  fn from_xml(s: &mut S) -> decode::Result<GetFeedSubmissionListResponse> {
    use self::decode::{start_document, element, fold_elements, characters};
    start_document(s)?;
    element(s, vec!["GetFeedSubmissionListResponse", "GetFeedSubmissionListByNextTokenResponse"], |s| {
      fold_elements(s, GetFeedSubmissionListResponse::default(), |s, response| {
        match s.local_name() {
          "GetFeedSubmissionListResult" | "GetFeedSubmissionListByNextTokenResult" => {
            fold_elements(s, (), |s, _| {
              match s.local_name() {
                "FeedSubmissionInfo" => {
                  response.FeedSubmissionInfo.push(fold_elements(s, FeedSubmissionInfo::default(), |s, item| {
                    match s.local_name() {
                      "FeedProcessingStatus" => {
                        item.FeedProcessingStatus = characters(s)?;
                      },
                      "FeedType" => {
                        item.FeedType = characters(s)?;
                      },
                      "FeedSubmissionId" => {
                        item.FeedSubmissionId = characters(s)?;
                      },
                      "StartedProcessingDate" => {
                        item.StartedProcessingDate = Some(characters(s)?);
                      },
                      "SubmittedDate" => {
                        item.SubmittedDate = Some(characters(s)?);
                      },
                      "CompletedProcessingDate" => {
                        item.CompletedProcessingDate = Some(characters(s)?);
                      },
                      _ => {}
                    }
                    Ok(())
                  })?);
                },
                "NextToken" => {
                  response.NextToken = Some(characters(s)?);
                },
                _ => {},
              }
              Ok(())
            })
          },
          "ResponseMetadata" => {
            response.RequestId = element(s, "RequestId", |s| {
              characters(s)
            })?;
            Ok(())
          },
          _ => { Ok(()) }
        }
      })
    })
  }
}

#[allow(non_snake_case)]
pub fn GetFeedSubmissionList(client: &Client, parameters: GetFeedSubmissionListParameters) -> Result<Response<GetFeedSubmissionListResponse>> {
  client.request_xml(Method::Post, PATH, VERSION, "GetFeedSubmissionList", parameters).map_err(|err| err.into())
}

#[allow(non_snake_case)]
pub fn GetFeedSubmissionListByNextToken(client: &Client, next_token: String) -> Result<Response<GetFeedSubmissionListResponse>> {
  let params = vec![
    ("NextToken".to_string(), next_token)
  ];
  client.request_xml(Method::Post, PATH, VERSION, "GetFeedSubmissionListByNextToken", params).map_err(|err| err.into())
}

#[cfg(test)]
mod tests {
  use super::*;
  use xmlhelper::encode::{EventWriter, EmitterConfig};
  use xmlhelper::encode::XmlWrite;

  #[test]
  fn test_envelope_write_xml() {
    let mut writer = EventWriter::new_with_config(vec![], EmitterConfig::new().perform_indent(true));

    {
      let w = &mut writer;
      let mut e = Envelope::<inventory::InventoryMessage>::new("1234567890".to_owned());
      e.add_message(inventory::InventoryMessage {
        SKU: "p1".to_owned(),
        Quantity: 100,
        FulfillmentLatency: 0,
      }, Some(OperationType::PartialUpdate))
      .add_message(inventory::InventoryMessage {
        SKU: "p2".to_owned(),
        Quantity: 200,
        FulfillmentLatency: 0,
      }, Some(OperationType::PartialUpdate));
      e.write_xml(w).unwrap();
    }

    let xml = String::from_utf8(writer.into_inner()).unwrap();
    assert_eq!(xml, r#"<?xml version="1.0" encoding="utf-8"?>
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amznenvelope.xsd">
  <Header>
    <DocumentVersion>1.01</DocumentVersion>
    <MerchantIdentifier>1234567890</MerchantIdentifier>
  </Header>
  <MessageType>Inventory</MessageType>
  <Messages>
    <Message>
      <SKU>p1</SKU>
      <Quantity>100</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
    <Message>
      <SKU>p2</SKU>
      <Quantity>200</Quantity>
      <FulfillmentLatency>0</FulfillmentLatency>
    </Message>
  </Messages>
</AmazonEnvelope>"#);
  }
}<|endoftext|>