<commit_before>
use std::fmt::Write;

/*
macro_rules! js_args {
    ($w:expr, ) => (());
    ($args:tt) => (concat!["(", $args, ");"]);
}

macro_rules! js_call {
    ($func_name:ident, $($args:tt)*) => (concat![stringify![$func_name], $($args)*]);
}

macro_rules! do_jsr_call {
    ($func_name:ident, $element_type:ident, @single $($args:tt)*) => { concat!(stringify!($func_name), $(stringify!($args))*) };
    ($func_name:ident, $element_type:ident, @count $($rest:expr),*) => { ... };
}
*/

macro_rules! script_src {
    ($uri:expr) => (concat![""])
}

macro_rules! jsr_call {
    // text node
    (text, $text:tt) => {
        concat!("IncrementalDOM.text('", $text, "');")
    };

    // element without attributes
    ($func_name:ident, $element_type:ident) => {
        concat!("IncrementalDOM.", stringify!($func_name), "('", stringify!($element_type), "');") };

    // element with attributes
    ($func_name:ident, $element_type:ident, $($key:ident => $value:expr,)+) => {
        concat!("IncrementalDOM.", stringify!($func_name), "('", stringify!($element_type), "', ",
            "[", $("'", stringify!($key), "', ", stringify!($value), ", "),*, "]); ") };
    ($func_name:ident, $element_type:ident, $($key:ident => $value:expr),*) => {
        concat!("IncrementalDOM.", stringify!($func_name), "('", stringify!($element_type), "', ",
            "[", $("'", stringify!($key), "', ", stringify!($value), ", "),*, "]); ") };
}

macro_rules! response {
    () => ("");
}

macro_rules! output_rust_call {
    ($w:expr, elementOpen $element_type:ident) => { write!($w, "<{}>", stringify!($element_type)); };
    ($w:expr, elementClose $element_type:ident) => { write!($w, "<{}>", stringify!($element_type)); };
    ($w:expr, text $text:tt) => { write!($w, "{}", $text); };
}

macro_rules! output_js_call {
    ($w:expr, elementOpen $element_type:ident) => { write!($w, "{}", jsr_call!(elementOpen, $element_type)); };
    ($w:expr, elementClose $element_type:ident) => { write!($w, "{}", jsr_call!(elementClose, $element_type)); };
    ($w:expr, text $text:tt) => { write!($w, "{}", jsr_call!(text, $text)); };

    ($w:expr, render_on_load $template_name:ident) => {
        write!($w, "document.addEventListener('DOMContentLoaded', function() {{ IncrementalDOM.patch(document.querySelector('#{}'), template_{}); }});",
            stringify!($template_name), stringify!($template_name));
    };
}

macro_rules! incr_template_gen {
    ($js:expr, $rs:expr, view $template_name:ident [ $($inner:tt)* ] $($rest:tt)*) => {
        // Output JS function and Rust code
        write!($js, "function template_{}() {{", stringify!($template_name));
            incr_template_gen!($js, $rs, $($inner)*);
        write!($js, "}};")
    };

    ($js:expr, $rs:expr) => ("");
    ($js:expr, $rs:expr, $text:tt) => (
        output_js_call!($js, text $text);
        output_rust_call!($rs, text $text);
    );

    ($js:expr, $rs:expr, $element_type:ident [ $($inner:tt)* ] $($rest:tt)*) => {
        output_js_call!($js, elementOpen $element_type);
        output_rust_call!($rs, elementOpen $element_type);

        incr_template_gen!($js, $rs, $($inner)*);

        output_js_call!($js, elementClose $element_type);
        output_rust_call!($rs, elementClose $element_type);
    };
}

macro_rules! incr_template {
    (view $template_name:ident [ ]) => { concat!["function template_", stringify!($template_name), "(){};"] };
    (view $template_name:ident [ $($inner:tt)* ] $($rest:tt)*) => { concat!["function template_", stringify!($template_name), "(){", incr_template!($($inner)*), "};"] };

    () => ("");
    ($e:tt) => ( concat!["IncrementalDOM.text('", $e, "');"] );

    ($element_type:ident [ $($inner:tt)* ] $($rest:tt)*) => { concat![
        jsr_call!(elementOpen, $element_type),
            incr_template!($($inner)*),
        jsr_call!(elementClose, $element_type),
        incr_template!($($rest)*)
    ]};
}

fn render_rust_and_js_template(js: &mut String) -> String {
    emit_rust_and_js_template!(&mut js,
        view root [
            h1 [ {"Heading"}]

            p [ {"testing"} ]
        ]
    )
}

fn render_template() -> String {
    emit_rust_template!(
        view root [
            h1 [ {"Heading"}]

            p [ {"testing"} ]
        ]
    )
}

fn render_page(page: &mut String) {
    let mut js = String::new();
    let mut rs = String::new();

    // Populate js and rs variables
    //    incr_template_gen!(&mut js, &mut rs, view root [ p [ "test" ] ]);
    //    output_js_call!(&mut js, render_on_load root);

    // Render Rust and JS template
        let s = render_rust_and_js_template(&mut js);
        println!("Contents: [{}]", s);

    // HTML template
        write!(page, "<title>incrust demo</title>");
        write!(page, script_src!("/assets/js/incremental-dom.js"));
        write!(page, "
{}

{}

{}
", s, rs, js);

    // TODO: Renable this once the Rust output HTML and IncrementalDOM rendering match
        write!(page, "", js);
}

pub fn render() -> String {
    let mut page = String::new();

    render_page(&mut page);

    page
}<commit_msg>Remove rs output variable<commit_after>
use std::fmt::Write;

/*
macro_rules! js_args {
    ($w:expr, ) => (());
    ($args:tt) => (concat!["(", $args, ");"]);
}

macro_rules! js_call {
    ($func_name:ident, $($args:tt)*) => (concat![stringify![$func_name], $($args)*]);
}

macro_rules! do_jsr_call {
    ($func_name:ident, $element_type:ident, @single $($args:tt)*) => { concat!(stringify!($func_name), $(stringify!($args))*) };
    ($func_name:ident, $element_type:ident, @count $($rest:expr),*) => { ... };
}
*/

macro_rules! script_src {
    ($uri:expr) => (concat![""])
}

macro_rules! jsr_call {
    // text node
    (text, $text:tt) => {
        concat!("IncrementalDOM.text('", $text, "');")
    };

    // element without attributes
    ($func_name:ident, $element_type:ident) => {
        concat!("IncrementalDOM.", stringify!($func_name), "('", stringify!($element_type), "');") };

    // element with attributes
    ($func_name:ident, $element_type:ident, $($key:ident => $value:expr,)+) => {
        concat!("IncrementalDOM.", stringify!($func_name), "('", stringify!($element_type), "', ",
            "[", $("'", stringify!($key), "', ", stringify!($value), ", "),*, "]); ") };
    ($func_name:ident, $element_type:ident, $($key:ident => $value:expr),*) => {
        concat!("IncrementalDOM.", stringify!($func_name), "('", stringify!($element_type), "', ",
            "[", $("'", stringify!($key), "', ", stringify!($value), ", "),*, "]); ") };
}

macro_rules! response {
    () => ("");
}

macro_rules! output_rust_call {
    ($w:expr, elementOpen $element_type:ident) => { write!($w, "<{}>", stringify!($element_type)); };
    ($w:expr, elementClose $element_type:ident) => { write!($w, "<{}>", stringify!($element_type)); };
    ($w:expr, text $text:tt) => { write!($w, "{}", $text); };
}

macro_rules! output_js_call {
    ($w:expr, elementOpen $element_type:ident) => { write!($w, "{}", jsr_call!(elementOpen, $element_type)); };
    ($w:expr, elementClose $element_type:ident) => { write!($w, "{}", jsr_call!(elementClose, $element_type)); };
    ($w:expr, text $text:tt) => { write!($w, "{}", jsr_call!(text, $text)); };

    ($w:expr, render_on_load $template_name:ident) => {
        write!($w, "document.addEventListener('DOMContentLoaded', function() {{ IncrementalDOM.patch(document.querySelector('#{}'), template_{}); }});",
            stringify!($template_name), stringify!($template_name));
    };
}

macro_rules! incr_template_gen {
    ($js:expr, $rs:expr, view $template_name:ident [ $($inner:tt)* ] $($rest:tt)*) => {
        // Output JS function and Rust code
        write!($js, "function template_{}() {{", stringify!($template_name));
            incr_template_gen!($js, $rs, $($inner)*);
        write!($js, "}};")
    };

    ($js:expr, $rs:expr) => ("");
    ($js:expr, $rs:expr, $text:tt) => (
        output_js_call!($js, text $text);
        output_rust_call!($rs, text $text);
    );

    ($js:expr, $rs:expr, $element_type:ident [ $($inner:tt)* ] $($rest:tt)*) => {
        output_js_call!($js, elementOpen $element_type);
        output_rust_call!($rs, elementOpen $element_type);

        incr_template_gen!($js, $rs, $($inner)*);

        output_js_call!($js, elementClose $element_type);
        output_rust_call!($rs, elementClose $element_type);
    };
}

macro_rules! incr_template {
    (view $template_name:ident [ ]) => { concat!["function template_", stringify!($template_name), "(){};"] };
    (view $template_name:ident [ $($inner:tt)* ] $($rest:tt)*) => { concat!["function template_", stringify!($template_name), "(){", incr_template!($($inner)*), "};"] };

    () => ("");
    ($e:tt) => ( concat!["IncrementalDOM.text('", $e, "');"] );

    ($element_type:ident [ $($inner:tt)* ] $($rest:tt)*) => { concat![
        jsr_call!(elementOpen, $element_type),
            incr_template!($($inner)*),
        jsr_call!(elementClose, $element_type),
        incr_template!($($rest)*)
    ]};
}

fn render_rust_and_js_template(js: &mut String) -> String {
    emit_rust_and_js_template!(&mut js,
        view root [
            h1 [ {"Heading"}]

            p [ {"testing"} ]
        ]
    )
}

fn render_template() -> String {
    emit_rust_template!(
        view root [
            h1 [ {"Heading"}]

            p [ {"testing"} ]
        ]
    )
}

fn render_page(page: &mut String) {
    let mut js = String::new();

    // Render Rust and JS template
        let s = render_rust_and_js_template(&mut js);
        println!("Contents: [{}]", s);

    // HTML template
        write!(page, "<title>incrust demo</title>");
        write!(page, script_src!("/assets/js/incremental-dom.js"));
        write!(page, "
{}

{}
", s, js);

    // TODO: Renable this once the Rust output HTML and IncrementalDOM rendering match
        write!(page, "", js);
}

pub fn render() -> String {
    let mut page = String::new();

    render_page(&mut page);

    page
}<|endoftext|>


<commit_before>extern crate piston_window;

fn main() {
    let window: piston_window::PistonWindow = piston_window::WindowSettings::new("piston-tutorial", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

    for _e in window {
        break;
    }
}
<commit_msg>Break has been removed<commit_after>extern crate piston_window;

fn main() {
    let window: piston_window::PistonWindow = piston_window::WindowSettings::new("piston-tutorial", [600, 600])
        .exit_on_esc(true)
        .build()
        .unwrap();

    for _e in window {
    }
}
<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::event::Event;
use sdl2::keyboard::Keycode;

fn main() {
    let context = sdl2::init().unwrap();
    let video = context.video().unwrap();

    let window = video.window("rrthozopsi", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();
    let mut event_pump = context.event_pump().unwrap();

    let mut timer = context.timer().unwrap();
    let mut frames = 0;
    let mut start_time = timer.ticks();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }

        renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 0));
        renderer.clear();
        renderer.present();

        frames += 1;

        let current_time = timer.ticks();
        let diff_time = current_time - start_time;
        if diff_time > 250
        {
            println!("FPS: {}", frames / diff_time);
            start_time = current_time;
            frames = 0;
        }
    }
}
<commit_msg>FPS implementation fix<commit_after>extern crate sdl2;

