<commit_before>/*! Rusty Vangers FFI bindings.

Matches "lib/renderer/src/renderer/scene/rust/vange_rs.h"
See https://github.com/KranX/Vangers/pull/517

Changelog:
  1. Add `rv_resize()`.
  0. Basic version.
!*/

use futures::executor::LocalPool;
use std::{ffi::CString, os::raw, ptr};

// Update this whenever C header changes
#[no_mangle]
pub static rv_api_1: i32 = 1;

#[repr(C)]
#[derive(Default)]
pub struct Vector3 {
    x: f32,
    y: f32,
    z: f32,
}

#[repr(C)]
#[derive(Default)]
pub struct Quaternion {
    x: f32,
    y: f32,
    z: f32,
    w: f32,
}

#[repr(C)]
#[derive(Default)]
pub struct Transform {
    position: Vector3,
    rotation: Quaternion,
}

#[repr(C)]
pub struct Rect {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}

impl Rect {
    fn to_native(&self) -> vangers::render::Rect {
        vangers::render::Rect {
            x: self.x as u16,
            y: self.y as u16,
            w: self.width as u16,
            h: self.height as u16,
        }
    }
}

#[repr(C)]
#[derive(Default)]
pub struct CameraDescription {
    fov: f32,
    aspect: f32,
    near: f32,
    far: f32,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct MapDescription {
    width: i32,
    height: i32,
    lines: *const *const u8,
    material_begin_offsets: *const u8,
    material_end_offsets: *const u8,
    material_count: i32,
    palette: *const u8,
}

struct LevelContext {
    desc: MapDescription,
    render: vangers::render::Render,
    level: vangers::level::Level,
}

pub struct Context {
    level: Option<LevelContext>,
    render_config: vangers::config::settings::Render,
    color_format: wgpu::TextureFormat,
    color_view: wgpu::TextureView,
    depth_view: wgpu::TextureView,
    extent: wgpu::Extent3d,
    queue: wgpu::Queue,
    device: wgpu::Device,
    downlevel_caps: wgpu::DownlevelCapabilities,
    _instance: wgpu::Instance,
    camera: vangers::space::Camera,
}

pub type GlFunctionDiscovery = unsafe extern "C" fn(*const raw::c_char) -> *const raw::c_void;

#[repr(C)]
pub struct InitDescriptor {
    width: u32,
    height: u32,
    gl_functor: GlFunctionDiscovery,
}

fn crate_main_views(
    device: &wgpu::Device,
    extent: wgpu::Extent3d,
    color_format: wgpu::TextureFormat,
) -> (wgpu::TextureView, wgpu::TextureView) {
    let mut texture_desc = wgpu::TextureDescriptor {
        label: None,
        size: extent,
        mip_level_count: 1,
        sample_count: 1,
        dimension: wgpu::TextureDimension::D2,
        format: wgpu::TextureFormat::R8Uint, //dummy
        usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
    };
    let color_view = {
        let hal_texture_color =
            <hal::api::Gles as hal::Api>::Texture::default_framebuffer(color_format);
        texture_desc.format = color_format;
        let color_texture = unsafe {
            device.create_texture_from_hal::<hal::api::Gles>(hal_texture_color, &texture_desc)
        };
        color_texture.create_view(&wgpu::TextureViewDescriptor::default())
    };
    let depth_view = {
        let hal_texture_depth = <hal::api::Gles as hal::Api>::Texture::default_framebuffer(
            vangers::render::DEPTH_FORMAT,
        );
        texture_desc.format = vangers::render::DEPTH_FORMAT;
        let depth_texture = unsafe {
            device.create_texture_from_hal::<hal::api::Gles>(hal_texture_depth, &texture_desc)
        };
        depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
    };
    (color_view, depth_view)
}

#[no_mangle]
pub extern "C" fn rv_init(desc: InitDescriptor) -> Option<ptr::NonNull<Context>> {
    use cgmath::Zero as _;
    use vangers::config::settings as st;

    #[cfg(feature = "env_logger")]
    let _ = env_logger::try_init();
    let mut task_pool = LocalPool::new();

    let exposed = unsafe {
        <hal::api::Gles as hal::Api>::Adapter::new_external(|name| {
            let cstr = CString::new(name).unwrap();
            (desc.gl_functor)(cstr.as_ptr())
        })
    }
    .expect("GL adapter can't be initialized");

    let instance = wgpu::Instance::new(wgpu::Backends::empty());
    let adapter = unsafe { instance.create_adapter_from_hal(exposed) };

    let limits = {
        let adapter_limits = adapter.limits();
        let desired_height = 16 << 10;
        wgpu::Limits {
            max_texture_dimension_2d: if adapter_limits.max_texture_dimension_2d < desired_height {
                println!(
                    "Adapter only supports {} texutre size, main levels are not compatible",
                    adapter_limits.max_texture_dimension_2d
                );
                adapter_limits.max_texture_dimension_2d
            } else {
                desired_height
            },
            ..wgpu::Limits::downlevel_webgl2_defaults()
        }
    };

    let (device, queue) = task_pool
        .run_until(adapter.request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: wgpu::Features::empty(),
                limits,
            },
            None,
        ))
        .ok()?;

    let extent = wgpu::Extent3d {
        width: desc.width,
        height: desc.height,
        depth_or_array_layers: 1,
    };
    let color_format = wgpu::TextureFormat::Rgba8UnormSrgb;
    let (color_view, depth_view) = crate_main_views(&device, extent, color_format);

    let ctx = Context {
        level: None,
        render_config: st::Render {
            wgpu_trace_path: String::new(),
            light: st::Light {
                pos: [1.0, 2.0, 4.0, 0.0],
                color: [1.0, 1.0, 1.0, 1.0],
                shadow: st::Shadow {
                    size: 0,
                    terrain: st::ShadowTerrain::RayTraced,
                },
            },
            terrain: st::Terrain::RayTraced,
            fog: st::Fog {
                color: [0.1, 0.2, 0.3, 1.0],
                depth: 50.0,
            },
            debug: st::DebugRender::default(),
        },
        color_format,
        color_view,
        depth_view,
        extent,
        queue,
        device,
        downlevel_caps: adapter.get_downlevel_properties(),
        _instance: instance,
        camera: vangers::space::Camera {
            loc: cgmath::Vector3::zero(),
            rot: cgmath::Quaternion::zero(),
            proj: vangers::space::Projection::Perspective(cgmath::PerspectiveFov {
                aspect: 1.0,
                near: 1.0,
                far: 100.0,
                fovy: cgmath::Deg(45.0).into(),
            }),
        },
    };
    let ptr = Box::into_raw(Box::new(ctx));
    ptr::NonNull::new(ptr)
}

#[no_mangle]
pub unsafe extern "C" fn rv_exit(ctx: *mut Context) {
    let _ctx = Box::from_raw(ctx);
}

#[no_mangle]
pub extern "C" fn rv_resize(ctx: &mut Context, width: u32, height: u32) {
    ctx.extent = wgpu::Extent3d {
        width,
        height,
        depth_or_array_layers: 1,
    };
    let (color_view, depth_view) = crate_main_views(&ctx.device, ctx.extent, ctx.color_format);
    ctx.color_view = color_view;
    ctx.depth_view = depth_view;
}

#[no_mangle]
pub extern "C" fn rv_camera_init(ctx: &mut Context, desc: CameraDescription) {
    ctx.camera.proj = vangers::space::Projection::Perspective(cgmath::PerspectiveFov {
        aspect: desc.aspect,
        near: desc.near,
        far: desc.far,
        fovy: cgmath::Deg(desc.fov).into(),
    });
}

#[no_mangle]
pub extern "C" fn rv_camera_set_transform(ctx: &mut Context, t: Transform) {
    ctx.camera.loc = cgmath::vec3(t.position.x, t.position.y, t.position.z);
    ctx.camera.rot =
        cgmath::Quaternion::new(t.rotation.w, t.rotation.x, t.rotation.y, t.rotation.z);
}

#[no_mangle]
pub extern "C" fn rv_map_init(ctx: &mut Context, desc: MapDescription) {
    let terrains = (0..desc.material_count)
        .map(|i| unsafe {
            let mut tc = vangers::level::TerrainConfig::default();
            tc.colors.start = *desc.material_begin_offsets.offset(i as isize);
            tc.colors.end = *desc.material_end_offsets.offset(i as isize);
            tc
        })
        .collect::<Box<[_]>>();

    let total = (desc.width * desc.height) as usize;
    let level = vangers::level::Level {
        size: (desc.width, desc.height),
        flood_map: vec![0; 128].into_boxed_slice(),
        flood_section_power: 7, //TODO
        height: vec![0; total].into_boxed_slice(),
        meta: vec![0; total].into_boxed_slice(),
        palette: [[0; 4]; 0x100],
        terrains,
    };

    let render = vangers::render::Render::new(
        &ctx.device,
        &ctx.queue,
        &ctx.downlevel_caps,
        &level,
        &[[0; 4]; 0x100], //TODO: objects palette
        &ctx.render_config,
        ctx.color_format,
        ctx.extent, //Note: needs update on window resize
    );
    ctx.level = Some(LevelContext {
        desc,
        render,
        level,
    });
}

#[no_mangle]
pub extern "C" fn rv_map_exit(ctx: &mut Context) {
    ctx.level = None;
}

#[no_mangle]
pub unsafe extern "C" fn rv_map_update_data(ctx: &mut Context, region: Rect) {
    let lc = ctx.level.as_mut().unwrap();
    let line_width = lc.level.size.0 as usize;

    for y in region.y..region.y + region.height {
        // In the source data, each line contains N height values followed by N meta values.
        // We copy them into separate height and meta data arrays.
        let dst_offset = y as usize * line_width + region.x as usize;
        let line = *lc.desc.lines.add(y as usize);
        ptr::copy_nonoverlapping(
            line.add(region.x as usize),
            lc.level.height[dst_offset..].as_mut_ptr(),
            region.width as usize,
        );
        ptr::copy_nonoverlapping(
            line.add(region.x as usize + line_width),
            lc.level.meta[dst_offset..].as_mut_ptr(),
            region.width as usize,
        );
    }

    lc.render.terrain.dirty_rects.push(region.to_native());
}

#[no_mangle]
pub unsafe extern "C" fn rv_map_update_palette(
    ctx: &mut Context,
    first_entry: u32,
    entries_count: u32,
    palette: *const u8,
) {
    let lc = ctx.level.as_mut().unwrap();
    let end = first_entry + entries_count;

    for (i, color) in lc.level.palette[first_entry as usize..end as usize]
        .iter_mut()
        .enumerate()
    {
        ptr::copy_nonoverlapping(palette.add(i * 3), color.first_mut().unwrap(), 3);
    }

    let dp = lc.render.terrain.dirty_palette.clone();
    lc.render.terrain.dirty_palette = if dp != (0..0) {
        dp.start.min(first_entry)..dp.end.max(end)
    } else {
        first_entry..end
    };
}

