<commit_before>/*
 * Copyright (c) 2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;

use capnp::capability::{FromServer, Server};
use capnp::list::{PrimitiveList};
use capnp::message::{MallocMessageBuilder, MessageBuilder};

use capnp_rpc::capability::{WaitForContent};
use capnp_rpc::ez_rpc::EzRpcServer;

use calculator_capnp::Calculator;

struct ValueImpl {
    value : f64
}

impl ValueImpl {
    fn new(value : f64) -> ValueImpl {
        ValueImpl { value : value }
    }
}

impl Calculator::Value::Server for ValueImpl {
    fn read(&mut self, mut context : Calculator::Value::ReadContext) {
        let (_, results) = context.get();
        results.set_value(self.value);
        context.done();
    }
}

fn evaluate_impl(
    expression : Calculator::Expression::Reader,
    params : Option<PrimitiveList::Reader<f64>>) -> f64 {

    match expression.which() {
        Some(Calculator::Expression::Literal(v)) => v,
        Some(Calculator::Expression::PreviousResult(p)) => {
            p.read_request().send().wait().get_value()
        }
        Some(Calculator::Expression::Parameter(p)) => {
            match params {
                None => {fail!()}
                Some(params) => {
                    params[p as uint]
                }
            }
        }
        Some(Calculator::Expression::Call(call)) => {
            let _func = call.get_function();
            fail!()
        }
        None => fail!("unsupported expression"),
    }
}

struct FunctionImpl {
    param_count : uint,
    body : MallocMessageBuilder,
}

impl FunctionImpl {
    fn new(param_count : uint, body : Calculator::Expression::Reader) -> FunctionImpl {
        let mut result = FunctionImpl { param_count : param_count, body : MallocMessageBuilder::new_default() };
        result.body.set_root(&body.reader);
        result
    }
}

impl Calculator::Function::Server for FunctionImpl {
    fn call(&mut self, mut context : Calculator::Function::CallContext) {
        let (params, results) = context.get();
        assert!(params.get_params().size() == self.param_count,
                "Wrong number of parameters.");

        {
            let expression = self.body.get_root::<Calculator::Expression::Builder>().as_reader();
            results.set_value(evaluate_impl(expression, Some(params.get_params())));
        }
        context.done();
    }
}

pub struct OperatorImpl {
    op : Calculator::Operator::Reader,
}

impl Calculator::Function::Server for OperatorImpl {
    fn call(&mut self, mut context : Calculator::Function::CallContext) {
        let (params, results) = context.get();
        let params = params.get_params();
        assert!(params.size() == 2, "Wrong number of parameters.");

        let result = match self.op {
            Calculator::Operator::Add => params[0] + params[1],
            Calculator::Operator::Subtract => params[0] - params[1],
            Calculator::Operator::Multiply => params[0] * params[1],
            Calculator::Operator::Divide => params[0] / params[1],
        };

        results.set_value(result);
        context.done();
    }
}

struct CalculatorImpl;

impl Calculator::Server for CalculatorImpl {
    fn evaluate(&mut self, mut context : Calculator::EvaluateContext) {
        let (params, results) = context.get();
        results.set_value(
            FromServer::new(
                None::<EzRpcServer>,
                ~ValueImpl::new(evaluate_impl(params.get_expression(), None))));
        context.done();
    }
    fn def_function(&mut self, mut context : Calculator::DefFunctionContext) {
        let (params, results) = context.get();
        results.set_func(
            FromServer::new(
                None::<EzRpcServer>,
                ~FunctionImpl::new(params.get_param_count() as uint, params.get_body())));
    }
    fn get_operator(&mut self, mut context : Calculator::GetOperatorContext) {
        let (params, results) = context.get();
        results.set_func(
            match params.get_op() {
                Some(op) => {
                    FromServer::new(
                        None::<EzRpcServer>,
                        ~OperatorImpl {op : op})
                }
                None => fail!("Unknown operator."),
            });
        context.done();
    }
}

pub fn main() {
    let args = std::os::args();
    if args.len() != 3 {
        println!("usage: {} server ADDRESS[:PORT]", args[0]);
        return;
    }

    let mut rpc_server = EzRpcServer::new(args[2]).unwrap();

    // There's got to be a better way to do this.
    let calculator = (~Calculator::ServerDispatch { server : ~CalculatorImpl}) as ~Server;
    rpc_server.export_cap("calculator", calculator);

}
<commit_msg>finish evaluate_impl<commit_after>/*
 * Copyright (c) 2014, David Renshaw (dwrenshaw@gmail.com)
 *
 * See the LICENSE file in the capnproto-rust root directory.
 */

use std;

use capnp::capability::{FromServer, Server};
use capnp::list::{PrimitiveList};
use capnp::message::{MallocMessageBuilder, MessageBuilder};

use capnp_rpc::capability::{InitRequest, WaitForContent};
use capnp_rpc::ez_rpc::EzRpcServer;

use calculator_capnp::Calculator;

struct ValueImpl {
    value : f64
}

impl ValueImpl {
    fn new(value : f64) -> ValueImpl {
        ValueImpl { value : value }
    }
}

impl Calculator::Value::Server for ValueImpl {
    fn read(&mut self, mut context : Calculator::Value::ReadContext) {
        let (_, results) = context.get();
        results.set_value(self.value);
        context.done();
    }
}

fn evaluate_impl(
    expression : Calculator::Expression::Reader,
    params : Option<PrimitiveList::Reader<f64>>) -> f64 {

    match expression.which() {
        Some(Calculator::Expression::Literal(v)) => v,
        Some(Calculator::Expression::PreviousResult(p)) => {
            p.read_request().send().wait().get_value()
        }
        Some(Calculator::Expression::Parameter(p)) => {
            match params {
                None => {fail!()}
                Some(params) => {
                    params[p as uint]
                }
            }
        }
        Some(Calculator::Expression::Call(call)) => {
            let func = call.get_function();
            let call_params = call.get_params();
            let mut param_values = ~[];
            for ii in range(0, call_params.size()) {
                param_values.push(evaluate_impl(call_params[ii], params));
            }
            let mut request = func.call_request();
            let request_params = request.init().init_params(param_values.len());
            for ii in range(0, param_values.len()) {
                request_params.set(ii, param_values[ii]);
            }
            return request.send().wait().get_value();
        }
        None => fail!("unsupported expression"),
    }
}

struct FunctionImpl {
    param_count : uint,
    body : MallocMessageBuilder,
}

impl FunctionImpl {
    fn new(param_count : uint, body : Calculator::Expression::Reader) -> FunctionImpl {
        let mut result = FunctionImpl { param_count : param_count, body : MallocMessageBuilder::new_default() };
        result.body.set_root(&body.reader);
        result
    }
}

impl Calculator::Function::Server for FunctionImpl {
    fn call(&mut self, mut context : Calculator::Function::CallContext) {
        let (params, results) = context.get();
        assert!(params.get_params().size() == self.param_count,
                "Wrong number of parameters.");

        {
            let expression = self.body.get_root::<Calculator::Expression::Builder>().as_reader();
            results.set_value(evaluate_impl(expression, Some(params.get_params())));
        }
        context.done();
    }
}

pub struct OperatorImpl {
    op : Calculator::Operator::Reader,
}

impl Calculator::Function::Server for OperatorImpl {
    fn call(&mut self, mut context : Calculator::Function::CallContext) {
        let (params, results) = context.get();
        let params = params.get_params();
        assert!(params.size() == 2, "Wrong number of parameters.");

        let result = match self.op {
            Calculator::Operator::Add => params[0] + params[1],
            Calculator::Operator::Subtract => params[0] - params[1],
            Calculator::Operator::Multiply => params[0] * params[1],
            Calculator::Operator::Divide => params[0] / params[1],
        };

        results.set_value(result);
        context.done();
    }
}

struct CalculatorImpl;

impl Calculator::Server for CalculatorImpl {
    fn evaluate(&mut self, mut context : Calculator::EvaluateContext) {
        let (params, results) = context.get();
        results.set_value(
            FromServer::new(
                None::<EzRpcServer>,
                ~ValueImpl::new(evaluate_impl(params.get_expression(), None))));
        context.done();
    }
    fn def_function(&mut self, mut context : Calculator::DefFunctionContext) {
        let (params, results) = context.get();
        results.set_func(
            FromServer::new(
                None::<EzRpcServer>,
                ~FunctionImpl::new(params.get_param_count() as uint, params.get_body())));
    }
    fn get_operator(&mut self, mut context : Calculator::GetOperatorContext) {
        let (params, results) = context.get();
        results.set_func(
            match params.get_op() {
                Some(op) => {
                    FromServer::new(
                        None::<EzRpcServer>,
                        ~OperatorImpl {op : op})
                }
                None => fail!("Unknown operator."),
            });
        context.done();
    }
}

pub fn main() {
    let args = std::os::args();
    if args.len() != 3 {
        println!("usage: {} server ADDRESS[:PORT]", args[0]);
        return;
    }

    let rpc_server = EzRpcServer::new(args[2]).unwrap();

    // There's got to be a better way to do this.
    let calculator = (~Calculator::ServerDispatch { server : ~CalculatorImpl}) as ~Server;
    rpc_server.export_cap("calculator", calculator);

}
<|endoftext|>


<commit_before>extern crate array_ext;
extern crate custom_gl as gl;
extern crate custom_egl as egl;

mod types;
#[macro_use]
mod typeinfo;
mod shader;
mod eglw;

use std::mem;
use std::ffi::CStr;
use std::ptr;
use std::cell::Cell;
use gl::types::*;
use typeinfo::TypeInfo;
use array_ext::Array;
use shader::{Shader, Program};

pub use egl::NativeDisplayType;
pub use egl::NativeWindowType;
pub use eglw::Surface;

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct Vertex
{
    pos: [i16; 2],
    col: [f32; 4],
    texc: [f32; 2],
}

impl_typeinfo!(Vertex, pos, col, texc);

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
enum PrimType
{
    Points = gl::POINTS,
    Lines = gl::LINES,
    LineStrip = gl::LINE_STRIP,
    Triangles = gl::TRIANGLES,
}

pub struct DrawEngine
{
    egl_disp: eglw::Display,
    prog: Program,
    vbo_vert: GLuint,
    vbo_idx: GLuint,
    default_tex: GLuint,
    cur_ty: Cell<PrimType>,
    vert_off: Cell<usize>,
    idx_off: Cell<usize>,
    vert_len: Cell<usize>,
    idx_len: Cell<usize>,
    cur_tex: Cell<GLuint>,
    pub max_verts: usize,
    pub max_idxs: usize,
}

impl DrawEngine
{
    pub fn new(xdisp: NativeDisplayType) -> Result<Self, &'static str>
    {
        let egl_disp = try!(eglw::Display::new(xdisp));

        unsafe
        {
            let vendor = CStr::from_ptr(gl::GetString(gl::VENDOR) as *const _);
            let renderer = CStr::from_ptr(gl::GetString(gl::RENDERER) as *const _);
            let version = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _);
            let exts = CStr::from_ptr(gl::GetString(gl::EXTENSIONS) as *const _);
            println!("GL vendor: {:?}\nGL renderer: {:?}\nGL version: {:?}\nGL extensions: {:?}",
                vendor, renderer, version, exts);
        }

        unsafe
        {
            let prog = Program::new(&[
                Shader::new(gl::VERTEX_SHADER, &[include_str!("test.vert.glsl")]).unwrap_or_else(|e| panic!("vert: {}", e)),
                Shader::new(gl::FRAGMENT_SHADER, &[include_str!("test.frag.glsl")]).unwrap_or_else(|e| panic!("frag: {}", e)),
            ]).unwrap_or_else(|e| panic!("link: {}", e));
            prog.set_active();

            // vertex buffer
            let mut vbo_vert = 0;
            gl::GenBuffers(1, &mut vbo_vert);
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo_vert);
            let size = mem::size_of::<Vertex>();
            Vertex::visit_fields(|name, offset, count, ty| {
                let num = prog.get_attrib(name).unwrap();
                gl::VertexAttribPointer(num, count as GLint, ty as GLenum, gl::FALSE, size as GLsizei, offset as *const _);
                gl::EnableVertexAttribArray(num);
            });

