<commit_before>//! Layout handling

// remove
#![allow(unused)]

use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::types::VIEW_MAXIMIZED;
use std::rc::{Rc, Weak};
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::cell::RefCell;

pub type Node = Rc<RefCell<Container>>;

#[derive(Debug, Clone)]
enum Handle {
    View(WlcView),
    Output(WlcOutput)
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerType {
    /// Root container, only one exists
    Root,
    /// WlcOutput/Monitor
    Output,
    /// A workspace
    Workspace,
    /// A view (window)
    View
}

/// Layout mode for a container
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Layout {
    None,
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

#[derive(Clone)]
pub struct Container {
    handle: Option<Handle>,
    parent: Option<Weak<RefCell<Container>>>,
    children: Vec<Node>,
    container_type: ContainerType,
    layout: Layout,
    width: u32,
    height: u32,
    x: i64,
    y: i64,
    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

/// Like i3, everything (workspaces, containers, views) are containable.
impl Container {

    /// Makes the root container. There should be only one of these
    /// Does not ensure that this is the only root container
    // NOTE Need to find a way to ensure there is only one of these things
    // Perhaps set a static global variable
    pub fn new_root() -> Node {
        trace!("Root created");
        Rc::new(RefCell::new(Container {
            handle: None,
            parent: None,
            children: vec!(),
            container_type: ContainerType::Root,
            layout: Layout::None,
            width: 0,
            height: 0,
            x: 0,
            y: 0,
            visible: false,
            is_focused: false,
            is_floating: false
        }))
    }

    /// Makes a new workspace container. This should only be called by root
    /// since it will properly initialize the right number and properly put
    /// them in the main tree.
    pub fn new_workspace(root: &mut Node) -> Node {
        if ! root.borrow().is_root() {
            panic!("Only workspaces can be added to the root node");
        }
        let workspace: Node =
            Rc::new(RefCell::new(Container {
                handle: None,
                parent: Some(Rc::downgrade(&root)),
                children: vec!(),
                container_type: ContainerType::Workspace,
                // NOTE Change this to some other default
                layout: Layout::None,
                // NOTE Figure out how to initialize these properly
                width: 0,
                height: 0,
                x: 0,
                y: 0,
                visible: false,
                is_focused: false,
                is_floating: false,
                }));
        root.borrow_mut().add_child(workspace.clone());
        workspace
    }
    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    pub fn get_parent(&self) -> Option<Node> {
        if self.is_root() {
            None
        } else {
            // NOTE Clone has to be done here because we have to store the
            // parent as an option since the `Weak::new` is unstable
            if let Some(parent) = self.parent.clone() {
                parent.upgrade()
            } else {
                None
            }
        }
    }

    pub fn add_child(&mut self, container: Node) {
        if self.get_type() == ContainerType::Workspace
            && container.borrow().get_type() == ContainerType::Workspace {
            panic!("Only containers can be children of a workspace");
        }
        // NOTE check to make sure we are not adding a duplicate
        self.children.push(container);
    }

    /// Removes this container and all of its children
    pub fn remove_container(&mut self) -> Result<(), &'static str> {
        if self.is_root() {
            panic!("Cannot remove root container");
        }
        if let Some(parent) = self.get_parent() {
            parent.borrow_mut().remove_child(self);
        }
        self.children = vec!();
        Ok(())
    }

    /// Gets the children of this container.
    ///
    /// Views never have children
    pub fn get_children(&self) -> Option<Vec<Node>> {
        if self.get_type() == ContainerType::View {
            None
        }
        else {
            Some(self.children.clone())
        }
    }

    /// Gets the type of the container
    pub fn get_type(&self) -> ContainerType {
        self.container_type
    }

    /// Returns true if this container is focused.
    pub fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes the child at the specified index
    pub fn remove_child_at(&mut self, index: usize) -> Result<Node, &'static str> {
        Ok(self.children.remove(index))
    }

    /// Removes the given child from this container's children.
    /// If the child is not present, then an error is returned
    pub fn remove_child(&mut self, node: &mut Container) -> Result<Node, &'static str> {
        for (index, child) in self.children.clone().iter().enumerate() {
            if *child.borrow() == *node {
                return Ok(self.children.remove(index));
            }
        }
        return Err("");//&format!("Could not find child {:?} in {:?}", node, self));
    }

    /// Sets this container (and everything in it) to given visibility
    pub fn set_visibility(&mut self, visibility: bool) {
        self.visible = visibility
    }

    /// Gets the visibility of the container
    pub fn get_visibility(&self) -> bool {
        self.visible
    }

    /// Gets the X and Y dimensions of the container
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    pub fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

    /// Returns true if this container is a parent of the child
    pub fn is_parent_of(&self, child: Node) -> bool {
        if self.is_root() {
            true
        } else {
            unimplemented!();
        }
    }

    /// Returns true if this container is a child is an decedent of the parent
    pub fn is_child_of(&self, parent: Node) -> bool {
        if self.is_root() {
            false
        } else {
            if let Some(my_parent) = self.get_parent() {
                my_parent == parent
            } else {
                false
            }
        }
    }

    pub fn is_root(&self) -> bool {
        self.get_type() == ContainerType::Root
    }

    /// Finds a parent container with the given type, if there is any
    pub fn get_parent_by_type(&self, container_type: ContainerType) -> Option<Node> {
        let mut container = self.get_parent();
        loop {
            if let Some(parent) = container {
                if parent.borrow().get_type() == container_type {
                    return Some(parent);
                }
                container = parent.borrow().get_parent();
            } else {
                return None;
            }
        }
    }
}

impl PartialEq for Container {
    fn eq(&self, other: &Container) -> bool {
        self.get_type() == other.get_type()
    }
}

impl Eq for Container { }

impl Debug for Container {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        f.debug_struct("Containable")
            .field("type", &self.get_type())
            .field("parent", &self.get_parent())
            .field("children", &self.get_children())
            .field("focused", &self.is_focused())
            .finish()
    }
}
<commit_msg>Added container type<commit_after>//! Layout handling

// remove
#![allow(unused)]

use rustwlc::handle::{WlcView, WlcOutput};
use rustwlc::types::VIEW_MAXIMIZED;
use std::rc::{Rc, Weak};
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::cell::RefCell;

pub type Node = Rc<RefCell<Container>>;

#[derive(Debug, Clone)]
enum Handle {
    View(WlcView),
    Output(WlcOutput)
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ContainerType {
    /// Root container, only one exists
    Root,
    /// WlcOutput/Monitor
    Output,
    /// A workspace
    Workspace,
    /// A Container, houses views and other containers
    Container,
    /// A view (window)
    View
}

/// Layout mode for a container
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Layout {
    None,
    Horizontal,
    Vertical,
    Stacked,
    Tabbed,
    Floating
}

#[derive(Clone)]
pub struct Container {
    handle: Option<Handle>,
    parent: Option<Weak<RefCell<Container>>>,
    children: Vec<Node>,
    container_type: ContainerType,
    layout: Layout,
    width: u32,
    height: u32,
    x: i64,
    y: i64,
    visible: bool,
    is_focused: bool,
    is_floating: bool,
}

/// Like i3, everything (workspaces, containers, views) are containable.
impl Container {

    /// Makes the root container. There should be only one of these
    /// Does not ensure that this is the only root container
    // NOTE Need to find a way to ensure there is only one of these things
    // Perhaps set a static global variable
    pub fn new_root() -> Node {
        trace!("Root created");
        Rc::new(RefCell::new(Container {
            handle: None,
            parent: None,
            children: vec!(),
            container_type: ContainerType::Root,
            layout: Layout::None,
            width: 0,
            height: 0,
            x: 0,
            y: 0,
            visible: false,
            is_focused: false,
            is_floating: false
        }))
    }

    /// Makes a new workspace container. This should only be called by root
    /// since it will properly initialize the right number and properly put
    /// them in the main tree.
    pub fn new_workspace(root: &mut Node) -> Node {
        if ! root.borrow().is_root() {
            panic!("Only workspaces can be added to the root node");
        }
        let workspace: Node =
            Rc::new(RefCell::new(Container {
                // NOTE Give this an output
                handle: None,
                parent: Some(Rc::downgrade(&root)),
                children: vec!(),
                container_type: ContainerType::Workspace,
                // NOTE Change this to some other default
                layout: Layout::None,
                // NOTE Figure out how to initialize these properly
                width: 0,
                height: 0,
                x: 0,
                y: 0,
                visible: false,
                is_focused: false,
                is_floating: false,
                }));
        root.borrow_mut().add_child(workspace.clone());
        workspace
    }

