<commit_before>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

#![allow(unused_variables)]
#![allow(unused_must_use)]

include!("bindings.rs");

use std::os::raw::c_char;
use std::io::Write;

#[derive(PartialEq)]
enum PrintState {
    OUT,
    IN,
    DISPLAY
}

fn print_ptr_rec<W: Write>(port: &mut W, p: ptr, state: PrintState) {
    let x = p as u32;
    if  (x & fx_mask) == fx_tag {
        write!(port, "{}", (x as i32) >> fx_shift);
    } else if x == bool_f {
        write!(port, "#f");
    } else if x == bool_t {
        write!(port, "#t");
    } else if x == list_nil {
        write!(port, "()");
    } else if x == eof_obj {
        write!(port, "#!eof");
    } else if (x & char_mask) == char_tag {
        let c = std::char::from_u32(x >> char_shift).
            expect("a char");
        if state == PrintState::DISPLAY {
            write!(port, "{}", c);
        } else {
            if      c == '\t' { write!(port, "#\\tab"); }
            else if c == '\n' { write!(port, "#\\newline"); }
            else if c == '\r' { write!(port, "#\\return"); }
            else if c == ' '  { write!(port, "#\\space"); }
            else              { write!(port, "#\\{}", c); }
        }
    } else if (x & obj_mask) == pair_tag {
        if state == PrintState::OUT { write!(port, "("); }
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let car = cell.car;
        print_ptr_rec(port, car, PrintState::OUT);
        let cdr = cell.cdr;
        if cdr != list_nil {
            if (cdr & obj_mask) != pair_tag {
                write!(port, " . ");
                print_ptr_rec(port, cdr, PrintState::OUT);
            } else {
                write!(port, " ");
                print_ptr_rec(port, cdr, PrintState::IN);
            }
        }
        if state == PrintState::OUT { write!(port, ")"); }
    } else if (x & obj_mask) == vector_tag {
        write!(port, "#(");
        unsafe {
        let p = &*((x-vector_tag) as *const vector);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            if i > 0 { write!(port, " "); }
            print_ptr_rec(port,
                *((p.buf.as_ptr()).offset(i as isize)),
                PrintState::OUT)
        }}
        write!(port, ")");
    } else if (x & obj_mask) == string_tag {
        if state == PrintState::OUT { write!(port, "\""); }
        unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            let c = std::char::from_u32(*((p.buf.as_ptr()).offset(i as isize)) as u32)
                .expect("char");
            if c == '"'       { write!(port, "\\\""); }
            else if c == '\\' { write!(port, "\\\\"); }
            else              { write!(port, "{}", c); }
        }}
        if state == PrintState::OUT { write!(port, "\""); }
    } else if (x & obj_mask) == symbol_tag {
        print_ptr_rec(port, (x - symbol_tag) | string_tag, PrintState::IN);
    } else if (x & obj_mask) == closure_tag {
        write!(port, "#<procedure>");
    } else {
        write!(port, "#<unknown 0x{:x}>", x);
    }
}
fn print_ptr(x: ptr) {
    print_ptr_rec(&mut std::io::stdout(), x, PrintState::OUT);
    println!("");
}