            // index buffer
            let mut vbo_idx = 0;
            gl::GenBuffers(1, &mut vbo_idx);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vbo_idx);

            // 1x1 white texture
            let mut tex = 0;
            gl::GenTextures(1, &mut tex);
            gl::BindTexture(gl::TEXTURE_2D, tex);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
            gl::TexImage2D(gl::TEXTURE_2D, 0, gl::LUMINANCE as GLint, 1, 1, 0, gl::LUMINANCE, gl::UNSIGNED_BYTE, [255u8].as_ptr() as *const _);

            let eng = DrawEngine{
                egl_disp: egl_disp,
                prog: prog,
                vbo_vert: vbo_vert,
                vbo_idx: vbo_idx,
                default_tex: tex,
                cur_ty: Cell::new(PrimType::Triangles),
                vert_off: Cell::new(0),
                idx_off: Cell::new(0),
                vert_len: Cell::new(0),
                idx_len: Cell::new(0),
                cur_tex: Cell::new(0),
                // allocate 1mb
                max_verts: 32768,
                max_idxs: 65536,
            };

            eng.alloc_vert();
            eng.alloc_idx();

            Ok(eng)
        }
    }

    pub fn create_window_surface(&self, win: NativeWindowType) -> Result<Surface, &'static str>
    {
        self.egl_disp.create_window_surface(win)
    }

    pub fn begin_draw<'a>(&'a self, surface: &'a Surface, (width, height): (u32, u32)) -> DrawContext
    {
        if !surface.is_current()
        {
            let (w, h) = (width as f32, height as f32);
            let tf = [
                2.0/w,    0.0, 0.0, 0.0,
                  0.0, -2.0/h, 0.0, 0.0,
                  0.0,    0.0, 1.0, 0.0,
                 -1.0,    1.0, 0.0, 1.0,
            ];
            surface.make_current();
            let loc_tf = self.prog.get_uniform("tf").unwrap() as GLint;
            unsafe
            {
                gl::Viewport(0, 0, width as GLsizei, height as GLsizei);
                gl::UniformMatrix4fv(loc_tf, 1, gl::FALSE, tf.as_ptr());
            }
        }

        DrawContext::new(self, surface)
    }

    fn alloc_vert(&self)
    {
        self.vert_off.set(0);
        let size = self.max_verts * mem::size_of::<Vertex>();
        unsafe { gl::BufferData(gl::ARRAY_BUFFER, size as GLsizeiptr, ptr::null(), gl::STREAM_DRAW) };
    }

    fn alloc_idx(&self)
    {
        self.idx_off.set(0);
        let size = self.max_idxs * mem::size_of::<u16>();
        unsafe { gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, size as GLsizeiptr, ptr::null(), gl::STREAM_DRAW) };
    }

    fn clear(&self, r: f32, g: f32, b: f32, a: f32)
    {
        self.vert_len.set(0);
        self.idx_len.set(0);
        unsafe
        {
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }
    }

    fn push_elems<T: Array<u16>>(&self, ty: PrimType, tex: Option<GLuint>, verts: &[Vertex], idxs: T)
    {
        assert!(verts.len() <= self.max_verts && idxs.len() <= self.max_idxs);
        let tex = tex.unwrap_or(self.default_tex);

        let vert_start = self.vert_off.get() + self.vert_len.get();
        let idx_start = self.idx_off.get() + self.idx_len.get();

        let oom_vert = vert_start + verts.len() > self.max_verts;
        let oom_idx = idx_start + idxs.len() > self.max_idxs;
        let new_tex = self.cur_tex.get() != tex;

        if oom_vert || oom_idx || new_tex || self.cur_ty.get() != ty ||
            self.cur_ty.get() == PrimType::LineStrip  // close the previous line strip
        {
            self.commit();
            self.cur_ty.set(ty);

            if oom_vert { self.alloc_vert(); }
            if oom_idx { self.alloc_idx(); }

            if new_tex
            {
                self.cur_tex.set(tex);
                unsafe { gl::BindTexture(gl::TEXTURE_2D, tex) };
            }
        }

        let vert_size = vert_start * mem::size_of::<Vertex>();
        unsafe { gl::BufferSubData(gl::ARRAY_BUFFER, vert_size as GLsizeiptr, mem::size_of_val(verts) as GLintptr, verts.as_ptr() as *const _) };
        self.vert_len.set(self.vert_len.get() + verts.len());

        if !idxs.is_empty()
        {
            let idxs = idxs.map_(|idx| idx + vert_start as u16);
            let idx_size = idx_start * mem::size_of::<u16>();
            unsafe { gl::BufferSubData(gl::ELEMENT_ARRAY_BUFFER, idx_size as GLsizeiptr, mem::size_of_val(&idxs) as GLintptr, idxs.as_ptr() as *const _) };
            self.idx_len.set(self.idx_len.get() + idxs.len());
        }
    }

    fn commit(&self)
    {
        if self.vert_len.get() == 0 { return }

        match self.cur_ty.get()
        {
            PrimType::Triangles | PrimType::Lines => {
                let offset = self.idx_off.get() * mem::size_of::<i16>();
                unsafe { gl::DrawElements(self.cur_ty.get() as GLenum, self.idx_len.get() as GLsizei, gl::UNSIGNED_SHORT, offset as *const _) };
            }
            _ => {
                unsafe { gl::DrawArrays(self.cur_ty.get() as GLenum, self.vert_off.get() as GLint, self.vert_len.get() as GLsizei) };
            }
        }

        self.vert_off.set(self.vert_off.get() + self.vert_len.get());
        self.idx_off.set(self.idx_off.get() + self.idx_len.get());

        self.vert_len.set(0);
        self.idx_len.set(0);
    }
}

impl Drop for DrawEngine
{
    fn drop(&mut self)
    {
        unsafe
        {
            gl::DeleteBuffers(2, [self.vbo_vert, self.vbo_idx].as_ptr());
            gl::DeleteTextures(1, &self.default_tex);
        }
    }
}

pub struct DrawContext<'a>
{
    eng: &'a DrawEngine,
    surface: &'a Surface<'a>,
}

impl<'a> DrawContext<'a>
{
    fn new(eng: &'a DrawEngine, surface: &'a Surface) -> Self
    {
        DrawContext{
            eng: eng,
            surface: surface,
        }
    }

    pub fn clear(&self, color: [f32; 4])
    {
        self.eng.clear(color[0], color[1], color[2], color[3]);
    }

    pub fn draw_point(&self, pos: [i16; 2], color: [f32; 4])
    {
        self.eng.push_elems(PrimType::Points, None,
            &[Vertex{ pos: pos, col: color, texc: [0.0, 0.0] }], []);
    }

    pub fn draw_line(&self, p0: [i16; 2], p1: [i16; 2], color: [f32; 4])
    {
        self.eng.push_elems(PrimType::Lines, None, &[
            Vertex{ pos: p0, col: color, texc: [0.0, 0.0] },
            Vertex{ pos: p1, col: color, texc: [0.0, 0.0] },
        ], [0, 1]);
    }

    pub fn draw_polyline(&self, ps: &[[i16; 2]], color: [f32; 4])
    {
        let verts: Vec<_> = ps.iter().map(|&p| Vertex{ pos: p, col: color, texc: [0.0, 0.0] }).collect();
        self.eng.push_elems(PrimType::LineStrip, None, &verts, []);
    }

    pub fn draw_triangle(&self, p0: [i16; 2], p1: [i16; 2], p2: [i16; 2], color: [f32; 4])
    {
        self.eng.push_elems(PrimType::Triangles, None, &[
            Vertex{ pos: p0, col: color, texc: [0.0, 0.0] },
            Vertex{ pos: p1, col: color, texc: [0.0, 0.0] },
            Vertex{ pos: p2, col: color, texc: [0.0, 0.0] },
        ], [0, 1, 2]);
    }

    pub fn draw_rect(&self, pos: [i16; 2], width: u16, height: u16, color: [f32; 4])
    {
        let (x, y) = (pos[0], pos[1]);
        let xw = x + width as i16;
        let yh = y + height as i16;

        self.eng.push_elems(PrimType::Triangles, None, &[
            Vertex{ pos: pos,      col: color, texc: [0.0, 0.0] },
            Vertex{ pos: [xw, y],  col: color, texc: [0.0, 0.0] },
            Vertex{ pos: [xw, yh], col: color, texc: [0.0, 0.0] },
            Vertex{ pos: [ x, yh], col: color, texc: [0.0, 0.0] },
        ], [
            0, 1, 2,
            2, 3, 0,
        ]);
    }
}

impl<'a> Drop for DrawContext<'a>
{
    fn drop(&mut self)
    {
        self.eng.commit();
        self.surface.swap_buffers();
    }
}
<commit_msg>added typedefs for Point and Color arrays<commit_after>extern crate array_ext;
extern crate custom_gl as gl;
extern crate custom_egl as egl;

mod types;
#[macro_use]
mod typeinfo;
mod shader;
mod eglw;

use std::mem;
use std::ffi::CStr;
use std::ptr;
use std::cell::Cell;
use gl::types::*;
use typeinfo::TypeInfo;
use array_ext::Array;
use shader::{Shader, Program};

pub use egl::NativeDisplayType;
pub use egl::NativeWindowType;
pub use eglw::Surface;

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct Vertex
{
    pos: [i16; 2],
    col: [f32; 4],
    texc: [f32; 2],
}

impl_typeinfo!(Vertex, pos, col, texc);

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[repr(u32)]
enum PrimType
{
    Points = gl::POINTS,
    Lines = gl::LINES,
    LineStrip = gl::LINE_STRIP,
    Triangles = gl::TRIANGLES,
}

pub struct DrawEngine
{
    egl_disp: eglw::Display,
    prog: Program,
    vbo_vert: GLuint,
    vbo_idx: GLuint,
    default_tex: GLuint,
    cur_ty: Cell<PrimType>,
    vert_off: Cell<usize>,
    idx_off: Cell<usize>,
    vert_len: Cell<usize>,
    idx_len: Cell<usize>,
    cur_tex: Cell<GLuint>,
    pub max_verts: usize,
    pub max_idxs: usize,
}

