<commit_before>#![crate_name = "gui"]
#![unstable]
#![crate_type = "rlib"]
#![crate_type = "dylib"]

#![feature(macro_rules, globs)]

extern crate libc;

extern crate cairo;
extern crate sdl2;
extern crate time;

//use std::ptr;
//use std::io::timer;
//use std::time::duration::Duration;
use cairo::Context;
use time::precise_time_ns;

use sdl2::video::{OPENGL, WindowPos};
use sdl2::event::{poll_event};
pub use sdl2::event::Event;//reexprot events
//use std::cell::RefCell;
//use sdl2::rect::{Rect};
mod sw;

pub mod components; //TODO: export gui components

//TODO: inline functions in cairo wrapper for better speed

/// Struct of a desctop app which is the basic setup
/// it includes everything nedded for a desktop application.
/// Sdl2 is used as the interface to the window manager and cairo for rendering.
pub struct Window{
    delay: uint,//delay betwen event checks default is 10
    pub window: sdl2::video::Window,
    ctx: Context,//cairo context for drawing
}

impl Window{
    /// create a new window with given title, width and height
    pub fn new(title: &str, width: int, height: int) -> Window {
        sdl2::init(sdl2::INIT_EVERYTHING);

        let window = sdl2::video::Window::new(title, WindowPos::PosCentered, WindowPos::PosCentered, width, height, OPENGL).unwrap();
        let ctx: Context = Context::new(&mut sw::SurfaceWrapper::from_sdl(window.get_surface().unwrap())).unwrap();
        Window{
            delay: 12,
            // Create a window
            window: window,
            ctx: ctx,
        }
    }

    /// function which takes the render function to generate the content, and then listens for input events
    /// it will return, if the window has been closed.
    pub fn show(&mut self, render: |&mut CTX<()>|){
        use sdl2::event;

        self.cairo_context().save();
        {
            let none = &Event::None;
            let mut ctx = CTX::new::<()>(self, none, true);
            render(&mut ctx);
        }
        self.cairo_context().restore();
        self.update();

        'event : loop {
            let e = poll_event();
            match e {
                Event::Quit(_) => break 'event,
                Event::KeyDown(_, _, key_code, scan_code, _,_) => println!("deydown {} {}", key_code, scan_code),
                Event::KeyUp(_, _, _, _, _, _) => println!("key up"),
                Event::MouseMotion(_, _, _, _, _, _, _, _) => {
                    //TODO: get mouse state
                    //println!("mouse move: ({}|{}) ({}|{})",x,y,xrel,yrel);

                    self.cairo_context().save();
                    {
                        let mut ctx = CTX::new::<()>(self, &e, true);
                        render(&mut ctx);
                    }
                    self.cairo_context().restore();
                    let start = precise_time_ns();
                    self.update();
                    let taken = precise_time_ns() - start;
                    println!("  => {:.3} ms", (taken as f64)/1000000.0);
                },
                Event::MouseButtonDown(_,_,_,_,_,_) => {
                    self.cairo_context().save();
                    {
                        let mut ctx = CTX::new::<()>(self, &e, true);
                        render(&mut ctx);
                    }
                    self.cairo_context().restore();
                    self.update();
                },
                Event::MouseButtonUp(_,_,_,_,_,_) => {
                    self.cairo_context().save();
                    {
                        let mut ctx = CTX::new::<()>(self, &e, true);
                        render(&mut ctx);
                    }
                    self.cairo_context().restore();
                    self.update();
                },
                Event::Window(_, _, id, d1, d2) => {
                    //TODO: use this event to redraw on size changes and to sleep
                    println!("window event {} {} {}", id, d1, d2);
                },
                _ => sdl2::timer::delay(self.delay)
            }
        }
        sdl2::quit();
    }

    /// get the ciro drawing context to draw on it
    #[stable]
    #[inline(always)]
    pub fn cairo_context(&mut self) -> &mut cairo::Context{
        &mut self.ctx
    }

    /// calls the given function and provides a cairo drawing context
    #[stable]
    #[inline(always)]
    pub fn draw(&mut self, draw_closure: |&mut cairo::Context|){
        draw_closure(&mut self.ctx);
    }

    ///Function to update view to cairo drawing
    #[stable]
    #[inline(always)]
    pub fn update(&mut self){
        let _ = self.window.update_surface();//surface updaten
    }

    /// close the window
    #[stable]
    #[inline(always)]
    pub fn close(&mut self){
        sdl2::quit();
    }

    /// set the title of the window
    #[inline(always)]
    pub fn title(&mut self, val: String){
        self.window.set_title(val.as_slice());
    }

    /// get title of the window
    #[inline(always)]
    pub fn get_title(&self) -> String{
        self.window.get_title()
    }

    /// get the size of the window
    #[inline(always)]
    pub fn get_size(&self) -> (int, int){
        self.window.get_size()
    }

    //get size of the canvas to draw on
    #[inline(always)]
    pub fn get_draw_size(&self) -> (int, int){
        self.window.get_drawable_size()
    }
}

/// the trait implemented by all widgets displayed.
/// A widget can eather have state, in which case it gets its own frame-buffer
/// or it has no state in which case its result will be thrown away after changes.
pub trait Widget<Event>{
    /// In this function only rendering to the screen and atouching event listeners is done
    /// the state of the component gets passed as a imutable reference, so this rutine is not
    /// able to change anything.
    /// It returns the (width, hight) of the area affected by the render method
    fn render(&mut self, ctx: &mut CTX<Event>) -> (f64, f64);

    /// Method which is used by the layout engine to get the size of a component
    /// by default the size will be calculated by using the render function with
    /// blocked drawing, but if speed matters this function can provide faster information
    #[inline(always)]
    fn size(&self) -> (f64, f64) {
        (0.0,0.0)
    }
}

pub struct CTX<'a, Event>{
    window: &'a mut Window,//ref to the window
    event: &'a sdl2::event::Event,
    pos: (f64,f64),
    should_draw: bool,//wether anything should be drawing
    should_handle: bool,
    events: Vec<Event>,
}

impl<'a> CTX<'a, Event>{
    pub fn new<'a, Event>(window: &'a mut Window, event:&'a sdl2::event::Event, should_draw: bool) -> CTX<'a, Event>{
        CTX{
            window: window,
            event: event,
            pos: (0.0,0.0),
            should_draw: should_draw,
            should_handle: true,
            events: vec![],
        }
    }
}

impl<'a, Event> CTX<'a, Event>{
    ///this function calls a closure with the cairo drawing context as parameter
    ///so the widget can draw some lower level stuff
    pub fn draw(&mut self, draw_closure: |&mut cairo::Context|){
        if !self.should_draw{
            return;
        }
        draw_closure(self.window.cairo_context());
    }

    ///add a component as a child of the current component
    /// id: this is an unique identifier which is used to manage state and caching
    ///     it has to be unique in this component
    /// w: the widget which should be added. One widget can be added multible times
    /// event: the closure which should be called if the Widget fires an event
    ///        normaly widgets use enums which can then be matched an events can be handled
    ///        if no event should be catched this should be None
    #[inlne]
    pub fn add<Event>(&mut self,id: uint, w: &mut Widget<Event>, event:Option<|Event|>) -> (f64, f64){
        //println!("add");
        //TODO: create a sub context
        self.window.cairo_context().save();
        let (x, y) = self.pos;
        self.window.cairo_context().translate(x,y);//go to the right position
        let mut e;
        //TODO: ignore emits if no event handler is given
        {
            let mut ctx:CTX<Event> = CTX::new(self.window, self.event, self.should_draw);
            e = w.render(&mut ctx);
            match event{
                Some(c) => {//handle the events fired
                    for s in ctx.events.into_iter() {
                        c(s);
                    }
                },
                None => {}
            }
            //TODO: call callback for event
        }
        self.window.cairo_context().restore();
        e
    }

    ///emit an event which can be handled by the parent element.
    #[inline]
    pub fn emit(&mut self, event: Event){
        self.events.push(event);
    }

    /// set the position for the next widget.
    #[inline(always)]
    pub fn go_to(&mut self, x: f64, y: f64){
        self.pos = (x,y);
    }

    #[inline(always)]
    pub fn cairo_pos(&mut self) -> (f64, f64){
        let mut sx = 0.0;
        let mut sy = 0.0;
        self.window.cairo_context().user_to_device(&mut sx, &mut sy);
        (sx,sy)
    }

    /// get current x positiont
    #[inline(always)]
    pub fn x(&mut self) -> f64{
        let (x,_) = self.cairo_pos();
        x
    }

    /// get current y position
    #[inline(always)]
    pub fn y(&mut self) -> f64{
        let (_,y) = self.cairo_pos();
        y
    }

    ///with this function it is possible to mutate the state of the component,
    ///it should be avoided in render function, maybe in event handler
    pub fn get_mut_state(){}

    /// register mouse event listener
    //TODO: add window event subsribing capabilitys
    pub fn mouseover(&mut self, size: (f64,f64), handle: |&sdl2::event::Event, &mut CTX<Event>|){
        use sdl2::event;
        if !self.should_handle{
            return;
        }
        //TODO: register instead of handling directly

        let mut sx = 0.0;
        let mut sy = 0.0;
        self.window.cairo_context().user_to_device(&mut sx, &mut sy);

        match self.event{
            &Event::MouseMotion(_, _, _, _, x, y, xrel, yrel) => {
                let (bx, by) = size;
                let x = x as f64;
                let y = y as f64;
                if x >= sx && y >= sy && x <= bx+sx && y <= by+sy{
                    handle(self.event, self);
                }
                //self.found = true;
            },
            &Event::MouseButtonDown(_, _, _, _, x, y) => {
                let (bx, by) = size;
                let x = x as f64;
                let y = y as f64;
                if x >= sx && y >= sy && x <= bx+sx && y <= by+sy{
                    handle(self.event, self);
                }
                //self.found = true;
            },

            _ => return,
        }
    }
}
<commit_msg>compress match<commit_after>#![crate_name = "gui"]
#![unstable]
#![crate_type = "rlib"]
#![crate_type = "dylib"]