    /// Makes a new container. These hold views and other containers.
    /// Container hold information about specific parts of the tree in some
    /// workspace and the layout of the views within.
    pub fn new_container(parent_: &mut Node, view: WlcView) -> Node {
        let mut parent = parent_.borrow_mut();
        if parent.is_root() {
            panic!("Container cannot be a direct child of root");
        }
        let container = Rc::new(RefCell::new(Container {
            handle: Some(Handle::View(view)),
            parent: Some(Rc::downgrade(&parent_)),
            children: vec!(),
            container_type: ContainerType::Container,
            // NOTE Get default, either from config or from workspace
            layout: Layout::None,
            // NOTE Get this information from somewhere, or set it later
            width: 0,
            height: 0,
            x: 0,
            y: 0,
            visible: false,
            is_focused: false,
            is_floating: false,
        }));
        parent.add_child(container.clone());
        container
    }

    /// Gets the parent that this container sits in.
    ///
    /// If the container is the root, it returns None
    pub fn get_parent(&self) -> Option<Node> {
        if self.is_root() {
            None
        } else {
            // NOTE Clone has to be done here because we have to store the
            // parent as an option since the `Weak::new` is unstable
            if let Some(parent) = self.parent.clone() {
                parent.upgrade()
            } else {
                None
            }
        }
    }

    pub fn add_child(&mut self, container: Node) {
        if self.get_type() == ContainerType::Workspace
            && container.borrow().get_type() == ContainerType::Workspace {
            panic!("Only containers can be children of a workspace");
        }
        // NOTE check to make sure we are not adding a duplicate
        self.children.push(container);
    }

    /// Removes this container and all of its children
    pub fn remove_container(&mut self) -> Result<(), &'static str> {
        if self.is_root() {
            panic!("Cannot remove root container");
        }
        if let Some(parent) = self.get_parent() {
            parent.borrow_mut().remove_child(self);
        }
        self.children = vec!();
        Ok(())
    }

    /// Gets the children of this container.
    ///
    /// Views never have children
    pub fn get_children(&self) -> Option<Vec<Node>> {
        if self.get_type() == ContainerType::View {
            None
        }
        else {
            Some(self.children.clone())
        }
    }

    /// Gets the type of the container
    pub fn get_type(&self) -> ContainerType {
        self.container_type
    }

    /// Returns true if this container is focused.
    pub fn is_focused(&self) -> bool {
        self.is_focused
    }

    /// Removes the child at the specified index
    pub fn remove_child_at(&mut self, index: usize) -> Result<Node, &'static str> {
        Ok(self.children.remove(index))
    }

    /// Removes the given child from this container's children.
    /// If the child is not present, then an error is returned
    pub fn remove_child(&mut self, node: &mut Container) -> Result<Node, &'static str> {
        for (index, child) in self.children.clone().iter().enumerate() {
            if *child.borrow() == *node {
                return Ok(self.children.remove(index));
            }
        }
        return Err("");//&format!("Could not find child {:?} in {:?}", node, self));
    }

    /// Sets this container (and everything in it) to given visibility
    pub fn set_visibility(&mut self, visibility: bool) {
        self.visible = visibility
    }

    /// Gets the visibility of the container
    pub fn get_visibility(&self) -> bool {
        self.visible
    }

    /// Gets the X and Y dimensions of the container
    pub fn get_dimensions(&self) -> (u32, u32) {
        (self.width, self.height)
    }

    /// Gets the position of this container on the screen
    pub fn get_position(&self) -> (i64, i64) {
        (self.x, self.y)
    }

    /// Returns true if this container is a parent of the child
    pub fn is_parent_of(&self, child: Node) -> bool {
        if self.is_root() {
            true
        } else {
            unimplemented!();
        }
    }

    /// Returns true if this container is a child is an decedent of the parent
    pub fn is_child_of(&self, parent: Node) -> bool {
        if self.is_root() {
            false
        } else {
            if let Some(my_parent) = self.get_parent() {
                my_parent == parent
            } else {
                false
            }
        }
    }

    pub fn is_root(&self) -> bool {
        self.get_type() == ContainerType::Root
    }

    /// Finds a parent container with the given type, if there is any
    pub fn get_parent_by_type(&self, container_type: ContainerType) -> Option<Node> {
        let mut container = self.get_parent();
        loop {
            if let Some(parent) = container {
                if parent.borrow().get_type() == container_type {
                    return Some(parent);
                }
                container = parent.borrow().get_parent();
            } else {
                return None;
            }
        }
    }
}

impl PartialEq for Container {
    fn eq(&self, other: &Container) -> bool {
        self.get_type() == other.get_type()
    }
}

impl Eq for Container { }

impl Debug for Container {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        f.debug_struct("Containable")
            .field("type", &self.get_type())
            .field("parent", &self.get_parent())
            .field("children", &self.get_children())
            .field("focused", &self.is_focused())
            .finish()
    }
}
<|endoftext|>