impl DrawEngine
{
    pub fn new(xdisp: NativeDisplayType) -> Result<Self, &'static str>
    {
        let egl_disp = try!(eglw::Display::new(xdisp));

        unsafe
        {
            let vendor = CStr::from_ptr(gl::GetString(gl::VENDOR) as *const _);
            let renderer = CStr::from_ptr(gl::GetString(gl::RENDERER) as *const _);
            let version = CStr::from_ptr(gl::GetString(gl::VERSION) as *const _);
            let exts = CStr::from_ptr(gl::GetString(gl::EXTENSIONS) as *const _);
            println!("GL vendor: {:?}\nGL renderer: {:?}\nGL version: {:?}\nGL extensions: {:?}",
                vendor, renderer, version, exts);
        }

        unsafe
        {
            let prog = Program::new(&[
                Shader::new(gl::VERTEX_SHADER, &[include_str!("test.vert.glsl")]).unwrap_or_else(|e| panic!("vert: {}", e)),
                Shader::new(gl::FRAGMENT_SHADER, &[include_str!("test.frag.glsl")]).unwrap_or_else(|e| panic!("frag: {}", e)),
            ]).unwrap_or_else(|e| panic!("link: {}", e));
            prog.set_active();

            // vertex buffer
            let mut vbo_vert = 0;
            gl::GenBuffers(1, &mut vbo_vert);
            gl::BindBuffer(gl::ARRAY_BUFFER, vbo_vert);
            let size = mem::size_of::<Vertex>();
            Vertex::visit_fields(|name, offset, count, ty| {
                let num = prog.get_attrib(name).unwrap();
                gl::VertexAttribPointer(num, count as GLint, ty as GLenum, gl::FALSE, size as GLsizei, offset as *const _);
                gl::EnableVertexAttribArray(num);
            });

            // index buffer
            let mut vbo_idx = 0;
            gl::GenBuffers(1, &mut vbo_idx);
            gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, vbo_idx);

            // 1x1 white texture
            let mut tex = 0;
            gl::GenTextures(1, &mut tex);
            gl::BindTexture(gl::TEXTURE_2D, tex);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint);
            gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint);
            gl::TexImage2D(gl::TEXTURE_2D, 0, gl::LUMINANCE as GLint, 1, 1, 0, gl::LUMINANCE, gl::UNSIGNED_BYTE, [255u8].as_ptr() as *const _);

            let eng = DrawEngine{
                egl_disp: egl_disp,
                prog: prog,
                vbo_vert: vbo_vert,
                vbo_idx: vbo_idx,
                default_tex: tex,
                cur_ty: Cell::new(PrimType::Triangles),
                vert_off: Cell::new(0),
                idx_off: Cell::new(0),
                vert_len: Cell::new(0),
                idx_len: Cell::new(0),
                cur_tex: Cell::new(0),
                // allocate 1mb
                max_verts: 32768,
                max_idxs: 65536,
            };

            eng.alloc_vert();
            eng.alloc_idx();

            Ok(eng)
        }
    }

    pub fn create_window_surface(&self, win: NativeWindowType) -> Result<Surface, &'static str>
    {
        self.egl_disp.create_window_surface(win)
    }

    pub fn begin_draw<'a>(&'a self, surface: &'a Surface, (width, height): (u32, u32)) -> DrawContext
    {
        if !surface.is_current()
        {
            let (w, h) = (width as f32, height as f32);
            let tf = [
                2.0/w,    0.0, 0.0, 0.0,
                  0.0, -2.0/h, 0.0, 0.0,
                  0.0,    0.0, 1.0, 0.0,
                 -1.0,    1.0, 0.0, 1.0,
            ];
            surface.make_current();
            let loc_tf = self.prog.get_uniform("tf").unwrap() as GLint;
            unsafe
            {
                gl::Viewport(0, 0, width as GLsizei, height as GLsizei);
                gl::UniformMatrix4fv(loc_tf, 1, gl::FALSE, tf.as_ptr());
            }
        }

        DrawContext::new(self, surface)
    }

    fn alloc_vert(&self)
    {
        self.vert_off.set(0);
        let size = self.max_verts * mem::size_of::<Vertex>();
        unsafe { gl::BufferData(gl::ARRAY_BUFFER, size as GLsizeiptr, ptr::null(), gl::STREAM_DRAW) };
    }

    fn alloc_idx(&self)
    {
        self.idx_off.set(0);
        let size = self.max_idxs * mem::size_of::<u16>();
        unsafe { gl::BufferData(gl::ELEMENT_ARRAY_BUFFER, size as GLsizeiptr, ptr::null(), gl::STREAM_DRAW) };
    }

    fn clear(&self, r: f32, g: f32, b: f32, a: f32)
    {
        self.vert_len.set(0);
        self.idx_len.set(0);
        unsafe
        {
            gl::ClearColor(r, g, b, a);
            gl::Clear(gl::COLOR_BUFFER_BIT);
        }
    }

    fn push_elems<T: Array<u16>>(&self, ty: PrimType, tex: Option<GLuint>, verts: &[Vertex], idxs: T)
    {
        assert!(verts.len() <= self.max_verts && idxs.len() <= self.max_idxs);
        let tex = tex.unwrap_or(self.default_tex);

        let vert_start = self.vert_off.get() + self.vert_len.get();
        let idx_start = self.idx_off.get() + self.idx_len.get();

        let oom_vert = vert_start + verts.len() > self.max_verts;
        let oom_idx = idx_start + idxs.len() > self.max_idxs;
        let new_tex = self.cur_tex.get() != tex;

        if oom_vert || oom_idx || new_tex || self.cur_ty.get() != ty ||
            self.cur_ty.get() == PrimType::LineStrip  // close the previous line strip
        {
            self.commit();
            self.cur_ty.set(ty);

            if oom_vert { self.alloc_vert(); }
            if oom_idx { self.alloc_idx(); }

            if new_tex
            {
                self.cur_tex.set(tex);
                unsafe { gl::BindTexture(gl::TEXTURE_2D, tex) };
            }
        }

        let vert_size = vert_start * mem::size_of::<Vertex>();
        unsafe { gl::BufferSubData(gl::ARRAY_BUFFER, vert_size as GLsizeiptr, mem::size_of_val(verts) as GLintptr, verts.as_ptr() as *const _) };
        self.vert_len.set(self.vert_len.get() + verts.len());

        if !idxs.is_empty()
        {
            let idxs = idxs.map_(|idx| idx + vert_start as u16);
            let idx_size = idx_start * mem::size_of::<u16>();
            unsafe { gl::BufferSubData(gl::ELEMENT_ARRAY_BUFFER, idx_size as GLsizeiptr, mem::size_of_val(&idxs) as GLintptr, idxs.as_ptr() as *const _) };
            self.idx_len.set(self.idx_len.get() + idxs.len());
        }
    }

    fn commit(&self)
    {
        if self.vert_len.get() == 0 { return }

        match self.cur_ty.get()
        {
            PrimType::Triangles | PrimType::Lines => {
                let offset = self.idx_off.get() * mem::size_of::<i16>();
                unsafe { gl::DrawElements(self.cur_ty.get() as GLenum, self.idx_len.get() as GLsizei, gl::UNSIGNED_SHORT, offset as *const _) };
            }
            _ => {
                unsafe { gl::DrawArrays(self.cur_ty.get() as GLenum, self.vert_off.get() as GLint, self.vert_len.get() as GLsizei) };
            }
        }

        self.vert_off.set(self.vert_off.get() + self.vert_len.get());
        self.idx_off.set(self.idx_off.get() + self.idx_len.get());

        self.vert_len.set(0);
        self.idx_len.set(0);
    }
}

impl Drop for DrawEngine
{
    fn drop(&mut self)
    {
        unsafe
        {
            gl::DeleteBuffers(2, [self.vbo_vert, self.vbo_idx].as_ptr());
            gl::DeleteTextures(1, &self.default_tex);
        }
    }
}

pub type Point = [i16; 2];
pub type Color = [f32; 4];

pub struct DrawContext<'a>
{
    eng: &'a DrawEngine,
    surface: &'a Surface<'a>,
}

impl<'a> DrawContext<'a>
{
    fn new(eng: &'a DrawEngine, surface: &'a Surface) -> Self
    {
        DrawContext{
            eng: eng,
            surface: surface,
        }
    }

    pub fn clear(&self, color: Color)
    {
        self.eng.clear(color[0], color[1], color[2], color[3]);
    }

    pub fn draw_point(&self, pos: Point, color: Color)
    {
        self.eng.push_elems(PrimType::Points, None,
            &[Vertex{ pos: pos, col: color, texc: [0.0, 0.0] }], []);
    }

    pub fn draw_line(&self, p0: Point, p1: Point, color: Color)
    {
        self.eng.push_elems(PrimType::Lines, None, &[
            Vertex{ pos: p0, col: color, texc: [0.0, 0.0] },
            Vertex{ pos: p1, col: color, texc: [0.0, 0.0] },
        ], [0, 1]);
    }

    pub fn draw_polyline(&self, ps: &[Point], color: Color)
    {
        let verts: Vec<_> = ps.iter().map(|&p| Vertex{ pos: p, col: color, texc: [0.0, 0.0] }).collect();
        self.eng.push_elems(PrimType::LineStrip, None, &verts, []);
    }

    pub fn draw_triangle(&self, p0: Point, p1: Point, p2: Point, color: Color)
    {
        self.eng.push_elems(PrimType::Triangles, None, &[
            Vertex{ pos: p0, col: color, texc: [0.0, 0.0] },
            Vertex{ pos: p1, col: color, texc: [0.0, 0.0] },
            Vertex{ pos: p2, col: color, texc: [0.0, 0.0] },
        ], [0, 1, 2]);
    }

    pub fn draw_rect(&self, pos: Point, width: u16, height: u16, color: Color)
    {
        let (x, y) = (pos[0], pos[1]);
        let xw = x + width as i16;
        let yh = y + height as i16;

        self.eng.push_elems(PrimType::Triangles, None, &[
            Vertex{ pos: pos,      col: color, texc: [0.0, 0.0] },
            Vertex{ pos: [xw, y],  col: color, texc: [0.0, 0.0] },
            Vertex{ pos: [xw, yh], col: color, texc: [0.0, 0.0] },
            Vertex{ pos: [ x, yh], col: color, texc: [0.0, 0.0] },
        ], [
            0, 1, 2,
            2, 3, 0,
        ]);
    }
}

impl<'a> Drop for DrawContext<'a>
{
    fn drop(&mut self)
    {
        self.eng.commit();
        self.surface.swap_buffers();
    }
}
<|endoftext|>


<commit_before>use std::ops::{Mul,Add};
use num::traits::Zero;

#[derive(PartialEq,Debug)]
pub struct Vec3<T> where T: Mul<T, Output = T> + Add<T, Output = T> + Zero + Copy + Clone {
    x: T,
    y: T,
    z: T,
}

impl <T> Vec3<T> where T : Mul<T, Output = T> + Add<T, Output = T> + Zero + Copy + Clone {
    pub fn new(xx: T, yy: T, zz: T) -> Vec3<T> {
        Vec3 { x: xx, y: yy, z: zz }
    }

    pub fn zero() -> Vec3<T> {
        Vec3::new(T::zero(), T::zero(), T::zero())
    }

    pub fn diagonal(xx: T) -> Vec3<T> {
        Vec3::new(xx, xx, xx)
    }

    pub fn norm(self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z)
    }
}

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

    #[test]
    fn should_be_created_with_constructor() {
        let v: Vec3<f64> = Vec3::new(0.0, 1.0, 2.0);

        assert_eq!(v, Vec3 { x: 0.0, y: 1.0, z: 2.0 });
    }

    #[test]
    fn should_initialize_to_zero_vector() {
        let v: Vec3<f64> = Vec3::zero();

        assert_eq!(v, Vec3::<f64>{ x: 0.0, y: 0.0, z: 0.0 });
    }

    #[test]
    fn should_initialize_to_diagonal_vector() {
        let v: Vec3<f64> = Vec3::diagonal(1.0);

        assert_eq!(v, Vec3::<f64>{ x: 1.0, y: 1.0, z: 1.0 });
    }

    #[test]
    fn should_know_its_norm() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.norm(), 0.0);
    }
}
<commit_msg>Introduce dot product for Vec3<commit_after>use std::ops::{Mul,Add};
use num::traits::{Zero,Float};

#[derive(PartialEq,Debug)]
pub struct Vec3<T> where T: Mul<T, Output = T> + Add<T, Output = T> + Zero + Copy + Clone {
    x: T,
    y: T,
    z: T,
}

impl <T> Vec3<T> where T : Mul<T, Output = T> + Add<T, Output = T> + Zero + Copy + Clone {
    pub fn new(xx: T, yy: T, zz: T) -> Vec3<T> {
        Vec3 { x: xx, y: yy, z: zz }
    }

    pub fn zero() -> Vec3<T> {
        Vec3::new(T::zero(), T::zero(), T::zero())
    }

    pub fn diagonal(xx: T) -> Vec3<T> {
        Vec3::new(xx, xx, xx)
    }
}

impl <T> Mul<Vec3<T>> for Vec3<T> where T: Mul<T, Output = T> + Add<T, Output = T> + Zero + Copy + Clone {
    type Output = T;

    fn mul(self, rhs: Vec3<T>) -> T {
        return self.x * rhs.x + self.y * rhs.y + self.z * rhs.z
    }
}

impl <T> Vec3<T> where T: Mul<T, Output=T> + Add<T, Output=T> + Zero + Float + Clone + Copy {
    pub fn norm(self) -> T {
        (self.x * self.x + self.y * self.y + self.z * self.z)
    }
}

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

    #[test]
    fn should_be_created_with_constructor() {
        let v: Vec3<f64> = Vec3::new(0.0, 1.0, 2.0);

        assert_eq!(v, Vec3 { x: 0.0, y: 1.0, z: 2.0 });
    }

    #[test]
    fn should_initialize_to_zero_vector() {
        let v: Vec3<f64> = Vec3::zero();

        assert_eq!(v, Vec3::<f64>{ x: 0.0, y: 0.0, z: 0.0 });
    }

    #[test]
    fn should_initialize_to_diagonal_vector() {
        let v: Vec3<f64> = Vec3::diagonal(1.0);

        assert_eq!(v, Vec3::<f64>{ x: 1.0, y: 1.0, z: 1.0 });
    }

    #[test]
    fn should_know_dot_product() {
        let u: Vec3<f64> = Vec3::diagonal(1.0);
        let v: Vec3<f64> = Vec3::new(0.0, 1.0, 2.0);

        let dot_product: f64 = u * v;

        assert_eq!(dot_product, 3.0);
    }

    #[test]
    fn should_know_its_norm() {
        let v: Vec3<f64> = Vec3 { x: 0.0, y: 0.0, z: 0.0 };

        assert_eq!(v.norm(), 0.0);
    }
}
<|endoftext|>