#![feature(macro_rules, globs)]

extern crate libc;

extern crate cairo;
extern crate sdl2;
extern crate time;

//use std::ptr;
//use std::io::timer;
//use std::time::duration::Duration;
use cairo::Context;
use time::precise_time_ns;

use sdl2::video::{OPENGL, WindowPos};
use sdl2::event::{poll_event};
pub use sdl2::event::Event;//reexprot events
//use std::cell::RefCell;
//use sdl2::rect::{Rect};
mod sw;

pub mod components; //TODO: export gui components

//TODO: inline functions in cairo wrapper for better speed

/// Struct of a desctop app which is the basic setup
/// it includes everything nedded for a desktop application.
/// Sdl2 is used as the interface to the window manager and cairo for rendering.
pub struct Window{
    delay: uint,//delay betwen event checks default is 10
    pub window: sdl2::video::Window,
    ctx: Context,//cairo context for drawing
}

impl Window{
    /// create a new window with given title, width and height
    pub fn new(title: &str, width: int, height: int) -> Window {
        sdl2::init(sdl2::INIT_EVERYTHING);

        let window = sdl2::video::Window::new(title, WindowPos::PosCentered, WindowPos::PosCentered, width, height, OPENGL).unwrap();
        let ctx: Context = Context::new(&mut sw::SurfaceWrapper::from_sdl(window.get_surface().unwrap())).unwrap();
        Window{
            delay: 12,
            // Create a window
            window: window,
            ctx: ctx,
        }
    }

    /// function which takes the render function to generate the content, and then listens for input events
    /// it will return, if the window has been closed.
    pub fn show(&mut self, render: |&mut CTX<()>|){
        use sdl2::event;

        self.cairo_context().save();
        {
            let none = &Event::None;
            let mut ctx = CTX::new::<()>(self, none, true);
            render(&mut ctx);
        }
        self.cairo_context().restore();
        self.update();

        'event : loop {
            let e = poll_event();
            match e {
                Event::Quit(_) => break 'event,
                Event::KeyDown(_, _, key_code, scan_code, _,_) => println!("deydown {} {}", key_code, scan_code),
                Event::KeyUp(_, _, _, _, _, _) => println!("key up"),
                Event::MouseMotion(_,_,_,_,_,_,_,_) | Event::MouseButtonDown(_,_,_,_,_,_) | Event::MouseButtonUp(_,_,_,_,_,_) => {
                    //TODO: get mouse state
                    //println!("mouse move: ({}|{}) ({}|{})",x,y,xrel,yrel);
                    let start = precise_time_ns();
                    self.cairo_context().save();
                    {
                        let mut ctx = CTX::new::<()>(self, &e, true);
                        render(&mut ctx);
                    }
                    self.cairo_context().restore();

                    self.update();
                    let taken = precise_time_ns() - start;
                    println!("  => {:.3} ms", (taken as f64)/1000000.0);
                },
                Event::Window(_, _, id, d1, d2) => {
                    //TODO: use this event to redraw on size changes and to sleep
                    println!("window event {} {} {}", id, d1, d2);
                },
                _ => sdl2::timer::delay(self.delay)
            }
        }
        sdl2::quit();
    }

    /// get the ciro drawing context to draw on it
    #[stable]
    #[inline(always)]
    pub fn cairo_context(&mut self) -> &mut cairo::Context{
        &mut self.ctx
    }

    /// calls the given function and provides a cairo drawing context
    #[stable]
    #[inline(always)]
    pub fn draw(&mut self, draw_closure: |&mut cairo::Context|){
        draw_closure(&mut self.ctx);
    }

    ///Function to update view to cairo drawing
    #[stable]
    #[inline(always)]
    pub fn update(&mut self){
        let _ = self.window.update_surface();//surface updaten
    }

    /// close the window
    #[stable]
    #[inline(always)]
    pub fn close(&mut self){
        sdl2::quit();
    }

    /// set the title of the window
    #[inline(always)]
    pub fn title(&mut self, val: String){
        self.window.set_title(val.as_slice());
    }

    /// get title of the window
    #[inline(always)]
    pub fn get_title(&self) -> String{
        self.window.get_title()
    }

    /// get the size of the window
    #[inline(always)]
    pub fn get_size(&self) -> (int, int){
        self.window.get_size()
    }

    //get size of the canvas to draw on
    #[inline(always)]
    pub fn get_draw_size(&self) -> (int, int){
        self.window.get_drawable_size()
    }
}

/// the trait implemented by all widgets displayed.
/// A widget can eather have state, in which case it gets its own frame-buffer
/// or it has no state in which case its result will be thrown away after changes.
pub trait Widget<Event>{
    /// In this function only rendering to the screen and atouching event listeners is done
    /// the state of the component gets passed as a imutable reference, so this rutine is not
    /// able to change anything.
    /// It returns the (width, hight) of the area affected by the render method
    fn render(&mut self, ctx: &mut CTX<Event>) -> (f64, f64);

    /// Method which is used by the layout engine to get the size of a component
    /// by default the size will be calculated by using the render function with
    /// blocked drawing, but if speed matters this function can provide faster information
    #[inline(always)]
    fn size(&self) -> (f64, f64) {
        (0.0,0.0)
    }
}

pub struct CTX<'a, Event>{
    window: &'a mut Window,//ref to the window
    event: &'a sdl2::event::Event,
    pos: (f64,f64),
    should_draw: bool,//wether anything should be drawing
    should_handle: bool,
    events: Vec<Event>,
}

impl<'a> CTX<'a, Event>{
    pub fn new<'a, Event>(window: &'a mut Window, event:&'a sdl2::event::Event, should_draw: bool) -> CTX<'a, Event>{
        CTX{
            window: window,
            event: event,
            pos: (0.0,0.0),
            should_draw: should_draw,
            should_handle: true,
            events: vec![],
        }
    }
}

impl<'a, Event> CTX<'a, Event>{
    ///this function calls a closure with the cairo drawing context as parameter
    ///so the widget can draw some lower level stuff
    pub fn draw(&mut self, draw_closure: |&mut cairo::Context|){
        if !self.should_draw{
            return;
        }
        draw_closure(self.window.cairo_context());
    }

    ///add a component as a child of the current component
    /// id: this is an unique identifier which is used to manage state and caching
    ///     it has to be unique in this component
    /// w: the widget which should be added. One widget can be added multible times
    /// event: the closure which should be called if the Widget fires an event
    ///        normaly widgets use enums which can then be matched an events can be handled
    ///        if no event should be catched this should be None
    #[inlne]
    pub fn add<Event>(&mut self,id: uint, w: &mut Widget<Event>, event:Option<|Event|>) -> (f64, f64){
        //println!("add");
        //TODO: create a sub context
        self.window.cairo_context().save();
        let (x, y) = self.pos;
        self.window.cairo_context().translate(x,y);//go to the right position
        let mut e;
        //TODO: ignore emits if no event handler is given
        {
            let mut ctx:CTX<Event> = CTX::new(self.window, self.event, self.should_draw);
            e = w.render(&mut ctx);
            match event{
                Some(c) => {//handle the events fired
                    for s in ctx.events.into_iter() {
                        c(s);
                    }
                },
                None => {}
            }
            //TODO: call callback for event
        }
        self.window.cairo_context().restore();
        e
    }

    ///emit an event which can be handled by the parent element.
    #[inline]
    pub fn emit(&mut self, event: Event){
        self.events.push(event);
    }

    /// set the position for the next widget.
    #[inline(always)]
    pub fn go_to(&mut self, x: f64, y: f64){
        self.pos = (x,y);
    }

    #[inline(always)]
    pub fn cairo_pos(&mut self) -> (f64, f64){
        let mut sx = 0.0;
        let mut sy = 0.0;
        self.window.cairo_context().user_to_device(&mut sx, &mut sy);
        (sx,sy)
    }

    /// get current x positiont
    #[inline(always)]
    pub fn x(&mut self) -> f64{
        let (x,_) = self.cairo_pos();
        x
    }

    /// get current y position
    #[inline(always)]
    pub fn y(&mut self) -> f64{
        let (_,y) = self.cairo_pos();
        y
    }

    ///with this function it is possible to mutate the state of the component,
    ///it should be avoided in render function, maybe in event handler
    pub fn get_mut_state(){
        unimplemented!();
    }

    pub fn get_state(){
        unimplemented!();
    }

