<commit_before>extern crate gl_generator;

use gl_generator::{Registry, Api, Profile, Fallbacks};
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

mod textures;

fn main() {
    let dest = env::var("OUT_DIR").unwrap();
    let dest = Path::new(&dest);

    textures::build_texture_file(&mut File::create(&dest.join("textures.rs")).unwrap());
    println!("cargo:rerun-if-changed=build/main.rs");

    // There is a `#[derive(Clone)]` line in the bindings that triggers a stack overflow
    // in rustc (https://github.com/rust-lang/rust/issues/26467).
    // Therefore we write the bindings to memory first, then remove this line, and then copy
    // to the file.
    let mut gl_bindings = Vec::new();
    generate_gl_bindings(&mut gl_bindings);
    let gl_bindings = String::from_utf8(gl_bindings).unwrap();
    let gl_bindings = gl_bindings.replace("#[derive(Clone)]", "");
    let mut file_output = File::create(&dest.join("gl_bindings.rs")).unwrap();
    file_output.write_all(&gl_bindings.into_bytes()).unwrap();
}

fn generate_gl_bindings<W>(dest: &mut W) where W: Write {
    let gl_registry = Registry::new(
        Api::Gl,
        (4, 5),
        Profile::Compatibility,
        Fallbacks::None,
        vec![
            "GL_AMD_depth_clamp_separate",
            "GL_APPLE_vertex_array_object",
            "GL_ARB_bindless_texture",
            "GL_ARB_buffer_storage",
            "GL_ARB_compute_shader",
            "GL_ARB_copy_buffer",
            "GL_ARB_debug_output",
            "GL_ARB_depth_texture",
            "GL_ARB_direct_state_access",
            "GL_ARB_draw_buffers",
            "GL_ARB_ES2_compatibility",
            "GL_ARB_ES3_compatibility",
            "GL_ARB_ES3_1_compatibility",
            "GL_ARB_ES3_2_compatibility",
            "GL_ARB_framebuffer_sRGB",
            "GL_ARB_geometry_shader4",
            "GL_ARB_gpu_shader_fp64",
            "GL_ARB_gpu_shader_int64",
            "GL_ARB_invalidate_subdata",
            "GL_ARB_multi_draw_indirect",
            "GL_ARB_occlusion_query",
            "GL_ARB_pixel_buffer_object",
            "GL_ARB_robustness",
            "GL_ARB_shader_image_load_store",
            "GL_ARB_shader_objects",
            "GL_ARB_texture_buffer_object",
            "GL_ARB_texture_float",
            "GL_ARB_texture_multisample",
            "GL_ARB_texture_rg",
            "GL_ARB_texture_rgb10_a2ui",
            "GL_ARB_transform_feedback3",
            "GL_ARB_vertex_buffer_object",
            "GL_ARB_vertex_shader",
            "GL_ATI_draw_buffers",
            "GL_ATI_meminfo",
            "GL_EXT_debug_marker",
            "GL_EXT_direct_state_access",
            "GL_EXT_framebuffer_blit",
            "GL_EXT_framebuffer_multisample",
            "GL_EXT_framebuffer_object",
            "GL_EXT_framebuffer_sRGB",
            "GL_EXT_gpu_shader4",
            "GL_EXT_packed_depth_stencil",
            "GL_EXT_provoking_vertex",
            "GL_EXT_texture_array",
            "GL_EXT_texture_buffer_object",
            "GL_EXT_texture_compression_s3tc",
            "GL_EXT_texture_filter_anisotropic",
            "GL_EXT_texture_integer",
            "GL_EXT_texture_sRGB",
            "GL_EXT_transform_feedback",
            "GL_GREMEDY_string_marker",
            "GL_KHR_robustness",
            "GL_NVX_gpu_memory_info",
            "GL_NV_conditional_render",
            "GL_NV_vertex_attrib_integer_64bit",
        ],
    );

    let gles_registry = Registry::new(
        Api::Gles2,
        (3, 2),
        Profile::Compatibility,
        Fallbacks::None,
        vec![
            "GL_ANGLE_framebuffer_multisample",
            "GL_APPLE_framebuffer_multisample",
            "GL_APPLE_sync",
            "GL_ARM_rgba8",
            "GL_EXT_buffer_storage",
            "GL_EXT_disjoint_timer_query",
            "GL_EXT_multi_draw_indirect",
            "GL_EXT_multisampled_render_to_texture",
            "GL_EXT_occlusion_query_boolean",
            "GL_EXT_primitive_bounding_box",
            "GL_EXT_robustness",
            "GL_KHR_debug",
            "GL_NV_copy_buffer",
            "GL_NV_framebuffer_multisample",
            "GL_NV_internalformat_sample_query",
            "GL_NV_pixel_buffer_object",
            "GL_OES_depth_texture",
            "GL_OES_draw_elements_base_vertex",
            "GL_OES_packed_depth_stencil",
            "GL_OES_primitive_bounding_box",
            "GL_OES_rgb8_rgba8",
            "GL_OES_texture_buffer",
            "GL_OES_texture_npot",
            "GL_OES_vertex_array_object",
            "GL_OES_vertex_type_10_10_10_2",
        ],
    );

    (gl_registry + gles_registry)
        .write_bindings(gl_generator::StructGenerator, dest)
        .unwrap();
}
<commit_msg>remove unnecessary build hack<commit_after>extern crate gl_generator;

use gl_generator::{Registry, Api, Profile, Fallbacks};
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

mod textures;

fn main() {
    let dest = env::var("OUT_DIR").unwrap();
    let dest = Path::new(&dest);

    textures::build_texture_file(&mut File::create(&dest.join("textures.rs")).unwrap());
    println!("cargo:rerun-if-changed=build/main.rs");

    let mut file_output = File::create(&dest.join("gl_bindings.rs")).unwrap();
    generate_gl_bindings(&mut file_output);
}

fn generate_gl_bindings<W>(dest: &mut W) where W: Write {
    let gl_registry = Registry::new(
        Api::Gl,
        (4, 5),
        Profile::Compatibility,
        Fallbacks::None,
        vec![
            "GL_AMD_depth_clamp_separate",
            "GL_APPLE_vertex_array_object",
            "GL_ARB_bindless_texture",
            "GL_ARB_buffer_storage",
            "GL_ARB_compute_shader",
            "GL_ARB_copy_buffer",
            "GL_ARB_debug_output",
            "GL_ARB_depth_texture",
            "GL_ARB_direct_state_access",
            "GL_ARB_draw_buffers",
            "GL_ARB_ES2_compatibility",
            "GL_ARB_ES3_compatibility",
            "GL_ARB_ES3_1_compatibility",
            "GL_ARB_ES3_2_compatibility",
            "GL_ARB_framebuffer_sRGB",
            "GL_ARB_geometry_shader4",
            "GL_ARB_gpu_shader_fp64",
            "GL_ARB_gpu_shader_int64",
            "GL_ARB_invalidate_subdata",
            "GL_ARB_multi_draw_indirect",
            "GL_ARB_occlusion_query",
            "GL_ARB_pixel_buffer_object",
            "GL_ARB_robustness",
            "GL_ARB_shader_image_load_store",
            "GL_ARB_shader_objects",
            "GL_ARB_texture_buffer_object",
            "GL_ARB_texture_float",
            "GL_ARB_texture_multisample",
            "GL_ARB_texture_rg",
            "GL_ARB_texture_rgb10_a2ui",
            "GL_ARB_transform_feedback3",
            "GL_ARB_vertex_buffer_object",
            "GL_ARB_vertex_shader",
            "GL_ATI_draw_buffers",
            "GL_ATI_meminfo",
            "GL_EXT_debug_marker",
            "GL_EXT_direct_state_access",
            "GL_EXT_framebuffer_blit",
            "GL_EXT_framebuffer_multisample",
            "GL_EXT_framebuffer_object",
            "GL_EXT_framebuffer_sRGB",
            "GL_EXT_gpu_shader4",
            "GL_EXT_packed_depth_stencil",
            "GL_EXT_provoking_vertex",
            "GL_EXT_texture_array",
            "GL_EXT_texture_buffer_object",
            "GL_EXT_texture_compression_s3tc",
            "GL_EXT_texture_filter_anisotropic",
            "GL_EXT_texture_integer",
            "GL_EXT_texture_sRGB",
            "GL_EXT_transform_feedback",
            "GL_GREMEDY_string_marker",
            "GL_KHR_robustness",
            "GL_NVX_gpu_memory_info",
            "GL_NV_conditional_render",
            "GL_NV_vertex_attrib_integer_64bit",
        ],
    );

    let gles_registry = Registry::new(
        Api::Gles2,
        (3, 2),
        Profile::Compatibility,
        Fallbacks::None,
        vec![
            "GL_ANGLE_framebuffer_multisample",
            "GL_APPLE_framebuffer_multisample",
            "GL_APPLE_sync",
            "GL_ARM_rgba8",
            "GL_EXT_buffer_storage",
            "GL_EXT_disjoint_timer_query",
            "GL_EXT_multi_draw_indirect",
            "GL_EXT_multisampled_render_to_texture",
            "GL_EXT_occlusion_query_boolean",
            "GL_EXT_primitive_bounding_box",
            "GL_EXT_robustness",
            "GL_KHR_debug",
            "GL_NV_copy_buffer",
            "GL_NV_framebuffer_multisample",
            "GL_NV_internalformat_sample_query",
            "GL_NV_pixel_buffer_object",
            "GL_OES_depth_texture",
            "GL_OES_draw_elements_base_vertex",
            "GL_OES_packed_depth_stencil",
            "GL_OES_primitive_bounding_box",
            "GL_OES_rgb8_rgba8",
            "GL_OES_texture_buffer",
            "GL_OES_texture_npot",
            "GL_OES_vertex_array_object",
            "GL_OES_vertex_type_10_10_10_2",
        ],
    );

    (gl_registry + gles_registry)
        .write_bindings(gl_generator::StructGenerator, dest)
        .unwrap();
}
<|endoftext|>


<commit_before>#![feature(lang_items)]
#![no_std]
#![feature(const_fn)]
#![feature(unique)]
#![feature(asm)]
#![feature(naked_functions)]

extern crate rlibc;
extern crate volatile;
extern crate spin;
#[macro_use]
extern crate bitflags;
extern crate bit_field;
extern crate x86;
#[macro_use]
extern crate lazy_static;

use rlibc::memset;
use memory::FrameAllocator;

mod initium;
#[macro_use]
mod vga_buffer;
mod version;
mod memory;
mod interrupts;

/// Magic number passed to the entry point of a Initium kernel.
static INITIUM_MAGIC: u32 = 0xb007cafe;