<commit_before>use std::f64;

/// The `IterStatistics` trait provides the same host of statistical
/// utilities as the `Statistics` traited ported for use with iterators
pub trait IterStatistics<T> : Iterator<Item=T>
{
    /// Returns the minimum absolute value in the data
    ///
    /// # Remarks
    ///
    /// Returns `f64::NAN` if data is empty or an entry is `f64::NAN`
    ///
    /// # Examples
    ///
    /// ```
    /// use std::f64;
    /// use statrs::statistics::IterStatistics;
    ///
    /// let x: Vec<f64> = vec![];
    /// assert!(x.into_iter().abs_min().is_nan());
    ///
    /// let y: Vec<f64>  = vec![0.0, f64::NAN, 3.0, -2.0];
    /// assert!(y.into_iter().abs_min().is_nan());
    ///
    /// let z: Vec<f64>  = vec![0.0, 3.0, -2.0];
    /// assert_eq!(z.into_iter().abs_min(), 0.0);
    /// ```
    fn abs_min(&mut self) -> T;
}

impl<T: Iterator<Item=f64>> IterStatistics<f64> for T {
    fn abs_min(&mut self) -> f64 {
        let mut min = f64::INFINITY;
        let mut any = false;
        for x in self {
            let abs = x.abs();
            if abs < min || abs.is_nan() {
                min = abs;
            }
            any = true;
        }
        if any { min } else { f64::NAN }
    }
}<commit_msg>implement abs_max for IterStats<commit_after>use std::f64;

/// The `IterStatistics` trait provides the same host of statistical
/// utilities as the `Statistics` traited ported for use with iterators
pub trait IterStatistics<T>: Iterator<Item = T> {
    /// Returns the minimum absolute value in the data
    ///
    /// # Remarks
    ///
    /// Returns `f64::NAN` if data is empty or an entry is `f64::NAN`
    ///
    /// # Examples
    ///
    /// ```
    /// use std::f64;
    /// use statrs::statistics::IterStatistics;
    ///
    /// let x = vec![];
    /// assert!(x.into_iter().abs_min().is_nan());
    ///
    /// let y = vec![0.0, f64::NAN, 3.0, -2.0];
    /// assert!(y.into_iter().abs_min().is_nan());
    ///
    /// let z = vec![0.0, 3.0, -2.0];
    /// assert_eq!(z.into_iter().abs_min(), 0.0);
    /// ```
    fn abs_min(&mut self) -> T;

    /// Returns the maximum absolute value in the data
    ///
    /// # Remarks
    ///
    /// Returns `f64::NAN` if data is empty or an entry is `f64::NAN`
    ///
    /// # Examples
    ///
    /// ```
    /// use std::f64;
    /// use statrs::statistics::IterStatistics;
    ///
    /// let x = vec![];
    /// assert!(x.into_iter().abs_max().is_nan());
    ///
    /// let y = vec![0.0, f64::NAN, 3.0, -2.0];
    /// assert!(y.into_iter().abs_max().is_nan());
    ///
    /// let z = vec![0.0, 3.0, -2.0, -8.0];
    /// assert_eq!(z.into_iter().abs_max(), 8.0);
    /// ```
    fn abs_max(&mut self) -> T;
}

impl<T: Iterator<Item = f64>> IterStatistics<f64> for T {
    fn abs_min(&mut self) -> f64 {
        match self.next() {
            None => f64::NAN,
            Some(x) => {
                self.map(|x| x.abs())
                    .fold(x.abs(),
                          |acc, x| if x < acc || x.is_nan() { x } else { acc })
            }
        }
    }

    fn abs_max(&mut self) -> f64 {
        match self.next() {
            None => f64::NAN,
            Some(x) => {
                self.map(|x| x.abs())
                    .fold(x.abs(),
                          |acc, x| if x > acc || x.is_nan() { x } else { acc })
            }
        }
    }
}
<|endoftext|>


<commit_before>/// This is an implementation of an echo server.

/// One process reads input and sends it to the other process, which outputs it.
#[macro_use]
extern crate session_types;
use session_types::*;

use std::thread::spawn;

type Srv = Offer<Eps, Recv<String, Var<Z>>>;
fn srv(c: Chan<(), Rec<Srv>>) {
    let mut c = c.enter();

    loop {
        c = offer!{ c,
            CLOSE => {
                println!("Closing server.");
                c.close();
                break
            },
            RECV => {
                let (c, s) = c.recv();
                println!("Received: {}", s);
                c.zero()
            }
        };
    }
}

type Cli = <Srv as HasDual>::Dual;
fn cli(c: Chan<(), Rec<Cli>>) {
    let stdin = std::io::stdin();
    let mut count = 0usize;

    let mut c = c.enter();
    let mut buf = "".to_string();
    loop {
        stdin.read_line(&mut buf).ok().unwrap();
        if !buf.is_empty() {
            buf.pop();
        }
        match &buf[..] {
            "q" => {
                let c = c.sel2().send(format!("{} lines sent", count));
                c.zero().sel1().close();
                println!("Client quitting");
                break;
            }
            _ => {
                c = c.sel2().send(buf.clone()).zero();
                buf.clear();
                count += 1;
            }
        }
    }
}

fn main() {
    let (c1, c2) = session_channel();
    spawn(move || srv(c1));
    cli(c2);
}
<commit_msg>examples: Minor fixes for echo-server<commit_after>/// This is an implementation of an echo server.

/// One process reads input and sends it to the other process, which outputs it.
#[macro_use]
extern crate session_types;
use session_types::*;

use std::thread::spawn;

type Srv = Offer<Eps, Recv<String, Var<Z>>>;
fn srv(c: Chan<(), Rec<Srv>>) {
    let mut c = c.enter();

    loop {
        c = offer!{ c,
            CLOSE => {
                println!("Closing server.");
                c.close();
                break
            },
            RECV => {
                let (c, s) = c.recv();
                println!("Received: {}", s);
                c.zero()
            }
        };
    }
}

type Cli = <Srv as HasDual>::Dual;
fn cli(c: Chan<(), Rec<Cli>>) {
    let stdin = std::io::stdin();
    let mut count = 0usize;

    let mut c = c.enter();
    let mut buf = String::with_capacity(1024);
    loop {
        stdin.read_line(&mut buf).ok().unwrap();
        if !buf.is_empty() {
            buf.pop();
        }
        match &buf[..] {
            "q" => {
                let c = c.sel2().send(format!("{} lines sent", count));
                c.zero().sel1().close();
                println!("Client quitting");
                break;
            }
            _ => {
                c = c.sel2().send(buf.clone()).zero();
                buf.clear();
                count += 1;
            }
        }
    }
}

fn main() {
    let (c1, c2) = session_channel();
    let t = spawn(move || srv(c1));
    cli(c2);
    let _ = t.join();
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use std::path::{Path, PathBuf};
use structopt::StructOpt;
use thiserror::Error;

use crate::app::conf::ConfigurationFile;
use crate::app::TransportWrapper;
use crate::transport::hyperdebug::c2d2::C2d2Flavor;
use crate::transport::hyperdebug::StandardFlavor;
use crate::transport::{EmptyTransport, Transport};
use crate::util::parse_int::ParseInt;

mod cw310;
mod hyperdebug;
mod proxy;
mod ultradebug;
mod verilator;

#[derive(Debug, StructOpt)]
pub struct BackendOpts {
    #[structopt(long, help = "Name of the debug interface")]
    interface: Option<String>,

    #[structopt(long, parse(try_from_str = u16::from_str),
                help="USB Vendor ID of the interface")]
    usb_vid: Option<u16>,
    #[structopt(long, parse(try_from_str = u16::from_str),
                help="USB Product ID of the interface")]
    usb_pid: Option<u16>,
    #[structopt(long, help = "USB serial number of the interface")]
    usb_serial: Option<String>,

    #[structopt(flatten)]
    verilator_opts: verilator::VerilatorOpts,

    #[structopt(flatten)]
    proxy_opts: proxy::ProxyOpts,

    #[structopt(long, help = "Configuration files")]
    conf: Option<PathBuf>,
}

#[derive(Error, Debug)]
pub enum Error {
    #[error("unknown interface {0}")]
    UnknownInterface(String),
}

/// Creates the requested backend interface according to [`BackendOpts`].
pub fn create(args: &BackendOpts, default_interface: &str) -> Result<TransportWrapper> {
    let interface = args.interface.as_deref().unwrap_or(default_interface);
    let mut env = TransportWrapper::new(match interface {
        "null" => create_empty_transport(),
        "proxy" => proxy::create(&args.proxy_opts),
        "verilator" => verilator::create(&args.verilator_opts),
        "ultradebug" => ultradebug::create(args),
        "hyperdebug" => hyperdebug::create::<StandardFlavor>(args),
        "c2d2" => hyperdebug::create::<C2d2Flavor>(args),
        "cw310" => cw310::create(args),
        _ => Err(Error::UnknownInterface(interface.to_string()).into()),
    }?);
    for conf_file in &args.conf {
        process_config_file(&mut env, conf_file)?
    }
    Ok(env)
}

pub fn create_empty_transport() -> Result<Box<dyn Transport>> {
    Ok(Box::new(EmptyTransport))
}

fn process_config_file(env: &mut TransportWrapper, conf_file: &Path) -> Result<()> {
    log::debug!("Reading config file {:?}", conf_file);
    let conf_data = std::fs::read_to_string(conf_file).expect("Unable to read configuration file");
    let res: ConfigurationFile =
        serde_json::from_str(&conf_data).expect("Unable to parse configuration file");

    let subdir = conf_file.parent().unwrap_or_else(|| Path::new(""));
    for included_conf_file in &res.includes {
        let path = subdir.join(included_conf_file);
        process_config_file(env, &path)?
    }
    env.add_configuration_file(res)
}
<commit_msg>[opentitantool] Include context in conf errors<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use std::path::{Path, PathBuf};
use structopt::StructOpt;
use thiserror::Error;

use crate::app::conf::ConfigurationFile;
use crate::app::TransportWrapper;
use crate::transport::hyperdebug::c2d2::C2d2Flavor;
use crate::transport::hyperdebug::StandardFlavor;
use crate::transport::{EmptyTransport, Transport};
use crate::util::parse_int::ParseInt;

mod cw310;
mod hyperdebug;
mod proxy;
mod ultradebug;
mod verilator;

#[derive(Debug, StructOpt)]
pub struct BackendOpts {
    #[structopt(long, help = "Name of the debug interface")]
    interface: Option<String>,

    #[structopt(long, parse(try_from_str = u16::from_str),
                help="USB Vendor ID of the interface")]
    usb_vid: Option<u16>,
    #[structopt(long, parse(try_from_str = u16::from_str),
                help="USB Product ID of the interface")]
    usb_pid: Option<u16>,
    #[structopt(long, help = "USB serial number of the interface")]
    usb_serial: Option<String>,

    #[structopt(flatten)]
    verilator_opts: verilator::VerilatorOpts,

    #[structopt(flatten)]
    proxy_opts: proxy::ProxyOpts,

    #[structopt(long, help = "Configuration files")]
    conf: Option<PathBuf>,
}

#[derive(Error, Debug)]
pub enum Error {
    #[error("Unknown interface {0}")]
    UnknownInterface(String),
    #[error("Loading configuration file `{0}`: {1}")]
    ConfReadError(PathBuf, anyhow::Error),
    #[error("Parsing configuration file `{0}`: {1}")]
    ConfParseError(PathBuf, anyhow::Error),
}

/// Creates the requested backend interface according to [`BackendOpts`].
pub fn create(args: &BackendOpts, default_interface: &str) -> Result<TransportWrapper> {
    let interface = args.interface.as_deref().unwrap_or(default_interface);
    let mut env = TransportWrapper::new(match interface {
        "null" => create_empty_transport(),
        "proxy" => proxy::create(&args.proxy_opts),
        "verilator" => verilator::create(&args.verilator_opts),
        "ultradebug" => ultradebug::create(args),
        "hyperdebug" => hyperdebug::create::<StandardFlavor>(args),
        "c2d2" => hyperdebug::create::<C2d2Flavor>(args),
        "cw310" => cw310::create(args),
        _ => Err(Error::UnknownInterface(interface.to_string()).into()),
    }?);
    for conf_file in &args.conf {
        process_config_file(&mut env, conf_file)?
    }
    Ok(env)
}