<commit_before>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).unwrap();
    let pool = Rc::new(CpuPool::new_num_cpus());
    let state = Arc::new(RwLock::new(State::new()));
    let (read_channel_out, read_channel_in) = futures::sync::mpsc::unbounded();
    let (write_channel_out, write_channel_in) = futures::sync::mpsc::unbounded();
    let handle_inner = handle.clone();
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            println!("Got a connection from: {}", addr);
            if !upgrade.protocols().iter().any(|s| s == "rust-websocket") {
                spawn_future(upgrade.reject(), "Upgrade Rejection", &handle_inner);
                return Ok(());
            }
            let read_channel_out = read_channel_out.clone();
            let write_channel_out = write_channel_out.clone();
            upgrade
                .use_protocol("rust-websocket")
                .accept()
                .and_then(move |(framed, _)| {
                    let (sink, stream) = framed.split();
                    read_channel_out.send(stream).wait().unwrap();
                    write_channel_out.send(sink).wait().unwrap();
                    Ok(())
                })
                .wait()
                .unwrap();
            Ok(())
        })
        .map_err(|_| ());

    let state_read = state.clone();
    let remote_write = remote.clone();
    let read_handler = pool.spawn_fn( || {
        read_channel_in.for_each(move |stream| {
            let state_read = state_read.clone();
            remote_write.spawn(|_| {
                stream
                    .for_each(move |msg|{
                        handle_incoming(&mut state_read.write().unwrap(), &msg);
                        Ok(())
                    })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let write_handler = pool.spawn_fn(move || {
        write_channel_in.for_each(move |sink| {
            let state_write = state.clone();
            future::loop_fn(sink, move |sink| {
                thread::sleep(Duration::from_millis(100));
                send(&state_write.read().unwrap(), sink)
                    .map(|sink| {
                        Loop::Continue(sink)
                    })
                    .map_err(|_| Loop::Break::<(), SplitSink>(()))
            }).map_err(|_| ())
        })
    });

    let handlers = connection_handler.select2(read_handler.select(write_handler));
    core.run(handlers).map_err(|_| println!("err")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn handle_incoming(state: &mut State, msg: &OwnedMessage) {
    match msg {
        &OwnedMessage::Text(ref txt) => {
            println!("Received message: {}", txt);
            state.msg = txt.clone();
        }
        _ => {}
    }
}

type SplitSink = futures::stream::SplitSink<
                    websocket::client::async::Framed<tokio_core::net::TcpStream,
                    websocket::async::MessageCodec<websocket::OwnedMessage>>
                >;

fn send(state: &State, sink: SplitSink) -> futures::sink::Send<SplitSink> {
    let msg = serde_json::to_string(&state).unwrap();
    println!("Sending message: {}", msg);
    sink.send(OwnedMessage::Text(msg))
}

#[derive(Serialize)]
struct State {
    msg: String,
}

impl State {
    fn new() -> State {
        State { msg: "git gud".to_string() }
    }
}
<commit_msg>Core: Gardening<commit_after>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
#[macro_use]
extern crate serde_derive;

use websocket::message::OwnedMessage;
use websocket::server::InvalidConnection;
use websocket::async::Server;

use tokio_core::reactor::{Handle, Core};

use futures::{Future, Sink, Stream};
use futures::future::{self, Loop};
use futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::thread;
use std::rc::Rc;
use std::fmt::Debug;
use std::time::Duration;

fn main() {
    let mut core = Core::new().unwrap();
    let handle = core.handle();
    let remote = core.remote();
    let server = Server::bind("localhost:8081", &handle).unwrap();
    let pool = Rc::new(CpuPool::new_num_cpus());
    let state = Arc::new(RwLock::new(State::new()));
    let (read_channel_out, read_channel_in) = futures::sync::mpsc::unbounded();
    let (write_channel_out, write_channel_in) = futures::sync::mpsc::unbounded();
    let handle_inner = handle.clone();
    let connection_handler = server.incoming()
        // we don't wanna save the stream if it drops
        .map_err(|InvalidConnection { error, .. }| error)
        .for_each(move |(upgrade, addr)| {
            println!("Got a connection from: {}", addr);
            if !upgrade.protocols().iter().any(|s| s == "rust-websocket") {
                spawn_future(upgrade.reject(), "Upgrade Rejection", &handle_inner);
                return Ok(());
            }
            let read_channel_out = read_channel_out.clone();
            let write_channel_out = write_channel_out.clone();
            upgrade
                .use_protocol("rust-websocket")
                .accept()
                .and_then(move |(framed, _)| {
                    let (sink, stream) = framed.split();
                    read_channel_out.send(stream).wait().unwrap();
                    write_channel_out.send(sink).wait().unwrap();
                    Ok(())
                })
                .wait()
                .unwrap();
            Ok(())
        })
        .map_err(|_| ());

    let state_read = state.clone();
    let remote_write = remote.clone();
    let read_handler = pool.spawn_fn( || {
        read_channel_in.for_each(move |stream| {
            let state_read = state_read.clone();
            remote_write.spawn(|_| {
                stream
                    .for_each(move |msg|{
                        handle_incoming(&mut state_read.write().unwrap(), &msg);
                        Ok(())
                    })
                    .map_err(|_| ())
            });
            Ok(())
        })
    });

    let write_handler = pool.spawn_fn(move || {
        write_channel_in.for_each(move |sink| {
            let state_write = state.clone();
            future::loop_fn(sink, move |sink| {
                thread::sleep(Duration::from_millis(100));
                send(&state_write.read().unwrap(), sink)
                    .map(|sink| Loop::Continue(sink))
                    .map_err(|_| Loop::Break::<(), SplitSink>(()))
            }).map_err(|_| ())
        })
    });

    let handlers = connection_handler.select2(read_handler.select(write_handler));
    core.run(handlers).map_err(|_| println!("err")).unwrap();
}

fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
    where F: Future<Item = I, Error = E> + 'static,
          E: Debug
{
    handle.spawn(f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
                     .map(move |_| println!("{}: Finished.", desc)));
}

fn handle_incoming(state: &mut State, msg: &OwnedMessage) {
    match msg {
        &OwnedMessage::Text(ref txt) => {
            println!("Received message: {}", txt);
            state.msg = txt.clone();
        }
        _ => {}
    }
}

type SplitSink = futures::stream::SplitSink<
                    websocket::client::async::Framed<tokio_core::net::TcpStream,
                    websocket::async::MessageCodec<websocket::OwnedMessage>>
                >;

fn send(state: &State, sink: SplitSink) -> futures::sink::Send<SplitSink> {
    let msg = serde_json::to_string(&state).unwrap();
    println!("Sending message: {}", msg);
    sink.send(OwnedMessage::Text(msg))
}

#[derive(Serialize)]
struct State {
    msg: String,
}

impl State {
    fn new() -> State {
        State { msg: "git gud".to_string() }
    }
}
<|endoftext|>


<commit_before>extern crate shootr;

extern crate specs;
extern crate chrono;

use self::specs::{DispatcherBuilder, World};
use self::chrono::prelude::*;

use shootr::engine::{Msg, Engine, EventHandler, Id};
use shootr::util::{read_env_var, elapsed_ms};
use shootr::model::{Vel, Pos, Ids};
use shootr::system::{Physics, Sending};

use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::Duration;

fn main() {
    shootr::engine::execute::<Handler>();
}
struct Handler {
    engine: Engine,
    ids: Ids,
}
impl EventHandler for Handler {
    fn new(engine: Engine) -> Self {
        Handler {
            engine,
            ids: Ids(Arc::new(RwLock::new(Vec::new()))),
        }
    }
    fn main_loop(&self) {
        let mut world = World::new();
        world.register::<Pos>();
        world.register::<Vel>();
        world.add_resource(self.engine.clone());
        world.add_resource(self.ids.clone());
        for _ in 0..1 {
            world
                .create_entity()
                .with(Vel { x: 80, y: 60 })
                .with(Pos { x: 500, y: 500 })
                .build();
        }

        let mut physics = DispatcherBuilder::new()
            .add(Physics, "physics", &[])
            .build();
        let mut renderer = DispatcherBuilder::new().add(Sending, "send", &[]).build();
        physics.dispatch(&mut world.res);

        let mut lag: u64 = 0;
        let mut previous = Utc::now();
        let updates_per_sec = read_env_var("CORE_UPDATES_PER_SEC").parse::<u64>().expect(
            "Failed to parse environmental variable as integer",
        );
        let ms_per_update = 1000 / updates_per_sec;
        loop {
            let current = Utc::now();
            let elapsed = elapsed_ms(previous, current);
            previous = current;
            lag += elapsed;
            while lag >= ms_per_update {
                physics.dispatch(&mut world.res);
                lag -= ms_per_update;
            }
            renderer.dispatch(&mut world.res);
            sleep(Duration::from_millis(ms_per_update - lag));
        }
    }
    fn message(&self, msg: &Msg) {
        println!("Received message: {}", msg.content);
    }
    fn connect(&self, id: Id) -> bool {
        self.ids.write().unwrap().push(id);
        true
    }
    fn disconnect(&self, id: Id) {
        let mut ids = self.ids.write().unwrap();
        let pos = ids.iter().position(|&x| x == id).expect(
            "Tried to remove id that was not added in the first place",
        );

        ids.remove(pos);
    }
}
<commit_msg>Core: Decrease demo speed<commit_after>extern crate shootr;

extern crate specs;
extern crate chrono;

use self::specs::{DispatcherBuilder, World};
use self::chrono::prelude::*;

use shootr::engine::{Msg, Engine, EventHandler, Id};
use shootr::util::{read_env_var, elapsed_ms};
use shootr::model::{Vel, Pos, Ids};
use shootr::system::{Physics, Sending};

use std::sync::{Arc, RwLock};
use std::thread::sleep;
use std::time::Duration;

fn main() {
    shootr::engine::execute::<Handler>();
}
struct Handler {
    engine: Engine,
    ids: Ids,
}
impl EventHandler for Handler {
    fn new(engine: Engine) -> Self {
        Handler {
            engine,
            ids: Ids(Arc::new(RwLock::new(Vec::new()))),
        }
    }
    fn main_loop(&self) {
        let mut world = World::new();
        world.register::<Pos>();
        world.register::<Vel>();
        world.add_resource(self.engine.clone());
        world.add_resource(self.ids.clone());
        for _ in 0..1 {
            world
                .create_entity()
                .with(Vel { x: 8, y: 6 })
                .with(Pos { x: 500, y: 500 })
                .build();
        }

        let mut physics = DispatcherBuilder::new()
            .add(Physics, "physics", &[])
            .build();
        let mut renderer = DispatcherBuilder::new().add(Sending, "send", &[]).build();
        physics.dispatch(&mut world.res);

        let mut lag: u64 = 0;
        let mut previous = Utc::now();
        let updates_per_sec = read_env_var("CORE_UPDATES_PER_SEC").parse::<u64>().expect(
            "Failed to parse environmental variable as integer",
        );
        let ms_per_update = 1000 / updates_per_sec;
        loop {
            let current = Utc::now();
            let elapsed = elapsed_ms(previous, current);
            previous = current;
            lag += elapsed;
            while lag >= ms_per_update {
                physics.dispatch(&mut world.res);
                lag -= ms_per_update;
            }
            renderer.dispatch(&mut world.res);
            sleep(Duration::from_millis(ms_per_update - lag));
        }
    }
    fn message(&self, msg: &Msg) {
        println!("Received message: {}", msg.content);
    }
    fn connect(&self, id: Id) -> bool {
        self.ids.write().unwrap().push(id);
        true
    }
    fn disconnect(&self, id: Id) {
        let mut ids = self.ids.write().unwrap();
        let pos = ids.iter().position(|&x| x == id).expect(
            "Tried to remove id that was not added in the first place",
        );

        ids.remove(pos);
    }
}
<|endoftext|>


<commit_before>use std::io::{BufReader, BufRead};
use std::str::FromStr;
use std::fs::File;
use std::cmp;
use tar::Archive;
use spiral::Spiral;
use dfa::{Dfa, DfaState};
use field::Field;

struct Move {
  x: u32,
  y: u32,
  p: f64 // probability
}

struct Pattern {
  p: f64, // priority (probability = p / sum(p))
  moves: Vec<Move>
}

pub struct Patterns {
  dfa: Dfa,
  patterns: Vec<Pattern>
}

impl Patterns {
  fn read_header<T: BufRead>(input: &mut T, s: &mut String) -> (u32, u32, u32, f64) {
    s.clear();
    input.read_line(s).ok();
    s.pop();
    let mut split = s.split(' ').fuse();
    let width = u32::from_str(split.next().expect("Invalid pattern format: expected width.")).expect("Invalid pattern format: width must be u32."); //TODO: validate all this.
    let height = u32::from_str(split.next().expect("Invalid pattern format: expected height.")).expect("Invalid pattern format: height must be u32.");
    let moves_count = u32::from_str(split.next().expect("Invalid pattern format: expected moves count.")).expect("Invalid pattern format: moves count must be u32.");
    let priority = f64::from_str(split.next().expect("Invalid pattern format: expected priority.")).expect("Invalid pattern format: priority must be f64.");
    (width, height, moves_count, priority)
  }

  fn read_pattern<T: BufRead>(input: &mut T, s: &mut String, width: u32, height: u32) {
    s.clear();
    for y in 0 .. height {
      input.read_line(s).ok(); //TODO: check sizes.
      s.pop();
    }
  }

  fn read_moves<T: BufRead>(input: &mut T, s: &mut String, moves_count: u32) -> Vec<Move> {
    unimplemented!()
  }

  fn covering_spiral_length(side_of_square: u32) -> u32 {
    let x = side_of_square / 2;
    (8 * x - 13) * x + 6
  }

  fn build_dfa(width: u32, height: u32, pattern: u32, s: &str) -> Dfa {
    let center_x = width / 2;
    let center_y = height / 2;
    let spiral_length = Patterns::covering_spiral_length(cmp::max(width, height)) as usize;
    let mut states = Vec::with_capacity(spiral_length + 1);
    let mut i = 0;
    for (shift_x, shift_y) in Spiral::new().into_iter().take(spiral_length) {
      i += 1;
      let x = center_x as i32 + shift_x;
      let y = center_y as i32 + shift_y;
      let state = if x >= 0 && x < width as i32 && y >= 0 && y < height as i32 {
        let pos = y as u32 * width + x as u32;
        match s.char_at(pos as usize) {
          '.' => DfaState::new(i, -1, -1, -1, -1),
          '?' => DfaState::new(i, i, i, i, -1),
          'R' => DfaState::new(-1, i, -1, -1, -1),
          'B' => DfaState::new(-1, -1, i, -1, -1),
          'r' => DfaState::new(i, i, -1, -1, -1),
          'b' => DfaState::new(i, -1, i, -1, -1),
          '*' => DfaState::new(-1, -1, -1, i, -1),
          c   => panic!("Invalid character in pattern: {}", c)
        }
      } else {
        DfaState::new(-1, -1, -1, -1, -1)
      };
      states.push(state);
    }
    states.push(DfaState::new(-1, -1, -1, -1, pattern as i32));
    Dfa::new(states)
  }

  pub fn load(file: File) -> Patterns {
    let archive = Archive::new(file);
    let mut s = String::new();
    let mut patterns = Vec::new();
    let mut iter = archive.files().expect("Reading of tar archive is failed.").into_iter().map(|file| file.expect("Reading of file in tar archive is failed."));
    let mut dfa = {
      let file = iter.next().expect("Archive should contain at least one pattern.");
      let mut input = BufReader::new(file);
      let (width, height, moves_count, priority) = Patterns::read_header(&mut input, &mut s);
      Patterns::read_pattern(&mut input, &mut s, width, height);
      let cur_dfa = Patterns::build_dfa(width, height, 0, &s);
      let moves = Patterns::read_moves(&mut input, &mut s, moves_count);
      patterns.push(Pattern {
        p: priority,
        moves: moves
      });
      cur_dfa
    };
    for file in iter {
      let mut input = BufReader::new(file);
      let (width, height, moves_count, priority) = Patterns::read_header(&mut input, &mut s);
      Patterns::read_pattern(&mut input, &mut s, width, height);
      let cur_dfa = Patterns::build_dfa(width, height, patterns.len() as u32, &s);
      dfa = dfa.product(&cur_dfa);
      dfa.delete_non_reachable();
      let moves = Patterns::read_moves(&mut input, &mut s, moves_count);
      patterns.push(Pattern {
        p: priority,
        moves: moves
      });
    }
    dfa.minimize();
    Patterns {
      dfa: dfa,
      patterns: patterns
    }
  }

  pub fn find(&self, field: &Field) -> Vec<(i32, i32, f64)> {
    unimplemented!()
  }
}
<commit_msg>Implement read moves.<commit_after>use std::io::{BufReader, BufRead};
use std::str::FromStr;
use std::fs::File;
use std::cmp;
use tar::Archive;
use spiral::Spiral;
use dfa::{Dfa, DfaState};
use field::Field;

struct Move {
  x: u32,
  y: u32,
  p: f64 // probability
}

struct Pattern {
  p: f64, // priority (probability = p / sum(p))
  moves: Vec<Move>
}

pub struct Patterns {
  dfa: Dfa,
  patterns: Vec<Pattern>
}

impl Patterns {
  fn read_header<T: BufRead>(input: &mut T, s: &mut String) -> (u32, u32, u32, f64) {
    s.clear();
    input.read_line(s).ok();
    s.pop();
    let mut split = s.split(' ').fuse();
    let width = u32::from_str(split.next().expect("Invalid pattern format: expected width.")).expect("Invalid pattern format: width must be u32."); //TODO: validate all this.
    let height = u32::from_str(split.next().expect("Invalid pattern format: expected height.")).expect("Invalid pattern format: height must be u32.");
    let moves_count = u32::from_str(split.next().expect("Invalid pattern format: expected moves count.")).expect("Invalid pattern format: moves count must be u32.");
    let priority = f64::from_str(split.next().expect("Invalid pattern format: expected priority.")).expect("Invalid pattern format: priority must be f64.");
    (width, height, moves_count, priority)
  }

  fn read_pattern<T: BufRead>(input: &mut T, s: &mut String, width: u32, height: u32) {
    s.clear();
    for y in 0 .. height {
      input.read_line(s).ok(); //TODO: check sizes.
      s.pop();
    }
  }

  fn read_moves<T: BufRead>(input: &mut T, s: &mut String, moves_count: u32) -> Vec<Move> {
    let mut moves = Vec::with_capacity(moves_count as usize);
    for _ in 0 .. moves_count {
      s.clear();
      input.read_line(s).ok();
      s.pop();
      let mut split = s.split(' ').fuse();
      let x = u32::from_str(split.next().expect("Invalid pattern format: expected x coordinate.")).expect("Invalid pattern format: x coordinate must be u32.");
      let y = u32::from_str(split.next().expect("Invalid pattern format: expected x coordinate.")).expect("Invalid pattern format: x coordinate must be u32.");
      let p = f64::from_str(split.next().expect("Invalid pattern format: expected probability.")).expect("Invalid pattern format: probability must be f64.");
      moves.push(Move {
        x: x,
        y: y,
        p: p
      });
    }
    moves
  }

  fn covering_spiral_length(side_of_square: u32) -> u32 {
    let x = side_of_square / 2;
    (8 * x - 13) * x + 6
  }

  fn build_dfa(width: u32, height: u32, pattern: u32, s: &str) -> Dfa {
    let center_x = width / 2;
    let center_y = height / 2;
    let spiral_length = Patterns::covering_spiral_length(cmp::max(width, height)) as usize;
    let mut states = Vec::with_capacity(spiral_length + 1);
    let mut i = 0;
    for (shift_x, shift_y) in Spiral::new().into_iter().take(spiral_length) {
      i += 1;
      let x = center_x as i32 + shift_x;
      let y = center_y as i32 + shift_y;
      let state = if x >= 0 && x < width as i32 && y >= 0 && y < height as i32 {
        let pos = y as u32 * width + x as u32;
        match s.char_at(pos as usize) {
          '.' => DfaState::new(i, -1, -1, -1, -1),
          '?' => DfaState::new(i, i, i, i, -1),
          'R' => DfaState::new(-1, i, -1, -1, -1),
          'B' => DfaState::new(-1, -1, i, -1, -1),
          'r' => DfaState::new(i, i, -1, -1, -1),
          'b' => DfaState::new(i, -1, i, -1, -1),
          '*' => DfaState::new(-1, -1, -1, i, -1),
          c   => panic!("Invalid character in pattern: {}", c)
        }
      } else {
        DfaState::new(-1, -1, -1, -1, -1)
      };
      states.push(state);
    }
    states.push(DfaState::new(-1, -1, -1, -1, pattern as i32));
    Dfa::new(states)
  }

  pub fn load(file: File) -> Patterns {
    let archive = Archive::new(file);
    let mut s = String::new();
    let mut patterns = Vec::new();
    let mut iter = archive.files().expect("Reading of tar archive is failed.").into_iter().map(|file| file.expect("Reading of file in tar archive is failed."));
    let mut dfa = {
      let file = iter.next().expect("Archive should contain at least one pattern.");
      let mut input = BufReader::new(file);
      let (width, height, moves_count, priority) = Patterns::read_header(&mut input, &mut s);
      Patterns::read_pattern(&mut input, &mut s, width, height);
      let cur_dfa = Patterns::build_dfa(width, height, 0, &s);
      let moves = Patterns::read_moves(&mut input, &mut s, moves_count);
      patterns.push(Pattern {
        p: priority,
        moves: moves
      });
      cur_dfa
    };
    for file in iter {
      let mut input = BufReader::new(file);
      let (width, height, moves_count, priority) = Patterns::read_header(&mut input, &mut s);
      Patterns::read_pattern(&mut input, &mut s, width, height);
      let cur_dfa = Patterns::build_dfa(width, height, patterns.len() as u32, &s);
      dfa = dfa.product(&cur_dfa);
      dfa.delete_non_reachable();
      let moves = Patterns::read_moves(&mut input, &mut s, moves_count);
      patterns.push(Pattern {
        p: priority,
        moves: moves
      });
    }
    dfa.minimize();
    Patterns {
      dfa: dfa,
      patterns: patterns
    }
  }

  pub fn find(&self, field: &Field) -> Vec<(i32, i32, f64)> {
    unimplemented!()
  }
}
<|endoftext|>


<commit_before>use serde_json::builder::ObjectBuilder;
use serde_json::Value;
use std::net::Shutdown;
use std::sync::mpsc::{
    TryRecvError,
    Receiver as MpscReceiver,
    Sender as MpscSender
};
use std::time::Duration as StdDuration;
use std::{env, thread};
use super::super::ClientError;
use super::{GatewayError, GatewayStatus};
use time::{self, Duration};
use websocket::client::request::Url as RequestUrl;
use websocket::client::{Receiver, Sender};
use websocket::stream::WebSocketStream;
use ::constants::{self, OpCode};
use ::error::{Error, Result};
use ::internal::ws_impl::{ReceiverExt, SenderExt};
use ::model::event::{Event, GatewayEvent, ReadyEvent};

#[inline]
pub fn parse_ready(event: GatewayEvent,
                   tx: &MpscSender<GatewayStatus>,
                   receiver: &mut Receiver<WebSocketStream>,
                   identification: Value)
                   -> Result<(ReadyEvent, u64)> {
    match event {
        GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
            Ok((event, seq))
        },
        GatewayEvent::InvalidateSession => {
            debug!("Session invalidation");

            let _ = tx.send(GatewayStatus::SendMessage(identification));

            match receiver.recv_json(GatewayEvent::decode)? {
                GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
                    Ok((event, seq))
                },
                other => {
                    debug!("Unexpected event: {:?}", other);

                    Err(Error::Gateway(GatewayError::InvalidHandshake))
                },
            }
        },
        other => {
            debug!("Unexpected event: {:?}", other);

            Err(Error::Gateway(GatewayError::InvalidHandshake))
        },
    }
}

pub fn identify(token: &str, shard_info: Option<[u64; 2]>) -> Value {
    ObjectBuilder::new()
        .insert("op", OpCode::Identify.num())
        .insert_object("d", |mut object| {
            object = identify_compression(object)
                .insert("large_threshold", 250) // max value
                .insert_object("properties", |object| object
                    .insert("$browser", "Ergonomic and high-level Rust library")
                    .insert("$device", "serenity")
                    .insert("$os", env::consts::OS))
                .insert("token", token)
                .insert("v", constants::GATEWAY_VERSION);

            if let Some(shard_info) = shard_info {
                object = object.insert_array("shard", |a| a
                    .push(shard_info[0])
                    .push(shard_info[1]));
            }

            object
        })
        .build()
}

#[inline(always)]
pub fn identify_compression(object: ObjectBuilder) -> ObjectBuilder {
    object.insert("compression", !cfg!(feature="debug"))
}

pub fn build_gateway_url(base: &str) -> Result<RequestUrl> {
    RequestUrl::parse(&format!("{}?v={}", base, constants::GATEWAY_VERSION))
        .map_err(|_| Error::Client(ClientError::Gateway))
}

pub fn keepalive(interval: u64,
                 mut sender: Sender<WebSocketStream>,
                 channel: MpscReceiver<GatewayStatus>) {
    let mut base_interval = Duration::milliseconds(interval as i64);
    let mut next_tick = time::get_time() + base_interval;

    let mut last_sequence = 0;

    'outer: loop {
        thread::sleep(StdDuration::from_millis(100));

        loop {
            match channel.try_recv() {
                Ok(GatewayStatus::Interval(interval)) => {
                    base_interval = Duration::milliseconds(interval as i64);
                },
                Ok(GatewayStatus::Sender(new_sender)) => {
                    sender = new_sender;
                },
                Ok(GatewayStatus::SendMessage(val)) => {
                    if let Err(why) = sender.send_json(&val) {
                        warn!("Error sending message: {:?}", why);
                    }
                },
                Ok(GatewayStatus::Sequence(seq)) => {
                    last_sequence = seq;
                },
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => break 'outer,
            }
        }

        if time::get_time() >= next_tick {
            next_tick = next_tick + base_interval;

            let map = ObjectBuilder::new()
                .insert("d", last_sequence)
                .insert("op", OpCode::Heartbeat.num())
                .build();

            debug!("Sending heartbeat d: {}", last_sequence);

            if let Err(why) = sender.send_json(&map) {
                warn!("Error sending keepalive: {:?}", why);
            }
        }
    }

    debug!("Closing keepalive");

    let _ = sender.get_mut().shutdown(Shutdown::Both);
}
<commit_msg>Convert heartbeat debug to a trace<commit_after>use serde_json::builder::ObjectBuilder;
use serde_json::Value;
use std::net::Shutdown;
use std::sync::mpsc::{
    TryRecvError,
    Receiver as MpscReceiver,
    Sender as MpscSender
};
use std::time::Duration as StdDuration;
use std::{env, thread};
use super::super::ClientError;
use super::{GatewayError, GatewayStatus};
use time::{self, Duration};
use websocket::client::request::Url as RequestUrl;
use websocket::client::{Receiver, Sender};
use websocket::stream::WebSocketStream;
use ::constants::{self, OpCode};
use ::error::{Error, Result};
use ::internal::ws_impl::{ReceiverExt, SenderExt};
use ::model::event::{Event, GatewayEvent, ReadyEvent};

#[inline]
pub fn parse_ready(event: GatewayEvent,
                   tx: &MpscSender<GatewayStatus>,
                   receiver: &mut Receiver<WebSocketStream>,
                   identification: Value)
                   -> Result<(ReadyEvent, u64)> {
    match event {
        GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
            Ok((event, seq))
        },
        GatewayEvent::InvalidateSession => {
            debug!("Session invalidation");

            let _ = tx.send(GatewayStatus::SendMessage(identification));

            match receiver.recv_json(GatewayEvent::decode)? {
                GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
                    Ok((event, seq))
                },
                other => {
                    debug!("Unexpected event: {:?}", other);

                    Err(Error::Gateway(GatewayError::InvalidHandshake))
                },
            }
        },
        other => {
            debug!("Unexpected event: {:?}", other);

            Err(Error::Gateway(GatewayError::InvalidHandshake))
        },
    }
}

pub fn identify(token: &str, shard_info: Option<[u64; 2]>) -> Value {
    ObjectBuilder::new()
        .insert("op", OpCode::Identify.num())
        .insert_object("d", |mut object| {
            object = identify_compression(object)
                .insert("large_threshold", 250) // max value
                .insert_object("properties", |object| object
                    .insert("$browser", "Ergonomic and high-level Rust library")
                    .insert("$device", "serenity")
                    .insert("$os", env::consts::OS))
                .insert("token", token)
                .insert("v", constants::GATEWAY_VERSION);

            if let Some(shard_info) = shard_info {
                object = object.insert_array("shard", |a| a
                    .push(shard_info[0])
                    .push(shard_info[1]));
            }

            object
        })
        .build()
}

#[inline(always)]
pub fn identify_compression(object: ObjectBuilder) -> ObjectBuilder {
    object.insert("compression", !cfg!(feature="debug"))
}

pub fn build_gateway_url(base: &str) -> Result<RequestUrl> {
    RequestUrl::parse(&format!("{}?v={}", base, constants::GATEWAY_VERSION))
        .map_err(|_| Error::Client(ClientError::Gateway))
}

pub fn keepalive(interval: u64,
                 mut sender: Sender<WebSocketStream>,
                 channel: MpscReceiver<GatewayStatus>) {
    let mut base_interval = Duration::milliseconds(interval as i64);
    let mut next_tick = time::get_time() + base_interval;

    let mut last_sequence = 0;

    'outer: loop {
        thread::sleep(StdDuration::from_millis(100));

        loop {
            match channel.try_recv() {
                Ok(GatewayStatus::Interval(interval)) => {
                    base_interval = Duration::milliseconds(interval as i64);
                },
                Ok(GatewayStatus::Sender(new_sender)) => {
                    sender = new_sender;
                },
                Ok(GatewayStatus::SendMessage(val)) => {
                    if let Err(why) = sender.send_json(&val) {
                        warn!("Error sending message: {:?}", why);
                    }
                },
                Ok(GatewayStatus::Sequence(seq)) => {
                    last_sequence = seq;
                },
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => break 'outer,
            }
        }

        if time::get_time() >= next_tick {
            next_tick = next_tick + base_interval;

            let map = ObjectBuilder::new()
                .insert("d", last_sequence)
                .insert("op", OpCode::Heartbeat.num())
                .build();

            trace!("Sending heartbeat d: {}", last_sequence);

            if let Err(why) = sender.send_json(&map) {
                warn!("Error sending keepalive: {:?}", why);
            }
        }
    }

    debug!("Closing keepalive");

    let _ = sender.get_mut().shutdown(Shutdown::Both);
}
<|endoftext|>


<commit_before>use libc;
use ram::entry;
use ram::tombstone::{TOMBSTONE_SIZE_U32, Tombstone};
use ram::cell;
use ram::cell::Cell;
use ram::chunk::Chunk;
use ram::entry::EntryMeta;
use std::sync::atomic::{AtomicUsize, AtomicU32, AtomicI64, AtomicBool, Ordering};
use std::collections::BTreeSet;
use std::fs::{File, remove_file, copy};
use std::io::BufWriter;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use crc32c::crc32c;
use bifrost::utils::async_locks::{RwLock, RwLockReadGuard};
use parking_lot;

use super::cell::CellHeader;

pub const MAX_SEGMENT_SIZE_U32: u32 = 8 * 1024 * 1024;
pub const MAX_SEGMENT_SIZE: usize = MAX_SEGMENT_SIZE_U32 as usize;

pub struct Segment {
    pub id: u64,
    pub addr: usize,
    pub bound: usize,
    pub append_header: AtomicUsize,
    pub dead_space: AtomicU32,
    pub tombstones: AtomicU32,
    pub dead_tombstones: AtomicU32,
    pub last_tombstones_scanned: AtomicI64,
    pub references: AtomicUsize,
    pub backup_file_name: Option<String>,
    pub wal_file: Option<parking_lot::Mutex<BufWriter<File>>>,
    pub wal_file_name: Option<String>,
    pub archived: AtomicBool,
    pub dropped: AtomicBool
}

impl Segment {
    pub fn new(id: u64, size: usize,
               backup_storage: &Option<String>,
               wal_storage: &Option<String>) -> Segment {
        let buffer_ptr = unsafe { libc::malloc(size) as usize };
        let mut wal_file_name = None;
        let mut wal_file = None;
        if let Some(wal_storage) = wal_storage {
            let file_name = format!("{}/{}.log", wal_storage, id);
            let file = BufWriter::with_capacity(
                4096, // most common disk block size
                File::open(&file_name).unwrap()); // fast fail
            wal_file_name = Some(file_name);
            wal_file = Some(parking_lot::Mutex::new(file));
        }
        debug!("Creating new segment with id {}, size {}, address {}", id, size, buffer_ptr);
        Segment {
            addr: buffer_ptr,
            id,
            bound: buffer_ptr + size,
            append_header: AtomicUsize::new(buffer_ptr),
            dead_space: AtomicU32::new(0),
            tombstones: AtomicU32::new(0),
            dead_tombstones: AtomicU32::new(0),
            last_tombstones_scanned: AtomicI64::new(0),
            references: AtomicUsize::new(0),
            backup_file_name: backup_storage.clone().map(|path| format!("{}/{}.backup", path, id)),
            archived: AtomicBool::new(false),
            dropped: AtomicBool::new(false),
            wal_file,
            wal_file_name
        }
    }

    pub fn try_acquire(&self, size: u32) -> Option<usize> {
        let size = size as usize;
        loop {
            let curr_last = self.append_header.load(Ordering::SeqCst);
            let exp_last = curr_last + size;
            if exp_last > self.bound {
                return None;
            } else {
                if self.append_header.compare_and_swap(curr_last, exp_last, Ordering::SeqCst) != curr_last {
                    continue;
                } else {
                    return Some(curr_last);
                }
            }
        }
    }

    fn append_header(&self) -> usize {
        self.append_header.load(Ordering::Relaxed)
    }

    pub fn entry_iter(&self) -> SegmentEntryIter {
        SegmentEntryIter {
            bound: self.append_header(),
            cursor: self.addr
        }
    }

    pub fn dead_space(&self) -> u32 {
        self.dead_space.load(Ordering::Relaxed)
    }

    // dead space plus tombstone spaces
    pub fn total_dead_space(&self) -> u32 {
        let dead_tombstones_space = self.dead_tombstones.load(Ordering::Relaxed) * TOMBSTONE_SIZE_U32;
        let dead_cells_space = self.dead_space();
        return dead_tombstones_space + dead_cells_space;
    }

    pub fn used_spaces(&self) -> u32 {
        return (self.append_header.load(Ordering::Relaxed) as usize - self.addr) as u32
    }

    pub fn living_space(&self) -> u32 {
        let total_dead_space = self.total_dead_space();
        return self.used_spaces() - total_dead_space;
    }

    pub fn valid_space(&self) -> u32 {
        return self.used_spaces() - self.dead_space();
    }

    pub fn living_rate(&self) -> f32 {
        let used_space = self.used_spaces() as f32;
        if used_space == 0f32 {
            // empty segment
            return 1f32;
        }
        return self.living_space() as f32 / used_space;
    }

    // archive this segment and write the data to backup storage
    pub fn archive(&self) -> Result<bool, io::Error> {
        if let &Some(ref backup_file) = &self.backup_file_name {
            while !self.no_references() { /* wait until all references released */}
            let backup_file_path = Path::new(backup_file);
            if backup_file_path.exists() {
                warn!("Segment backup {} exists and can't archive twice", backup_file);
                return Ok(false);
            }
            if let Some(ref wal_file) = self.wal_file_name {
                // if there is a WAL file ready, copy this file to backup
                if let Some(ref file_mutex) = self.wal_file {
                    // this should be redundant but I don't want to take the chance
                    // obtain the writer lock before continue
                    let _ = file_mutex.lock();
                    copy(wal_file, backup_file);
                    remove_file(wal_file);
                } else { panic!() }

            } else {
                let backup_file = File::open(backup_file_path)?;
                let seg_size = self.append_header.load(Ordering::Relaxed) - self.addr;
                let mut buffer = BufWriter::with_capacity(seg_size, backup_file);
                unsafe {
                    for offset in 0..seg_size {
                        let ptr = (self.addr + offset) as *const u8;
                        let byte = *ptr;
                        buffer.write(&[byte])?;
                    }
                }
                buffer.flush()?;
                return Ok(true);
            }
        }
        return Ok(false);
    }

    pub fn write_wal(&self, addr: usize, size: u32) -> io::Result<()> {
        if let Some(ref wal_file) = self.wal_file {
            let mut file = wal_file.lock();
            unsafe {
                for offset in 0..size as usize {
                    let ptr = (addr + offset) as *const u8;
                    let byte = *ptr;
                    file.write(&[byte])?;
                }
            }
            file.flush()?;
        }
        return Ok(());
    }

    pub fn no_references(&self) -> bool { self.references.load(Ordering::Relaxed) == 0 }

    pub fn mem_drop(&self) {
        if !self.dropped.compare_and_swap(false, true, Ordering::Relaxed) {
            debug!("disposing segment at {}", self.addr);
            unsafe {
                libc::free(self.addr as *mut libc::c_void)
            }
        }
    }

    // remove the backup if it have one
    pub fn dispense(&self) {
        debug!("dispense segment {}", self.id);
        if let &Some(ref backup_storage) = &self.backup_file_name {
            let path = Path::new(backup_storage);
            if path.exists() {
                if let Err(e) = remove_file(path) {
                    error!("cannot reclaim segment file on dispense {}", backup_storage)
                }
            } else {
                error!("cannot find segment backup {}", backup_storage)
            }
        }
    }
}

impl Drop for Segment {
    fn drop(&mut self) {
        debug!("Memory dropping segment {}", self.id);
        assert_eq!(self.references.load(Ordering::Relaxed), 0);
        self.mem_drop()
    }
}

pub struct SegmentEntryIter {
    bound: usize,
    cursor: usize
}

impl Iterator for SegmentEntryIter {
    type Item = EntryMeta;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        let cursor = self.cursor;
        if cursor >= self.bound {
            return None;
        }
        let (_, entry_meta) = entry::Entry::decode_from(
            cursor,
            |body_pos, header| {
                let entry_header_size = body_pos - cursor;
                let entry_size = entry_header_size + header.content_length as usize;
                debug!("Found body pos {}, entry header {:?}. Header size: {}, entry size: {}, entry pos: {}, content length {}, bound {}",
                       body_pos, header, entry_header_size, entry_size, cursor, header.content_length, self.bound);
                return EntryMeta {
                    body_pos, entry_header: header, entry_size, entry_pos: cursor
                };
            });
        self.cursor += entry_meta.entry_size;
        Some(entry_meta)
    }
}<commit_msg>failsafe on living space calculation<commit_after>use libc;
use ram::entry;
use ram::tombstone::{TOMBSTONE_SIZE_U32, Tombstone};
use ram::cell;
use ram::cell::Cell;
use ram::chunk::Chunk;
use ram::entry::EntryMeta;
use std::sync::atomic::{AtomicUsize, AtomicU32, AtomicI64, AtomicBool, Ordering};
use std::collections::BTreeSet;
use std::fs::{File, remove_file, copy};
use std::io::BufWriter;
use std::io::prelude::*;
use std::io;
use std::path::Path;
use crc32c::crc32c;
use bifrost::utils::async_locks::{RwLock, RwLockReadGuard};
use parking_lot;

