<commit_before>//! Primitives for creating and controlling [`Window`](struct.Window.html).

use glutin;
use glutin::GlContext;
use mint;
use render;

use camera::Camera;
use factory::Factory;
use input::Input;
use render::Renderer;
use scene::Scene;
use std::path::PathBuf;

pub use glutin::CursorState;

/// `Window` is the core entity of every `three-rs` application.
///
/// It provides [user input](struct.Window.html#method.update),
/// [`Factory`](struct.Factory.html) and [`Renderer`](struct.Renderer.html).
pub struct Window {
    event_loop: glutin::EventsLoop,
    window: glutin::GlWindow,
    /// See [`Input`](struct.Input.html).
    pub input: Input,
    /// See [`Renderer`](struct.Renderer.html).
    pub renderer: Renderer,
    /// See [`Factory`](struct.Factory.html).
    pub factory: Factory,
    /// See [`Scene`](struct.Scene.html).
    pub scene: Scene,
    /// Reset input on each frame? See [`Input::reset`](struct.Input.html#method.reset).
    ///
    /// Defaults to `true`.
    pub reset_input: bool,
}

/// Builder for creating new [`Window`](struct.Window.html) with desired parameters.
#[derive(Debug, Clone)]
pub struct Builder {
    dimensions: (u32, u32),
    fullscreen: bool,
    multisampling: u16,
    shader_directory: Option<PathBuf>,
    title: String,
    vsync: bool,
}

impl Builder {
    /// Set the size of the viewport (the resolution) in pixels. Defaults to 1024x768.
    pub fn dimensions(
        &mut self,
        width: u32,
        height: u32,
    ) -> &mut Self {
        self.dimensions = (width, height);
        self
    }

    /// Whether enable fullscreen mode or not. Defauls to `false`.
    pub fn fullscreen(
        &mut self,
        option: bool,
    ) -> &mut Self {
        self.fullscreen = option;
        self
    }

    /// Sets the multisampling level to request. A value of `0` indicates that multisampling must
    /// not be enabled. Must be the power of 2. Defaults to `0`.
    pub fn multisampling(
        &mut self,
        option: u16,
    ) -> &mut Self {
        self.multisampling = option;
        self
    }

    /// Specifies the user shader directory.
    pub fn shader_directory<P: Into<PathBuf>>(
        &mut self,
        option: P,
    ) -> &mut Self {
        self.shader_directory = Some(option.into());
        self
    }

    /// Whether to enable vertical synchronization or not. Defaults to `true`.
    pub fn vsync(
        &mut self,
        option: bool,
    ) -> &mut Self {
        self.vsync = option;
        self
    }

    /// Create new `Window` with desired parameters.
    pub fn build(&mut self) -> Window {
        let event_loop = glutin::EventsLoop::new();
        let monitor_id = if self.fullscreen {
            Some(event_loop.get_primary_monitor())
        } else {
            None
        };

        let builder = glutin::WindowBuilder::new()
            .with_fullscreen(monitor_id)
            .with_dimensions(self.dimensions.0, self.dimensions.1)
            .with_title(self.title.clone());

        let context = glutin::ContextBuilder::new()
            .with_vsync(self.vsync)
            .with_multisampling(self.multisampling);

        let mut source_set = render::source::Set::default();
        if let Some(path) = self.shader_directory.as_ref() {
            let path = path.to_str().unwrap();
            macro_rules! try_override {
                ($name:ident) => {
                    match render::Source::user(path, stringify!($name), "vs") {
                        Ok(src) => {
                            info!("Overriding {}_vs.glsl", stringify!($name));
                            source_set.$name.vs = src;
                        }
                        Err(err) => {
                            error!("{:#?}", err);
                            info!("Using default {}_vs.glsl", stringify!($name));
                        }
                    }
                    match render::Source::user(path, stringify!($name), "ps") {
                        Ok(src) => {
                            info!("Overriding {}_ps.glsl", stringify!($name));
                            source_set.$name.ps = src;
                        }
                        Err(err) => {
                            error!("{:#?}", err);
                            info!("Using default {}_ps.glsl", stringify!($name));
                        }
                    }
                };
                ( $($name:ident,)* ) => {
                    $( try_override!($name); )*
                };
            }
            try_override!(basic, gouraud, pbr, phong, quad, shadow, skybox, sprite,);
        }

        let (renderer, window, mut factory) = Renderer::new(builder, context, &event_loop, &source_set);
        let scene = factory.scene();
        Window {
            event_loop,
            window,
            input: Input::new(),
            renderer,
            factory,
            scene,
            reset_input: true,
        }
    }
}

impl Window {
    /// Create a new window with default parameters.
    pub fn new<T: Into<String>>(title: T) -> Self {
        Self::builder(title).build()
    }

    /// Create new `Builder` with standard parameters.
    pub fn builder<T: Into<String>>(title: T) -> Builder {
        Builder {
            dimensions: (1024, 768),
            fullscreen: false,
            multisampling: 0,
            shader_directory: None,
            title: title.into(),
            vsync: true,
        }
    }

    /// `update` method returns `false` if the window was closed.
    pub fn update(&mut self) -> bool {
        let mut running = true;
        let renderer = &mut self.renderer;
        let input = &mut self.input;
        if self.reset_input {
            input.reset();
        }

        self.window.swap_buffers().unwrap();
        let window = &self.window;

        self.event_loop.poll_events(|event| {
            use glutin::WindowEvent::{Closed, Focused, KeyboardInput, MouseInput, CursorMoved, MouseWheel, Resized};
            match event {
                glutin::Event::WindowEvent { event, .. } => match event {
                    Resized(..) => renderer.resize(window),
                    Focused(state) => input.window_focus(state),
                    Closed => running = false,
                    KeyboardInput {
                        input: glutin::KeyboardInput {
                            state,
                            virtual_keycode: Some(keycode),
                            ..
                        },
                        ..
                    } => input.keyboard_input(state, keycode),
                    MouseInput { state, button, .. } => input.mouse_input(state, button),
                    CursorMoved {
                        position: (x, y), ..
                    } => input.mouse_moved(
                        [x as f32, y as f32].into(),
                        renderer.map_to_ndc([x as f32, y as f32]),
                    ),
                    MouseWheel { delta, .. } => input.mouse_wheel_input(delta),
                    _ => {}
                },
                glutin::Event::DeviceEvent { event, .. } => match event {
                    glutin::DeviceEvent::Motion { axis, value } => {
                        input.axis_moved_raw(axis as u8, value as f32);
                    }
                    _ => {}
                },
                _ => {}
            }
        });

        running
    }

    /// Render the current scene with specific [`Camera`](struct.Camera.html).
    pub fn render(
        &mut self,
        camera: &Camera,
    ) {
        self.renderer.render(&self.scene, camera);
    }

    /// Get current window size in pixels.
    pub fn size(&self) -> mint::Vector2<f32> {
        let size = self.window
            .get_inner_size()
            .expect("Can't get window size");
        [size.0 as f32, size.1 as f32].into()
    }

    /// Sets how the cursor should be handled.
    ///
    /// See the documentation for [`CursorState`] for the possible cursor states.
    ///
    /// Note that if you use [`CursorState::Grab`], you should use [`Input::mouse_delta_raw`] for
    /// detecting mouse movement, as [`Input::mouse_delta`] will only report movement of the cursor
    /// within the window.
    ///
    /// [`CursorState`]: enum.CursorState.html
    /// [`CursorState::Grab`]: enum.CursorState.html#variant.Grab
    /// [`Input::mouse_delta_raw`]: struct.Input.html#method.mouse_delta_raw
    /// [`Input::mouse_delta`]: struct.Input.html#method.mouse_delta_raw
    pub fn set_cursor_state(&self, state: CursorState) {
        let _ = self.window.set_cursor_state(state);
    }

    /// Returns underlaying `glutin::GlWindow`.
    #[cfg(feature = "opengl")]
    pub fn glutin_window(&self) -> &glutin::GlWindow {
        &self.window
    }
}
<commit_msg>Add the ability to set the full screen mode after creating the window.<commit_after>//! Primitives for creating and controlling [`Window`](struct.Window.html).

use glutin;
use glutin::GlContext;
use mint;
use render;

use camera::Camera;
use factory::Factory;
use input::Input;
use render::Renderer;
use scene::Scene;
use std::path::PathBuf;

pub use glutin::CursorState;

/// `Window` is the core entity of every `three-rs` application.
///
/// It provides [user input](struct.Window.html#method.update),
/// [`Factory`](struct.Factory.html) and [`Renderer`](struct.Renderer.html).
pub struct Window {
    event_loop: glutin::EventsLoop,
    window: glutin::GlWindow,
    /// See [`Input`](struct.Input.html).
    pub input: Input,
    /// See [`Renderer`](struct.Renderer.html).
    pub renderer: Renderer,
    /// See [`Factory`](struct.Factory.html).
    pub factory: Factory,
    /// See [`Scene`](struct.Scene.html).
    pub scene: Scene,
    /// Reset input on each frame? See [`Input::reset`](struct.Input.html#method.reset).
    ///
    /// Defaults to `true`.
    pub reset_input: bool,
    is_fullscreen: bool,
}

/// Builder for creating new [`Window`](struct.Window.html) with desired parameters.
#[derive(Debug, Clone)]
pub struct Builder {
    dimensions: (u32, u32),
    fullscreen: bool,
    multisampling: u16,
    shader_directory: Option<PathBuf>,
    title: String,
    vsync: bool,
}

impl Builder {
    /// Set the size of the viewport (the resolution) in pixels. Defaults to 1024x768.
    pub fn dimensions(
        &mut self,
        width: u32,
        height: u32,
    ) -> &mut Self {
        self.dimensions = (width, height);
        self
    }

    /// Whether enable fullscreen mode or not. Defauls to `false`.
    pub fn fullscreen(
        &mut self,
        option: bool,
    ) -> &mut Self {
        self.fullscreen = option;
        self
    }

    /// Sets the multisampling level to request. A value of `0` indicates that multisampling must
    /// not be enabled. Must be the power of 2. Defaults to `0`.
    pub fn multisampling(
        &mut self,
        option: u16,
    ) -> &mut Self {
        self.multisampling = option;
        self
    }

    /// Specifies the user shader directory.
    pub fn shader_directory<P: Into<PathBuf>>(
        &mut self,
        option: P,
    ) -> &mut Self {
        self.shader_directory = Some(option.into());
        self
    }

    /// Whether to enable vertical synchronization or not. Defaults to `true`.
    pub fn vsync(
        &mut self,
        option: bool,
    ) -> &mut Self {
        self.vsync = option;
        self
    }