pub fn create_empty_transport() -> Result<Box<dyn Transport>> {
    Ok(Box::new(EmptyTransport))
}

fn process_config_file(env: &mut TransportWrapper, conf_file: &Path) -> Result<()> {
    log::debug!("Reading config file {:?}", conf_file);
    let conf_data = std::fs::read_to_string(conf_file)
        .map_err(|e| Error::ConfReadError(conf_file.to_path_buf(), e.into()))?;
    let res: ConfigurationFile = serde_json::from_str(&conf_data)
        .map_err(|e| Error::ConfParseError(conf_file.to_path_buf(), e.into()))?;

    let subdir = conf_file.parent().unwrap_or_else(|| Path::new(""));
    for included_conf_file in &res.includes {
        let path = subdir.join(included_conf_file);
        process_config_file(env, &path)?
    }
    env.add_configuration_file(res)
}
<|endoftext|>


<commit_before>// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture

#[derive(Default, Clone)]
pub struct Registers {
    pub rax:    u64,
    pub rbx:    u64,
    pub rcx:    u64,
    pub rdx:    u64,
    pub rsp:    u64,
    pub rbp:    u64,
    pub rsi:    u64,
    pub rdi:    u64,
    pub r8:     u64,
    pub r9:     u64,
    pub r10:    u64,
    pub r11:    u64,
    pub r12:    u64,
    pub r13:    u64,
    pub r14:    u64,
    pub r15:    u64,
    pub rflags: u64,
    pub rip:    u64,
    pub es:     u16,
    pub cs:     u16,
    pub ss:     u16,
    pub ds:     u16,
    pub fs:     u16,
    pub gs:     u16,
    pub gdtr:   u64,
    pub ldtr:   u64,
    pub idtr:   u64,
    pub fpu:    Option<Box<FPU>>,
    pub avx:    Option<Box<AVX>>,
}

const FLAG_CF: u8 = 0;
const FLAG_PF: u8 = 2;
const FLAG_AF: u8 = 4;
const FLAG_ZF: u8 = 6;
const FLAG_SF: u8 = 7;
const FLAG_DF: u8 = 10;
const FLAG_OF: u8 = 11;

pub const STATUS_MASK: u64 = 0
    | (1 << FLAG_CF)
    | (1 << FLAG_PF)
    | (1 << FLAG_AF)
    | (1 << FLAG_ZF)
    | (1 << FLAG_SF)
    | (1 << FLAG_DF)
    | (1 << FLAG_OF);

macro_rules! flag {
    ($index:ident, $get:ident, $set:ident) => {
        #[inline]
        pub fn $get(&self) -> bool {
            (self.rflags & (1 << $index)) > 0
        }

        #[inline]
        pub fn $set(&mut self, is_set: bool) {
            if is_set {
                self.rflags |= 1 << $index;
            } else {
                self.rflags &= !(1 << $index);
            }
        }
    };
}

macro_rules! reg {
    ($reg:ident, $get_64:ident, $get_32:ident, $get_16:ident, $get_8l:ident, $set_64:ident, $set_32:ident, $set_16:ident, $set_8l:ident) => {
        #[inline]
        pub fn $get_64(&self) -> u64 {
            self.$reg
        }

        #[inline]
        pub fn $get_32(&self) -> u32 {
            (self.$reg & 0xFFFF_FFFF) as u32
        }

        #[inline]
        pub fn $get_16(&self) -> u16 {
            (self.$reg & 0xFFFF) as u16
        }

        #[inline]
        pub fn $get_8l(&self) -> u8 {
            (self.$reg & 0xFF) as u8
        }

        #[inline]
        pub fn $set_64(&mut self, value: u64) {
            self.$reg = value;
        }

        #[inline]
        pub fn $set_32(&mut self, value: u32) {
            self.$reg &= 0xFFFF_FFFF_0000_0000;
            self.$reg |= (value as u64) & 0xFFFF_FFFF;
        }

        #[inline]
        pub fn $set_16(&mut self, value: u16) {
            self.$reg &= 0xFFFF_FFFF_FFFF_0000;
            self.$reg |= (value as u64) & 0xFFFF;
        }

        #[inline]
        pub fn $set_8l(&mut self, value: u8) {
            self.$reg &= 0xFFFF_FFFF_FFFF_FF00;
            self.$reg |= (value as u64) & 0xFF;
        }
    };
}

// generate accessor and mutator for the "h" register flavor.
// that is, the 2nd least significant byte, such as AH.
macro_rules! regh {
    ($reg:ident, $get_8h:ident, $set_8h:ident) => {
        #[inline]
        pub fn $get_8h(&self) -> u8 {
            ((self.$reg & 0xFF00) >> 8) as u8
        }

        #[inline]
        pub fn $set_8h(&mut self, value: u8) {
            self.$reg &= 0xFFFF_FFFF_FFFF_00FF;
            self.$reg |= ((value as u64) & 0xFF) << 8;
        }
    };
}

impl Registers {
    reg!(rax, rax, eax, ax, al, set_rax, set_eax, set_ax, set_al);

    regh!(rax, ah, set_ah);

    reg!(rbx, rbx, ebx, bx, bl, set_rbx, set_ebx, set_bx, set_bl);

    regh!(rbx, bh, set_bh);

    reg!(rcx, rcx, ecx, cx, cl, set_rcx, set_ecx, set_cx, set_cl);

    regh!(rcx, ch, set_ch);

    reg!(rdx, rdx, edx, dx, dl, set_rdx, set_edx, set_dx, set_dl);

    regh!(rdx, dh, set_dh);

    reg!(r8, r8, r8d, r8w, r8b, set_r8, set_r8d, set_r8w, set_r8b);

    reg!(r9, r9, r9d, r9w, r9b, set_r9, set_r9d, set_r9w, set_r9b);

    reg!(r10, r10, r10d, r10w, r10b, set_r10, set_r10d, set_r10w, set_r10b);

    reg!(r11, r11, r11d, r11w, r11b, set_r11, set_r11d, set_r11w, set_r11b);

    reg!(r12, r12, r12d, r12w, r12b, set_r12, set_r12d, set_r12w, set_r12b);

    reg!(r13, r13, r13d, r13w, r13b, set_r13, set_r13d, set_r13w, set_r13b);

    reg!(r14, r14, r14d, r14w, r14b, set_r14, set_r14d, set_r14w, set_r14b);

    reg!(r15, r15, r15d, r15w, r15b, set_r15, set_r15d, set_r15w, set_r15b);

    reg!(rsi, rsi, esi, si, sil, set_rsi, set_esi, set_si, set_sil);

    reg!(rdi, rdi, edi, di, dil, set_rdi, set_edi, set_di, set_dil);

    reg!(rsp, rsp, esp, sp, spl, set_rsp, set_esp, set_sp, set_spl);

    reg!(rbp, rbp, ebp, bp, bpl, set_rbp, set_ebp, set_bp, set_bpl);

    // register IPL is made up, please don't use.
    reg!(rip, rip, eip, ip, _ipl_fake, set_rip, set_eip, set_ip, _set_ipl);

    flag!(FLAG_CF, cf, set_cf);

    flag!(FLAG_PF, pf, set_pf);

    flag!(FLAG_AF, af, set_af);

    flag!(FLAG_ZF, zf, set_zf);

    flag!(FLAG_SF, sf, set_sf);

    flag!(FLAG_DF, df, set_df);

    flag!(FLAG_OF, of, set_of);

    pub fn es(&self) -> u16 {
        self.es
    }

    pub fn cs(&self) -> u16 {
        self.cs
    }

    pub fn ss(&self) -> u16 {
        self.ss
    }

    pub fn ds(&self) -> u16 {
        self.ds
    }

    pub fn fs(&self) -> u16 {
        self.fs
    }

    pub fn gs(&self) -> u16 {
        self.gs
    }

    // flags
    // https://www.cs.utexas.edu/~byoung/cs429/condition-codes.pdf

    #[inline]
    pub fn rflags(&self) -> u64 {
        self.rflags
    }
}

#[derive(Default, Clone)]
pub struct FPU {
    // TODO: this is not thought out at all.
    pub st0:        f64,
    pub st1:        f64,
    pub st2:        f64,
    pub st3:        f64,
    pub st4:        f64,
    pub st5:        f64,
    pub st6:        f64,
    pub st7:        f64,
    pub x87control: u64,
    pub x87status:  u64,
    pub x87tag:     u64,
}

#[derive(Default, Clone)]
pub struct AVX {
    pub zmm0:  [u8; 32],
    pub zmm1:  [u8; 32],
    pub zmm2:  [u8; 32],
    pub zmm3:  [u8; 32],
    pub zmm4:  [u8; 32],
    pub zmm5:  [u8; 32],
    pub zmm6:  [u8; 32],
    pub zmm7:  [u8; 32],
    pub zmm8:  [u8; 32],
    pub zmm9:  [u8; 32],
    pub zmm10: [u8; 32],
    pub zmm11: [u8; 32],
    pub zmm12: [u8; 32],
    pub zmm13: [u8; 32],
    pub zmm14: [u8; 32],
    pub zmm15: [u8; 32],
    pub zmm16: [u8; 32],
    pub zmm17: [u8; 32],
    pub zmm18: [u8; 32],
    pub zmm19: [u8; 32],
    pub zmm20: [u8; 32],
    pub zmm21: [u8; 32],
    pub zmm22: [u8; 32],
    pub zmm23: [u8; 32],
    pub zmm24: [u8; 32],
    pub zmm25: [u8; 32],
    pub zmm26: [u8; 32],
    pub zmm27: [u8; 32],
    pub zmm28: [u8; 32],
    pub zmm29: [u8; 32],
    pub zmm30: [u8; 32],
    pub zmm31: [u8; 32],
}
<commit_msg>emu: reg: can't leave upper 32 bit during mov unless working with lower 16-bits<commit_after>// https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/x64-architecture

#[derive(Default, Clone)]
pub struct Registers {
    pub rax:    u64,
    pub rbx:    u64,
    pub rcx:    u64,
    pub rdx:    u64,
    pub rsp:    u64,
    pub rbp:    u64,
    pub rsi:    u64,
    pub rdi:    u64,
    pub r8:     u64,
    pub r9:     u64,
    pub r10:    u64,
    pub r11:    u64,
    pub r12:    u64,
    pub r13:    u64,
    pub r14:    u64,
    pub r15:    u64,
    pub rflags: u64,
    pub rip:    u64,
    pub es:     u16,
    pub cs:     u16,
    pub ss:     u16,
    pub ds:     u16,
    pub fs:     u16,
    pub gs:     u16,
    pub gdtr:   u64,
    pub ldtr:   u64,
    pub idtr:   u64,
    pub fpu:    Option<Box<FPU>>,
    pub avx:    Option<Box<AVX>>,
}

const FLAG_CF: u8 = 0;
const FLAG_PF: u8 = 2;
const FLAG_AF: u8 = 4;
const FLAG_ZF: u8 = 6;
const FLAG_SF: u8 = 7;
const FLAG_DF: u8 = 10;
const FLAG_OF: u8 = 11;

pub const STATUS_MASK: u64 = 0
    | (1 << FLAG_CF)
    | (1 << FLAG_PF)
    | (1 << FLAG_AF)
    | (1 << FLAG_ZF)
    | (1 << FLAG_SF)
    | (1 << FLAG_DF)
    | (1 << FLAG_OF);

macro_rules! flag {
    ($index:ident, $get:ident, $set:ident) => {
        #[inline]
        pub fn $get(&self) -> bool {
            (self.rflags & (1 << $index)) > 0
        }

        #[inline]
        pub fn $set(&mut self, is_set: bool) {
            if is_set {
                self.rflags |= 1 << $index;
            } else {
                self.rflags &= !(1 << $index);
            }
        }
    };
}