/// This is the entry point for the Kernel, all the things must be initialized
#[no_mangle]
pub extern "C" fn start(magic: u32, initium_info_addr: usize) -> ! {
    extern "C" {
        /// The starting byte of the .bss segment
        static mut __bss_start: u8;
        /// The ending byte of the .bss segment
        static mut __bss_end: u8;
    }

    // Zero BSS, this initializes statics that are set to 0
    unsafe {
        let start_ptr = &mut __bss_start as *mut u8;
        let end_ptr = &mut __bss_end as *const u8 as usize;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            memset(start_ptr, 0, size);
        }
    }

    // clear the screen
    vga_buffer::clear_screen();

    // Print a Welcome message
    println!("Infinity OS {}", version::PULSAR_VER_STRING);

    // print out the Initium Magic number
    println!("Bootloder magic flag: 0x{0:x}", magic);

    // check if we are been booted up from a valid bootloader
    if magic != INITIUM_MAGIC {
        panic!("Invalid magic flag!");
    }

    // load boot information
    let boot_info = unsafe { initium::load(initium_info_addr) };

    // get the free memory areas and print it out
    let memory_map_tag = boot_info.memory_map();
    println!("Memory Areas:");
    for entry in memory_map_tag {
        println!("    start: 0x{:x}, length: 0x{:x}",
        entry.base_address(), entry.length());
    }

    // Print the kernel sections
    let sections_tag = boot_info.elf_sections().expect("Elf-sections tag required");
    println!("Kernel Sections:");
    for section in sections_tag.elf_sections() {
        println!("    addr: 0x{:x}, size: 0x{:x}, flags: 0x{:x}",
                 section.section_start_address(), section.size_bytes(), section.flags());
    }

    let core_information = boot_info.core_information().expect("Core tag required");
    let initium_start = initium_info_addr;
    let initium_end = initium_info_addr + (core_information.tags_size() as usize);

    let kernel_start = sections_tag.elf_sections().map(|s| s.section_start_address())
        .min().unwrap();
    let kernel_end = sections_tag.elf_sections().map(|s| s.section_start_address() + s.size_bytes())
        .max().unwrap();

    // This is just for debug proposes, on the future this must be removed
    println!("Kernel range: 0x{:x} - 0x{:x}", kernel_start, kernel_end);
    println!("Initium range: 0x{:x} - 0x{:x}", initium_start, initium_end);

    let mut frame_allocator = memory::AreaFrameAllocator::new(kernel_start as usize,
                                                              kernel_end as usize,
                                                              initium_start,
                                                              initium_end,
                                                              boot_info.memory_map());

    // WIP: testing page
    // TODO: use the bootloader page tables tag to get the PML4 address
    // memory::test_paging(&mut frame_allocator);

    // WIP: Initialize IDT system
    // interrupts::init();

    fn divide_by_zero() {
        unsafe {
            asm!("mov dx, 0; div dx" ::: "ax", "dx" : "volatile", "intel")
        }
    }

    // provoke a divide-by-zero fault
    // divide_by_zero();

    println!("It did not crash!");

    // Makes a infinity loop to avoid the kernel returns
    loop {}
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
    loop {}
}

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[lang = "panic_fmt"]
#[no_mangle]
pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str,
                        line: u32) -> !
{
    println!("\n\nPANIC in {} at line {}:", file, line);
    println!("    {}", fmt);

    loop{}
}

<commit_msg>Cleanup some code<commit_after>#![feature(lang_items)]
#![no_std]
#![feature(const_fn)]
#![feature(unique)]
#![feature(asm)]
#![feature(naked_functions)]

extern crate rlibc;
extern crate volatile;
extern crate spin;
#[macro_use]
extern crate bitflags;
extern crate bit_field;
extern crate x86;
#[macro_use]
extern crate lazy_static;

use rlibc::memset;
use memory::FrameAllocator;

mod initium;
#[macro_use]
mod vga_buffer;
mod version;
mod memory;
mod interrupts;

/// Magic number passed to the entry point of a Initium kernel.
static INITIUM_MAGIC: u32 = 0xb007cafe;

/// Kernel allocation area base
const KERNEL_KMEM_BASE: u32 = 0xFFFFFF8000000000;
/// Kernel allocation area size (510GB)
const KERNEL_KMEM_SIZE: u32 = 0x0000007F80000000;
/// Last address of kmem space
const KERNEL_KMEM_END: u32 = (KERNEL_KMEM_BASE + KERNEL_KMEM_SIZE - 1);