    /// register mouse event listener
    //TODO: add window event subsribing capabilitys
    pub fn mouseover(&mut self, size: (f64,f64), handle: |&sdl2::event::Event, &mut CTX<Event>|){
        use sdl2::event;
        if !self.should_handle{
            return;
        }
        //TODO: register instead of handling directly

        let mut sx = 0.0;
        let mut sy = 0.0;
        self.window.cairo_context().user_to_device(&mut sx, &mut sy);

        match self.event{
            &Event::MouseMotion(_, _, _, _, x, y, _, _)
            | &Event::MouseButtonDown(_, _, _, _, x, y)
            | &Event::MouseButtonUp(_, _, _, _, x, y) => {
                let (bx, by) = size;
                let x = x as f64;
                let y = y as f64;
                if x >= sx && y >= sy && x <= bx+sx && y <= by+sy{
                    handle(self.event, self);
                }
                //self.found = true;
            },
            _ => return,
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{self, StdoutLock, Write};
use std::path::{Path, PathBuf};
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

use lscolors::{LsColors, Style};

use crate::exit_codes::ExitCode;
use crate::filesystem::strip_current_dir;
use crate::options::Options;

pub fn replace_path_separator(path: &str, new_path_separator: &str) -> String {
    path.replace(std::path::MAIN_SEPARATOR, &new_path_separator)
}

// TODO: this function is performance critical and can probably be optimized
pub fn print_entry(
    stdout: &mut StdoutLock,
    entry: &PathBuf,
    config: &Options,
    wants_to_quit: &Arc<AtomicBool>,
) {
    let path = if entry.is_absolute() {
        entry.as_path()
    } else {
        strip_current_dir(entry)
    };

    let r = if let Some(ref ls_colors) = config.ls_colors {
        print_entry_colorized(stdout, path, config, ls_colors, &wants_to_quit)
    } else {
        print_entry_uncolorized(stdout, path, config)
    };

    if r.is_err() {
        // Probably a broken pipe. Exit gracefully.
        process::exit(ExitCode::GeneralError.into());
    }
}

// TODO: this function is performance critical and can probably be optimized
fn print_entry_colorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Options,
    ls_colors: &LsColors,
    wants_to_quit: &Arc<AtomicBool>,
) -> io::Result<()> {
    let default_style = ansi_term::Style::default();

    // Traverse the path and colorize each component
    for (component, style) in ls_colors.style_for_path_components(path) {
        let style = style
            .map(Style::to_ansi_term_style)
            .unwrap_or(default_style);

        let mut path_string = component.to_string_lossy();
        if let Some(ref separator) = config.path_separator {
            *path_string.to_mut() = replace_path_separator(&path_string, &separator);
        }
        write!(stdout, "{}", style.paint(path_string))?;

        // TODO: can we move this out of the if-statement? Why do we call it that often?
        if wants_to_quit.load(Ordering::Relaxed) {
            writeln!(stdout)?;
            process::exit(ExitCode::KilledBySigint.into());
        }
    }

    if config.null_separator {
        write!(stdout, "\0")
    } else {
        writeln!(stdout)
    }
}

// TODO: this function is performance critical and can probably be optimized
fn print_entry_uncolorized_base(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Options,
) -> io::Result<()> {
    let separator = if config.null_separator { "\0" } else { "\n" };

    let mut path_string = path.to_string_lossy();
    if let Some(ref separator) = config.path_separator {
        *path_string.to_mut() = replace_path_separator(&path_string, &separator);
    }
    write!(stdout, "{}{}", path_string, separator)
}

#[cfg(not(unix))]
fn print_entry_uncolorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Options,
) -> io::Result<()> {
    print_entry_uncolorized_base(stdout, path, config)
}

#[cfg(unix)]
fn print_entry_uncolorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Options,
) -> io::Result<()> {
    use std::os::unix::ffi::OsStrExt;

    if config.interactive_terminal || config.path_separator.is_some() {
        // Fall back to the base implementation
        print_entry_uncolorized_base(stdout, path, config)
    } else {
        // Print path as raw bytes, allowing invalid UTF-8 filenames to be passed to other processes
        let separator = if config.null_separator { b"\0" } else { b"\n" };
        stdout.write_all(path.as_os_str().as_bytes())?;
        stdout.write_all(separator)
    }
}
<commit_msg>hide private func<commit_after>use std::io::{self, StdoutLock, Write};
use std::path::{Path, PathBuf};
use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

use lscolors::{LsColors, Style};

use crate::exit_codes::ExitCode;
use crate::filesystem::strip_current_dir;
use crate::options::Options;

fn replace_path_separator(path: &str, new_path_separator: &str) -> String {
    path.replace(std::path::MAIN_SEPARATOR, &new_path_separator)
}

// TODO: this function is performance critical and can probably be optimized
pub fn print_entry(
    stdout: &mut StdoutLock,
    entry: &PathBuf,
    config: &Options,
    wants_to_quit: &Arc<AtomicBool>,
) {
    let path = if entry.is_absolute() {
        entry.as_path()
    } else {
        strip_current_dir(entry)
    };

    let r = if let Some(ref ls_colors) = config.ls_colors {
        print_entry_colorized(stdout, path, config, ls_colors, &wants_to_quit)
    } else {
        print_entry_uncolorized(stdout, path, config)
    };

    if r.is_err() {
        // Probably a broken pipe. Exit gracefully.
        process::exit(ExitCode::GeneralError.into());
    }
}

// TODO: this function is performance critical and can probably be optimized
fn print_entry_colorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Options,
    ls_colors: &LsColors,
    wants_to_quit: &Arc<AtomicBool>,
) -> io::Result<()> {
    let default_style = ansi_term::Style::default();

    // Traverse the path and colorize each component
    for (component, style) in ls_colors.style_for_path_components(path) {
        let style = style
            .map(Style::to_ansi_term_style)
            .unwrap_or(default_style);

        let mut path_string = component.to_string_lossy();
        if let Some(ref separator) = config.path_separator {
            *path_string.to_mut() = replace_path_separator(&path_string, &separator);
        }
        write!(stdout, "{}", style.paint(path_string))?;

        // TODO: can we move this out of the if-statement? Why do we call it that often?
        if wants_to_quit.load(Ordering::Relaxed) {
            writeln!(stdout)?;
            process::exit(ExitCode::KilledBySigint.into());
        }
    }

    if config.null_separator {
        write!(stdout, "\0")
    } else {
        writeln!(stdout)
    }
}

// TODO: this function is performance critical and can probably be optimized
fn print_entry_uncolorized_base(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Options,
) -> io::Result<()> {
    let separator = if config.null_separator { "\0" } else { "\n" };

    let mut path_string = path.to_string_lossy();
    if let Some(ref separator) = config.path_separator {
        *path_string.to_mut() = replace_path_separator(&path_string, &separator);
    }
    write!(stdout, "{}{}", path_string, separator)
}

#[cfg(not(unix))]
fn print_entry_uncolorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Options,
) -> io::Result<()> {
    print_entry_uncolorized_base(stdout, path, config)
}

#[cfg(unix)]
fn print_entry_uncolorized(
    stdout: &mut StdoutLock,
    path: &Path,
    config: &Options,
) -> io::Result<()> {
    use std::os::unix::ffi::OsStrExt;

    if config.interactive_terminal || config.path_separator.is_some() {
        // Fall back to the base implementation
        print_entry_uncolorized_base(stdout, path, config)
    } else {
        // Print path as raw bytes, allowing invalid UTF-8 filenames to be passed to other processes
        let separator = if config.null_separator { b"\0" } else { b"\n" };
        stdout.write_all(path.as_os_str().as_bytes())?;
        stdout.write_all(separator)
    }
}
<|endoftext|>


<commit_before>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(macro_rules)]

extern crate libc;
extern crate std;
extern crate opengles;

#[cfg(target_os="android")]
pub mod glut;

#[cfg(test,target_os="android")]
pub mod test;

<commit_msg>Rust upgrade<commit_after>// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#![feature(macro_rules)]

extern crate libc;
extern crate opengles;

#[cfg(target_os="android")]
pub mod glut;

#[cfg(test,target_os="android")]
pub mod test;

<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(unused_imports)]

#[macro_use]
extern crate nom;

extern crate crc;

use nom::{HexDisplay,Needed,IResult,ErrorKind,le_i32,le_u32,le_u8,le_u16,length_value,FileProducer};
use nom::Err;
use nom::IResult::*;

struct A {
  a: u8,
  b: u8
}

named!(length_encoded,
    chain!(
        size: le_u32 ~
        crc: le_u32 ~
        data: take!(size),
        || {data}
    )
);

/// Text is encoded with a leading int that denotes the number of bytes that
/// the text spans. The last byte in the text will be null terminated, so we trim
/// it off. It may seem redundant to store this information, but stackoverflow contains
/// a nice reasoning for why it may have been done this way:
/// http://stackoverflow.com/questions/6293457/why-are-c-net-strings-length-prefixed-and-null-terminated
named!(text_encoded<&[u8], &str>,
    chain!(
        size: le_u32 ~
        data: take_str!(size - 1) ~
        take!(1),
        || {data}
    )
);

named!(f<&[u8],A>,
    chain!(
        header_size:  le_i32 ~
        header_crc:   le_i32 ~
        header:       take!(header_size) ~
        content_size: le_i32 ~
        content_crc:  le_i32 ~
        content:      take!(content_size),
        || {A {a: 0, b: 0}}
    )
);

#[cfg(test)]
mod tests {
    use nom::IResult::{Done, Error, Incomplete};
    use nom::Needed::Size;

    #[test]
    fn missing_header_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..8]);
        assert_eq!(r, Incomplete(Size(4776)));
    }

    #[test]
    fn incomplete_header_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..9]);
        assert_eq!(r, Incomplete(Size(4776)));
    }

    #[test]
    fn missing_header() {
        let r = super::length_encoded(&[]);
        assert_eq!(r, Incomplete(Size(4)));
    }

    #[test]
    fn missing_crc_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..4]);
        assert_eq!(r, Incomplete(Size(8)));
    }

    #[test]
    fn parse_a_header_with_zero_data() {
        let data = [0, 0, 0, 0, 0, 0, 0, 0];
        let r = super::length_encoded(&data);
        assert_eq!(r, Done(&[][..], &[][..]));
    }

    #[test]
    fn parse_text_encoding() {
        // dd skip=16 count=28 if=rumble.replay of=text.replay bs=1
        let data = include_bytes!("../assets/text.replay");
        let r = super::text_encoded(data);
        assert_eq!(r, Done(&[][..], "TAGame.Replay_Soccar_TA"));
    }
}
<commit_msg>Add RProp enum<commit_after>#![allow(dead_code)]
#![allow(unused_imports)]

#[macro_use]
extern crate nom;

extern crate crc;

use nom::{HexDisplay,Needed,IResult,ErrorKind,le_i32,le_u32,le_u8,le_u16,length_value,FileProducer};
use nom::Err;
use nom::IResult::*;

struct A {
  a: u8,
  b: u8
}

enum RProp {
    Array(Box<[RProp]>),
    Bool(bool),
    Byte(u8),
    Float(f32),
    Int(u32),
    Name(String),
    QWord(u64),
    Str(String)
}

named!(length_encoded,
    chain!(
        size: le_u32 ~
        crc: le_u32 ~
        data: take!(size),
        || {data}
    )
);