use super::cell::CellHeader;

pub const MAX_SEGMENT_SIZE_U32: u32 = 8 * 1024 * 1024;
pub const MAX_SEGMENT_SIZE: usize = MAX_SEGMENT_SIZE_U32 as usize;

pub struct Segment {
    pub id: u64,
    pub addr: usize,
    pub bound: usize,
    pub append_header: AtomicUsize,
    pub dead_space: AtomicU32,
    pub tombstones: AtomicU32,
    pub dead_tombstones: AtomicU32,
    pub last_tombstones_scanned: AtomicI64,
    pub references: AtomicUsize,
    pub backup_file_name: Option<String>,
    pub wal_file: Option<parking_lot::Mutex<BufWriter<File>>>,
    pub wal_file_name: Option<String>,
    pub archived: AtomicBool,
    pub dropped: AtomicBool
}

impl Segment {
    pub fn new(id: u64, size: usize,
               backup_storage: &Option<String>,
               wal_storage: &Option<String>) -> Segment {
        let buffer_ptr = unsafe { libc::malloc(size) as usize };
        let mut wal_file_name = None;
        let mut wal_file = None;
        if let Some(wal_storage) = wal_storage {
            let file_name = format!("{}/{}.log", wal_storage, id);
            let file = BufWriter::with_capacity(
                4096, // most common disk block size
                File::open(&file_name).unwrap()); // fast fail
            wal_file_name = Some(file_name);
            wal_file = Some(parking_lot::Mutex::new(file));
        }
        debug!("Creating new segment with id {}, size {}, address {}", id, size, buffer_ptr);
        Segment {
            addr: buffer_ptr,
            id,
            bound: buffer_ptr + size,
            append_header: AtomicUsize::new(buffer_ptr),
            dead_space: AtomicU32::new(0),
            tombstones: AtomicU32::new(0),
            dead_tombstones: AtomicU32::new(0),
            last_tombstones_scanned: AtomicI64::new(0),
            references: AtomicUsize::new(0),
            backup_file_name: backup_storage.clone().map(|path| format!("{}/{}.backup", path, id)),
            archived: AtomicBool::new(false),
            dropped: AtomicBool::new(false),
            wal_file,
            wal_file_name
        }
    }