/// This is the entry point for the Kernel, all the things must be initialized
#[no_mangle]
pub extern "C" fn start(magic: u32, initium_info_addr: usize) -> ! {
    extern "C" {
        /// The starting byte of the .bss segment
        static mut __bss_start: u8;
        /// The ending byte of the .bss segment
        static mut __bss_end: u8;
    }

    // Zero BSS, this initializes statics that are set to 0
    unsafe {
        let start_ptr = &mut __bss_start as *mut u8;
        let end_ptr = &mut __bss_end as *const u8 as usize;

        if start_ptr as usize <= end_ptr {
            let size = end_ptr - start_ptr as usize;
            memset(start_ptr, 0, size);
        }
    }

    // clear the screen
    vga_buffer::clear_screen();

    // Print a Welcome message
    println!("kernel: version {} booting...", version::PULSAR_VER_STRING);

    // check if we are been booted up from a valid bootloader
    if magic != INITIUM_MAGIC {
        panic!("Invalid magic flag!");
    }

    // load boot information
    let boot_info = unsafe { initium::load(initium_info_addr) };

    let core_information = boot_info.core_information().expect("Core tag required");
    let initium_start = initium_info_addr;
    let initium_end = initium_info_addr + (core_information.tags_size() as usize);

    let mut frame_allocator = memory::AreaFrameAllocator::new(KERNEL_KMEM_BASE as usize,
                                                              KERNEL_KMEM_END as usize,
                                                              initium_start,
                                                              initium_end,
                                                              boot_info.memory_map());

    loop {}

    // --- OLD

    // WIP: testing page
    // TODO: use the bootloader page tables tag to get the PML4 address
    // memory::test_paging(&mut frame_allocator);

    // WIP: Initialize IDT system
    interrupts::init();

    fn divide_by_zero() {
        unsafe {
            asm!("mov dx, 0; div dx" ::: "ax", "dx" : "volatile", "intel")
        }
    }

    // provoke a divide-by-zero fault
    divide_by_zero();

    println!("It did not crash!");
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn _Unwind_Resume() -> ! {
    loop {}
}

#[lang = "eh_personality"]
extern "C" fn eh_personality() {}

#[lang = "panic_fmt"]
#[no_mangle]
pub extern fn panic_fmt(fmt: core::fmt::Arguments, file: &'static str,
                        line: u32) -> !
{
    println!("\n\nPANIC in {} at line {}:", file, line);
    println!("    {}", fmt);

    loop{}
}

<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::compartments::InCompartment;
use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode;
use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType;
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XREnvironmentBlendMode;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRSessionMethods;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrlayer::XRLayer;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrrenderstate::XRRenderState;
use crate::dom::xrspace::XRSpace;
use dom_struct::dom_struct;
use euclid::Vector3D;
use std::cell::Cell;
use std::rc::Rc;
use webxr_api::Session;

#[dom_struct]
pub struct XRSession {
    eventtarget: EventTarget,
    base_layer: MutNullableDom<XRLayer>,
    blend_mode: XREnvironmentBlendMode,
    viewer_space: MutNullableDom<XRSpace>,
    #[ignore_malloc_size_of = "defined in webxr"]
    session: Session,
    frame_requested: Cell<bool>,
    pending_render_state: MutNullableDom<XRRenderState>,
    active_render_state: MutDom<XRRenderState>,
}

impl XRSession {
    fn new_inherited(session: Session, render_state: &XRRenderState) -> XRSession {
        XRSession {
            eventtarget: EventTarget::new_inherited(),
            base_layer: Default::default(),
            // we don't yet support any AR devices
            blend_mode: XREnvironmentBlendMode::Opaque,
            viewer_space: Default::default(),
            session,
            frame_requested: Cell::new(false),
            pending_render_state: MutNullableDom::new(None),
            active_render_state: MutDom::new(render_state),
        }
    }

    pub fn new(global: &GlobalScope, session: Session) -> DomRoot<XRSession> {
        let render_state = XRRenderState::new(global, 0.1, 1000.0, None);
        reflect_dom_object(
            Box::new(XRSession::new_inherited(session, &render_state)),
            global,
            XRSessionBinding::Wrap,
        )
    }

    pub fn set_layer(&self, layer: &XRLayer) {
        self.base_layer.set(Some(layer))
    }

    pub fn left_eye_params_offset(&self) -> Vector3D<f64> {
        unimplemented!()
    }

    pub fn right_eye_params_offset(&self) -> Vector3D<f64> {
        unimplemented!()
    }
}

impl XRSessionMethods for XRSession {
    /// https://immersive-web.github.io/webxr/#dom-xrsession-mode
    fn Mode(&self) -> XRSessionMode {
        XRSessionMode::Immersive_vr
    }

    // https://immersive-web.github.io/webxr/#dom-xrsession-renderstate
    fn RenderState(&self) -> DomRoot<XRRenderState> {
        self.active_render_state.get()
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-updaterenderstate
    fn UpdateRenderState(&self, init: &XRRenderStateInit, _: InCompartment) {
        // XXXManishearth various checks:
        // If session’s ended value is true, throw an InvalidStateError and abort these steps
        // If newState’s baseLayer's was created with an XRSession other than session,
        // throw an InvalidStateError and abort these steps
        // If newState’s inlineVerticalFieldOfView is set and session is an
        // immersive session, throw an InvalidStateError and abort these steps.

        let pending = self
            .pending_render_state
            .or_init(|| self.active_render_state.get().copy());
        if let Some(near) = init.depthNear {
            pending.set_depth_near(*near);
        }
        if let Some(far) = init.depthFar {
            pending.set_depth_far(*far);
        }
        if let Some(ref layer) = init.baseLayer {
            pending.set_layer(Some(&layer))
        }
        // XXXManishearth handle inlineVerticalFieldOfView
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe
    fn RequestAnimationFrame(&self, callback: Rc<XRFrameRequestCallback>) -> i32 {
        unimplemented!()
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-cancelanimationframe
    fn CancelAnimationFrame(&self, frame: i32) {
        unimplemented!()
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-environmentblendmode
    fn EnvironmentBlendMode(&self) -> XREnvironmentBlendMode {
        self.blend_mode
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-requestreferencespace
    fn RequestReferenceSpace(&self, ty: XRReferenceSpaceType, comp: InCompartment) -> Rc<Promise> {
        let p = Promise::new_in_current_compartment(&self.global(), comp);

        // https://immersive-web.github.io/webxr/#create-a-reference-space

        // XXXManishearth reject based on session type
        // https://github.com/immersive-web/webxr/blob/master/spatial-tracking-explainer.md#practical-usage-guidelines

        match ty {
            XRReferenceSpaceType::Bounded_floor | XRReferenceSpaceType::Unbounded => {
                // XXXManishearth eventually support these
                p.reject_error(Error::NotSupported)
            },
            ty => {
                p.resolve_native(&XRReferenceSpace::new(&self.global(), self, ty));
            },
        }

        p
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-getinputsources
    fn GetInputSources(&self) -> Vec<DomRoot<XRInputSource>> {
        unimplemented!()
    }
}
<commit_msg>Add basic rAF and cAF functions that do nothing with the callbacks<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::compartments::InCompartment;
use crate::dom::bindings::cell::DomRefCell;
use crate::dom::bindings::codegen::Bindings::XRBinding::XRSessionMode;
use crate::dom::bindings::codegen::Bindings::XRReferenceSpaceBinding::XRReferenceSpaceType;
use crate::dom::bindings::codegen::Bindings::XRRenderStateBinding::XRRenderStateInit;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XREnvironmentBlendMode;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRFrameRequestCallback;
use crate::dom::bindings::codegen::Bindings::XRSessionBinding::XRSessionMethods;
use crate::dom::bindings::error::Error;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject};
use crate::dom::bindings::root::{DomRoot, MutDom, MutNullableDom};
use crate::dom::eventtarget::EventTarget;
use crate::dom::globalscope::GlobalScope;
use crate::dom::promise::Promise;
use crate::dom::xrinputsource::XRInputSource;
use crate::dom::xrlayer::XRLayer;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrrenderstate::XRRenderState;
use crate::dom::xrspace::XRSpace;
use dom_struct::dom_struct;
use euclid::Vector3D;
use std::cell::Cell;
use std::rc::Rc;
use webxr_api::Session;

#[dom_struct]
pub struct XRSession {
    eventtarget: EventTarget,
    base_layer: MutNullableDom<XRLayer>,
    blend_mode: XREnvironmentBlendMode,
    viewer_space: MutNullableDom<XRSpace>,
    #[ignore_malloc_size_of = "defined in webxr"]
    session: Session,
    frame_requested: Cell<bool>,
    pending_render_state: MutNullableDom<XRRenderState>,
    active_render_state: MutDom<XRRenderState>,

    next_raf_id: Cell<i32>,
    #[ignore_malloc_size_of = "closures are hard"]
    raf_callback_list: DomRefCell<Vec<(i32, Option<Rc<XRFrameRequestCallback>>)>>,
}

impl XRSession {
    fn new_inherited(session: Session, render_state: &XRRenderState) -> XRSession {
        XRSession {
            eventtarget: EventTarget::new_inherited(),
            base_layer: Default::default(),
            // we don't yet support any AR devices
            blend_mode: XREnvironmentBlendMode::Opaque,
            viewer_space: Default::default(),
            session,
            frame_requested: Cell::new(false),
            pending_render_state: MutNullableDom::new(None),
            active_render_state: MutDom::new(render_state),

            next_raf_id: Cell::new(0),
            raf_callback_list: DomRefCell::new(vec![]),
        }
    }

    pub fn new(global: &GlobalScope, session: Session) -> DomRoot<XRSession> {
        let render_state = XRRenderState::new(global, 0.1, 1000.0, None);
        reflect_dom_object(
            Box::new(XRSession::new_inherited(session, &render_state)),
            global,
            XRSessionBinding::Wrap,
        )
    }

    pub fn set_layer(&self, layer: &XRLayer) {
        self.base_layer.set(Some(layer))
    }

    pub fn left_eye_params_offset(&self) -> Vector3D<f64> {
        unimplemented!()
    }

    pub fn right_eye_params_offset(&self) -> Vector3D<f64> {
        unimplemented!()
    }
}

impl XRSessionMethods for XRSession {
    /// https://immersive-web.github.io/webxr/#dom-xrsession-mode
    fn Mode(&self) -> XRSessionMode {
        XRSessionMode::Immersive_vr
    }

    // https://immersive-web.github.io/webxr/#dom-xrsession-renderstate
    fn RenderState(&self) -> DomRoot<XRRenderState> {
        self.active_render_state.get()
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-updaterenderstate
    fn UpdateRenderState(&self, init: &XRRenderStateInit, _: InCompartment) {
        // XXXManishearth various checks:
        // If session’s ended value is true, throw an InvalidStateError and abort these steps
        // If newState’s baseLayer's was created with an XRSession other than session,
        // throw an InvalidStateError and abort these steps
        // If newState’s inlineVerticalFieldOfView is set and session is an
        // immersive session, throw an InvalidStateError and abort these steps.

        let pending = self
            .pending_render_state
            .or_init(|| self.active_render_state.get().copy());
        if let Some(near) = init.depthNear {
            pending.set_depth_near(*near);
        }
        if let Some(far) = init.depthFar {
            pending.set_depth_far(*far);
        }
        if let Some(ref layer) = init.baseLayer {
            pending.set_layer(Some(&layer))
        }
        // XXXManishearth handle inlineVerticalFieldOfView
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-requestanimationframe
    fn RequestAnimationFrame(&self, callback: Rc<XRFrameRequestCallback>) -> i32 {
        let raf_id = self.next_raf_id.get();
        self.next_raf_id.set(raf_id + 1);
        self.raf_callback_list
            .borrow_mut()
            .push((raf_id, Some(callback)));
        // XXXManishearth fill in callback request
        raf_id
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-cancelanimationframe
    fn CancelAnimationFrame(&self, frame: i32) {
        let mut list = self.raf_callback_list.borrow_mut();
        if let Some(pair) = list.iter_mut().find(|pair| pair.0 == frame) {
            pair.1 = None;
        }
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-environmentblendmode
    fn EnvironmentBlendMode(&self) -> XREnvironmentBlendMode {
        self.blend_mode
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-requestreferencespace
    fn RequestReferenceSpace(&self, ty: XRReferenceSpaceType, comp: InCompartment) -> Rc<Promise> {
        let p = Promise::new_in_current_compartment(&self.global(), comp);

        // https://immersive-web.github.io/webxr/#create-a-reference-space

        // XXXManishearth reject based on session type
        // https://github.com/immersive-web/webxr/blob/master/spatial-tracking-explainer.md#practical-usage-guidelines

        match ty {
            XRReferenceSpaceType::Bounded_floor | XRReferenceSpaceType::Unbounded => {
                // XXXManishearth eventually support these
                p.reject_error(Error::NotSupported)
            },
            ty => {
                p.resolve_native(&XRReferenceSpace::new(&self.global(), self, ty));
            },
        }

        p
    }

    /// https://immersive-web.github.io/webxr/#dom-xrsession-getinputsources
    fn GetInputSources(&self) -> Vec<DomRoot<XRInputSource>> {
        unimplemented!()
    }
}
<|endoftext|>


<commit_before>/// MIT License (C) 2016 Andy Georges
///
/// Pattern to compare directories with an allow taking the correct action.
///
/// A pattern is defined as a regular expression, annotated with
/// a modification operation. When both match, a set of tasks should be
/// carried out.

use std::path::PathBuf;

extern crate notify;
extern crate regex;

use self::notify::op::Op;
use self::regex::Regex;

use task::Task;

/// Pattern type
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Pattern {
    name: String,
    op: Op,
    pattern: Regex,
    pub tasks: Vec<Task>,
}

impl Pattern {

    pub fn new(name: String, op: Op, pattern: Regex, tasks: Vec<Task>) -> Pattern {
        Pattern {
            name: name,
            op: op,
            pattern: pattern,
            tasks: tasks,
        }
    }

    // Matching a given path?
    pub fn is_match(&self, path: &PathBuf, op: &notify::op::Op) -> bool {
        self.pattern.is_match(&path.to_str().unwrap()) && self.op.eq(op)
    }

}

/// Predefined patterns and associated tasks
pub fn predefined_patterns() -> Vec<Pattern> {
    let mut m: Vec<Pattern> = Vec::new();

    // USR grouping directories
    m.push(Pattern::new(
        String::from("USR grouping dir"),
        notify::op::CREATE,
        Regex::new("^/.*/vsc[0-9]{3}$").unwrap(),
        vec![Task::AddWatcher, Task::Rescan]));

    // USR personal directories
    m.push(Pattern::new(
        String::from("USR personal dir"),
        notify::op::CHMOD,
        Regex::new("^/.*/vsc[0-9]{3}/vsc[0-9]{5}$").unwrap(),
        vec![Task::PermissionCheck]));

    m
}

<commit_msg>Add Permission mask to the patterns<commit_after>/// MIT License (C) 2016 Andy Georges
///
/// Pattern to compare directories with an allow taking the correct action.
///
/// A pattern is defined as a regular expression, annotated with
/// a modification operation. When both match, a set of tasks should be
/// carried out.

use std::path::PathBuf;

extern crate notify;
extern crate regex;

use self::notify::op::Op;
use self::regex::Regex;

use task::Task;

/// Pattern type
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Pattern {
    name: String,
    op: Op,
    pattern: Regex,
    permission_mask: u32,
    pub tasks: Vec<Task>,
}

impl Pattern {

    pub fn new(name: String, op: Op, pattern: Regex, permission_mask: u32, tasks: Vec<Task>) -> Pattern {
        Pattern {
            name: name,
            op: op,
            pattern: pattern,
            permission_mask: permission_mask,
            tasks: tasks,
        }
    }

    // Matching a given path?
    pub fn is_match(&self, path: &PathBuf, op: &notify::op::Op) -> bool {
        self.pattern.is_match(&path.to_str().unwrap()) && self.op.eq(op)
    }

}

/// Predefined patterns and associated tasks
pub fn predefined_patterns() -> Vec<Pattern> {
    let mut m: Vec<Pattern> = Vec::new();

    // USR grouping directories
    m.push(Pattern::new(
        String::from("USR grouping dir"),
        notify::op::CREATE,
        Regex::new("^/.*/vsc[0-9]{3}$").unwrap(),
        0o750,
        vec![Task::AddWatcher, Task::Rescan]));

    // USR personal directories
    m.push(Pattern::new(
        String::from("USR personal dir"),
        notify::op::CHMOD,
        Regex::new("^/.*/vsc[0-9]{3}/vsc[0-9]{5}$").unwrap(),
        0o750,
        vec![Task::PermissionCheck]));

    m
}

<|endoftext|>


<commit_before>//! Decoding of netpbm image formats (pbm, pgm, ppm and pam).
//!
//! The formats pbm, pgm and ppm are fully supported. The pam decoder recognizes the tuple types
//! `BLACKANDWHITE`, `GRAYSCALE` and `RGB` and explicitely recognizes but rejects their `_ALPHA`
//! variants for now as alpha color types are unsupported.
use self::autobreak::AutoBreak;
pub use self::decoder::PNMDecoder;
pub use self::encoder::PNMEncoder;
use self::header::HeaderRecord;
pub use self::header::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader,
                       PixmapHeader};
pub use self::header::{PNMHeader, PNMSubtype, SampleEncoding};

mod autobreak;
mod decoder;
mod encoder;
mod header;

#[cfg(test)]
mod tests {
    use super::*;
    use color::ColorType;
    use image::{DecodingResult, ImageDecoder};

    fn execute_roundtrip_default(buffer: &[u8], width: u32, height: u32, color: ColorType) {
        let mut encoded_buffer = Vec::new();

        {
            let mut encoder = PNMEncoder::new(&mut encoded_buffer);
            encoder
                .encode(buffer, width, height, color)
                .expect("Failed to encode the image buffer");
        }

        let (header, loaded_color, loaded_image) = {
            let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap();
            let colortype = decoder.colortype().expect("Failed to decode color type");
            let image = decoder.read_image().expect("Failed to decode the image");
            let (_, header) = decoder.into_inner();
            (header, colortype, image)
        };

        assert_eq!(header.width(), width);
        assert_eq!(header.height(), height);
        assert_eq!(loaded_color, color);
        match loaded_image {
            DecodingResult::U8(ref data) if data.as_slice() == buffer => (),
            _ => panic!(
                "Loaded image buffer deviates from original! {:?}",
                loaded_image
            ),
        }
    }

    fn execute_roundtrip_with_subtype(
        buffer: &[u8],
        width: u32,
        height: u32,
        color: ColorType,
        subtype: PNMSubtype,
    ) {
        let mut encoded_buffer = Vec::new();

        {
            let mut encoder = PNMEncoder::new(&mut encoded_buffer).with_subtype(subtype);
            encoder
                .encode(buffer, width, height, color)
                .expect("Failed to encode the image buffer");
        }

        let (header, loaded_color, loaded_image) = {
            let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap();
            let colortype = decoder.colortype().expect("Failed to decode color type");
            let image = decoder.read_image().expect("Failed to decode the image");
            let (_, header) = decoder.into_inner();
            (header, colortype, image)
        };

        assert_eq!(header.width(), width);
        assert_eq!(header.height(), height);
        assert_eq!(header.subtype(), subtype);
        assert_eq!(loaded_color, color);
        match loaded_image {
            DecodingResult::U8(ref data) if data.as_slice() == buffer => (),
            _ => panic!(
                "Loaded image buffer deviates from original! {:?}",
                loaded_image
            ),
        }
    }

    fn execute_roundtrip_u16(buffer: &[u16], width: u32, height: u32, color: ColorType) {
        let mut encoded_buffer = Vec::new();

        {
            let mut encoder = PNMEncoder::new(&mut encoded_buffer);
            encoder
                .encode(buffer, width, height, color)
                .expect("Failed to encode the image buffer");
        }

        let (header, loaded_color, loaded_image) = {
            let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap();
            let colortype = decoder.colortype().expect("Failed to decode color type");
            let image = decoder.read_image().expect("Failed to decode the image");
            let (_, header) = decoder.into_inner();
            (header, colortype, image)
        };

        assert_eq!(header.width(), width);
        assert_eq!(header.height(), height);
        assert_eq!(loaded_color, color);
        match loaded_image {
            DecodingResult::U16(ref data) if data.as_slice() == buffer => (),
            _ => panic!(
                "Loaded image buffer deviates from original! {:?}",
                loaded_image
            ),
        }
    }

    #[test]
    fn roundtrip_rgb() {
        let buf: [u8; 27] = [
            0, 0, 0, 0, 0, 255, 0, 255, 0, 0, 255, 255, 255, 0, 0, 255, 0, 255, 255, 255, 0, 255,
            255, 255, 255, 255, 255,
        ];
        execute_roundtrip_default(&buf, 3, 3, ColorType::RGB(8));
        execute_roundtrip_with_subtype(&buf, 3, 3, ColorType::RGB(8), PNMSubtype::ArbitraryMap);
        execute_roundtrip_with_subtype(
            &buf,
            3,
            3,
            ColorType::RGB(8),
            PNMSubtype::Pixmap(SampleEncoding::Binary),
        );
        execute_roundtrip_with_subtype(
            &buf,
            3,
            3,
            ColorType::RGB(8),
            PNMSubtype::Pixmap(SampleEncoding::Ascii),
        );
    }

    #[test]
    fn roundtrip_u16() {
        let buf: [u16; 6] = [0, 1, 0xFFFF, 0x1234, 0x3412, 0xBEAF];

        execute_roundtrip_u16(&buf, 6, 1, ColorType::Gray(16));
    }
}
<commit_msg>3x9 pnm/mod.rs<commit_after>//! Decoding of netpbm image formats (pbm, pgm, ppm and pam).
//!
//! The formats pbm, pgm and ppm are fully supported. The pam decoder recognizes the tuple types
//! `BLACKANDWHITE`, `GRAYSCALE` and `RGB` and explicitely recognizes but rejects their `_ALPHA`
//! variants for now as alpha color types are unsupported.
use self::autobreak::AutoBreak;
pub use self::decoder::PNMDecoder;
pub use self::encoder::PNMEncoder;
use self::header::HeaderRecord;
pub use self::header::{ArbitraryHeader, ArbitraryTuplType, BitmapHeader, GraymapHeader,
                       PixmapHeader};
pub use self::header::{PNMHeader, PNMSubtype, SampleEncoding};

mod autobreak;
mod decoder;
mod encoder;
mod header;

#[cfg(test)]
mod tests {
    use super::*;
    use color::ColorType;
    use image::{DecodingResult, ImageDecoder};

    fn execute_roundtrip_default(buffer: &[u8], width: u32, height: u32, color: ColorType) {
        let mut encoded_buffer = Vec::new();

        {
            let mut encoder = PNMEncoder::new(&mut encoded_buffer);
            encoder
                .encode(buffer, width, height, color)
                .expect("Failed to encode the image buffer");
        }

        let (header, loaded_color, loaded_image) = {
            let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap();
            let colortype = decoder.colortype().expect("Failed to decode color type");
            let image = decoder.read_image().expect("Failed to decode the image");
            let (_, header) = decoder.into_inner();
            (header, colortype, image)
        };

        assert_eq!(header.width(), width);
        assert_eq!(header.height(), height);
        assert_eq!(loaded_color, color);
        match loaded_image {
            DecodingResult::U8(ref data) if data.as_slice() == buffer => (),
            _ => panic!(
                "Loaded image buffer deviates from original! {:?}",
                loaded_image
            ),
        }
    }

    fn execute_roundtrip_with_subtype(
        buffer: &[u8],
        width: u32,
        height: u32,
        color: ColorType,
        subtype: PNMSubtype,
    ) {
        let mut encoded_buffer = Vec::new();

        {
            let mut encoder = PNMEncoder::new(&mut encoded_buffer).with_subtype(subtype);
            encoder
                .encode(buffer, width, height, color)
                .expect("Failed to encode the image buffer");
        }

        let (header, loaded_color, loaded_image) = {
            let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap();
            let colortype = decoder.colortype().expect("Failed to decode color type");
            let image = decoder.read_image().expect("Failed to decode the image");
            let (_, header) = decoder.into_inner();
            (header, colortype, image)
        };

        assert_eq!(header.width(), width);
        assert_eq!(header.height(), height);
        assert_eq!(header.subtype(), subtype);
        assert_eq!(loaded_color, color);
        match loaded_image {
            DecodingResult::U8(ref data) if data.as_slice() == buffer => (),
            _ => panic!(
                "Loaded image buffer deviates from original! {:?}",
                loaded_image
            ),
        }
    }

    fn execute_roundtrip_u16(buffer: &[u16], width: u32, height: u32, color: ColorType) {
        let mut encoded_buffer = Vec::new();

        {
            let mut encoder = PNMEncoder::new(&mut encoded_buffer);
            encoder
                .encode(buffer, width, height, color)
                .expect("Failed to encode the image buffer");
        }

        let (header, loaded_color, loaded_image) = {
            let mut decoder = PNMDecoder::new(&encoded_buffer[..]).unwrap();
            let colortype = decoder.colortype().expect("Failed to decode color type");
            let image = decoder.read_image().expect("Failed to decode the image");
            let (_, header) = decoder.into_inner();
            (header, colortype, image)
        };

        assert_eq!(header.width(), width);
        assert_eq!(header.height(), height);
        assert_eq!(loaded_color, color);
        match loaded_image {
            DecodingResult::U16(ref data) if data.as_slice() == buffer => (),
            _ => panic!(
                "Loaded image buffer deviates from original! {:?}",
                loaded_image
            ),
        }
    }

    #[test]
    fn roundtrip_rgb() {
        #[cfg_attr(rustfmt, rustfmt_skip)]
        let buf: [u8; 27] = [
              0,   0,   0,
              0,   0, 255,
              0, 255,   0,
              0, 255, 255,
            255,   0,   0,
            255,   0, 255,
            255, 255,   0,
            255, 255, 255,
            255, 255, 255,
        ];
        execute_roundtrip_default(&buf, 3, 3, ColorType::RGB(8));
        execute_roundtrip_with_subtype(&buf, 3, 3, ColorType::RGB(8), PNMSubtype::ArbitraryMap);
        execute_roundtrip_with_subtype(
            &buf,
            3,
            3,
            ColorType::RGB(8),
            PNMSubtype::Pixmap(SampleEncoding::Binary),
        );
        execute_roundtrip_with_subtype(
            &buf,
            3,
            3,
            ColorType::RGB(8),
            PNMSubtype::Pixmap(SampleEncoding::Ascii),
        );
    }

    #[test]
    fn roundtrip_u16() {
        let buf: [u16; 6] = [0, 1, 0xFFFF, 0x1234, 0x3412, 0xBEAF];

        execute_roundtrip_u16(&buf, 6, 1, ColorType::Gray(16));
    }
}
<|endoftext|>


<commit_before>// pest. Smart PEGs in Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#[macro_export]
macro_rules! process {
    // handle patterns; increment $index automatically
    // _ : rule
    ( @pattern $slf:ident $index:ident ($block:expr) _ : $typ:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $index = $index + 1;

                    Some(($block, $index))
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) _ : $typ:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $index = $index + 1;

                    process!(@pattern $slf $index ($block) $( $tail )*)
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    // _
    ( @pattern $slf:ident $index:ident ($block:expr) _ ) => {
        {
            let $index = $index + 1;

            Some(($block, $index))
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) _, $( $tail:tt )* ) => {
        {
            let $index = $index + 1;

            process!(@pattern $slf $index ($block) $( $tail )*)
        }
    };
    // &name : rule
    ( @pattern $slf:ident $index:ident ($block:expr) &$head:ident : $typ:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $head = $slf.queue()[$index];
                    let $head = $slf.slice_input($head.start, $head.end);

                    let $index = $index + 1;

                    Some(($block, $index))
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) &$head:ident : $typ:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $head = $slf.queue()[$index];
                    let $head = $slf.slice_input($head.start, $head.end);

                    let $index = $index + 1;

                    process!(@pattern $slf $index ($block) $( $tail )*)
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    // &name
    ( @pattern $slf:ident $index:ident ($block:expr) &$head:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                let $head = token;
                let $head = $slf.slice_input($head.start, $head.end);

                let $index = $index + 1;

                Some(($block, $index))
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) &$head:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                let $head = token;
                let $head = $slf.slice_input($head.start, $head.end);

                let $index = $index + 1;

                process!(@pattern $slf $index ($block) $( $tail )*)
            } else {
                None
            }
        }
    };
    // @recurse
    ( @pattern $slf:ident $index:ident ($block:expr) @$head:ident ) => {
        {
            let ($head, index) = $slf.next($index);
            let $index = index;

            Some(($block, $index))
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) @$head:ident, $( $tail:tt )* ) => {
        {
            let ($head, index) = $slf.next($index);
            let $index = index;

            process!(@pattern $slf $index ($block) $( $tail )*)
        }
    };
    // name : rule
    ( @pattern $slf:ident $index:ident ($block:expr) $head:ident : $typ:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $head = $slf.queue()[$index];

                    let $index = $index + 1;

                    Some(($block, $index))
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) $head:ident : $typ:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $head = $slf.queue()[$index];

                    let $index = $index + 1;

                    process!(@pattern $slf $index ($block) $( $tail )*)
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    // name
    ( @pattern $slf:ident $index:ident ($block:expr) $head:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                let $head = token;

                let $index = $index + 1;

                Some(($block, $index))
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) $head:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                let $head = token;

                let $index = $index + 1;

                process!(@pattern $slf $index ($block) $( $tail )*)
            } else {
                None
            }
        }
    };

    // handle branches; panic if no branch matches
    ( @branches $slf:ident $index:ident ( $( $pattern:tt )* ) => $block:expr) => {
        if let Some(result) = process!(@pattern $slf $index ($block) $( $pattern )*) {
            result
        } else {
            panic!("no rules matched")
        }
    };
    ( @branches $slf:ident $index:ident ( $( $pattern:tt )* ) => $block:expr,) => {
        if let Some(result) = process!(@pattern $slf $index ($block) $( $pattern )*) {
            result
        } else {
            panic!("no rules matched")
        }
    };
    ( @branches $slf:ident $index:ident ( $( $pattern:tt )* ) => $block:expr, $( $tail:tt )* ) => {
        if let Some(result) = process!(@pattern $slf $index ($block) $( $pattern )*) {
            result
        } else {
            process!(@branches $slf $index $( $tail )*)
        }
    };

    ( (&$slf:ident) -> $typ:ty { $( $ts:tt )* } ) => {
        fn next(&$slf, index: usize) -> ($typ, usize) {
            process!(@branches $slf index $( $ts )*)
        }

        pub fn process(&self) -> $typ {
            self.next(0).0
        }
    }
}
<commit_msg>Added process documentation.<commit_after>// pest. Smart PEGs in Rust
// Copyright (C) 2016  Dragoș Tiselice
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/// A `macro` for pattern-matching queued `Token`s generated by a `Parser`. It generates a method
/// `process` on `&self` that processes the whole queue of `Token`s, reducing it to one single
/// result. The type of this result is specified at the beginning of the definition.
///
/// The `process` is populated with patterns and the way a pattern shall be dealt with. A pattern
/// is constructed from the following comma-separated items:
///
/// | Item       | What it does                   |
/// |------------|--------------------------------|
/// | `item`     | matches any `Token`            |
/// | `item: R`  | matches a `Token` of rule `R`  |
/// | `&item`    | captures a `Token`             |
/// | `&item: R` | captures a `Token` of rule `R` |
/// | `_`        | skips a `Token`                |
/// | `_: R`     | skips a `Token` of rule `R`    |
/// | `@item`    | recursively process child      |
///
/// # Examples
///
/// ### Nested letter
///
/// Let's consider the following grammar of nested letters:
///
/// ```no_run
/// # #[macro_use] extern crate pest;
/// # use pest::Parser;
/// # use pest::Token;
/// # use pest::Input;
/// # use pest::StringInput;
/// # fn main() {
/// # impl_rdp! {
/// # grammar! {
/// exp    = _{ paren | letter }      // exp is quiet since we already know what we're parsing
/// paren  =  { ["("] ~ exp ~ [")"] }
/// letter =  { ['a'..'z'] }
/// # }
/// # }
/// # unreachable!();
/// # }
/// ```
///
/// Defining the grammar paves way to a simple data-structre (an `enum`) that can be either a
/// `Paren` or a `Letter`.
///
/// ```no_run
/// #[derive(Debug, PartialEq)]
/// pub enum Exp {
///     Paren(Box<Exp>),
///     Letter(char)
/// }
/// ```
///
/// The processing phase needs to handle two cases: parens and letters. Letters are
/// straightforward captures:
///
/// ```ignore
/// (&letter: letter)
/// ```
///
/// Parens need to recursively process the next item in order to be stored inside of the `Paren`.
/// But before that, it needs to match a `paren` `Token` that gets ignored.
///
/// ```ignore
/// (_: paren, @exp)
/// ```
///
/// All together now:
///
/// ```
/// # #[macro_use] extern crate pest;
/// # use pest::Parser;
/// # use pest::Token;
/// # use pest::Input;
/// # use pest::StringInput;
/// # fn main() {
/// #[derive(Debug, PartialEq)]
/// pub enum Exp {
///     Paren(Box<Exp>),
///     Letter(char)
/// }
///
/// impl_rdp! {
///     grammar! {
///         exp    = _{ paren | letter }
///         paren  =  { ["("] ~ exp ~ [")"] }
///         letter =  { ['a'..'z'] }
///     }
///
///     process! {
///         (&self) -> Exp {
///             (&letter: letter) => {
///                 Exp::Letter(letter.chars().next().unwrap())
///             },
///             (_: paren, @exp) => {
///                 Exp::Paren(Box::new(exp))
///             }
///         }
///     }
/// }
///
/// let mut parser = Rdp::new(StringInput::new("((z))"));
///
/// assert!(parser.exp());
/// assert_eq!(parser.process(), Exp::Paren(Box::new(Exp::Paren(Box::new(Exp::Letter('z'))))));
/// # }
/// ```
#[macro_export]
macro_rules! process {
    // handle patterns; increment $index automatically
    // _ : rule
    ( @pattern $slf:ident $index:ident ($block:expr) _ : $typ:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $index = $index + 1;

                    Some(($block, $index))
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) _ : $typ:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $index = $index + 1;

                    process!(@pattern $slf $index ($block) $( $tail )*)
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    // _
    ( @pattern $slf:ident $index:ident ($block:expr) _ ) => {
        {
            let $index = $index + 1;

            Some(($block, $index))
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) _, $( $tail:tt )* ) => {
        {
            let $index = $index + 1;

            process!(@pattern $slf $index ($block) $( $tail )*)
        }
    };
    // &name : rule
    ( @pattern $slf:ident $index:ident ($block:expr) &$head:ident : $typ:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $head = $slf.queue()[$index];
                    let $head = $slf.slice_input($head.start, $head.end);

                    let $index = $index + 1;

                    Some(($block, $index))
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) &$head:ident : $typ:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $head = $slf.queue()[$index];
                    let $head = $slf.slice_input($head.start, $head.end);

                    let $index = $index + 1;

                    process!(@pattern $slf $index ($block) $( $tail )*)
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    // &name
    ( @pattern $slf:ident $index:ident ($block:expr) &$head:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                let $head = token;
                let $head = $slf.slice_input($head.start, $head.end);

                let $index = $index + 1;

                Some(($block, $index))
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) &$head:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                let $head = token;
                let $head = $slf.slice_input($head.start, $head.end);

                let $index = $index + 1;

                process!(@pattern $slf $index ($block) $( $tail )*)
            } else {
                None
            }
        }
    };
    // @recurse
    ( @pattern $slf:ident $index:ident ($block:expr) @$head:ident ) => {
        {
            let ($head, index) = $slf.next($index);
            let $index = index;

            Some(($block, $index))
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) @$head:ident, $( $tail:tt )* ) => {
        {
            let ($head, index) = $slf.next($index);
            let $index = index;

            process!(@pattern $slf $index ($block) $( $tail )*)
        }
    };
    // name : rule
    ( @pattern $slf:ident $index:ident ($block:expr) $head:ident : $typ:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $head = $slf.queue()[$index];

                    let $index = $index + 1;

                    Some(($block, $index))
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) $head:ident : $typ:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                if token.rule == Rule::$typ {
                    let $head = $slf.queue()[$index];

                    let $index = $index + 1;

                    process!(@pattern $slf $index ($block) $( $tail )*)
                } else {
                    None
                }
            } else {
                None
            }
        }
    };
    // name
    ( @pattern $slf:ident $index:ident ($block:expr) $head:ident ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                let $head = token;

                let $index = $index + 1;

                Some(($block, $index))
            } else {
                None
            }
        }
    };
    ( @pattern $slf:ident $index:ident ($block:expr) $head:ident, $( $tail:tt )* ) => {
        {
            if let Some(token) = $slf.queue().get($index) {
                let $head = token;

                let $index = $index + 1;

                process!(@pattern $slf $index ($block) $( $tail )*)
            } else {
                None
            }
        }
    };

    // handle branches; panic if no branch matches
    ( @branches $slf:ident $index:ident ( $( $pattern:tt )* ) => $block:expr) => {
        if let Some(result) = process!(@pattern $slf $index ($block) $( $pattern )*) {
            result
        } else {
            panic!("no rules matched")
        }
    };
    ( @branches $slf:ident $index:ident ( $( $pattern:tt )* ) => $block:expr,) => {
        if let Some(result) = process!(@pattern $slf $index ($block) $( $pattern )*) {
            result
        } else {
            panic!("no rules matched")
        }
    };
    ( @branches $slf:ident $index:ident ( $( $pattern:tt )* ) => $block:expr, $( $tail:tt )* ) => {
        if let Some(result) = process!(@pattern $slf $index ($block) $( $pattern )*) {
            result
        } else {
            process!(@branches $slf $index $( $tail )*)
        }
    };

    ( (&$slf:ident) -> $typ:ty { $( $ts:tt )* } ) => {
        fn next(&$slf, index: usize) -> ($typ, usize) {
            process!(@branches $slf index $( $ts )*)
        }

        pub fn process(&self) -> $typ {
            self.next(0).0
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;
use self::libc::*;

use low_level as ll;
use context::Context;
use error::Error;
use device::Device;
use kernel::Kernel;

use std::mem::{transmute, forget};
use std::ptr;
use std::iter::repeat;
use std::ffi::CString;

pub struct Program {
    pub id: ll::Program,
}

pub struct BuiltProgram {
    pub id: ll::Program,
}

impl Program {
    pub fn new_from_source<T: AsRef<str>>(ctx: Context,
                                           lines: &[T]) -> Result<Program, Error> {
        let num_lines = lines.len() as u32;
        let lengths: Vec<size_t> = lines.iter().map(|l| l.as_ref().len() as size_t).collect();
        let lines_raw: Vec<&str> = lines.iter().map(|l| l.as_ref()).collect();
        let id = unsafe {
            let mut err = 0;
            let id = ll::clCreateProgramWithSource(ctx.id,
                                                   num_lines,
                                                   transmute(&lines_raw[0]),
                                                   transmute(&lengths[0]),
                                                   &mut err);
            try!(Error::check(err));
            id
        };
        Ok(Program{id: id})
    }

    pub fn build(self: Self,
                devices: &[Device]) -> Result<BuiltProgram, Error> {
        let num_devices = devices.len() as u32;
        let device_ids: Vec<ll::DeviceID> = devices.iter().map(|d| d.id).collect();
        unsafe {
            match Error::check(ll::clBuildProgram(self.id,
                                                  num_devices,
                                                  &device_ids[0],
                                                  ptr::null(),
                                                  ptr::null(),
                                                  ptr::null_mut())) {
                Ok(()) => {},
                Err(Error::BuildProgramFailure(_)) => {
                    // need to get build log.  this is a little
                    // unpleasant.
                    let size_req = {
                        let mut tr: size_t = 0;
                        try!(Error::check(ll::clGetProgramBuildInfo(self.id,
                                                                    devices[0].id,
                                                                    0x1183,
                                                                    0,
                                                                    ptr::null_mut(),
                                                                    &mut tr)));
                        tr as usize
                    };
                    let mut buf: Vec<u8> = repeat(0).take(size_req).collect();
                    try!(Error::check(ll::clGetProgramBuildInfo(self.id,
                                                                devices[0].id,
                                                                0x1183,
                                                                size_req as size_t,
                                                                transmute(&mut buf[0]),
                                                                ptr::null_mut())));
                    return Err(Error::BuildProgramFailure(
                            String::from_utf8(buf)
                            .ok().expect("build error but build log not valid utf8?")));
                },
                Err(e) => {
                    return Err(e);
                },
            }
        };
        let id = self.id;
        forget(self);
        Ok(BuiltProgram{id: id})
    }
}

impl Drop for Program {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseProgram(self.id))
                .ok().expect("error releasing program");
        }
    }
}