/// Text is encoded with a leading int that denotes the number of bytes that
/// the text spans. The last byte in the text will be null terminated, so we trim
/// it off. It may seem redundant to store this information, but stackoverflow contains
/// a nice reasoning for why it may have been done this way:
/// http://stackoverflow.com/questions/6293457/why-are-c-net-strings-length-prefixed-and-null-terminated
named!(text_encoded<&[u8], &str>,
    chain!(
        size: le_u32 ~
        data: take_str!(size - 1) ~
        take!(1),
        || {data}
    )
);

named!(str_prop<&[u8], RProp>, map!(map!(text_encoded, str::to_string), RProp::Str));

named!(rprop_encoded<&[u8], RProp>,
  switch!(text_encoded,
    "ArrayProperty" => call!(str_prop) |
    "BoolProperty" => call!(str_prop) |
    "ByteProperty" => call!(str_prop)|
    "FloatProperty" => call!(str_prop) |
    "IntProperty" => call!(str_prop) |
    "NameProperty" => call!(str_prop) |
    "QWordProperty" => call!(str_prop) |
    "StrProperty" => call!(str_prop)
  )
);

named!(f<&[u8],A>,
    chain!(
        header_size:  le_i32 ~
        header_crc:   le_i32 ~
        header:       take!(header_size) ~
        content_size: le_i32 ~
        content_crc:  le_i32 ~
        content:      take!(content_size),
        || {A {a: 0, b: 0}}
    )
);

#[cfg(test)]
mod tests {
    use nom::IResult::{Done, Error, Incomplete};
    use nom::Needed::Size;

    #[test]
    fn missing_header_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..8]);
        assert_eq!(r, Incomplete(Size(4776)));
    }

    #[test]
    fn incomplete_header_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..9]);
        assert_eq!(r, Incomplete(Size(4776)));
    }

    #[test]
    fn missing_header() {
        let r = super::length_encoded(&[]);
        assert_eq!(r, Incomplete(Size(4)));
    }

    #[test]
    fn missing_crc_data() {
        let data = include_bytes!("../assets/rumble.replay");
        let r = super::length_encoded(&data[..4]);
        assert_eq!(r, Incomplete(Size(8)));
    }

    #[test]
    fn parse_a_header_with_zero_data() {
        let data = [0, 0, 0, 0, 0, 0, 0, 0];
        let r = super::length_encoded(&data);
        assert_eq!(r, Done(&[][..], &[][..]));
    }

    #[test]
    fn parse_text_encoding() {
        // dd skip=16 count=28 if=rumble.replay of=text.replay bs=1
        let data = include_bytes!("../assets/text.replay");
        let r = super::text_encoded(data);
        assert_eq!(r, Done(&[][..], "TAGame.Replay_Soccar_TA"));
    }
}
<|endoftext|>


<commit_before>
mod abort_on_panic;

use abort_on_panic::abort_on_panic;

/// Allows use of a value inside a `&mut T` as though it was owned by the closure
///
/// The closure must return a valid T
/// # Aborts
/// Will abort the program (exiting with status code -1) if the closure panics.
pub fn take<T, F>(mut_ref: &mut T, closure: F)
  where F: FnOnce(T) -> T {
    use std::ptr;
    abort_on_panic(|| {
        unsafe {
            let old_t = ptr::read(mut_ref);
            let new_t = closure(old_t);
            ptr::write(mut_ref, new_t);
        }
    });
}

#[test]
fn it_works() {
    enum Foo {A, B};
    impl Drop for Foo {
        fn drop(&mut self) {
            match *self {
                Foo::A => println!("Foo::A dropped"),
                Foo::B => println!("Foo::B dropped")
            }
        }
    }
    let mut foo = Foo::A;
    take(&mut foo, |mut f| {
       drop(f);
       Foo::B
    });
}<commit_msg>Actually test that the mutation worked.<commit_after>
mod abort_on_panic;

use abort_on_panic::abort_on_panic;

/// Allows use of a value inside a `&mut T` as though it was owned by the closure
///
/// The closure must return a valid T
/// # Aborts
/// Will abort the program (exiting with status code -1) if the closure panics.
pub fn take<T, F>(mut_ref: &mut T, closure: F)
  where F: FnOnce(T) -> T {
    use std::ptr;
    abort_on_panic(|| {
        unsafe {
            let old_t = ptr::read(mut_ref);
            let new_t = closure(old_t);
            ptr::write(mut_ref, new_t);
        }
    });
}

#[test]
fn it_works() {
    #[derive(PartialEq, Eq, Debug)]
    enum Foo {A, B};
    impl Drop for Foo {
        fn drop(&mut self) {
            match *self {
                Foo::A => println!("Foo::A dropped"),
                Foo::B => println!("Foo::B dropped")
            }
        }
    }
    let mut foo = Foo::A;
    take(&mut foo, |mut f| {
       drop(f);
       Foo::B
    });
    assert_eq!(&foo, &Foo::B);
}<|endoftext|>


<commit_before>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate url;
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

#[phase(plugin, link)]
extern crate log;
extern crate http;
extern crate iron;
extern crate mount;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::{GetUrl, Serve};
use iron::middleware::{Status, Continue, Unwind};
use mount::OriginalUrl;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

#[deriving(Clone)]
struct Favicon {
    favicon_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// This will attempt to serve static files from the given root path.
    /// The path may be relative or absolute. If `Path::new("")` is given,
    /// files will be served from the current directory.
    ///
    /// If a static file exists and can be read from, `enter` will serve it to
    /// the `Response` and `Unwind` the middleware stack with a status of `200`.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    /// If a file should have been read but cannot, due to permissions or
    /// read errors, a different `Middleware` should handle it.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }

    pub fn favicon(favicon_path: Path) -> Favicon {
        Favicon {
            favicon_path: favicon_path
        }
    }
}

impl Middleware for Static {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                // Check for requested file
                match res.serve_file(&self.root_path.join(
                    Path::new(
                        // Coerce to relative path.
                        // We include the slash to ensure that you never have a path like ".index.html"
                        // when you meant "./index.html", see http://is.gd/yz9p0B for an example.
                        "./".to_string().append(path.as_slice())))) {
                    Ok(()) => {
                        debug!("Serving static file at {}.",
                            &self.root_path.join("./".to_string().append(path.as_slice())).display());
                        return Unwind
                    },
                    Err(_) => ()
                }

                // Check for index.html
                let index_path = self.root_path.join(
                    Path::new("./".to_string().append(path.as_slice()))
                        .join("./index.html".to_string()));
                if index_path.is_file() {
                    // Avoid serving as a directory
                    if path.len() > 0 {
                        match path.as_slice().char_at_reverse(path.len()) {
                            '/' => {
                                match res.serve_file(&index_path) {
                                    Ok(()) => {
                                        debug!("Serving static file at {}.",
                                            &index_path.display());
                                        return Unwind
                                    },
                                    Err(err) => {
                                        debug!("Failed while trying to serve index.html: {}", err)
                                        return Continue
                                    }
                                }
                            },
                    // 303:
                            _ => ()
                        }
                    }
                    let redirect_path = match alloy.find::<OriginalUrl>() {
                        Some(&OriginalUrl(ref original_url)) => original_url.clone(),
                        None => path.clone()
                    }.append("/");
                    res.headers.extensions.insert("Location".to_string(), redirect_path.clone());
                    let _ = res.serve(::http::status::SeeOther,
                        format!("Redirecting to {}/", redirect_path).as_slice());
                    return Unwind
                }
            },
            None => ()
        }
        Continue
    }
}

impl Middleware for Favicon {
    fn enter(&mut self, req: &mut Request, res: &mut Response, _alloy: &mut Alloy) -> Status {
        match req.request_uri {
            AbsolutePath(ref path) => {
                if regex!("/favicon$").is_match(path.as_slice()) {
                    match res.serve_file(&self.favicon_path) {
                        Ok(()) => {
                            res.headers.cache_control = Some("max-age=86400".to_str());
                            return Unwind },
                        Err(_) => { return Continue }
                    }
                }
                Continue
            },
            _ => {
                Continue
            }
        }
    }
}
<commit_msg>(doc) Documented favicon.<commit_after>#![crate_id = "staticfile"]
#![deny(missing_doc)]
#![feature(phase)]

//! Static file-serving middleware.

extern crate url;
#[phase(plugin)]
extern crate regex_macros;
extern crate regex;

#[phase(plugin, link)]
extern crate log;
extern crate http;
extern crate iron;
extern crate mount;

use iron::{Request, Response, Middleware, Alloy};
use iron::mixin::{GetUrl, Serve};
use iron::middleware::{Status, Continue, Unwind};
use mount::OriginalUrl;

/// The static file-serving `Middleware`.
#[deriving(Clone)]
pub struct Static {
    root_path: Path
}

#[deriving(Clone)]
#[doc(hidden)]
struct Favicon {
    favicon_path: Path
}

impl Static {
    /// Create a new instance of `Static` with a given root path.
    ///
    /// This will attempt to serve static files from the given root path.
    /// The path may be relative or absolute. If `Path::new("")` is given,
    /// files will be served from the current directory.
    ///
    /// If a static file exists and can be read from, `enter` will serve it to
    /// the `Response` and `Unwind` the middleware stack with a status of `200`.
    ///
    /// In the case of any error, it will `Continue` through the stack.
    /// If a file should have been read but cannot, due to permissions or
    /// read errors, a different `Middleware` should handle it.
    ///
    /// If the path is '/', it will attempt to serve `index.html`.
    pub fn new(root_path: Path) -> Static {
        Static {
            root_path: root_path
        }
    }

    /// Create a favicon server from the given filepath.
    ///
    /// This will serve your favicon, as specified by `favicon_path`,
    /// to every request ending in "/favicon.ico" that it sees,
    /// and then unwind the middleware stack for those requests.
    ///
    /// It should be linked first in order to avoid additional processing
    /// for simple favicon requests.
    ///
    /// Unlike normally served static files, favicons are given a max-age
    /// of one day.
    #[allow(visible_private_types)]
    pub fn favicon(favicon_path: Path) -> Favicon {
        Favicon {
            favicon_path: favicon_path
        }
    }
}