    /// Create new `Window` with desired parameters.
    pub fn build(&mut self) -> Window {
        let event_loop = glutin::EventsLoop::new();
        let monitor_id = if self.fullscreen {
            Some(event_loop.get_primary_monitor())
        } else {
            None
        };
        let is_fullscreen = self.fullscreen;

        let builder = glutin::WindowBuilder::new()
            .with_fullscreen(monitor_id)
            .with_dimensions(self.dimensions.0, self.dimensions.1)
            .with_title(self.title.clone());

        let context = glutin::ContextBuilder::new()
            .with_vsync(self.vsync)
            .with_multisampling(self.multisampling);

        let mut source_set = render::source::Set::default();
        if let Some(path) = self.shader_directory.as_ref() {
            let path = path.to_str().unwrap();
            macro_rules! try_override {
                ($name:ident) => {
                    match render::Source::user(path, stringify!($name), "vs") {
                        Ok(src) => {
                            info!("Overriding {}_vs.glsl", stringify!($name));
                            source_set.$name.vs = src;
                        }
                        Err(err) => {
                            error!("{:#?}", err);
                            info!("Using default {}_vs.glsl", stringify!($name));
                        }
                    }
                    match render::Source::user(path, stringify!($name), "ps") {
                        Ok(src) => {
                            info!("Overriding {}_ps.glsl", stringify!($name));
                            source_set.$name.ps = src;
                        }
                        Err(err) => {
                            error!("{:#?}", err);
                            info!("Using default {}_ps.glsl", stringify!($name));
                        }
                    }
                };
                ( $($name:ident,)* ) => {
                    $( try_override!($name); )*
                };
            }
            try_override!(basic, gouraud, pbr, phong, quad, shadow, skybox, sprite,);
        }

        let (renderer, window, mut factory) = Renderer::new(builder, context, &event_loop, &source_set);
        let scene = factory.scene();
        Window {
            event_loop,
            window,
            input: Input::new(),
            renderer,
            factory,
            scene,
            reset_input: true,
            is_fullscreen,
        }
    }
}

impl Window {
    /// Create a new window with default parameters.
    pub fn new<T: Into<String>>(title: T) -> Self {
        Self::builder(title).build()
    }

    /// Create new `Builder` with standard parameters.
    pub fn builder<T: Into<String>>(title: T) -> Builder {
        Builder {
            dimensions: (1024, 768),
            fullscreen: false,
            multisampling: 0,
            shader_directory: None,
            title: title.into(),
            vsync: true,
        }
    }

    /// `update` method returns `false` if the window was closed.
    pub fn update(&mut self) -> bool {
        let mut running = true;
        let renderer = &mut self.renderer;
        let input = &mut self.input;
        if self.reset_input {
            input.reset();
        }

        self.window.swap_buffers().unwrap();
        let window = &self.window;

        self.event_loop.poll_events(|event| {
            use glutin::WindowEvent::{Closed, Focused, KeyboardInput, MouseInput, CursorMoved, MouseWheel, Resized};
            match event {
                glutin::Event::WindowEvent { event, .. } => match event {
                    Resized(..) => renderer.resize(window),
                    Focused(state) => input.window_focus(state),
                    Closed => running = false,
                    KeyboardInput {
                        input: glutin::KeyboardInput {
                            state,
                            virtual_keycode: Some(keycode),
                            ..
                        },
                        ..
                    } => input.keyboard_input(state, keycode),
                    MouseInput { state, button, .. } => input.mouse_input(state, button),
                    CursorMoved {
                        position: (x, y), ..
                    } => input.mouse_moved(
                        [x as f32, y as f32].into(),
                        renderer.map_to_ndc([x as f32, y as f32]),
                    ),
                    MouseWheel { delta, .. } => input.mouse_wheel_input(delta),
                    _ => {}
                },
                glutin::Event::DeviceEvent { event, .. } => match event {
                    glutin::DeviceEvent::Motion { axis, value } => {
                        input.axis_moved_raw(axis as u8, value as f32);
                    }
                    _ => {}
                },
                _ => {}
            }
        });

        running
    }

    /// Render the current scene with specific [`Camera`](struct.Camera.html).
    pub fn render(
        &mut self,
        camera: &Camera,
    ) {
        self.renderer.render(&self.scene, camera);
    }

    /// Get current window size in pixels.
    pub fn size(&self) -> mint::Vector2<f32> {
        let size = self.window
            .get_inner_size()
            .expect("Can't get window size");
        [size.0 as f32, size.1 as f32].into()
    }

    /// Sets how the cursor should be handled.
    ///
    /// See the documentation for [`CursorState`] for the possible cursor states.
    ///
    /// Note that if you use [`CursorState::Grab`], you should use [`Input::mouse_delta_raw`] for
    /// detecting mouse movement, as [`Input::mouse_delta`] will only report movement of the cursor
    /// within the window.
    ///
    /// [`CursorState`]: enum.CursorState.html
    /// [`CursorState::Grab`]: enum.CursorState.html#variant.Grab
    /// [`Input::mouse_delta_raw`]: struct.Input.html#method.mouse_delta_raw
    /// [`Input::mouse_delta`]: struct.Input.html#method.mouse_delta_raw
    pub fn set_cursor_state(&self, state: CursorState) {
        let _ = self.window.set_cursor_state(state);
    }

    /// Returns underlaying `glutin::GlWindow`.
    #[cfg(feature = "opengl")]
    pub fn glutin_window(&self) -> &glutin::GlWindow {
        &self.window
    }

    /// Returns the current full screen mode.
    pub fn is_fullscreen(&self) -> bool {
        self.is_fullscreen
    }

    /// Sets the full screen mode.
    /// If the window is already in full screen mode, does nothing.
    pub fn set_fullscreen(&mut self, fullscreen: bool) {
        if self.is_fullscreen == fullscreen {
            return;
        }
        self.is_fullscreen = fullscreen;
        let monitor = if fullscreen {
            Some(self.event_loop.get_primary_monitor())
        } else {
            None
        };
        self.window.set_fullscreen(monitor);
    }

    /// Toggles the full screen mode.
    /// Returns the new actual mode.
    pub fn toggle_fullscreen(&mut self) -> bool {
        let fullscreen = !self.is_fullscreen;
        self.set_fullscreen(fullscreen);
        fullscreen
    }
}
<|endoftext|>


<commit_before>use time;
use std::mem;
use sync::comm::Receiver;
use glfw;
use glfw::Context as _Context;
use gfx;

pub struct Window {
    title: String,
    dim: [u32, ..2],
}

impl Window {
    pub fn new() -> Window {
        Window {
            title: "window".to_string(),
            dim: [640, 360],
        }
    }

    /// Start running the engine, return an event iteration.
    pub fn run(&self) -> Context {
        Context::new(
            self.dim,
            self.title.as_slice(),
            Some(1.0 / 30.0))
    }
}

pub struct Context {
    glfw: glfw::Glfw,
    window: glfw::Window,
    events: Receiver<(f64, glfw::WindowEvent)>,
    graphics: gfx::Graphics<gfx::GlDevice, gfx::GlCommandBuffer>,
    frame: gfx::Frame,

    state: State,
    frame_interval: Option<f64>,
    last_render_time: f64,
}

#[deriving(PartialEq)]
enum State {
    Normal,
    EndFrame,
}

impl Context {
    fn new(
        dim: [u32, ..2],
        title: &str,
        frame_interval: Option<f64>) -> Context {

        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
        let (window, events) = glfw
            .create_window(dim[0], dim[1],
            title.as_slice(), glfw::Windowed)
            .expect("Failed to open window");
        window.make_current();
        glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
        window.set_key_polling(true);
        window.set_char_polling(true);

        let device = gfx::GlDevice::new(|s| glfw.get_proc_address(s));
        let graphics = gfx::Graphics::new(device);
        let frame = gfx::Frame::new(dim[0] as u16, dim[1] as u16);

        Context {
            glfw: glfw,
            window: window,
            events: events,
            graphics: graphics,
            frame: frame,
            state: Normal,
            frame_interval: frame_interval,
            last_render_time: time::precise_time_s(),
        }
    }

    /// Clear the screen
    pub fn clear(&mut self, color: [f32, ..4]) {
        self.graphics.clear(
            gfx::ClearData {
                color: color,
                depth: 1.0,
                stencil: 0,
            }, gfx::Color, &self.frame);
    }
}

pub enum Event<'a> {
    Render(&'a mut Context),
    Input(int), // TODO: Proper input type
}

impl<'a> Iterator<Event<'a>> for Context {
    fn next(&mut self) -> Option<Event<'a>> {
        // After a render event, control will return here on a new
        // iter call. Do post-render work here.
        if self.state == EndFrame {
            self.state = Normal;
            self.graphics.end_frame();
            self.window.swap_buffers();
        }

        loop {
            if self.window.should_close() {
                return None;
            }

            self.glfw.poll_events();

            match self.events.try_recv() {
                Ok(event) => {
                    // TODO: Process event.
                    return Some(Input(123))
                }
                _ => ()
            }

            let t = time::precise_time_s();
            if self.frame_interval.map_or(true,
                |x| t - self.last_render_time >= x) {
                self.last_render_time = t;

                // Time to render, must return a handle to self.
                // XXX: Need unsafe hackery to get around lifetimes check.
                self.state = EndFrame;
                unsafe {
                    return Some(Render(mem::transmute(self)))
                }
            }
        }
    }
}
<commit_msg>GLFW API update<commit_after>use time;
use std::mem;
use sync::comm::Receiver;
use glfw;
use glfw::Context as _Context;
use gfx;

pub struct Window {
    title: String,
    dim: [u32, ..2],
}

impl Window {
    pub fn new() -> Window {
        Window {
            title: "window".to_string(),
            dim: [640, 360],
        }
    }

    /// Start running the engine, return an event iteration.
    pub fn run(&self) -> Context {
        Context::new(
            self.dim,
            self.title.as_slice(),
            Some(1.0 / 30.0))
    }
}

pub struct Context {
    glfw: glfw::Glfw,
    window: glfw::Window,
    events: Receiver<(f64, glfw::WindowEvent)>,
    graphics: gfx::Graphics<gfx::GlDevice, gfx::GlCommandBuffer>,
    frame: gfx::Frame,

    state: State,
    frame_interval: Option<f64>,
    last_render_time: f64,
}

#[deriving(PartialEq)]
enum State {
    Normal,
    EndFrame,
}

impl Context {
    fn new(
        dim: [u32, ..2],
        title: &str,
        frame_interval: Option<f64>) -> Context {

        let glfw = glfw::init(glfw::FAIL_ON_ERRORS).unwrap();
        let (window, events) = glfw
            .create_window(dim[0], dim[1],
            title.as_slice(), glfw::Windowed)
            .expect("Failed to open window");
        window.make_current();
        glfw.set_error_callback(glfw::FAIL_ON_ERRORS);
        window.set_key_polling(true);
        window.set_char_polling(true);

        let device = gfx::GlDevice::new(|s| window.get_proc_address(s));
        let graphics = gfx::Graphics::new(device);
        let frame = gfx::Frame::new(dim[0] as u16, dim[1] as u16);

        Context {
            glfw: glfw,
            window: window,
            events: events,
            graphics: graphics,
            frame: frame,
            state: Normal,
            frame_interval: frame_interval,
            last_render_time: time::precise_time_s(),
        }
    }

    /// Clear the screen
    pub fn clear(&mut self, color: [f32, ..4]) {
        self.graphics.clear(
            gfx::ClearData {
                color: color,
                depth: 1.0,
                stencil: 0,
            }, gfx::Color, &self.frame);
    }
}

pub enum Event<'a> {
    Render(&'a mut Context),
    Input(int), // TODO: Proper input type
}