use sdl2::event::Event;
use sdl2::keyboard::Keycode;

fn main() {
    let context = sdl2::init().unwrap();
    let video = context.video().unwrap();

    let window = video.window("rrthozopsi", 800, 600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();

    let mut renderer = window.renderer().build().unwrap();
    let mut event_pump = context.event_pump().unwrap();

    let mut timer = context.timer().unwrap();
    let mut fps = 0;
    let mut start_time = timer.ticks();

    'running: loop {
        for event in event_pump.poll_iter() {
            match event {
                Event::Quit {..} | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => {
                    break 'running
                },
                _ => {}
            }
        }

        renderer.set_draw_color(sdl2::pixels::Color::RGB(255, 0, 0));
        renderer.clear();
        renderer.present();

        fps += 1;

        let current_time = timer.ticks();
        let diff_time = current_time - start_time;
        if diff_time > 1_000
        {
            println!("FPS: {}", fps);
            start_time = current_time;
            fps = 0;
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;

use super::*;

pub struct MercurySender {
    mercury: MercuryManager,
    uri: String,
    pending: VecDeque<MercuryFuture<MercuryResponse>>,
}

impl MercurySender {
    // TODO: pub(super) when stable
    pub(crate) fn new(mercury: MercuryManager, uri: String) -> MercurySender {
        MercurySender {
            mercury,
            uri,
            pending: VecDeque::new(),
        }
    }

    pub fn is_flushed(&self) -> bool {
        self.pending.is_empty()
    }

    pub fn send(&mut self, item: Vec<u8>) {
        let task = self.mercury.send(self.uri.clone(), item);
        self.pending.push_back(task);
    }

    pub async fn flush(&mut self) -> Result<(), MercuryError> {
        for fut in self.pending.drain(..) {
            fut.await?;
        }
        Ok(())
    }
}

impl Clone for MercurySender {
    fn clone(&self) -> MercurySender {
        MercurySender {
            mercury: self.mercury.clone(),
            uri: self.uri.clone(),
            pending: VecDeque::new(),
        }
    }
}
<commit_msg>Fix bug in MercurySender<commit_after>use std::collections::VecDeque;

use super::*;

pub struct MercurySender {
    mercury: MercuryManager,
    uri: String,
    pending: VecDeque<MercuryFuture<MercuryResponse>>,
    buffered_future: Option<MercuryFuture<MercuryResponse>>,
}

impl MercurySender {
    pub(crate) fn new(mercury: MercuryManager, uri: String) -> MercurySender {
        MercurySender {
            mercury,
            uri,
            pending: VecDeque::new(),
            buffered_future: None,
        }
    }

    pub fn is_flushed(&self) -> bool {
        self.buffered_future.is_none() && self.pending.is_empty()
    }

    pub fn send(&mut self, item: Vec<u8>) {
        let task = self.mercury.send(self.uri.clone(), item);
        self.pending.push_back(task);
    }

    pub async fn flush(&mut self) -> Result<(), MercuryError> {
        if self.buffered_future.is_none() {
            self.buffered_future = self.pending.pop_front();
        }

        while let Some(fut) = self.buffered_future.as_mut() {
            fut.await?;
            self.buffered_future = self.pending.pop_front();
        }
        Ok(())
    }
}

impl Clone for MercurySender {
    fn clone(&self) -> MercurySender {
        MercurySender {
            mercury: self.mercury.clone(),
            uri: self.uri.clone(),
            pending: VecDeque::new(),
            buffered_future: None,
        }
    }
}
<|endoftext|>


<commit_before>#![feature(core_intrinsics)]
use std::fs::File;
use std::io::{BufRead, BufReader};

use std::intrinsics::unlikely;

const VALUE: [u64; 256] = {
    let mut array = [0u64; 256];
    array[b'A' as usize] = 1;
    array[b'T' as usize] = 1;
    array[b'G' as usize] = 1 << 32;
    array[b'C' as usize] = 1 << 32;
    array
};

fn main() {
    let filename = "Homo_sapiens.GRCh37.67.dna_rm.chromosome.Y.fa";

    let file = File::open(filename).unwrap();
    let mut reader = BufReader::new(file);

    let mut totals = 0u64;
    let mut line = Vec::with_capacity(100);
    loop {
        if unlikely(reader.read_until(b'\n', &mut line).expect("error reading") == 0) {
            break;
        }

        if unlikely(line[0] == b'>') {
            line.clear();
            continue;
        }

        for c in line.iter() {
            totals += VALUE[*c as usize];
        }
        line.clear();
    }
    let at = totals & 0xFFFFFFFF;
    let gc = totals >> 32;
    let gc_ratio: f64 = gc as f64 / (gc as f64 + at as f64);
    println!("GC ratio (gc/(gc+at)): {}", gc_ratio);
}
<commit_msg>Use new chry<commit_after>#![feature(core_intrinsics)]
use std::fs::File;
use std::io::{BufRead, BufReader};

use std::intrinsics::unlikely;

const VALUE: [u64; 256] = {
    let mut array = [0u64; 256];
    array[b'A' as usize] = 1;
    array[b'T' as usize] = 1;
    array[b'G' as usize] = 1 << 32;
    array[b'C' as usize] = 1 << 32;
    array
};

fn main() {
    let filename = "chry_multiplied.fa";

    let file = File::open(filename).unwrap();
    let mut reader = BufReader::new(file);

    let mut totals = 0u64;
    let mut line = Vec::with_capacity(100);
    loop {
        if unlikely(reader.read_until(b'\n', &mut line).expect("error reading") == 0) {
            break;
        }

        if unlikely(line[0] == b'>') {
            line.clear();
            continue;
        }

        for c in line.iter() {
            totals += VALUE[*c as usize];
        }
        line.clear();
    }
    let at = totals & 0xFFFFFFFF;
    let gc = totals >> 32;
    let gc_ratio: f64 = gc as f64 / (gc as f64 + at as f64);
    println!("GC ratio (gc/(gc+at)): {}", gc_ratio);
}
<|endoftext|>


<commit_before>#![ cfg_attr( not( feature = "use_std"), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/woptions_meta/latest/woptions_meta/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

//!
//! Mechanism to define map of options for a fuction and its defaults laconically.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

// extern crate proc_macro_tools;
// mod former;
mod options;

// ///
// /// Attribute macro to generate options adapter and its implementation for structure option.
// ///
//
// #[ allow( non_snake_case ) ]
// #[ proc_macro_attribute ]
// pub fn Options( attr : proc_macro::TokenStream, item : proc_macro::TokenStream ) -> proc_macro::TokenStream
// {
//   let result = options::options( attr, item );
//   match result
//   {
//     Ok( stream ) => stream.into(),
//     Err( err ) => err.to_compile_error().into(),
//   }
// }

///
/// Function-like macro to generate options adapter and its implementation for structure option.
///

#[ allow( non_snake_case ) ]
#[ proc_macro ]
pub fn Options( item : proc_macro::TokenStream ) -> proc_macro::TokenStream
{
  let attr = proc_macro::TokenStream::new();
  let result = options::options( attr, item );
  match result
  {
    Ok( stream ) => stream.into(),
    Err( err ) => err.to_compile_error().into(),
  }
}
<commit_msg>Fix module `woptions_meta`, compile module under feature `use_std`<commit_after>#![ cfg_attr( not( feature = "use_std"), no_std ) ]
#![ doc( html_logo_url = "https://raw.githubusercontent.com/Wandalen/wTools/master/asset/img/logo_v3_trans_square.png" ) ]
#![ doc( html_favicon_url = "https://raw.githubusercontent.com/Wandalen/wTools/alpha/asset/img/logo_v3_trans_square_icon_small_v2.ico" ) ]
#![ doc( html_root_url = "https://docs.rs/woptions_meta/latest/woptions_meta/" ) ]
#![ warn( rust_2018_idioms ) ]
#![ warn( missing_debug_implementations ) ]
#![ warn( missing_docs ) ]

//!
//! Mechanism to define map of options for a fuction and its defaults laconically.
//!

#![ doc = include_str!( concat!( env!( "CARGO_MANIFEST_DIR" ), "/Readme.md" ) ) ]

// extern crate proc_macro_tools;
// mod former;
#[ cfg( feature = "use_std" ) ]
mod options;

// ///
// /// Attribute macro to generate options adapter and its implementation for structure option.
// ///
//
// #[ allow( non_snake_case ) ]
// #[ proc_macro_attribute ]
// pub fn Options( attr : proc_macro::TokenStream, item : proc_macro::TokenStream ) -> proc_macro::TokenStream
// {
//   let result = options::options( attr, item );
//   match result
//   {
//     Ok( stream ) => stream.into(),
//     Err( err ) => err.to_compile_error().into(),
//   }
// }

///
/// Function-like macro to generate options adapter and its implementation for structure option.
///

#[ cfg( feature = "use_std" ) ]
#[ allow( non_snake_case ) ]
#[ proc_macro ]
pub fn Options( item : proc_macro::TokenStream ) -> proc_macro::TokenStream
{
  let attr = proc_macro::TokenStream::new();
  let result = options::options( attr, item );
  match result
  {
    Ok( stream ) => stream.into(),
    Err( err ) => err.to_compile_error().into(),
  }
}
<|endoftext|>


<commit_before>use super::{Selection, UIState, WatchState};
use crate::err::{self, Result};
use crate::util;
use chrono::{Duration, Utc};
use smallvec::SmallVec;
use snafu::ResultExt;
use std::collections::VecDeque;
use std::fmt;
use std::io;
use std::sync::mpsc;
use std::thread;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};
use tui::backend::{self, Backend};
use tui::layout::{Alignment, Constraint, Direction, Layout, Rect};
use tui::style::{Color, Modifier, Style};
use tui::terminal::{Frame, Terminal};
use tui::widgets::{Block, Borders, Paragraph, SelectableList, Text, Widget};

macro_rules! create_stat_list {
    ($($header:expr => $value:expr),+) => {
        [$(
            create_stat_list!(h $header),
            create_stat_list!(v $header.len(), $value),
        )+]
    };

    (h $header:expr) => {
        Text::styled(format!("{}\n", $header), Style::default().modifier(Modifier::BOLD))
    };

    (v $len:expr, $value:expr) => {
        Text::styled(format!("{:^width$}\n\n", $value, width = $len), Style::default().modifier(Modifier::ITALIC))
    };
}

pub struct UI<'a, B>
where
    B: Backend,
{
    terminal: Terminal<B>,
    status_log: StatusLog<'a>,
}

impl<'a, B> UI<'a, B>
where
    B: Backend,
{
    pub fn clear(&mut self) -> Result<()> {
        self.terminal.clear().context(err::IO)
    }

    pub fn push_log_status<S>(&mut self, text: S)
    where
        S: Into<String>,
    {
        self.status_log.push(text);
    }

    pub fn log_capture<S, F>(&mut self, text: S, f: F)
    where
        S: Into<String>,
        F: FnOnce() -> Result<()>,
    {
        self.status_log.capture(text, f);
    }

    pub fn draw(&mut self, state: &UIState) -> Result<()> {
        let status_log = &mut self.status_log;

        self.terminal
            .draw(|mut frame| {
                // Top panels for series information
                let horiz_splitter = Layout::default()
                    .direction(Direction::Horizontal)
                    .constraints(
                        [
                            Constraint::Min(20),
                            Constraint::Min(8),
                            Constraint::Percentage(60),
                        ]
                        .as_ref(),
                    )
                    .split(frame.size());

                UI::draw_top_panels(state, &horiz_splitter, &mut frame);

                // Series info panel vertical splitter
                let info_panel_splitter = Layout::default()
                    .direction(Direction::Vertical)
                    .constraints([Constraint::Percentage(80), Constraint::Percentage(20)].as_ref())
                    .split(horiz_splitter[2]);

                UI::draw_info_panel(state, &info_panel_splitter, &mut frame);
                UI::draw_status_bar(status_log, info_panel_splitter[1], &mut frame);
            })
            .context(err::IO)
    }

    fn draw_top_panels(state: &UIState, layout: &[Rect], frame: &mut Frame<B>) {
        let mut series_list = SelectableList::default()
            .block(Block::default().title("Series").borders(Borders::ALL))
            .items(state.series_names.as_ref())
            .select(Some(state.selected_series))
            .style(Style::default().fg(Color::White))
            .highlight_style(Style::default().fg(Color::Green).modifier(Modifier::ITALIC));

        if state.selection == Selection::Series {
            series_list = series_list.highlight_symbol(">");
        }

        series_list.render(frame, layout[0]);

        let season_nums = (1..=state.series.num_seasons)
            .map(|i| i.to_string())
            .collect::<SmallVec<[_; 4]>>();

        let mut season_list = SelectableList::default()
            .block(Block::default().title("Season").borders(Borders::ALL))
            .items(season_nums.as_ref())
            .select(Some(state.series.season.season_num))
            .style(Style::default().fg(Color::White))
            .highlight_style(Style::default().fg(Color::Green).modifier(Modifier::ITALIC));

        if state.selection == Selection::Season {
            season_list = season_list.highlight_symbol(">");
        }

        season_list.render(frame, layout[1]);
    }

    fn draw_info_panel(state: &UIState, layout: &[Rect], frame: &mut Frame<B>) {
        Block::default()
            .title("Info")
            .borders(Borders::ALL)
            .render(frame, layout[0]);

        let info_layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints(
                [
                    Constraint::Length(4),
                    Constraint::Percentage(70),
                    Constraint::Length(4),
                ]
                .as_ref(),
            )
            .margin(2)
            .split(layout[0]);

        let season = &state.series.season;
        let info = &season.series.info;
        let entry = &season.tracker.state;

        // Series title
        {
            let text_items = {
                let mut items = SmallVec::<[_; 2]>::new();

                items.push(Text::styled(
                    &info.title,
                    Style::default().modifier(Modifier::BOLD),
                ));

                if entry.needs_sync() {
                    items.push(Text::styled(
                        " [*]",
                        Style::default().modifier(Modifier::ITALIC),
                    ));
                }

                items
            };

            Paragraph::new(text_items.iter())
                .alignment(Alignment::Center)
                .render(frame, info_layout[0]);
        }

        // Items in panel
        let stat_layout = Layout::default()
            .direction(Direction::Horizontal)
            .constraints(
                [
                    Constraint::Percentage(33),
                    Constraint::Percentage(33),
                    Constraint::Percentage(33),
                ]
                .as_ref(),
            )
            .split(info_layout[1]);

        {
            let left_items = create_stat_list!(
                "Watch Time" => season.value_cache.watch_time,
                "Time Left" => season.value_cache.watch_time_left,
                "Episode Length" => season.value_cache.episode_length
            );

            Paragraph::new(left_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[0]);
        }

        {
            let center_items = create_stat_list!(
                "Progress" => season.value_cache.progress,
                "Score" => season.value_cache.score,
                "Status" => entry.status()
            );

            Paragraph::new(center_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[1]);
        }

        {
            let right_items = create_stat_list!(
                "Start Date" => season.value_cache.start_date,
                "Finish Date" => season.value_cache.end_date,
                "Rewatched" => entry.times_rewatched()
            );

            Paragraph::new(right_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[2]);
        }

        // Watch time needed indicator at bottom
        match season.watch_state {
            WatchState::Idle => (),
            WatchState::Watching(_, progress_time, _) => {
                let watch_time = progress_time - Utc::now();
                let watch_secs = watch_time.num_seconds();

                if watch_secs > 0 {
                    let remaining_mins = watch_secs as f32 / 60.0;

                    let text_str = format!(
                        "{} Remaining Until Progression",
                        util::ms_from_mins(remaining_mins)
                    );

                    let text = Text::styled(text_str, Style::default().modifier(Modifier::BOLD));

                    Paragraph::new([text].iter())
                        .alignment(Alignment::Center)
                        .render(frame, info_layout[2]);
                }
            }
        }
    }

    fn draw_status_bar(log: &mut StatusLog, layout: Rect, frame: &mut Frame<B>) {
        log.prepare_to_draw(layout);

        Paragraph::new(log.draw_items().iter())
            .block(Block::default().title("Status").borders(Borders::ALL))
            .render(frame, layout);
    }
}

pub type TermionBackend = backend::TermionBackend<RawTerminal<io::Stdout>>;

impl<'a> UI<'a, TermionBackend> {
    pub fn init() -> Result<UI<'a, TermionBackend>> {
        let stdout = io::stdout().into_raw_mode().context(err::IO)?;
        let backend = TermionBackend::new(stdout);
        let mut terminal = Terminal::new(backend).context(err::IO)?;

        terminal.clear().context(err::IO)?;
        terminal.hide_cursor().context(err::IO)?;

        Ok(UI {
            terminal,
            status_log: StatusLog::new(),
        })
    }
}

pub enum Event {
    Input(Key),
    Tick,
}

pub struct Events(mpsc::Receiver<Event>);

impl Events {
    pub fn new(tick_rate: Duration) -> Events {
        let (tx, rx) = mpsc::channel();

        Events::spawn_key_handler(tx.clone());
        Events::spawn_tick_handler(tick_rate, tx);

        Events(rx)
    }

    fn spawn_key_handler(tx: mpsc::Sender<Event>) -> thread::JoinHandle<()> {
        let stdin = io::stdin();

        thread::spawn(move || {
            for event in stdin.keys() {
                if let Ok(key) = event {
                    tx.send(Event::Input(key)).unwrap();
                }
            }
        })
    }

    fn spawn_tick_handler(tick_rate: Duration, tx: mpsc::Sender<Event>) -> thread::JoinHandle<()> {
        let tick_rate = tick_rate
            .to_std()
            .unwrap_or_else(|_| std::time::Duration::from_secs(1));

        thread::spawn(move || loop {
            thread::sleep(tick_rate);
            tx.send(Event::Tick).unwrap();
        })
    }

    pub fn next(&self) -> Result<Event> {
        self.0.recv().context(err::MPSCRecv)
    }
}

pub enum LogItemStatus {
    Ok,
    Pending,
    Failed(err::Error),
}

impl LogItemStatus {
    pub fn is_resolved(&self) -> bool {
        match self {
            LogItemStatus::Ok | LogItemStatus::Failed(_) => true,
            LogItemStatus::Pending => false,
        }
    }
}

impl fmt::Display for LogItemStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            LogItemStatus::Ok => write!(f, "ok"),
            LogItemStatus::Pending => write!(f, "pending"),
            LogItemStatus::Failed(_) => write!(f, "failed"),
        }
    }
}