macro_rules! reg {
    ($reg:ident, $get_64:ident, $get_32:ident, $get_16:ident, $get_8l:ident, $set_64:ident, $set_32:ident, $set_16:ident, $set_8l:ident) => {
        #[inline]
        pub fn $get_64(&self) -> u64 {
            self.$reg
        }

        #[inline]
        pub fn $get_32(&self) -> u32 {
            (self.$reg & 0xFFFF_FFFF) as u32
        }

        #[inline]
        pub fn $get_16(&self) -> u16 {
            (self.$reg & 0xFFFF) as u16
        }

        #[inline]
        pub fn $get_8l(&self) -> u8 {
            (self.$reg & 0xFF) as u8
        }

        #[inline]
        pub fn $set_64(&mut self, value: u64) {
            self.$reg = value;
        }

        #[inline]
        pub fn $set_32(&mut self, value: u32) {
            self.$reg = value as u64;
        }

        #[inline]
        pub fn $set_16(&mut self, value: u16) {
            // only lower 16-bits of a register can be set
            // without overwriting higher parts.
            // https://stackoverflow.com/questions/48449833/move-smaller-operand-into-larger-operand#comment83894774_48450559
            self.$reg &= 0xFFFF_FFFF_FFFF_0000;
            self.$reg |= (value as u64) & 0xFFFF;
        }

        #[inline]
        pub fn $set_8l(&mut self, value: u8) {
            self.$reg &= 0xFFFF_FFFF_FFFF_FF00;
            self.$reg |= (value as u64) & 0xFF;
        }
    };
}

// generate accessor and mutator for the "h" register flavor.
// that is, the 2nd least significant byte, such as AH.
macro_rules! regh {
    ($reg:ident, $get_8h:ident, $set_8h:ident) => {
        #[inline]
        pub fn $get_8h(&self) -> u8 {
            ((self.$reg & 0xFF00) >> 8) as u8
        }

        #[inline]
        pub fn $set_8h(&mut self, value: u8) {
            self.$reg &= 0xFFFF_FFFF_FFFF_00FF;
            self.$reg |= ((value as u64) & 0xFF) << 8;
        }
    };
}

impl Registers {
    reg!(rax, rax, eax, ax, al, set_rax, set_eax, set_ax, set_al);

    regh!(rax, ah, set_ah);

    reg!(rbx, rbx, ebx, bx, bl, set_rbx, set_ebx, set_bx, set_bl);

    regh!(rbx, bh, set_bh);

    reg!(rcx, rcx, ecx, cx, cl, set_rcx, set_ecx, set_cx, set_cl);

    regh!(rcx, ch, set_ch);

    reg!(rdx, rdx, edx, dx, dl, set_rdx, set_edx, set_dx, set_dl);

    regh!(rdx, dh, set_dh);

    reg!(r8, r8, r8d, r8w, r8b, set_r8, set_r8d, set_r8w, set_r8b);

    reg!(r9, r9, r9d, r9w, r9b, set_r9, set_r9d, set_r9w, set_r9b);

    reg!(r10, r10, r10d, r10w, r10b, set_r10, set_r10d, set_r10w, set_r10b);

    reg!(r11, r11, r11d, r11w, r11b, set_r11, set_r11d, set_r11w, set_r11b);

    reg!(r12, r12, r12d, r12w, r12b, set_r12, set_r12d, set_r12w, set_r12b);

    reg!(r13, r13, r13d, r13w, r13b, set_r13, set_r13d, set_r13w, set_r13b);

    reg!(r14, r14, r14d, r14w, r14b, set_r14, set_r14d, set_r14w, set_r14b);

    reg!(r15, r15, r15d, r15w, r15b, set_r15, set_r15d, set_r15w, set_r15b);

    reg!(rsi, rsi, esi, si, sil, set_rsi, set_esi, set_si, set_sil);

    reg!(rdi, rdi, edi, di, dil, set_rdi, set_edi, set_di, set_dil);

    reg!(rsp, rsp, esp, sp, spl, set_rsp, set_esp, set_sp, set_spl);

    reg!(rbp, rbp, ebp, bp, bpl, set_rbp, set_ebp, set_bp, set_bpl);

    // register IPL is made up, please don't use.
    reg!(rip, rip, eip, ip, _ipl_fake, set_rip, set_eip, set_ip, _set_ipl);

    flag!(FLAG_CF, cf, set_cf);

    flag!(FLAG_PF, pf, set_pf);

    flag!(FLAG_AF, af, set_af);

    flag!(FLAG_ZF, zf, set_zf);

    flag!(FLAG_SF, sf, set_sf);

    flag!(FLAG_DF, df, set_df);

    flag!(FLAG_OF, of, set_of);

    pub fn es(&self) -> u16 {
        self.es
    }

    pub fn cs(&self) -> u16 {
        self.cs
    }

    pub fn ss(&self) -> u16 {
        self.ss
    }

    pub fn ds(&self) -> u16 {
        self.ds
    }

    pub fn fs(&self) -> u16 {
        self.fs
    }

    pub fn gs(&self) -> u16 {
        self.gs
    }

    // flags
    // https://www.cs.utexas.edu/~byoung/cs429/condition-codes.pdf

    #[inline]
    pub fn rflags(&self) -> u64 {
        self.rflags
    }
}

#[derive(Default, Clone)]
pub struct FPU {
    // TODO: this is not thought out at all.
    pub st0:        f64,
    pub st1:        f64,
    pub st2:        f64,
    pub st3:        f64,
    pub st4:        f64,
    pub st5:        f64,
    pub st6:        f64,
    pub st7:        f64,
    pub x87control: u64,
    pub x87status:  u64,
    pub x87tag:     u64,
}

#[derive(Default, Clone)]
pub struct AVX {
    pub zmm0:  [u8; 32],
    pub zmm1:  [u8; 32],
    pub zmm2:  [u8; 32],
    pub zmm3:  [u8; 32],
    pub zmm4:  [u8; 32],
    pub zmm5:  [u8; 32],
    pub zmm6:  [u8; 32],
    pub zmm7:  [u8; 32],
    pub zmm8:  [u8; 32],
    pub zmm9:  [u8; 32],
    pub zmm10: [u8; 32],
    pub zmm11: [u8; 32],
    pub zmm12: [u8; 32],
    pub zmm13: [u8; 32],
    pub zmm14: [u8; 32],
    pub zmm15: [u8; 32],
    pub zmm16: [u8; 32],
    pub zmm17: [u8; 32],
    pub zmm18: [u8; 32],
    pub zmm19: [u8; 32],
    pub zmm20: [u8; 32],
    pub zmm21: [u8; 32],
    pub zmm22: [u8; 32],
    pub zmm23: [u8; 32],
    pub zmm24: [u8; 32],
    pub zmm25: [u8; 32],
    pub zmm26: [u8; 32],
    pub zmm27: [u8; 32],
    pub zmm28: [u8; 32],
    pub zmm29: [u8; 32],
    pub zmm30: [u8; 32],
    pub zmm31: [u8; 32],
}
<|endoftext|>


<commit_before>//! TODO documentation

use wlroots_sys::{wlr_output_cursor, wlr_output_cursor_create, wlr_output_cursor_destroy,
                  wlr_output_cursor_move, wlr_output_cursor_set_image,
                  wlr_output_cursor_set_surface};

use {Image, Output, OutputHandle, Surface, UpgradeHandleErr};

#[derive(Debug, Eq, PartialEq)]
pub struct OutputCursor {
    cursor: *mut wlr_output_cursor,
    output_handle: OutputHandle
}

impl OutputCursor {
    /// Creates a new `OutputCursor` that's bound to the given `Output`.
    ///
    /// When the `Output` is destroyed, this can no longer be used.
    ///
    /// # Ergonomics
    ///
    /// To make this easier for you, I would suggest putting the `OutputCursor` in your
    /// `OutputHandler` implementor's state so that when the `Output` is removed you
    /// just don't have to think about it and it will clean itself up by itself.
    pub fn new(output: &mut Output) -> Option<OutputCursor> {
        unsafe {
            let output_handle = output.weak_reference();
            let cursor = wlr_output_cursor_create(output.as_ptr());
            if cursor.is_null() {
                None
            } else {
                Some(OutputCursor { cursor,
                                    output_handle })
            }
        }
    }