    pub fn try_acquire(&self, size: u32) -> Option<usize> {
        let size = size as usize;
        loop {
            let curr_last = self.append_header.load(Ordering::SeqCst);
            let exp_last = curr_last + size;
            if exp_last > self.bound {
                return None;
            } else {
                if self.append_header.compare_and_swap(curr_last, exp_last, Ordering::SeqCst) != curr_last {
                    continue;
                } else {
                    return Some(curr_last);
                }
            }
        }
    }

    fn append_header(&self) -> usize {
        self.append_header.load(Ordering::Relaxed)
    }

    pub fn entry_iter(&self) -> SegmentEntryIter {
        SegmentEntryIter {
            bound: self.append_header(),
            cursor: self.addr
        }
    }

    pub fn dead_space(&self) -> u32 {
        self.dead_space.load(Ordering::Relaxed)
    }

    // dead space plus tombstone spaces
    pub fn total_dead_space(&self) -> u32 {
        let dead_tombstones_space = self.dead_tombstones.load(Ordering::Relaxed) * TOMBSTONE_SIZE_U32;
        let dead_cells_space = self.dead_space();
        return dead_tombstones_space + dead_cells_space;
    }

    pub fn used_spaces(&self) -> u32 {
        return (self.append_header.load(Ordering::Relaxed) as usize - self.addr) as u32
    }