impl Clone for Program {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainProgram(self.id))
                .ok().expect("error retaining program");
        }
        Program{ id: self.id }
    }
}

impl BuiltProgram {
    pub fn log(self: &Self,
               device: Device) -> Result<String, Error> {
        let size_req = unsafe {
            let mut tr: size_t = 0;
            try!(Error::check(ll::clGetProgramBuildInfo(self.id,
                                                        device.id,
                                                        0x1183,
                                                        0,
                                                        ptr::null_mut(),
                                                        &mut tr)));
            tr as usize
        };
        let mut buf: Vec<u8> = repeat(0).take(size_req).collect();
        unsafe {
            try!(Error::check(ll::clGetProgramBuildInfo(self.id,
                                                        device.id,
                                                        0x1183,
                                                        size_req as size_t,
                                                        transmute(&mut buf[0]),
                                                        ptr::null_mut())))
        };
        Ok(String::from_utf8(buf).ok().expect("CL returned invalid string"))
    }

    pub fn create_kernel<T: AsRef<str>>(self: &Self,
                                        name: T) -> Result<Kernel, Error> {
        let mut err: i32 = 0;
        let name_str = CString::new(name.as_ref())
                .ok().expect("kernel name is invalid c string");
        let id = unsafe {
            ll::clCreateKernel(self.id,
                               name_str.as_ptr(),
                               &mut err)
        };
        try!(Error::check(err));
        Ok(Kernel::new(id))
    }
}