    /// Sets the hardware cursor's image.
    pub fn set_image(&mut self, image: &Image) -> bool {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| {
                                                 wlr_output_cursor_set_image(cursor,
                                                                             image.pixels.as_ptr(),
                                                                             image.stride,
                                                                             image.width,
                                                                             image.height,
                                                                             image.hotspot_x,
                                                                             image.hotspot_y)
                                             });
            match res {
                Ok(res) => res,
                Err(UpgradeHandleErr::AlreadyDropped) => false,
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Sets the hardware cursor's surface.
    pub fn set_surface(&mut self, surface: Option<Surface>, hotspot_x: i32, hotspot_y: i32) {
        unsafe {
            let surface_ptr = surface.map(|surface| surface.as_ptr())
                                     .unwrap_or_else(|| ptr::null_mut());
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| {
                                                 wlr_output_cursor_set_surface(cursor,
                                                                               surface_ptr,
                                                                               hotspot_x,
                                                                               hotspot_y)
                                             });
            match res {
                Ok(_) | Err(UpgradeHandleErr::AlreadyDropped) => {}
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Moves the hardware cursor to the desired location
    pub fn move_to(&mut self, x: f64, y: f64) -> bool {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| wlr_output_cursor_move(cursor, x, y));
            match res {
                Ok(res) => res,
                Err(UpgradeHandleErr::AlreadyDropped) => false,
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Get the coordinates of the cursor.
    ///
    /// Returned value is in (x, y) format.
    pub fn coords(&self) -> (f64, f64) {
        unsafe { ((*self.cursor).x, (*self.cursor).y) }
    }

    /// Determines if the hardware cursor is enabled or not.
    pub fn enabled(&self) -> bool {
        unsafe { (*self.cursor).enabled }
    }

    /// Determines if the hardware cursor is visible or not.
    pub fn visible(&self) -> bool {
        unsafe { (*self.cursor).visible }
    }

    /// Gets the width and height of the hardware cursor.
    ///
    /// Returned value is in (width, height) format.
    pub fn size(&self) -> (u32, u32) {
        unsafe { ((*self.cursor).width, (*self.cursor).height) }
    }

    /// Gets the hotspot coordinates of the hardware cursor.
    ///
    /// Returned value is in (x, y) coordinates.
    pub fn hotspots(&self) -> (i32, i32) {
        unsafe { ((*self.cursor).hotspot_x, (*self.cursor).hotspot_y) }
    }
}

impl Drop for OutputCursor {
    fn drop(&mut self) {
        unsafe { wlr_output_cursor_destroy(self.cursor) }
    }
}
<commit_msg>Added OutputCursor::{texture,surface}<commit_after>//! TODO documentation

use std::ptr;
use wlroots_sys::{wlr_output_cursor, wlr_output_cursor_create, wlr_output_cursor_destroy,
                  wlr_output_cursor_move, wlr_output_cursor_set_image,
                  wlr_output_cursor_set_surface};

use {Image, Output, OutputHandle, Surface, SurfaceHandle, Texture, UpgradeHandleErr};

#[derive(Debug, Eq, PartialEq)]
pub struct OutputCursor {
    cursor: *mut wlr_output_cursor,
    output_handle: OutputHandle
}

impl OutputCursor {
    /// Creates a new `OutputCursor` that's bound to the given `Output`.
    ///
    /// When the `Output` is destroyed, this can no longer be used.
    ///
    /// # Ergonomics
    ///
    /// To make this easier for you, I would suggest putting the `OutputCursor` in your
    /// `OutputHandler` implementor's state so that when the `Output` is removed you
    /// just don't have to think about it and it will clean itself up by itself.
    pub fn new(output: &mut Output) -> Option<OutputCursor> {
        unsafe {
            let output_handle = output.weak_reference();
            let cursor = wlr_output_cursor_create(output.as_ptr());
            if cursor.is_null() {
                None
            } else {
                Some(OutputCursor { cursor,
                                    output_handle })
            }
        }
    }

    /// Sets the hardware cursor's image.
    pub fn set_image(&mut self, image: &Image) -> bool {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| {
                                                 wlr_output_cursor_set_image(cursor,
                                                                             image.pixels.as_ptr(),
                                                                             image.stride,
                                                                             image.width,
                                                                             image.height,
                                                                             image.hotspot_x,
                                                                             image.hotspot_y)
                                             });
            match res {
                Ok(res) => res,
                Err(UpgradeHandleErr::AlreadyDropped) => false,
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Sets the hardware cursor's surface.
    pub fn set_surface(&mut self, surface: Option<Surface>, hotspot_x: i32, hotspot_y: i32) {
        unsafe {
            let surface_ptr = surface.map(|surface| surface.as_ptr())
                                     .unwrap_or_else(|| ptr::null_mut());
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| {
                                                 wlr_output_cursor_set_surface(cursor,
                                                                               surface_ptr,
                                                                               hotspot_x,
                                                                               hotspot_y)
                                             });
            match res {
                Ok(_) | Err(UpgradeHandleErr::AlreadyDropped) => {}
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Moves the hardware cursor to the desired location
    pub fn move_to(&mut self, x: f64, y: f64) -> bool {
        unsafe {
            let cursor = self.cursor;
            let res = self.output_handle.run(|_| wlr_output_cursor_move(cursor, x, y));
            match res {
                Ok(res) => res,
                Err(UpgradeHandleErr::AlreadyDropped) => false,
                err @ Err(UpgradeHandleErr::AlreadyBorrowed) => panic!(err)
            }
        }
    }

    /// Get the coordinates of the cursor.
    ///
    /// Returned value is in (x, y) format.
    pub fn coords(&self) -> (f64, f64) {
        unsafe { ((*self.cursor).x, (*self.cursor).y) }
    }

    /// Determines if the hardware cursor is enabled or not.
    pub fn enabled(&self) -> bool {
        unsafe { (*self.cursor).enabled }
    }

    /// Determines if the hardware cursor is visible or not.
    pub fn visible(&self) -> bool {
        unsafe { (*self.cursor).visible }
    }

    /// Gets the width and height of the hardware cursor.
    ///
    /// Returned value is in (width, height) format.
    pub fn size(&self) -> (u32, u32) {
        unsafe { ((*self.cursor).width, (*self.cursor).height) }
    }

    /// Gets the hotspot coordinates of the hardware cursor.
    ///
    /// Returned value is in (x, y) coordinates.
    pub fn hotspots(&self) -> (i32, i32) {
        unsafe { ((*self.cursor).hotspot_x, (*self.cursor).hotspot_y) }
    }

    /// Gets the texture for the cursor, if a software cursor is used without a
    /// surface.
    pub fn texture(&self) -> Option<Texture> {
        unsafe {
            let texture = (*self.cursor).texture;
            if texture.is_null() {
                None
            } else {
                Some(Texture::from_ptr(texture))
            }
        }
    }

    /// Gets the surface for the cursor, if using a cursor surface.
    pub fn surface(&self) -> Option<SurfaceHandle> {
        unsafe {
            let surface = (*self.cursor).surface;
            if surface.is_null() {
                None
            } else {
                Some(SurfaceHandle::from_ptr(surface))
            }
        }
    }
}

impl Drop for OutputCursor {
    fn drop(&mut self) {
        unsafe { wlr_output_cursor_destroy(self.cursor) }
    }
}
<|endoftext|>


<commit_before>mod dbscheme;
mod language;
mod ql;
mod ql_gen;

use language::Language;
use std::collections::BTreeSet as Set;
use std::fs::File;
use std::io::LineWriter;
use std::path::PathBuf;
use tracing::{error, info};

/// Given the name of the parent node, and its field information, returns the
/// name of the field's type. This may be an ad-hoc union of all the possible
/// types the field can take, in which case the union is added to `entries`.
fn make_field_type(
    parent_name: &str,
    field_name: &str,
    types: &Set<node_types::TypeName>,
    entries: &mut Vec<dbscheme::Entry>,
) -> String {
    if types.len() == 1 {
        // This field can only have a single type.
        let t = types.iter().next().unwrap();
        node_types::escape_name(&node_types::node_type_name(&t.kind, t.named))
    } else {
        // This field can have one of several types. Create an ad-hoc QL union
        // type to represent them.
        let field_union_name = format!("{}_{}_type", parent_name, field_name);
        let field_union_name = node_types::escape_name(&field_union_name);
        let members: Vec<String> = types
            .iter()
            .map(|t| node_types::escape_name(&node_types::node_type_name(&t.kind, t.named)))
            .collect();
        entries.push(dbscheme::Entry::Union(dbscheme::Union {
            name: field_union_name.clone(),
            members,
        }));
        field_union_name
    }
}

/// Adds the appropriate dbscheme information for the given field, either as a
/// column on `main_table`, or as an auxiliary table.
fn add_field(
    main_table: &mut dbscheme::Table,
    field: &node_types::Field,
    entries: &mut Vec<dbscheme::Entry>,
) {
    let field_name = match &field.name {
        None => "child".to_owned(),
        Some(x) => x.to_owned(),
    };
    let parent_name = node_types::node_type_name(&field.parent.kind, field.parent.named);
    match field.storage {
        node_types::Storage::Table { .. } => {
            // This field can appear zero or multiple times, so put
            // it in an auxiliary table.
            let field_type = make_field_type(&parent_name, &field_name, &field.types, entries);
            let field_table = dbscheme::Table {
                name: format!("{}_{}", parent_name, field_name),
                columns: vec![
                    // First column is a reference to the parent.
                    dbscheme::Column {
                        unique: false,
                        db_type: dbscheme::DbColumnType::Int,
                        name: node_types::escape_name(&parent_name),
                        ql_type: ql::Type::AtType(node_types::escape_name(&parent_name)),
                        ql_type_is_ref: true,
                    },
                    // Then an index column.
                    dbscheme::Column {
                        unique: false,
                        db_type: dbscheme::DbColumnType::Int,
                        name: "index".to_string(),
                        ql_type: ql::Type::Int,
                        ql_type_is_ref: true,
                    },
                    // And then the field
                    dbscheme::Column {
                        unique: true,
                        db_type: dbscheme::DbColumnType::Int,
                        name: node_types::escape_name(&field_type),
                        ql_type: ql::Type::AtType(field_type),
                        ql_type_is_ref: true,
                    },
                ],
                // In addition to the field being unique, the combination of
                // parent+index is unique, so add a keyset for them.
                keysets: Some(vec![
                    node_types::escape_name(&parent_name),
                    "index".to_string(),
                ]),
            };
            entries.push(dbscheme::Entry::Table(field_table));
        }
        node_types::Storage::Column => {
            // This field must appear exactly once, so we add it as
            // a column to the main table for the node type.
            let field_type = make_field_type(&parent_name, &field_name, &field.types, entries);
            main_table.columns.push(dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: node_types::escape_name(&field_name),
                ql_type: ql::Type::AtType(field_type),
                ql_type_is_ref: true,
            });
        }
    }
}

/// Converts the given tree-sitter node types into CodeQL dbscheme entries.
fn convert_nodes(nodes: &Vec<node_types::Entry>) -> Vec<dbscheme::Entry> {
    let mut entries: Vec<dbscheme::Entry> = vec![
        create_location_table(),
        create_source_location_prefix_table(),
    ];
    let mut top_members: Vec<String> = Vec::new();

    for node in nodes {
        match &node {
            node_types::Entry::Union {
                type_name,
                members: n_members,
            } => {
                // It's a tree-sitter supertype node, for which we create a union
                // type.
                let mut members: Vec<String> = Vec::new();
                for n_member in n_members {
                    members.push(node_types::escape_name(&node_types::node_type_name(
                        &n_member.kind,
                        n_member.named,
                    )))
                }
                entries.push(dbscheme::Entry::Union(dbscheme::Union {
                    name: node_types::escape_name(&node_types::node_type_name(
                        &type_name.kind,
                        type_name.named,
                    )),
                    members,
                }));
            }
            node_types::Entry::Table { type_name, fields } => {
                // It's a product type, defined by a table.
                let name = node_types::node_type_name(&type_name.kind, type_name.named);
                let mut main_table = dbscheme::Table {
                    name: node_types::escape_name(&(format!("{}_def", name))),
                    columns: vec![dbscheme::Column {
                        db_type: dbscheme::DbColumnType::Int,
                        name: "id".to_string(),
                        unique: true,
                        ql_type: ql::Type::AtType(node_types::escape_name(&name)),
                        ql_type_is_ref: false,
                    }],
                    keysets: None,
                };
                top_members.push(node_types::escape_name(&name));

                // If the type also has fields or children, then we create either
                // auxiliary tables or columns in the defining table for them.
                for field in fields {
                    add_field(&mut main_table, &field, &mut entries);
                }

                if fields.is_empty() {
                    // There were no fields and no children, so it's a leaf node in
                    // the TS grammar. Add a column for the node text.
                    main_table.columns.push(dbscheme::Column {
                        unique: false,
                        db_type: dbscheme::DbColumnType::String,
                        name: "text".to_string(),
                        ql_type: ql::Type::String,
                        ql_type_is_ref: true,
                    });
                }

                // Finally, the type's defining table also includes the location.
                main_table.columns.push(dbscheme::Column {
                    unique: false,
                    db_type: dbscheme::DbColumnType::Int,
                    name: "loc".to_string(),
                    ql_type: ql::Type::AtType("location".to_string()),
                    ql_type_is_ref: true,
                });

                entries.push(dbscheme::Entry::Table(main_table));
            }
        }
    }

    // Create a union of all database types.
    entries.push(dbscheme::Entry::Union(dbscheme::Union {
        name: "top".to_string(),
        members: top_members,
    }));

    entries
}

fn write_dbscheme(language: &Language, entries: &[dbscheme::Entry]) -> std::io::Result<()> {
    info!(
        "Writing database schema for {} to '{}'",
        &language.name,
        match language.dbscheme_path.to_str() {
            None => "<undisplayable>",
            Some(p) => p,
        }
    );
    let file = File::create(&language.dbscheme_path)?;
    let mut file = LineWriter::new(file);
    dbscheme::write(&language.name, &mut file, &entries)
}

fn create_location_table() -> dbscheme::Entry {
    dbscheme::Entry::Table(dbscheme::Table {
        name: "location".to_string(),
        keysets: None,
        columns: vec![
            dbscheme::Column {
                unique: true,
                db_type: dbscheme::DbColumnType::Int,
                name: "id".to_string(),
                ql_type: ql::Type::AtType("location".to_string()),
                ql_type_is_ref: false,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::String,
                name: "file_path".to_string(),
                ql_type: ql::Type::String,
                ql_type_is_ref: true,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: "start_line".to_string(),
                ql_type: ql::Type::Int,
                ql_type_is_ref: true,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: "start_column".to_string(),
                ql_type: ql::Type::Int,
                ql_type_is_ref: true,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: "end_line".to_string(),
                ql_type: ql::Type::Int,
                ql_type_is_ref: true,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: "end_column".to_string(),
                ql_type: ql::Type::Int,
                ql_type_is_ref: true,
            },
        ],
    })
}

fn create_source_location_prefix_table() -> dbscheme::Entry {
    dbscheme::Entry::Table(dbscheme::Table {
        name: "sourceLocationPrefix".to_string(),
        keysets: None,
        columns: vec![dbscheme::Column {
            unique: false,
            db_type: dbscheme::DbColumnType::String,
            name: "prefix".to_string(),
            ql_type: ql::Type::String,
            ql_type_is_ref: true,
        }],
    })
}

fn main() {
    tracing_subscriber::fmt()
        .with_target(false)
        .without_time()
        .with_level(true)
        .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
        .init();

    // TODO: figure out proper dbscheme output path and/or take it from the
    // command line.
    let ruby = Language {
        name: "Ruby".to_string(),
        node_types: tree_sitter_ruby::NODE_TYPES,
        dbscheme_path: PathBuf::from("ruby.dbscheme"),
        ql_library_path: PathBuf::from("ruby_ast.qll"),
    };
    match node_types::read_node_types_str(&ruby.node_types) {
        Err(e) => {
            error!("Failed to read node-types JSON for {}: {}", ruby.name, e);
            std::process::exit(1);
        }
        Ok(nodes) => {
            let dbscheme_entries = convert_nodes(&nodes);

            match write_dbscheme(&ruby, &dbscheme_entries) {
                Err(e) => {
                    error!("Failed to write dbscheme: {}", e);
                    std::process::exit(2);
                }
                Ok(()) => {}
            }

            let classes = ql_gen::convert_nodes(&nodes);

            match ql_gen::write(&ruby, &classes) {
                Err(e) => {
                    println!("Failed to write QL library: {}", e);
                    std::process::exit(3);
                }
                Ok(()) => {}
            }
        }
    }
}
<commit_msg>Simplify error handling with `if let`<commit_after>mod dbscheme;
mod language;
mod ql;
mod ql_gen;

use language::Language;
use std::collections::BTreeSet as Set;
use std::fs::File;
use std::io::LineWriter;
use std::path::PathBuf;
use tracing::{error, info};

/// Given the name of the parent node, and its field information, returns the
/// name of the field's type. This may be an ad-hoc union of all the possible
/// types the field can take, in which case the union is added to `entries`.
fn make_field_type(
    parent_name: &str,
    field_name: &str,
    types: &Set<node_types::TypeName>,
    entries: &mut Vec<dbscheme::Entry>,
) -> String {
    if types.len() == 1 {
        // This field can only have a single type.
        let t = types.iter().next().unwrap();
        node_types::escape_name(&node_types::node_type_name(&t.kind, t.named))
    } else {
        // This field can have one of several types. Create an ad-hoc QL union
        // type to represent them.
        let field_union_name = format!("{}_{}_type", parent_name, field_name);
        let field_union_name = node_types::escape_name(&field_union_name);
        let members: Vec<String> = types
            .iter()
            .map(|t| node_types::escape_name(&node_types::node_type_name(&t.kind, t.named)))
            .collect();
        entries.push(dbscheme::Entry::Union(dbscheme::Union {
            name: field_union_name.clone(),
            members,
        }));
        field_union_name
    }
}

/// Adds the appropriate dbscheme information for the given field, either as a
/// column on `main_table`, or as an auxiliary table.
fn add_field(
    main_table: &mut dbscheme::Table,
    field: &node_types::Field,
    entries: &mut Vec<dbscheme::Entry>,
) {
    let field_name = match &field.name {
        None => "child".to_owned(),
        Some(x) => x.to_owned(),
    };
    let parent_name = node_types::node_type_name(&field.parent.kind, field.parent.named);
    match field.storage {
        node_types::Storage::Table { .. } => {
            // This field can appear zero or multiple times, so put
            // it in an auxiliary table.
            let field_type = make_field_type(&parent_name, &field_name, &field.types, entries);
            let field_table = dbscheme::Table {
                name: format!("{}_{}", parent_name, field_name),
                columns: vec![
                    // First column is a reference to the parent.
                    dbscheme::Column {
                        unique: false,
                        db_type: dbscheme::DbColumnType::Int,
                        name: node_types::escape_name(&parent_name),
                        ql_type: ql::Type::AtType(node_types::escape_name(&parent_name)),
                        ql_type_is_ref: true,
                    },
                    // Then an index column.
                    dbscheme::Column {
                        unique: false,
                        db_type: dbscheme::DbColumnType::Int,
                        name: "index".to_string(),
                        ql_type: ql::Type::Int,
                        ql_type_is_ref: true,
                    },
                    // And then the field
                    dbscheme::Column {
                        unique: true,
                        db_type: dbscheme::DbColumnType::Int,
                        name: node_types::escape_name(&field_type),
                        ql_type: ql::Type::AtType(field_type),
                        ql_type_is_ref: true,
                    },
                ],
                // In addition to the field being unique, the combination of
                // parent+index is unique, so add a keyset for them.
                keysets: Some(vec![
                    node_types::escape_name(&parent_name),
                    "index".to_string(),
                ]),
            };
            entries.push(dbscheme::Entry::Table(field_table));
        }
        node_types::Storage::Column => {
            // This field must appear exactly once, so we add it as
            // a column to the main table for the node type.
            let field_type = make_field_type(&parent_name, &field_name, &field.types, entries);
            main_table.columns.push(dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: node_types::escape_name(&field_name),
                ql_type: ql::Type::AtType(field_type),
                ql_type_is_ref: true,
            });
        }
    }
}

/// Converts the given tree-sitter node types into CodeQL dbscheme entries.
fn convert_nodes(nodes: &Vec<node_types::Entry>) -> Vec<dbscheme::Entry> {
    let mut entries: Vec<dbscheme::Entry> = vec![
        create_location_table(),
        create_source_location_prefix_table(),
    ];
    let mut top_members: Vec<String> = Vec::new();

    for node in nodes {
        match &node {
            node_types::Entry::Union {
                type_name,
                members: n_members,
            } => {
                // It's a tree-sitter supertype node, for which we create a union
                // type.
                let mut members: Vec<String> = Vec::new();
                for n_member in n_members {
                    members.push(node_types::escape_name(&node_types::node_type_name(
                        &n_member.kind,
                        n_member.named,
                    )))
                }
                entries.push(dbscheme::Entry::Union(dbscheme::Union {
                    name: node_types::escape_name(&node_types::node_type_name(
                        &type_name.kind,
                        type_name.named,
                    )),
                    members,
                }));
            }
            node_types::Entry::Table { type_name, fields } => {
                // It's a product type, defined by a table.
                let name = node_types::node_type_name(&type_name.kind, type_name.named);
                let mut main_table = dbscheme::Table {
                    name: node_types::escape_name(&(format!("{}_def", name))),
                    columns: vec![dbscheme::Column {
                        db_type: dbscheme::DbColumnType::Int,
                        name: "id".to_string(),
                        unique: true,
                        ql_type: ql::Type::AtType(node_types::escape_name(&name)),
                        ql_type_is_ref: false,
                    }],
                    keysets: None,
                };
                top_members.push(node_types::escape_name(&name));

                // If the type also has fields or children, then we create either
                // auxiliary tables or columns in the defining table for them.
                for field in fields {
                    add_field(&mut main_table, &field, &mut entries);
                }

                if fields.is_empty() {
                    // There were no fields and no children, so it's a leaf node in
                    // the TS grammar. Add a column for the node text.
                    main_table.columns.push(dbscheme::Column {
                        unique: false,
                        db_type: dbscheme::DbColumnType::String,
                        name: "text".to_string(),
                        ql_type: ql::Type::String,
                        ql_type_is_ref: true,
                    });
                }

                // Finally, the type's defining table also includes the location.
                main_table.columns.push(dbscheme::Column {
                    unique: false,
                    db_type: dbscheme::DbColumnType::Int,
                    name: "loc".to_string(),
                    ql_type: ql::Type::AtType("location".to_string()),
                    ql_type_is_ref: true,
                });

                entries.push(dbscheme::Entry::Table(main_table));
            }
        }
    }

    // Create a union of all database types.
    entries.push(dbscheme::Entry::Union(dbscheme::Union {
        name: "top".to_string(),
        members: top_members,
    }));

    entries
}

fn write_dbscheme(language: &Language, entries: &[dbscheme::Entry]) -> std::io::Result<()> {
    info!(
        "Writing database schema for {} to '{}'",
        &language.name,
        match language.dbscheme_path.to_str() {
            None => "<undisplayable>",
            Some(p) => p,
        }
    );
    let file = File::create(&language.dbscheme_path)?;
    let mut file = LineWriter::new(file);
    dbscheme::write(&language.name, &mut file, &entries)
}

fn create_location_table() -> dbscheme::Entry {
    dbscheme::Entry::Table(dbscheme::Table {
        name: "location".to_string(),
        keysets: None,
        columns: vec![
            dbscheme::Column {
                unique: true,
                db_type: dbscheme::DbColumnType::Int,
                name: "id".to_string(),
                ql_type: ql::Type::AtType("location".to_string()),
                ql_type_is_ref: false,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::String,
                name: "file_path".to_string(),
                ql_type: ql::Type::String,
                ql_type_is_ref: true,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: "start_line".to_string(),
                ql_type: ql::Type::Int,
                ql_type_is_ref: true,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: "start_column".to_string(),
                ql_type: ql::Type::Int,
                ql_type_is_ref: true,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: "end_line".to_string(),
                ql_type: ql::Type::Int,
                ql_type_is_ref: true,
            },
            dbscheme::Column {
                unique: false,
                db_type: dbscheme::DbColumnType::Int,
                name: "end_column".to_string(),
                ql_type: ql::Type::Int,
                ql_type_is_ref: true,
            },
        ],
    })
}

fn create_source_location_prefix_table() -> dbscheme::Entry {
    dbscheme::Entry::Table(dbscheme::Table {
        name: "sourceLocationPrefix".to_string(),
        keysets: None,
        columns: vec![dbscheme::Column {
            unique: false,
            db_type: dbscheme::DbColumnType::String,
            name: "prefix".to_string(),
            ql_type: ql::Type::String,
            ql_type_is_ref: true,
        }],
    })
}

fn main() {
    tracing_subscriber::fmt()
        .with_target(false)
        .without_time()
        .with_level(true)
        .with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
        .init();

    // TODO: figure out proper dbscheme output path and/or take it from the
    // command line.
    let ruby = Language {
        name: "Ruby".to_string(),
        node_types: tree_sitter_ruby::NODE_TYPES,
        dbscheme_path: PathBuf::from("ruby.dbscheme"),
        ql_library_path: PathBuf::from("ruby_ast.qll"),
    };
    match node_types::read_node_types_str(&ruby.node_types) {
        Err(e) => {
            error!("Failed to read node-types JSON for {}: {}", ruby.name, e);
            std::process::exit(1);
        }
        Ok(nodes) => {
            let dbscheme_entries = convert_nodes(&nodes);

            if let Err(e) = write_dbscheme(&ruby, &dbscheme_entries) {
                error!("Failed to write dbscheme: {}", e);
                std::process::exit(2);
            }

            let classes = ql_gen::convert_nodes(&nodes);

            if let Err(e) = ql_gen::write(&ruby, &classes) {
                println!("Failed to write QL library: {}", e);
                std::process::exit(3);
            }
        }
    }
}
<|endoftext|>


<commit_before>use super::split_pattern;
use super::super::types::parse::{KeyBuf, KeyIterator, TypeError};

/// The arguments expression given to a function declaration goes into here, which will be
/// converted into a tuple consisting of a `KeyIterator` iterator, which will collect type
/// information, and an optional description of the function.
pub fn parse_function<'a>(arg: &'a str) -> (KeyIterator<'a>, Option<&'a str>) {
    let (args, description) = split_pattern(arg, "--");
    (KeyIterator::new(args), description)
}

/// All type information will be collected from the `KeyIterator` and stored into a vector. If a
/// type error is detected, then that error will be returned instead. This is required because
/// of lifetime restrictions on `KeyIterator`, which will not live for the remainder of the
/// declared function's lifetime.
pub fn collect_arguments<'a>(args: KeyIterator<'a>) -> Result<Vec<KeyBuf>, TypeError<'a>> {
    // NOTE: Seems to be some kind of issue with Rust's compiler accepting this:
    //     Ok(args.map(|a| a.map(Into::into)?).collect::<Vec<_>>())
    // Seems to think that `a` is a `KeyBuf` when it's actually a `Result<Key, _>`.
    let mut output = Vec::new();
    for arg in args {
        output.push(arg?.into());
    }
    Ok(output)
}

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

    #[test]
    fn function_parsing() {
        let (args, description) = split_comments("a:int b:bool -- a comment");
        assert_eq!(args, "a:int b:bool");
        assert_eq!(description, Some("a comment"));
    }
}
<commit_msg>Fix Test<commit_after>use super::split_pattern;
use super::super::types::parse::{KeyBuf, KeyIterator, TypeError};

/// The arguments expression given to a function declaration goes into here, which will be
/// converted into a tuple consisting of a `KeyIterator` iterator, which will collect type
/// information, and an optional description of the function.
pub fn parse_function<'a>(arg: &'a str) -> (KeyIterator<'a>, Option<&'a str>) {
    let (args, description) = split_pattern(arg, "--");
    (KeyIterator::new(args), description)
}

/// All type information will be collected from the `KeyIterator` and stored into a vector. If a
/// type error is detected, then that error will be returned instead. This is required because
/// of lifetime restrictions on `KeyIterator`, which will not live for the remainder of the
/// declared function's lifetime.
pub fn collect_arguments<'a>(args: KeyIterator<'a>) -> Result<Vec<KeyBuf>, TypeError<'a>> {
    // NOTE: Seems to be some kind of issue with Rust's compiler accepting this:
    //     Ok(args.map(|a| a.map(Into::into)?).collect::<Vec<_>>())
    // Seems to think that `a` is a `KeyBuf` when it's actually a `Result<Key, _>`.
    let mut output = Vec::new();
    for arg in args {
        output.push(arg?.into());
    }
    Ok(output)
}

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

    #[test]
    fn function_parsing() {
        let (args, description) = split_pattern("a:int b:bool -- a comment", "--");
        assert_eq!(args, "a:int b:bool");
        assert_eq!(description, Some("a comment"));
    }
}
<|endoftext|>