    pub fn living_space(&self) -> u32 {
        let total_dead_space = self.total_dead_space();
        let used_space = self.used_spaces();
        if total_dead_space <= used_space {
            used_space - total_dead_space
        } else {
            warn!("living space check error, used {}, dead {}", used_space, total_dead_space);
            0
        }
    }

    pub fn valid_space(&self) -> u32 {
        return self.used_spaces() - self.dead_space();
    }

    pub fn living_rate(&self) -> f32 {
        let used_space = self.used_spaces() as f32;
        if used_space == 0f32 {
            // empty segment
            return 1f32;
        }
        return self.living_space() as f32 / used_space;
    }

    // archive this segment and write the data to backup storage
    pub fn archive(&self) -> Result<bool, io::Error> {
        if let &Some(ref backup_file) = &self.backup_file_name {
            while !self.no_references() { /* wait until all references released */}
            let backup_file_path = Path::new(backup_file);
            if backup_file_path.exists() {
                warn!("Segment backup {} exists and can't archive twice", backup_file);
                return Ok(false);
            }
            if let Some(ref wal_file) = self.wal_file_name {
                // if there is a WAL file ready, copy this file to backup
                if let Some(ref file_mutex) = self.wal_file {
                    // this should be redundant but I don't want to take the chance
                    // obtain the writer lock before continue
                    let _ = file_mutex.lock();
                    copy(wal_file, backup_file);
                    remove_file(wal_file);
                } else { panic!() }

            } else {
                let backup_file = File::open(backup_file_path)?;
                let seg_size = self.append_header.load(Ordering::Relaxed) - self.addr;
                let mut buffer = BufWriter::with_capacity(seg_size, backup_file);
                unsafe {
                    for offset in 0..seg_size {
                        let ptr = (self.addr + offset) as *const u8;
                        let byte = *ptr;
                        buffer.write(&[byte])?;
                    }
                }
                buffer.flush()?;
                return Ok(true);
            }
        }
        return Ok(false);
    }