impl Drop for BuiltProgram {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseProgram(self.id))
                .ok().expect("error releasing program");
        }
    }
}

impl Clone for BuiltProgram {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainProgram(self.id))
                .ok().expect("error retaining program");
        }
        BuiltProgram{ id: self.id }
    }
}

<commit_msg>use correct ffi cstrings<commit_after>extern crate libc;
use self::libc::*;

use low_level as ll;
use context::Context;
use error::Error;
use device::Device;
use kernel::Kernel;

use std::mem::{transmute, forget};
use std::ptr;
use std::iter::repeat;
use std::ffi::CString;

pub struct Program {
    pub id: ll::Program,
}

pub struct BuiltProgram {
    pub id: ll::Program,
}

impl Program {
    pub fn new_from_source<T: AsRef<str>>(ctx: Context,
                                           lines: &[T]) -> Result<Program, Error> {
        let num_lines = lines.len() as u32;
        let cstrings: Vec<CString> = lines.iter().map(|l| CString::new(l.as_ref()).unwrap()).collect();
        let lengths: Vec<size_t> = lines.iter().map(|l| l.as_ref().len() as size_t).collect();
        let lines_raw: Vec<*const libc::c_char> = cstrings.iter().map(|l| l.as_ptr()).collect();
        let id = unsafe {
            let mut err = 0;
            let id = ll::clCreateProgramWithSource(ctx.id,
                                                   num_lines,
                                                   transmute(&lines_raw[0]),
                                                   transmute(&lengths[0]),
                                                   &mut err);
            try!(Error::check(err));
            id
        };
        Ok(Program{id: id})
    }