#[no_mangle]
pub extern "C" fn ik_log(msg: ptr) {
}
#[no_mangle]
pub extern "C" fn ik_error(x: ptr) {
    std::process::exit(0);
}
#[no_mangle]
pub extern "C" fn s_write(fd: ptr, str: ptr, len: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_open_write(fname: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_fflush(fd: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn scheme_write(fd: ptr, x: ptr, opt: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_open_read(fname: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_read_char(fd: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_close(fd: ptr) -> ptr {
    0
}

#[no_mangle]
pub extern "C" fn heap_alloc(mem: *mut memory, stack: *mut c_char, size: usize) -> *mut c_char {
    let heap_next = unsafe { (*mem).heap_next };
    let heap_new = unsafe { heap_next.offset(size as isize) };
    if heap_new >= unsafe { (*mem).heap_top } {
        eprintln!("Exception: overflow");
        std::process::exit(0);
    }
    unsafe {(*mem).heap_next = heap_new};
    return heap_next;
}

fn allocate_protected_space(size: usize) -> *mut c_char {
    let mut v = Vec::with_capacity(size);
    let ptr = v.as_mut_ptr();
    std::mem::forget(v);
    ptr
}

fn deallocate_protected_space(p: *mut c_char, size: usize) {
    unsafe { std::mem::drop(Vec::from_raw_parts(p, 0, size)) };
}

fn main() {
    let stack_size = 16 * 4096;
    let heap_size = 4 * 16 * 4096;
    let global_size = 16 * 4096;
    let scratch_size = 16 * 4096;

    let stack_top = allocate_protected_space(stack_size);
    let stack_base = unsafe { stack_top.offset(stack_size as isize) };

    let heap = allocate_protected_space(heap_size);
    let global = allocate_protected_space(global_size);
    let scratch = allocate_protected_space(scratch_size);

    let uninit = 0 as (*mut std::os::raw::c_void);

    let mut ctxt = context {
        eax : uninit,
        ebx : uninit,
        ecx : uninit,
        edx : uninit,
        esi : uninit,
        edi : uninit,
        ebp : uninit,
        esp : uninit,
    };

    let heap_top = unsafe { heap.offset((heap_size as isize)/2) };
    let mut mem = memory {
        heap_next : heap,
        global_next : global,
        heap_base : heap,
        heap_top : heap_top,
        heap_base_alt : heap_top,
        heap_top_alt : unsafe { heap.offset(heap_size as isize) },
        global_base : global,
        stack_base : stack_base,
        scratch_base : scratch,
        edi : 0
    };

    print_ptr(unsafe {
        scheme_entry(&mut ctxt, stack_base, &mut mem)
    });

    deallocate_protected_space(stack_top, stack_size);
    deallocate_protected_space(heap, stack_size);
}
<commit_msg>implement ik_log<commit_after>#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

#![allow(unused_variables)]
#![allow(unused_must_use)]

include!("bindings.rs");

use std::os::raw::c_char;
use std::io::Write;

#[derive(PartialEq)]
enum PrintState {
    OUT,
    IN,
    DISPLAY
}

fn print_ptr_rec<W: Write>(port: &mut W, p: ptr, state: PrintState) {
    let x = p as u32;
    if  (x & fx_mask) == fx_tag {
        write!(port, "{}", (x as i32) >> fx_shift);
    } else if x == bool_f {
        write!(port, "#f");
    } else if x == bool_t {
        write!(port, "#t");
    } else if x == list_nil {
        write!(port, "()");
    } else if x == eof_obj {
        write!(port, "#!eof");
    } else if (x & char_mask) == char_tag {
        let c = std::char::from_u32(x >> char_shift).
            expect("a char");
        if state == PrintState::DISPLAY {
            write!(port, "{}", c);
        } else {
            if      c == '\t' { write!(port, "#\\tab"); }
            else if c == '\n' { write!(port, "#\\newline"); }
            else if c == '\r' { write!(port, "#\\return"); }
            else if c == ' '  { write!(port, "#\\space"); }
            else              { write!(port, "#\\{}", c); }
        }
    } else if (x & obj_mask) == pair_tag {
        if state == PrintState::OUT { write!(port, "("); }
        let cell = unsafe { *((x-pair_tag) as *const cell) };
        let car = cell.car;
        print_ptr_rec(port, car, PrintState::OUT);
        let cdr = cell.cdr;
        if cdr != list_nil {
            if (cdr & obj_mask) != pair_tag {
                write!(port, " . ");
                print_ptr_rec(port, cdr, PrintState::OUT);
            } else {
                write!(port, " ");
                print_ptr_rec(port, cdr, PrintState::IN);
            }
        }
        if state == PrintState::OUT { write!(port, ")"); }
    } else if (x & obj_mask) == vector_tag {
        write!(port, "#(");
        unsafe {
        let p = &*((x-vector_tag) as *const vector);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            if i > 0 { write!(port, " "); }
            print_ptr_rec(port,
                *((p.buf.as_ptr()).offset(i as isize)),
                PrintState::OUT)
        }}
        write!(port, ")");
    } else if (x & obj_mask) == string_tag {
        if state == PrintState::OUT { write!(port, "\""); }
        unsafe {
        let p = &*((x-string_tag) as *const string);
        let n = (p.length as i32) >> fx_shift;
        for i in 0..n {
            let c = std::char::from_u32(*((p.buf.as_ptr()).offset(i as isize)) as u32)
                .expect("char");
            if c == '"'       { write!(port, "\\\""); }
            else if c == '\\' { write!(port, "\\\\"); }
            else              { write!(port, "{}", c); }
        }}
        if state == PrintState::OUT { write!(port, "\""); }
    } else if (x & obj_mask) == symbol_tag {
        print_ptr_rec(port, (x - symbol_tag) | string_tag, PrintState::IN);
    } else if (x & obj_mask) == closure_tag {
        write!(port, "#<procedure>");
    } else {
        write!(port, "#<unknown 0x{:x}>", x);
    }
}
fn print_ptr(x: ptr) {
    print_ptr_rec(&mut std::io::stdout(), x, PrintState::OUT);
    println!("");
}

#[no_mangle]
pub extern "C" fn ik_log(msg: ptr) -> ptr {
    eprint!("log: ");
    print_ptr_rec(&mut std::io::stderr(), msg, PrintState::IN);
    eprintln!("");
    0
}
#[no_mangle]
pub extern "C" fn ik_error(x: ptr) {
    std::process::exit(0);
}
#[no_mangle]
pub extern "C" fn s_write(fd: ptr, str: ptr, len: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_open_write(fname: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_fflush(fd: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn scheme_write(fd: ptr, x: ptr, opt: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_open_read(fname: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_read_char(fd: ptr) -> ptr {
    0
}
#[no_mangle]
pub extern "C" fn s_close(fd: ptr) -> ptr {
    0
}

#[no_mangle]
pub extern "C" fn heap_alloc(mem: *mut memory, stack: *mut c_char, size: usize) -> *mut c_char {
    let heap_next = unsafe { (*mem).heap_next };
    let heap_new = unsafe { heap_next.offset(size as isize) };
    if heap_new >= unsafe { (*mem).heap_top } {
        eprintln!("Exception: overflow");
        std::process::exit(0);
    }
    unsafe {(*mem).heap_next = heap_new};
    return heap_next;
}

fn allocate_protected_space(size: usize) -> *mut c_char {
    let mut v = Vec::with_capacity(size);
    let ptr = v.as_mut_ptr();
    std::mem::forget(v);
    ptr
}

fn deallocate_protected_space(p: *mut c_char, size: usize) {
    unsafe { std::mem::drop(Vec::from_raw_parts(p, 0, size)) };
}

fn main() {
    let stack_size = 16 * 4096;
    let heap_size = 4 * 16 * 4096;
    let global_size = 16 * 4096;
    let scratch_size = 16 * 4096;

    let stack_top = allocate_protected_space(stack_size);
    let stack_base = unsafe { stack_top.offset(stack_size as isize) };

    let heap = allocate_protected_space(heap_size);
    let global = allocate_protected_space(global_size);
    let scratch = allocate_protected_space(scratch_size);

    let uninit = 0 as (*mut std::os::raw::c_void);

    let mut ctxt = context {
        eax : uninit,
        ebx : uninit,
        ecx : uninit,
        edx : uninit,
        esi : uninit,
        edi : uninit,
        ebp : uninit,
        esp : uninit,
    };

    let heap_top = unsafe { heap.offset((heap_size as isize)/2) };
    let mut mem = memory {
        heap_next : heap,
        global_next : global,
        heap_base : heap,
        heap_top : heap_top,
        heap_base_alt : heap_top,
        heap_top_alt : unsafe { heap.offset(heap_size as isize) },
        global_base : global,
        stack_base : stack_base,
        scratch_base : scratch,
        edi : 0
    };

    print_ptr(unsafe {
        scheme_entry(&mut ctxt, stack_base, &mut mem)
    });

    deallocate_protected_space(stack_top, stack_size);
    deallocate_protected_space(heap, stack_size);
}
<|endoftext|>


<commit_before>/*!
    How to use an external rendering API with the NWG ExternalCanvas.
    Also show how NWG controls can be subclassed

    Requires the following features: `cargo run --example opengl_canvas --features "color-dialog extern-canvas"`
*/
extern crate glutin;
extern crate gl;
#[macro_use] extern crate native_windows_gui as nwg;

use std::cell::RefCell;
use crate::glutin::{
    ContextBuilder, GlRequest, GlProfile, PossiblyCurrent, RawContext, Api,
    dpi::PhysicalSize,
    os::windows::RawContextExt
};
use crate::nwg::NativeUi;

type Ctx = RawContext<PossiblyCurrent>;

/**
Specialize the canvas.

To register a custom struct as a NWG control with full support you need to implement 4 traits:
  * Deref
  * DerefMut
  * Into<nwg::ControlHandle>
  * PartialEq<SubclassControl> for nwg::ControlHandle

You can either to it manually or the `subclass_control!(type, base_type, field)` macro.
*/
#[derive(Default)]
pub struct OpenGlCanvas {
    ctx: RefCell<Option<Ctx>>,
    canvas: nwg::ExternCanvas,
}

impl OpenGlCanvas {

    /// Create an opengl canvas with glutin & gl
    pub fn create_context(&self) {
        use std::ffi::c_void;
        use std::{mem, ptr};

        unsafe {
            let ctx = ContextBuilder::new()
                .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
                .with_gl_profile(GlProfile::Core)
                .build_raw_context(self.canvas.handle.hwnd().unwrap() as *mut c_void)
                .expect("Failed to build opengl context")
                .make_current()
                .expect("Failed to set opengl context as current");

            // Load the function pointers
            gl::Clear::load_with(|s| ctx.get_proc_address(s) as *const _);
            gl::ClearColor::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::CreateShader::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::ShaderSource::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::CompileShader::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::CreateProgram::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::AttachShader::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::LinkProgram::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::UseProgram::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::GenBuffers::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::BindBuffer::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::BufferData::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::GetAttribLocation::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::VertexAttribPointer::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::EnableVertexAttribArray::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::GenVertexArrays::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::BindVertexArray::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::DrawArrays::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::Viewport::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::BufferSubData::load_with(|s| ctx.get_proc_address(s) as *const _ );

            // Init default state
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);

            let vs = gl::CreateShader(gl::VERTEX_SHADER);
            gl::ShaderSource(vs, 1, [VS_SRC.as_ptr() as *const _].as_ptr(), ptr::null());
            gl::CompileShader(vs);

            let fs = gl::CreateShader(gl::FRAGMENT_SHADER);
            gl::ShaderSource(fs, 1, [FS_SRC.as_ptr() as *const _].as_ptr(), ptr::null());
            gl::CompileShader(fs);

            let program = gl::CreateProgram();
            gl::AttachShader(program, vs);
            gl::AttachShader(program, fs);
            gl::LinkProgram(program);
            gl::UseProgram(program);

            let vertex_data: &[f32] = &[
                0.0,  1.0,   1.0, 1.0, 1.0,
               -1.0, -1.0,   1.0, 1.0, 1.0,
                1.0, -1.0,   1.0, 1.0, 1.0,
            ];
            let vertex_size = vertex_data.len() * mem::size_of::<f32>();

            let mut vb = mem::zeroed();
            gl::GenBuffers(1, &mut vb);
            gl::BindBuffer(gl::ARRAY_BUFFER, vb);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertex_size as gl::types::GLsizeiptr,
                vertex_data.as_ptr() as *const _,
                gl::STATIC_DRAW,
            );

            let mut vao = mem::zeroed();
            gl::GenVertexArrays(1, &mut vao);
            gl::BindVertexArray(vao);

            gl::EnableVertexAttribArray(0);
            gl::EnableVertexAttribArray(1);

            let stride = mem::size_of::<f32>() * 5;
            let color_offset = 8 as *const c_void;
            gl::VertexAttribPointer(0, 2, gl::FLOAT, 0, stride as i32, ptr::null());
            gl::VertexAttribPointer(1, 4, gl::FLOAT, 0, stride as i32, color_offset);

            *self.ctx.borrow_mut() = Some(ctx);
        }
    }

    /// Our render function
    pub fn render(&self) {
        self.ctx.borrow().as_ref().map(|ctx| unsafe {
            gl::Clear(gl::COLOR_BUFFER_BIT);
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
            ctx.swap_buffers().unwrap();
        });
    }

    pub fn resize(&self) {
        self.ctx.borrow().as_ref().map(|ctx| unsafe {
            let (w, h) = self.canvas.physical_size();
            gl::Viewport(0, 0, w as _, h as _);
            ctx.resize(PhysicalSize::new(w as f64, h as f64));
        });

        self.render();
    }

}

subclass_control!(OpenGlCanvas, ExternCanvas, canvas);

// subclass_control generates the following code

/*
use std::ops::{Deref, DerefMut};
impl Deref for OpenGlCanvas {
    type Target = nwg::ExternCanvas;
    fn deref(&self) -> &nwg::ExternCanvas { &self.canvas }
}

impl DerefMut for OpenGlCanvas {
    fn deref_mut(&mut self) -> &mut Self::Target {&mut self.canvas }
}

impl Into<nwg::ControlHandle> for &OpenGlCanvas {
    fn into(self) -> nwg::ControlHandle { self.canvas.handle.clone() }
}

impl PartialEq<OpenGlCanvas> for nwg::ControlHandle {
    fn eq(&self, other: &OpenGlCanvas) -> bool {
        *self == other.handle
    }
}*/

/**
    The Ui application. Spoiler alert, there's nothing much different from the other examples.
*/
#[derive(Default)]
pub struct ExternCanvas {
    window: nwg::Window,
    layout: nwg::GridLayout,
    canvas: OpenGlCanvas,
    color_dialog: nwg::ColorDialog,
    choose_color_btn1: nwg::Button,
    choose_color_btn2: nwg::Button,
}

impl ExternCanvas {

    pub fn show(&self) {
        self.window.set_visible(true);
        self.window.set_focus();
    }

    pub fn exit(&self) {
        nwg::stop_thread_dispatch();
    }

    pub fn resize_canvas(&self) {
        self.canvas.resize();
    }

    pub fn select_bg_color(&self) {
        if self.color_dialog.run(Some(&self.window)) {
            let [r, g, b] = self.color_dialog.color();
            let [r, g, b] = [r as f32 / 225.0, g as f32 / 225.0, b as f32 / 225.0];

            unsafe {
                gl::ClearColor(r, g, b, 1.0);
            }
        }

        self.window.invalidate();
    }

    pub fn select_tri_color(&self) {
        use std::mem;

        if self.color_dialog.run(Some(&self.window)) {
            let [r, g, b] = self.color_dialog.color();
            let [r, g, b] = [r as f32 / 225.0, g as f32 / 225.0, b as f32 / 225.0];

            let vertex_data: &[f32] = &[
                0.0,  1.0,   r, g, b,
               -1.0, -1.0,   r, g, b,
                1.0, -1.0,   r, g, b,
            ];

            let vertex_size = vertex_data.len() * mem::size_of::<f32>();

            unsafe {
                gl::BufferSubData(gl::ARRAY_BUFFER, 0, vertex_size as gl::types::GLsizeiptr, vertex_data.as_ptr() as *const _);
            }
        }

        self.window.invalidate();
    }

}

mod extern_canvas_ui {
    use native_windows_gui as nwg;
    use super::*;
    use std::rc::Rc;
    use std::ops::Deref;

    pub struct ExternCanvasUi {
        inner: ExternCanvas,
        default_handler: RefCell<Vec<nwg::EventHandler>>
    }

    impl nwg::NativeUi<ExternCanvas, Rc<ExternCanvasUi>> for ExternCanvas {
        fn build_ui(mut data: ExternCanvas) -> Result<Rc<ExternCanvasUi>, nwg::NwgError> {
            use nwg::Event as E;

            // Resources
            nwg::ColorDialog::builder()
                .build(&mut data.color_dialog)?;

            // Controls
            nwg::Window::builder()
                .flags(nwg::WindowFlags::MAIN_WINDOW)
                .size((600, 500))
                .position((300, 300))
                .title("Native windows GUI / OpenGL")
                .build(&mut data.window)?;

            nwg::ExternCanvas::builder()
                .parent(Some(&data.window))
                .build(&mut data.canvas)?;

            nwg::Button::builder()
                .text("Background color")
                .parent(&data.window)
                .build(&mut data.choose_color_btn1)?;

            nwg::Button::builder()
                .text("Triangle color")
                .parent(&data.window)
                .build(&mut data.choose_color_btn2)?;

            // Wrap-up
            let ui = Rc::new(ExternCanvasUi {
                inner: data,
                default_handler: RefCell::default(),
            });

            // Events
            let window_handles = [&ui.window.handle];

            for handle in window_handles.iter() {
                let evt_ui = ui.clone();
                let handle_events = move |evt, _evt_data, handle| {
                    match evt {
                        E::OnResize => {
                            if &handle == &evt_ui.canvas {
                                ExternCanvas::resize_canvas(&evt_ui.inner);
                            }
                        },
                        E::OnButtonClick => {
                            if &handle == &evt_ui.choose_color_btn1 {
                                ExternCanvas::select_bg_color(&evt_ui.inner);
                            } else if &handle == &evt_ui.choose_color_btn2 {
                                ExternCanvas::select_tri_color(&evt_ui.inner);
                            }
                        },
                        E::OnWindowClose => {
                            if &handle == &evt_ui.window {
                                ExternCanvas::exit(&evt_ui.inner);
                            }
                        },
                        E::OnInit => {
                            if &handle == &evt_ui.window {
                                ExternCanvas::show(&evt_ui.inner);
                            }
                        },
                        _ => {}
                    }
                };

                ui.default_handler.borrow_mut().push(
                    nwg::full_bind_event_handler(handle, handle_events)
                );
            }

            // Layouts
            nwg::GridLayout::builder()
                .parent(&ui.window)
                .max_column(Some(4))
                .max_row(Some(8))
                .child_item(nwg::GridLayoutItem::new(&ui.canvas, 0, 0, 3, 8))
                .child(3, 0, &ui.choose_color_btn1)
                .child(3, 1, &ui.choose_color_btn2)
                .build(&ui.layout);

            return Ok(ui);
        }
    }

    impl ExternCanvasUi {
        /// To make sure that everything is freed without issues, the default handler must be unbound.
        pub fn destroy(&self) {
            let mut handlers = self.default_handler.borrow_mut();
            for handler in handlers.drain(0..) {
                nwg::unbind_event_handler(&handler);
            }
        }
    }

    impl Deref for ExternCanvasUi {
        type Target = ExternCanvas;

        fn deref(&self) -> &ExternCanvas {
            &self.inner
        }
    }

}

pub fn main() {
    unsafe {
        nwg::set_dpi_awareness();
    };
    nwg::init().expect("Failed to init Native Windows GUI");

    let app = ExternCanvas::build_ui(Default::default()).expect("Failed to build UI");

    // Make sure to render everything at least once before showing the window to remove weird artifacts.
    app.canvas.create_context();
    app.canvas.render();

    // Here we use the `with_callback` version of dispatch_thread_events
    // Internally the callback will be executed almost as fast as `loop { callback() }`
    let callback_app = app.clone();
    nwg::dispatch_thread_events_with_callback(move || {
        callback_app.canvas.render();
    });

    app.destroy();
}

const VS_SRC: &'static [u8] = b"#version 330
layout (location=0) in vec2 a_position;
layout (location=1) in vec4 a_color;

out vec4 color;

void main() {
    color = a_color;
    gl_Position = vec4(a_position, 0.0, 1.0);
}
\0";

const FS_SRC: &'static [u8] = b"#version 330
precision mediump float;

in vec4 color;

out vec4 outColor;

void main() {
    outColor = color;
}
\0";
<commit_msg>Fixed opengl-canvas example<commit_after>/*!
    How to use an external rendering API with the NWG ExternalCanvas.
    Also show how NWG controls can be subclassed

    Requires the following features: `cargo run --example opengl_canvas --features "color-dialog extern-canvas"`
*/
extern crate glutin;
extern crate gl;
#[macro_use] extern crate native_windows_gui as nwg;

use std::cell::RefCell;
use crate::glutin::{
    ContextBuilder, GlRequest, GlProfile, PossiblyCurrent, RawContext, Api,
    dpi::PhysicalSize,
    os::windows::RawContextExt
};
use crate::nwg::NativeUi;

type Ctx = RawContext<PossiblyCurrent>;

/**
Specialize the canvas.

To register a custom struct as a NWG control with full support you need to implement 4 traits:
  * Deref
  * DerefMut
  * Into<nwg::ControlHandle>
  * PartialEq<SubclassControl> for nwg::ControlHandle

You can either to it manually or the `subclass_control!(type, base_type, field)` macro.
*/
#[derive(Default)]
pub struct OpenGlCanvas {
    ctx: RefCell<Option<Ctx>>,
    canvas: nwg::ExternCanvas,
}

impl OpenGlCanvas {

    /// Create an opengl canvas with glutin & gl
    pub fn create_context(&self) {
        use std::ffi::c_void;
        use std::{mem, ptr};

        unsafe {
            let ctx = ContextBuilder::new()
                .with_gl(GlRequest::Specific(Api::OpenGl, (3, 3)))
                .with_gl_profile(GlProfile::Core)
                .build_raw_context(self.canvas.handle.hwnd().unwrap() as *mut c_void)
                .expect("Failed to build opengl context")
                .make_current()
                .expect("Failed to set opengl context as current");

            // Load the function pointers
            gl::Clear::load_with(|s| ctx.get_proc_address(s) as *const _);
            gl::ClearColor::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::CreateShader::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::ShaderSource::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::CompileShader::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::CreateProgram::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::AttachShader::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::LinkProgram::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::UseProgram::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::GenBuffers::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::BindBuffer::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::BufferData::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::GetAttribLocation::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::VertexAttribPointer::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::EnableVertexAttribArray::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::GenVertexArrays::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::BindVertexArray::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::DrawArrays::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::Viewport::load_with(|s| ctx.get_proc_address(s) as *const _ );
            gl::BufferSubData::load_with(|s| ctx.get_proc_address(s) as *const _ );

            // Init default state
            gl::ClearColor(0.0, 0.0, 0.0, 1.0);

            let vs = gl::CreateShader(gl::VERTEX_SHADER);
            gl::ShaderSource(vs, 1, [VS_SRC.as_ptr() as *const _].as_ptr(), ptr::null());
            gl::CompileShader(vs);

            let fs = gl::CreateShader(gl::FRAGMENT_SHADER);
            gl::ShaderSource(fs, 1, [FS_SRC.as_ptr() as *const _].as_ptr(), ptr::null());
            gl::CompileShader(fs);

            let program = gl::CreateProgram();
            gl::AttachShader(program, vs);
            gl::AttachShader(program, fs);
            gl::LinkProgram(program);
            gl::UseProgram(program);

            let vertex_data: &[f32] = &[
                0.0,  1.0,   1.0, 1.0, 1.0,
               -1.0, -1.0,   1.0, 1.0, 1.0,
                1.0, -1.0,   1.0, 1.0, 1.0,
            ];
            let vertex_size = vertex_data.len() * mem::size_of::<f32>();

            let mut vb = mem::zeroed();
            gl::GenBuffers(1, &mut vb);
            gl::BindBuffer(gl::ARRAY_BUFFER, vb);
            gl::BufferData(
                gl::ARRAY_BUFFER,
                vertex_size as gl::types::GLsizeiptr,
                vertex_data.as_ptr() as *const _,
                gl::STATIC_DRAW,
            );

            let mut vao = mem::zeroed();
            gl::GenVertexArrays(1, &mut vao);
            gl::BindVertexArray(vao);

            gl::EnableVertexAttribArray(0);
            gl::EnableVertexAttribArray(1);

            let stride = mem::size_of::<f32>() * 5;
            let color_offset = 8 as *const c_void;
            gl::VertexAttribPointer(0, 2, gl::FLOAT, 0, stride as i32, ptr::null());
            gl::VertexAttribPointer(1, 4, gl::FLOAT, 0, stride as i32, color_offset);

            *self.ctx.borrow_mut() = Some(ctx);
        }
    }

    /// Our render function
    pub fn render(&self) {
        self.ctx.borrow().as_ref().map(|ctx| unsafe {
            gl::Clear(gl::COLOR_BUFFER_BIT);
            gl::DrawArrays(gl::TRIANGLES, 0, 3);
            ctx.swap_buffers().unwrap();
        });
    }

    pub fn resize(&self) {
        self.ctx.borrow().as_ref().map(|ctx| unsafe {
            let (w, h) = self.canvas.physical_size();
            gl::Viewport(0, 0, w as _, h as _);
            ctx.resize(PhysicalSize::new(w as f64, h as f64));
        });

        self.render();
    }

}

subclass_control!(OpenGlCanvas, ExternCanvas, canvas);

// subclass_control generates the following code

/*
use std::ops::{Deref, DerefMut};
impl Deref for OpenGlCanvas {
    type Target = nwg::ExternCanvas;
    fn deref(&self) -> &nwg::ExternCanvas { &self.canvas }
}

impl DerefMut for OpenGlCanvas {
    fn deref_mut(&mut self) -> &mut Self::Target {&mut self.canvas }
}

impl Into<nwg::ControlHandle> for &OpenGlCanvas {
    fn into(self) -> nwg::ControlHandle { self.canvas.handle.clone() }
}

impl PartialEq<OpenGlCanvas> for nwg::ControlHandle {
    fn eq(&self, other: &OpenGlCanvas) -> bool {
        *self == other.handle
    }
}*/

/**
    The Ui application. Spoiler alert, there's nothing much different from the other examples.
*/
#[derive(Default)]
pub struct ExternCanvas {
    window: nwg::Window,
    layout: nwg::GridLayout,
    canvas: OpenGlCanvas,
    color_dialog: nwg::ColorDialog,
    choose_color_btn1: nwg::Button,
    choose_color_btn2: nwg::Button,
}

impl ExternCanvas {

    pub fn show(&self) {
        self.window.set_visible(true);
        self.window.set_focus();
    }

    pub fn exit(&self) {
        nwg::stop_thread_dispatch();
    }

    pub fn resize_canvas(&self) {
        self.canvas.resize();
    }

    pub fn select_bg_color(&self) {
        if self.color_dialog.run(Some(&self.window)) {
            let [r, g, b] = self.color_dialog.color();
            let [r, g, b] = [r as f32 / 225.0, g as f32 / 225.0, b as f32 / 225.0];

            unsafe {
                gl::ClearColor(r, g, b, 1.0);
            }
        }

        self.window.invalidate();
    }

    pub fn select_tri_color(&self) {
        use std::mem;

        if self.color_dialog.run(Some(&self.window)) {
            let [r, g, b] = self.color_dialog.color();
            let [r, g, b] = [r as f32 / 225.0, g as f32 / 225.0, b as f32 / 225.0];

            let vertex_data: &[f32] = &[
                0.0,  1.0,   r, g, b,
               -1.0, -1.0,   r, g, b,
                1.0, -1.0,   r, g, b,
            ];

            let vertex_size = vertex_data.len() * mem::size_of::<f32>();

            unsafe {
                gl::BufferSubData(gl::ARRAY_BUFFER, 0, vertex_size as gl::types::GLsizeiptr, vertex_data.as_ptr() as *const _);
            }
        }

        self.window.invalidate();
    }

}

mod extern_canvas_ui {
    use native_windows_gui as nwg;
    use super::*;
    use std::rc::Rc;
    use std::ops::Deref;

    pub struct ExternCanvasUi {
        inner: Rc<ExternCanvas>,
        default_handler: RefCell<Vec<nwg::EventHandler>>
    }

    impl nwg::NativeUi<ExternCanvasUi> for ExternCanvas {
        fn build_ui(mut data: ExternCanvas) -> Result<ExternCanvasUi, nwg::NwgError> {
            use nwg::Event as E;

            // Resources
            nwg::ColorDialog::builder()
                .build(&mut data.color_dialog)?;

            // Controls
            nwg::Window::builder()
                .flags(nwg::WindowFlags::MAIN_WINDOW)
                .size((600, 500))
                .position((300, 300))
                .title("Native windows GUI / OpenGL")
                .build(&mut data.window)?;

            nwg::ExternCanvas::builder()
                .parent(Some(&data.window))
                .build(&mut data.canvas)?;

            nwg::Button::builder()
                .text("Background color")
                .parent(&data.window)
                .build(&mut data.choose_color_btn1)?;

            nwg::Button::builder()
                .text("Triangle color")
                .parent(&data.window)
                .build(&mut data.choose_color_btn2)?;

            // Wrap-up
            let ui = ExternCanvasUi {
                inner: Rc::new(data),
                default_handler: RefCell::default(),
            };

            // Events
            let window_handles = [&ui.window.handle];

            for handle in window_handles.iter() {
                let evt_ui = Rc::downgrade(&ui.inner);
                let handle_events = move |evt, _evt_data, handle| {
                    if let Some(evt_ui) = evt_ui.upgrade() {
                        match evt {
                            E::OnResize => {
                                if &handle == &evt_ui.canvas {
                                    ExternCanvas::resize_canvas(&evt_ui);
                                }
                            },
                            E::OnButtonClick => {
                                if &handle == &evt_ui.choose_color_btn1 {
                                    ExternCanvas::select_bg_color(&evt_ui);
                                } else if &handle == &evt_ui.choose_color_btn2 {
                                    ExternCanvas::select_tri_color(&evt_ui);
                                }
                            },
                            E::OnWindowClose => {
                                if &handle == &evt_ui.window {
                                    ExternCanvas::exit(&evt_ui);
                                }
                            },
                            E::OnInit => {
                                if &handle == &evt_ui.window {
                                    ExternCanvas::show(&evt_ui);
                                }
                            },
                            _ => {}
                        }
                    }
                };

                ui.default_handler.borrow_mut().push(
                    nwg::full_bind_event_handler(handle, handle_events)
                );
            }

            // Layouts
            nwg::GridLayout::builder()
                .parent(&ui.window)
                .max_column(Some(4))
                .max_row(Some(8))
                .child_item(nwg::GridLayoutItem::new(&ui.canvas, 0, 0, 3, 8))
                .child(3, 0, &ui.choose_color_btn1)
                .child(3, 1, &ui.choose_color_btn2)
                .build(&ui.layout)?;

            return Ok(ui);
        }
    }

    impl Drop for ExternCanvasUi {
        /// To make sure that everything is freed without issues, the default handler must be unbound.
        fn drop(&mut self) {
            let mut handlers = self.default_handler.borrow_mut();
            for handler in handlers.drain(0..) {
                nwg::unbind_event_handler(&handler);
            }
        }
    }

    impl Deref for ExternCanvasUi {
        type Target = ExternCanvas;

        fn deref(&self) -> &ExternCanvas {
            &self.inner
        }
    }

}

pub fn main() {
    nwg::init().expect("Failed to init Native Windows GUI");

    let app = ExternCanvas::build_ui(Default::default()).expect("Failed to build UI");

    // Make sure to render everything at least once before showing the window to remove weird artifacts.
    app.canvas.create_context();
    app.canvas.render();

    // Here we use the `with_callback` version of dispatch_thread_events
    // Internally the callback will be executed almost as fast as `loop { callback() }`
    nwg::dispatch_thread_events_with_callback(move || {
        app.canvas.render();
    });
}

const VS_SRC: &'static [u8] = b"#version 330
layout (location=0) in vec2 a_position;
layout (location=1) in vec4 a_color;

out vec4 color;

void main() {
    color = a_color;
    gl_Position = vec4(a_position, 0.0, 1.0);
}
\0";

const FS_SRC: &'static [u8] = b"#version 330
precision mediump float;

in vec4 color;

out vec4 outColor;

void main() {
    outColor = color;
}
\0";
<|endoftext|>


<commit_before>use std::collections::HashSet;
use std::io::{Read, Write, Error};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};

use super::super::utils::DEFAULT_BUF_SIZE;
use super::super::io::binary::*;

#[derive(Debug)]
enum Directive {
	// raw, file
	Line(Vec<u8>, String),
	// raw
	HdrStop(Vec<u8>),
	// raw
	Unknown(Vec<u8>)
}

pub fn filter_preprocessed(base: &Option<PathBuf>, reader: &mut Read, writer: &mut Write, marker: &Option<String>, keep_headers: bool) -> Result<Vec<PathBuf>, Error> {
	let mut line_begin = true;
	// Entry file.
	let mut entry_file: Option<String> = None;
	let mut header_found: bool = false;
	let mut header_files: HashSet<String> = HashSet::new();
	loop {
		let c = try! (read_u8(reader));
		match c {
			b'\n' | b'\r' => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
				line_begin = true;
			}
			b'\t' | b' ' => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
			}
			b'#' if line_begin => {
				let directive = try! (read_directive(c, reader));
				match directive {
					Directive::Line(raw, raw_file) => {
						let file = raw_file.replace("\\", "/");
						entry_file = match entry_file {
							Some(path) => {
								if header_found && (path == file) {
									try! (writer.write_all(b"#pragma hdrstop\n"));
									try! (writer.write_all(&raw));
									break;
								}
								match *marker {
									Some(ref raw_path) => {
										let path = raw_path.replace("\\", "/");
										if file == path || Path::new(&file).ends_with(&Path::new(&path)) {
											header_found = true;
										}
									}
									None => {}
								}
								Some(path)
							}
							None => Some(file.clone())
						};
						header_files.insert(file);
						if keep_headers {
							try! (writer.write_all(&raw));
						}
					}
					Directive::HdrStop(raw) => {
						try! (writer.write_all(&raw));
						break;
					}
					Directive::Unknown(raw) => {
						if keep_headers {
							try! (writer.write_all(&raw));
						}
					}
				}
			}
			_ => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
				line_begin = false;
			}
		}
	}
	// Copy end of stream.
	let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
	loop {
		let size = try! (reader.read(&mut buf));
		if size <= 0 {
			break;
		}
		try! (writer.write_all(&buf[0..size]));
	}
	Ok(Vec::from_iter(header_files.into_iter().map(|arg:String|->PathBuf {
		match base {
			&Some(ref path) => path.join(arg),
			&None => Path::new(&arg).to_path_buf(),
		}
	})))
}

fn read_directive(first: u8, reader: &mut Read) -> Result<Directive, Error> {
	let mut raw: Vec<u8> = Vec::new();
	raw.push(first);
	let (next, token) = try! (read_token(None, reader, &mut raw));
	match &token[..] {
		b"line" => read_directive_line(next, reader, raw),
		b"pragma" => read_directive_pragma(next, reader, raw),
		_ => {
			try! (skip_line(next, reader, &mut raw));
			Ok(Directive::Unknown(raw))
		}
	}
}

fn read_token(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<(Option<u8>, Vec<u8>), Error> {
	match try! (skip_spaces(first, reader, raw)) {
		Some(first_char) => {
			let mut token: Vec<u8> = Vec::new();
			let mut escape = false;
			let quote: bool;
			if first_char == b'"' {
				quote = true;
			} else {
				token.push(first_char);
				quote = false;
			}
			loop {
				let c = try! (read_u8(reader));
				raw.push(c);
				if quote {
					if escape {
						match c {
							b'n' => token.push(b'\n'),
							b'r' => token.push(b'\r'),
							b't' => token.push(b'\t'),
							v => token.push(v)
						}
						escape = false;
					} else if c == ('\\' as u8) {
						escape = true;
					} else if c == b'"' {
						let n = try! (read_u8(reader));
						raw.push(n);
						return Ok((Some(n), token));
					} else {
						token.push(c);
					}
				} else {
					match c {
						b'a' ... b'z' | b'A' ... b'Z' | b'0' ... b'9' => {
							token.push(c);
						}
						_ => {
							return Ok((Some(c), token));
						}
					}
				}
			}
		}
		None => {
			return Ok((None, Vec::new()));
		}
	}
}

fn read_directive_line(first: Option<u8>, reader: &mut Read, mut raw: Vec<u8>) -> Result<Directive, Error> {
	// Line number
	let (next1, _) = try! (read_token(first, reader, &mut raw));
	// File name
	let (next2, file) = try! (read_token(next1, reader, &mut raw));
	try! (skip_line(next2, reader, &mut raw));
	Ok(Directive::Line(raw, String::from_utf8_lossy(&file).to_string()))
}

fn read_directive_pragma(first: Option<u8>, reader: &mut Read, mut raw: Vec<u8>) -> Result<Directive, Error> {
	let (next, token) = try! (read_token(first, reader, &mut raw));
	try! (skip_line(next, reader, &mut raw));
	match &token[..] {
		b"hdrstop" => Ok(Directive::HdrStop(raw)),
		_ => Ok(Directive::Unknown(raw))
	}
}

fn skip_spaces(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<Option<u8>, Error> {
	match first {
		Some(c) => {
			match c {
				b'\n' | b'\r' => {return Ok(None);}
				b'\t' | b' ' => {}
				_ => {return Ok(first);}
			}
		}
		_ => {}
	}
	loop {
		let c = try! (read_u8(reader));
		try! (write_u8(raw, c));
		match c {
			b'\n' | b'\r' => {return Ok(None);}
			b'\t' | b' ' => {}
			_ => {return Ok(Some(c));}
		}
	}
}

fn skip_line(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<(), Error> {
	match first {
		Some(c) => {
			match c {
				b'\n' | b'\r' => {return Ok(());}
				_ => {}
			}
		}
		_ => {}
	}
	loop {
		let c = try! (read_u8(reader));
		try! (write_u8(raw, c));
		match c {
			b'\n' | b'\r' => {return Ok(());}
			_ => {}
		}
	}
}

#[cfg(test)]
mod test {
	extern crate test;

	use std::io::{Read, Write, Cursor};
	use std::fs::File;
	use self::test::Bencher;

	fn check_filter(original: &str, expected: &str, marker: Option<String>, keep_headers: bool) {
		let mut writer: Vec<u8> = Vec::new();
		let mut stream: Vec<u8> = Vec::new();
		stream.write(&original.as_bytes()[..]).unwrap();
		match super::filter_preprocessed(&None, &mut Cursor::new(stream), &mut writer, &marker, keep_headers) {
			Ok(_) => {assert_eq! (String::from_utf8_lossy(&writer), expected)}
			Err(e) => {panic! (e);}
		}
	}

	#[test]
	fn test_filter_precompiled_keep() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("sample header.h".to_string()), true)
	}

	#[test]
	fn test_filter_precompiled_remove() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello1();
void hello2();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("sample header.h".to_string()), false);
	}

	#[test]
	fn test_filter_precompiled_hdrstop() {
		check_filter(
r#"#line 1 "sample.cpp"
 #line 1 "e:/work/octobuild/test_cl/sample header.h"
void hello();
# pragma  hdrstop
void data();
# pragma once
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"# pragma  hdrstop
void data();
# pragma once
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, None, false);
	}

	#[test]
	fn test_filter_precompiled_winpath() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:\\work\\octobuild\\test_cl\\sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#line 1 "sample.cpp"
#line 1 "e:\\work\\octobuild\\test_cl\\sample header.h"
# pragma once
void hello();
#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("e:\\work\\octobuild\\test_cl\\sample header.h".to_string()), true);
	}

	fn bench_filter(b: &mut Bencher, path: &str, marker: Option<String>, keep_headers: bool) {
		let mut source = Vec::new();
		File::open(path).unwrap().read_to_end(&mut source).unwrap();
		b.iter(|| {
			super::filter_preprocessed(&None, &mut Cursor::new(source.clone()), &mut Vec::new(), &marker, keep_headers).unwrap();
		});
	}

	#[bench]
	fn bench_check_filter(b: &mut Bencher) {
		bench_filter(b, "tests/filter_preprocessed.i", Some("c:\\bozaro\\github\\octobuild\\test_cl\\sample.h".to_string()), false)
	}
}
<commit_msg>Fix benchmark<commit_after>use std::collections::HashSet;
use std::io::{Read, Write, Error};
use std::iter::FromIterator;
use std::path::{Path, PathBuf};

use super::super::utils::DEFAULT_BUF_SIZE;
use super::super::io::binary::*;

#[derive(Debug)]
enum Directive {
	// raw, file
	Line(Vec<u8>, String),
	// raw
	HdrStop(Vec<u8>),
	// raw
	Unknown(Vec<u8>)
}

pub fn filter_preprocessed(base: &Option<PathBuf>, reader: &mut Read, writer: &mut Write, marker: &Option<String>, keep_headers: bool) -> Result<Vec<PathBuf>, Error> {
	let mut line_begin = true;
	// Entry file.
	let mut entry_file: Option<String> = None;
	let mut header_found: bool = false;
	let mut header_files: HashSet<String> = HashSet::new();
	loop {
		let c = try! (read_u8(reader));
		match c {
			b'\n' | b'\r' => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
				line_begin = true;
			}
			b'\t' | b' ' => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
			}
			b'#' if line_begin => {
				let directive = try! (read_directive(c, reader));
				match directive {
					Directive::Line(raw, raw_file) => {
						let file = raw_file.replace("\\", "/");
						entry_file = match entry_file {
							Some(path) => {
								if header_found && (path == file) {
									try! (writer.write_all(b"#pragma hdrstop\n"));
									try! (writer.write_all(&raw));
									break;
								}
								match *marker {
									Some(ref raw_path) => {
										let path = raw_path.replace("\\", "/");
										if file == path || Path::new(&file).ends_with(&Path::new(&path)) {
											header_found = true;
										}
									}
									None => {}
								}
								Some(path)
							}
							None => Some(file.clone())
						};
						header_files.insert(file);
						if keep_headers {
							try! (writer.write_all(&raw));
						}
					}
					Directive::HdrStop(raw) => {
						try! (writer.write_all(&raw));
						break;
					}
					Directive::Unknown(raw) => {
						if keep_headers {
							try! (writer.write_all(&raw));
						}
					}
				}
			}
			_ => {
				if keep_headers {
					try! (write_u8(writer, c));
				}
				line_begin = false;
			}
		}
	}
	// Copy end of stream.
	let mut buf: [u8; DEFAULT_BUF_SIZE] = [0; DEFAULT_BUF_SIZE];
	loop {
		let size = try! (reader.read(&mut buf));
		if size <= 0 {
			break;
		}
		try! (writer.write_all(&buf[0..size]));
	}
	Ok(Vec::from_iter(header_files.into_iter().map(|arg:String|->PathBuf {
		match base {
			&Some(ref path) => path.join(arg),
			&None => Path::new(&arg).to_path_buf(),
		}
	})))
}