    pub fn write_wal(&self, addr: usize, size: u32) -> io::Result<()> {
        if let Some(ref wal_file) = self.wal_file {
            let mut file = wal_file.lock();
            unsafe {
                for offset in 0..size as usize {
                    let ptr = (addr + offset) as *const u8;
                    let byte = *ptr;
                    file.write(&[byte])?;
                }
            }
            file.flush()?;
        }
        return Ok(());
    }

    pub fn no_references(&self) -> bool { self.references.load(Ordering::Relaxed) == 0 }

    pub fn mem_drop(&self) {
        if !self.dropped.compare_and_swap(false, true, Ordering::Relaxed) {
            debug!("disposing segment at {}", self.addr);
            unsafe {
                libc::free(self.addr as *mut libc::c_void)
            }
        }
    }

    // remove the backup if it have one
    pub fn dispense(&self) {
        debug!("dispense segment {}", self.id);
        if let &Some(ref backup_storage) = &self.backup_file_name {
            let path = Path::new(backup_storage);
            if path.exists() {
                if let Err(e) = remove_file(path) {
                    error!("cannot reclaim segment file on dispense {}", backup_storage)
                }
            } else {
                error!("cannot find segment backup {}", backup_storage)
            }
        }
    }
}

impl Drop for Segment {
    fn drop(&mut self) {
        debug!("Memory dropping segment {}", self.id);
        assert_eq!(self.references.load(Ordering::Relaxed), 0);
        self.mem_drop()
    }
}

pub struct SegmentEntryIter {
    bound: usize,
    cursor: usize
}

impl Iterator for SegmentEntryIter {
    type Item = EntryMeta;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        let cursor = self.cursor;
        if cursor >= self.bound {
            return None;
        }
        let (_, entry_meta) = entry::Entry::decode_from(
            cursor,
            |body_pos, header| {
                let entry_header_size = body_pos - cursor;
                let entry_size = entry_header_size + header.content_length as usize;
                debug!("Found body pos {}, entry header {:?}. Header size: {}, entry size: {}, entry pos: {}, content length {}, bound {}",
                       body_pos, header, entry_header_size, entry_size, cursor, header.content_length, self.bound);
                return EntryMeta {
                    body_pos, entry_header: header, entry_size, entry_pos: cursor
                };
            });
        self.cursor += entry_meta.entry_size;
        Some(entry_meta)
    }
}<|endoftext|>


<commit_before>use lexer::new;
use lexer::Lexer;
use lexer::StateFunction;
use lexer::Token;
use lexer::Category;

fn initial_state(lexer: &mut Lexer) -> Option<StateFunction> {
    if lexer.token_position >= lexer.char_count {
        // There was uncategorized text before this; pass it along
        if lexer.token_position != lexer.token_start {
            lexer.tokens.push(Token{
                lexeme: lexer.data.slice_chars(lexer.token_start,
                    lexer.token_position).to_string(),
                category: Category::Text
            });
            lexer.token_start = lexer.token_position;
        }

        return None;
    }

    // TODO: Replace char_at with something UTF8 compatible.
    match lexer.data.char_at(lexer.token_position) {
        '{' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Brace });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        '[' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Bracket });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        ' ' | '\n' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.token_position += 1;
            Some(StateFunction(whitespace))
        },
        '"' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.token_position += 1;
            Some(StateFunction(inside_string))
        },
        ':' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::AssignmentOperator });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        '}' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Brace });
            None
        },
        ']' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Bracket });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        _ => {
            if lexer.token_position == lexer.token_start {
                let remaining_data = lexer.data.slice_from(lexer.token_position);
                if remaining_data.starts_with("true") {
                    lexer.token_position += 4;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Boolean
                    });
                    lexer.token_start = lexer.token_position;
                } else if remaining_data.starts_with("false") {
                    lexer.token_position += 5;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Boolean
                    });
                    lexer.token_start = lexer.token_position;
                } else if remaining_data.starts_with("null") {
                    lexer.token_position += 4;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Keyword
                    });
                    lexer.token_start = lexer.token_position;
                } else {
                    lexer.token_position += 1;
                }
            } else {
                lexer.token_position += 1;
            }
            Some(StateFunction(initial_state))
        }
    }
}