pub struct LogItem {
    pub text: String,
    pub status: LogItemStatus,
}

impl LogItem {
    pub fn new<S>(text: S) -> LogItem
    where
        S: Into<String>,
    {
        LogItem {
            text: text.into(),
            status: LogItemStatus::Pending,
        }
    }
}

impl<T> From<T> for LogItem
where
    T: Into<String>,
{
    fn from(value: T) -> Self {
        LogItem::new(value)
    }
}

pub struct StatusLog<'a> {
    items: VecDeque<LogItem>,
    formatted: Vec<Text<'a>>,
    max_items: u16,
}

impl<'a> StatusLog<'a> {
    pub fn new() -> StatusLog<'a> {
        StatusLog {
            items: VecDeque::new(),
            formatted: Vec::new(),
            max_items: 0,
        }
    }

    fn rebuild(&mut self) {
        self.formatted.clear();

        for item in &self.items {
            let value_text = if item.status.is_resolved() {
                format!("{}... ", item.text)
            } else {
                format!("{}...\n", item.text)
            };

            self.formatted.push(Text::raw(value_text));

            if !item.status.is_resolved() {
                continue;
            }

            let status_color = match item.status {
                LogItemStatus::Ok => Color::Green,
                LogItemStatus::Pending => Color::Yellow,
                LogItemStatus::Failed(_) => Color::Red,
            };

            let status = Text::styled(
                format!("{}\n", item.status),
                Style::default().fg(status_color),
            );

            self.formatted.push(status);

            if let LogItemStatus::Failed(err) = &item.status {
                let err_text =
                    Text::styled(format!(".. {}\n", err), Style::default().fg(Color::Red));

                self.formatted.push(err_text);
            }
        }
    }

    pub fn push<I>(&mut self, item: I)
    where
        I: Into<LogItem>,
    {
        self.trim();
        self.items.push_back(item.into());
        self.rebuild();
    }

    pub fn set_status_on_last(&mut self, status: LogItemStatus) {
        let last = match self.items.get_mut(self.items.len() - 1) {
            Some(last) => last,
            None => return,
        };

        last.status = status;
        self.rebuild();
    }

    pub fn capture<S, F>(&mut self, text: S, f: F)
    where
        S: Into<String>,
        F: FnOnce() -> Result<()>,
    {
        self.push(text);

        let status = match f() {
            Ok(_) => LogItemStatus::Ok,
            Err(err) => LogItemStatus::Failed(err),
        };

        self.set_status_on_last(status);
    }

    pub fn prepare_to_draw(&mut self, size: Rect) {
        // We assume a border is around the list, so subtract 2 from the height
        self.max_items = size.height.saturating_sub(2);
        self.trim();
    }

    fn trim(&mut self) {
        while self.items.len() >= self.max_items as usize && !self.items.is_empty() {
            self.items.pop_front();
        }
    }

    /// Returns the log items in a ready-to-draw form.
    ///
    /// Note that this is intended by used with the Paragraph widget type.
    pub fn draw_items(&self) -> &Vec<Text<'a>> {
        &self.formatted
    }
}
<commit_msg>[anup] Set S type paramter to Into<LogItem> for UI::push_log_status<commit_after>use super::{Selection, UIState, WatchState};
use crate::err::{self, Result};
use crate::util;
use chrono::{Duration, Utc};
use smallvec::SmallVec;
use snafu::ResultExt;
use std::collections::VecDeque;
use std::fmt;
use std::io;
use std::sync::mpsc;
use std::thread;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::{IntoRawMode, RawTerminal};
use tui::backend::{self, Backend};
use tui::layout::{Alignment, Constraint, Direction, Layout, Rect};
use tui::style::{Color, Modifier, Style};
use tui::terminal::{Frame, Terminal};
use tui::widgets::{Block, Borders, Paragraph, SelectableList, Text, Widget};