    pub fn build(self: Self,
                devices: &[Device]) -> Result<BuiltProgram, Error> {
        let num_devices = devices.len() as u32;
        let device_ids: Vec<ll::DeviceID> = devices.iter().map(|d| d.id).collect();
        unsafe {
            match Error::check(ll::clBuildProgram(self.id,
                                                  num_devices,
                                                  &device_ids[0],
                                                  ptr::null(),
                                                  ptr::null(),
                                                  ptr::null_mut())) {
                Ok(()) => {},
                Err(Error::BuildProgramFailure(_)) => {
                    // need to get build log.  this is a little
                    // unpleasant.
                    let size_req = {
                        let mut tr: size_t = 0;
                        try!(Error::check(ll::clGetProgramBuildInfo(self.id,
                                                                    devices[0].id,
                                                                    0x1183,
                                                                    0,
                                                                    ptr::null_mut(),
                                                                    &mut tr)));
                        tr as usize
                    };
                    let mut buf: Vec<u8> = repeat(0).take(size_req).collect();
                    try!(Error::check(ll::clGetProgramBuildInfo(self.id,
                                                                devices[0].id,
                                                                0x1183,
                                                                size_req as size_t,
                                                                transmute(&mut buf[0]),
                                                                ptr::null_mut())));
                    return Err(Error::BuildProgramFailure(
                            String::from_utf8(buf)
                            .ok().expect("build error but build log not valid utf8?")));
                },
                Err(e) => {
                    return Err(e);
                },
            }
        };
        let id = self.id;
        forget(self);
        Ok(BuiltProgram{id: id})
    }
}

impl Drop for Program {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseProgram(self.id))
                .ok().expect("error releasing program");
        }
    }
}

impl Clone for Program {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainProgram(self.id))
                .ok().expect("error retaining program");
        }
        Program{ id: self.id }
    }
}

impl BuiltProgram {
    pub fn log(self: &Self,
               device: Device) -> Result<String, Error> {
        let size_req = unsafe {
            let mut tr: size_t = 0;
            try!(Error::check(ll::clGetProgramBuildInfo(self.id,
                                                        device.id,
                                                        0x1183,
                                                        0,
                                                        ptr::null_mut(),
                                                        &mut tr)));
            tr as usize
        };
        let mut buf: Vec<u8> = repeat(0).take(size_req).collect();
        unsafe {
            try!(Error::check(ll::clGetProgramBuildInfo(self.id,
                                                        device.id,
                                                        0x1183,
                                                        size_req as size_t,
                                                        transmute(&mut buf[0]),
                                                        ptr::null_mut())))
        };
        Ok(String::from_utf8(buf).ok().expect("CL returned invalid string"))
    }

    pub fn create_kernel<T: AsRef<str>>(self: &Self,
                                        name: T) -> Result<Kernel, Error> {
        let mut err: i32 = 0;
        let name_str = CString::new(name.as_ref())
                .ok().expect("kernel name is invalid c string");
        let id = unsafe {
            ll::clCreateKernel(self.id,
                               name_str.as_ptr(),
                               &mut err)
        };
        try!(Error::check(err));
        Ok(Kernel::new(id))
    }
}

impl Drop for BuiltProgram {
    fn drop(self: &mut Self) -> () {
        unsafe {
            Error::check(ll::clReleaseProgram(self.id))
                .ok().expect("error releasing program");
        }
    }
}

impl Clone for BuiltProgram {
    fn clone(self: &Self) -> Self {
        unsafe {
            Error::check(ll::clRetainProgram(self.id))
                .ok().expect("error retaining program");
        }
        BuiltProgram{ id: self.id }
    }
}

<|endoftext|>


<commit_before>use crate::tokenizer;
use crate::{
    constants::*,
    token_collector::{Style, StyledToken, TokenCollector},
};
use diffus::{
    edit::{self, collection},
    Diffable,
};

/// If more than this part of either adds or moves is highlighted,
/// we consider it to be a replacement rather than a move, and skip
/// highlighting it.
const MAX_HIGHLIGHT_PERCENTAGE: usize = 30;

/// If it's only this few highlights, we'll just highligh anyway without
/// checking the `MAX_HIGHLIGHT_PERCENTAGE`.
const OK_HIGHLIGHT_COUNT: usize = 5;