#[no_mangle]
pub extern "C" fn rv_render(ctx: &mut Context, viewport: Rect) {
    let lc = ctx.level.as_mut().unwrap();
    let targets = vangers::render::ScreenTargets {
        extent: ctx.extent,
        depth: &ctx.depth_view,
        color: &ctx.color_view,
    };
    let mut encoder = ctx
        .device
        .create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
    let mut batcher = vangers::render::Batcher::new();

    lc.render.custom_viewport = Some(viewport.to_native());
    lc.render.draw_world(
        &mut encoder,
        &mut batcher,
        &lc.level,
        &ctx.camera,
        targets,
        &ctx.device,
    );

    ctx.queue.submit(Some(encoder.finish()));
}
<commit_msg>shadows, crash<commit_after>/*! Rusty Vangers FFI bindings.

Matches "lib/renderer/src/renderer/scene/rust/vange_rs.h"
See https://github.com/KranX/Vangers/pull/517

Changelog:
  1. Add `rv_resize()`.
  0. Basic version.
!*/

use futures::executor::LocalPool;
use std::{ffi::CString, os::raw, ptr};

// Update this whenever C header changes
#[no_mangle]
pub static rv_api_1: i32 = 1;

#[repr(C)]
#[derive(Default)]
pub struct Vector3 {
    x: f32,
    y: f32,
    z: f32,
}

#[repr(C)]
#[derive(Default)]
pub struct Quaternion {
    x: f32,
    y: f32,
    z: f32,
    w: f32,
}

#[repr(C)]
#[derive(Default)]
pub struct Transform {
    position: Vector3,
    rotation: Quaternion,
}

#[repr(C)]
pub struct Rect {
    x: i32,
    y: i32,
    width: i32,
    height: i32,
}

impl Rect {
    fn to_native(&self) -> vangers::render::Rect {
        vangers::render::Rect {
            x: self.x as u16,
            y: self.y as u16,
            w: self.width as u16,
            h: self.height as u16,
        }
    }
}

#[repr(C)]
#[derive(Default)]
pub struct CameraDescription {
    fov: f32,
    aspect: f32,
    near: f32,
    far: f32,
}

#[repr(C)]
#[derive(Clone, Copy)]
pub struct MapDescription {
    width: i32,
    height: i32,
    lines: *const *const u8,
    material_begin_offsets: *const u8,
    material_end_offsets: *const u8,
    material_count: i32,
    palette: *const u8,
}

struct LevelContext {
    desc: MapDescription,
    render: vangers::render::Render,
    level: vangers::level::Level,
}

pub struct Context {
    level: Option<LevelContext>,
    render_config: vangers::config::settings::Render,
    color_format: wgpu::TextureFormat,
    color_view: wgpu::TextureView,
    depth_view: wgpu::TextureView,
    extent: wgpu::Extent3d,
    queue: wgpu::Queue,
    device: wgpu::Device,
    downlevel_caps: wgpu::DownlevelCapabilities,
    _instance: wgpu::Instance,
    camera: vangers::space::Camera,
}

pub type GlFunctionDiscovery = unsafe extern "C" fn(*const raw::c_char) -> *const raw::c_void;

#[repr(C)]
pub struct InitDescriptor {
    width: u32,
    height: u32,
    gl_functor: GlFunctionDiscovery,
}

fn crate_main_views(
    device: &wgpu::Device,
    extent: wgpu::Extent3d,
    color_format: wgpu::TextureFormat,
) -> (wgpu::TextureView, wgpu::TextureView) {
    let mut texture_desc = wgpu::TextureDescriptor {
        label: None,
        size: extent,
        mip_level_count: 1,
        sample_count: 1,
        dimension: wgpu::TextureDimension::D2,
        format: wgpu::TextureFormat::R8Uint, //dummy
        usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
    };
    let color_view = {
        let hal_texture_color =
            <hal::api::Gles as hal::Api>::Texture::default_framebuffer(color_format);
        texture_desc.format = color_format;
        let color_texture = unsafe {
            device.create_texture_from_hal::<hal::api::Gles>(hal_texture_color, &texture_desc)
        };
        color_texture.create_view(&wgpu::TextureViewDescriptor::default())
    };
    let depth_view = {
        let hal_texture_depth = <hal::api::Gles as hal::Api>::Texture::default_framebuffer(
            vangers::render::DEPTH_FORMAT,
        );
        texture_desc.format = vangers::render::DEPTH_FORMAT;
        let depth_texture = unsafe {
            device.create_texture_from_hal::<hal::api::Gles>(hal_texture_depth, &texture_desc)
        };
        depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
    };
    (color_view, depth_view)
}

#[no_mangle]
pub extern "C" fn rv_init(desc: InitDescriptor) -> Option<ptr::NonNull<Context>> {
    use cgmath::Zero as _;
    use vangers::config::settings as st;

    #[cfg(feature = "env_logger")]
    let _ = env_logger::try_init();
    let mut task_pool = LocalPool::new();

    let exposed = unsafe {
        <hal::api::Gles as hal::Api>::Adapter::new_external(|name| {
            let cstr = CString::new(name).unwrap();
            (desc.gl_functor)(cstr.as_ptr())
        })
    }
    .expect("GL adapter can't be initialized");

    let instance = wgpu::Instance::new(wgpu::Backends::empty());
    let adapter = unsafe { instance.create_adapter_from_hal(exposed) };

    let limits = {
        let adapter_limits = adapter.limits();
        let desired_height = 16 << 10;
        wgpu::Limits {
            max_texture_dimension_2d: if adapter_limits.max_texture_dimension_2d < desired_height {
                println!(
                    "Adapter only supports {} texutre size, main levels are not compatible",
                    adapter_limits.max_texture_dimension_2d
                );
                adapter_limits.max_texture_dimension_2d
            } else {
                desired_height
            },
            ..wgpu::Limits::downlevel_webgl2_defaults()
        }
    };

    let (device, queue) = task_pool
        .run_until(adapter.request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                features: wgpu::Features::empty(),
                limits,
            },
            None,
        ))
        .ok()?;

    let extent = wgpu::Extent3d {
        width: desc.width,
        height: desc.height,
        depth_or_array_layers: 1,
    };
    let color_format = wgpu::TextureFormat::Rgba8UnormSrgb;
    let (color_view, depth_view) = crate_main_views(&device, extent, color_format);

    let ctx = Context {
        level: None,
        render_config: st::Render {
            wgpu_trace_path: String::new(),
            light: st::Light {
                pos: [1.0, 2.0, 4.0, 0.0],
                color: [1.0, 1.0, 1.0, 1.0],
                shadow: st::Shadow {
                    size: 1024,
                    terrain: st::ShadowTerrain::RayTraced,
                },
            },
            terrain: st::Terrain::RayTraced,
            fog: st::Fog {
                color: [0.1, 0.2, 0.3, 1.0],
                depth: 50.0,
            },
            debug: st::DebugRender::default(),
        },
        color_format,
        color_view,
        depth_view,
        extent,
        queue,
        device,
        downlevel_caps: adapter.get_downlevel_properties(),
        _instance: instance,
        camera: vangers::space::Camera {
            loc: cgmath::Vector3::zero(),
            rot: cgmath::Quaternion::zero(),
            proj: vangers::space::Projection::Perspective(cgmath::PerspectiveFov {
                aspect: 1.0,
                near: 1.0,
                far: 100.0,
                fovy: cgmath::Deg(45.0).into(),
            }),
        },
    };
    let ptr = Box::into_raw(Box::new(ctx));
    ptr::NonNull::new(ptr)
}

#[no_mangle]
pub unsafe extern "C" fn rv_exit(ctx: *mut Context) {
    let _ctx = Box::from_raw(ctx);
}

#[no_mangle]
pub extern "C" fn rv_resize(ctx: &mut Context, width: u32, height: u32) {
    ctx.extent = wgpu::Extent3d {
        width,
        height,
        depth_or_array_layers: 1,
    };
    let (color_view, depth_view) = crate_main_views(&ctx.device, ctx.extent, ctx.color_format);
    ctx.color_view = color_view;
    ctx.depth_view = depth_view;
}

#[no_mangle]
pub extern "C" fn rv_camera_init(ctx: &mut Context, desc: CameraDescription) {
    ctx.camera.proj = vangers::space::Projection::Perspective(cgmath::PerspectiveFov {
        aspect: desc.aspect,
        near: desc.near,
        far: desc.far,
        fovy: cgmath::Deg(desc.fov).into(),
    });
}

#[no_mangle]
pub extern "C" fn rv_camera_set_transform(ctx: &mut Context, t: Transform) {
    ctx.camera.loc = cgmath::vec3(t.position.x, t.position.y, t.position.z);
    ctx.camera.rot =
        cgmath::Quaternion::new(t.rotation.w, t.rotation.x, t.rotation.y, t.rotation.z);
}

#[no_mangle]
pub extern "C" fn rv_map_init(ctx: &mut Context, desc: MapDescription) {
    let terrains = (0..desc.material_count)
        .map(|i| unsafe {
            let mut tc = vangers::level::TerrainConfig::default();
            tc.colors.start = *desc.material_begin_offsets.offset(i as isize);
            tc.colors.end = *desc.material_end_offsets.offset(i as isize);
            tc
        })
        .collect::<Box<[_]>>();

    let total = (desc.width * desc.height) as usize;
    let level = vangers::level::Level {
        size: (desc.width, desc.height),
        flood_map: vec![0; 128].into_boxed_slice(),
        flood_section_power: 7, //TODO
        height: vec![0; total].into_boxed_slice(),
        meta: vec![0; total].into_boxed_slice(),
        palette: [[0; 4]; 0x100],
        terrains,
    };

    let render = vangers::render::Render::new(
        &ctx.device,
        &ctx.queue,
        &ctx.downlevel_caps,
        &level,
        &[[0; 4]; 0x100], //TODO: objects palette
        &ctx.render_config,
        ctx.color_format,
        ctx.extent, //Note: needs update on window resize
    );
    ctx.level = Some(LevelContext {
        desc,
        render,
        level,
    });
}

#[no_mangle]
pub extern "C" fn rv_map_exit(ctx: &mut Context) {
    ctx.level = None;
}