fn read_directive(first: u8, reader: &mut Read) -> Result<Directive, Error> {
	let mut raw: Vec<u8> = Vec::new();
	raw.push(first);
	let (next, token) = try! (read_token(None, reader, &mut raw));
	match &token[..] {
		b"line" => read_directive_line(next, reader, raw),
		b"pragma" => read_directive_pragma(next, reader, raw),
		_ => {
			try! (skip_line(next, reader, &mut raw));
			Ok(Directive::Unknown(raw))
		}
	}
}

fn read_token(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<(Option<u8>, Vec<u8>), Error> {
	match try! (skip_spaces(first, reader, raw)) {
		Some(first_char) => {
			let mut token: Vec<u8> = Vec::new();
			let mut escape = false;
			let quote: bool;
			if first_char == b'"' {
				quote = true;
			} else {
				token.push(first_char);
				quote = false;
			}
			loop {
				let c = try! (read_u8(reader));
				raw.push(c);
				if quote {
					if escape {
						match c {
							b'n' => token.push(b'\n'),
							b'r' => token.push(b'\r'),
							b't' => token.push(b'\t'),
							v => token.push(v)
						}
						escape = false;
					} else if c == ('\\' as u8) {
						escape = true;
					} else if c == b'"' {
						let n = try! (read_u8(reader));
						raw.push(n);
						return Ok((Some(n), token));
					} else {
						token.push(c);
					}
				} else {
					match c {
						b'a' ... b'z' | b'A' ... b'Z' | b'0' ... b'9' => {
							token.push(c);
						}
						_ => {
							return Ok((Some(c), token));
						}
					}
				}
			}
		}
		None => {
			return Ok((None, Vec::new()));
		}
	}
}

fn read_directive_line(first: Option<u8>, reader: &mut Read, mut raw: Vec<u8>) -> Result<Directive, Error> {
	// Line number
	let (next1, _) = try! (read_token(first, reader, &mut raw));
	// File name
	let (next2, file) = try! (read_token(next1, reader, &mut raw));
	try! (skip_line(next2, reader, &mut raw));
	Ok(Directive::Line(raw, String::from_utf8_lossy(&file).to_string()))
}

fn read_directive_pragma(first: Option<u8>, reader: &mut Read, mut raw: Vec<u8>) -> Result<Directive, Error> {
	let (next, token) = try! (read_token(first, reader, &mut raw));
	try! (skip_line(next, reader, &mut raw));
	match &token[..] {
		b"hdrstop" => Ok(Directive::HdrStop(raw)),
		_ => Ok(Directive::Unknown(raw))
	}
}

fn skip_spaces(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<Option<u8>, Error> {
	match first {
		Some(c) => {
			match c {
				b'\n' | b'\r' => {return Ok(None);}
				b'\t' | b' ' => {}
				_ => {return Ok(first);}
			}
		}
		_ => {}
	}
	loop {
		let c = try! (read_u8(reader));
		try! (write_u8(raw, c));
		match c {
			b'\n' | b'\r' => {return Ok(None);}
			b'\t' | b' ' => {}
			_ => {return Ok(Some(c));}
		}
	}
}

fn skip_line(first: Option<u8>, reader: &mut Read, raw: &mut Vec<u8>) -> Result<(), Error> {
	match first {
		Some(c) => {
			match c {
				b'\n' | b'\r' => {return Ok(());}
				_ => {}
			}
		}
		_ => {}
	}
	loop {
		let c = try! (read_u8(reader));
		try! (write_u8(raw, c));
		match c {
			b'\n' | b'\r' => {return Ok(());}
			_ => {}
		}
	}
}

#[cfg(test)]
mod test {
	extern crate test;

	use std::io::{Read, Write, Cursor};
	use std::fs::File;
	use self::test::Bencher;

	fn check_filter(original: &str, expected: &str, marker: Option<String>, keep_headers: bool) {
		let mut writer: Vec<u8> = Vec::new();
		let mut stream: Vec<u8> = Vec::new();
		stream.write(&original.as_bytes()[..]).unwrap();
		match super::filter_preprocessed(&None, &mut Cursor::new(stream), &mut writer, &marker, keep_headers) {
			Ok(_) => {assert_eq! (String::from_utf8_lossy(&writer), expected)}
			Err(e) => {panic! (e);}
		}
	}

	#[test]
	fn test_filter_precompiled_keep() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello();
#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("sample header.h".to_string()), true)
	}

	#[test]
	fn test_filter_precompiled_remove() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:/work/octobuild/test_cl/sample header.h"
# pragma once
void hello1();
void hello2();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("sample header.h".to_string()), false);
	}

	#[test]
	fn test_filter_precompiled_hdrstop() {
		check_filter(
r#"#line 1 "sample.cpp"
 #line 1 "e:/work/octobuild/test_cl/sample header.h"
void hello();
# pragma  hdrstop
void data();
# pragma once
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"# pragma  hdrstop
void data();
# pragma once
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, None, false);
	}

	#[test]
	fn test_filter_precompiled_winpath() {
		check_filter(
r#"#line 1 "sample.cpp"
#line 1 "e:\\work\\octobuild\\test_cl\\sample header.h"
# pragma once
void hello();
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#,
r#"#line 1 "sample.cpp"
#line 1 "e:\\work\\octobuild\\test_cl\\sample header.h"
# pragma once
void hello();
#pragma hdrstop
#line 2 "sample.cpp"

int main(int argc, char **argv) {
	return 0;
}
"#, Some("e:\\work\\octobuild\\test_cl\\sample header.h".to_string()), true);
	}

	fn bench_filter(b: &mut Bencher, path: &str, marker: Option<String>, keep_headers: bool) {
		let mut source = Vec::new();
		File::open(path).unwrap().read_to_end(&mut source).unwrap();
		b.iter(|| {
			let mut result = Vec::new();
			super::filter_preprocessed(&None, &mut Cursor::new(source.clone()), &mut result, &marker, keep_headers).unwrap();
			result
		});
	}

	#[bench]
	fn bench_check_filter(b: &mut Bencher) {
		bench_filter(b, "tests/filter_preprocessed.i", Some("c:\\bozaro\\github\\octobuild\\test_cl\\sample.h".to_string()), false)
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Traps and notifies UNIX signals.

use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering, ATOMIC_BOOL_INIT, ATOMIC_USIZE_INIT};
use std::sync::{Once, ONCE_INIT};

use os::process::{OsSignal, Signal, SignalCode};

use super::SignalEvent;

static INIT: Once = ONCE_INIT;
// True when we have caught a signal
static CAUGHT: AtomicBool = ATOMIC_BOOL_INIT;
// Stores the value of the signal we caught
static SIGNAL: AtomicUsize = ATOMIC_USIZE_INIT;

// Functions from POSIX libc.
extern "C" {
    fn signal(
        sig: SignalCode,
        cb: unsafe extern "C" fn(SignalCode),
    ) -> unsafe extern "C" fn(SignalCode);
}

unsafe extern "C" fn handle_signal(signal: SignalCode) {
    CAUGHT.store(true, Ordering::SeqCst);
    SIGNAL.store(signal as usize, Ordering::SeqCst);
}

pub fn init() {
    INIT.call_once(|| {
        self::set_signal_handlers();
        CAUGHT.store(false, Ordering::SeqCst);
        SIGNAL.store(0 as usize, Ordering::SeqCst);
    });
}

pub fn check_for_signal() -> Option<SignalEvent> {
    if CAUGHT.load(Ordering::SeqCst) {
        let code = SIGNAL.load(Ordering::SeqCst) as SignalCode;
        let event = match Signal::from_signal_code(code) {
            Some(Signal::INT) | Some(Signal::TERM) => Some(SignalEvent::Shutdown),
            Some(Signal::CHLD) => Some(SignalEvent::WaitForChild),
            Some(signal) => Some(SignalEvent::Passthrough(signal)),
            None => {
                println!("Received invalid signal: #{}", code);
                None
            }
        };
        // Clear out a signal that has been caught so we don't end up
        // processing it again.
        CAUGHT.store(false, Ordering::SeqCst);
        SIGNAL.store(0 as usize, Ordering::SeqCst);
        event
    } else {
        None
    }
}

fn set_signal_handlers() {
    unsafe {
        signal(Signal::HUP.os_signal(), handle_signal);
        signal(Signal::INT.os_signal(), handle_signal);
        signal(Signal::QUIT.os_signal(), handle_signal);
        signal(Signal::ALRM.os_signal(), handle_signal);
        signal(Signal::TERM.os_signal(), handle_signal);
        signal(Signal::USR1.os_signal(), handle_signal);
        signal(Signal::USR2.os_signal(), handle_signal);
        signal(Signal::CHLD.os_signal(), handle_signal);
    }
}
<commit_msg>When multiple signals are received, return them in order; don't drop any<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Traps and notifies UNIX signals.

use std::collections::VecDeque;
use std::sync::{Mutex, Once, ONCE_INIT};

use os::process::{OsSignal, Signal, SignalCode};

use super::SignalEvent;

static INIT: Once = ONCE_INIT;

lazy_static! {
    static ref CAUGHT_SIGNALS: Mutex<VecDeque<SignalCode>> = Mutex::new(VecDeque::new());
}

// Functions from POSIX libc.
extern "C" {
    fn signal(
        sig: SignalCode,
        cb: unsafe extern "C" fn(SignalCode),
    ) -> unsafe extern "C" fn(SignalCode);
}

unsafe extern "C" fn handle_signal(signal: SignalCode) {
    CAUGHT_SIGNALS
        .lock()
        .expect("Signal mutex poisoned")
        .push_back(signal);
}

pub fn init() {
    INIT.call_once(|| {
        self::set_signal_handlers();
    });
}

/// Consumers should call this function fairly frequently and since the vast
/// majority of the time there is at most one signal event waiting, we return
/// at most one. If multiple signals have been received since the last call,
/// they will be returned, one per call in the order they were received.
pub fn check_for_signal() -> Option<SignalEvent> {
    let mut signals = CAUGHT_SIGNALS.lock().expect("Signal mutex poisoned");

    if let Some(code) = signals.pop_front() {
        match Signal::from_signal_code(code) {
            Some(Signal::INT) | Some(Signal::TERM) => Some(SignalEvent::Shutdown),
            Some(Signal::CHLD) => Some(SignalEvent::WaitForChild),
            Some(signal) => Some(SignalEvent::Passthrough(signal)),
            None => {
                println!("Received invalid signal: #{}", code);
                None
            }
        }
    } else {
        None
    }
}

fn set_signal_handlers() {
    unsafe {
        signal(Signal::HUP.os_signal(), handle_signal);
        signal(Signal::INT.os_signal(), handle_signal);
        signal(Signal::QUIT.os_signal(), handle_signal);
        signal(Signal::ALRM.os_signal(), handle_signal);
        signal(Signal::TERM.os_signal(), handle_signal);
        signal(Signal::USR1.os_signal(), handle_signal);
        signal(Signal::USR2.os_signal(), handle_signal);
        signal(Signal::CHLD.os_signal(), handle_signal);
    }
}
<|endoftext|>


<commit_before>use rustc_serialize::json;
use ::xflow::errors::*;

pub type XFlowEdge = (i32, i32);

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowStruct {
    pub id:           String,
    pub version:      i32,
    pub name:         String,
    pub requirements: Vec<XFlowRequirement>,
    pub variables:    XFlowVariables,
    pub nodes:        Vec<XFlowNode>,
    pub edges:        Vec<XFlowEdge>,
    pub branches:     Vec<XFlowBranch>,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowRequirement {
    pub xtype:   String,
    pub version: i32,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariableDefinition {
    pub name:  String,
    pub vtype: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariable {
    pub name:  String,
    pub vtype: String,
    pub value: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariables {
    pub input:  Vec<XFlowVariable>,
    pub local:  Vec<XFlowVariable>,
    pub output: Vec<XFlowVariableDefinition>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Eq, PartialEq)]
pub struct XFlowNode {
    pub id:       i32,
    pub nodetype: String,
    pub label:    String,
    pub action:   String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Eq, PartialEq)]
pub struct XFlowBranch {
    pub name: String,
    pub edge: XFlowEdge,
}

impl XFlowStruct {
    /// Constructs a new `XFlowStruct`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// println!("XFlow version {}", xfs.id);
    /// ```
    pub fn new() -> XFlowStruct {
        XFlowStruct {
            id:          "".to_string(),
            name:        "".to_string(),
            version:      1,
            requirements: Vec::<XFlowRequirement>::new(),
            variables:    XFlowVariables {
                input:  Vec::<XFlowVariable>::new(),
                local:  Vec::<XFlowVariable>::new(),
                output: Vec::<XFlowVariableDefinition>::new(),
            },
            nodes:        Vec::<XFlowNode>::new(),
            edges:        Vec::<XFlowEdge>::new(),
            branches:     Vec::<XFlowBranch>::new(),
        }
    }

    /// Return a string representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_string();
    /// ```
    pub fn to_string(&self) -> String {
        format!("xflow {}", self.id)
    }

    /// Get `XFlowNode`s of `nodetype` and `action`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_by("flow", "start");
    /// ```
    pub fn get_nodes_by(&self, nodetype:&str, action:&str) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype &&
                node.action == action
        }).collect();

        res
    }

    /// Get `XFlowNode`s of `nodetype`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.get_nodes_of_type("flow");
    /// ```
    pub fn get_nodes_of_type(&self, nodetype:&str) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype
        }).collect();

        res
    }

    /// Return a JSON representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_json();
    /// ```
    pub fn to_json(&self) -> String {
        json::encode(&self).unwrap()
    }

    /// Initialize a XFlowStruct from a JSON string
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    ///
    /// let empty_flow = "{\"id\":\"empty\",\"name\":\"empty\",\"version\":1,\"requirements\":[{\"xtype\":\"flow\",\"version\":1},{\"xtype\":\"flox\",\"version\":1}],\"variables\":{\"input\":[],\"output\":[],\"local\":[]},\"nodes\":[],\"edges\":[],\"branches\":[]}";
    ///
    /// let xfs = XFlowStruct::from_json(empty_flow);
    /// println!("XFlow has version {}", xfs.version);
    /// ```
    pub fn from_json(json_string:&str) -> XFlowStruct {
        let xfs:XFlowStruct = json::decode(json_string).unwrap();
        xfs
    }

    pub fn get_in_edges(&self, node:&XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge.1 == node.id
        }).collect();

        res
    }

    pub fn get_out_edges(&self, node:&XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge.0 == node.id
        }).collect();

        res
    }

    pub fn get_branches_for(&self, edge:&XFlowEdge) -> Vec<&XFlowBranch> {

        let res:Vec<&XFlowBranch> = self.branches.iter().filter({|branch|
            edge.0 == branch.edge.0 &&
                edge.1 == branch.edge.1
        }).collect();

        res

    }

    pub fn get_entry_node(&self) -> Result<&XFlowNode, XFlowError> {
        let res = self.get_nodes_by("flow", "start");
        match res.len() {
            0 => Err(XFlowError::NoEntryNode),
            1 => Ok(res[0]),
            _ => Err(XFlowError::MultipleEntryNodes),
        }
    }

    pub fn get_terminal_nodes(&self) -> Result<Vec<&XFlowNode>, XFlowError> {
        let res = self.get_nodes_by("flow", "end");
        match res.len() {
            0 => Err(XFlowError::NoTerminalNode),
            _ => Ok(res),
        }
    }

}