impl Middleware for Static {
    fn enter(&mut self, req: &mut Request, res: &mut Response, alloy: &mut Alloy) -> Status {
        match req.url() {
            Some(path) => {
                // Check for requested file
                match res.serve_file(&self.root_path.join(
                    Path::new(
                        // Coerce to relative path.
                        // We include the slash to ensure that you never have a path like ".index.html"
                        // when you meant "./index.html", see http://is.gd/yz9p0B for an example.
                        "./".to_string().append(path.as_slice())))) {
                    Ok(()) => {
                        debug!("Serving static file at {}.",
                            &self.root_path.join("./".to_string().append(path.as_slice())).display());
                        return Unwind
                    },
                    Err(_) => ()
                }

                // Check for index.html
                let index_path = self.root_path.join(
                    Path::new("./".to_string().append(path.as_slice()))
                        .join("./index.html".to_string()));
                if index_path.is_file() {
                    // Avoid serving as a directory
                    if path.len() > 0 {
                        match path.as_slice().char_at_reverse(path.len()) {
                            '/' => {
                                match res.serve_file(&index_path) {
                                    Ok(()) => {
                                        debug!("Serving static file at {}.",
                                            &index_path.display());
                                        return Unwind
                                    },
                                    Err(err) => {
                                        debug!("Failed while trying to serve index.html: {}", err)
                                        return Continue
                                    }
                                }
                            },
                    // 303:
                            _ => ()
                        }
                    }
                    let redirect_path = match alloy.find::<OriginalUrl>() {
                        Some(&OriginalUrl(ref original_url)) => original_url.clone(),
                        None => path.clone()
                    }.append("/");
                    res.headers.extensions.insert("Location".to_string(), redirect_path.clone());
                    let _ = res.serve(::http::status::SeeOther,
                        format!("Redirecting to {}/", redirect_path).as_slice());
                    return Unwind
                }
            },
            None => ()
        }
        Continue
    }
}