#[no_mangle]
pub unsafe extern "C" fn rv_map_update_data(ctx: &mut Context, region: Rect) {
    let lc = ctx.level.as_mut().unwrap();
    let line_width = lc.level.size.0 as usize;

    for y in region.y..region.y + region.height {
        // In the source data, each line contains N height values followed by N meta values.
        // We copy them into separate height and meta data arrays.
        let dst_offset = y as usize * line_width + region.x as usize;
        let line = *lc.desc.lines.add(y as usize);
        if line.is_null() {
            continue;
        }
        ptr::copy_nonoverlapping(
            line.add(region.x as usize),
            lc.level.height[dst_offset..].as_mut_ptr(),
            region.width as usize,
        );
        ptr::copy_nonoverlapping(
            line.add(region.x as usize + line_width),
            lc.level.meta[dst_offset..].as_mut_ptr(),
            region.width as usize,
        );
    }

    lc.render.terrain.dirty_rects.push(region.to_native());
}

#[no_mangle]
pub unsafe extern "C" fn rv_map_update_palette(
    ctx: &mut Context,
    first_entry: u32,
    entries_count: u32,
    palette: *const u8,
) {
    let lc = ctx.level.as_mut().unwrap();
    let end = first_entry + entries_count;

    for (i, color) in lc.level.palette[first_entry as usize..end as usize]
        .iter_mut()
        .enumerate()
    {
        ptr::copy_nonoverlapping(palette.add(i * 3), color.first_mut().unwrap(), 3);
    }

    let dp = lc.render.terrain.dirty_palette.clone();
    lc.render.terrain.dirty_palette = if dp != (0..0) {
        dp.start.min(first_entry)..dp.end.max(end)
    } else {
        first_entry..end
    };
}

#[no_mangle]
pub extern "C" fn rv_render(ctx: &mut Context, viewport: Rect) {
    let lc = ctx.level.as_mut().unwrap();
    let targets = vangers::render::ScreenTargets {
        extent: ctx.extent,
        depth: &ctx.depth_view,
        color: &ctx.color_view,
    };
    let mut encoder = ctx
        .device
        .create_command_encoder(&wgpu::CommandEncoderDescriptor::default());
    let mut batcher = vangers::render::Batcher::new();

    lc.render.custom_viewport = Some(viewport.to_native());
    lc.render.draw_world(
        &mut encoder,
        &mut batcher,
        &lc.level,
        &ctx.camera,
        targets,
        &ctx.device,
    );

    ctx.queue.submit(Some(encoder.finish()));
}
<|endoftext|>


<commit_before>//! Wayland cursor utilities
//!
//! This crate aims to reimplement the functionality of the `libwayland-cursor` library in Rust.
//!
//! It allows you to load cursors from the system and display them correctly.
//!
//! First of all, you need to create a `CursorTheme`,
//! which represents the full cursor theme.
//!
//! From this theme, using the `get_cursor` method, you can load a specific `Cursor`,
//! which can contain several images if the cursor is animated. It also provides you with the
//! means of querying which frame of the animation should be displayed at
//! what time, as well as handles to the buffers containing these frames, to
//! attach them to a wayland surface.

use std::{
    fs::File,
    io::{Read, Seek, SeekFrom, Write},
    ops::{Deref, Index},
    os::unix::io::{AsRawFd, FromRawFd},
};
use wayland_client::{
    protocol::{
        wl_buffer::WlBuffer,
        wl_shm::{Format, WlShm},
        wl_shm_pool::WlShmPool,
    },
    Attached, Main,
};
use xcur::parser::File as XCurFile;
use xcursor::{theme_search_paths, XCursorTheme};

/// Represents a cursor theme loaded from the system.
pub struct CursorTheme {
    name: String,
    cursors: Vec<Cursor>,
    size: u32,
    pool: Main<WlShmPool>,
    pool_size: i32,
    file: File,
}

impl CursorTheme {
    /// Create a new cursor theme.
    pub fn new(name: &str, size: u32, shm: &Attached<WlShm>) -> Self {
        let name = String::from(name);
        let pool_size = (size * size * 4) as i32;
        let mem_fd = create_shm_fd().unwrap();
        let file = unsafe { File::from_raw_fd(mem_fd) };
        let pool = shm.create_pool(file.as_raw_fd(), pool_size);

        CursorTheme {
            name,
            file,
            size,
            pool,
            pool_size,
            cursors: Vec::new(),
        }
    }

    /// Retrieve a cursor from the theme.
    ///
    /// This method returns `None` if this cursor is not provided
    /// either by the theme, or by one of its parents.
    pub fn get_cursor(&mut self, name: &str) -> Option<&Cursor> {
        let cur = self.cursors.iter().position(|i| i.name == name);

        match cur {
            Some(i) => Some(&self.cursors[i]),
            None => {
                let cur = self.load_cursor(name, self.size).unwrap();
                self.cursors.push(cur);
                self.cursors.iter().last()
            }
        }
    }

    /// This function loads a cursor, parses it and
    /// pushes the images onto the shm pool.
    /// Keep in mind that if the cursor is already loaded,
    /// the function will make a duplicate.
    fn load_cursor(&mut self, name: &str, size: u32) -> Option<Cursor> {
        let icon_path = XCursorTheme::load(&self.name, &theme_search_paths()).load_icon(name);
        let mut icon_file = File::open(icon_path.unwrap()).ok()?;

        let mut buf = Vec::new();
        let xcur = {
            icon_file.read_to_end(&mut buf).ok()?;
            XCurFile::parse(&buf)
        };

        // Terminate if cursor can't be parsed
        if !xcur.is_done() {
            return None;
        }

        let file_images = xcur.unwrap().1.images;
        let cursor = Cursor::new(name, self, &file_images, size);

        Some(cursor)
    }

    /// Grow the wl_shm_pool this theme is stored on.
    /// This method does nothing if the provided size is
    /// smaller or equal to the pool's current size.
    fn grow(&mut self, size: i32) {
        if size > self.pool_size {
            self.pool.resize(size);
            self.pool_size = size;
        }
    }
}

/// A cursor from a theme. Can contain several images if animated.
#[derive(Clone)]
pub struct Cursor {
    name: String,
    images: Vec<CursorImageBuffer>,
}

impl Cursor {
    /// Construct a new Cursor.
    ///
    /// Each of the provided images will be written into `theme`.
    /// This will also grow `theme.pool` if necessary.
    fn new(name: &str, theme: &mut CursorTheme, images: &[xcur::parser::Image], size: u32) -> Self {
        let mut buffers = Vec::with_capacity(images.len());
        let iter = images.iter().filter(|el| {el.width == size && el.height == size});

        for img in iter {
            buffers.push(CursorImageBuffer::new(theme, img));
        }

        Cursor {
            name: String::from(name),
            images: buffers,
        }
    }

    /// Given a time, calculate which frame to show, and how much time remains until the next frame.
    ///
    /// Time will wrap, so if for instance the cursor has an animation during 100ms,
    /// then calling this function with 5ms and 105ms as input gives the same output.
    pub fn frame_and_duration(&self, mut millis: u32) -> FrameAndDuration {
        let mut iter = self.images.iter().enumerate().cycle();
        loop {
            let (i, img) = iter.next().unwrap();
            if millis > img.delay {
                millis -= img.delay;
            } else {
                return FrameAndDuration {
                    frame_index: i,
                    frame_duration: millis,
                };
            }
        }
    }
}

impl Index<usize> for Cursor {
    type Output = CursorImageBuffer;

    fn index(&self, index: usize) -> &Self::Output {
        &self.images[index]
    }
}

/// A buffer containing a cursor image.
///
/// You can access the `WlBuffer` via `Deref`.
///
/// Note that this proxy will be considered as "unmanaged" by the crate, as such you should
/// not try to act on it beyond assigning it to `wl_surface`s.
#[derive(Clone)]
pub struct CursorImageBuffer {
    buffer: WlBuffer,
    delay: u32,
    xhot: u32,
    yhot: u32,
    width: u32,
    height: u32,
}

impl CursorImageBuffer {
    /// Construct a new CursorImageBuffer
    ///
    /// This function appends the pixels of the image to the provided file,
    /// and constructs a wl_buffer on that data.
    fn new(theme: &mut CursorTheme, image: &xcur::parser::Image) -> Self {
        let buf = CursorImageBuffer::convert_pixels(&image.pixels);
        let offset = theme.file.seek(SeekFrom::End(0)).unwrap();
        theme.file.write_all(&buf).unwrap();

        let new_size = theme.file.seek(SeekFrom::End(0)).unwrap();
        theme.grow(new_size as i32);

        let buffer = theme
            .pool
            .create_buffer(
                offset as i32,
                image.width as i32,
                image.height as i32,
                (image.width * 4) as i32,
                Format::Argb8888,
            )
            .detach();

        CursorImageBuffer {
            buffer,
            delay: image.delay,
            xhot: image.xhot,
            yhot: image.yhot,
            width: image.width,
            height: image.height,
        }
    }

    /// Convert the pixels saved in `u32`s into `u8`s.
    fn convert_pixels(pixels: &[u32]) -> Vec<u8> {
        let mut buf: Vec<u8> = Vec::with_capacity(pixels.len() * 4);

        for pixel in pixels {
            buf.push((pixel >> 24) as u8);
            buf.push((pixel >> 16) as u8);
            buf.push((pixel >> 8) as u8);
            buf.push(*pixel as u8);
        }

        buf
    }
}

impl Deref for CursorImageBuffer {
    type Target = WlBuffer;
    fn deref(&self) -> &WlBuffer {
        &self.buffer
    }
}

/// Which frame to show, and for how long.
///
/// This struct is output by `Cursor::frame_and_duration`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FrameAndDuration {
    /// The index of the frame which should be shown.
    pub frame_index: usize,
    /// The duration that the frame should be shown for.
    pub frame_duration: u32,
}