<commit_msg>Add minor doctests<commit_after>use rustc_serialize::json;
use ::xflow::errors::*;

pub type XFlowEdge = (i32, i32);

// Automatically generate `RustcDecodable` and `RustcEncodable` trait
// implementations

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowStruct {
    pub id:           String,
    pub version:      i32,
    pub name:         String,
    pub requirements: Vec<XFlowRequirement>,
    pub variables:    XFlowVariables,
    pub nodes:        Vec<XFlowNode>,
    pub edges:        Vec<XFlowEdge>,
    pub branches:     Vec<XFlowBranch>,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowRequirement {
    pub xtype:   String,
    pub version: i32,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariableDefinition {
    pub name:  String,
    pub vtype: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariable {
    pub name:  String,
    pub vtype: String,
    pub value: String,
}

#[derive(RustcDecodable, RustcEncodable, Debug)]
pub struct XFlowVariables {
    pub input:  Vec<XFlowVariable>,
    pub local:  Vec<XFlowVariable>,
    pub output: Vec<XFlowVariableDefinition>,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Eq, PartialEq)]
pub struct XFlowNode {
    pub id:       i32,
    pub nodetype: String,
    pub label:    String,
    pub action:   String,
}

#[derive(RustcDecodable, RustcEncodable, Debug, Eq, PartialEq)]
pub struct XFlowBranch {
    pub name: String,
    pub edge: XFlowEdge,
}

impl XFlowStruct {
    /// Constructs a new `XFlowStruct`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// println!("XFlow version {}", xfs.id);
    /// ```
    pub fn new() -> XFlowStruct {
        XFlowStruct {
            id:          "".to_string(),
            name:        "".to_string(),
            version:      1,
            requirements: Vec::<XFlowRequirement>::new(),
            variables:    XFlowVariables {
                input:  Vec::<XFlowVariable>::new(),
                local:  Vec::<XFlowVariable>::new(),
                output: Vec::<XFlowVariableDefinition>::new(),
            },
            nodes:        Vec::<XFlowNode>::new(),
            edges:        Vec::<XFlowEdge>::new(),
            branches:     Vec::<XFlowBranch>::new(),
        }
    }

    /// Return a string representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_string();
    /// ```
    pub fn to_string(&self) -> String {
        format!("xflow {}", self.id)
    }

    /// Get `XFlowNode`s of `nodetype` and `action`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// let nodes = xfs.get_nodes_by("flow", "start");
    /// assert_eq!(nodes.len(), 0);
    /// ```
    pub fn get_nodes_by(&self, nodetype:&str, action:&str) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype &&
                node.action == action
        }).collect();

        res
    }

    /// Get `XFlowNode`s of `nodetype`
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// let nodes = xfs.get_nodes_of_type("flow");
    /// assert_eq!(nodes.len(), 0);
    /// ```
    pub fn get_nodes_of_type(&self, nodetype:&str) -> Vec<&XFlowNode> {

        let res:Vec<&XFlowNode> = self.nodes.iter().filter({|node|
            node.nodetype == nodetype
        }).collect();

        res
    }

    /// Return a JSON representation of the XFlowStruct
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    /// let xfs = XFlowStruct::new();
    /// xfs.to_json();
    /// ```
    pub fn to_json(&self) -> String {
        json::encode(&self).unwrap()
    }

    /// Initialize a XFlowStruct from a JSON string
    ///
    /// # Example
    /// ```
    /// use xfdocs::xflow::xfstruct::{XFlowStruct};
    ///
    /// let empty_flow = "{\"id\":\"empty\",\"name\":\"empty\",\"version\":1,\"requirements\":[{\"xtype\":\"flow\",\"version\":1},{\"xtype\":\"flox\",\"version\":1}],\"variables\":{\"input\":[],\"output\":[],\"local\":[]},\"nodes\":[],\"edges\":[],\"branches\":[]}";
    ///
    /// let xfs = XFlowStruct::from_json(empty_flow);
    /// println!("XFlow has version {}", xfs.version);
    /// ```
    pub fn from_json(json_string:&str) -> XFlowStruct {
        let xfs:XFlowStruct = json::decode(json_string).unwrap();
        xfs
    }

    pub fn get_in_edges(&self, node:&XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge.1 == node.id
        }).collect();

        res
    }

    pub fn get_out_edges(&self, node:&XFlowNode) -> Vec<&XFlowEdge> {

        let res:Vec<&XFlowEdge> = self.edges.iter().filter({|edge|
            edge.0 == node.id
        }).collect();

        res
    }

    pub fn get_branches_for(&self, edge:&XFlowEdge) -> Vec<&XFlowBranch> {

        let res:Vec<&XFlowBranch> = self.branches.iter().filter({|branch|
            edge.0 == branch.edge.0 &&
                edge.1 == branch.edge.1
        }).collect();

        res

    }

    pub fn get_entry_node(&self) -> Result<&XFlowNode, XFlowError> {
        let res = self.get_nodes_by("flow", "start");
        match res.len() {
            0 => Err(XFlowError::NoEntryNode),
            1 => Ok(res[0]),
            _ => Err(XFlowError::MultipleEntryNodes),
        }
    }

    pub fn get_terminal_nodes(&self) -> Result<Vec<&XFlowNode>, XFlowError> {
        let res = self.get_nodes_by("flow", "end");
        match res.len() {
            0 => Err(XFlowError::NoTerminalNode),
            _ => Ok(res),
        }
    }

}