impl Middleware for Favicon {
    fn enter(&mut self, req: &mut Request, res: &mut Response, _alloy: &mut Alloy) -> Status {
        match req.request_uri {
            AbsolutePath(ref path) => {
                if regex!("/favicon$").is_match(path.as_slice()) {
                    match res.serve_file(&self.favicon_path) {
                        Ok(()) => {
                            res.headers.cache_control = Some("max-age=86400".to_str());
                            return Unwind },
                        Err(_) => { return Continue }
                    }
                }
                Continue
            },
            _ => {
                Continue
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate libc;

use libc::{uint8_t, size_t};

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_init(ctn: u16, pn: u16) -> i8 {

    1
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_data(ctn: u16, dad: *mut uint8_t, sad: *mut uint8_t, lenc: size_t, command: *const uint8_t, lenr: *mut size_t, response: *mut uint8_t) -> i8 {
    unsafe {

        1
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_close(ctn: u16) -> i8 {

    1
}
<commit_msg>Revert "just functions"<commit_after>extern crate hyper;
extern crate libc;
#[macro_use]
extern crate lazy_static;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate serde_json;

use hyper::Client;
use hyper::client::response::Response;
use hyper::header::{Headers, ContentType};
use hyper::mime::{Mime, TopLevel, SubLevel};
use hyper::status::StatusCode;
use libc::{uint8_t, size_t};
use serde::Serialize;
use std::collections::HashMap;
use std::env::var;
use std::io::Read;
use std::slice;
use std::sync::Mutex;

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

static OK: i8 = 0;
static ERR_INVALID: i8 = -1;
static ERR_HOST: i8 = -127;

#[derive(Serialize)]
struct Empty();

macro_rules! post_request {
    ($path:expr) => (post_request($path, &Empty{}));
    ($path:expr, $data:expr) => (post_request($path, $data));
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_init(ctn: u16, pn: u16) -> i8 {
    // Do we know this CTN?
    if MAP.lock().unwrap().contains_key(&ctn) {
        return ERR_INVALID
    }

    // Build the request URL
    let endpoint = "ct_init".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    let mut response = post_request!(&path);

    match response.status {
        StatusCode::Ok => {
            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Store CTN
                MAP.lock().unwrap().insert(ctn, pn);
            }

            status
        },
        _ => ERR_HOST
    }
}

#[derive(Serialize)]
struct RequestData {
    ctn: u16,
    dad: u8,
    sad: u8,
    lenc: usize,
    command: Vec<u8>,
    lenr: usize
}

#[allow(non_snake_case)]
#[derive(Deserialize)]
struct ResponseData {
    dad: u8,
    sad: u8,
    lenr: usize,
    response: Vec<u8>,
    responseCode: i8
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_data(ctn: u16, dad: *mut uint8_t, sad: *mut uint8_t, lenc: size_t, command: *const uint8_t, lenr: *mut size_t, response: *mut uint8_t) -> i8 {
    unsafe {
        if !MAP.lock().unwrap().contains_key(&ctn) {
            return ERR_INVALID
        }

        let dad: &mut u8 = &mut *dad;

        let sad: &mut u8 = &mut *sad;

        let lenr: &mut size_t = &mut *lenr;

        let command = slice::from_raw_parts(command, lenc as usize);

        let response = slice::from_raw_parts_mut(response, *lenr);

        let requestData = RequestData {
            ctn: ctn,
            dad: *dad,
            sad: *sad,
            lenc: lenc,
            command: command.to_vec(),
            lenr: *lenr
        };

        let pn = MAP.lock().unwrap();
        let pn = pn.get(&ctn).unwrap();
        let endpoint = "ct_data".to_string();
        let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

        let mut http_response = post_request(&path, &requestData);

        match http_response.status {
            StatusCode::Ok => {
                // decode server response
                let mut body = String::new();
                http_response.read_to_string(&mut body).unwrap();
                let responseData: ResponseData = serde_json::from_str(&body).unwrap();

                if responseData.responseCode == OK {

                    *dad = responseData.dad;
                    *sad = responseData.sad;
                    *lenr = responseData.lenr;

                    for (place, element) in response.iter_mut().zip(responseData.response.iter()) {
                        *place = *element;
                    }
                }
                return responseData.responseCode;
            },
            _ => ERR_HOST
        }
    }
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn CT_close(ctn: u16) -> i8 {
    // Do we know this CTN?
    if !MAP.lock().unwrap().contains_key(&ctn) {
        return ERR_INVALID
    }

    // Build the request URL
    let pn = MAP.lock().unwrap().get(&ctn).unwrap().clone();
    let endpoint = "ct_close".to_string();
    let path = endpoint + "/" + &ctn.to_string() + "/" + &pn.to_string();

    // Perform the request
    let mut response = post_request!(&path);

    match response.status {
        StatusCode::Ok => {
            // Cast server response
            let mut body = String::new();
            response.read_to_string(&mut body).unwrap();

            let status = body.parse::<i8>().unwrap();
            if status == OK {
                // Remove CTN
                MAP.lock().unwrap().remove(&ctn);
            }

            status
        },
        _ => ERR_HOST
    }
}

fn env_or_default(var_name: &str, default: &str) -> String {
    match var(var_name) {
        Ok(s) => s,
        Err(_) => default.into(),
    }
}

fn post_request<T>(path: &str, payload: &T) -> Response
    where T: Serialize
{
    // untested
    let base_url = env_or_default("K2_BASE_URL", "http://localhost:8080/k2/ctapi/");
    let url = base_url + path;

    let client = Client::new();

    let mut headers = Headers::new();
    headers.set(
        ContentType(Mime(TopLevel::Application, SubLevel::Json, vec![]))
    );

    let body = serde_json::to_string(&payload).unwrap();

    return client.post(&url)
        .headers(headers)
        .body(&body[..])
        .send()
        .unwrap();
}
<|endoftext|>


<commit_before>#![crate_name = "input"]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]
#![allow(unstable)]

//! A flexible structure for user interactions
//! to be used in window frameworks and widgets libraries.

#[macro_use] extern crate rustc_bitflags;
extern crate "rustc-serialize" as rustc_serialize;

pub use mouse::MouseButton;
pub use keyboard::Key;

pub mod keyboard;
pub mod mouse;

/// Models different kinds of buttons.
#[derive(Copy, Clone, RustcDecodable, RustcEncodable, PartialEq, Eq, Show)]
pub enum Button {
    /// A keyboard button.
    Keyboard(Key),
    /// A mouse button.
    Mouse(MouseButton),
}

/// Models different kinds of motion.
#[derive(Copy, Clone, RustcDecodable, RustcEncodable, PartialEq, Show)]
pub enum Motion {
    /// x and y in window coordinates.
    MouseCursor(f64, f64),
    /// x and y in relative coordinates.
    MouseRelative(f64, f64),
    /// x and y in scroll ticks.
    MouseScroll(f64, f64),
}

/// Models input events.
#[derive(Clone, RustcDecodable, RustcEncodable, PartialEq, Show)]
pub enum Input {
    /// Pressed a button.
    Press(Button),
    /// Released a button.
    Release(Button),
    /// Moved mouse cursor.
    Move(Motion),
    /// Text (usually from keyboard).
    Text(String),
    /// Window got resized.
    Resize(u32, u32),
    /// Window gained or lost focus.
    Focus(bool),
}
<commit_msg>Fixed bitflags<commit_after>#![crate_name = "input"]
#![deny(missing_docs)]
#![deny(missing_copy_implementations)]
#![allow(unstable)]

//! A flexible structure for user interactions
//! to be used in window frameworks and widgets libraries.

#[macro_use]
extern crate bitflags;
extern crate "rustc-serialize" as rustc_serialize;

pub use mouse::MouseButton;
pub use keyboard::Key;

pub mod keyboard;
pub mod mouse;

/// Models different kinds of buttons.
#[derive(Copy, Clone, RustcDecodable, RustcEncodable, PartialEq, Eq, Show)]
pub enum Button {
    /// A keyboard button.
    Keyboard(Key),
    /// A mouse button.
    Mouse(MouseButton),
}

/// Models different kinds of motion.
#[derive(Copy, Clone, RustcDecodable, RustcEncodable, PartialEq, Show)]
pub enum Motion {
    /// x and y in window coordinates.
    MouseCursor(f64, f64),
    /// x and y in relative coordinates.
    MouseRelative(f64, f64),
    /// x and y in scroll ticks.
    MouseScroll(f64, f64),
}

/// Models input events.
#[derive(Clone, RustcDecodable, RustcEncodable, PartialEq, Show)]
pub enum Input {
    /// Pressed a button.
    Press(Button),
    /// Released a button.
    Release(Button),
    /// Moved mouse cursor.
    Move(Motion),
    /// Text (usually from keyboard).
    Text(String),
    /// Window got resized.
    Resize(u32, u32),
    /// Window gained or lost focus.
    Focus(bool),
}
<|endoftext|>


<commit_before>//! Note: library usage is not semver/API-stable
//!
//! Type evolution of a websocat run:
//!
//! 1. `&str` - string as passed to command line
//! 2. `Specifier` - more organized representation, maybe nested
//! 3. `PeerConstructor` - a future or stream that returns one or more connections
//! 4. `Peer` - one active connection
//! 5. `Transfer` - two peers recombine into two (if bidirectional) transfers
//! 6. `Session` - a running websocat connection from one specifier to another

extern crate futures;
extern crate tokio_core;
#[macro_use]
extern crate tokio_io;
extern crate websocket;

#[macro_use]
extern crate log;

use tokio_core::reactor::{Handle};
use futures::future::Future;
use tokio_io::{AsyncRead,AsyncWrite};

use futures::Stream;

use std::any::Any;
use std::rc::Rc;

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

fn wouldblock<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::WouldBlock, ""))
}
fn brokenpipe<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, ""))
}
fn io_other_error<E : std::error::Error + Send + Sync + 'static>(e:E) -> std::io::Error {
    std::io::Error::new(std::io::ErrorKind::Other,e)
}

pub use lints::ConfigurationConcern;

pub struct WebsocatConfiguration {
    pub opts : Options,
    pub s1 : Rc<Specifier>,
    pub s2: Rc<Specifier>,
}

impl WebsocatConfiguration {
    pub fn serve<OE>(self, h: Handle, onerror: std::rc::Rc<OE>)
        -> Box<Future<Item=(), Error=()>>
        where OE : Fn(Box<std::error::Error>) -> () + 'static
    {
        serve(h, self.s1,self.s2, self.opts, onerror)
    }
}

#[derive(Default,Debug)]
pub struct Options {
}

#[derive(Default)]
pub struct ProgramState {
    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    stdio : stdio_peer::GlobalState,

    reuser: connection_reuse_peer::GlobalState,
}

pub struct Peer(Box<AsyncRead>, Box<AsyncWrite>);

pub type BoxedNewPeerFuture = Box<Future<Item=Peer, Error=Box<std::error::Error>>>;
pub type BoxedNewPeerStream = Box<Stream<Item=Peer, Error=Box<std::error::Error>>>;

/// He wants to peek into a Specifier. `FnMut` wants to be `FnOnce` actually.
pub type SpecifierInspector = Rc<Fn(&Specifier)-> Box<Any>>;

/// For checking specifier combinations for problems
#[derive(Eq,PartialEq,Debug,Clone,Copy)]
pub enum SpecifierType {
    Stdio,
    Reuser,
    Other,
}

#[derive(Debug,Clone,Copy)]
pub struct OneSpecifierInfo {
    pub multiconnect: bool,
    pub uses_global_state: bool,
    pub typ: SpecifierType,
}

#[derive(Debug,Clone)]
pub struct SpecifierInfo {
    pub this: OneSpecifierInfo,
    pub subspecifier: Option<Box<SpecifierInfo>>,
}

impl SpecifierInfo {
    fn collect(&self) -> Vec<OneSpecifierInfo> {
        let mut r = vec![];
        r.push(self.this);
        let mut ss = &self.subspecifier;
        while let Some(sub) = ss {
            r.push(sub.this);
            ss = &sub.subspecifier;
        }
        r
    }
}

/// A parsed command line argument.
/// For example, `ws-listen:tcp-l:127.0.0.1:8080` gets parsed into
/// a `WsUpgrade(TcpListen(SocketAddr))`.
pub trait Specifier : std::fmt::Debug {
    /// Apply the specifier for constructing a "socket" or other connecting device.
    fn construct(&self, h:&Handle, ps: &mut ProgramState) -> PeerConstructor;

    // Specified by `specifier_boilerplate!`:
    fn is_multiconnect(&self) -> bool;
    fn uses_global_state(&self) -> bool;
    fn visit_myself(&self, f: SpecifierInspector) -> Box<Any>;
    fn get_type(&self) -> SpecifierType;

    // May be overridden by `self_0_is_subspecifier`:
    fn visit_hierarchy(&self, f: SpecifierInspector) -> Vec<Box<Any>> {
        let mut rets = vec![];
        rets.push (self.visit_myself(f));
        rets
    }
    fn get_info(&self) -> SpecifierInfo {
        SpecifierInfo {
            this: self.get_info_without_subspecs(),
            subspecifier: None,
        }
    }

    // Provided:
    fn get_info_without_subspecs(&self) -> OneSpecifierInfo {
        OneSpecifierInfo {
            multiconnect: self.is_multiconnect(),
            uses_global_state: self.uses_global_state(),
            typ: self.get_type(),
        }
    }
}

impl Specifier for Rc<Specifier> {
    fn construct(&self, h:&Handle, ps: &mut ProgramState) -> PeerConstructor {
        (**self).construct(h, ps)
    }
    fn is_multiconnect(&self) -> bool { (**self).is_multiconnect() }
    fn visit_myself(&self, f: SpecifierInspector) -> Box<Any> { (**self).visit_myself(f) }
    fn visit_hierarchy(&self, f: SpecifierInspector) -> Vec<Box<Any>>  { (**self).visit_hierarchy(f) }
    fn get_type(&self) -> SpecifierType { (**self).get_type() }
    fn uses_global_state(&self) -> bool { (**self).uses_global_state() }
    fn get_info_without_subspecs(&self) -> OneSpecifierInfo { (**self).get_info_without_subspecs() }
    fn get_info(&self) -> SpecifierInfo { (**self).get_info() }
}

macro_rules! specifier_boilerplate {
    (singleconnect $($e:tt)*) => {
        fn is_multiconnect(&self) -> bool { false }
        specifier_boilerplate!($($e)*);
    };
    (multiconnect $($e:tt)*) => {
        fn is_multiconnect(&self) -> bool { true }
        specifier_boilerplate!($($e)*);
    };
    (no_subspec $($e:tt)*) => {
        specifier_boilerplate!($($e)*);
    };
    (has_subspec $($e:tt)*) => {
        specifier_boilerplate!($($e)*);
    };
    (typ=$tn:ident $($e:tt)*) => {
        fn get_type(&self) -> $crate::SpecifierType { $crate::SpecifierType::$tn }
        specifier_boilerplate!($($e)*);
    };
    () => {
        fn visit_myself(&self, f: $crate::SpecifierInspector) -> Box<::std::any::Any> { f(self) }
    };
    (globalstate $($e:tt)*) => {
        fn uses_global_state(&self) -> bool { true }
        specifier_boilerplate!($($e)*);
    };
    (noglobalstate $($e:tt)*) => {
        fn uses_global_state(&self) -> bool { false }
        specifier_boilerplate!($($e)*);
    };
}

macro_rules! self_0_is_subspecifier {
    (...) => {
        fn visit_hierarchy(&self, f: $crate::SpecifierInspector) -> Vec<Box<::std::any::Any>> {
            let mut rets = vec![];
            let ff = f.clone();
            rets.push (self.visit_myself(f));
            rets.append(&mut self.0.visit_hierarchy(ff));
            rets
        }
        fn get_info(&self) -> $crate::SpecifierInfo {
            $crate::SpecifierInfo {
                this: self.get_info_without_subspecs(),
                subspecifier: Some(Box::new(self.0.get_info())),
            }
        }
    };
    (proxy_is_multiconnect) => {
        self_0_is_subspecifier!(...);
        fn is_multiconnect(&self) -> bool { self.0.is_multiconnect() }
    };
}

mod my_copy;
pub mod lints;

#[cfg(all(unix,not(feature="no_unix_stdio")))]
pub mod stdio_peer;

pub mod ws_peer;
pub mod ws_server_peer;
pub mod ws_client_peer;
pub mod net_peer;
pub mod stdio_threaded_peer;
pub mod connection_reuse_peer;
pub mod mirror_peer;
pub mod trivial_peer;
pub mod reconnect_peer;

pub mod specparse;

pub enum PeerConstructor {
    ServeOnce(BoxedNewPeerFuture),
    ServeMultipleTimes(BoxedNewPeerStream),
}

impl PeerConstructor {
    pub fn map<F:'static>(self, f : F) -> Self
            where F:FnMut(Peer) -> BoxedNewPeerFuture
    {
        use PeerConstructor::*;
        match self {
            ServeOnce(x) => ServeOnce(Box::new(x.and_then(f)) as BoxedNewPeerFuture),
            ServeMultipleTimes(s) => ServeMultipleTimes(
                Box::new(
                    s.and_then(f)
                ) as BoxedNewPeerStream
            )
        }
    }

    pub fn get_only_first_conn(self) -> BoxedNewPeerFuture {
        use PeerConstructor::*;
        match self {
            ServeMultipleTimes(stre) => {
                Box::new(
                    stre
                    .into_future()
                    .map(move |(std_peer,_)| {
                        let peer2 = std_peer.expect("Nowhere to connect it");
                        peer2
                    })
                    .map_err(|(e,_)|e)
                ) as BoxedNewPeerFuture
            },
            ServeOnce(future) => {
                future
            },
        }
    }
}

/// A `Read` utility to deal with partial reads
#[derive(Default)]
pub struct ReadDebt(pub Option<Vec<u8>>);

impl ReadDebt {
    pub fn process_message(&mut self, buf: &mut [u8], buf_in: &[u8]) -> std::result::Result<usize, std::io::Error> {
        assert_eq!(self.0, None);
        let l = buf_in.len().min(buf.len());
        buf[..l].copy_from_slice(&buf_in[..l]);

        if l < buf_in.len() {
            self.0 = Some(buf_in[l..].to_vec());
        }

        Ok(l)
    }
    pub fn check_debt(&mut self, buf: &mut [u8]) -> Option<std::result::Result<usize, std::io::Error>>       {
        if let Some(debt) = self.0.take() {
            Some(self.process_message(buf, debt.as_slice()))
        } else {
            None
        }
    }
}

pub fn once(x:BoxedNewPeerFuture) -> PeerConstructor {
    PeerConstructor::ServeOnce(x)
}
pub fn multi(x:BoxedNewPeerStream) -> PeerConstructor {
    PeerConstructor::ServeMultipleTimes(x)
}

pub fn peer_err<E: std::error::Error + 'static>(e : E) -> BoxedNewPeerFuture {
    Box::new(futures::future::err(Box::new(e) as Box<std::error::Error>)) as BoxedNewPeerFuture
}
pub fn peer_err_s<E: std::error::Error + 'static>(e : E) -> BoxedNewPeerStream {
    Box::new(
        futures::stream::iter_result(vec![Err(Box::new(e) as Box<std::error::Error>)])
    ) as BoxedNewPeerStream
}
pub fn peer_strerr(e : &str) -> BoxedNewPeerFuture {
    let q : Box<std::error::Error> = From::from(e);
    Box::new(futures::future::err(q)) as BoxedNewPeerFuture
}
pub fn box_up_err<E: std::error::Error + 'static>(e : E) -> Box<std::error::Error> {
    Box::new(e) as Box<std::error::Error>
}