/// Create a shared file descriptor in memory
use {
    nix::{
        errno::Errno,
        fcntl,
        sys::{memfd, mman, stat},
        unistd,
    },
    std::{
        ffi::CStr,
        io,
        os::unix::io::RawFd,
        time::{SystemTime, UNIX_EPOCH},
    },
};
fn create_shm_fd() -> io::Result<RawFd> {
    // Only try memfd on linux
    #[cfg(target_os = "linux")]
    loop {
        match memfd::memfd_create(
            CStr::from_bytes_with_nul(b"smithay-client-toolkit\0").unwrap(),
            memfd::MemFdCreateFlag::MFD_CLOEXEC,
        ) {
            Ok(fd) => return Ok(fd),
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(Errno::ENOSYS)) => break,
            Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
            Err(err) => unreachable!(err),
        }
    }

    // Fallback to using shm_open
    let sys_time = SystemTime::now();
    let mut mem_file_handle = format!(
        "/smithay-client-toolkit-{}",
        sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
    );
    loop {
        match mman::shm_open(
            mem_file_handle.as_str(),
            fcntl::OFlag::O_CREAT | fcntl::OFlag::O_EXCL | fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC,
            stat::Mode::S_IRUSR | stat::Mode::S_IWUSR,
        ) {
            Ok(fd) => match mman::shm_unlink(mem_file_handle.as_str()) {
                Ok(_) => return Ok(fd),
                Err(nix::Error::Sys(errno)) => match unistd::close(fd) {
                    Ok(_) => return Err(io::Error::from(errno)),
                    Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
                    Err(err) => panic!(err),
                },
                Err(err) => panic!(err),
            },
            Err(nix::Error::Sys(Errno::EEXIST)) => {
                // If a file with that handle exists then change the handle
                mem_file_handle = format!(
                    "/smithay-client-toolkit-{}",
                    sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
                );
                continue;
            }
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
            Err(err) => unreachable!(err),
        }
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_convert_pixels() {
        let pixels: &[u32] = &[0x12345678, 0x87654321];
        let parsed_pixels: &[u8] = &[0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21];

        assert_eq!(
            super::CursorImageBuffer::convert_pixels(&pixels),
            Vec::from(parsed_pixels)
        );
    }
}
<commit_msg>cursor: handle environment variables<commit_after>//! Wayland cursor utilities
//!
//! This crate aims to reimplement the functionality of the `libwayland-cursor` library in Rust.
//!
//! It allows you to load cursors from the system and display them correctly.
//!
//! First of all, you need to create a `CursorTheme`,
//! which represents the full cursor theme.
//!
//! From this theme, using the `get_cursor` method, you can load a specific `Cursor`,
//! which can contain several images if the cursor is animated. It also provides you with the
//! means of querying which frame of the animation should be displayed at
//! what time, as well as handles to the buffers containing these frames, to
//! attach them to a wayland surface.

use std::{
    env,
    fs::File,
    io::{Read, Seek, SeekFrom, Write},
    ops::{Deref, Index},
    os::unix::io::{AsRawFd, FromRawFd},
};
use wayland_client::{
    protocol::{
        wl_buffer::WlBuffer,
        wl_shm::{Format, WlShm},
        wl_shm_pool::WlShmPool,
    },
    Attached, Main,
};
use xcur::parser::File as XCurFile;
use xcursor::{theme_search_paths, XCursorTheme};

/// Represents a cursor theme loaded from the system.
pub struct CursorTheme {
    name: String,
    cursors: Vec<Cursor>,
    size: u32,
    pool: Main<WlShmPool>,
    pool_size: i32,
    file: File,
}

impl CursorTheme {
    /// Load a cursor theme from system defaults.
    ///
    /// Same as calling `load_or("default", size, shm)`
    pub fn load(size: u32, shm: &Attached<WlShm>) -> Self {
        CursorTheme::load_or("default", size, shm)
    }

    /// Load a cursor theme, using `name` as fallback.
    ///
    /// The theme name and cursor size are read from the `XCURSOR_THEME` and
    /// `XCURSOR_SIZE` environment variables, respectively, or from the provided variables
    /// if those are invalid.
    pub fn load_or(name: &str, mut size: u32, shm: &Attached<WlShm>) -> Self {
        let name_string = String::from(name);
        let name = &env::var("XCURSOR_THEME").unwrap_or(name_string);

        if let Ok(var) = env::var("XCURSOR_SIZE") {
            if let Ok(int) = var.parse() {
                size = int;
            }
        }

        CursorTheme::load_from_name(name, size, shm)
    }

    /// Create a new cursor theme, ignoring the system defaults.
    pub fn load_from_name(name: &str, size: u32, shm: &Attached<WlShm>) -> Self {
        let name = String::from(name);
        let pool_size = (size * size * 4) as i32;
        let mem_fd = create_shm_fd().unwrap();
        let file = unsafe { File::from_raw_fd(mem_fd) };
        let pool = shm.create_pool(file.as_raw_fd(), pool_size);

        CursorTheme {
            name,
            file,
            size,
            pool,
            pool_size,
            cursors: Vec::new(),
        }
    }

    /// Retrieve a cursor from the theme.
    ///
    /// This method returns `None` if this cursor is not provided
    /// either by the theme, or by one of its parents.
    pub fn get_cursor(&mut self, name: &str) -> Option<&Cursor> {
        let cur = self.cursors.iter().position(|i| i.name == name);

        match cur {
            Some(i) => Some(&self.cursors[i]),
            None => {
                let cur = self.load_cursor(name, self.size).unwrap();
                self.cursors.push(cur);
                self.cursors.iter().last()
            }
        }
    }

    /// This function loads a cursor, parses it and
    /// pushes the images onto the shm pool.
    /// Keep in mind that if the cursor is already loaded,
    /// the function will make a duplicate.
    fn load_cursor(&mut self, name: &str, size: u32) -> Option<Cursor> {
        let icon_path = XCursorTheme::load(&self.name, &theme_search_paths()).load_icon(name)?;
        let mut icon_file = File::open(icon_path).ok()?;

        let mut buf = Vec::new();
        let xcur = {
            icon_file.read_to_end(&mut buf).ok()?;
            XCurFile::parse(&buf)
        };

        // Terminate if cursor can't be parsed
        if !xcur.is_done() {
            return None;
        }

        let file_images = xcur.unwrap().1.images;
        let cursor = Cursor::new(name, self, &file_images, size);

        Some(cursor)
    }

    /// Grow the wl_shm_pool this theme is stored on.
    /// This method does nothing if the provided size is
    /// smaller or equal to the pool's current size.
    fn grow(&mut self, size: i32) {
        if size > self.pool_size {
            self.pool.resize(size);
            self.pool_size = size;
        }
    }
}

/// A cursor from a theme. Can contain several images if animated.
#[derive(Clone)]
pub struct Cursor {
    name: String,
    images: Vec<CursorImageBuffer>,
}

impl Cursor {
    /// Construct a new Cursor.
    ///
    /// Each of the provided images will be written into `theme`.
    /// This will also grow `theme.pool` if necessary.
    fn new(name: &str, theme: &mut CursorTheme, images: &[xcur::parser::Image], size: u32) -> Self {
        let mut buffers = Vec::with_capacity(images.len());
        let iter = images.iter().filter(|el| el.width == size && el.height == size);

        for img in iter {
            buffers.push(CursorImageBuffer::new(theme, img));
        }

        Cursor {
            name: String::from(name),
            images: buffers,
        }
    }

    /// Given a time, calculate which frame to show, and how much time remains until the next frame.
    ///
    /// Time will wrap, so if for instance the cursor has an animation during 100ms,
    /// then calling this function with 5ms and 105ms as input gives the same output.
    pub fn frame_and_duration(&self, mut millis: u32) -> FrameAndDuration {
        let mut iter = self.images.iter().enumerate().cycle();
        loop {
            let (i, img) = iter.next().unwrap();
            if millis > img.delay {
                millis -= img.delay;
            } else {
                return FrameAndDuration {
                    frame_index: i,
                    frame_duration: millis,
                };
            }
        }
    }
}

impl Index<usize> for Cursor {
    type Output = CursorImageBuffer;

    fn index(&self, index: usize) -> &Self::Output {
        &self.images[index]
    }
}

/// A buffer containing a cursor image.
///
/// You can access the `WlBuffer` via `Deref`.
///
/// Note that this proxy will be considered as "unmanaged" by the crate, as such you should
/// not try to act on it beyond assigning it to `wl_surface`s.
#[derive(Clone)]
pub struct CursorImageBuffer {
    buffer: WlBuffer,
    delay: u32,
    xhot: u32,
    yhot: u32,
    width: u32,
    height: u32,
}

impl CursorImageBuffer {
    /// Construct a new CursorImageBuffer
    ///
    /// This function appends the pixels of the image to the provided file,
    /// and constructs a wl_buffer on that data.
    fn new(theme: &mut CursorTheme, image: &xcur::parser::Image) -> Self {
        let buf = CursorImageBuffer::convert_pixels(&image.pixels);
        let offset = theme.file.seek(SeekFrom::End(0)).unwrap();
        theme.file.write_all(&buf).unwrap();

        let new_size = theme.file.seek(SeekFrom::End(0)).unwrap();
        theme.grow(new_size as i32);

        let buffer = theme
            .pool
            .create_buffer(
                offset as i32,
                image.width as i32,
                image.height as i32,
                (image.width * 4) as i32,
                Format::Argb8888,
            )
            .detach();

        CursorImageBuffer {
            buffer,
            delay: image.delay,
            xhot: image.xhot,
            yhot: image.yhot,
            width: image.width,
            height: image.height,
        }
    }

    /// Convert the pixels saved in `u32`s into `u8`s.
    fn convert_pixels(pixels: &[u32]) -> Vec<u8> {
        let mut buf: Vec<u8> = Vec::with_capacity(pixels.len() * 4);

        for pixel in pixels {
            buf.push((pixel >> 24) as u8);
            buf.push((pixel >> 16) as u8);
            buf.push((pixel >> 8) as u8);
            buf.push(*pixel as u8);
        }

        buf
    }
}

impl Deref for CursorImageBuffer {
    type Target = WlBuffer;
    fn deref(&self) -> &WlBuffer {
        &self.buffer
    }
}

/// Which frame to show, and for how long.
///
/// This struct is output by `Cursor::frame_and_duration`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct FrameAndDuration {
    /// The index of the frame which should be shown.
    pub frame_index: usize,
    /// The duration that the frame should be shown for.
    pub frame_duration: u32,
}

/// Create a shared file descriptor in memory
use {
    nix::{
        errno::Errno,
        fcntl,
        sys::{memfd, mman, stat},
        unistd,
    },
    std::{
        ffi::CStr,
        io,
        os::unix::io::RawFd,
        time::{SystemTime, UNIX_EPOCH},
    },
};
fn create_shm_fd() -> io::Result<RawFd> {
    // Only try memfd on linux
    #[cfg(target_os = "linux")]
    loop {
        match memfd::memfd_create(
            CStr::from_bytes_with_nul(b"smithay-client-toolkit\0").unwrap(),
            memfd::MemFdCreateFlag::MFD_CLOEXEC,
        ) {
            Ok(fd) => return Ok(fd),
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(Errno::ENOSYS)) => break,
            Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
            Err(err) => unreachable!(err),
        }
    }

    // Fallback to using shm_open
    let sys_time = SystemTime::now();
    let mut mem_file_handle = format!(
        "/smithay-client-toolkit-{}",
        sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
    );
    loop {
        match mman::shm_open(
            mem_file_handle.as_str(),
            fcntl::OFlag::O_CREAT | fcntl::OFlag::O_EXCL | fcntl::OFlag::O_RDWR | fcntl::OFlag::O_CLOEXEC,
            stat::Mode::S_IRUSR | stat::Mode::S_IWUSR,
        ) {
            Ok(fd) => match mman::shm_unlink(mem_file_handle.as_str()) {
                Ok(_) => return Ok(fd),
                Err(nix::Error::Sys(errno)) => match unistd::close(fd) {
                    Ok(_) => return Err(io::Error::from(errno)),
                    Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
                    Err(err) => panic!(err),
                },
                Err(err) => panic!(err),
            },
            Err(nix::Error::Sys(Errno::EEXIST)) => {
                // If a file with that handle exists then change the handle
                mem_file_handle = format!(
                    "/smithay-client-toolkit-{}",
                    sys_time.duration_since(UNIX_EPOCH).unwrap().subsec_nanos()
                );
                continue;
            }
            Err(nix::Error::Sys(Errno::EINTR)) => continue,
            Err(nix::Error::Sys(errno)) => return Err(io::Error::from(errno)),
            Err(err) => unreachable!(err),
        }
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_convert_pixels() {
        let pixels: &[u32] = &[0x12345678, 0x87654321];
        let parsed_pixels: &[u8] = &[0x12, 0x34, 0x56, 0x78, 0x87, 0x65, 0x43, 0x21];

        assert_eq!(
            super::CursorImageBuffer::convert_pixels(&pixels),
            Vec::from(parsed_pixels)
        );
    }
}
<|endoftext|>