macro_rules! create_stat_list {
    ($($header:expr => $value:expr),+) => {
        [$(
            create_stat_list!(h $header),
            create_stat_list!(v $header.len(), $value),
        )+]
    };

    (h $header:expr) => {
        Text::styled(format!("{}\n", $header), Style::default().modifier(Modifier::BOLD))
    };

    (v $len:expr, $value:expr) => {
        Text::styled(format!("{:^width$}\n\n", $value, width = $len), Style::default().modifier(Modifier::ITALIC))
    };
}

pub struct UI<'a, B>
where
    B: Backend,
{
    terminal: Terminal<B>,
    status_log: StatusLog<'a>,
}

impl<'a, B> UI<'a, B>
where
    B: Backend,
{
    pub fn clear(&mut self) -> Result<()> {
        self.terminal.clear().context(err::IO)
    }

    pub fn push_log_status<S>(&mut self, text: S)
    where
        S: Into<LogItem>,
    {
        self.status_log.push(text);
    }

    pub fn log_capture<S, F>(&mut self, text: S, f: F)
    where
        S: Into<String>,
        F: FnOnce() -> Result<()>,
    {
        self.status_log.capture(text, f);
    }

    pub fn draw(&mut self, state: &UIState) -> Result<()> {
        let status_log = &mut self.status_log;

        self.terminal
            .draw(|mut frame| {
                // Top panels for series information
                let horiz_splitter = Layout::default()
                    .direction(Direction::Horizontal)
                    .constraints(
                        [
                            Constraint::Min(20),
                            Constraint::Min(8),
                            Constraint::Percentage(60),
                        ]
                        .as_ref(),
                    )
                    .split(frame.size());

                UI::draw_top_panels(state, &horiz_splitter, &mut frame);

                // Series info panel vertical splitter
                let info_panel_splitter = Layout::default()
                    .direction(Direction::Vertical)
                    .constraints([Constraint::Percentage(80), Constraint::Percentage(20)].as_ref())
                    .split(horiz_splitter[2]);

                UI::draw_info_panel(state, &info_panel_splitter, &mut frame);
                UI::draw_status_bar(status_log, info_panel_splitter[1], &mut frame);
            })
            .context(err::IO)
    }

    fn draw_top_panels(state: &UIState, layout: &[Rect], frame: &mut Frame<B>) {
        let mut series_list = SelectableList::default()
            .block(Block::default().title("Series").borders(Borders::ALL))
            .items(state.series_names.as_ref())
            .select(Some(state.selected_series))
            .style(Style::default().fg(Color::White))
            .highlight_style(Style::default().fg(Color::Green).modifier(Modifier::ITALIC));

        if state.selection == Selection::Series {
            series_list = series_list.highlight_symbol(">");
        }

        series_list.render(frame, layout[0]);

        let season_nums = (1..=state.series.num_seasons)
            .map(|i| i.to_string())
            .collect::<SmallVec<[_; 4]>>();

        let mut season_list = SelectableList::default()
            .block(Block::default().title("Season").borders(Borders::ALL))
            .items(season_nums.as_ref())
            .select(Some(state.series.season.season_num))
            .style(Style::default().fg(Color::White))
            .highlight_style(Style::default().fg(Color::Green).modifier(Modifier::ITALIC));

        if state.selection == Selection::Season {
            season_list = season_list.highlight_symbol(">");
        }

        season_list.render(frame, layout[1]);
    }

    fn draw_info_panel(state: &UIState, layout: &[Rect], frame: &mut Frame<B>) {
        Block::default()
            .title("Info")
            .borders(Borders::ALL)
            .render(frame, layout[0]);

        let info_layout = Layout::default()
            .direction(Direction::Vertical)
            .constraints(
                [
                    Constraint::Length(4),
                    Constraint::Percentage(70),
                    Constraint::Length(4),
                ]
                .as_ref(),
            )
            .margin(2)
            .split(layout[0]);

        let season = &state.series.season;
        let info = &season.series.info;
        let entry = &season.tracker.state;

        // Series title
        {
            let text_items = {
                let mut items = SmallVec::<[_; 2]>::new();

                items.push(Text::styled(
                    &info.title,
                    Style::default().modifier(Modifier::BOLD),
                ));

                if entry.needs_sync() {
                    items.push(Text::styled(
                        " [*]",
                        Style::default().modifier(Modifier::ITALIC),
                    ));
                }

                items
            };

            Paragraph::new(text_items.iter())
                .alignment(Alignment::Center)
                .render(frame, info_layout[0]);
        }

        // Items in panel
        let stat_layout = Layout::default()
            .direction(Direction::Horizontal)
            .constraints(
                [
                    Constraint::Percentage(33),
                    Constraint::Percentage(33),
                    Constraint::Percentage(33),
                ]
                .as_ref(),
            )
            .split(info_layout[1]);

        {
            let left_items = create_stat_list!(
                "Watch Time" => season.value_cache.watch_time,
                "Time Left" => season.value_cache.watch_time_left,
                "Episode Length" => season.value_cache.episode_length
            );

            Paragraph::new(left_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[0]);
        }

        {
            let center_items = create_stat_list!(
                "Progress" => season.value_cache.progress,
                "Score" => season.value_cache.score,
                "Status" => entry.status()
            );

            Paragraph::new(center_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[1]);
        }

        {
            let right_items = create_stat_list!(
                "Start Date" => season.value_cache.start_date,
                "Finish Date" => season.value_cache.end_date,
                "Rewatched" => entry.times_rewatched()
            );

            Paragraph::new(right_items.iter())
                .alignment(Alignment::Center)
                .render(frame, stat_layout[2]);
        }

        // Watch time needed indicator at bottom
        match season.watch_state {
            WatchState::Idle => (),
            WatchState::Watching(_, progress_time, _) => {
                let watch_time = progress_time - Utc::now();
                let watch_secs = watch_time.num_seconds();

                if watch_secs > 0 {
                    let remaining_mins = watch_secs as f32 / 60.0;

                    let text_str = format!(
                        "{} Remaining Until Progression",
                        util::ms_from_mins(remaining_mins)
                    );

                    let text = Text::styled(text_str, Style::default().modifier(Modifier::BOLD));

                    Paragraph::new([text].iter())
                        .alignment(Alignment::Center)
                        .render(frame, info_layout[2]);
                }
            }
        }
    }

    fn draw_status_bar(log: &mut StatusLog, layout: Rect, frame: &mut Frame<B>) {
        log.prepare_to_draw(layout);

        Paragraph::new(log.draw_items().iter())
            .block(Block::default().title("Status").borders(Borders::ALL))
            .render(frame, layout);
    }
}