impl Peer {
    fn new<R:AsyncRead+'static, W:AsyncWrite+'static>(r:R, w:W) -> Self {
        Peer (
            Box::new(r) as Box<AsyncRead>,
            Box::new(w) as Box<AsyncWrite>,
        )
    }
}

pub use specparse::boxup;
pub use specparse::spec;

pub fn peer_from_str(ps: &mut ProgramState, handle: &Handle, s: &str) -> PeerConstructor {
    let spec = match spec(s) {
        Ok(x) => x,
        Err(e) => return once(Box::new(futures::future::err(e)) as BoxedNewPeerFuture),
    };
    spec.construct(handle, ps)
}

pub struct Transfer {
    from: Box<AsyncRead>,
    to:   Box<AsyncWrite>,
}
pub struct Session(Transfer,Transfer);

impl Session {
    pub fn run(self) -> Box<Future<Item=(),Error=Box<std::error::Error>>> {
        let f1 = my_copy::copy(self.0.from, self.0.to, true);
        let f2 = my_copy::copy(self.1.from, self.1.to, true);
        let f1 = f1.map(|(_,r,mut w)|{
            info!("Forward finished");
            let _ = w.shutdown();
            std::mem::drop(r);
            std::mem::drop(w);
        });
        let f2 = f2.map(|(_,r,mut w)|{
            info!("Reverse finished");
            let _ = w.shutdown();
            std::mem::drop(r);
            std::mem::drop(w);
        });
        Box::new(
            f1.join(f2)
            .map(|(_,_)|{
                info!("Finished");
            })
            .map_err(|x|  Box::new(x) as Box<std::error::Error> )
        ) as Box<Future<Item=(),Error=Box<std::error::Error>>>
    }
    pub fn new(peer1: Peer, peer2: Peer) -> Self {
        Session (
            Transfer {
                from: peer1.0,
                to: peer2.1,
            },
            Transfer {
                from: peer2.0,
                to: peer1.1,
            },
        )
    }
}

pub fn serve<S1, S2, OE>(h: Handle, s1: S1, s2 : S2, opts: Options, onerror: std::rc::Rc<OE>)
    -> Box<Future<Item=(), Error=()>>
    where S1 : Specifier + 'static, S2: Specifier + 'static, OE : Fn(Box<std::error::Error>) -> () + 'static
{
    info!("Serving {:?} to {:?} with {:?}", s1, s2, opts);
    let mut ps = ProgramState::default();

    use PeerConstructor::{ServeMultipleTimes, ServeOnce};

    let h1 = h.clone();
    let h2 = h.clone();

    let e1 = onerror.clone();
    let e2 = onerror.clone();
    let e3 = onerror.clone();

    let left = s1.construct(&h, &mut ps);
    let prog = match left {
        ServeMultipleTimes(stream) => {
            let runner = stream
            .map(move |peer1| {
                let e1_1 = e1.clone();
                h1.spawn(
                    s2.construct(&h1, &mut ps)
                    .get_only_first_conn()
                    .and_then(move |peer2| {
                        let s = Session::new(peer1,peer2);
                        s.run()
                    })
                    .map_err(move|e|e1_1(e))
                )
            }).for_each(|()|futures::future::ok(()));
            Box::new(runner.map_err(move|e|e2(e))) as Box<Future<Item=(), Error=()>>
        },
        ServeOnce(peer1c) => {
            let runner = peer1c
            .and_then(move |peer1| {
                let right = s2.construct(&h2, &mut ps);
                let fut = right.get_only_first_conn();
                fut.and_then(move |peer2| {
                    let s = Session::new(peer1,peer2);
                    s.run().map(|()| {
                        ::std::mem::drop(ps)
                        // otherwise ps will be dropped sooner
                        // and stdin/stdout may become blocking sooner
                    })
                })
            });
            Box::new(runner.map_err(move |e|e3(e))) as Box<Future<Item=(), Error=()>>
        },
    };
    prog
}

<commit_msg>Remove visitors from Specifier<commit_after>//! Note: library usage is not semver/API-stable
//!
//! Type evolution of a websocat run:
//!
//! 1. `&str` - string as passed to command line
//! 2. `Specifier` - more organized representation, maybe nested
//! 3. `PeerConstructor` - a future or stream that returns one or more connections
//! 4. `Peer` - one active connection
//! 5. `Transfer` - two peers recombine into two (if bidirectional) transfers
//! 6. `Session` - a running websocat connection from one specifier to another

extern crate futures;
extern crate tokio_core;
#[macro_use]
extern crate tokio_io;
extern crate websocket;

#[macro_use]
extern crate log;

use tokio_core::reactor::{Handle};
use futures::future::Future;
use tokio_io::{AsyncRead,AsyncWrite};

use futures::Stream;

use std::rc::Rc;

type Result<T> = std::result::Result<T, Box<std::error::Error>>;

fn wouldblock<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::WouldBlock, ""))
}
fn brokenpipe<T>() -> std::io::Result<T> {
    Err(std::io::Error::new(std::io::ErrorKind::BrokenPipe, ""))
}
fn io_other_error<E : std::error::Error + Send + Sync + 'static>(e:E) -> std::io::Error {
    std::io::Error::new(std::io::ErrorKind::Other,e)
}

pub use lints::ConfigurationConcern;

pub struct WebsocatConfiguration {
    pub opts : Options,
    pub s1 : Rc<Specifier>,
    pub s2: Rc<Specifier>,
}

impl WebsocatConfiguration {
    pub fn serve<OE>(self, h: Handle, onerror: std::rc::Rc<OE>)
        -> Box<Future<Item=(), Error=()>>
        where OE : Fn(Box<std::error::Error>) -> () + 'static
    {
        serve(h, self.s1,self.s2, self.opts, onerror)
    }
}

#[derive(Default,Debug)]
pub struct Options {
}

#[derive(Default)]
pub struct ProgramState {
    #[cfg(all(unix,not(feature="no_unix_stdio")))]
    stdio : stdio_peer::GlobalState,

    reuser: connection_reuse_peer::GlobalState,
}

pub struct Peer(Box<AsyncRead>, Box<AsyncWrite>);

pub type BoxedNewPeerFuture = Box<Future<Item=Peer, Error=Box<std::error::Error>>>;
pub type BoxedNewPeerStream = Box<Stream<Item=Peer, Error=Box<std::error::Error>>>;

/// For checking specifier combinations for problems
#[derive(Eq,PartialEq,Debug,Clone,Copy)]
pub enum SpecifierType {
    Stdio,
    Reuser,
    Other,
}

#[derive(Debug,Clone,Copy)]
pub struct OneSpecifierInfo {
    pub multiconnect: bool,
    pub uses_global_state: bool,
    pub typ: SpecifierType,
}

#[derive(Debug,Clone)]
pub struct SpecifierInfo {
    pub this: OneSpecifierInfo,
    pub subspecifier: Option<Box<SpecifierInfo>>,
}

impl SpecifierInfo {
    fn collect(&self) -> Vec<OneSpecifierInfo> {
        let mut r = vec![];
        r.push(self.this);
        let mut ss = &self.subspecifier;
        while let Some(sub) = ss {
            r.push(sub.this);
            ss = &sub.subspecifier;
        }
        r
    }
}

/// A parsed command line argument.
/// For example, `ws-listen:tcp-l:127.0.0.1:8080` gets parsed into
/// a `WsUpgrade(TcpListen(SocketAddr))`.
pub trait Specifier : std::fmt::Debug {
    /// Apply the specifier for constructing a "socket" or other connecting device.
    fn construct(&self, h:&Handle, ps: &mut ProgramState) -> PeerConstructor;

    // Specified by `specifier_boilerplate!`:
    fn is_multiconnect(&self) -> bool;
    fn uses_global_state(&self) -> bool;
    fn get_type(&self) -> SpecifierType;

    // May be overridden by `self_0_is_subspecifier`:
    fn get_info(&self) -> SpecifierInfo {
        SpecifierInfo {
            this: self.get_info_without_subspecs(),
            subspecifier: None,
        }
    }