/// Format old and new lines in OLD and NEW colors.
///
/// No intra-line refinement.
#[must_use]
fn simple_format(old_text: &str, new_text: &str) -> Vec<String> {
    let mut lines: Vec<String> = Vec::new();

    for old_line in old_text.lines() {
        lines.push(format!("{}-{}{}", OLD, old_line, NORMAL));
    }
    if (!old_text.is_empty()) && !old_text.ends_with('\n') {
        lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    for add_line in new_text.lines() {
        lines.push(format!("{}+{}{}", NEW, add_line, NORMAL))
    }
    if (!new_text.is_empty()) && !new_text.ends_with('\n') {
        lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    return lines;
}

/// Returns a vector of ANSI highlighted lines
#[must_use]
pub fn format(old_text: &str, new_text: &str) -> Vec<String> {
    if new_text.is_empty() {
        return simple_format(old_text, new_text);
    }

    if old_text.is_empty() {
        return simple_format(old_text, new_text);
    }

    // Find diffs between adds and removals
    let mut old_collector = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
    let mut new_collector = TokenCollector::create(StyledToken::new("+".to_string(), Style::New));
    let mut old_highlight_count = 0;
    let mut new_highlight_count = 0;

    // Tokenize adds and removes before diffing them
    let tokenized_old = tokenizer::tokenize(old_text);
    let tokenized_new = tokenizer::tokenize(new_text);

    let diff = tokenized_old.diff(&tokenized_new);
    match diff {
        edit::Edit::Copy(unchanged) => {
            for token in unchanged {
                old_collector.push(StyledToken::new(token.clone(), Style::Old));
                new_collector.push(StyledToken::new(token.clone(), Style::New));
            }
        }
        edit::Edit::Change(diff) => {
            diff.into_iter()
                .map(|edit| {
                    match edit {
                        collection::Edit::Copy(token) => {
                            old_collector.push(StyledToken::new(token.clone(), Style::Old));
                            new_collector.push(StyledToken::new(token.clone(), Style::New));
                        }
                        collection::Edit::Insert(token) => {
                            new_highlight_count += 1;
                            if token == "\n" {
                                // Make sure the highlighted linefeed is visible
                                new_collector
                                    .push(StyledToken::new("⏎".to_string(), Style::NewInverse));
                            }
                            new_collector.push(StyledToken::new(token.clone(), Style::NewInverse));
                        }
                        collection::Edit::Remove(token) => {
                            old_highlight_count += 1;

                            if token == "\n" {
                                // Make sure the highlighted linefeed is visible
                                old_collector
                                    .push(StyledToken::new("⏎".to_string(), Style::OldInverse));
                            }
                            old_collector.push(StyledToken::new(token.clone(), Style::OldInverse));
                        }
                        collection::Edit::Change(_) => unimplemented!("Not implemented, help!"),
                    };
                })
                .for_each(drop);
        }
    }

    let highlight_count = old_highlight_count + new_highlight_count;
    let token_count = tokenized_old.len() + tokenized_new.len();

    // FIXME: Maybe for this check count how many characters were highlighted
    // rather than how many tokens? Heuristics are difficult...
    if highlight_count <= OK_HIGHLIGHT_COUNT {
        // Few enough highlights, Just do it (tm)
    } else if (100 * highlight_count) / token_count > MAX_HIGHLIGHT_PERCENTAGE {
        return simple_format(old_text, new_text);
    }

    let highlighted_old_text = old_collector.render();
    let highlighted_new_text = new_collector.render();
    return to_lines(&highlighted_old_text, &highlighted_new_text);
}

#[must_use]
fn to_lines(old: &str, new: &str) -> Vec<String> {
    let mut lines: Vec<String> = Vec::new();
    for highlighted_old_line in old.lines() {
        lines.push(highlighted_old_line.to_string());
    }
    if (!old.is_empty()) && !old.ends_with('\n') {
        lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    for highlighted_new_line in new.lines() {
        lines.push(highlighted_new_line.to_string());
    }
    if (!new.is_empty()) && !new.ends_with('\n') {
        lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    return lines;
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_simple_format_adds_and_removes() {
        let empty: Vec<String> = Vec::new();
        assert_eq!(simple_format(&"".to_string(), &"".to_string()), empty);

        // Test adds-only
        assert_eq!(
            simple_format(&"".to_string(), &"a\n".to_string()),
            ["".to_string() + NEW + "+a" + NORMAL]
        );
        assert_eq!(
            simple_format(&"".to_string(), &"a\nb\n".to_string()),
            [
                "".to_string() + NEW + "+a" + NORMAL,
                "".to_string() + NEW + "+b" + NORMAL,
            ]
        );

        // Test removes-only
        assert_eq!(
            simple_format(&"a\n".to_string(), &"".to_string()),
            ["".to_string() + OLD + "-a" + NORMAL]
        );
        assert_eq!(
            simple_format(&"a\nb\n".to_string(), &"".to_string()),
            [
                "".to_string() + OLD + "-a" + NORMAL,
                "".to_string() + OLD + "-b" + NORMAL,
            ]
        );
    }

    #[test]
    fn test_quote_change() {
        let result = format(&"<quotes>\n".to_string(), &"[quotes]\n".to_string());
        assert_eq!(
            result,
            [
                format!(
                    "{}-{}<{}quotes{}>{}",
                    OLD, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
                format!(
                    "{}+{}[{}quotes{}]{}",
                    NEW, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
            ]
        )
    }
}
<commit_msg>Performance improvements<commit_after>use crate::tokenizer;
use crate::{
    constants::*,
    token_collector::{Style, StyledToken, TokenCollector},
};
use diffus::{
    edit::{self, collection},
    Diffable,
};

/// If more than this part of either adds or moves is highlighted,
/// we consider it to be a replacement rather than a move, and skip
/// highlighting it.
const MAX_HIGHLIGHT_PERCENTAGE: usize = 30;

/// If it's only this few highlights, we'll just highligh anyway without
/// checking the `MAX_HIGHLIGHT_PERCENTAGE`.
const OK_HIGHLIGHT_COUNT: usize = 5;

/// Format old and new lines in OLD and NEW colors.
///
/// No intra-line refinement.
#[must_use]
fn simple_format(old_text: &str, new_text: &str) -> Vec<String> {
    let mut lines: Vec<String> = Vec::new();

    for old_line in old_text.lines() {
        lines.push(format!("{}-{}{}", OLD, old_line, NORMAL));
    }
    if (!old_text.is_empty()) && !old_text.ends_with('\n') {
        lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    for add_line in new_text.lines() {
        lines.push(format!("{}+{}{}", NEW, add_line, NORMAL))
    }
    if (!new_text.is_empty()) && !new_text.ends_with('\n') {
        lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    return lines;
}

/// Returns a vector of ANSI highlighted lines
#[must_use]
pub fn format(old_text: &str, new_text: &str) -> Vec<String> {
    if new_text.is_empty() {
        return simple_format(old_text, new_text);
    }

    if old_text.is_empty() {
        return simple_format(old_text, new_text);
    }

    // These two conditions make us about 30% faster. The idea is that if the
    // texts are too unequal in length, we're unlikely to highlight just small
    // parts of them.
    if (100 * old_text.len()) / (old_text.len() + new_text.len()) < MAX_HIGHLIGHT_PERCENTAGE {
        return simple_format(old_text, new_text);
    }
    if (100 * new_text.len()) / (old_text.len() + new_text.len()) < MAX_HIGHLIGHT_PERCENTAGE {
        return simple_format(old_text, new_text);
    }

    // Find diffs between adds and removals
    let mut old_collector = TokenCollector::create(StyledToken::new("-".to_string(), Style::Old));
    let mut new_collector = TokenCollector::create(StyledToken::new("+".to_string(), Style::New));
    let mut old_highlight_count = 0;
    let mut new_highlight_count = 0;

    // Tokenize adds and removes before diffing them
    let tokenized_old = tokenizer::tokenize(old_text);
    let tokenized_new = tokenizer::tokenize(new_text);

    let diff = tokenized_old.diff(&tokenized_new);
    match diff {
        edit::Edit::Copy(unchanged) => {
            for token in unchanged {
                old_collector.push(StyledToken::new(token.clone(), Style::Old));
                new_collector.push(StyledToken::new(token.clone(), Style::New));
            }
        }
        edit::Edit::Change(diff) => {
            diff.into_iter()
                .map(|edit| {
                    match edit {
                        collection::Edit::Copy(token) => {
                            old_collector.push(StyledToken::new(token.clone(), Style::Old));
                            new_collector.push(StyledToken::new(token.clone(), Style::New));
                        }
                        collection::Edit::Insert(token) => {
                            new_highlight_count += 1;
                            if token == "\n" {
                                // Make sure the highlighted linefeed is visible
                                new_collector
                                    .push(StyledToken::new("⏎".to_string(), Style::NewInverse));
                            }
                            new_collector.push(StyledToken::new(token.clone(), Style::NewInverse));
                        }
                        collection::Edit::Remove(token) => {
                            old_highlight_count += 1;

                            if token == "\n" {
                                // Make sure the highlighted linefeed is visible
                                old_collector
                                    .push(StyledToken::new("⏎".to_string(), Style::OldInverse));
                            }
                            old_collector.push(StyledToken::new(token.clone(), Style::OldInverse));
                        }
                        collection::Edit::Change(_) => unimplemented!("Not implemented, help!"),
                    };
                })
                .for_each(drop);
        }
    }

    let highlight_count = old_highlight_count + new_highlight_count;
    let token_count = tokenized_old.len() + tokenized_new.len();

    // FIXME: Maybe for this check count how many characters were highlighted
    // rather than how many tokens? Heuristics are difficult...
    if highlight_count <= OK_HIGHLIGHT_COUNT {
        // Few enough highlights, Just do it (tm)
    } else if (100 * highlight_count) / token_count > MAX_HIGHLIGHT_PERCENTAGE {
        return simple_format(old_text, new_text);
    }

    let highlighted_old_text = old_collector.render();
    let highlighted_new_text = new_collector.render();
    return to_lines(&highlighted_old_text, &highlighted_new_text);
}

#[must_use]
fn to_lines(old: &str, new: &str) -> Vec<String> {
    let mut lines: Vec<String> = Vec::new();
    for highlighted_old_line in old.lines() {
        lines.push(highlighted_old_line.to_string());
    }
    if (!old.is_empty()) && !old.ends_with('\n') {
        lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    for highlighted_new_line in new.lines() {
        lines.push(highlighted_new_line.to_string());
    }
    if (!new.is_empty()) && !new.ends_with('\n') {
        lines.push(format!(
            "{}{}{}",
            NO_EOF_NEWLINE_COLOR, NO_EOF_NEWLINE_MARKER, NORMAL
        ));
    }

    return lines;
}

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

    #[cfg(test)]
    use pretty_assertions::assert_eq;

    #[test]
    fn test_simple_format_adds_and_removes() {
        let empty: Vec<String> = Vec::new();
        assert_eq!(simple_format(&"".to_string(), &"".to_string()), empty);

        // Test adds-only
        assert_eq!(
            simple_format(&"".to_string(), &"a\n".to_string()),
            ["".to_string() + NEW + "+a" + NORMAL]
        );
        assert_eq!(
            simple_format(&"".to_string(), &"a\nb\n".to_string()),
            [
                "".to_string() + NEW + "+a" + NORMAL,
                "".to_string() + NEW + "+b" + NORMAL,
            ]
        );

        // Test removes-only
        assert_eq!(
            simple_format(&"a\n".to_string(), &"".to_string()),
            ["".to_string() + OLD + "-a" + NORMAL]
        );
        assert_eq!(
            simple_format(&"a\nb\n".to_string(), &"".to_string()),
            [
                "".to_string() + OLD + "-a" + NORMAL,
                "".to_string() + OLD + "-b" + NORMAL,
            ]
        );
    }

    #[test]
    fn test_quote_change() {
        let result = format(&"<quotes>\n".to_string(), &"[quotes]\n".to_string());
        assert_eq!(
            result,
            [
                format!(
                    "{}-{}<{}quotes{}>{}",
                    OLD, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
                format!(
                    "{}+{}[{}quotes{}]{}",
                    NEW, INVERSE_VIDEO, NOT_INVERSE_VIDEO, INVERSE_VIDEO, NORMAL
                ),
            ]
        )
    }
}
<|endoftext|>


<commit_before>#[cfg(feature = "reqwest")]
extern crate reqwest;

use Value;
use error::{Error, RequestErrorKind};
use utils::escape_xml;
use transport::Transport;
use parser::parse_response;

use std::io::{self, Write};
use std::collections::BTreeMap;

/// A request to call a procedure.
#[derive(Clone, Debug)]
pub struct Request<'a> {
    name: &'a str,
    args: Vec<Value>,
}

impl<'a> Request<'a> {
    /// Creates a new request to call a function named `name`.
    ///
    /// By default, no arguments are passed. Use the `arg` method to append arguments.
    pub fn new(name: &'a str) -> Self {
        Request {
            name,
            args: Vec::new(),
        }
    }

    /// Appends an argument to be passed to the current list of arguments.
    pub fn arg<T: Into<Value>>(mut self, value: T) -> Self {
        self.args.push(value.into());
        self
    }

    /// Performs the request using a [`Transport`].
    ///
    /// # Errors
    ///
    /// Any errors that occur while sending the request using the [`Transport`] will be returned to
    /// the caller. Additionally, if the response is malformed (invalid XML), or indicates that the
    /// method call failed, an error will also be returned.
    ///
    /// [`Transport`]: trait.Transport.html
    pub fn call<T: Transport>(&self, transport: T) -> Result<Value, Error> {
        let mut reader = transport.transmit(self)
            .map_err(RequestErrorKind::TransportError)?;

        let response = parse_response(&mut reader).map_err(RequestErrorKind::ParseError)?;

        let value = response.map_err(RequestErrorKind::Fault)?;
        Ok(value)
    }

    /// Performs the request on a URL.
    ///
    /// You can pass a `&str` or an already parsed reqwest URL.
    ///
    /// This is a convenience method that will internally create a new `reqwest::Client` and send an
    /// HTTP POST request to the given URL. If you only use this method to perform requests, you
    /// don't need to depend on `reqwest` yourself.
    ///
    /// This method is only available when the `reqwest` feature is enabled (this is the default).
    ///
    /// # Errors
    ///
    /// Since this is just a convenience wrapper around [`Request::call`], the same error conditions
    /// apply.
    ///
    /// Any reqwest errors will be propagated to the caller.
    ///
    /// [`Request::call`]: #method.call
    /// [`Transport`]: trait.Transport.html
    #[cfg(feature = "reqwest")]
    pub fn call_url<U: reqwest::IntoUrl>(&self, url: U) -> Result<Value, Error> {
        // While we could implement `Transport` for `T: IntoUrl`, such an impl might not be
        // completely obvious (as it applies to `&str), so I've added this method instead.
        // Might want to reconsider if someone has an objection.
        self.call(reqwest::Client::new().post(url))
    }

    /// Formats this `Request` as a UTF-8 encoded XML document.
    ///
    /// # Errors
    ///
    /// Any errors reported by the writer will be propagated to the caller. If the writer never
    /// returns an error, neither will this method.
    pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        write!(fmt, r#"<?xml version="1.0" encoding="utf-8"?>"#)?;
        write!(fmt, r#"<methodCall>"#)?;
        write!(fmt, r#"    <methodName>{}</methodName>"#, escape_xml(&self.name))?;
        write!(fmt, r#"    <params>"#)?;
        for value in &self.args {
            write!(fmt, r#"        <param>"#)?;
            value.write_as_xml(fmt)?;
            write!(fmt, r#"        </param>"#)?;
        }
        write!(fmt, r#"    </params>"#)?;
        write!(fmt, r#"</methodCall>"#)?;
        Ok(())
    }

    /// Serialize this `Request` into an XML-RPC struct that can be passed to
    /// the [`system.multicall`](https://mirrors.talideon.com/articles/multicall.html)
    /// XML-RPC method, specifically a struct with two fields:
    ///
    /// * `methodName`: the request name
    /// * `params`: the request arguments
    pub fn into_multicall_struct(self) -> Value {
        let mut multicall_struct: BTreeMap<String, Value> = BTreeMap::new();

        multicall_struct.insert("methodName".into(), self.name.into());
        multicall_struct.insert("params".into(), Value::Array(self.args));

        Value::Struct(multicall_struct)
    }
}

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

    #[test]
    fn escapes_method_names() {
        let mut output: Vec<u8> = Vec::new();
        let req = Request::new("x<&x");

        req.write_as_xml(&mut output).unwrap();
        assert!(
            str::from_utf8(&output)
            .unwrap()
            .contains("<methodName>x<&x</methodName>"));
    }
}
<commit_msg>Fix typo<commit_after>#[cfg(feature = "reqwest")]
extern crate reqwest;

use Value;
use error::{Error, RequestErrorKind};
use utils::escape_xml;
use transport::Transport;
use parser::parse_response;

use std::io::{self, Write};
use std::collections::BTreeMap;

/// A request to call a procedure.
#[derive(Clone, Debug)]
pub struct Request<'a> {
    name: &'a str,
    args: Vec<Value>,
}

impl<'a> Request<'a> {
    /// Creates a new request to call a function named `name`.
    ///
    /// By default, no arguments are passed. Use the `arg` method to append arguments.
    pub fn new(name: &'a str) -> Self {
        Request {
            name,
            args: Vec::new(),
        }
    }

    /// Appends an argument to be passed to the current list of arguments.
    pub fn arg<T: Into<Value>>(mut self, value: T) -> Self {
        self.args.push(value.into());
        self
    }

    /// Performs the request using a [`Transport`].
    ///
    /// # Errors
    ///
    /// Any errors that occur while sending the request using the [`Transport`] will be returned to
    /// the caller. Additionally, if the response is malformed (invalid XML), or indicates that the
    /// method call failed, an error will also be returned.
    ///
    /// [`Transport`]: trait.Transport.html
    pub fn call<T: Transport>(&self, transport: T) -> Result<Value, Error> {
        let mut reader = transport.transmit(self)
            .map_err(RequestErrorKind::TransportError)?;

        let response = parse_response(&mut reader).map_err(RequestErrorKind::ParseError)?;

        let value = response.map_err(RequestErrorKind::Fault)?;
        Ok(value)
    }

    /// Performs the request on a URL.
    ///
    /// You can pass a `&str` or an already parsed reqwest URL.
    ///
    /// This is a convenience method that will internally create a new `reqwest::Client` and send an
    /// HTTP POST request to the given URL. If you only use this method to perform requests, you
    /// don't need to depend on `reqwest` yourself.
    ///
    /// This method is only available when the `reqwest` feature is enabled (this is the default).
    ///
    /// # Errors
    ///
    /// Since this is just a convenience wrapper around [`Request::call`], the same error conditions
    /// apply.
    ///
    /// Any reqwest errors will be propagated to the caller.
    ///
    /// [`Request::call`]: #method.call
    /// [`Transport`]: trait.Transport.html
    #[cfg(feature = "reqwest")]
    pub fn call_url<U: reqwest::IntoUrl>(&self, url: U) -> Result<Value, Error> {
        // While we could implement `Transport` for `T: IntoUrl`, such an impl might not be
        // completely obvious (as it applies to `&str`), so I've added this method instead.
        // Might want to reconsider if someone has an objection.
        self.call(reqwest::Client::new().post(url))
    }

    /// Formats this `Request` as a UTF-8 encoded XML document.
    ///
    /// # Errors
    ///
    /// Any errors reported by the writer will be propagated to the caller. If the writer never
    /// returns an error, neither will this method.
    pub fn write_as_xml<W: Write>(&self, fmt: &mut W) -> io::Result<()> {
        write!(fmt, r#"<?xml version="1.0" encoding="utf-8"?>"#)?;
        write!(fmt, r#"<methodCall>"#)?;
        write!(fmt, r#"    <methodName>{}</methodName>"#, escape_xml(&self.name))?;
        write!(fmt, r#"    <params>"#)?;
        for value in &self.args {
            write!(fmt, r#"        <param>"#)?;
            value.write_as_xml(fmt)?;
            write!(fmt, r#"        </param>"#)?;
        }
        write!(fmt, r#"    </params>"#)?;
        write!(fmt, r#"</methodCall>"#)?;
        Ok(())
    }

    /// Serialize this `Request` into an XML-RPC struct that can be passed to
    /// the [`system.multicall`](https://mirrors.talideon.com/articles/multicall.html)
    /// XML-RPC method, specifically a struct with two fields:
    ///
    /// * `methodName`: the request name
    /// * `params`: the request arguments
    pub fn into_multicall_struct(self) -> Value {
        let mut multicall_struct: BTreeMap<String, Value> = BTreeMap::new();

        multicall_struct.insert("methodName".into(), self.name.into());
        multicall_struct.insert("params".into(), Value::Array(self.args));

        Value::Struct(multicall_struct)
    }
}

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

    #[test]
    fn escapes_method_names() {
        let mut output: Vec<u8> = Vec::new();
        let req = Request::new("x<&x");

        req.write_as_xml(&mut output).unwrap();
        assert!(
            str::from_utf8(&output)
            .unwrap()
            .contains("<methodName>x<&x</methodName>"));
    }
}
<|endoftext|>