pub type TermionBackend = backend::TermionBackend<RawTerminal<io::Stdout>>;

impl<'a> UI<'a, TermionBackend> {
    pub fn init() -> Result<UI<'a, TermionBackend>> {
        let stdout = io::stdout().into_raw_mode().context(err::IO)?;
        let backend = TermionBackend::new(stdout);
        let mut terminal = Terminal::new(backend).context(err::IO)?;

        terminal.clear().context(err::IO)?;
        terminal.hide_cursor().context(err::IO)?;

        Ok(UI {
            terminal,
            status_log: StatusLog::new(),
        })
    }
}

pub enum Event {
    Input(Key),
    Tick,
}

pub struct Events(mpsc::Receiver<Event>);

impl Events {
    pub fn new(tick_rate: Duration) -> Events {
        let (tx, rx) = mpsc::channel();

        Events::spawn_key_handler(tx.clone());
        Events::spawn_tick_handler(tick_rate, tx);

        Events(rx)
    }

    fn spawn_key_handler(tx: mpsc::Sender<Event>) -> thread::JoinHandle<()> {
        let stdin = io::stdin();

        thread::spawn(move || {
            for event in stdin.keys() {
                if let Ok(key) = event {
                    tx.send(Event::Input(key)).unwrap();
                }
            }
        })
    }

    fn spawn_tick_handler(tick_rate: Duration, tx: mpsc::Sender<Event>) -> thread::JoinHandle<()> {
        let tick_rate = tick_rate
            .to_std()
            .unwrap_or_else(|_| std::time::Duration::from_secs(1));

        thread::spawn(move || loop {
            thread::sleep(tick_rate);
            tx.send(Event::Tick).unwrap();
        })
    }

    pub fn next(&self) -> Result<Event> {
        self.0.recv().context(err::MPSCRecv)
    }
}

pub enum LogItemStatus {
    Ok,
    Pending,
    Failed(err::Error),
}

impl LogItemStatus {
    pub fn is_resolved(&self) -> bool {
        match self {
            LogItemStatus::Ok | LogItemStatus::Failed(_) => true,
            LogItemStatus::Pending => false,
        }
    }
}

impl fmt::Display for LogItemStatus {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            LogItemStatus::Ok => write!(f, "ok"),
            LogItemStatus::Pending => write!(f, "pending"),
            LogItemStatus::Failed(_) => write!(f, "failed"),
        }
    }
}

pub struct LogItem {
    pub text: String,
    pub status: LogItemStatus,
}

impl LogItem {
    pub fn new<S>(text: S) -> LogItem
    where
        S: Into<String>,
    {
        LogItem {
            text: text.into(),
            status: LogItemStatus::Pending,
        }
    }
}

impl<T> From<T> for LogItem
where
    T: Into<String>,
{
    fn from(value: T) -> Self {
        LogItem::new(value)
    }
}

pub struct StatusLog<'a> {
    items: VecDeque<LogItem>,
    formatted: Vec<Text<'a>>,
    max_items: u16,
}

impl<'a> StatusLog<'a> {
    pub fn new() -> StatusLog<'a> {
        StatusLog {
            items: VecDeque::new(),
            formatted: Vec::new(),
            max_items: 0,
        }
    }

    fn rebuild(&mut self) {
        self.formatted.clear();

        for item in &self.items {
            let value_text = if item.status.is_resolved() {
                format!("{}... ", item.text)
            } else {
                format!("{}...\n", item.text)
            };

            self.formatted.push(Text::raw(value_text));

            if !item.status.is_resolved() {
                continue;
            }

            let status_color = match item.status {
                LogItemStatus::Ok => Color::Green,
                LogItemStatus::Pending => Color::Yellow,
                LogItemStatus::Failed(_) => Color::Red,
            };

            let status = Text::styled(
                format!("{}\n", item.status),
                Style::default().fg(status_color),
            );

            self.formatted.push(status);

            if let LogItemStatus::Failed(err) = &item.status {
                let err_text =
                    Text::styled(format!(".. {}\n", err), Style::default().fg(Color::Red));

                self.formatted.push(err_text);
            }
        }
    }

    pub fn push<I>(&mut self, item: I)
    where
        I: Into<LogItem>,
    {
        self.trim();
        self.items.push_back(item.into());
        self.rebuild();
    }

    pub fn set_status_on_last(&mut self, status: LogItemStatus) {
        let last = match self.items.get_mut(self.items.len() - 1) {
            Some(last) => last,
            None => return,
        };

        last.status = status;
        self.rebuild();
    }

    pub fn capture<S, F>(&mut self, text: S, f: F)
    where
        S: Into<String>,
        F: FnOnce() -> Result<()>,
    {
        self.push(text);

        let status = match f() {
            Ok(_) => LogItemStatus::Ok,
            Err(err) => LogItemStatus::Failed(err),
        };

        self.set_status_on_last(status);
    }

    pub fn prepare_to_draw(&mut self, size: Rect) {
        // We assume a border is around the list, so subtract 2 from the height
        self.max_items = size.height.saturating_sub(2);
        self.trim();
    }

    fn trim(&mut self) {
        while self.items.len() >= self.max_items as usize && !self.items.is_empty() {
            self.items.pop_front();
        }
    }

    /// Returns the log items in a ready-to-draw form.
    ///
    /// Note that this is intended by used with the Paragraph widget type.
    pub fn draw_items(&self) -> &Vec<Text<'a>> {
        &self.formatted
    }
}
<|endoftext|>