    // Provided:
    fn get_info_without_subspecs(&self) -> OneSpecifierInfo {
        OneSpecifierInfo {
            multiconnect: self.is_multiconnect(),
            uses_global_state: self.uses_global_state(),
            typ: self.get_type(),
        }
    }
}

impl Specifier for Rc<Specifier> {
    fn construct(&self, h:&Handle, ps: &mut ProgramState) -> PeerConstructor {
        (**self).construct(h, ps)
    }

    fn is_multiconnect(&self) -> bool { (**self).is_multiconnect() }
    fn get_type(&self) -> SpecifierType { (**self).get_type() }
    fn uses_global_state(&self) -> bool { (**self).uses_global_state() }

    fn get_info_without_subspecs(&self) -> OneSpecifierInfo { (**self).get_info_without_subspecs() }
    fn get_info(&self) -> SpecifierInfo { (**self).get_info() }
}

macro_rules! specifier_boilerplate {
    (singleconnect $($e:tt)*) => {
        fn is_multiconnect(&self) -> bool { false }
        specifier_boilerplate!($($e)*);
    };
    (multiconnect $($e:tt)*) => {
        fn is_multiconnect(&self) -> bool { true }
        specifier_boilerplate!($($e)*);
    };
    (no_subspec $($e:tt)*) => {
        specifier_boilerplate!($($e)*);
    };
    (has_subspec $($e:tt)*) => {
        specifier_boilerplate!($($e)*);
    };
    (typ=$tn:ident $($e:tt)*) => {
        fn get_type(&self) -> $crate::SpecifierType { $crate::SpecifierType::$tn }
        specifier_boilerplate!($($e)*);
    };
    () => {
    };
    (globalstate $($e:tt)*) => {
        fn uses_global_state(&self) -> bool { true }
        specifier_boilerplate!($($e)*);
    };
    (noglobalstate $($e:tt)*) => {
        fn uses_global_state(&self) -> bool { false }
        specifier_boilerplate!($($e)*);
    };
}

macro_rules! self_0_is_subspecifier {
    (...) => {
        fn get_info(&self) -> $crate::SpecifierInfo {
            $crate::SpecifierInfo {
                this: self.get_info_without_subspecs(),
                subspecifier: Some(Box::new(self.0.get_info())),
            }
        }
    };
    (proxy_is_multiconnect) => {
        self_0_is_subspecifier!(...);
        fn is_multiconnect(&self) -> bool { self.0.is_multiconnect() }
    };
}

mod my_copy;
pub mod lints;

#[cfg(all(unix,not(feature="no_unix_stdio")))]
pub mod stdio_peer;

pub mod ws_peer;
pub mod ws_server_peer;
pub mod ws_client_peer;
pub mod net_peer;
pub mod stdio_threaded_peer;
pub mod connection_reuse_peer;
pub mod mirror_peer;
pub mod trivial_peer;
pub mod reconnect_peer;

pub mod specparse;

pub enum PeerConstructor {
    ServeOnce(BoxedNewPeerFuture),
    ServeMultipleTimes(BoxedNewPeerStream),
}

impl PeerConstructor {
    pub fn map<F:'static>(self, f : F) -> Self
            where F:FnMut(Peer) -> BoxedNewPeerFuture
    {
        use PeerConstructor::*;
        match self {
            ServeOnce(x) => ServeOnce(Box::new(x.and_then(f)) as BoxedNewPeerFuture),
            ServeMultipleTimes(s) => ServeMultipleTimes(
                Box::new(
                    s.and_then(f)
                ) as BoxedNewPeerStream
            )
        }
    }

    pub fn get_only_first_conn(self) -> BoxedNewPeerFuture {
        use PeerConstructor::*;
        match self {
            ServeMultipleTimes(stre) => {
                Box::new(
                    stre
                    .into_future()
                    .map(move |(std_peer,_)| {
                        let peer2 = std_peer.expect("Nowhere to connect it");
                        peer2
                    })
                    .map_err(|(e,_)|e)
                ) as BoxedNewPeerFuture
            },
            ServeOnce(future) => {
                future
            },
        }
    }
}

/// A `Read` utility to deal with partial reads
#[derive(Default)]
pub struct ReadDebt(pub Option<Vec<u8>>);

impl ReadDebt {
    pub fn process_message(&mut self, buf: &mut [u8], buf_in: &[u8]) -> std::result::Result<usize, std::io::Error> {
        assert_eq!(self.0, None);
        let l = buf_in.len().min(buf.len());
        buf[..l].copy_from_slice(&buf_in[..l]);

        if l < buf_in.len() {
            self.0 = Some(buf_in[l..].to_vec());
        }

        Ok(l)
    }
    pub fn check_debt(&mut self, buf: &mut [u8]) -> Option<std::result::Result<usize, std::io::Error>>       {
        if let Some(debt) = self.0.take() {
            Some(self.process_message(buf, debt.as_slice()))
        } else {
            None
        }
    }
}

pub fn once(x:BoxedNewPeerFuture) -> PeerConstructor {
    PeerConstructor::ServeOnce(x)
}
pub fn multi(x:BoxedNewPeerStream) -> PeerConstructor {
    PeerConstructor::ServeMultipleTimes(x)
}

pub fn peer_err<E: std::error::Error + 'static>(e : E) -> BoxedNewPeerFuture {
    Box::new(futures::future::err(Box::new(e) as Box<std::error::Error>)) as BoxedNewPeerFuture
}
pub fn peer_err_s<E: std::error::Error + 'static>(e : E) -> BoxedNewPeerStream {
    Box::new(
        futures::stream::iter_result(vec![Err(Box::new(e) as Box<std::error::Error>)])
    ) as BoxedNewPeerStream
}
pub fn peer_strerr(e : &str) -> BoxedNewPeerFuture {
    let q : Box<std::error::Error> = From::from(e);
    Box::new(futures::future::err(q)) as BoxedNewPeerFuture
}
pub fn box_up_err<E: std::error::Error + 'static>(e : E) -> Box<std::error::Error> {
    Box::new(e) as Box<std::error::Error>
}

impl Peer {
    fn new<R:AsyncRead+'static, W:AsyncWrite+'static>(r:R, w:W) -> Self {
        Peer (
            Box::new(r) as Box<AsyncRead>,
            Box::new(w) as Box<AsyncWrite>,
        )
    }
}

pub use specparse::boxup;
pub use specparse::spec;

pub fn peer_from_str(ps: &mut ProgramState, handle: &Handle, s: &str) -> PeerConstructor {
    let spec = match spec(s) {
        Ok(x) => x,
        Err(e) => return once(Box::new(futures::future::err(e)) as BoxedNewPeerFuture),
    };
    spec.construct(handle, ps)
}

pub struct Transfer {
    from: Box<AsyncRead>,
    to:   Box<AsyncWrite>,
}
pub struct Session(Transfer,Transfer);

impl Session {
    pub fn run(self) -> Box<Future<Item=(),Error=Box<std::error::Error>>> {
        let f1 = my_copy::copy(self.0.from, self.0.to, true);
        let f2 = my_copy::copy(self.1.from, self.1.to, true);
        let f1 = f1.map(|(_,r,mut w)|{
            info!("Forward finished");
            let _ = w.shutdown();
            std::mem::drop(r);
            std::mem::drop(w);
        });
        let f2 = f2.map(|(_,r,mut w)|{
            info!("Reverse finished");
            let _ = w.shutdown();
            std::mem::drop(r);
            std::mem::drop(w);
        });
        Box::new(
            f1.join(f2)
            .map(|(_,_)|{
                info!("Finished");
            })
            .map_err(|x|  Box::new(x) as Box<std::error::Error> )
        ) as Box<Future<Item=(),Error=Box<std::error::Error>>>
    }
    pub fn new(peer1: Peer, peer2: Peer) -> Self {
        Session (
            Transfer {
                from: peer1.0,
                to: peer2.1,
            },
            Transfer {
                from: peer2.0,
                to: peer1.1,
            },
        )
    }
}

pub fn serve<S1, S2, OE>(h: Handle, s1: S1, s2 : S2, opts: Options, onerror: std::rc::Rc<OE>)
    -> Box<Future<Item=(), Error=()>>
    where S1 : Specifier + 'static, S2: Specifier + 'static, OE : Fn(Box<std::error::Error>) -> () + 'static
{
    info!("Serving {:?} to {:?} with {:?}", s1, s2, opts);
    let mut ps = ProgramState::default();

    use PeerConstructor::{ServeMultipleTimes, ServeOnce};

    let h1 = h.clone();
    let h2 = h.clone();

    let e1 = onerror.clone();
    let e2 = onerror.clone();
    let e3 = onerror.clone();

    let left = s1.construct(&h, &mut ps);
    let prog = match left {
        ServeMultipleTimes(stream) => {
            let runner = stream
            .map(move |peer1| {
                let e1_1 = e1.clone();
                h1.spawn(
                    s2.construct(&h1, &mut ps)
                    .get_only_first_conn()
                    .and_then(move |peer2| {
                        let s = Session::new(peer1,peer2);
                        s.run()
                    })
                    .map_err(move|e|e1_1(e))
                )
            }).for_each(|()|futures::future::ok(()));
            Box::new(runner.map_err(move|e|e2(e))) as Box<Future<Item=(), Error=()>>
        },
        ServeOnce(peer1c) => {
            let runner = peer1c
            .and_then(move |peer1| {
                let right = s2.construct(&h2, &mut ps);
                let fut = right.get_only_first_conn();
                fut.and_then(move |peer2| {
                    let s = Session::new(peer1,peer2);
                    s.run().map(|()| {
                        ::std::mem::drop(ps)
                        // otherwise ps will be dropped sooner
                        // and stdin/stdout may become blocking sooner
                    })
                })
            });
            Box::new(runner.map_err(move |e|e3(e))) as Box<Future<Item=(), Error=()>>
        },
    };
    prog
}

<|endoftext|>