fn inside_string(lexer: &mut Lexer) -> Option<StateFunction> {
    match lexer.data.char_at(lexer.token_position) {
        '"' => {
            lexer.token_position += 1;
            lexer.tokens.push(Token{ lexeme: lexer.data.slice_chars(lexer.token_start, lexer.token_position).to_string(), category: Category::String });
            lexer.token_start = lexer.token_position;
            Some(StateFunction(initial_state))
        },
        '\\' => {
            lexer.token_position += 2;
            Some(StateFunction(inside_string))
        }
        _ => {
            lexer.token_position += 1;
            Some(StateFunction(inside_string))
        }
    }
}

fn whitespace(lexer: &mut Lexer) -> Option<StateFunction> {
    match lexer.data.char_at(lexer.token_position) {
        ' ' | '\n' => {
            lexer.token_position += 1;
            Some(StateFunction(whitespace))
        },
        _ => {
            lexer.tokens.push(Token{ lexeme: lexer.data.slice_chars(lexer.token_start, lexer.token_position).to_string(), category: Category::Whitespace });
            lexer.token_start = lexer.token_position;
            Some(StateFunction(initial_state))
        }
    }
}

fn lex(data: &str) -> Vec<Token> {
    let mut lexer = new(data);
    let mut state_function = StateFunction(initial_state);
    loop {
        let StateFunction(actual_function) = state_function;
        match actual_function(&mut lexer) {
            Some(f) => state_function = f,
            None => return lexer.tokens,
        }
    }
}

mod tests {
    use super::lex;
    use lexer::Token;
    use lexer::Category;
    use std::old_io::{File, Open, Read};

    #[test]
    fn it_works() {
        let data = File::open_mode(&Path::new("test_data/data.json"), Open, Read)
            .unwrap().read_to_string().unwrap();
        let tokens = lex(&data);
        let expected_tokens = vec![
            Token{ lexeme: "{".to_string(), category: Category::Brace },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"key\"".to_string(), category: Category::String },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"4032\"".to_string(), category: Category::String },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'single'".to_string(), category: Category::Text },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'quotes\\'',".to_string(), category: Category::Text },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"literals\"".to_string(), category: Category::String },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "[".to_string(), category: Category::Bracket },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "true".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "false".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "null".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "]".to_string(), category: Category::Bracket },
            Token{ lexeme: "\n".to_string(), category: Category::Whitespace },
            Token{ lexeme: "}".to_string(), category: Category::Brace },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }
}
<commit_msg>Test that JSON lexer can handle garbage data. Handle open strings.<commit_after>use lexer::new;
use lexer::Lexer;
use lexer::StateFunction;
use lexer::Token;
use lexer::Category;

fn initial_state(lexer: &mut Lexer) -> Option<StateFunction> {
    if lexer.token_position >= lexer.char_count {
        // There was uncategorized text before this; pass it along
        if lexer.token_position != lexer.token_start {
            lexer.tokens.push(Token{
                lexeme: lexer.data.slice_chars(lexer.token_start,
                    lexer.token_position).to_string(),
                category: Category::Text
            });
            lexer.token_start = lexer.token_position;
        }

        return None;
    }

    // TODO: Replace char_at with something UTF8 compatible.
    match lexer.data.char_at(lexer.token_position) {
        '{' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Brace });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        '[' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Bracket });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        ' ' | '\n' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.token_position += 1;
            Some(StateFunction(whitespace))
        },
        '"' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.token_position += 1;
            Some(StateFunction(inside_string))
        },
        ':' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::AssignmentOperator });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        '}' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Brace });
            None
        },
        ']' => {
            // There was uncategorized text before this; pass it along
            if lexer.token_position != lexer.token_start {
                lexer.tokens.push(Token{
                    lexeme: lexer.data.slice_chars(lexer.token_start,
                        lexer.token_position).to_string(),
                    category: Category::Text
                });
                lexer.token_start = lexer.token_position;
            }

            lexer.tokens.push(Token{ lexeme: lexer.data.char_at(lexer.token_position).to_string(), category: Category::Bracket });
            lexer.token_start += 1;
            lexer.token_position += 1;
            Some(StateFunction(initial_state))
        },
        _ => {
            if lexer.token_position == lexer.token_start {
                let remaining_data = lexer.data.slice_from(lexer.token_position);
                if remaining_data.starts_with("true") {
                    lexer.token_position += 4;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Boolean
                    });
                    lexer.token_start = lexer.token_position;
                } else if remaining_data.starts_with("false") {
                    lexer.token_position += 5;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Boolean
                    });
                    lexer.token_start = lexer.token_position;
                } else if remaining_data.starts_with("null") {
                    lexer.token_position += 4;
                    lexer.tokens.push(Token{
                        lexeme: lexer.data.slice_chars(lexer.token_start,
                            lexer.token_position).to_string(),
                        category: Category::Keyword
                    });
                    lexer.token_start = lexer.token_position;
                } else {
                    lexer.token_position += 1;
                }
            } else {
                lexer.token_position += 1;
            }
            Some(StateFunction(initial_state))
        }
    }
}

fn inside_string(lexer: &mut Lexer) -> Option<StateFunction> {
    if lexer.token_position >= lexer.char_count {
        lexer.tokens.push(Token{ lexeme: lexer.data.slice_chars(lexer.token_start, lexer.token_position).to_string(), category: Category::String });
        return None;
    }
    match lexer.data.char_at(lexer.token_position) {
        '"' => {
            lexer.token_position += 1;
            lexer.tokens.push(Token{ lexeme: lexer.data.slice_chars(lexer.token_start, lexer.token_position).to_string(), category: Category::String });
            lexer.token_start = lexer.token_position;
            Some(StateFunction(initial_state))
        },
        '\\' => {
            lexer.token_position += 2;
            Some(StateFunction(inside_string))
        }
        _ => {
            lexer.token_position += 1;
            Some(StateFunction(inside_string))
        }
    }
}

fn whitespace(lexer: &mut Lexer) -> Option<StateFunction> {
    match lexer.data.char_at(lexer.token_position) {
        ' ' | '\n' => {
            lexer.token_position += 1;
            Some(StateFunction(whitespace))
        },
        _ => {
            lexer.tokens.push(Token{ lexeme: lexer.data.slice_chars(lexer.token_start, lexer.token_position).to_string(), category: Category::Whitespace });
            lexer.token_start = lexer.token_position;
            Some(StateFunction(initial_state))
        }
    }
}

fn lex(data: &str) -> Vec<Token> {
    let mut lexer = new(data);
    let mut state_function = StateFunction(initial_state);
    loop {
        let StateFunction(actual_function) = state_function;
        match actual_function(&mut lexer) {
            Some(f) => state_function = f,
            None => return lexer.tokens,
        }
    }
}

mod tests {
    use super::lex;
    use lexer::Token;
    use lexer::Category;
    use std::old_io::{File, Open, Read};

    #[test]
    fn it_works() {
        let data = File::open_mode(&Path::new("test_data/data.json"), Open, Read)
            .unwrap().read_to_string().unwrap();
        let tokens = lex(&data);
        let expected_tokens = vec![
            Token{ lexeme: "{".to_string(), category: Category::Brace },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"key\"".to_string(), category: Category::String },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"4032\"".to_string(), category: Category::String },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'single'".to_string(), category: Category::Text },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "'quotes\\'',".to_string(), category: Category::Text },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "\"literals\"".to_string(), category: Category::String },
            Token{ lexeme: ":".to_string(), category: Category::AssignmentOperator },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "[".to_string(), category: Category::Bracket },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "true".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "false".to_string(), category: Category::Boolean },
            Token{ lexeme: ",".to_string(), category: Category::Text },
            Token{ lexeme: "\n    ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "null".to_string(), category: Category::Keyword },
            Token{ lexeme: "\n  ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "]".to_string(), category: Category::Bracket },
            Token{ lexeme: "\n".to_string(), category: Category::Whitespace },
            Token{ lexeme: "}".to_string(), category: Category::Brace },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }

    #[test]
    fn it_can_handle_garbage() {
        let tokens = lex("} adwyx123&*_ ");
        let expected_tokens = vec![
            Token{ lexeme: "}".to_string(), category: Category::Brace },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
            Token{ lexeme: "adwyx123&*_".to_string(), category: Category::Text },
            Token{ lexeme: " ".to_string(), category: Category::Whitespace },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }

    #[test]
    fn it_can_handle_open_strings() {
        let tokens = lex("\"open!");
        let expected_tokens = vec![
            Token{ lexeme: "\"open!".to_string(), category: Category::String },
        ];

        for (index, token) in tokens.iter().enumerate() {
            assert_eq!(*token, expected_tokens[index]);
        }
    }
}
<|endoftext|>