<commit_before>use crate::grammar::model::Fragment;
use crate::grammar::parsers::whitespace;
use codespan::{FileId, Files};

fn setup(src: &str) -> (Files<String>, FileId) {
    let mut f: Files<String> = Files::new();
    let id = f.add("test", src.to_string());
    (f, id)
}

#[test]
fn single_comment() {
    let (f, h) = setup("// line comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty_comment() {
    let (f, h) = setup("//");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_with_tail() {
    let (f, h) = setup("// line comment\nnot a comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 14);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comments_and_whitespace() {
    let (f, h) = setup("// line comment\n// this is another comment\n    // third comment\n");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty() {
    let (f, h) = setup("");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_only() {
    let (f, h) = setup("// comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn whitespace_only() {
    let (f, h) = setup("\t  \n\n   \t  ");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, _)) = res {
        assert_eq!(rem.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}
<commit_msg>Verify comment values<commit_after>use crate::grammar::model::Fragment;
use crate::grammar::parsers::whitespace;
use codespan::{FileId, Files};

fn setup(src: &str) -> (Files<String>, FileId) {
    let mut f: Files<String> = Files::new();
    let id = f.add("test", src.to_string());
    (f, id)
}

#[test]
fn single_comment() {
    let (f, h) = setup("// line comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), " line comment");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty_comment() {
    let (f, h) = setup("//");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.source(), "");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_with_tail() {
    let (f, h) = setup("// line comment\nnot a comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::line_comment(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 14);
        assert_eq!(val.source(), " line comment");
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comments_and_whitespace() {
    let (f, h) = setup("// line comment\n// this is another comment\n    // third comment\n");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(
            val.iter().map(Fragment::source).collect::<Vec<_>>(),
            vec![
                " line comment",
                " this is another comment",
                " third comment",
            ],
        );
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn empty() {
    let (f, h) = setup("");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn comment_only() {
    let (f, h) = setup("// comment");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(
            val.iter().map(Fragment::source).collect::<Vec<_>>(),
            vec![
                " comment",
            ],
        );
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}

#[test]
fn whitespace_only() {
    let (f, h) = setup("\t  \n\n   \t  ");
    let frag = Fragment::new(&f, h);
    let res = whitespace::token_delimiter(frag);
    if let Ok((rem, val)) = res {
        assert_eq!(rem.len(), 0);
        assert_eq!(val.len(), 0);
    } else {
        eprintln!("{:#?}", res);
        assert!(false);
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

use proc_macro2::TokenStream;
use quote::quote;
use syn::{
    parse::Parser, parse_quote, punctuated::Punctuated, token::Unsafe, Attribute, FnArg,
    ForeignItem, Ident, ImplItem, Item, ReturnType,
};

use super::{
    unqualify::{unqualify_params, unqualify_ret_type},
    RsCodegenResult, Use,
};
use crate::types::make_ident;
use crate::{
    conversion::{
        analysis::fun::{ArgumentAnalysis, FnAnalysisBody, FnKind, MethodKind, RustRenameStrategy},
        api::ImplBlockDetails,
    },
    types::{Namespace, TypeName},
};

pub(crate) fn gen_function(ns: &Namespace, analysis: FnAnalysisBody) -> RsCodegenResult {
    let cxxbridge_name = analysis.cxxbridge_name;
    let rust_name = analysis.rust_name;
    let ret_type = analysis.ret_type;
    let param_details = analysis.param_details;
    let cpp_call_name = analysis.cpp_call_name;
    let wrapper_function_needed = analysis.cpp_wrapper.is_some();
    let requires_unsafe = analysis.requires_unsafe;
    let params = analysis.params;
    let vis = analysis.vis;
    let kind = analysis.kind;

    let mut cpp_name_attr = Vec::new();
    let mut impl_entry = None;
    let unsafety: Option<Unsafe> = if requires_unsafe {
        Some(parse_quote!(unsafe))
    } else {
        None
    };
    let rust_name_attr: Vec<_> = match &analysis.rust_rename_strategy {
        RustRenameStrategy::RenameUsingRustAttr => Attribute::parse_outer
            .parse2(quote!(
                #[rust_name = #rust_name]
            ))
            .unwrap(),
        _ => Vec::new(),
    };
    let mut materialization = match kind {
        FnKind::Method(..) => Use::Unused,
        FnKind::Function => match analysis.rust_rename_strategy {
            RustRenameStrategy::RenameInOutputMod(alias) => Use::UsedFromCxxBridgeWithAlias(alias),
            _ => Use::UsedFromCxxBridge,
        },
    };
    let any_param_needs_rust_conversion = param_details
        .iter()
        .any(|pd| pd.conversion.rust_work_needed());
    let rust_wrapper_needed = any_param_needs_rust_conversion
        || (cxxbridge_name != rust_name && matches!(kind, FnKind::Method(..)));
    if rust_wrapper_needed {
        if let FnKind::Method(ref type_name, ref method_kind) = kind {
            // Method, or static method.
            impl_entry = Some(generate_method_impl(
                &param_details,
                matches!(method_kind, MethodKind::Constructor),
                type_name,
                &cxxbridge_name,
                &rust_name,
                &ret_type,
                &unsafety,
            ));
        } else {
            // Generate plain old function
            materialization = Use::Custom(generate_function_impl(
                &param_details,
                &rust_name,
                &ret_type,
                &unsafety,
            ));
        }
    }
    if cxxbridge_name != cpp_call_name && !wrapper_function_needed {
        cpp_name_attr = Attribute::parse_outer
            .parse2(quote!(
                #[cxx_name = #cpp_call_name]
            ))
            .unwrap();
    }
    // Finally - namespace support. All the Types in everything
    // above this point are fully qualified. We need to unqualify them.
    // We need to do that _after_ the above wrapper_function_needed
    // work, because it relies upon spotting fully qualified names like
    // std::unique_ptr. However, after it's done its job, all such
    // well-known types should be unqualified already (e.g. just UniquePtr)
    // and the following code will act to unqualify only those types
    // which the user has declared.
    let params = unqualify_params(params);
    let ret_type = unqualify_ret_type(ret_type);
    // And we need to make an attribute for the namespace that the function
    // itself is in.
    let namespace_attr = if ns.is_empty() || wrapper_function_needed {
        Vec::new()
    } else {
        let namespace_string = ns.to_string();
        Attribute::parse_outer
            .parse2(quote!(
                #[namespace = #namespace_string]
            ))
            .unwrap()
    };
    // At last, actually generate the cxx::bridge entry.
    let extern_c_mod_item = ForeignItem::Fn(parse_quote!(
        #(#namespace_attr)*
        #(#rust_name_attr)*
        #(#cpp_name_attr)*
        #vis #unsafety fn #cxxbridge_name ( #params ) #ret_type;
    ));
    RsCodegenResult {
        extern_c_mod_item: Some(extern_c_mod_item),
        bridge_items: Vec::new(),
        global_items: Vec::new(),
        bindgen_mod_item: None,
        impl_entry,
        materialization,
    }
}

fn generate_arg_lists(
    param_details: &[ArgumentAnalysis],
    is_constructor: bool,
) -> (Punctuated<FnArg, syn::Token![,]>, Vec<TokenStream>) {
    let mut wrapper_params: Punctuated<FnArg, syn::Token![,]> = Punctuated::new();
    let mut arg_list = Vec::new();

    for pd in param_details {
        let type_name = pd.conversion.rust_wrapper_unconverted_type();
        let wrapper_arg_name = if pd.self_type.is_some() && !is_constructor {
            parse_quote!(self)
        } else {
            pd.name.clone()
        };
        wrapper_params.push(parse_quote!(
            #wrapper_arg_name: #type_name
        ));
        arg_list.push(pd.conversion.rust_conversion(wrapper_arg_name));
    }
    (wrapper_params, arg_list)
}

/// Generate an 'impl Type { methods-go-here }' item
fn generate_method_impl(
    param_details: &[ArgumentAnalysis],
    is_constructor: bool,
    impl_block_type_name: &TypeName,
    cxxbridge_name: &Ident,
    rust_name: &str,
    ret_type: &ReturnType,
    unsafety: &Option<Unsafe>,
) -> Box<ImplBlockDetails> {
    let (wrapper_params, arg_list) = generate_arg_lists(param_details, is_constructor);
    let rust_name = make_ident(&rust_name);
    Box::new(ImplBlockDetails {
        item: ImplItem::Method(parse_quote! {
            pub #unsafety fn #rust_name ( #wrapper_params ) #ret_type {
                cxxbridge::#cxxbridge_name ( #(#arg_list),* )
            }
        }),
        ty: make_ident(impl_block_type_name.get_final_ident()),
    })
}

/// Generate a function call wrapper
fn generate_function_impl(
    param_details: &[ArgumentAnalysis],
    rust_name: &str,
    ret_type: &ReturnType,
    unsafety: &Option<Unsafe>,
) -> Box<Item> {
    let (wrapper_params, arg_list) = generate_arg_lists(param_details, false);
    let rust_name = make_ident(&rust_name);
    Box::new(Item::Fn(parse_quote! {
        pub #unsafety fn #rust_name ( #wrapper_params ) #ret_type {
            cxxbridge::#rust_name ( #(#arg_list),* )
        }
    }))
}
<commit_msg>Slight simplification<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

use proc_macro2::TokenStream;
use quote::quote;
use syn::{
    parse::Parser, parse_quote, punctuated::Punctuated, token::Unsafe, Attribute, FnArg,
    ForeignItem, Ident, ImplItem, Item, ReturnType,
};

use super::{
    unqualify::{unqualify_params, unqualify_ret_type},
    RsCodegenResult, Use,
};
use crate::types::make_ident;
use crate::{
    conversion::{
        analysis::fun::{ArgumentAnalysis, FnAnalysisBody, FnKind, MethodKind, RustRenameStrategy},
        api::ImplBlockDetails,
    },
    types::{Namespace, TypeName},
};

pub(crate) fn gen_function(ns: &Namespace, analysis: FnAnalysisBody) -> RsCodegenResult {
    let cxxbridge_name = analysis.cxxbridge_name;
    let rust_name = analysis.rust_name;
    let ret_type = analysis.ret_type;
    let param_details = analysis.param_details;
    let cpp_call_name = analysis.cpp_call_name;
    let wrapper_function_needed = analysis.cpp_wrapper.is_some();
    let params = analysis.params;
    let vis = analysis.vis;
    let kind = analysis.kind;

    let mut cpp_name_attr = Vec::new();
    let mut impl_entry = None;
    let unsafety: Option<Unsafe> = if analysis.requires_unsafe {
        Some(parse_quote!(unsafe))
    } else {
        None
    };
    let rust_name_attr: Vec<_> = match &analysis.rust_rename_strategy {
        RustRenameStrategy::RenameUsingRustAttr => Attribute::parse_outer
            .parse2(quote!(
                #[rust_name = #rust_name]
            ))
            .unwrap(),
        _ => Vec::new(),
    };
    let mut materialization = match kind {
        FnKind::Method(..) => Use::Unused,
        FnKind::Function => match analysis.rust_rename_strategy {
            RustRenameStrategy::RenameInOutputMod(alias) => Use::UsedFromCxxBridgeWithAlias(alias),
            _ => Use::UsedFromCxxBridge,
        },
    };
    let any_param_needs_rust_conversion = param_details
        .iter()
        .any(|pd| pd.conversion.rust_work_needed());
    let rust_wrapper_needed = any_param_needs_rust_conversion
        || (cxxbridge_name != rust_name && matches!(kind, FnKind::Method(..)));
    if rust_wrapper_needed {
        if let FnKind::Method(ref type_name, ref method_kind) = kind {
            // Method, or static method.
            impl_entry = Some(generate_method_impl(
                &param_details,
                matches!(method_kind, MethodKind::Constructor),
                type_name,
                &cxxbridge_name,
                &rust_name,
                &ret_type,
                &unsafety,
            ));
        } else {
            // Generate plain old function
            materialization = Use::Custom(generate_function_impl(
                &param_details,
                &rust_name,
                &ret_type,
                &unsafety,
            ));
        }
    }
    if cxxbridge_name != cpp_call_name && !wrapper_function_needed {
        cpp_name_attr = Attribute::parse_outer
            .parse2(quote!(
                #[cxx_name = #cpp_call_name]
            ))
            .unwrap();
    }
    // Finally - namespace support. All the Types in everything
    // above this point are fully qualified. We need to unqualify them.
    // We need to do that _after_ the above wrapper_function_needed
    // work, because it relies upon spotting fully qualified names like
    // std::unique_ptr. However, after it's done its job, all such
    // well-known types should be unqualified already (e.g. just UniquePtr)
    // and the following code will act to unqualify only those types
    // which the user has declared.
    let params = unqualify_params(params);
    let ret_type = unqualify_ret_type(ret_type);
    // And we need to make an attribute for the namespace that the function
    // itself is in.
    let namespace_attr = if ns.is_empty() || wrapper_function_needed {
        Vec::new()
    } else {
        let namespace_string = ns.to_string();
        Attribute::parse_outer
            .parse2(quote!(
                #[namespace = #namespace_string]
            ))
            .unwrap()
    };
    // At last, actually generate the cxx::bridge entry.
    let extern_c_mod_item = ForeignItem::Fn(parse_quote!(
        #(#namespace_attr)*
        #(#rust_name_attr)*
        #(#cpp_name_attr)*
        #vis #unsafety fn #cxxbridge_name ( #params ) #ret_type;
    ));
    RsCodegenResult {
        extern_c_mod_item: Some(extern_c_mod_item),
        bridge_items: Vec::new(),
        global_items: Vec::new(),
        bindgen_mod_item: None,
        impl_entry,
        materialization,
    }
}

fn generate_arg_lists(
    param_details: &[ArgumentAnalysis],
    is_constructor: bool,
) -> (Punctuated<FnArg, syn::Token![,]>, Vec<TokenStream>) {
    let mut wrapper_params: Punctuated<FnArg, syn::Token![,]> = Punctuated::new();
    let mut arg_list = Vec::new();

    for pd in param_details {
        let type_name = pd.conversion.rust_wrapper_unconverted_type();
        let wrapper_arg_name = if pd.self_type.is_some() && !is_constructor {
            parse_quote!(self)
        } else {
            pd.name.clone()
        };
        wrapper_params.push(parse_quote!(
            #wrapper_arg_name: #type_name
        ));
        arg_list.push(pd.conversion.rust_conversion(wrapper_arg_name));
    }
    (wrapper_params, arg_list)
}

/// Generate an 'impl Type { methods-go-here }' item
fn generate_method_impl(
    param_details: &[ArgumentAnalysis],
    is_constructor: bool,
    impl_block_type_name: &TypeName,
    cxxbridge_name: &Ident,
    rust_name: &str,
    ret_type: &ReturnType,
    unsafety: &Option<Unsafe>,
) -> Box<ImplBlockDetails> {
    let (wrapper_params, arg_list) = generate_arg_lists(param_details, is_constructor);
    let rust_name = make_ident(&rust_name);
    Box::new(ImplBlockDetails {
        item: ImplItem::Method(parse_quote! {
            pub #unsafety fn #rust_name ( #wrapper_params ) #ret_type {
                cxxbridge::#cxxbridge_name ( #(#arg_list),* )
            }
        }),
        ty: make_ident(impl_block_type_name.get_final_ident()),
    })
}

/// Generate a function call wrapper
fn generate_function_impl(
    param_details: &[ArgumentAnalysis],
    rust_name: &str,
    ret_type: &ReturnType,
    unsafety: &Option<Unsafe>,
) -> Box<Item> {
    let (wrapper_params, arg_list) = generate_arg_lists(param_details, false);
    let rust_name = make_ident(&rust_name);
    Box::new(Item::Fn(parse_quote! {
        pub #unsafety fn #rust_name ( #wrapper_params ) #ret_type {
            cxxbridge::#rust_name ( #(#arg_list),* )
        }
    }))
}
<|endoftext|>


<commit_before>/* AES ECB/CBC mode oracle
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate aes_lib;

use std::rand::{random, task_rng, Rng, Rand};
use std::fmt;
use std::fmt::{Show, Formatter};
use std::collections::HashSet;
use std::io::File;

use aes_lib::{AES_BLOCK_SIZE, encrypt_aes_ecb, encrypt_aes_cbc};

#[deriving(PartialEq, Eq)]
enum Mode {
    ECB,
    CBC
}

impl Rand for Mode {
    fn rand<R: Rng>(rng: &mut R) -> Mode {
        match rng.gen() {
            true => Mode::ECB,
            false => Mode::CBC
        }
    }
}

impl Show for Mode {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Mode::ECB => write!(f, "ECB"),
            Mode::CBC => write!(f, "CBC"),
        }
    }
}

#[inline]
fn random_bytes(len: uint) -> Vec<u8> {
    Vec::from_fn(len, |_| random::<u8>())
}

#[inline]
fn random_uint(low: uint, high: uint) -> uint {
    task_rng().gen_range(low, high)
}

fn aes_oracle(input: &[u8]) -> (Vec<u8>, Mode) {
    let key = random_bytes(AES_BLOCK_SIZE);
    let prepend = random_bytes(random_uint(5, 10));
    let append = random_bytes(random_uint(5, 10));
    let data = prepend + input.to_vec() + append;
    match random::<Mode>() {
        Mode::ECB =>
            (encrypt_aes_ecb(data.as_slice(), key.as_slice()), Mode::ECB),
        Mode::CBC => {
            let iv = random_bytes(AES_BLOCK_SIZE);
            (encrypt_aes_cbc(data.as_slice(), key.as_slice(),
                             iv.as_slice()), Mode::CBC)
        }
    }
}

fn guess_aes_mode(buffer: &[u8]) -> Mode {
    let mut blocks = HashSet::new();
    match buffer.chunks(AES_BLOCK_SIZE).any(|b| !blocks.insert(b)) {
        true => Mode::ECB,
        false => Mode::CBC
    }
}

fn read_example_text() -> Vec<u8> {
    File::open(&Path::new("text.txt")).read_to_end().unwrap()
}

fn main() {
    let data = read_example_text();
    let (encrypted, mode) = aes_oracle(data.as_slice());
    print!("Mode: {} - ", mode);
    match guess_aes_mode(encrypted.as_slice()) {
        m if m == mode => println!("Matched"),
        _ => println!("Not matched")
    }
}
<commit_msg>Replace pattern matching with 'if'<commit_after>/* AES ECB/CBC mode oracle
 *
 * Dmitry Vasiliev <dima@hlabs.org>
 */

extern crate aes_lib;

use std::rand::{random, task_rng, Rng, Rand};
use std::fmt;
use std::fmt::{Show, Formatter};
use std::collections::HashSet;
use std::io::File;

use aes_lib::{AES_BLOCK_SIZE, encrypt_aes_ecb, encrypt_aes_cbc};

#[deriving(PartialEq, Eq)]
enum Mode {
    ECB,
    CBC
}

impl Rand for Mode {
    fn rand<R: Rng>(rng: &mut R) -> Mode {
        match rng.gen() {
            true => Mode::ECB,
            false => Mode::CBC
        }
    }
}

impl Show for Mode {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        match *self {
            Mode::ECB => write!(f, "ECB"),
            Mode::CBC => write!(f, "CBC"),
        }
    }
}

#[inline]
fn random_bytes(len: uint) -> Vec<u8> {
    Vec::from_fn(len, |_| random::<u8>())
}

#[inline]
fn random_uint(low: uint, high: uint) -> uint {
    task_rng().gen_range(low, high)
}

fn aes_oracle(input: &[u8]) -> (Vec<u8>, Mode) {
    let key = random_bytes(AES_BLOCK_SIZE);
    let prepend = random_bytes(random_uint(5, 10));
    let append = random_bytes(random_uint(5, 10));
    let data = prepend + input.to_vec() + append;
    match random::<Mode>() {
        Mode::ECB =>
            (encrypt_aes_ecb(data.as_slice(), key.as_slice()), Mode::ECB),
        Mode::CBC => {
            let iv = random_bytes(AES_BLOCK_SIZE);
            (encrypt_aes_cbc(data.as_slice(), key.as_slice(),
                             iv.as_slice()), Mode::CBC)
        }
    }
}

fn guess_aes_mode(buffer: &[u8]) -> Mode {
    let mut blocks = HashSet::new();
    match buffer.chunks(AES_BLOCK_SIZE).any(|b| !blocks.insert(b)) {
        true => Mode::ECB,
        false => Mode::CBC
    }
}

fn read_example_text() -> Vec<u8> {
    File::open(&Path::new("text.txt")).read_to_end().unwrap()
}

fn main() {
    let data = read_example_text();
    let (encrypted, mode) = aes_oracle(data.as_slice());
    print!("Mode: {} - ", mode);
    if guess_aes_mode(encrypted.as_slice()) == mode {
        println!("Matched");
    } else {
        println!("Not matched");
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate serde_derive;

extern crate bytes;
extern crate tokio;
extern crate tokio_codec;
extern crate tokio_io;

extern crate serde;
extern crate serde_json;

use bytes::BytesMut;
use std::io;
use tokio::codec::{Encoder,Decoder};
use tokio::prelude::*;
use tokio::net::TcpListener;
use std::collections::HashMap;
use std::sync::{Mutex, Arc};

#[derive(Clone,Copy)]
pub struct ExampleJSONParser;
impl ExampleJSONParser {
    fn new() -> ExampleJSONParser {
        ExampleJSONParser{}
    }
}

impl ExampleJSONParser {
    fn parse(&self, info: &Vec<u8>)  -> Message {
        let vec_to_parse = info.clone();
        let message = String::from_utf8(vec_to_parse).unwrap();
        println!("Json parser for: {:?}", message);
        let msg: Message = match serde_json::from_str(&message)  {
            Err(..) =>   {println!("It was not parsed correctly"); Message::new_empty() },
            Ok(msg) => msg,
        };
        return msg
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Message {
    operation: String,
}

impl Message {
    fn new(operation: String) -> Message {
        Message {operation: operation}
    }
    fn new_empty() -> Message  {
        Message {operation: "".to_string()}
    }

}
pub trait Operation {
}

pub struct MyBytesCodec {
    json_parser: ExampleJSONParser,
    operations: HashMap<String, Box<dyn Operation + Send>>,
}

impl MyBytesCodec {
    fn new() -> MyBytesCodec {
        MyBytesCodec{json_parser: ExampleJSONParser::new(), operations: HashMap::new()}
    }
}

impl Decoder for MyBytesCodec {
    type Item = Message;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<Message>> {
        if buf.len() == 0 {
            return Ok(None);
        }
        let data = buf.clone().to_vec();
        let cloned_data = data.clone();
        let parsed = self.json_parser.parse(&cloned_data);
        buf.clear();
        Ok(Some(parsed))
    }
}

impl Encoder for MyBytesCodec {
    type Item = Message;
    type Error = io::Error;

    fn encode(&mut self, data: Message, buf: &mut BytesMut) -> io::Result<()> {
        buf.extend(serde_json::to_string(&data)?.into_bytes());
        Ok(())
    }
}

fn main() {
    let addr = "127.0.0.1:12345".parse().unwrap();
    let listener = TcpListener::bind(&addr).expect("unable to bind TCP listener");
    let server = listener.incoming()
            .map_err(|e| eprintln!("accept failed = {:?}", e))
            .for_each(move |socket| {
                let framed = MyBytesCodec::new().framed(socket);
                let (_writer, reader) = framed.split();

                /* function to handle connection  */
                let handle_conn = reader.for_each(|message| {
                    println!("my parsed message!!: {:?}", serde_json::to_string(&message));
                    Ok(())
                })
                .and_then(|()| {
                    println!("Socket received FIN packet and closed connection");
                    Ok(())
                })
                .or_else(|err| {
                    println!("Socked closed with error: {:?}", err);
                    Err(err)

                })
                .then(|result| {
                    println!("Socket closed with result: {:?}", result);
                    Ok(())
                });

            tokio::spawn(handle_conn)
    });
    tokio::run(server);
}

<commit_msg>Added both options to compile hashmap of operations<commit_after>#[macro_use]
extern crate serde_derive;

extern crate bytes;
extern crate tokio;
extern crate tokio_codec;
extern crate tokio_io;

extern crate serde;
extern crate serde_json;

use bytes::BytesMut;
use std::io;
use tokio::codec::{Encoder,Decoder};
use tokio::prelude::*;
use tokio::net::TcpListener;
use std::collections::HashMap;
use std::sync::{Mutex, Arc};

#[derive(Clone,Copy)]
pub struct ExampleJSONParser;
impl ExampleJSONParser {
    fn new() -> ExampleJSONParser {
        ExampleJSONParser{}
    }
}

impl ExampleJSONParser {
    fn parse(&self, info: &Vec<u8>)  -> Message {
        let vec_to_parse = info.clone();
        let message = String::from_utf8(vec_to_parse).unwrap();
        println!("Json parser for: {:?}", message);
        let msg: Message = match serde_json::from_str(&message)  {
            Err(..) =>   {println!("It was not parsed correctly"); Message::new_empty() },
            Ok(msg) => msg,
        };
        return msg
    }
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Message {
    operation: String,
}

impl Message {
    fn new(operation: String) -> Message {
        Message {operation: operation}
    }
    fn new_empty() -> Message  {
        Message {operation: "".to_string()}
    }

}
pub trait Operation {
}

pub struct MyBytesCodec {
    json_parser: ExampleJSONParser,
    operations: HashMap<String, Arc<Mutex<dyn Operation + Send + 'static>>>,
    //operations: HashMap<String, Box<dyn Operation + Send>>,
}

impl MyBytesCodec {
    fn new() -> MyBytesCodec {
        MyBytesCodec{json_parser: ExampleJSONParser::new(), operations: HashMap::new()}
    }
}

impl Decoder for MyBytesCodec {
    type Item = Message;
    type Error = io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> io::Result<Option<Message>> {
        if buf.len() == 0 {
            return Ok(None);
        }
        let data = buf.clone().to_vec();
        let cloned_data = data.clone();
        let parsed = self.json_parser.parse(&cloned_data);
        buf.clear();
        Ok(Some(parsed))
    }
}

impl Encoder for MyBytesCodec {
    type Item = Message;
    type Error = io::Error;

    fn encode(&mut self, data: Message, buf: &mut BytesMut) -> io::Result<()> {
        buf.extend(serde_json::to_string(&data)?.into_bytes());
        Ok(())
    }
}

fn main() {
    let addr = "127.0.0.1:12345".parse().unwrap();
    let listener = TcpListener::bind(&addr).expect("unable to bind TCP listener");
    let server = listener.incoming()
            .map_err(|e| eprintln!("accept failed = {:?}", e))
            .for_each(move |socket| {
                let framed = MyBytesCodec::new().framed(socket);
                let (_writer, reader) = framed.split();

                /* function to handle connection  */
                let handle_conn = reader.for_each(|message| {
                    println!("my parsed message!!: {:?}", serde_json::to_string(&message));
                    Ok(())
                })
                .and_then(|()| {
                    println!("Socket received FIN packet and closed connection");
                    Ok(())
                })
                .or_else(|err| {
                    println!("Socked closed with error: {:?}", err);
                    Err(err)

                })
                .then(|result| {
                    println!("Socket closed with result: {:?}", result);
                    Ok(())
                });

            tokio::spawn(handle_conn)
    });
    tokio::run(server);
}

<|endoftext|>


<commit_before>lazy_static!{}
<commit_msg>Delete log_ebr.rs<commit_after><|endoftext|>