<commit_before>mod options;

use crate::options::{CodegenOutput, ErrorStyle, Options};
use failure::{format_err, Error, ResultExt};
use log::info;
use lucet_module::bindings::Bindings;
use lucet_validate::Validator;
use lucetc::{
    signature::{self, PublicKey},
    Lucetc, LucetcOpts,
};
use serde::Serialize;
use serde_json;
use std::path::PathBuf;
use std::process;

#[derive(Clone, Debug, Serialize)]
pub struct SerializedLucetcError {
    error: String,
}

impl From<Error> for SerializedLucetcError {
    fn from(e: Error) -> Self {
        SerializedLucetcError {
            error: format!("{}", e),
        }
    }
}

fn main() {
    env_logger::init();

    let opts = Options::get().unwrap();

    if let Err(err) = run(&opts) {
        match opts.error_style {
            ErrorStyle::Human => eprintln!("Error: {}\n", err),
            ErrorStyle::Json => {
                let errs: Vec<SerializedLucetcError> = vec![err.into()];
                let json = serde_json::to_string(&errs).unwrap();
                eprintln!("{}", json);
            }
        }
        process::exit(1);
    }
}

pub fn run(opts: &Options) -> Result<(), Error> {
    info!("lucetc {:?}", opts);

    if opts.keygen {
        keygen(opts)?;
        return Ok(());
    }

    let input = &match opts.input.len() {
        0 => Err(format_err!("must provide at least one input")),
        1 => Ok(opts.input[0].clone()),
        _ => Err(format_err!("provided too many inputs: {:?}", opts.input)),
    }?;

    let mut bindings = Bindings::empty();
    for file in opts.binding_files.iter() {
        let file_bindings =
            Bindings::from_file(file).context(format!("bindings file {:?}", file))?;
        bindings
            .extend(&file_bindings)
            .context(format!("adding bindings from {:?}", file))?;
    }

    let mut c = Lucetc::new(PathBuf::from(input))
        .with_bindings(bindings)
        .with_opt_level(opts.opt_level);

    match opts.witx_specs.len() {
        0 => {}
        1 => {
            let validator = Validator::load(&opts.witx_specs[0])?.with_wasi_exe(opts.wasi_exe);
            c.validator(validator);
        }
        _ => Err(format_err!("multiple witx specs not yet supported"))?,
    }

    if let Some(ref builtins) = opts.builtins_path {
        c.builtins(builtins);
    }

    if let Some(min_reserved_size) = opts.min_reserved_size {
        c.min_reserved_size(min_reserved_size);
    }

    if let Some(max_reserved_size) = opts.max_reserved_size {
        c.max_reserved_size(max_reserved_size);
    }

    // this comes after min and max, so it overrides them if present
    if let Some(reserved_size) = opts.reserved_size {
        c.reserved_size(reserved_size);
    }

    if let Some(guard_size) = opts.guard_size {
        c.guard_size(guard_size);
    }

    if let Some(pk_path) = &opts.pk_path {
        c.pk(PublicKey::from_file(pk_path)?);
    }

    if let Some(sk_path) = &opts.sk_path {
        c.sk(signature::sk_from_file(sk_path)?);
    }

    if opts.verify {
        c.verify();
    }

    if opts.sign {
        c.sign();
    }

    if opts.count_instructions {
        c.count_instructions(true);
    }

    match opts.codegen {
        CodegenOutput::Obj => c.object_file(&opts.output)?,
        CodegenOutput::SharedObj => c.shared_object_file(&opts.output)?,
        CodegenOutput::Clif => c.clif_ir(&opts.output)?,
    }
    Ok(())
}

fn keygen(opts: &Options) -> Result<(), Error> {
    let (pk_path, sk_path) = match (&opts.pk_path, &opts.sk_path) {
        (Some(pk_path), Some(sk_path)) => (pk_path, sk_path),
        _ => Err(format_err!("Keypair generation requires --signature-pk and --signature-sk to specify where the keys should be stored to"))?
    };
    signature::keygen(pk_path, sk_path)?;
    Ok(())
}
<commit_msg>[lucetc] restore output for the underlying cause of `lucetc::Error`s<commit_after>mod options;

use crate::options::{CodegenOutput, ErrorStyle, Options};
use failure::{format_err, Error, ResultExt};
use log::info;
use lucet_module::bindings::Bindings;
use lucet_validate::Validator;
use lucetc::{
    signature::{self, PublicKey},
    Lucetc, LucetcOpts,
};
use serde::Serialize;
use serde_json;
use std::path::PathBuf;
use std::process;

#[derive(Clone, Debug, Serialize)]
pub struct SerializedLucetcError {
    error: String,
}

impl From<Error> for SerializedLucetcError {
    fn from(e: Error) -> Self {
        SerializedLucetcError {
            error: if let Some(cause) = e.as_fail().cause() {
                format!("{}: {}", e, cause)
            } else {
                format!("{}", e)
            },
        }
    }
}

fn main() {
    env_logger::init();

    let opts = Options::get().unwrap();

    if let Err(err) = run(&opts) {
        match opts.error_style {
            ErrorStyle::Human => {
                eprintln!("Error: {}\n", err);
                if let Some(cause) = err.as_fail().cause() {
                    eprintln!("{}", cause);
                }
            }
            ErrorStyle::Json => {
                let errs: Vec<SerializedLucetcError> = vec![err.into()];
                let json = serde_json::to_string(&errs).unwrap();
                eprintln!("{}", json);
            }
        }
        process::exit(1);
    }
}

pub fn run(opts: &Options) -> Result<(), Error> {
    info!("lucetc {:?}", opts);

    if opts.keygen {
        keygen(opts)?;
        return Ok(());
    }

    let input = &match opts.input.len() {
        0 => Err(format_err!("must provide at least one input")),
        1 => Ok(opts.input[0].clone()),
        _ => Err(format_err!("provided too many inputs: {:?}", opts.input)),
    }?;

    let mut bindings = Bindings::empty();
    for file in opts.binding_files.iter() {
        let file_bindings =
            Bindings::from_file(file).context(format!("bindings file {:?}", file))?;
        bindings
            .extend(&file_bindings)
            .context(format!("adding bindings from {:?}", file))?;
    }

    let mut c = Lucetc::new(PathBuf::from(input))
        .with_bindings(bindings)
        .with_opt_level(opts.opt_level);

    match opts.witx_specs.len() {
        0 => {}
        1 => {
            let validator = Validator::load(&opts.witx_specs[0])?.with_wasi_exe(opts.wasi_exe);
            c.validator(validator);
        }
        _ => Err(format_err!("multiple witx specs not yet supported"))?,
    }

    if let Some(ref builtins) = opts.builtins_path {
        c.builtins(builtins);
    }

    if let Some(min_reserved_size) = opts.min_reserved_size {
        c.min_reserved_size(min_reserved_size);
    }

    if let Some(max_reserved_size) = opts.max_reserved_size {
        c.max_reserved_size(max_reserved_size);
    }

    // this comes after min and max, so it overrides them if present
    if let Some(reserved_size) = opts.reserved_size {
        c.reserved_size(reserved_size);
    }

    if let Some(guard_size) = opts.guard_size {
        c.guard_size(guard_size);
    }

    if let Some(pk_path) = &opts.pk_path {
        c.pk(PublicKey::from_file(pk_path)?);
    }

    if let Some(sk_path) = &opts.sk_path {
        c.sk(signature::sk_from_file(sk_path)?);
    }

    if opts.verify {
        c.verify();
    }

    if opts.sign {
        c.sign();
    }

    if opts.count_instructions {
        c.count_instructions(true);
    }

    match opts.codegen {
        CodegenOutput::Obj => c.object_file(&opts.output)?,
        CodegenOutput::SharedObj => c.shared_object_file(&opts.output)?,
        CodegenOutput::Clif => c.clif_ir(&opts.output)?,
    }
    Ok(())
}

fn keygen(opts: &Options) -> Result<(), Error> {
    let (pk_path, sk_path) = match (&opts.pk_path, &opts.sk_path) {
        (Some(pk_path), Some(sk_path)) => (pk_path, sk_path),
        _ => Err(format_err!("Keypair generation requires --signature-pk and --signature-sk to specify where the keys should be stored to"))?
    };
    signature::keygen(pk_path, sk_path)?;
    Ok(())
}
<|endoftext|>


<commit_before>//! Middleware for tokio services that adds automatic retries
//! in case of failure.
//!
//! # Examples
//!
//! ```rust
//! extern crate futures;
//! extern crate tokio_core;
//! extern crate tokio_service;
//! extern crate tokio_retry;
//!
//! use std::io;
//!
//! use futures::{BoxFuture, Future, future};
//! use tokio_core::reactor::Core;
//! use tokio_service::Service;
//! use tokio_retry::Middleware;
//! use tokio_retry::strategy::{ExponentialBackoff, jitter};
//!
//! struct EchoService;
//!
//! impl Service for EchoService {
//!    type Request = String;
//!    type Response = String;
//!    type Error = ();
//!    type Future = BoxFuture<String, ()>;
//!    fn call(&self, input: String) -> Self::Future {
//!        future::ok(input).boxed()
//!    }
//! }
//!
//! fn main() {
//!     let mut core = Core::new().unwrap();
//!
//!     let retry_strategy = || ExponentialBackoff::from_millis(10)
//!         .map(jitter)
//!         .take(3);
//!
//!     let retry_service = Middleware::new(core.handle(), retry_strategy, EchoService);
//!     let retry_result = core.run(retry_service.call("hello world!".to_string()));
//!
//!     assert_eq!(retry_result, Ok("hello world!".to_string()));
//! }
//! ```