<|endoftext|>


<commit_before>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[deny(missing_docs)]

extern crate gfx_core;
extern crate gfx_device_gl;
extern crate glutin;

use gfx_core::{format, handle};
use gfx_core::tex::Size;

/// Initialize with a window builder.
/// Generically parametrized version over the main framebuffer format.
pub fn init<Cf, Df>(builder: glutin::WindowBuilder) ->
            (glutin::Window, gfx_device_gl::Device, gfx_device_gl::Factory,
            handle::RenderTargetView<gfx_device_gl::Resources, Cf>,
            handle::DepthStencilView<gfx_device_gl::Resources, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    use gfx_core::factory::Phantom;
    let (window, device, factory, color_view, ds_view) = init_raw(builder, Cf::get_format(), Df::get_format());
    (window, device, factory, Phantom::new(color_view), Phantom::new(ds_view))
}

/// Initialize with a window builder. Raw version.
pub fn init_raw(builder: glutin::WindowBuilder,
                color_format: format::Format, ds_format: format::Format) ->
                (glutin::Window, gfx_device_gl::Device, gfx_device_gl::Factory,
                handle::RawRenderTargetView<gfx_device_gl::Resources>,
                handle::RawDepthStencilView<gfx_device_gl::Resources>)
{
    let window = {
        let color_total_bits = color_format.0.get_total_bits();
        let alpha_bits = color_format.0.get_alpha_stencil_bits();
        let depth_total_bits = ds_format.0.get_total_bits();
        let stencil_bits = ds_format.0.get_alpha_stencil_bits();
        builder
            .with_depth_buffer(depth_total_bits - stencil_bits)
            .with_stencil_buffer(stencil_bits)
            .with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
            .with_srgb(Some(color_format.1 == format::ChannelType::Srgb))
            .build()
    }.unwrap();

    unsafe { window.make_current().unwrap() };
    let (device, factory) = gfx_device_gl::create(|s|
        window.get_proc_address(s) as *const std::os::raw::c_void);

    // create the main color/depth targets
    let (width, height) = window.get_inner_size().unwrap();
    let aa = window.get_pixel_format().multisampling
                   .unwrap_or(0) as gfx_core::tex::NumSamples;
    let dim = (width as Size, height as Size, 1, aa.into());
    let (color_view, ds_view) = gfx_device_gl::create_main_targets(dim, color_format.0, ds_format.0);

    // done
    (window, device, factory, color_view, ds_view)
}
<commit_msg>Glutin - implemented update_views<commit_after>// Copyright 2015 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#[deny(missing_docs)]