impl<'a> Iterator<Event<'a>> for Context {
    fn next(&mut self) -> Option<Event<'a>> {
        // After a render event, control will return here on a new
        // iter call. Do post-render work here.
        if self.state == EndFrame {
            self.state = Normal;
            self.graphics.end_frame();
            self.window.swap_buffers();
        }

        loop {
            if self.window.should_close() {
                return None;
            }

            self.glfw.poll_events();

            match self.events.try_recv() {
                Ok(_event) => {
                    // TODO: Process event.
                    return Some(Input(123))
                }
                _ => ()
            }

            let t = time::precise_time_s();
            if self.frame_interval.map_or(true,
                |x| t - self.last_render_time >= x) {
                self.last_render_time = t;

                // Time to render, must return a handle to self.
                // XXX: Need unsafe hackery to get around lifetimes check.
                self.state = EndFrame;
                unsafe {
                    return Some(Render(mem::transmute(self)))
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2015-2018 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Worker for performing corpus imports, when served as "init" tasks by the `CorTeX` dispatcher
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::borrow::Cow;
use std::error::Error;
use std::fs::File;
use std::path::Path;
use std::thread;
use std::time::Duration;
use zmq::{Context, Message, SNDMORE};

use crate::backend;
use crate::backend::DEFAULT_DB_ADDRESS;
use crate::importer::Importer;
use crate::models::{Corpus, NewCorpus, Task};
use pericortex::worker::Worker;

/// `Worker` for initializing/importing a new corpus into `CorTeX`
#[derive(Debug, Clone)]
pub struct InitWorker {
  /// name of the service ("init")
  pub service: String,
  /// version, as usual
  pub version: f32,
  /// message size, as usual
  pub message_size: usize,
  /// full URL (including port) to task source/dispatcher
  pub source: String,
  /// full URL (including port) to task sink/receiver
  pub sink: String,
  /// address to the Task store backend
  /// (special case, only for the init service, third-party workers can't access the Task store
  /// directly)
  pub backend_address: String,
  /// thread-local unique identifier
  pub identity: String,
}
impl Default for InitWorker {
  fn default() -> InitWorker {
    InitWorker {
      service: "init".to_string(),
      version: 0.1,
      message_size: 100_000,
      source: "tcp://localhost:51695".to_string(),
      sink: "tcp://localhost:51696".to_string(),
      backend_address: DEFAULT_DB_ADDRESS.to_string(),
      identity: String::new(),
    }
  }
}
impl Worker for InitWorker {
  fn get_service(&self) -> &str { &self.service }
  fn get_source_address(&self) -> Cow<str> { Cow::Borrowed(&self.source) }
  fn get_sink_address(&self) -> Cow<str> { Cow::Borrowed(&self.sink) }
  fn get_identity(&self) -> &str { &self.identity }
  fn set_identity(&mut self, identity: String) { self.identity = identity; }
  fn message_size(&self) -> usize { self.message_size }

  fn convert(&self, path_opt: &Path) -> Result<File, Box<dyn Error>> {
    let path = path_opt.to_str().unwrap().to_string();
    let name = path
      .rsplit_once('/')
      .map(|x| x.1)
      .unwrap_or(&path)
      .to_lowercase(); // TODO: this is Unix path only
    let backend = backend::from_address(&self.backend_address);
    let corpus = NewCorpus {
      name,
      path,
      complex: true,
      description: String::new(),
    };
    // Add the new corpus.
    backend.add(&corpus).expect("Failed to create new corpus.");
    let registered_corpus =
      Corpus::find_by_name(&corpus.name, &backend.connection).expect("Failed to create new corpus.");

    // Create an importer for the corpus, and then process all entries to populate CorTeX tasks
    let importer = Importer {
      corpus: registered_corpus,
      backend: backend::from_address(&self.backend_address),
      cwd: Importer::cwd(),
    };

    importer.process()?;
    // TODO: Stopgap, we should do the error-reporting well
    Err(From::from("init worker does not return a file handle."))
  }

  fn start(&mut self, limit: Option<usize>) -> Result<(), Box<dyn Error>> {
    let mut work_counter = 0;
    let mut rng = thread_rng();
    // Connect to a task ventilator
    let context_source = Context::new();
    let source = context_source.socket(zmq::DEALER).unwrap();
    let letters: Vec<_> = "abcdefghijklmonpqrstuvwxyz".chars().collect();
    let mut identity = String::new();
    for _step in 1..20 {
      identity.push(*letters.choose(&mut rng).unwrap());
    }
    source.set_identity(identity.as_bytes()).unwrap();

    source.connect(&self.get_source_address()).unwrap();
    // Connect to a task sink
    let context_sink = Context::new();
    let sink = context_sink.socket(zmq::PUSH).unwrap();
    sink.connect(&self.get_sink_address()).unwrap();
    let backend = backend::from_address(&self.backend_address);
    // Work in perpetuity
    loop {
      let mut taskid_msg = Message::new();
      let mut recv_msg = Message::new();

      source.send(self.get_service(), 0).unwrap();
      source.recv(&mut taskid_msg, 0).unwrap();
      let taskid = taskid_msg.as_str().unwrap();

      // Terminating with an empty message in place of a payload (INIT is special)
      source.recv(&mut recv_msg, 0).unwrap();

      let task_result = Task::find(taskid.parse::<i64>().unwrap(), &backend.connection);
      let task = match task_result {
        Ok(t) => t,
        _ => {
          // If there was nothing to do, retry a minute later
          thread::sleep(Duration::new(60, 0));
          continue;
        },
      };

      self.convert(Path::new(&task.entry))?;
      sink.send(&identity, SNDMORE).unwrap();
      sink.send(&self.get_service(), SNDMORE).unwrap();
      sink.send(taskid, SNDMORE).unwrap();
      sink.send(&Vec::new(), 0).unwrap();

      work_counter += 1;
      if let Some(upper_bound) = limit {
        if work_counter >= upper_bound {
          // Give enough time to complete the Final job.
          thread::sleep(Duration::from_millis(500));
          break;
        }
      };
    }
    Ok(())
  }
}
<commit_msg>small clippy lint<commit_after>// Copyright 2015-2018 Deyan Ginev. See the LICENSE
// file at the top-level directory of this distribution.
//
// Licensed under the MIT license <LICENSE-MIT or http://opensource.org/licenses/MIT>.
// This file may not be copied, modified, or distributed
// except according to those terms.

//! Worker for performing corpus imports, when served as "init" tasks by the `CorTeX` dispatcher
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::borrow::Cow;
use std::error::Error;
use std::fs::File;
use std::path::Path;
use std::thread;
use std::time::Duration;
use zmq::{Context, Message, SNDMORE};

use crate::backend;
use crate::backend::DEFAULT_DB_ADDRESS;
use crate::importer::Importer;
use crate::models::{Corpus, NewCorpus, Task};
use pericortex::worker::Worker;

/// `Worker` for initializing/importing a new corpus into `CorTeX`
#[derive(Debug, Clone)]
pub struct InitWorker {
  /// name of the service ("init")
  pub service: String,
  /// version, as usual
  pub version: f32,
  /// message size, as usual
  pub message_size: usize,
  /// full URL (including port) to task source/dispatcher
  pub source: String,
  /// full URL (including port) to task sink/receiver
  pub sink: String,
  /// address to the Task store backend
  /// (special case, only for the init service, third-party workers can't access the Task store
  /// directly)
  pub backend_address: String,
  /// thread-local unique identifier
  pub identity: String,
}
impl Default for InitWorker {
  fn default() -> InitWorker {
    InitWorker {
      service: "init".to_string(),
      version: 0.1,
      message_size: 100_000,
      source: "tcp://localhost:51695".to_string(),
      sink: "tcp://localhost:51696".to_string(),
      backend_address: DEFAULT_DB_ADDRESS.to_string(),
      identity: String::new(),
    }
  }
}
impl Worker for InitWorker {
  fn get_service(&self) -> &str { &self.service }
  fn get_source_address(&self) -> Cow<str> { Cow::Borrowed(&self.source) }
  fn get_sink_address(&self) -> Cow<str> { Cow::Borrowed(&self.sink) }
  fn get_identity(&self) -> &str { &self.identity }
  fn set_identity(&mut self, identity: String) { self.identity = identity; }
  fn message_size(&self) -> usize { self.message_size }

  fn convert(&self, path_opt: &Path) -> Result<File, Box<dyn Error>> {
    let path = path_opt.to_str().unwrap().to_string();
    let name = path
      .rsplit_once('/')
      .map(|x| x.1)
      .unwrap_or(&path)
      .to_lowercase(); // TODO: this is Unix path only
    let backend = backend::from_address(&self.backend_address);
    let corpus = NewCorpus {
      name,
      path,
      complex: true,
      description: String::new(),
    };
    // Add the new corpus.
    backend.add(&corpus).expect("Failed to create new corpus.");
    let registered_corpus =
      Corpus::find_by_name(&corpus.name, &backend.connection).expect("Failed to create new corpus.");

    // Create an importer for the corpus, and then process all entries to populate CorTeX tasks
    let importer = Importer {
      corpus: registered_corpus,
      backend: backend::from_address(&self.backend_address),
      cwd: Importer::cwd(),
    };

    importer.process()?;
    // TODO: Stopgap, we should do the error-reporting well
    Err(From::from("init worker does not return a file handle."))
  }

  fn start(&mut self, limit: Option<usize>) -> Result<(), Box<dyn Error>> {
    let mut work_counter = 0;
    let mut rng = thread_rng();
    // Connect to a task ventilator
    let context_source = Context::new();
    let source = context_source.socket(zmq::DEALER).unwrap();
    let letters: Vec<_> = "abcdefghijklmonpqrstuvwxyz".chars().collect();
    let mut identity = String::new();
    for _step in 1..20 {
      identity.push(*letters.choose(&mut rng).unwrap());
    }
    source.set_identity(identity.as_bytes()).unwrap();

    source.connect(&self.get_source_address()).unwrap();
    // Connect to a task sink
    let context_sink = Context::new();
    let sink = context_sink.socket(zmq::PUSH).unwrap();
    sink.connect(&self.get_sink_address()).unwrap();
    let backend = backend::from_address(&self.backend_address);
    // Work in perpetuity
    loop {
      let mut taskid_msg = Message::new();
      let mut recv_msg = Message::new();

      source.send(self.get_service(), 0).unwrap();
      source.recv(&mut taskid_msg, 0).unwrap();
      let taskid = taskid_msg.as_str().unwrap();

      // Terminating with an empty message in place of a payload (INIT is special)
      source.recv(&mut recv_msg, 0).unwrap();

      let task_result = Task::find(taskid.parse::<i64>().unwrap(), &backend.connection);
      let task = match task_result {
        Ok(t) => t,
        _ => {
          // If there was nothing to do, retry a minute later
          thread::sleep(Duration::new(60, 0));
          continue;
        },
      };

      self.convert(Path::new(&task.entry))?;
      sink.send(&identity, SNDMORE).unwrap();
      sink.send(self.get_service(), SNDMORE).unwrap();
      sink.send(taskid, SNDMORE).unwrap();
      sink.send(&Vec::new(), 0).unwrap();

      work_counter += 1;
      if let Some(upper_bound) = limit {
        if work_counter >= upper_bound {
          // Give enough time to complete the Final job.
          thread::sleep(Duration::from_millis(500));
          break;
        }
      };
    }
    Ok(())
  }
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This module defines all kinds of structures in the Sparse Merkle Tree maintained in scratch pad.
//! There are four kinds of nodes:
//! - A `SubTree::Empty` represents an empty subtree with zero leaf. Its root hash is assumed to be
//! the default hash.
//!
//! - A `SubTree::NonEmpty` represents a subtree with one or more leaves, it carries its root hash.
//!
//! From a `SubTree::NonEmpty` one may or may not get an reference to its root node, depending on
//! how this subtree structure was created and if the root node has been dropped (when its persisted
//! to DB and given up by any possible cache). A non empty subtree can refer to one of two types of
//! nodes as its root:
//!
//! - An `InternalNode` is a node that has two children. It is same as the internal node in a
//! standard Merkle tree.
//!
//! - A `LeafNode` represents a single account. Similar to what is in storage, a leaf node has a
//! key which is the hash of the account address as well as a value hash which is the hash of the
//! corresponding account content. The difference is that a `LeafNode` does not always have the
//! value, in the case when the leaf was loaded into memory as part of a non-inclusion proof.

use diem_crypto::{
    hash::{CryptoHash, SPARSE_MERKLE_PLACEHOLDER_HASH},
    HashValue,
};
use diem_types::proof::{SparseMerkleInternalNode, SparseMerkleLeafNode};
use std::sync::{Arc, Weak};

#[derive(Debug)]
pub(crate) struct InternalNode<V> {
    pub left: SubTree<V>,
    pub right: SubTree<V>,
}

impl<V: CryptoHash> InternalNode<V> {
    pub fn calc_hash(&self) -> HashValue {
        SparseMerkleInternalNode::new(self.left.hash(), self.right.hash()).hash()
    }
}

#[derive(Debug)]
pub(crate) struct LeafNode<V> {
    pub key: HashValue,
    pub value: LeafValue<V>,
}

impl<V: CryptoHash> LeafNode<V> {
    pub fn new(key: HashValue, value: LeafValue<V>) -> Self {
        Self { key, value }
    }
    pub fn calc_hash(&self) -> HashValue {
        SparseMerkleLeafNode::new(self.key, self.value.calc_hash()).hash()
    }
}

impl<V> From<SparseMerkleLeafNode> for LeafNode<V>
where
    V: CryptoHash,
{
    fn from(leaf_node: SparseMerkleLeafNode) -> Self {
        Self {
            key: leaf_node.key(),
            value: LeafValue::ValueHash(leaf_node.value_hash()),
        }
    }
}

#[derive(Debug)]
pub(crate) enum Node<V> {
    Internal(InternalNode<V>),
    Leaf(LeafNode<V>),
}

impl<V: CryptoHash> Node<V> {
    pub fn new_leaf(key: HashValue, value: LeafValue<V>) -> Self {
        Self::Leaf(LeafNode::new(key, value))
    }

    pub fn new_internal(left: SubTree<V>, right: SubTree<V>) -> Self {
        Self::Internal(InternalNode { left, right })
    }

    pub fn calc_hash(&self) -> HashValue {
        match self {
            Self::Internal(internal_node) => internal_node.calc_hash(),
            Self::Leaf(leaf_node) => leaf_node.calc_hash(),
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) enum NodeHandle<V> {
    Shared(Arc<Node<V>>),
    Weak(Weak<Node<V>>),
}

impl<V> NodeHandle<V> {
    pub fn new_unkonwn() -> Self {
        Self::Weak(Weak::new())
    }

    pub fn new_shared(node: Node<V>) -> Self {
        Self::Shared(Arc::new(node))
    }

    pub fn weak(&self) -> Self {
        Self::Weak(match self {
            Self::Shared(arc) => Arc::downgrade(arc),
            Self::Weak(weak) => weak.clone(),
        })
    }

    pub fn get_node_if_in_mem(&self) -> Option<Arc<Node<V>>> {
        match self {
            Self::Shared(arc) => Some(arc.clone()),
            Self::Weak(weak) => weak.upgrade(),
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) enum SubTree<V> {
    Empty,
    NonEmpty {
        hash: HashValue,
        root: NodeHandle<V>,
    },
}

impl<V: CryptoHash> SubTree<V> {
    pub fn new_empty() -> Self {
        Self::Empty
    }

    pub fn new_unknown(hash: HashValue) -> Self {
        Self::NonEmpty {
            hash,
            root: NodeHandle::new_unkonwn(),
        }
    }

    pub fn new_leaf_with_value(key: HashValue, value: V) -> Self {
        Self::new_leaf_impl(key, LeafValue::Value(value))
    }

    pub fn new_leaf_with_value_hash(key: HashValue, value_hash: HashValue) -> Self {
        Self::new_leaf_impl(key, LeafValue::ValueHash(value_hash))
    }

    fn new_leaf_impl(key: HashValue, value: LeafValue<V>) -> Self {
        let leaf = Node::new_leaf(key, value);

        Self::NonEmpty {
            hash: leaf.calc_hash(),
            root: NodeHandle::new_shared(leaf),
        }
    }

    pub fn new_internal(left: Self, right: Self) -> Self {
        let internal = Node::new_internal(left, right);

        Self::NonEmpty {
            hash: internal.calc_hash(),
            root: NodeHandle::new_shared(internal),
        }
    }

    pub fn hash(&self) -> HashValue {
        match self {
            Self::Empty => *SPARSE_MERKLE_PLACEHOLDER_HASH,
            Self::NonEmpty { hash, .. } => *hash,
        }
    }

    pub fn weak(&self) -> Self {
        match self {
            Self::Empty => Self::Empty,
            Self::NonEmpty { hash, root } => Self::NonEmpty {
                hash: *hash,
                root: root.weak(),
            },
        }
    }

    pub fn get_node_if_in_mem(&self) -> Option<Arc<Node<V>>> {
        match self {
            Self::Empty => None,
            Self::NonEmpty { root, .. } => root.get_node_if_in_mem(),
        }
    }

    #[cfg(test)]
    pub fn is_unknown(&self) -> bool {
        matches!(
            self,
            Self::NonEmpty {
                root: NodeHandle::Weak(_),
                ..
            }
        )
    }

    #[cfg(test)]
    pub fn is_empty(&self) -> bool {
        matches!(self, SubTree::Empty)
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LeafValue<V> {
    /// The content of the leaf.
    Value(V),

    /// The hash of the leaf content.
    ValueHash(HashValue),
}

impl<V: CryptoHash> LeafValue<V> {
    pub fn calc_hash(&self) -> HashValue {
        match self {
            LeafValue::Value(val) => val.hash(),
            LeafValue::ValueHash(val_hash) => *val_hash,
        }
    }
}
<commit_msg>correct type in node.rs<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

//! This module defines all kinds of structures in the Sparse Merkle Tree maintained in scratch pad.
//! There are four kinds of nodes:
//! - A `SubTree::Empty` represents an empty subtree with zero leaf. Its root hash is assumed to be
//! the default hash.
//!
//! - A `SubTree::NonEmpty` represents a subtree with one or more leaves, it carries its root hash.
//!
//! From a `SubTree::NonEmpty` one may or may not get an reference to its root node, depending on
//! how this subtree structure was created and if the root node has been dropped (when its persisted
//! to DB and given up by any possible cache). A non empty subtree can refer to one of two types of
//! nodes as its root:
//!
//! - An `InternalNode` is a node that has two children. It is same as the internal node in a
//! standard Merkle tree.
//!
//! - A `LeafNode` represents a single account. Similar to what is in storage, a leaf node has a
//! key which is the hash of the account address as well as a value hash which is the hash of the
//! corresponding account content. The difference is that a `LeafNode` does not always have the
//! value, in the case when the leaf was loaded into memory as part of a non-inclusion proof.

use diem_crypto::{
    hash::{CryptoHash, SPARSE_MERKLE_PLACEHOLDER_HASH},
    HashValue,
};
use diem_types::proof::{SparseMerkleInternalNode, SparseMerkleLeafNode};
use std::sync::{Arc, Weak};

#[derive(Debug)]
pub(crate) struct InternalNode<V> {
    pub left: SubTree<V>,
    pub right: SubTree<V>,
}

impl<V: CryptoHash> InternalNode<V> {
    pub fn calc_hash(&self) -> HashValue {
        SparseMerkleInternalNode::new(self.left.hash(), self.right.hash()).hash()
    }
}

#[derive(Debug)]
pub(crate) struct LeafNode<V> {
    pub key: HashValue,
    pub value: LeafValue<V>,
}

impl<V: CryptoHash> LeafNode<V> {
    pub fn new(key: HashValue, value: LeafValue<V>) -> Self {
        Self { key, value }
    }
    pub fn calc_hash(&self) -> HashValue {
        SparseMerkleLeafNode::new(self.key, self.value.calc_hash()).hash()
    }
}

impl<V> From<SparseMerkleLeafNode> for LeafNode<V>
where
    V: CryptoHash,
{
    fn from(leaf_node: SparseMerkleLeafNode) -> Self {
        Self {
            key: leaf_node.key(),
            value: LeafValue::ValueHash(leaf_node.value_hash()),
        }
    }
}

#[derive(Debug)]
pub(crate) enum Node<V> {
    Internal(InternalNode<V>),
    Leaf(LeafNode<V>),
}

impl<V: CryptoHash> Node<V> {
    pub fn new_leaf(key: HashValue, value: LeafValue<V>) -> Self {
        Self::Leaf(LeafNode::new(key, value))
    }

    pub fn new_internal(left: SubTree<V>, right: SubTree<V>) -> Self {
        Self::Internal(InternalNode { left, right })
    }

    pub fn calc_hash(&self) -> HashValue {
        match self {
            Self::Internal(internal_node) => internal_node.calc_hash(),
            Self::Leaf(leaf_node) => leaf_node.calc_hash(),
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) enum NodeHandle<V> {
    Shared(Arc<Node<V>>),
    Weak(Weak<Node<V>>),
}

impl<V> NodeHandle<V> {
    pub fn new_unknown() -> Self {
        Self::Weak(Weak::new())
    }

    pub fn new_shared(node: Node<V>) -> Self {
        Self::Shared(Arc::new(node))
    }

    pub fn weak(&self) -> Self {
        Self::Weak(match self {
            Self::Shared(arc) => Arc::downgrade(arc),
            Self::Weak(weak) => weak.clone(),
        })
    }

    pub fn get_node_if_in_mem(&self) -> Option<Arc<Node<V>>> {
        match self {
            Self::Shared(arc) => Some(arc.clone()),
            Self::Weak(weak) => weak.upgrade(),
        }
    }
}

#[derive(Clone, Debug)]
pub(crate) enum SubTree<V> {
    Empty,
    NonEmpty {
        hash: HashValue,
        root: NodeHandle<V>,
    },
}

impl<V: CryptoHash> SubTree<V> {
    pub fn new_empty() -> Self {
        Self::Empty
    }

    pub fn new_unknown(hash: HashValue) -> Self {
        Self::NonEmpty {
            hash,
            root: NodeHandle::new_unknown(),
        }
    }

    pub fn new_leaf_with_value(key: HashValue, value: V) -> Self {
        Self::new_leaf_impl(key, LeafValue::Value(value))
    }

    pub fn new_leaf_with_value_hash(key: HashValue, value_hash: HashValue) -> Self {
        Self::new_leaf_impl(key, LeafValue::ValueHash(value_hash))
    }

    fn new_leaf_impl(key: HashValue, value: LeafValue<V>) -> Self {
        let leaf = Node::new_leaf(key, value);

        Self::NonEmpty {
            hash: leaf.calc_hash(),
            root: NodeHandle::new_shared(leaf),
        }
    }

    pub fn new_internal(left: Self, right: Self) -> Self {
        let internal = Node::new_internal(left, right);

        Self::NonEmpty {
            hash: internal.calc_hash(),
            root: NodeHandle::new_shared(internal),
        }
    }

    pub fn hash(&self) -> HashValue {
        match self {
            Self::Empty => *SPARSE_MERKLE_PLACEHOLDER_HASH,
            Self::NonEmpty { hash, .. } => *hash,
        }
    }

    pub fn weak(&self) -> Self {
        match self {
            Self::Empty => Self::Empty,
            Self::NonEmpty { hash, root } => Self::NonEmpty {
                hash: *hash,
                root: root.weak(),
            },
        }
    }

    pub fn get_node_if_in_mem(&self) -> Option<Arc<Node<V>>> {
        match self {
            Self::Empty => None,
            Self::NonEmpty { root, .. } => root.get_node_if_in_mem(),
        }
    }

    #[cfg(test)]
    pub fn is_unknown(&self) -> bool {
        matches!(
            self,
            Self::NonEmpty {
                root: NodeHandle::Weak(_),
                ..
            }
        )
    }

    #[cfg(test)]
    pub fn is_empty(&self) -> bool {
        matches!(self, SubTree::Empty)
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum LeafValue<V> {
    /// The content of the leaf.
    Value(V),

    /// The hash of the leaf content.
    ValueHash(HashValue),
}

impl<V: CryptoHash> LeafValue<V> {
    pub fn calc_hash(&self) -> HashValue {
        match self {
            LeafValue::Value(val) => val.hash(),
            LeafValue::ValueHash(val_hash) => *val_hash,
        }
    }
}
<|endoftext|>


<commit_before>use nom::{
  IResult,
  bytes::complete::{
      tag,
      take_while1,
  },
  multi::{
      separated_list0,
      many0,
  },
  combinator::map,
  branch::alt,
  sequence::delimited,
  character::complete::{
      multispace1,
      multispace0,
  },
};
use std::fmt;

use nom::InputLength;
use nom::InputTake;
use nom::InputIter;
use nom::Slice;
use nom::UnspecializedInput;

use std::iter::Enumerate;
use std::ops::RangeFull;
use std::ops::RangeFrom;
use std::ops::RangeTo;
use std::ops::Range;

// TODO: add in specific support for parsing at-here and other special <!user_id> entities
// so that in the message subsystem it can do the right thing
#[derive(Debug, PartialEq)]
pub struct Command<'a> (pub &'a str, pub Vec<&'a str>);

pub fn command(input: &str) -> IResult<&str, Command> {
    let (input, _) = tag("!")(input)?;
    let (input, cmd) = command_string(input)?;
    let (input, _) = multispace0(input)?;
    let (input, arg) = args(input)?;

    Ok((input, Command(cmd, arg)))
}

fn command_string(input: &str) -> IResult<&str, &str> {
    take_while1(|c:char| c.is_alphanumeric())(input)
}

fn not_multispace1(input: &str) -> IResult<&str, &str> {
    alt((
        delimited(
            tag("\""),
            take_while1(|c:char| c != '"'),
            tag("\""),
        ),
        take_while1(|c:char| !c.is_whitespace()),
    ))(input)
}

fn args(input: &str) -> IResult<&str, Vec<&str>> {
    separated_list0(multispace1, not_multispace1)(input)
}

// This starts karma tokenizer stream
// TODO: make fancy but for now basic objective
// 1. Convert inbound &str to a token stream and work on that (for structural concerns)
// 2. support 2 types of braces '"' and '['/']' to support single type and open/close
// 3. suppport 3 types of karma, up, down, side
// 4. support single character or multiple character karma token, for now '++', '--', '+-' '±'
// 5. support 'emoji' karma token - ':++:'
#[derive(Debug, PartialEq, Clone)]
enum KarmaToken<'a>{
    // Alphanumberic
    Text(&'a str),
    // Whitespace (with a copy in so we can reproduce the string exactly) (only because we care if
    // there is whitespace before the karma or not)
    Space(&'a str),
    // Only the " mark
    // TODO: quotation escaping?
    Quote,
    // Only the [ mark
    OpenBrace,
    // Only the ] mark
    CloseBrace,
    // Karma (only complete chunk makes it in) (':++:', '++', '--', '+-', '±' for now)
    // TODO: this is eager, will need to figure out if we want to deal with "+++" at all
    Karma(&'a str)
}

impl <'a> fmt::Display for KarmaToken<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            KarmaToken::Text(t)    => write!(f, "{}", t),
            KarmaToken::Space(t)   => write!(f, "{}", t),
            KarmaToken::Karma(t)   => write!(f, "{}", t),
            KarmaToken::Quote      => write!(f, "\""),
            KarmaToken::OpenBrace  => write!(f, "["),
            KarmaToken::CloseBrace => write!(f, "]"),
        }
    }
}

fn all_token(input: &str) -> IResult<&str, Vec<KarmaToken>> {
    many0(token)(input)
}

fn token(input: &str) -> IResult<&str, KarmaToken> {
    alt((
        map(tag(":++:"), |k| KarmaToken::Karma(k)),
        map(tag("++"),   |k| KarmaToken::Karma(k)),
        map(tag("--"),   |k| KarmaToken::Karma(k)),
        map(tag("+-"),   |k| KarmaToken::Karma(k)),
        map(tag("±"),    |k| KarmaToken::Karma(k)),
        map(tag("\""),   |_| KarmaToken::Quote),
        map(tag("["),    |_| KarmaToken::OpenBrace),
        map(tag("]"),    |_| KarmaToken::CloseBrace),
        space,
        text,
    ))(input)
}

fn space(input: &str) -> IResult<&str, KarmaToken> {
    map(take_while1(|c:char| c.is_whitespace()), |s| KarmaToken::Space(s))(input)
}

fn text(input: &str) -> IResult<&str, KarmaToken> {
    map(take_while1(|c:char| c.is_alphanumeric()), |s| KarmaToken::Text(s))(input)
}

// Engine for allowing us to parse on top of tokens
#[derive(Debug, PartialEq, Clone, Copy)]
struct Tokens<'a> {
    tok: &'a [KarmaToken<'a>],
    start: usize,
    end: usize,
}

impl<'a> Tokens<'a> {
    fn new(vec: &'a Vec<KarmaToken<'a>>) -> Self {
        Tokens {
            tok: vec.as_slice(),
            start: 0,
            end: vec.len(),
        }
    }
}

impl<'a> InputLength for Tokens<'a> {
    #[inline]
    fn input_len(&self) -> usize {
        self.tok.len()
    }
}

impl<'a> InputTake for Tokens<'a> {
    #[inline]
    fn take(&self, count: usize) -> Self {
        Tokens {
            tok: &self.tok[0..count],
            start: 0,
            end: count,
        }
    }

    #[inline]
    fn take_split(&self, count: usize) -> (Self, Self) {
        let (prefix, suffix) = self.tok.split_at(count);
        let first = Tokens {
            tok: prefix,
            start: 0,
            end: prefix.len(),
        };
        let second = Tokens {
            tok: suffix,
            start: 0,
            end: suffix.len(),
        };
        (second, first)
    }
}

impl<'a> InputLength for KarmaToken<'a> {
    #[inline]
    fn input_len(&self) -> usize {
        1
    }
}

impl<'a> Slice<Range<usize>> for Tokens<'a> {
    #[inline]
    fn slice(&self, range: Range<usize>) -> Self {
        Tokens {
            tok: self.tok.slice(range.clone()),
            start: self.start + range.start,
            end: self.start + range.end,
        }
    }
}

impl<'a> Slice<RangeTo<usize>> for Tokens<'a> {
    #[inline]
    fn slice(&self, range: RangeTo<usize>) -> Self {
        self.slice(0..range.end)
    }
}

impl<'a> Slice<RangeFrom<usize>> for Tokens<'a> {
    #[inline]
    fn slice(&self, range: RangeFrom<usize>) -> Self {
        self.slice(range.start..self.end - self.start)
    }
}

impl<'a> Slice<RangeFull> for Tokens<'a> {
    #[inline]
    fn slice(&self, _: RangeFull) -> Self {
        Tokens {
            tok: self.tok,
            start: self.start,
            end: self.end,
        }
    }
}

impl<'a> InputIter for Tokens<'a> {
    type Item = &'a KarmaToken<'a>;
    type Iter = Enumerate<::std::slice::Iter<'a, KarmaToken<'a>>>;
    type IterElem = ::std::slice::Iter<'a, KarmaToken<'a>>;

    #[inline]
    fn iter_indices(&self) -> Enumerate<::std::slice::Iter<'a, KarmaToken<'a>>> {
        self.tok.iter().enumerate()
    }
    #[inline]
    fn iter_elements(&self) -> ::std::slice::Iter<'a, KarmaToken<'a>> {
        self.tok.iter()
    }
    #[inline]
    fn position<P>(&self, predicate: P) -> Option<usize>
    where
        P: Fn(Self::Item) -> bool,
    {
        self.tok.iter().position(|b| predicate(b))
    }
    #[inline]
    fn slice_index(&self, count: usize) -> Result<usize, nom::Needed> {
        if self.tok.len() >= count {
            Ok(count)
        } else {
            Err(nom::Needed::Unknown)
        }
    }
}

impl UnspecializedInput for Tokens<'_> {}

// Now here begins the actual structural karma parser (Karma Structure Tree (KST))
// Some simple rules for now:
// 1. asdf
#[derive(Debug, PartialEq)]
enum KST {
    Test
}

fn structural_karma(input: Tokens) -> IResult<Tokens, KST> {
    map(
        take_while1(|c:&KarmaToken| {
            match c {
                KarmaToken::Quote   => true,
                _ => false,
            }
        }),
        |_| KST::Test
    )(input)
}

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

    #[test]
    fn test_karma() {
        let token = all_token("\"\"++");

        let kst = token.unwrap().1;
        let kst = structural_karma(Tokens::new(&kst));

        let empty = vec![KarmaToken::Karma("++")];
        let empty = Tokens::new(&empty);

        assert_eq!(kst, Ok((empty, KST::Test)));
    }
}

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

    #[test]
    fn test_karma() {
        let karma = vec![":++:", "++", "--", "+-", "±"];

        assert_eq!(
            all_token(&karma.join("")),
            Ok(("", karma.iter().map(|k| KarmaToken::Karma(k)).collect()))
        );
    }

    #[test]
    fn test_quote() {
        assert_eq!(
            all_token("\"\"\""),
            Ok(("", vec![KarmaToken::Quote; 3]))
        );
    }

    #[test]
    fn test_brace() {
        assert_eq!(
            all_token("][]]"),
            Ok(("", vec![
                KarmaToken::CloseBrace,
                KarmaToken::OpenBrace,
                KarmaToken::CloseBrace,
                KarmaToken::CloseBrace
            ]))
        );
    }

    #[test]
    fn test_whitespace() {
        assert_eq!(
            all_token(" \t"),
            Ok(("", vec![KarmaToken::Space(" \t")]))
        );
    }

    #[test]
    fn test_whitespace_block() {
        assert_eq!(
            all_token(" ]\t[  "),
            Ok(("", vec![
                KarmaToken::Space(" "),
                KarmaToken::CloseBrace,
                KarmaToken::Space("\t"),
                KarmaToken::OpenBrace,
                KarmaToken::Space("  ")
            ]))
        );
    }

    #[test]
    fn test_text() {
        assert_eq!(
            all_token("this藏test"),
            Ok(("", vec![KarmaToken::Text("this藏test")]))
        );
    }

    #[test]
    fn test_text_block() {
        assert_eq!(
            all_token("this\t[\"藏  ++]"),
            Ok(("", vec![
                KarmaToken::Text("this"),
                KarmaToken::Space("\t"),
                KarmaToken::OpenBrace,
                KarmaToken::Quote,
                KarmaToken::Text("藏"),
                KarmaToken::Space("  "),
                KarmaToken::Karma("++"),
                KarmaToken::CloseBrace,
            ]))
        );
    }

    #[test]
    fn test_roundtrip() {
        let text = "this\t[\"藏  ++]";
        let parse = all_token(text).unwrap().1;

        assert_eq!(parse.iter().map(|t| t.to_string()).collect::<Vec<String>>().join(""), text);
    }
}

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

    #[test]
    fn test_command() {
        assert_eq!(
            command("!karma"),
            Ok(("", Command("karma", vec![])))
        );
    }

    #[test]
    fn test_command_one_arg() {
        assert_eq!(
            command("!karma a"),
            Ok(("", Command("karma", vec!["a"])))
        );
    }

    #[test]
    fn test_command_two_arg() {
        assert_eq!(
            command("!karma a bcd"),
            Ok(("", Command("karma", vec!["a", "bcd"])))
        );
    }

    #[test]
    fn test_command_one_quote_arg() {
        assert_eq!(
            command("!karma \"a b\""),
            Ok(("", Command("karma", vec!["a b"])))
        );
    }

    #[test]
    fn test_command_two_quote_arg() {
        assert_eq!(
            command("!karma \"a b\" \"c d\""),
            Ok(("", Command("karma", vec!["a b", "c d"])))
        );
    }

    #[test]
    fn test_command_two_quote_and_unquote_arg() {
        assert_eq!(
            command("!karma \"a b\" cd"),
            Ok(("", Command("karma", vec!["a b", "cd"])))
        );
    }

    #[test]
    fn test_command_fail_close_arg() {
        assert_eq!(
            command("!karma \"a"),
            Ok(("", Command("karma", vec!["\"a"])))
        );
    }

    #[test]
    fn test_command_fail_open_arg() {
        assert_eq!(
            command("!karma a\""),
            Ok(("", Command("karma", vec!["a\""])))
        );
    }

    // TODO: decide how to deal with this case
//    #[test]
//    fn test_command_multi_quote_arg() {
//        assert_eq!(
//            command("!karma \"\"a\"\""),
//            Ok(("", Command("karma", vec!["a"])))
//        );
//    }

    // TODO: decide how to deal with this case
//    #[test]
//    fn test_command_escape_quote_arg() {
//        assert_eq!(
//            command("!karma \"\\\"a\\\"\""),
//            Ok(("", Command("karma", vec!["\"a\""])))
//        );
//    }
}
<commit_msg>Working simple case<commit_after>use nom::{
  IResult,
  bytes::complete::{
      tag,
      take_while1,
      take,
  },
  multi::{
      separated_list0,
      many0,
  },
  combinator::{
      map,
      eof,
      peek,
  },
  branch::alt,
  sequence::{
      delimited,
      pair,
      terminated,
  },
  character::complete::{
      multispace1,
      multispace0,
  },
  error::{
      Error,
      ErrorKind,
  },
};
use std::fmt;

use nom::InputLength;
use nom::InputTake;
use nom::InputIter;
use nom::Slice;
use nom::UnspecializedInput;

use std::iter::Enumerate;
use std::ops::RangeFull;
use std::ops::RangeFrom;
use std::ops::RangeTo;
use std::ops::Range;

// TODO: add in specific support for parsing at-here and other special <!user_id> entities
// so that in the message subsystem it can do the right thing
#[derive(Debug, PartialEq)]
pub struct Command<'a> (pub &'a str, pub Vec<&'a str>);

pub fn command(input: &str) -> IResult<&str, Command> {
    let (input, _) = tag("!")(input)?;
    let (input, cmd) = command_string(input)?;
    let (input, _) = multispace0(input)?;
    let (input, arg) = args(input)?;

    Ok((input, Command(cmd, arg)))
}

fn command_string(input: &str) -> IResult<&str, &str> {
    take_while1(|c:char| c.is_alphanumeric())(input)
}

fn not_multispace1(input: &str) -> IResult<&str, &str> {
    alt((
        delimited(
            tag("\""),
            take_while1(|c:char| c != '"'),
            tag("\""),
        ),
        take_while1(|c:char| !c.is_whitespace()),
    ))(input)
}

fn args(input: &str) -> IResult<&str, Vec<&str>> {
    separated_list0(multispace1, not_multispace1)(input)
}

// This starts karma tokenizer stream
// TODO: make fancy but for now basic objective
// 1. Convert inbound &str to a token stream and work on that (for structural concerns)
// 2. support 2 types of braces '"' and '['/']' to support single type and open/close
// 3. suppport 3 types of karma, up, down, side
// 4. support single character or multiple character karma token, for now '++', '--', '+-' '±'
// 5. support 'emoji' karma token - ':++:'
#[derive(Debug, PartialEq, Clone)]
enum KarmaToken<'a>{
    // Alphanumberic
    Text(&'a str),
    // Whitespace (with a copy in so we can reproduce the string exactly) (only because we care if
    // there is whitespace before the karma or not)
    Space(&'a str),
    // Only the " mark
    // TODO: quotation escaping?
    Quote,
    // Only the [ mark
    OpenBrace,
    // Only the ] mark
    CloseBrace,
    // Karma (only complete chunk makes it in) (':++:', '++', '--', '+-', '±' for now)
    // TODO: this is eager, will need to figure out if we want to deal with "+++" at all
    Karma(&'a str)
}

impl <'a> fmt::Display for KarmaToken<'a> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            KarmaToken::Text(t)    => write!(f, "{}", t),
            KarmaToken::Space(t)   => write!(f, "{}", t),
            KarmaToken::Karma(t)   => write!(f, "{}", t),
            KarmaToken::Quote      => write!(f, "\""),
            KarmaToken::OpenBrace  => write!(f, "["),
            KarmaToken::CloseBrace => write!(f, "]"),
        }
    }
}

fn all_token(input: &str) -> IResult<&str, Vec<KarmaToken>> {
    many0(token)(input)
}

fn token(input: &str) -> IResult<&str, KarmaToken> {
    alt((
        map(tag(":++:"), |k| KarmaToken::Karma(k)),
        map(tag("++"),   |k| KarmaToken::Karma(k)),
        map(tag("--"),   |k| KarmaToken::Karma(k)),
        map(tag("+-"),   |k| KarmaToken::Karma(k)),
        map(tag("±"),    |k| KarmaToken::Karma(k)),
        map(tag("\""),   |_| KarmaToken::Quote),
        map(tag("["),    |_| KarmaToken::OpenBrace),
        map(tag("]"),    |_| KarmaToken::CloseBrace),
        space,
        text,
    ))(input)
}

fn space(input: &str) -> IResult<&str, KarmaToken> {
    map(take_while1(|c:char| c.is_whitespace()), |s| KarmaToken::Space(s))(input)
}

fn text(input: &str) -> IResult<&str, KarmaToken> {
    map(take_while1(|c:char| c.is_alphanumeric()), |s| KarmaToken::Text(s))(input)
}

// Engine for allowing us to parse on top of tokens
#[derive(Debug, PartialEq, Clone, Copy)]
struct Tokens<'a> {
    tok: &'a [KarmaToken<'a>],
    start: usize,
    end: usize,
}

impl<'a> Tokens<'a> {
    fn new(vec: &'a Vec<KarmaToken<'a>>) -> Self {
        Tokens {
            tok: vec.as_slice(),
            start: 0,
            end: vec.len(),
        }
    }
}

impl<'a> InputLength for Tokens<'a> {
    #[inline]
    fn input_len(&self) -> usize {
        self.tok.len()
    }
}

impl<'a> InputTake for Tokens<'a> {
    #[inline]
    fn take(&self, count: usize) -> Self {
        Tokens {
            tok: &self.tok[0..count],
            start: 0,
            end: count,
        }
    }

    #[inline]
    fn take_split(&self, count: usize) -> (Self, Self) {
        let (prefix, suffix) = self.tok.split_at(count);
        let first = Tokens {
            tok: prefix,
            start: 0,
            end: prefix.len(),
        };
        let second = Tokens {
            tok: suffix,
            start: 0,
            end: suffix.len(),
        };
        (second, first)
    }
}

impl<'a> InputLength for KarmaToken<'a> {
    #[inline]
    fn input_len(&self) -> usize {
        1
    }
}

impl<'a> Slice<Range<usize>> for Tokens<'a> {
    #[inline]
    fn slice(&self, range: Range<usize>) -> Self {
        Tokens {
            tok: self.tok.slice(range.clone()),
            start: self.start + range.start,
            end: self.start + range.end,
        }
    }
}

impl<'a> Slice<RangeTo<usize>> for Tokens<'a> {
    #[inline]
    fn slice(&self, range: RangeTo<usize>) -> Self {
        self.slice(0..range.end)
    }
}

impl<'a> Slice<RangeFrom<usize>> for Tokens<'a> {
    #[inline]
    fn slice(&self, range: RangeFrom<usize>) -> Self {
        self.slice(range.start..self.end - self.start)
    }
}

impl<'a> Slice<RangeFull> for Tokens<'a> {
    #[inline]
    fn slice(&self, _: RangeFull) -> Self {
        Tokens {
            tok: self.tok,
            start: self.start,
            end: self.end,
        }
    }
}

impl<'a> InputIter for Tokens<'a> {
    type Item = &'a KarmaToken<'a>;
    type Iter = Enumerate<::std::slice::Iter<'a, KarmaToken<'a>>>;
    type IterElem = ::std::slice::Iter<'a, KarmaToken<'a>>;

    #[inline]
    fn iter_indices(&self) -> Enumerate<::std::slice::Iter<'a, KarmaToken<'a>>> {
        self.tok.iter().enumerate()
    }
    #[inline]
    fn iter_elements(&self) -> ::std::slice::Iter<'a, KarmaToken<'a>> {
        self.tok.iter()
    }
    #[inline]
    fn position<P>(&self, predicate: P) -> Option<usize>
    where
        P: Fn(Self::Item) -> bool,
    {
        self.tok.iter().position(|b| predicate(b))
    }
    #[inline]
    fn slice_index(&self, count: usize) -> Result<usize, nom::Needed> {
        if self.tok.len() >= count {
            Ok(count)
        } else {
            Err(nom::Needed::Unknown)
        }
    }
}

impl UnspecializedInput for Tokens<'_> {}

// Now here begins the actual structural karma parser (Karma Structure Tree (KST))
#[derive(Debug, PartialEq)]
enum KST<'a> {
    Karma(&'a str, &'a str)
}

fn structural_karma(input: Tokens) -> IResult<Tokens, KST> {
    Ok((input, KST::Karma("str", "++")))
}

// TODO: how to make these basic parser way less ugly?
fn ktext(input: Tokens) -> IResult<Tokens, &str> {
    let (_, tkt) = peek(take(1usize))(input)?;

    // Extract this out of the Tokens structure
    let kt = tkt.tok.get(0);

    match kt {
        Some(KarmaToken::Text(t)) => {
            let (input, _) = take(1usize)(input)?;
            Ok((input, t))
        },
        _ => Err(nom::Err::Error(Error::new(input, ErrorKind::Tag))),
    }
}

fn kkarma(input: Tokens) -> IResult<Tokens, &str> {
    let (_, tkt) = peek(take(1usize))(input)?;

    // Extract this out of the Tokens structure
    let kt = tkt.tok.get(0);

    match kt {
        Some(KarmaToken::Karma(t)) => {
            let (input, _) = take(1usize)(input)?;
            Ok((input, t))
        },
        _ => Err(nom::Err::Error(Error::new(input, ErrorKind::Tag))),
    }
}

fn kspace(input: Tokens) -> IResult<Tokens, &str> {
    let (_, tkt) = peek(take(1usize))(input)?;

    // Extract this out of the Tokens structure
    let kt = tkt.tok.get(0);

    match kt {
        Some(KarmaToken::Space(t)) => {
            let (input, _) = take(1usize)(input)?;
            Ok((input, t))
        },
        _ => Err(nom::Err::Error(Error::new(input, ErrorKind::Tag))),
    }
}

// TODO: make basic parsers for - quote/(open/close brace)
//enum KarmaToken<'a>{ Text(&'a str), Space(&'a str), Quote, OpenBrace, CloseBrace, Karma(&'a str) }

// Simple Karma:
// 1. a++     -> ("",    Karma("a", "++"))
// 2. a++ b++ -> ("b++", Karma("a", "++"))
// 3. a++ b   -> ("b",   Karma("a", "++"))
//
// Ground rule for this particular parse:
// 1. Text followed by karma
// 2. Karma followed by whitespace/eol
fn simple(input: Tokens) -> IResult<Tokens, KST> {
    map(terminated(
            pair(ktext, kkarma),
            alt((
                kspace,
                map(eof, |_| ""),
            )),
        ),
        |(t, k)| KST::Karma(t, k)
    )(input)
}

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

    #[test]
    fn test_case_one() {
        let token = all_token("a++").unwrap().1;
        let parse = simple(Tokens::new(&token));

        let empty = vec![];
        let empty = Tokens::new(&empty);
        assert_eq!(parse, Ok((empty, KST::Karma("a", "++"))));
    }

    #[test]
    fn test_case_two() {
        let token = all_token("a++ b").unwrap().1;
        let parse = simple(Tokens::new(&token));

        let empty = vec![KarmaToken::Text("b")];
        let empty = Tokens::new(&empty);
        assert_eq!(parse, Ok((empty, KST::Karma("a", "++"))));
    }

    #[test]
    fn test_case_three() {
        let token = all_token("a++ b++").unwrap().1;
        let parse = simple(Tokens::new(&token));

        let empty = vec![KarmaToken::Text("b"), KarmaToken::Karma("++")];
        let empty = Tokens::new(&empty);
        assert_eq!(parse, Ok((empty, KST::Karma("a", "++"))));
    }
}

// TODO:
// 4. a b++   -> ("",    Karma(Up, "b"))
//
// Simple invalid cases:
// 1. a
// 2. a b
// 3. a++b
// 4. ++
// 5. a ++
//

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

    #[test]
    fn test_karma() {
        let karma = vec![":++:", "++", "--", "+-", "±"];

        assert_eq!(
            all_token(&karma.join("")),
            Ok(("", karma.iter().map(|k| KarmaToken::Karma(k)).collect()))
        );
    }

    #[test]
    fn test_quote() {
        assert_eq!(
            all_token("\"\"\""),
            Ok(("", vec![KarmaToken::Quote; 3]))
        );
    }

    #[test]
    fn test_brace() {
        assert_eq!(
            all_token("][]]"),
            Ok(("", vec![
                KarmaToken::CloseBrace,
                KarmaToken::OpenBrace,
                KarmaToken::CloseBrace,
                KarmaToken::CloseBrace
            ]))
        );
    }

    #[test]
    fn test_whitespace() {
        assert_eq!(
            all_token(" \t"),
            Ok(("", vec![KarmaToken::Space(" \t")]))
        );
    }

    #[test]
    fn test_whitespace_block() {
        assert_eq!(
            all_token(" ]\t[  "),
            Ok(("", vec![
                KarmaToken::Space(" "),
                KarmaToken::CloseBrace,
                KarmaToken::Space("\t"),
                KarmaToken::OpenBrace,
                KarmaToken::Space("  ")
            ]))
        );
    }

    #[test]
    fn test_text() {
        assert_eq!(
            all_token("this藏test"),
            Ok(("", vec![KarmaToken::Text("this藏test")]))
        );
    }

    #[test]
    fn test_text_block() {
        assert_eq!(
            all_token("this\t[\"藏  ++]"),
            Ok(("", vec![
                KarmaToken::Text("this"),
                KarmaToken::Space("\t"),
                KarmaToken::OpenBrace,
                KarmaToken::Quote,
                KarmaToken::Text("藏"),
                KarmaToken::Space("  "),
                KarmaToken::Karma("++"),
                KarmaToken::CloseBrace,
            ]))
        );
    }

    #[test]
    fn test_roundtrip() {
        let text = "this\t[\"藏  ++]";
        let parse = all_token(text).unwrap().1;

        assert_eq!(parse.iter().map(|t| t.to_string()).collect::<Vec<String>>().join(""), text);
    }
}

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

    #[test]
    fn test_command() {
        assert_eq!(
            command("!karma"),
            Ok(("", Command("karma", vec![])))
        );
    }

    #[test]
    fn test_command_one_arg() {
        assert_eq!(
            command("!karma a"),
            Ok(("", Command("karma", vec!["a"])))
        );
    }

    #[test]
    fn test_command_two_arg() {
        assert_eq!(
            command("!karma a bcd"),
            Ok(("", Command("karma", vec!["a", "bcd"])))
        );
    }

    #[test]
    fn test_command_one_quote_arg() {
        assert_eq!(
            command("!karma \"a b\""),
            Ok(("", Command("karma", vec!["a b"])))
        );
    }

    #[test]
    fn test_command_two_quote_arg() {
        assert_eq!(
            command("!karma \"a b\" \"c d\""),
            Ok(("", Command("karma", vec!["a b", "c d"])))
        );
    }

    #[test]
    fn test_command_two_quote_and_unquote_arg() {
        assert_eq!(
            command("!karma \"a b\" cd"),
            Ok(("", Command("karma", vec!["a b", "cd"])))
        );
    }

    #[test]
    fn test_command_fail_close_arg() {
        assert_eq!(
            command("!karma \"a"),
            Ok(("", Command("karma", vec!["\"a"])))
        );
    }

    #[test]
    fn test_command_fail_open_arg() {
        assert_eq!(
            command("!karma a\""),
            Ok(("", Command("karma", vec!["a\""])))
        );
    }

    // TODO: decide how to deal with this case
//    #[test]
//    fn test_command_multi_quote_arg() {
//        assert_eq!(
//            command("!karma \"\"a\"\""),
//            Ok(("", Command("karma", vec!["a"])))
//        );
//    }

    // TODO: decide how to deal with this case
//    #[test]
//    fn test_command_escape_quote_arg() {
//        assert_eq!(
//            command("!karma \"\\\"a\\\"\""),
//            Ok(("", Command("karma", vec!["\"a\""])))
//        );
//    }
}
<|endoftext|>


<commit_before>
pub use descartes::{N, P3, P2, V3, V4, M4, Iso3, Persp3, ToHomogeneous, Norm, Into2d, Into3d,
                    WithUniqueOrthogonal, Inverse, Rotate};
use kay::{Recipient, Fate};

use ::{Renderer, Eye};

#[derive(Copy, Clone)]
pub enum Movement {
    Shift(V3),
    Zoom(N),
    Yaw(N),
    Pitch(N),
}

#[derive(Copy, Clone)]
pub struct MoveEye {
    pub scene_id: usize,
    pub movement: Movement,
}
#[derive(Copy, Clone)]
pub struct EyeMoved {
    pub eye: Eye,
    pub movement: Movement,
}

impl Recipient<MoveEye> for Renderer {
    fn receive(&mut self, msg: &MoveEye) -> Fate {
        match *msg {
            MoveEye { scene_id, movement } => {
                match movement {
                    Movement::Shift(delta) => self.movement_shift(scene_id, delta),
                    Movement::Zoom(delta) => self.movement_zoom(scene_id, delta),
                    Movement::Yaw(delta) => self.movement_yaw(scene_id, delta),
                    Movement::Pitch(delta) => self.movement_pitch(scene_id, delta),
                }

                for &id in &self.scenes[scene_id].eye_listeners {
                    id <<
                    EyeMoved {
                        eye: self.scenes[scene_id].eye,
                        movement: movement,
                    };
                }
                Fate::Live
            }
        }
    }
}

impl Renderer {
    fn movement_shift(&mut self, scene_id: usize, delta: V3) {
        let eye = &mut self.scenes[scene_id].eye;
        let eye_direction_2d = (eye.target - eye.position).into_2d().normalize();
        let absolute_delta = delta.x * eye_direction_2d.into_3d() +
                             delta.y * eye_direction_2d.orthogonal().into_3d() +
                             V3::new(0.0, 0.0, delta.z);

        eye.position += absolute_delta * (eye.position.z / 100.0);
        eye.target += absolute_delta * (eye.position.z / 100.0);
    }

    fn movement_zoom(&mut self, scene_id: usize, delta: N) {
        let eye = &mut self.scenes[scene_id].eye;
        let eye_direction = (eye.target - eye.position).normalize();
        if (eye.target - eye.position).norm() > 30.0 || delta < 0.0 {
            eye.position += eye_direction * delta * (eye.position.z / 100.0);
        }
    }

    fn movement_yaw(&mut self, scene_id: usize, delta: N) {
        let eye = &mut self.scenes[scene_id].eye;
        let relative_eye_position = eye.position - eye.target;
        let iso = Iso3::new(V3::new(0.0, 0.0, 0.0), V3::new(0.0, 0.0, delta));
        let rotated_relative_eye_position = iso.rotate(&relative_eye_position);

        eye.position = eye.target + rotated_relative_eye_position;
    }

    fn movement_pitch(&mut self, scene_id: usize, delta: N) {
        let eye = &mut self.scenes[scene_id].eye;
        let relative_eye_position = eye.position - eye.target;

        // Convert relative eye position to spherical coordinates
        let r = relative_eye_position.norm();
        let mut inc = (relative_eye_position.z / r).acos();
        let azi = relative_eye_position.y.atan2(relative_eye_position.x);

        // Add delta to the inclination
        inc += delta;

        // Clamp the inclination to within 0;1.5 radians
        inc = if inc < 0.0001 { 0.0001 } else { inc }; // Check lower bounds
        inc = if inc > 1.5 { 1.5 } else { inc }; // Check upper bounds;

        println!("{}", inc);

        // Convert spherical coordinates back into carteesiam coordinates
        let x = r * inc.sin() * azi.cos();
        let y = r * inc.sin() * azi.sin();
        let z = r * inc.cos();

        // The spherical coordinates are calculated relative to the target.
        eye.position = eye.target + V3::new(x, y, z);
    }
}
<commit_msg>Remove debug printing<commit_after>
pub use descartes::{N, P3, P2, V3, V4, M4, Iso3, Persp3, ToHomogeneous, Norm, Into2d, Into3d,
                    WithUniqueOrthogonal, Inverse, Rotate};
use kay::{Recipient, Fate};

use ::{Renderer, Eye};

#[derive(Copy, Clone)]
pub enum Movement {
    Shift(V3),
    Zoom(N),
    Yaw(N),
    Pitch(N),
}

#[derive(Copy, Clone)]
pub struct MoveEye {
    pub scene_id: usize,
    pub movement: Movement,
}
#[derive(Copy, Clone)]
pub struct EyeMoved {
    pub eye: Eye,
    pub movement: Movement,
}

impl Recipient<MoveEye> for Renderer {
    fn receive(&mut self, msg: &MoveEye) -> Fate {
        match *msg {
            MoveEye { scene_id, movement } => {
                match movement {
                    Movement::Shift(delta) => self.movement_shift(scene_id, delta),
                    Movement::Zoom(delta) => self.movement_zoom(scene_id, delta),
                    Movement::Yaw(delta) => self.movement_yaw(scene_id, delta),
                    Movement::Pitch(delta) => self.movement_pitch(scene_id, delta),
                }

                for &id in &self.scenes[scene_id].eye_listeners {
                    id <<
                    EyeMoved {
                        eye: self.scenes[scene_id].eye,
                        movement: movement,
                    };
                }
                Fate::Live
            }
        }
    }
}

impl Renderer {
    fn movement_shift(&mut self, scene_id: usize, delta: V3) {
        let eye = &mut self.scenes[scene_id].eye;
        let eye_direction_2d = (eye.target - eye.position).into_2d().normalize();
        let absolute_delta = delta.x * eye_direction_2d.into_3d() +
                             delta.y * eye_direction_2d.orthogonal().into_3d() +
                             V3::new(0.0, 0.0, delta.z);

        eye.position += absolute_delta * (eye.position.z / 100.0);
        eye.target += absolute_delta * (eye.position.z / 100.0);
    }

    fn movement_zoom(&mut self, scene_id: usize, delta: N) {
        let eye = &mut self.scenes[scene_id].eye;
        let eye_direction = (eye.target - eye.position).normalize();
        if (eye.target - eye.position).norm() > 30.0 || delta < 0.0 {
            eye.position += eye_direction * delta * (eye.position.z / 100.0);
        }
    }

    fn movement_yaw(&mut self, scene_id: usize, delta: N) {
        let eye = &mut self.scenes[scene_id].eye;
        let relative_eye_position = eye.position - eye.target;
        let iso = Iso3::new(V3::new(0.0, 0.0, 0.0), V3::new(0.0, 0.0, delta));
        let rotated_relative_eye_position = iso.rotate(&relative_eye_position);

        eye.position = eye.target + rotated_relative_eye_position;
    }

    fn movement_pitch(&mut self, scene_id: usize, delta: N) {
        let eye = &mut self.scenes[scene_id].eye;
        let relative_eye_position = eye.position - eye.target;

        // Convert relative eye position to spherical coordinates
        let r = relative_eye_position.norm();
        let mut inc = (relative_eye_position.z / r).acos();
        let azi = relative_eye_position.y.atan2(relative_eye_position.x);

        // Add delta to the inclination
        inc += delta;

        // Clamp the inclination to within 0;1.5 radians
        inc = if inc < 0.0001 { 0.0001 } else { inc }; // Check lower bounds
        inc = if inc > 1.5 { 1.5 } else { inc }; // Check upper bounds;

        // Convert spherical coordinates back into carteesiam coordinates
        let x = r * inc.sin() * azi.cos();
        let y = r * inc.sin() * azi.sin();
        let z = r * inc.cos();

        // The spherical coordinates are calculated relative to the target.
        eye.position = eye.target + V3::new(x, y, z);
    }
}
<|endoftext|>


<commit_before>// force-host
// no-prefer-dynamic

#![feature(repr128)]
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
use std::iter::FromIterator;

#[proc_macro]
pub fn macro_test(input_stream: TokenStream) -> TokenStream {
    let first_token = input_stream.into_iter().next().unwrap();
    let span = first_token.span();

    TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("fn", Span::call_site())),
        TokenTree::Ident(Ident::new("code", Span::call_site())),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
        TokenTree::Group(Group::new(Delimiter::Brace, {
            let mut clause = Group::new(Delimiter::Brace, TokenStream::new());
            clause.set_span(span);

            TokenStream::from_iter(vec![
                TokenTree::Ident(Ident::new("if", Span::call_site())),
                TokenTree::Ident(Ident::new("true", Span::call_site())),
                TokenTree::Group(clause.clone()),
                TokenTree::Ident(Ident::new("else", Span::call_site())),
                TokenTree::Group(clause.clone()),
            ])
        })),
    ])
}
<commit_msg>Remove force-host and explain no-prefer-dynamic<commit_after>// no-prefer-dynamic
// ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro
// crates. If we don't set this, compiletest will override the `crate_type` attribute below and
// compile this as dylib. Removing this then causes the test to fail because a `dylib` crate can't
// contain a proc-macro.