use std::iter::{Iterator, IntoIterator};
use std::time::Duration;
use std::sync::Arc;
use tokio_service::Service;
use tokio_core::reactor::Handle;

use super::{Retry, Error};
use super::action::Action;

pub struct ServiceRequest<S: Service> {
    inner: Arc<S>,
    request: S::Request
}

impl<S: Service> Action for ServiceRequest<S> where S::Request: Clone {
    type Error = S::Error;
    type Item = S::Response;
    type Future = S::Future;

    fn run(&mut self) -> Self::Future {
        self.inner.call(self.request.clone())
    }
}

/// Middleware that adds retries to a service via a retry strategy.
pub struct Middleware<T, S> {
    inner: Arc<S>,
    handle: Handle,
    strategy: T
}

pub trait StrategyFactory {
    type Iter: Iterator<Item=Duration>;

    fn get_strategy(&self) -> Self::Iter;
}

impl<F, I: IntoIterator<Item=Duration>> StrategyFactory for F where F: Fn() -> I {
    type Iter = I::IntoIter;

    fn get_strategy(&self) -> Self::Iter {
        self().into_iter()
    }
}

impl<T: StrategyFactory, S> Middleware<T, S> {
    pub fn new(handle: Handle, strategy: T, inner: S) -> Middleware<T, S> {
        Middleware{
            inner: Arc::new(inner),
            handle: handle,
            strategy: strategy
        }
    }
}

impl<T: StrategyFactory, S: Service> Service for Middleware<T, S> where S::Request: Clone {
    type Request = S::Request;
    type Response = S::Response;
    type Error = Error<S::Error>;
    type Future = Retry<T::Iter, ServiceRequest<S>>;

    fn call(&self, request: Self::Request) -> Self::Future {
        let action = ServiceRequest{
            inner: self.inner.clone(),
            request: request
        };

        Retry::spawn(self.handle.clone(), self.strategy.get_strategy(), action)
    }
}
<commit_msg>extra doco<commit_after>//! Middleware for tokio services that adds automatic retries
//! in case of failure.
//!
//! # Examples
//!
//! ```rust
//! extern crate futures;
//! extern crate tokio_core;
//! extern crate tokio_service;
//! extern crate tokio_retry;
//!
//! use std::io;
//!
//! use futures::{BoxFuture, Future, future};
//! use tokio_core::reactor::Core;
//! use tokio_service::Service;
//! use tokio_retry::Middleware;
//! use tokio_retry::strategy::{ExponentialBackoff, jitter};
//!
//! struct EchoService;
//!
//! impl Service for EchoService {
//!    type Request = String;
//!    type Response = String;
//!    type Error = ();
//!    type Future = BoxFuture<String, ()>;
//!    fn call(&self, input: String) -> Self::Future {
//!        future::ok(input).boxed()
//!    }
//! }
//!
//! fn main() {
//!     let mut core = Core::new().unwrap();
//!
//!     let retry_strategy = || ExponentialBackoff::from_millis(10)
//!         .map(jitter)
//!         .take(3);
//!
//!     let retry_service = Middleware::new(core.handle(), retry_strategy, EchoService);
//!     let retry_result = core.run(retry_service.call("hello world!".to_string()));
//!
//!     assert_eq!(retry_result, Ok("hello world!".to_string()));
//! }
//! ```

use std::iter::{Iterator, IntoIterator};
use std::time::Duration;
use std::sync::Arc;
use tokio_service::Service;
use tokio_core::reactor::Handle;

use super::{Retry, Error};
use super::action::Action;

/// Represents a retryable request to a service.
pub struct ServiceRequest<S: Service> {
    inner: Arc<S>,
    request: S::Request
}

impl<S: Service> Action for ServiceRequest<S> where S::Request: Clone {
    type Error = S::Error;
    type Item = S::Response;
    type Future = S::Future;

    fn run(&mut self) -> Self::Future {
        self.inner.call(self.request.clone())
    }
}

/// Middleware that adds retries to a service via a retry strategy.
pub struct Middleware<T, S> {
    inner: Arc<S>,
    handle: Handle,
    strategy: T
}

/// Trait to produce iterators that will be used as retry strategies.
///
/// Can be implemented directly, but the simplest way to instantiate
/// a strategy factory is by leveraging the `impl` for `Fn()`:
///
/// ```rust
/// # use tokio_retry::strategy::ExponentialBackoff;
/// let retry_strategy = || ExponentialBackoff::from_millis(10);
/// ```
pub trait StrategyFactory {
    type Iter: Iterator<Item=Duration>;

    fn get_strategy(&self) -> Self::Iter;
}

impl<F, I: IntoIterator<Item=Duration>> StrategyFactory for F where F: Fn() -> I {
    type Iter = I::IntoIter;

    fn get_strategy(&self) -> Self::Iter {
        self().into_iter()
    }
}

impl<T: StrategyFactory, S> Middleware<T, S> {
    pub fn new(handle: Handle, strategy: T, inner: S) -> Middleware<T, S> {
        Middleware{
            inner: Arc::new(inner),
            handle: handle,
            strategy: strategy
        }
    }
}

impl<T: StrategyFactory, S: Service> Service for Middleware<T, S> where S::Request: Clone {
    type Request = S::Request;
    type Response = S::Response;
    type Error = Error<S::Error>;
    type Future = Retry<T::Iter, ServiceRequest<S>>;

    fn call(&self, request: Self::Request) -> Self::Future {
        let action = ServiceRequest{
            inner: self.inner.clone(),
            request: request
        };

        Retry::spawn(self.handle.clone(), self.strategy.get_strategy(), action)
    }
}
<|endoftext|>


<commit_before>use control::Key;

pub struct KeySet {
    keys: usize,  // bit flags
}

impl KeySet {
    pub fn new() -> KeySet {
        KeySet {
            keys: 0,
        }
    }

    pub fn set_key(&mut self, k: Key) {
        self.keys = self.keys | (1 << (k as usize))
    }

    pub fn has_key(&self, k: Key) -> bool {
        (self.keys & (1 << (k as usize))) != 0
    }
}

#[cfg(test)]
mod tests {
    use super::KeySet;
    use control::Key;

    #[test]
    fn test_set_key_has_key() {
        let mut ks = KeySet::new();
        assert!(!ks.has_key(Key::Up));
        assert!(!ks.has_key(Key::Right));
        assert!(!ks.has_key(Key::Left));
        assert!(!ks.has_key(Key::Down));
        assert!(!ks.has_key(Key::RightTurn));
        assert!(!ks.has_key(Key::LeftTurn));
        assert!(!ks.has_key(Key::Start));

        ks.set_key(Key::Up);
        ks.set_key(Key::Right);
        assert!(ks.has_key(Key::Up));
        assert!(ks.has_key(Key::Right));
        assert!(!ks.has_key(Key::Left));
        assert!(!ks.has_key(Key::Down));
        assert!(!ks.has_key(Key::RightTurn));
        assert!(!ks.has_key(Key::LeftTurn));
        assert!(!ks.has_key(Key::Start));
    }
}
<commit_msg>Add KeySet::parse_keysetseq<commit_after>use control::Key;

#[derive(Copy, Clone, Debug, PartialEq)]
pub struct KeySet {
    keys: usize,  // bit flags
}

impl KeySet {
    pub fn new() -> KeySet {
        KeySet {
            keys: 0,
        }
    }

    pub fn from_key(k: Key) -> KeySet {
        let mut ks = KeySet::new();
        ks.set_key(k);
        ks
    }

    pub fn from_keys(keys: &[Key]) -> KeySet {
        let mut ks = KeySet::new();
        for k in keys {
            ks.set_key(*k);
        }
        ks
    }

    pub fn set_key(&mut self, k: Key) {
        self.keys = self.keys | (1 << (k as usize))
    }

    pub fn has_key(&self, k: Key) -> bool {
        (self.keys & (1 << (k as usize))) != 0
    }
}

pub fn parse_keysetseq(s: &str) -> Result<Vec<KeySet>, String> {
    let mut keysetseq = Vec::new();
    for x in s.split(',') {
        let mut ks = KeySet::new();
        for c in x.chars() {
            ks.set_key(try!(Key::parse_char(c)))
        }
        keysetseq.push(ks);
    }
    Ok(keysetseq)
}

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

    #[test]
    fn test_set_key_has_key() {
        let mut ks = KeySet::new();
        assert!(!ks.has_key(Key::Up));
        assert!(!ks.has_key(Key::Right));
        assert!(!ks.has_key(Key::Left));
        assert!(!ks.has_key(Key::Down));
        assert!(!ks.has_key(Key::RightTurn));
        assert!(!ks.has_key(Key::LeftTurn));
        assert!(!ks.has_key(Key::Start));

        ks.set_key(Key::Up);
        ks.set_key(Key::Right);
        assert!(ks.has_key(Key::Up));
        assert!(ks.has_key(Key::Right));
        assert!(!ks.has_key(Key::Left));
        assert!(!ks.has_key(Key::Down));
        assert!(!ks.has_key(Key::RightTurn));
        assert!(!ks.has_key(Key::LeftTurn));
        assert!(!ks.has_key(Key::Start));
    }

    #[test]
    fn test_parse_keysetseq_1() {
        let expected: &[KeySet] = &[
            KeySet::from_key(Key::Right),
            KeySet::from_key(Key::Left),
            KeySet::from_key(Key::Down),
            KeySet::from_key(Key::Up),
            KeySet::from_key(Key::RightTurn),
            KeySet::from_key(Key::LeftTurn),
            KeySet::from_key(Key::Start),
        ];

        assert_eq!(expected, parse_keysetseq(">,<,v,^,A,B,S").unwrap().as_slice());
    }

    #[test]
    fn test_parse_keysetseq_2() {
        let expected: &[KeySet] = &[
            KeySet::from_keys(&[Key::Right, Key::RightTurn]),
            KeySet::from_keys(&[Key::RightTurn, Key::Right]),
            KeySet::from_keys(&[Key::Left, Key::LeftTurn]),
            KeySet::from_keys(&[Key::LeftTurn, Key::Left]),
            KeySet::from_keys(&[Key::Down, Key::RightTurn]),
            KeySet::from_keys(&[Key::Down, Key::LeftTurn]),
        ];

        assert_eq!(expected, parse_keysetseq(">A,>A,<B,<B,vA,vB").unwrap().as_slice());
    }
}
<|endoftext|>


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

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// parser itself, the root node of the command tree that was
/// used to create this parser, as well as the tokens passed
/// into the parser.
///
/// ```
/// use commands::parser::nodes::RootNode;
/// use commands::parser::Parser;
///
/// let mut root = RootNode::new();
/// let mut parser = Parser::new(root);
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
pub struct Parser<'p> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'p>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<RootNode>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    pub fn complete(&self, token: Option<Token<'p>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::nodes::RootNode;
    /// use commands::parser::Parser;
    /// use commands::tokenizer::tokenize;
    ///
    /// let mut root = RootNode::new();
    /// let mut parser = Parser::new(root);
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'p>>) -> Result<(), ParseError<'p>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'p>) -> Result<(), ParseError<'p>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let matches = cn.successors()
                        .into_iter()
                        .filter(|n| n.acceptable(self) && n.matches(self, token))
                        .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token)),
            _ => Err(ParseError::AmbiguousMatch(token)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if self.commands.is_empty() {
            return Err(VerifyError::NoCommandAccepted);
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return Err(VerifyError::MissingParameter(expected.name().clone()));
                }
            }
        }
        Ok(())
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum ParseError<'t> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'t>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'t>), // XXX: One day, add: Vec<&'p Rc<Node>>),
}