extern crate gfx_core;
extern crate gfx_device_gl;
extern crate glutin;

use gfx_core::{format, handle, tex};
use gfx_device_gl::Resources as R;

/// Initialize with a window builder.
/// Generically parametrized version over the main framebuffer format.
pub fn init<Cf, Df>(builder: glutin::WindowBuilder) ->
            (glutin::Window, gfx_device_gl::Device, gfx_device_gl::Factory,
            handle::RenderTargetView<R, Cf>, handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    use gfx_core::factory::Phantom;
    let (window, device, factory, color_view, ds_view) = init_raw(builder, Cf::get_format(), Df::get_format());
    (window, device, factory, Phantom::new(color_view), Phantom::new(ds_view))
}

fn get_window_dimensions(window: &glutin::Window) -> tex::Dimensions {
    let (width, height) = window.get_inner_size().unwrap();
    let aa = window.get_pixel_format().multisampling
                   .unwrap_or(0) as tex::NumSamples;
    (width as tex::Size, height as tex::Size, 1, aa.into())
}

/// Initialize with a window builder. Raw version.
pub fn init_raw(builder: glutin::WindowBuilder,
                color_format: format::Format, ds_format: format::Format) ->
                (glutin::Window, gfx_device_gl::Device, gfx_device_gl::Factory,
                handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)
{
    let window = {
        let color_total_bits = color_format.0.get_total_bits();
        let alpha_bits = color_format.0.get_alpha_stencil_bits();
        let depth_total_bits = ds_format.0.get_total_bits();
        let stencil_bits = ds_format.0.get_alpha_stencil_bits();
        builder
            .with_depth_buffer(depth_total_bits - stencil_bits)
            .with_stencil_buffer(stencil_bits)
            .with_pixel_format(color_total_bits - alpha_bits, alpha_bits)
            .with_srgb(Some(color_format.1 == format::ChannelType::Srgb))
            .build()
    }.unwrap();

    unsafe { window.make_current().unwrap() };
    let (device, factory) = gfx_device_gl::create(|s|
        window.get_proc_address(s) as *const std::os::raw::c_void);

    // create the main color/depth targets
    let dim = get_window_dimensions(&window);
    let (color_view, ds_view) = gfx_device_gl::create_main_targets(dim, color_format.0, ds_format.0);

    // done
    (window, device, factory, color_view, ds_view)
}

/// Update the internal dimensions of the main framebuffer targets. Generic version over the format.
pub fn update_views<Cf, Df>(window: &glutin::Window, color_view: &mut handle::RenderTargetView<R, Cf>,
                    ds_view: &mut handle::DepthStencilView<R, Df>)
where
    Cf: format::RenderFormat,
    Df: format::DepthFormat,
{
    use gfx_core::factory::Phantom;
    let dim = color_view.get_dimensions();
    assert_eq!(dim, ds_view.get_dimensions());
    if let Some((cv, dv)) = update_views_raw(window, dim, Cf::get_format(), Df::get_format()) {
        *color_view = Phantom::new(cv);
        *ds_view = Phantom::new(dv);
    }
}

/// Return new main target views if the window resolution has changed from the old dimensions.
pub fn update_views_raw(window: &glutin::Window, old_dimensions: tex::Dimensions,
                        color_format: format::Format, ds_format: format::Format)
                        -> Option<(handle::RawRenderTargetView<R>, handle::RawDepthStencilView<R>)>
{
    let dim = get_window_dimensions(window);
    if dim != old_dimensions {
        Some(gfx_device_gl::create_main_targets(dim, color_format.0, ds_format.0))
    }else {
        None
    }
}
<|endoftext|>