#![feature(repr128)]
#![crate_type = "proc-macro"]

extern crate proc_macro;

use proc_macro::{Delimiter, Group, Ident, Span, TokenStream, TokenTree};
use std::iter::FromIterator;

#[proc_macro]
pub fn macro_test(input_stream: TokenStream) -> TokenStream {
    let first_token = input_stream.into_iter().next().unwrap();
    let span = first_token.span();

    TokenStream::from_iter(vec![
        TokenTree::Ident(Ident::new("fn", Span::call_site())),
        TokenTree::Ident(Ident::new("code", Span::call_site())),
        TokenTree::Group(Group::new(Delimiter::Parenthesis, TokenStream::new())),
        TokenTree::Group(Group::new(Delimiter::Brace, {
            let mut clause = Group::new(Delimiter::Brace, TokenStream::new());
            clause.set_span(span);

            TokenStream::from_iter(vec![
                TokenTree::Ident(Ident::new("if", Span::call_site())),
                TokenTree::Ident(Ident::new("true", Span::call_site())),
                TokenTree::Group(clause.clone()),
                TokenTree::Ident(Ident::new("else", Span::call_site())),
                TokenTree::Group(clause.clone()),
            ])
        })),
    ])
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use super::{
    ClientDB,
    DBError,
};
use super::POW_CHAIN_DB_COLUMN as DB_COLUMN;
extern crate rand;

pub struct PoWChainStore<T>
    where T: ClientDB
{
    db: Arc<T>,
}

impl<T: ClientDB> PoWChainStore<T> {
    pub fn new(db: Arc<T>) -> Self {
        Self {
            db,
        }
    }

    pub fn put_block_hash(&self, hash: &[u8])
        -> Result<(), DBError>
    {
        self.db.put(DB_COLUMN, hash, &[0])
    }

    pub fn block_hash_exists(&self, hash: &[u8])
        -> Result<bool, DBError>
    {
        self.db.exists(DB_COLUMN, hash)
    }
}

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

    #[test]
    fn test_put_block_hash() {
        let db = Arc::new(MemoryDB::open());
        let store = PoWChainStore::new(db.clone());

        let hash: &[u8] = &[rand::random()];
        store.put_block_hash(hash);

        assert!(db.exists(DB_COLUMN, hash).unwrap());
    }

    #[test]
    fn test_block_hash_exists() {
        let db = Arc::new(MemoryDB::open());
        let store = PoWChainStore::new(db.clone());

        let hash: &[u8] = &[rand::random()];
        db.put(DB_COLUMN, hash, &[0]);

        assert!(store.block_hash_exists(hash).unwrap());
    }

    #[test]
    fn test_block_hash_does_not_exist() {
        let db = Arc::new(MemoryDB::open());
        let store = PoWChainStore::new(db.clone());

        let hash: &[u8] = &[rand::random()];
        let other_hash: &[u8] = &[rand::random()];
        db.put(DB_COLUMN, hash, &[0]);

        assert!(!store.block_hash_exists(other_hash).unwrap());
    }
}
<commit_msg>rand import moved<commit_after>use std::sync::Arc;
use super::{
    ClientDB,
    DBError,
};
use super::POW_CHAIN_DB_COLUMN as DB_COLUMN;