impl<'t> Error for ParseError<'t> {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidState => "Invalid state.",
            ParseError::NoMatches(_) => "No match.",
            ParseError::AmbiguousMatch(_) => "Ambiguous match.",
        }
    }
}

impl<'t> fmt::Display for ParseError<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    MissingParameter(String),
}

impl Error for VerifyError {
    fn description(&self) -> &str {
        match *self {
            VerifyError::NoCommandAccepted => "No command has been accepted by the parser.",
            VerifyError::MissingParameter(_) => "A required parameter is missing.",
        }
    }
}

impl fmt::Display for VerifyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Can this node be accepted in the current parser state?
pub trait Acceptable {
    /// Can this node be accepted in the current parser state?
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

/// Define whether or not a node matches a token.
pub trait Matches {
    /// Does this node match the specified `token`?
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

/// Define the behavior of a node when it is accepted by the parser.
pub trait Accept {
    /// Accept this node with the given `token` as data.
    ///
    /// This is where parameters are stored, commands added.
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token);
}

impl Accept for Node {
    /// By default, nothing needs to happen for `accept`.
    fn accept<'p>(&self, _parser: &mut Parser<'p>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    /// Record this command.
    fn accept<'p>(&self, parser: &mut Parser<'p>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for ParameterNode {
    /// Record this parameter value.
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}

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

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = RootNode::new();
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }
}
<commit_msg>Examples: RootNode not mut.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! # Command Parser
//!
//! The `commands::parser` module provides:
//!
//! * Functionality for building a tree of commands based on their names.
//! * Parsing tokenized input to select a command. Input tokenization can
//!   be performed by the `commands::tokenizer` module.
//! * Validating parameters.
//! * Performing completion on commands and parameters.
//!
//! The parser is still a work in progress but is rapidly advancing.

pub mod nodes;
pub mod completion;

use std::collections::HashMap;
use std::error::Error;
use std::fmt;
use std::rc::Rc;
use parser::nodes::*;
use tokenizer::{Token, TokenType};
use parser::completion::{Complete, Completion};

/// Command parser
///
/// The lifetime parameter `'p` refers to the lifetime of the
/// parser itself, the root node of the command tree that was
/// used to create this parser, as well as the tokens passed
/// into the parser.
///
/// ```
/// use commands::parser::nodes::RootNode;
/// use commands::parser::Parser;
///
/// let root = RootNode::new();
/// let mut parser = Parser::new(root);
/// ```
///
/// The parser is constructed as a `mut`able object as most of
/// the methods on it will modify its state.
pub struct Parser<'p> {
    current_node: Rc<Node>,
    /// The nodes which have been accepted during `parse` or `advance`.
    pub nodes: Vec<Rc<Node>>,
    /// The tokens which have been accepted during `parse` or `advance`.
    pub tokens: Vec<Token<'p>>,
    commands: Vec<Rc<CommandNode>>,
    parameters: HashMap<String, String>,
}

impl<'p> Parser<'p> {
    /// Construct a parser with a root node.
    pub fn new(initial_node: Rc<RootNode>) -> Parser<'p> {
        Parser {
            current_node: initial_node,
            nodes: vec![],
            tokens: vec![],
            commands: vec![],
            parameters: HashMap::new(),
        }
    }

    /// Given an optional token, get the possible valid completions
    /// for the current parser state.
    ///
    /// Possible completions are successors of the current node which
    /// are not `hidden`, are `acceptable`, and which match the token,
    /// if one has been provided.
    ///
    /// Nodes may customize the `Complete` trait to customize the
    /// `Completion` and `CompletionOption`s which are generated
    /// for that node.
    ///
    /// Each valid successor node will have one `Completion` in the
    /// result vector. Each `Completion` will have one or more
    /// `CompletionOption` for each valid way that the value may be
    /// entered.
    pub fn complete(&self, token: Option<Token<'p>>) -> Vec<Completion> {
        self.current_node
            .successors()
            .into_iter()
            .filter(|n| {
                // To be a possible completion, the node should not be
                // hidden, it should be acceptable, and if there's a token,
                // it should be a valid match for the node.
                !n.hidden() && n.acceptable(self) &&
                if let Some(t) = token {
                    n.matches(self, t)
                } else {
                    true
                }
            })
            .map(|n| n.complete(token))
            .collect::<Vec<_>>()
    }

    /// Parse a vector of tokens, advancing through the
    /// node hierarchy.
    ///
    /// ```
    /// use commands::parser::nodes::RootNode;
    /// use commands::parser::Parser;
    /// use commands::tokenizer::tokenize;
    ///
    /// let root = RootNode::new();
    /// let mut parser = Parser::new(root);
    ///
    /// if let Ok(tokens) = tokenize("show interface") {
    ///     parser.parse(tokens);
    /// }
    /// ```
    pub fn parse(&mut self, tokens: Vec<Token<'p>>) -> Result<(), ParseError<'p>> {
        for token in tokens {
            match token.token_type {
                TokenType::Invalid => unreachable!(),
                TokenType::Whitespace => {}
                TokenType::Word => try!(self.advance(token)),
            }
        }
        Ok(())
    }

    /// Parse a single token, advancing through the node hierarchy.
    pub fn advance(&mut self, token: Token<'p>) -> Result<(), ParseError<'p>> {
        // We clone the current node so that it doesn't stay borrowed
        // and break things when we try to modify it below.
        let cn = self.current_node.clone();
        let matches = cn.successors()
                        .into_iter()
                        .filter(|n| n.acceptable(self) && n.matches(self, token))
                        .collect::<Vec<_>>();
        match matches.len() {
            1 => {
                let matching_node = matches[0];
                matching_node.accept(self, token);
                self.current_node = matching_node.clone();
                self.nodes.push(matching_node.clone());
                self.tokens.push(token);
                Ok(())
            }
            0 => Err(ParseError::NoMatches(token)),
            _ => Err(ParseError::AmbiguousMatch(token)),
        }
    }

    /// Execute the command that has been accepted by the parser.
    ///
    /// * XXX: This should be returning a Result probably.
    pub fn execute(&self) {
        if !self.commands.is_empty() {
            unimplemented!();
            // self.commands[0].execute(self)
        }
    }

    /// Verify that the parser is in a valid state with
    /// respect to having accepted a command and all
    /// required parameters.
    pub fn verify(&self) -> Result<(), VerifyError> {
        if self.commands.is_empty() {
            return Err(VerifyError::NoCommandAccepted);
        } else {
            for expected in self.commands[0].parameters() {
                if expected.required() && !self.parameters.contains_key(expected.name()) {
                    return Err(VerifyError::MissingParameter(expected.name().clone()));
                }
            }
        }
        Ok(())
    }
}

/// Errors that calling `parse` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum ParseError<'t> {
    /// The parser is in an invalid state.
    InvalidState,
    /// There were no matches for the token.
    NoMatches(Token<'t>),
    /// There was more than 1 possible match for the token.
    AmbiguousMatch(Token<'t>), // XXX: One day, add: Vec<&'p Rc<Node>>),
}

impl<'t> Error for ParseError<'t> {
    fn description(&self) -> &str {
        match *self {
            ParseError::InvalidState => "Invalid state.",
            ParseError::NoMatches(_) => "No match.",
            ParseError::AmbiguousMatch(_) => "Ambiguous match.",
        }
    }
}

impl<'t> fmt::Display for ParseError<'t> {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Errors that calling `verify` on the `Parser` can raise.
#[derive(Clone,Debug)]
pub enum VerifyError {
    /// No command has been accepted by the parser.
    NoCommandAccepted,
    /// A required parameter is missing.
    MissingParameter(String),
}

impl Error for VerifyError {
    fn description(&self) -> &str {
        match *self {
            VerifyError::NoCommandAccepted => "No command has been accepted by the parser.",
            VerifyError::MissingParameter(_) => "A required parameter is missing.",
        }
    }
}

impl fmt::Display for VerifyError {
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.description().fmt(f)
    }
}

/// Can this node be accepted in the current parser state?
pub trait Acceptable {
    /// Can this node be accepted in the current parser state?
    fn acceptable(&self, parser: &Parser) -> bool;
}

impl Acceptable for Rc<Node> {
    /// By default, a node can be accepted when it hasn't been seen yet.
    fn acceptable(&self, parser: &Parser) -> bool {
        !parser.nodes.contains(self)
    }
}

impl Acceptable for RepeatableNode {
    /// A repeatable node can be accepted.
    fn acceptable(&self, _parser: &Parser) -> bool {
        if self.repeatable() {
            return true;
        }
        unimplemented!()
        // This should check nodes.contains, but then go on to check
        // for a repeat marker and whether or not that's been seen.
    }
}

/// Define whether or not a node matches a token.
pub trait Matches {
    /// Does this node match the specified `token`?
    fn matches(&self, parser: &Parser, token: Token) -> bool;
}

impl Matches for Node {
    /// By default, a node matches a `token` when the name of the
    /// node starts with the `token`.
    fn matches(&self, _parser: &Parser, token: Token) -> bool {
        self.name().starts_with(token.text)
    }
}

/// Define the behavior of a node when it is accepted by the parser.
pub trait Accept {
    /// Accept this node with the given `token` as data.
    ///
    /// This is where parameters are stored, commands added.
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token);
}

impl Accept for Node {
    /// By default, nothing needs to happen for `accept`.
    fn accept<'p>(&self, _parser: &mut Parser<'p>, _token: Token) {}
}

impl Accept for Rc<CommandNode> {
    /// Record this command.
    fn accept<'p>(&self, parser: &mut Parser<'p>, _token: Token) {
        if let Some(_) = self.handler() {
            parser.commands.push(self.clone())
        }
    }
}