pub struct PoWChainStore<T>
    where T: ClientDB
{
    db: Arc<T>,
}

impl<T: ClientDB> PoWChainStore<T> {
    pub fn new(db: Arc<T>) -> Self {
        Self {
            db,
        }
    }

    pub fn put_block_hash(&self, hash: &[u8])
        -> Result<(), DBError>
    {
        self.db.put(DB_COLUMN, hash, &[0])
    }

    pub fn block_hash_exists(&self, hash: &[u8])
        -> Result<bool, DBError>
    {
        self.db.exists(DB_COLUMN, hash)
    }
}

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

    use super::*;
    use super::super::super::MemoryDB;

    #[test]
    fn test_put_block_hash() {
        let db = Arc::new(MemoryDB::open());
        let store = PoWChainStore::new(db.clone());

        let hash: &[u8] = &[rand::random()];
        store.put_block_hash(hash);

        assert!(db.exists(DB_COLUMN, hash).unwrap());
    }

    #[test]
    fn test_block_hash_exists() {
        let db = Arc::new(MemoryDB::open());
        let store = PoWChainStore::new(db.clone());

        let hash: &[u8] = &[rand::random()];
        db.put(DB_COLUMN, hash, &[0]);

        assert!(store.block_hash_exists(hash).unwrap());
    }

    #[test]
    fn test_block_hash_does_not_exist() {
        let db = Arc::new(MemoryDB::open());
        let store = PoWChainStore::new(db.clone());

        let hash: &[u8] = &[rand::random()];
        let other_hash: &[u8] = &[rand::random()];
        db.put(DB_COLUMN, hash, &[0]);

        assert!(!store.block_hash_exists(other_hash).unwrap());
    }
}
<|endoftext|>