impl Accept for ParameterNode {
    /// Record this parameter value.
    fn accept<'p>(&self, parser: &mut Parser<'p>, token: Token) {
        if self.repeatable() {
            unimplemented!();
        } else {
            parser.parameters.insert(self.name().clone(), token.text.to_string());
        }
    }
}

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

    #[test]
    #[should_panic]
    fn verify_signals_no_command() {
        let root = RootNode::new();
        let parser = Parser::new(root);
        match parser.verify() {
            Err(VerifyError::NoCommandAccepted) => panic!(),
            _ => {}
        }
    }
}
<|endoftext|>


<commit_before>pub use luminance::M44;
use nalgebra::Perspective3;

pub trait Projectable {
  fn projection(&self) -> M44;
}

pub fn perspective(ratio: f32, fovy: f32, znear: f32, zfar: f32) -> M44 {
  *Perspective3::new(ratio, fovy, znear, zfar).to_matrix().as_ref()
}

<commit_msg>More explicite perspective() implementation.<commit_after>pub use luminance::M44;
use nalgebra::Perspective3;

pub trait Projectable {
  fn projection(&self) -> M44;
}

pub fn perspective(ratio: f32, fovy: f32, znear: f32, zfar: f32) -> M44 {
  Perspective3::new(ratio, fovy, znear, zfar).to_matrix().as_ref().clone()
}

<|endoftext|>


<commit_before>// Extracted from the scopeguard crate
use core::ops::{Deref, DerefMut};

pub struct ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    dropfn: F,
    value: T,
}

#[cfg_attr(feature = "inline-more", inline)]
pub fn guard<T, F>(value: T, dropfn: F) -> ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    ScopeGuard { dropfn, value }
}

impl<T, F> Deref for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    type Target = T;
    #[cfg_attr(feature = "inline-more", inline)]
    fn deref(&self) -> &T {
        &self.value
    }
}

impl<T, F> DerefMut for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[cfg_attr(feature = "inline-more", inline)]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

impl<T, F> Drop for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    fn drop(&mut self) {
        (self.dropfn)(&mut self.value)
    }
}
<commit_msg>more inline<commit_after>// Extracted from the scopeguard crate
use core::ops::{Deref, DerefMut};

pub struct ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    dropfn: F,
    value: T,
}

#[inline]
pub fn guard<T, F>(value: T, dropfn: F) -> ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    ScopeGuard { dropfn, value }
}

impl<T, F> Deref for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    type Target = T;
    #[inline]
    fn deref(&self) -> &T {
        &self.value
    }
}

impl<T, F> DerefMut for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    fn deref_mut(&mut self) -> &mut T {
        &mut self.value
    }
}

impl<T, F> Drop for ScopeGuard<T, F>
where
    F: FnMut(&mut T),
{
    #[inline]
    fn drop(&mut self) {
        (self.dropfn)(&mut self.value)
    }
}
<|endoftext|>


<commit_before>use ppu::{Color, SCREEN_BUFFER_SIZE};
use screen::Screen;
use sdl2::{Sdl, VideoSubsystem};
use sdl2::keyboard::Keycode;
use sdl2::video::Window;
use sdl2::render::{Renderer, Texture};
use sdl2::pixels::PixelFormatEnum;
use sdl2::rect::Rect;

pub struct SDLScreen<'a> {
    video: VideoSubsystem,
    renderer: Renderer<'a>,
    texture: Texture,
}

const SCREEN_WIDTH: u32 = ::ppu::SCREEN_WIDTH as u32;
const SCREEN_HEIGHT: u32 = ::ppu::SCREEN_HEIGHT as u32;

impl<'a> SDLScreen<'a> {
    pub fn new(sdl_context: &Sdl) -> SDLScreen<'a> {
        let video_subsystem = sdl_context.video().unwrap();

        let window = video_subsystem.window("Corrosion", SCREEN_WIDTH, SCREEN_HEIGHT)
                                    .position_centered()
                                    .opengl()
                                    .build()
                                    .unwrap();

        let renderer = window.renderer().present_vsync().build().unwrap();

        let texture = renderer.create_texture_streaming(PixelFormatEnum::RGB24,
                                                            (SCREEN_WIDTH, SCREEN_HEIGHT)).unwrap();
        SDLScreen {
            video: video_subsystem,
            renderer: renderer,
            texture: texture,
        }
    }
}

//Using a hard-coded palette for now. Will add .pal file support later,
//maybe proper NTSC video decoding eventually.
#[cfg_attr(rustfmt, rustfmt_skip)]
static PALETTE: [u8; 192] = [
    84, 84, 84,       0, 30, 116,       8, 16, 144,       48, 0, 136,       68, 0, 100,       92, 0, 48,        84, 4, 0,         60, 24, 0,        32, 42, 0,        8, 58, 0,         0, 64, 0,         0, 60, 0,         0, 50, 60,        0, 0, 0,          0, 0, 0,    0, 0, 0,
    152, 150, 152,    8, 76, 196,       48, 50, 236,      92, 30, 228,      136, 20, 176,     160, 20, 100,     152, 34, 32,      120, 60, 0,       84, 90, 0,        40, 114, 0,       8, 124, 0,        0, 118, 40,       0, 102, 120,      0, 0, 0,          0, 0, 0,    0, 0, 0,
    236, 238, 236,    76, 154, 236,     120, 124, 236,    176, 98, 236,     228, 84, 236,     236, 88, 180,     236, 106, 100,    212, 136, 32,     160, 170, 0,      116, 196, 0,      76, 208, 32,      56, 204, 108,     56, 180, 204,     60, 60, 60,       0, 0, 0,    0, 0, 0,
    236, 238, 236,    168, 204, 236,    188, 188, 236,    212, 178, 236,    236, 174, 236,    236, 174, 212,    236, 180, 176,    228, 196, 144,    204, 210, 120,    180, 222, 120,    168, 226, 144,    152, 226, 180,    160, 214, 228,    160, 162, 160,    0, 0, 0,    0, 0, 0,
];

impl<'a> Screen for SDLScreen<'a> {
    fn draw(&mut self, buf: &[Color; SCREEN_BUFFER_SIZE]) {
        self.texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
            for y in 0..::ppu::SCREEN_HEIGHT {
                for x in 0..::ppu::SCREEN_WIDTH {
                    let color = buf[y * x];
                    let pal_idx = color.bits() as usize * 3;
                    let offset = y * pitch + x * 3;
                    buffer[offset + 0] = PALETTE[pal_idx + 0];
                    buffer[offset + 1] = PALETTE[pal_idx + 1];
                    buffer[offset + 2] = PALETTE[pal_idx + 2];
                }
            }
        }).unwrap();

        self.renderer.copy(&self.texture,
              None,
              Some(Rect::new_unwrap(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)));
        self.renderer.present();
    }
}
<commit_msg>Fix bug where pixels weren't rendered in the right place.<commit_after>use ppu::{Color, SCREEN_BUFFER_SIZE};
use screen::Screen;
use sdl2::{Sdl, VideoSubsystem};
use sdl2::keyboard::Keycode;
use sdl2::video::Window;
use sdl2::render::{Renderer, Texture};
use sdl2::pixels::PixelFormatEnum;
use sdl2::rect::Rect;

pub struct SDLScreen<'a> {
    video: VideoSubsystem,
    renderer: Renderer<'a>,
    texture: Texture,
}

const SCREEN_WIDTH: u32 = ::ppu::SCREEN_WIDTH as u32;
const SCREEN_HEIGHT: u32 = ::ppu::SCREEN_HEIGHT as u32;

impl<'a> SDLScreen<'a> {
    pub fn new(sdl_context: &Sdl) -> SDLScreen<'a> {
        let video_subsystem = sdl_context.video().unwrap();

        let window = video_subsystem.window("Corrosion", SCREEN_WIDTH, SCREEN_HEIGHT)
                                    .position_centered()
                                    .opengl()
                                    .build()
                                    .unwrap();

        let renderer = window.renderer().present_vsync().build().unwrap();

        let texture = renderer.create_texture_streaming(PixelFormatEnum::RGB24,
                                                            (SCREEN_WIDTH, SCREEN_HEIGHT)).unwrap();
        SDLScreen {
            video: video_subsystem,
            renderer: renderer,
            texture: texture,
        }
    }
}

//Using a hard-coded palette for now. Will add .pal file support later,
//maybe proper NTSC video decoding eventually.
#[cfg_attr(rustfmt, rustfmt_skip)]
static PALETTE: [u8; 192] = [
    84, 84, 84,       0, 30, 116,       8, 16, 144,       48, 0, 136,       68, 0, 100,       92, 0, 48,        84, 4, 0,         60, 24, 0,        32, 42, 0,        8, 58, 0,         0, 64, 0,         0, 60, 0,         0, 50, 60,        0, 0, 0,          0, 0, 0,    0, 0, 0,
    152, 150, 152,    8, 76, 196,       48, 50, 236,      92, 30, 228,      136, 20, 176,     160, 20, 100,     152, 34, 32,      120, 60, 0,       84, 90, 0,        40, 114, 0,       8, 124, 0,        0, 118, 40,       0, 102, 120,      0, 0, 0,          0, 0, 0,    0, 0, 0,
    236, 238, 236,    76, 154, 236,     120, 124, 236,    176, 98, 236,     228, 84, 236,     236, 88, 180,     236, 106, 100,    212, 136, 32,     160, 170, 0,      116, 196, 0,      76, 208, 32,      56, 204, 108,     56, 180, 204,     60, 60, 60,       0, 0, 0,    0, 0, 0,
    236, 238, 236,    168, 204, 236,    188, 188, 236,    212, 178, 236,    236, 174, 236,    236, 174, 212,    236, 180, 176,    228, 196, 144,    204, 210, 120,    180, 222, 120,    168, 226, 144,    152, 226, 180,    160, 214, 228,    160, 162, 160,    0, 0, 0,    0, 0, 0,
];

impl<'a> Screen for SDLScreen<'a> {
    fn draw(&mut self, buf: &[Color; SCREEN_BUFFER_SIZE]) {
        self.texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
            for y in 0..::ppu::SCREEN_HEIGHT {
                for x in 0..::ppu::SCREEN_WIDTH {
                    let color = buf[y * ::ppu::SCREEN_WIDTH + x];
                    let pal_idx = color.bits() as usize * 3;
                    let offset = y * pitch + x * 3;
                    buffer[offset + 0] = PALETTE[pal_idx + 0];
                    buffer[offset + 1] = PALETTE[pal_idx + 1];
                    buffer[offset + 2] = PALETTE[pal_idx + 2];
                }
            }
        }).unwrap();

        self.renderer.copy(&self.texture,
              None,
              Some(Rect::new_unwrap(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT)));
        self.renderer.present();
    }
}
<|endoftext|>