<commit_before>extern crate chrono;
extern crate fuse;
extern crate libc;
extern crate regex;
extern crate rustc_serialize;
extern crate time;
extern crate users;

use libc::ENOSYS;
use chrono::*;
use fuse::{Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory, ReplyEmpty};
use rustc_serialize::json;
use std::path::Path;

use std::ffi::OsStr;

use fs;
use fs::inode;
use gd;
use object;

use fs::helpers::{create_inode_directory_attributes, create_inode_file_attributes};

pub struct GoodDataFS {
    pub client: gd::GoodDataClient,
    pub users_cache: users::UsersCache,
}

impl Drop for GoodDataFS {
    fn drop(&mut self) {
        println!("Unmounting GoodData Filesystem");
    }
}

#[allow(dead_code)]
impl GoodDataFS {
    pub fn client(&self) -> &gd::GoodDataClient {
        &self.client
    }

    pub fn get_projects_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_PROJECTS)
    }

    pub fn get_root_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_ROOT)
    }

    pub fn get_user_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.user()).to_string());

        let user = json::decode::<object::AccountSetting>(&json);

        let ts = UTC.datetime_from_str(&user.unwrap().accountSetting.updated.unwrap()[..],
                               "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();

        let updated = time::Timespec::new(ts, 0);

        create_inode_file_attributes(fs::constants::INODE_USER, json.len() as u64, updated)
    }

    pub fn get_projects_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.projects()).to_string());

        create_inode_file_attributes(fs::constants::INODE_PROJECTS_JSON,
                                     json.len() as u64,
                                     fs::constants::DEFAULT_CREATE_TIME)
    }
}

impl Filesystem for GoodDataFS {
    fn getattr(&mut self, req: &Request, ino: u64, reply: ReplyAttr) {
        let inode = inode::Inode::deserialize(ino);
        println!("GoodDataFS::getattr() - Getting attributes {} - {:?}",
                 ino,
                 inode);

        match ino {
            fs::constants::INODE_ROOT => fs::root::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS => fs::projects::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS_JSON => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_projects_json_attributes())
            }
            fs::constants::INODE_USER => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_user_json_attributes())
            }
            _ => {
                if inode.project > 0 && inode.reserved == 0 {
                    fs::projects::getattr(self, req, ino, reply)
                } else if inode.project > 0 {
                    fs::project::getattr(self, req, ino, reply)
                } else {
                    println!("getattr() - HAPR")
                }
            }
        }
    }

    fn lookup(&mut self, req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::lookup() - Looking up parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());

        match parent {
            fs::constants::INODE_ROOT => fs::root::lookup(self, req, parent, name, reply),
            fs::constants::INODE_PROJECTS => fs::projects::lookup(self, req, parent, name, reply),
            _ => {
                if parent_inode.project > 0 {
                    fs::project::lookup(self, req, parent, name, reply)
                }
            }
        }
    }

    fn read(&mut self,
            req: &Request,
            ino: u64,
            fh: u64,
            offset: u64,
            size: u32,
            reply: ReplyData) {

        match ino {
            fs::constants::INODE_PROJECTS_JSON => {
                let json = format!("{}\n",
                                   json::as_pretty_json(&self.client.projects()).to_string());
                // let json: String = fs.client.projects().clone().unwrap().into();
                reply.data(&json.as_bytes()[offset as usize..]);
            }
            fs::constants::INODE_USER => {
                let json: String = self.client.user().clone().unwrap().into();
                reply.data(&json.as_bytes()[offset as usize..]);
            }
            _ => {
                let inode = inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::read(self, req, ino, fh, offset, size, reply);
                } else {
                    println!("read() - HAPR")
                }
            }
        }
    }

    fn readdir(&mut self, req: &Request, ino: u64, fh: u64, offset: u64, reply: ReplyDirectory) {
        let inode = inode::Inode::deserialize(ino);
        println!("GoodDataFS::readdir() - Reading inode {} - {:?}, fh: {}, offset: {}",
                 ino,
                 inode,
                 fh,
                 offset);

        match ino {
            fs::constants::INODE_ROOT => {
                if offset == 0 {
                    fs::root::readdir(self, req, ino, fh, offset, reply)
                }
            }
            fs::constants::INODE_PROJECTS => {
                if offset == 0 {
                    fs::projects::readdir(self, req, ino, fh, offset, reply)
                }
            }
            _ => {
                let inode: fs::inode::Inode = fs::inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::readdir(self, req, ino, fh, offset, reply)
                }
            }
        }
    }

    fn mkdir(&mut self, _req: &Request, parent: u64, name: &Path, _mode: u32, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::mkdir() - Making dir in parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::create(self, name, reply),
            _ => reply.error(ENOSYS),
        }
    }

    fn rmdir(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::rmdir() - Removing dir in parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::rmdir(self, name, reply),
            _ => reply.error(ENOSYS),
        }
    }
}

impl GoodDataFS {
    pub fn mount(self, mountpoint: String) {
        const VERSION: &'static str = env!("CARGO_PKG_VERSION");
        println!("Mounting GoodData as Filesystem ({}), mountpoint: {}",
                 VERSION,
                 mountpoint);

        fuse::mount(self, &mountpoint, &[&OsStr::new("debug")]);
    }
}
<commit_msg>Fix I/O error while listing dir<commit_after>extern crate chrono;
extern crate fuse;
extern crate libc;
extern crate regex;
extern crate rustc_serialize;
extern crate time;
extern crate users;

use libc::ENOSYS;
use chrono::*;
use fuse::{Filesystem, Request, ReplyData, ReplyEntry, ReplyAttr, ReplyDirectory, ReplyEmpty};
use rustc_serialize::json;
use std::path::Path;

use std::ffi::OsStr;

use fs;
use fs::inode;
use gd;
use object;

use fs::helpers::{create_inode_directory_attributes, create_inode_file_attributes};

pub struct GoodDataFS {
    pub client: gd::GoodDataClient,
    pub users_cache: users::UsersCache,
}

impl Drop for GoodDataFS {
    fn drop(&mut self) {
        println!("Unmounting GoodData Filesystem");
    }
}

#[allow(dead_code)]
impl GoodDataFS {
    pub fn client(&self) -> &gd::GoodDataClient {
        &self.client
    }

    pub fn get_projects_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_PROJECTS)
    }

    pub fn get_root_dir_attributes(&self) -> fuse::FileAttr {
        create_inode_directory_attributes(fs::constants::INODE_ROOT)
    }

    pub fn get_user_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.user()).to_string());

        let user = json::decode::<object::AccountSetting>(&json);

        let ts = UTC.datetime_from_str(&user.unwrap().accountSetting.updated.unwrap()[..],
                               "%Y-%m-%d %H:%M:%S")
            .unwrap()
            .timestamp();

        let updated = time::Timespec::new(ts, 0);

        create_inode_file_attributes(fs::constants::INODE_USER, json.len() as u64, updated)
    }

    pub fn get_projects_json_attributes(&self) -> fuse::FileAttr {
        let json = format!("{}\n",
                           json::as_pretty_json(&self.client.projects()).to_string());

        create_inode_file_attributes(fs::constants::INODE_PROJECTS_JSON,
                                     json.len() as u64,
                                     fs::constants::DEFAULT_CREATE_TIME)
    }
}

impl Filesystem for GoodDataFS {
    fn getattr(&mut self, req: &Request, ino: u64, reply: ReplyAttr) {
        let inode = inode::Inode::deserialize(ino);
        println!("GoodDataFS::getattr() - Getting attributes {} - {:?}",
                 ino,
                 inode);

        match ino {
            fs::constants::INODE_ROOT => fs::root::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS => fs::projects::getattr(self, req, ino, reply),
            fs::constants::INODE_PROJECTS_JSON => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_projects_json_attributes())
            }
            fs::constants::INODE_USER => {
                reply.attr(&fs::constants::DEFAULT_TTL,
                           &self.get_user_json_attributes())
            }
            _ => {
                if inode.project > 0 && inode.reserved == 0 {
                    fs::projects::getattr(self, req, ino, reply)
                } else if inode.project > 0 {
                    fs::project::getattr(self, req, ino, reply)
                } else {
                    println!("getattr() - HAPR")
                }
            }
        }
    }

    fn lookup(&mut self, req: &Request, parent: u64, name: &Path, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::lookup() - Looking up parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());

        match parent {
            fs::constants::INODE_ROOT => fs::root::lookup(self, req, parent, name, reply),
            fs::constants::INODE_PROJECTS => fs::projects::lookup(self, req, parent, name, reply),
            _ => {
                if parent_inode.project > 0 {
                    fs::project::lookup(self, req, parent, name, reply)
                }
            }
        }
    }

    fn read(&mut self,
            req: &Request,
            ino: u64,
            fh: u64,
            offset: u64,
            size: u32,
            reply: ReplyData) {

        match ino {
            fs::constants::INODE_PROJECTS_JSON => {
                let json = format!("{}\n",
                                   json::as_pretty_json(&self.client.projects()).to_string());
                // let json: String = fs.client.projects().clone().unwrap().into();
                reply.data(&json.as_bytes()[offset as usize..]);
            }
            fs::constants::INODE_USER => {
                let json: String = self.client.user().clone().unwrap().into();
                reply.data(&json.as_bytes()[offset as usize..]);
            }
            _ => {
                let inode = inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::read(self, req, ino, fh, offset, size, reply);
                } else {
                    println!("read() - HAPR")
                }
            }
        }
    }

    fn readdir(&mut self, req: &Request, ino: u64, fh: u64, offset: u64, reply: ReplyDirectory) {
        let inode = inode::Inode::deserialize(ino);
        println!("GoodDataFS::readdir() - Reading inode {} - {:?}, fh: {}, offset: {}",
                 ino,
                 inode,
                 fh,
                 offset);

        match ino {
            fs::constants::INODE_ROOT => {
                if offset == 0 {
                    fs::root::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            fs::constants::INODE_PROJECTS => {
                if offset == 0 {
                    fs::projects::readdir(self, req, ino, fh, offset, reply)
                } else {
                    reply.ok();
                }
            }
            _ => {
                let inode: fs::inode::Inode = fs::inode::Inode::deserialize(ino);
                if inode.project > 0 {
                    fs::project::readdir(self, req, ino, fh, offset, reply)
                }
            }
        }
    }

    fn mkdir(&mut self, _req: &Request, parent: u64, name: &Path, _mode: u32, reply: ReplyEntry) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::mkdir() - Making dir in parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::create(self, name, reply),
            _ => reply.error(ENOSYS),
        }
    }

    fn rmdir(&mut self, _req: &Request, parent: u64, name: &Path, reply: ReplyEmpty) {
        let parent_inode = inode::Inode::deserialize(parent);
        println!("GoodDataFS::rmdir() - Removing dir in parent {} - {:?}, path: {}",
                 parent,
                 parent_inode,
                 name.to_str().unwrap());
        match parent {
            fs::constants::INODE_PROJECTS => fs::projects::rmdir(self, name, reply),
            _ => reply.error(ENOSYS),
        }
    }
}

impl GoodDataFS {
    pub fn mount(self, mountpoint: String) {
        const VERSION: &'static str = env!("CARGO_PKG_VERSION");
        println!("Mounting GoodData as Filesystem ({}), mountpoint: {}",
                 VERSION,
                 mountpoint);

        fuse::mount(self, &mountpoint, &[&OsStr::new("debug")]);
    }
}
<|endoftext|>


<commit_before>use time;
use std::io::timer::sleep;

use GameWindow;
use keyboard;
use mouse;
use event;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
#[deriving(Clone)]
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
#[deriving(Clone)]
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
#[deriving(Clone)]
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
#[deriving(Clone)]
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
#[deriving(Clone)]
pub struct MouseMoveArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Mouse relative move arguments.
#[deriving(Clone)]
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Mouse scroll arguments.
#[deriving(Clone)]
pub struct MouseScrollArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
    /// Scrolled mouse.
    MouseScroll(MouseScrollArgs)
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let ref mut gl = Gl::new();
/// for e in GameIterator::new(&mut window, &game_iter_settings) {
///     match e {
///         Render(args) => {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;

                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_update) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( (next_event - current_time) / 1_000_000 );
                    } else if next_event == next_frame {
                        self.state = RenderState;
                    } else {
                        self.state = HandleEventsState;
                    }
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                            }))
                        },
                        event::MouseScrolled(x, y) => {
                            Some(MouseScroll(MouseScrollArgs {
                                x: x,
                                y: y
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            // Explicitly continue because otherwise the result
                            // of this match is immediately returned.
                            continue;
                        },
                    }
                },
                MouseRelativeMoveState(dx, dy) => {
                    self.state = HandleEventsState;
                    return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                        dx: dx,
                        dy: dy,
                    }));
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };
        }
    }
}
<commit_msg>Change sleep to use std::time::duration::Duration<commit_after>use time;
use std::io::timer::sleep;
use std::time::duration::Duration;

use GameWindow;
use keyboard;
use mouse;
use event;

use std::cmp;

/// Render argument.
#[deriving(Clone)]
pub struct RenderArgs {
    /// Extrapolated time in seconds, used to do smooth animation.
    pub ext_dt: f64,
    /// The width of rendered area.
    pub width: u32,
    /// The height of rendered area.
    pub height: u32,
}

/// Update argument.
#[deriving(Clone)]
pub struct UpdateArgs {
    /// Delta time in seconds.
    pub dt: f64,
}

/// Key press arguments.
#[deriving(Clone)]
pub struct KeyPressArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Key release arguments.
#[deriving(Clone)]
pub struct KeyReleaseArgs {
    /// Keyboard key.
    pub key: keyboard::Key,
}

/// Mouse press arguments.
#[deriving(Clone)]
pub struct MousePressArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse release arguments.
#[deriving(Clone)]
pub struct MouseReleaseArgs {
    /// Mouse button.
    pub button: mouse::Button,
}

/// Mouse move arguments.
#[deriving(Clone)]
pub struct MouseMoveArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Mouse relative move arguments.
#[deriving(Clone)]
pub struct MouseRelativeMoveArgs {
    /// Delta x.
    pub dx: f64,
    /// Delta y.
    pub dy: f64,
}

/// Mouse scroll arguments.
#[deriving(Clone)]
pub struct MouseScrollArgs {
    /// x.
    pub x: f64,
    /// y.
    pub y: f64,
}

/// Contains the different game events.
#[deriving(Clone)]
pub enum GameEvent {
    /// Render graphics.
    Render(RenderArgs),
    /// Update physical state of the game.
    Update(UpdateArgs),
    /// Pressed a keyboard key.
    KeyPress(KeyPressArgs),
    /// Released a keyboard key.
    KeyRelease(KeyReleaseArgs),
    /// Pressed a mouse button.
    MousePress(MousePressArgs),
    /// Released a mouse button.
    MouseRelease(MouseReleaseArgs),
    /// Moved mouse cursor.
    MouseMove(MouseMoveArgs),
    /// Moved mouse relative, not bounded by cursor.
    MouseRelativeMove(MouseRelativeMoveArgs),
    /// Scrolled mouse.
    MouseScroll(MouseScrollArgs)
}

#[deriving(Show)]
enum GameIteratorState {
    RenderState,
    SwapBuffersState,
    UpdateLoopState,
    HandleEventsState,
    MouseRelativeMoveState(f64, f64),
    UpdateState,
}

/// Settings for the game loop behavior.
#[deriving(Clone)]
pub struct GameIteratorSettings {
    /// The number of updates per second (UPS).
    pub updates_per_second: u64,
    /// The maximum number of frames per second (FPS target).
    pub max_frames_per_second: u64,
}

/// A game loop iterator.
///
/// Example:
///
/// ```Rust
/// let game_iter_settings = GameIteratorSettings {
///     updates_per_second: 120,
///     max_frames_per_second: 60,
/// };
/// let ref mut gl = Gl::new();
/// for e in GameIterator::new(&mut window, &game_iter_settings) {
///     match e {
///         Render(args) => {
///             // Set the viewport in window to render graphics.
///             gl.viewport(0, 0, args.width as i32, args.height as i32);
///             // Create graphics context with absolute coordinates.
///             let c = Context::abs(args.width as f64, args.height as f64);
///             // Do rendering here.
///         },
///     }
/// }
/// ```
pub struct GameIterator<'a, W> {
    /// The game window used by iterator.
    pub game_window: &'a mut W,
    state: GameIteratorState,
    last_update: u64,
    last_frame: u64,
    dt_update_in_ns: u64,
    dt_frame_in_ns: u64,
    dt: f64,
}

static billion: u64 = 1_000_000_000;

impl<'a, W: GameWindow> GameIterator<'a, W> {
    /// Creates a new game iterator.
    pub fn new(
        game_window: &'a mut W,
        settings: &GameIteratorSettings
    ) -> GameIterator<'a, W> {
        let updates_per_second: u64 = settings.updates_per_second;
        let max_frames_per_second: u64 = settings.max_frames_per_second;

        let start = time::precise_time_ns();
        GameIterator {
            game_window: game_window,
            state: RenderState,
            last_update: start,
            last_frame: start,
            dt_update_in_ns: billion / updates_per_second,
            dt_frame_in_ns: billion / max_frames_per_second,
            dt: 1.0 / updates_per_second as f64,
        }
    }
}

impl<'a, W: GameWindow>
Iterator<GameEvent>
for GameIterator<'a, W> {
    /// Returns the next game event.
    fn next(&mut self) -> Option<GameEvent> {
        loop {
            match self.state {
                RenderState => {
                    if self.game_window.should_close() { return None; }

                    let start_render = time::precise_time_ns();
                    self.last_frame = start_render;

                    let (w, h) = self.game_window.get_size();
                    if w != 0 && h != 0 {
                        // Swap buffers next time.
                        self.state = SwapBuffersState;
                        return Some(Render(RenderArgs {
                                // Extrapolate time forward to allow smooth motion.
                                ext_dt: (start_render - self.last_update) as f64 / billion as f64,
                                width: w,
                                height: h,
                            }
                        ));
                    }

                    self.state = UpdateLoopState;
                },
                SwapBuffersState => {
                    self.game_window.swap_buffers();
                    self.state = UpdateLoopState;
                },
                UpdateLoopState => {
                    let current_time = time::precise_time_ns();
                    let next_frame = self.last_frame + self.dt_frame_in_ns;
                    let next_update = self.last_update + self.dt_update_in_ns;
                    let next_event = cmp::min(next_frame, next_update);
                    if next_event > current_time {
                        sleep( Duration::nanoseconds((next_event - current_time) as i32) );
                    } else if next_event == next_frame {
                        self.state = RenderState;
                    } else {
                        self.state = HandleEventsState;
                    }
                },
                HandleEventsState => {
                    // Handle all events before updating.
                    return match self.game_window.poll_event() {
                        event::KeyPressed(key) => {
                            Some(KeyPress(KeyPressArgs {
                                key: key,
                            }))
                        },
                        event::KeyReleased(key) => {
                            Some(KeyRelease(KeyReleaseArgs {
                                key: key,
                            }))
                        },
                        event::MouseButtonPressed(mouse_button) => {
                            Some(MousePress(MousePressArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseButtonReleased(mouse_button) => {
                            Some(MouseRelease(MouseReleaseArgs {
                                button: mouse_button,
                            }))
                        },
                        event::MouseMoved(x, y, relative_move) => {
                            match relative_move {
                                Some((dx, dy)) =>
                                    self.state = MouseRelativeMoveState(dx, dy),
                                None => {},
                            };
                            Some(MouseMove(MouseMoveArgs {
                                x: x,
                                y: y,
                            }))
                        },
                        event::MouseScrolled(x, y) => {
                            Some(MouseScroll(MouseScrollArgs {
                                x: x,
                                y: y
                            }))
                        },
                        event::NoEvent => {
                            self.state = UpdateState;
                            // Explicitly continue because otherwise the result
                            // of this match is immediately returned.
                            continue;
                        },
                    }
                },
                MouseRelativeMoveState(dx, dy) => {
                    self.state = HandleEventsState;
                    return Some(MouseRelativeMove(MouseRelativeMoveArgs {
                        dx: dx,
                        dy: dy,
                    }));
                },
                UpdateState => {
                    self.state = UpdateLoopState;
                    self.last_update += self.dt_update_in_ns;
                    return Some(Update(UpdateArgs{
                        dt: self.dt,
                    }));
                },
            };
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 pdb Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::msf::PageNumber;
use crate::source::SourceSlice;

/// Represents a list of `PageNumbers`, which are likely (but not certainly) sequential, and which
/// will be presented as a slice of `SourceSlice`s.
#[derive(Debug)]
pub struct PageList {
    page_size: usize,
    source_slices: Vec<SourceSlice>,
    last_page: Option<PageNumber>,
    truncated: bool,
}

impl PageList {
    /// Create a new PageList for a given page size.
    pub fn new(page_size: usize) -> Self {
        PageList {
            page_size,
            source_slices: Vec::new(),
            last_page: None,
            truncated: false,
        }
    }

    /// Add a page to the PageList. If this page number is sequential with the previous page number,
    /// it will be combined into the previous `SourceSlice` for efficiency.
    pub fn push(&mut self, page: PageNumber) {
        assert!(!self.truncated);

        let is_continuous = match self.last_page {
            Some(n) => (n + 1) == page,
            None => false,
        };

        if is_continuous {
            // extend by one page
            debug_assert!(!self.source_slices.is_empty());
            let last_slice = self.source_slices.last_mut().unwrap();
            last_slice.size += self.page_size;
        } else {
            self.source_slices.push(SourceSlice {
                offset: (self.page_size as u64) * u64::from(page),
                size: self.page_size,
            });
        }

        self.last_page = Some(page);
    }

    /// Truncate the `PageList` to request only a certain number of bytes, regardless of how many
    /// pages were pushed. Truncatation is optional, but it must be last; `push()` may not be
    /// called after `truncate()`.
    pub fn truncate(&mut self, bytes: usize) {
        let mut bytes = bytes;
        let mut new_slices: Vec<SourceSlice> = Vec::new();

        for slice in &self.source_slices {
            let mut slice: SourceSlice = *slice;
            if bytes > 0 {
                // we need something from this slice
                // restrict this slice to the number of bytes remaining
                if slice.size > bytes {
                    slice.size = bytes;
                }

                // keep it
                new_slices.push(slice);

                // subtract the number of bytes in this slice
                bytes -= slice.size;
            } else {
                // we're done
                break;
            }
        }

        self.source_slices = new_slices;
        self.truncated = true;
    }

    /// Return the total length of this PageList.
    pub fn len(&self) -> usize {
        self.source_slices.iter().fold(0, |acc, s| acc + s.size)
    }

    /// Return a slice of SourceSlices.
    pub fn source_slices(&self) -> &[SourceSlice] {
        self.source_slices.as_slice()
    }
}

#[cfg(test)]
mod tests {
    use crate::msf::page_list::*;
    use crate::source::SourceSlice;

    #[test]
    fn test_push() {
        let mut list = PageList::new(4096);

        // PageList should coalesce sequential pages
        list.push(0);
        list.push(1);
        let expected = vec![SourceSlice {
            offset: 0,
            size: 8192,
        }];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 8192);

        // PageList should handle nonsequential runs too
        list.push(4);
        list.push(5);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 16384);

        // ...including nonsequential runs that go backwards
        list.push(2);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 20480);

        // ...and runs that repeat themselves
        list.push(2);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 24576);
    }

    #[test]
    fn test_truncate() {
        let mut list = PageList::new(4096);
        list.push(0);
        list.push(1);
        list.push(4);
        list.push(5);
        list.push(2);
        list.push(2);
        assert_eq!(list.len(), 24576);

        // truncation should do nothing when it's truncating more than is described
        list.truncate(25000);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 24576);

        // it's usually employed to reduce the size of the last slice...
        list.truncate(24000);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
            SourceSlice {
                offset: 8192,
                size: 3520,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 24000);

        // ...but it should be able to lop off entire slices too
        list.truncate(10000);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 1808,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 10000);

        // and again, it shouldn't do anything if we re-truncate to a larger size
        list.truncate(12000);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 1808,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 10000);

        // finally, we should be able to truncate the entire PageList down to nothing
        list.truncate(0);
        assert_eq!(list.source_slices().len(), 0);
        assert_eq!(list.len(), 0);
    }

    #[test]
    #[should_panic]
    fn test_push_after_truncate() {
        // push after truncate isn't permitted
        let mut list = PageList::new(4096);
        list.push(5);
        list.truncate(2000);
        // so far so good

        // bam!
        list.push(6);
    }
}
<commit_msg>fix: Avoid arithmetic overflow in PageList::push<commit_after>// Copyright 2017 pdb Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

use crate::msf::PageNumber;
use crate::source::SourceSlice;

/// Represents a list of `PageNumbers`, which are likely (but not certainly) sequential, and which
/// will be presented as a slice of `SourceSlice`s.
#[derive(Debug)]
pub struct PageList {
    page_size: usize,
    source_slices: Vec<SourceSlice>,
    last_page: Option<PageNumber>,
    truncated: bool,
}

impl PageList {
    /// Create a new PageList for a given page size.
    pub fn new(page_size: usize) -> Self {
        PageList {
            page_size,
            source_slices: Vec::new(),
            last_page: None,
            truncated: false,
        }
    }

    /// Add a page to the PageList. If this page number is sequential with the previous page number,
    /// it will be combined into the previous `SourceSlice` for efficiency.
    pub fn push(&mut self, page: PageNumber) {
        assert!(!self.truncated);

        let is_continuous = match self.last_page {
            Some(n) => n.checked_add(1) == Some(page),
            None => false,
        };

        if is_continuous {
            // extend by one page
            debug_assert!(!self.source_slices.is_empty());
            let last_slice = self.source_slices.last_mut().unwrap();
            last_slice.size += self.page_size;
        } else {
            self.source_slices.push(SourceSlice {
                offset: (self.page_size as u64) * u64::from(page),
                size: self.page_size,
            });
        }

        self.last_page = Some(page);
    }

    /// Truncate the `PageList` to request only a certain number of bytes, regardless of how many
    /// pages were pushed. Truncatation is optional, but it must be last; `push()` may not be
    /// called after `truncate()`.
    pub fn truncate(&mut self, bytes: usize) {
        let mut bytes = bytes;
        let mut new_slices: Vec<SourceSlice> = Vec::new();

        for slice in &self.source_slices {
            let mut slice: SourceSlice = *slice;
            if bytes > 0 {
                // we need something from this slice
                // restrict this slice to the number of bytes remaining
                if slice.size > bytes {
                    slice.size = bytes;
                }

                // keep it
                new_slices.push(slice);

                // subtract the number of bytes in this slice
                bytes -= slice.size;
            } else {
                // we're done
                break;
            }
        }

        self.source_slices = new_slices;
        self.truncated = true;
    }

    /// Return the total length of this PageList.
    pub fn len(&self) -> usize {
        self.source_slices.iter().fold(0, |acc, s| acc + s.size)
    }

    /// Return a slice of SourceSlices.
    pub fn source_slices(&self) -> &[SourceSlice] {
        self.source_slices.as_slice()
    }
}

#[cfg(test)]
mod tests {
    use crate::msf::page_list::*;
    use crate::source::SourceSlice;

    #[test]
    fn test_push() {
        let mut list = PageList::new(4096);

        // PageList should coalesce sequential pages
        list.push(0);
        list.push(1);
        let expected = vec![SourceSlice {
            offset: 0,
            size: 8192,
        }];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 8192);

        // PageList should handle nonsequential runs too
        list.push(4);
        list.push(5);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 16384);

        // ...including nonsequential runs that go backwards
        list.push(2);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 20480);

        // ...and runs that repeat themselves
        list.push(2);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 24576);
    }

    #[test]
    fn test_truncate() {
        let mut list = PageList::new(4096);
        list.push(0);
        list.push(1);
        list.push(4);
        list.push(5);
        list.push(2);
        list.push(2);
        assert_eq!(list.len(), 24576);

        // truncation should do nothing when it's truncating more than is described
        list.truncate(25000);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 24576);

        // it's usually employed to reduce the size of the last slice...
        list.truncate(24000);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 8192,
            },
            SourceSlice {
                offset: 8192,
                size: 4096,
            },
            SourceSlice {
                offset: 8192,
                size: 3520,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 24000);

        // ...but it should be able to lop off entire slices too
        list.truncate(10000);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 1808,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 10000);

        // and again, it shouldn't do anything if we re-truncate to a larger size
        list.truncate(12000);
        let expected = vec![
            SourceSlice {
                offset: 0,
                size: 8192,
            },
            SourceSlice {
                offset: 16384,
                size: 1808,
            },
        ];
        assert_eq!(list.source_slices(), expected.as_slice());
        assert_eq!(list.len(), 10000);

        // finally, we should be able to truncate the entire PageList down to nothing
        list.truncate(0);
        assert_eq!(list.source_slices().len(), 0);
        assert_eq!(list.len(), 0);
    }

    #[test]
    #[should_panic]
    fn test_push_after_truncate() {
        // push after truncate isn't permitted
        let mut list = PageList::new(4096);
        list.push(5);
        list.truncate(2000);
        // so far so good

        // bam!
        list.push(6);
    }

    #[test]
    fn push_overflow() {
        let mut list = PageList::new(4096);
        list.push(u32::MAX);
        list.push(u32::MAX);
    }
}
<|endoftext|>


<commit_before>pub struct Clock;

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        unimplemented!(
            "Construct a new Clock from {} hours and {} minutes",
            hours,
            minutes
        );
    }

    pub fn add_minutes(self, minutes: i32) -> Self {
        unimplemented!("Add {} minutes to existing Clock time", minutes);
    }
}
<commit_msg>clock: Modified the add_minutes stub function to take self by reference<commit_after>pub struct Clock;

impl Clock {
    pub fn new(hours: i32, minutes: i32) -> Self {
        unimplemented!(
            "Construct a new Clock from {} hours and {} minutes",
            hours,
            minutes
        );
    }

    pub fn add_minutes(&self, minutes: i32) -> Self {
        unimplemented!("Add {} minutes to existing Clock time", minutes);
    }
}
<|endoftext|>


<commit_before>use std::usize;
use lalrpop_util::ParseError;
use ::value::Value;
use super::parse;
use super::lexer::Token;
use super::error::Error;
use ::string_interner::StringInterner;

const EOF: usize = usize::MAX;

fn whatever(x: &ParseError<usize, Token, Error>) -> usize {
    match x {
        &ParseError::InvalidToken{location: pos} => pos,
        &ParseError::UnrecognizedToken{expected: _, token: Some((pos, _, _))} => pos,
        &ParseError::User{error: Error::InvalidToken(_, end)} => end,
        &ParseError::User{error: Error::UnexpectedEofString(_)} => EOF,
        &ParseError::User{error: Error::UnexpectedEofChar(_)} => EOF,
        &ParseError::User{error: Error::NonAsciiChar(x)} => x,
        x => panic!("got: {:?}", x),
    }
}

macro_rules! expect_error {
    // whatever
    ($parser:ident, $input:expr, $position:expr) => (
        expect_error!($parser, $input, whatever, true, $position);
    );

    // whatever wherever
    ($parser:ident, $input:expr) => (
        expect_error!($parser, $input, whatever, false, 0);
    );

    //internal
    ($parser:ident, $input:expr, $token_fn:ident, $use_pos:expr, $position:expr) => (
        let input = &*$input;
        let interner = &mut StringInterner::new();
        let result = $parser(input, interner);

        match result {
            Err(ref err) => {
                if $use_pos && $token_fn(err) != $position {
                    panic!("for input: {:?}, got Err({:?}) at pos {}, expected pos: {}", input, err, $token_fn(err), $position);
                }
            },
            Ok(v) => panic!("expected error for string: '{}', got: {}", input, v.to_string(interner)),
        }
    );
}

macro_rules! expect_ok {
    // with rest
    ($parser:ident, $interner:expr, $input:expr, $expected:expr) => (
        let input = &*$input;
        let expected = $expected.to_string($interner);
        let result = $parser(input, $interner);
        match result {
            Ok(v) => {
                let res = v.to_string($interner);
                if res != expected {
                    panic!("parser ok, but input: {:?} got: Ok({:?}), expected: {}", input, res, expected);
                }
            },
            Err(e) => {
                panic!("input: {:?} got: Err({:?}), expected: {}", input, e, &expected);
            }
        }
    );
}

#[test]
fn bool() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "true", Value::new_bool(true));
    expect_ok!(parse, interner, "false", Value::new_bool(false));
    expect_ok!(parse, interner, "trude", Value::new_symbol(interner.intern("trude")));
    expect_ok!(parse, interner, "fale", Value::new_symbol(interner.intern("fale")));
}

#[test]
fn char() {
    let interner = &mut StringInterner::new();
    use std::char;
    use std::iter;
    let mut input: String = "#\\".into();
    let printlable_asci = ('!' as u32)..('~' as u32) + 1;
    for x in printlable_asci {
        let c = char::from_u32(x).expect(&format!("tried to create invalid char with: 0x{:X}", x));
        input.push(c);
        { expect_ok!(parse, interner, input, Value::new_char(c)); }
        input.pop();
    }

    let invalid_asci = (0..('!' as u32)).chain(iter::once(127));
    for x in invalid_asci {
        let c = char::from_u32(x).expect(&format!("tried to create invalid char with: 0x{:X}", x));
        input.push(c);
        if c != '\n' && c != '\t' && c != ' ' { expect_error!(parse, input); }
        input.pop();
    }

    // special forms
    expect_ok!(parse, interner, r"#\\s", Value::new_char(' '));
    expect_ok!(parse, interner, r"#\\t", Value::new_char('\t'));
    expect_ok!(parse, interner, r"#\\n", Value::new_char('\n'));
    expect_ok!(parse, interner, r"#\\", Value::new_char('\\'));

    expect_error!(parse, r"#\", EOF);
    expect_error!(parse, "#\\\0", 2);
}

#[test]
fn integer() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "007", Value::new_integer(7));
    expect_ok!(parse, interner, "-007", Value::new_integer(-7));
    expect_ok!(parse, interner, "123456789", Value::new_integer(123456789));
    expect_ok!(parse, interner, "-123456789", Value::new_integer(-123456789));

    expect_error!(parse, "123b456789", 3);
    expect_error!(parse, "123456789c", 9);
    expect_error!(parse, "00-7", 2);
    expect_ok!(parse, interner, "a123456789", Value::new_symbol(interner.intern("a123456789")));
    expect_ok!(parse, interner, "--7", Value::new_symbol(interner.intern("--7")));
}

#[test]
fn symbol() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "+", Value::new_symbol(interner.intern("+")));
    expect_ok!(parse, interner, "-", Value::new_symbol(interner.intern("-")));
    expect_ok!(parse, interner, "#", Value::new_symbol(interner.intern("#")));
    expect_ok!(parse, interner, "a1a", Value::new_symbol(interner.intern("a1a")));
    expect_ok!(parse, interner, "num->str", Value::new_symbol(interner.intern("num->str")));
    expect_ok!(parse, interner, "//", Value::new_symbol(interner.intern("//")));

    // error is at 1 bc lexer tries to lex integer
    expect_error!(parse, "1a", 1);
}

#[test]
fn string() {
    fn q(s: &str) -> String {
        format!("\"{}\"", s)
    }

    macro_rules! expect_str_ok {
        ($s:expr, $e:expr) => ({
            let s = q($s);
            let interner = &mut StringInterner::new();
            expect_ok!(parse, interner, s, Value::new_string($e));
        });

        ($s:expr) => (expect_str_ok!($s, $s));
    }

    expect_str_ok!("");
    expect_str_ok!("abc");
    expect_str_ok!("Hello, World!!");
    expect_str_ok!("\n");
    expect_str_ok!(r"\n", "\n");
    expect_str_ok!("\t");
    expect_str_ok!(r"\t", "\t");
    expect_str_ok!(r"\\\\", "\\\\");
    expect_str_ok!(r#"Hi there: \" \\ \n \t"#, "Hi there: \" \\ \n \t");

    expect_error!(parse, "\"", EOF);
    expect_error!(parse, "\"❤\"", 1); // non ascii
}

#[test]
fn pair() {
    let interner = &mut StringInterner::new();
    let t = Value::new_bool(true);
    let f = Value::new_bool(false);
    let e = Value::empty_list();

    expect_ok!(parse, interner, "(true . false)", Value::new_pair(t.clone(), f.clone()));
    expect_ok!(parse, interner, "(true . (false . ()))", Value::new_pair(t, Value::new_pair(f.clone(), e.clone())));

    expect_error!(parse, "(1 .)", 4);
    expect_error!(parse, "(. 2)", 1);
    expect_error!(parse, "(1 . 2 3)", 7);
    expect_error!(parse, "(1 . 2 . 3)", 7);
    expect_error!(parse, "(1 2 . 3)", 5);
}

#[test]
fn list() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "()", Value::empty_list());
    expect_ok!(parse, interner, r#"(1 "2" (3 . 4))"#, Value::new_list(&vec![Value::new_integer(1), Value::new_string("2"), Value::new_pair(Value::new_integer(3), Value::new_integer(4))]));
    expect_ok!(parse, interner, "(() ())", Value::new_list(&vec![Value::empty_list(), Value::empty_list()]));

    expect_error!(parse, "(( ())");
}

#[test]
fn quote() {
    fn quoted(v: Value, interner: &mut StringInterner) -> Value {
        let quote_id = interner.intern("quote");
        Value::new_list(&[Value::new_symbol(quote_id), v])
    }
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "'()", quoted(Value::empty_list(), interner));
    expect_ok!(parse, interner, "'1", quoted(Value::new_integer(1), interner));
    expect_ok!(parse, interner, "'true", quoted(Value::new_bool(true), interner));
    expect_ok!(parse, interner, r#"'"2""#, quoted(Value::new_string("2"), interner));
    expect_ok!(parse, interner, "'#\\a", quoted(Value::new_char('a'), interner));
    expect_ok!(parse, interner, "'sym", quoted(Value::new_symbol(interner.intern("sym")), interner));
    expect_ok!(parse, interner, "'(1 2)", quoted(Value::new_list(&[Value::new_integer(1), Value::new_integer(2)]), interner));
}

#[test]
fn recur() {
    let interner = &mut StringInterner::new();

    expect_ok!(parse, interner, "recur", Value::new_symbol(interner.intern("recur")));
    expect_error!(parse, "(let () (recur) bla)");
}

#[test]
fn everything_together() {
    let interner = &mut StringInterner::new();
    let string = r#"("hi" my "NaMe" #\i #\s recur -42 # #\\n)"#;
    assert_eq!(parse(string, interner).unwrap().to_string(interner), r#"("hi" my "NaMe" #\i #\s recur -42 # #\\n)"#)
}
<commit_msg>fix tests and add one for tail calls<commit_after>use std::usize;
use lalrpop_util::ParseError;
use ::value::Value;
use super::parse;
use super::lexer::Token;
use super::error::Error;
use ::string_interner::StringInterner;

const EOF: usize = usize::MAX;

fn whatever(x: &ParseError<usize, Token, Error>) -> usize {
    match x {
        &ParseError::InvalidToken{location: pos} => pos,
        &ParseError::UnrecognizedToken{expected: _, token: Some((pos, _, _))} => pos,
        &ParseError::User{error: Error::InvalidToken(_, end)} => end,
        &ParseError::User{error: Error::UnexpectedEofString(_)} => EOF,
        &ParseError::User{error: Error::UnexpectedEofChar(_)} => EOF,
        &ParseError::User{error: Error::NonAsciiChar(x)} => x,
        x => panic!("got: {:?}", x),
    }
}

macro_rules! expect_error {
    // whatever
    ($parser:ident, $input:expr, $position:expr) => (
        expect_error!($parser, $input, whatever, true, $position);
    );

    // whatever wherever
    ($parser:ident, $input:expr) => (
        expect_error!($parser, $input, whatever, false, 0);
    );

    //internal
    ($parser:ident, $input:expr, $token_fn:ident, $use_pos:expr, $position:expr) => (
        let input = &*$input;
        let interner = &mut StringInterner::new();
        let result = $parser(input, interner);

        match result {
            Err(ref err) => {
                if $use_pos && $token_fn(err) != $position {
                    panic!("for input: {:?}, got Err({:?}) at pos {}, expected pos: {}", input, err, $token_fn(err), $position);
                }
            },
            Ok(v) => panic!("expected error for string: '{}', got: {}", input, v[0].to_string(interner)),
        }
    );
}

macro_rules! expect_ok {
    // with rest
    ($parser:ident, $interner:expr, $input:expr, $expected:expr) => (
        let input = &*$input;
        let expected = $expected.to_string($interner);
        let result = $parser(input, $interner);
        match result {
            Ok(v) => {
                assert!(v.len() == 1);
                let v = &v[0];
                let res = v.to_string($interner);
                if res != expected {
                    panic!("parser ok, but input: {:?} got: Ok({:?}), expected: {}", input, res, expected);
                }
            },
            Err(e) => {
                panic!("input: {:?} got: Err({:?}), expected: {}", input, e, &expected);
            }
        }
    );
}

#[test]
fn bool() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "true", Value::new_bool(true));
    expect_ok!(parse, interner, "false", Value::new_bool(false));
    expect_ok!(parse, interner, "trude", Value::new_symbol(interner.intern("trude")));
    expect_ok!(parse, interner, "fale", Value::new_symbol(interner.intern("fale")));
}

#[test]
fn char() {
    let interner = &mut StringInterner::new();
    use std::char;
    use std::iter;
    let mut input: String = "#\\".into();
    let printlable_asci = ('!' as u32)..('~' as u32) + 1;
    for x in printlable_asci {
        let c = char::from_u32(x).expect(&format!("tried to create invalid char with: 0x{:X}", x));
        input.push(c);
        { expect_ok!(parse, interner, input, Value::new_char(c)); }
        input.pop();
    }

    let invalid_asci = (0..('!' as u32)).chain(iter::once(127));
    for x in invalid_asci {
        let c = char::from_u32(x).expect(&format!("tried to create invalid char with: 0x{:X}", x));
        input.push(c);
        if c != '\n' && c != '\t' && c != ' ' { expect_error!(parse, input); }
        input.pop();
    }

    // special forms
    expect_ok!(parse, interner, r"#\\s", Value::new_char(' '));
    expect_ok!(parse, interner, r"#\\t", Value::new_char('\t'));
    expect_ok!(parse, interner, r"#\\n", Value::new_char('\n'));
    expect_ok!(parse, interner, r"#\\", Value::new_char('\\'));

    expect_error!(parse, r"#\", EOF);
    expect_error!(parse, "#\\\0", 2);
}

#[test]
fn integer() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "007", Value::new_integer(7));
    expect_ok!(parse, interner, "-007", Value::new_integer(-7));
    expect_ok!(parse, interner, "123456789", Value::new_integer(123456789));
    expect_ok!(parse, interner, "-123456789", Value::new_integer(-123456789));

    expect_error!(parse, "123b456789", 3);
    expect_error!(parse, "123456789c", 9);
    expect_error!(parse, "00-7", 2);
    expect_ok!(parse, interner, "a123456789", Value::new_symbol(interner.intern("a123456789")));
    expect_ok!(parse, interner, "--7", Value::new_symbol(interner.intern("--7")));
}

#[test]
fn symbol() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "+", Value::new_symbol(interner.intern("+")));
    expect_ok!(parse, interner, "-", Value::new_symbol(interner.intern("-")));
    expect_ok!(parse, interner, "#", Value::new_symbol(interner.intern("#")));
    expect_ok!(parse, interner, "a1a", Value::new_symbol(interner.intern("a1a")));
    expect_ok!(parse, interner, "num->str", Value::new_symbol(interner.intern("num->str")));
    expect_ok!(parse, interner, "//", Value::new_symbol(interner.intern("//")));

    // error is at 1 bc lexer tries to lex integer
    expect_error!(parse, "1a", 1);
}

#[test]
fn string() {
    fn q(s: &str) -> String {
        format!("\"{}\"", s)
    }

    macro_rules! expect_str_ok {
        ($s:expr, $e:expr) => ({
            let s = q($s);
            let interner = &mut StringInterner::new();
            expect_ok!(parse, interner, s, Value::new_string($e));
        });

        ($s:expr) => (expect_str_ok!($s, $s));
    }

    expect_str_ok!("");
    expect_str_ok!("abc");
    expect_str_ok!("Hello, World!!");
    expect_str_ok!("\n");
    expect_str_ok!(r"\n", "\n");
    expect_str_ok!("\t");
    expect_str_ok!(r"\t", "\t");
    expect_str_ok!(r"\\\\", "\\\\");
    expect_str_ok!(r#"Hi there: \" \\ \n \t"#, "Hi there: \" \\ \n \t");

    expect_error!(parse, "\"", EOF);
    expect_error!(parse, "\"❤\"", 1); // non ascii
}

#[test]
fn pair() {
    let interner = &mut StringInterner::new();
    let t = Value::new_bool(true);
    let f = Value::new_bool(false);
    let e = Value::empty_list();

    expect_ok!(parse, interner, "(true . false)", Value::new_pair(t.clone(), f.clone()));
    expect_ok!(parse, interner, "(true . (false . ()))", Value::new_pair(t, Value::new_pair(f.clone(), e.clone())));

    expect_error!(parse, "(1 .)", 4);
    expect_error!(parse, "(. 2)", 1);
    expect_error!(parse, "(1 . 2 3)", 7);
    expect_error!(parse, "(1 . 2 . 3)", 7);
    expect_error!(parse, "(1 2 . 3)", 5);
}

#[test]
fn list() {
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "()", Value::empty_list());
    expect_ok!(parse, interner, r#"(1 "2" (3 . 4))"#, Value::new_list(&vec![Value::new_integer(1), Value::new_string("2"), Value::new_pair(Value::new_integer(3), Value::new_integer(4))]));
    expect_ok!(parse, interner, "(() ())", Value::new_list(&vec![Value::empty_list(), Value::empty_list()]));

    expect_error!(parse, "(( ())");
}

#[test]
fn quote() {
    fn quoted(v: Value, interner: &mut StringInterner) -> Value {
        let quote_id = interner.intern("quote");
        Value::new_list(&[Value::new_symbol(quote_id), v])
    }
    let interner = &mut StringInterner::new();
    expect_ok!(parse, interner, "'()", quoted(Value::empty_list(), interner));
    expect_ok!(parse, interner, "'1", quoted(Value::new_integer(1), interner));
    expect_ok!(parse, interner, "'true", quoted(Value::new_bool(true), interner));
    expect_ok!(parse, interner, r#"'"2""#, quoted(Value::new_string("2"), interner));
    expect_ok!(parse, interner, "'#\\a", quoted(Value::new_char('a'), interner));
    expect_ok!(parse, interner, "'sym", quoted(Value::new_symbol(interner.intern("sym")), interner));
    expect_ok!(parse, interner, "'(1 2)", quoted(Value::new_list(&[Value::new_integer(1), Value::new_integer(2)]), interner));
}

#[test]
fn recur() {
    let interner = &mut StringInterner::new();

    expect_ok!(parse, interner, "recur", Value::new_symbol(interner.intern("recur")));
    expect_ok!(parse, interner, "'(recur)", Value::new_list(&[Value::new_symbol(interner.intern("quote")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "'recur", Value::new_list(&[Value::new_symbol(interner.intern("quote")), Value::new_symbol(interner.intern("recur"))]));
}

#[test]
fn tail_calls() {
    let interner = &mut StringInterner::new();

    // top level
    expect_error!(parse, "(recur)");

    // begin
    expect_error!(parse, "(begin (recur))");
    expect_error!(parse, "(begin bla (recur))");

    // define covered later

    // if
    expect_error!(parse, "(if true (recur) bla)");
    expect_error!(parse, "(if true bla (recur))");
    expect_error!(parse, "(if true (recur) (recur))");

    // let
    expect_error!(parse, "(let () (recur))");
    expect_error!(parse, "(let () bla (recur))");

    // loop
    expect_ok!(parse, interner, "(loop () (recur))", Value::new_list(&[Value::new_symbol(interner.intern("loop")), Value::empty_list(), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "(loop () bla (recur))", Value::new_list(&[Value::new_symbol(interner.intern("loop")), Value::empty_list(), Value::new_symbol(interner.intern("bla")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_error!(parse, "(loop () (recur) bla)");

    // lambda
    expect_ok!(parse, interner, "(lambda () (recur))", Value::new_list(&[Value::new_symbol(interner.intern("lambda")), Value::empty_list(), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_ok!(parse, interner, "(lambda () bla (recur))", Value::new_list(&[Value::new_symbol(interner.intern("lambda")), Value::empty_list(), Value::new_symbol(interner.intern("bla")), Value::new_list(&[Value::new_symbol(interner.intern("recur"))])]));
    expect_error!(parse, "(lambda () (recur) bla)");

    // invalid tail calls
    let begin = "(begin (recur) bla)";
    let define = "(define a (recur))";
    let let_ = "(let () (recur) bla)";

    let no_tail_calls = &[begin, define, let_];

    for x in no_tail_calls {
        // insert x so that a tail call would be correct
        let code = format!("(loop () {})", x);
        expect_error!(parse, code);
    }
}

// TODO add tests for special forms

#[test]
fn everything_together() {
    let interner = &mut StringInterner::new();
    let string = r#"("hi" my "NaMe" #\i #\s recur -42 # #\\n)"#;
    let parsed = parse(string, interner).unwrap();
    assert!(parsed.len() == 1);
    assert_eq!(parsed[0].to_string(interner), r#"("hi" my "NaMe" #\i #\s recur -42 # #\\n)"#);
}
<|endoftext|>


<commit_before>use core::marker::PhantomData;

use std::alloc;
use std::mem;
use std::ptr;
use std::ops::RangeFrom;
use std::slice;
use std::str;

pub struct PartialString {
    buf: *const u8,
    len: usize,
    _marker: PhantomData<[u8]>,
}

impl Drop for PartialString {
    fn drop(&mut self) {
        unsafe {
            let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::<u8>());
            alloc::dealloc(self.buf as *mut u8, layout);

            self.buf = ptr::null();
            self.len = 0;
        }
    }
}

impl Clone for PartialString {
    #[inline]
    fn clone(&self) -> Self {
        self.clone_from_offset(0)
    }
}

fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
    let mut terminator_idx = 0;

    for c in iter {
        if c == '\u{0}' {
            break;
        }

        terminator_idx += c.len_utf8();
    }

    terminator_idx
}

pub struct PStrIter {
    buf: *const u8,
}

impl PStrIter {
    #[inline]
    fn from(buf: *const u8, idx: usize) -> Self {
        PStrIter {
            buf: (buf as usize + idx) as *const _
        }
    }
}

impl Iterator for PStrIter {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let mut byte_count = 0;

            for n in 0 .. mem::size_of::<char>() {
                let b = ptr::read((self.buf as usize + n) as *const u8);

                if b == 0u8 {
                    break;
                } else {
                    byte_count += 1;
                }
            }

            if byte_count == 0 {
                return None;
            }

            let slice = slice::from_raw_parts(self.buf, byte_count);
            let s = str::from_utf8(slice).unwrap();

            if let Some(c) = s.chars().next() {
                self.buf = self.buf.offset(c.len_utf8() as isize);
                Some(c)
            } else {
                None
            }
        }
    }
}

impl PartialString {
    #[inline]
    pub(super)
    fn new(src: &str) -> Option<(Self, &str)> {
        let pstr = PartialString {
            buf: ptr::null_mut(),
            len: 0,
            _marker: PhantomData,
        };

        unsafe {
            pstr.append_chars(src)
        }
    }

    #[inline]
    pub(super)
    fn empty() -> Self {
        PartialString {
            buf: &"\u{0}".as_bytes()[0] as *const _,
            len: '\u{0}'.len_utf8(),
            _marker: PhantomData,
        }
    }

    unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
        let terminator_idx = scan_for_terminator(src.chars());

        if terminator_idx == 0 {
            return None;
        }

        let layout = alloc::Layout::from_size_align_unchecked(
            terminator_idx + '\u{0}'.len_utf8(),
            mem::align_of::<u8>(),
        );

        self.buf = alloc::alloc(layout) as *const _;
        self.len = terminator_idx + '\u{0}'.len_utf8();

        ptr::copy(
            src.as_ptr(),
            self.buf as *mut _,
            terminator_idx,
        );

        self.write_terminator_at(terminator_idx);

        Some(if terminator_idx != src.len() {
            (self, &src[terminator_idx + '\u{0}'.len_utf8() ..])
        } else {
            (self, "")
        })
    }

    pub(super)
    fn clone_from_offset(&self, n: usize) -> Self {
        let len = if self.len > n { self.len - n } else { 0 };

        let mut pstr = PartialString {
            buf: ptr::null_mut(),
            len: len + '\u{0}'.len_utf8(),
            _marker: PhantomData,
        };

        unsafe {
            let layout = alloc::Layout::from_size_align_unchecked(
                len + '\u{0}'.len_utf8(),
                mem::align_of::<u8>(),
            );

            pstr.buf = alloc::alloc(layout);

            if len > 0 {
                ptr::copy(
                    (self.buf as usize + n) as *const u8,
                    pstr.buf as *mut _,
                    len,
                );
            }

            pstr.write_terminator_at(len);
        }

        pstr
    }

    #[inline]
    pub(super)
    fn write_terminator_at(&mut self, index: usize) {
        unsafe {
            ptr::write(
                (self.buf as usize + index) as *mut u8,
                0u8,
            );
        }
    }

    #[inline]
    pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
        PStrIter::from(self.buf, index.start)
    }

    #[inline]
    pub fn at_end(&self, end_n: usize) -> bool {
        unsafe {
            ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
        }
    }
}
<commit_msg>allocate empty partial strings<commit_after>use core::marker::PhantomData;

use std::alloc;
use std::mem;
use std::ptr;
use std::ops::RangeFrom;
use std::slice;
use std::str;

pub struct PartialString {
    buf: *const u8,
    len: usize,
    _marker: PhantomData<[u8]>,
}

impl Drop for PartialString {
    fn drop(&mut self) {
        unsafe {
            let layout = alloc::Layout::from_size_align_unchecked(self.len, mem::align_of::<u8>());
            alloc::dealloc(self.buf as *mut u8, layout);

            self.buf = ptr::null();
            self.len = 0;
        }
    }
}

impl Clone for PartialString {
    #[inline]
    fn clone(&self) -> Self {
        self.clone_from_offset(0)
    }
}

fn scan_for_terminator<Iter: Iterator<Item = char>>(iter: Iter) -> usize {
    let mut terminator_idx = 0;

    for c in iter {
        if c == '\u{0}' {
            break;
        }

        terminator_idx += c.len_utf8();
    }

    terminator_idx
}

pub struct PStrIter {
    buf: *const u8,
}

impl PStrIter {
    #[inline]
    fn from(buf: *const u8, idx: usize) -> Self {
        PStrIter {
            buf: (buf as usize + idx) as *const _
        }
    }
}

impl Iterator for PStrIter {
    type Item = char;

    fn next(&mut self) -> Option<Self::Item> {
        unsafe {
            let mut byte_count = 0;

            for n in 0 .. mem::size_of::<char>() {
                let b = ptr::read((self.buf as usize + n) as *const u8);

                if b == 0u8 {
                    break;
                } else {
                    byte_count += 1;
                }
            }

            if byte_count == 0 {
                return None;
            }

            let slice = slice::from_raw_parts(self.buf, byte_count);
            let s = str::from_utf8(slice).unwrap();

            if let Some(c) = s.chars().next() {
                self.buf = self.buf.offset(c.len_utf8() as isize);
                Some(c)
            } else {
                None
            }
        }
    }
}

impl PartialString {
    #[inline]
    pub(super)
    fn new(src: &str) -> Option<(Self, &str)> {
        let pstr = PartialString {
            buf: ptr::null_mut(),
            len: 0,
            _marker: PhantomData,
        };

        unsafe {
            pstr.append_chars(src)
        }
    }

    #[inline]
    pub(super)
    fn empty() -> Self {
        let mut pstr = PartialString {
            buf: ptr::null(),
            len: 0,
            _marker: PhantomData,
        };

        unsafe {
            let layout = alloc::Layout::from_size_align_unchecked(
                '\u{0}'.len_utf8(),
                mem::align_of::<u8>(),
            );

            pstr.buf = alloc::alloc(layout) as *const _;
            pstr.len = '\u{0}'.len_utf8();

            pstr.write_terminator_at(0);
        }

        pstr
    }

    unsafe fn append_chars(mut self, src: &str) -> Option<(Self, &str)> {
        let terminator_idx = scan_for_terminator(src.chars());

        if terminator_idx == 0 {
            return None;
        }

        let layout = alloc::Layout::from_size_align_unchecked(
            terminator_idx + '\u{0}'.len_utf8(),
            mem::align_of::<u8>(),
        );

        self.buf = alloc::alloc(layout) as *const _;
        self.len = terminator_idx + '\u{0}'.len_utf8();

        ptr::copy(
            src.as_ptr(),
            self.buf as *mut _,
            terminator_idx,
        );

        self.write_terminator_at(terminator_idx);

        Some(if terminator_idx != src.len() {
            (self, &src[terminator_idx + '\u{0}'.len_utf8() ..])
        } else {
            (self, "")
        })
    }

    pub(super)
    fn clone_from_offset(&self, n: usize) -> Self {
        let len = if self.len > n { self.len - n } else { 0 };

        let mut pstr = PartialString {
            buf: ptr::null_mut(),
            len: len + '\u{0}'.len_utf8(),
            _marker: PhantomData,
        };

        unsafe {
            let layout = alloc::Layout::from_size_align_unchecked(
                len + '\u{0}'.len_utf8(),
                mem::align_of::<u8>(),
            );

            pstr.buf = alloc::alloc(layout);

            if len > 0 {
                ptr::copy(
                    (self.buf as usize + n) as *const u8,
                    pstr.buf as *mut _,
                    len,
                );
            }

            pstr.write_terminator_at(len);
        }

        pstr
    }

    #[inline]
    pub(super)
    fn write_terminator_at(&mut self, index: usize) {
        unsafe {
            ptr::write(
                (self.buf as usize + index) as *mut u8,
                0u8,
            );
        }
    }

    #[inline]
    pub fn range_from(&self, index: RangeFrom<usize>) -> PStrIter {
        PStrIter::from(self.buf, index.start)
    }

    #[inline]
    pub fn at_end(&self, end_n: usize) -> bool {
        unsafe {
            ptr::read((self.buf as usize + end_n) as *const u8) == 0u8
        }
    }
}
<|endoftext|>


<commit_before>use nom::{IResult, Consumer, ConsumerState};
use metadata::parser::{header, block_data};

use std::collections::HashMap;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Block {
  /// Marks whether the current metadata block is the last.
  pub is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  pub length: u32,
  /// Block data containing on of the eight different types of metadata.
  pub data: BlockData,
}

#[derive(Debug, PartialEq, Eq)]
pub enum BlockData {
  StreamInfo(StreamInfo),
  Padding(u32),
  Application(Application),
  SeekTable(Vec<SeekPoint>),
  VorbisComment(VorbisComment),
  CueSheet(CueSheet),
  Picture(Picture),
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream
#[derive(Debug, PartialEq, Eq)]
pub struct StreamInfo {
  pub min_block_size: u16,
  pub max_block_size: u16,
  pub min_frame_size: u32,
  pub max_frame_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub bits_per_sample: u8,
  pub total_samples: u64,
  pub md5_sum: [u8; 16],
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  pub id: String,
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  pub sample_number: u64,
  pub stream_offset: u64,
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  pub vendor_string: String,
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  pub media_catalog_number: String,
  pub lead_in: u64,
  pub is_cd: bool,
  pub tracks: Vec<CueSheetTrack>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  pub offset: u64,
  pub number: u8,
  pub isrc: String,
  pub is_audio: bool,
  pub is_pre_emphasis: bool,
  pub indices: Vec<CueSheetTrackIndex>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  pub offset: u64,
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  pub picture_type: PictureType,
  pub mime_type: String,
  pub description: String,
  pub width: u32,
  pub height: u32,
  pub depth: u32,
  pub colors: u32,
  pub data: Vec<u8>,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  Other,
  FileIconStandard,
  FileIcon,
  FrontCover,
  BackCover,
  LeafletPage,
  Media,
  LeadArtist,
  Artist,
  Conductor,
  Band,
  Composer,
  Lyricist,
  RecordingLocation,
  DuringRecording,
  DuringPerformace,
  VideoScreenCapture,
  Fish,
  Illustration,
  BandLogo,
  PublisherLogo,
}

enum ParserState {
  FLAC,
  Header,
  MetaData,
}

pub struct MetaDataConsumer {
  state: ParserState,
  is_last: bool,
  block_type: u8,
  length: u32,
  pub data: Vec<Block>
}

impl MetaDataConsumer {
  pub fn new() -> MetaDataConsumer {
    MetaDataConsumer {
      state: ParserState::FLAC,
      is_last: false,
      block_type: 127,
      length: 0,
      data: Vec::new(),
    }
  }
}

impl Consumer for MetaDataConsumer {
  fn consume(&mut self, input: &[u8]) -> ConsumerState {
    match self.state {
      ParserState::FLAC     => {
        match tag!(input, "fLaC") {
          IResult::Done(_, _) => {
            self.state = ParserState::Header;
            ConsumerState::Await(4, 4)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      }
      ParserState::Header   => {
        match header(input) {
          IResult::Done(_, data) => {
            let (is_last, block_type, length) = data;

            self.state      = ParserState::MetaData;
            self.is_last    = is_last;
            self.block_type = block_type;
            self.length     = length;

            ConsumerState::Await(4, length as usize)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      },
      ParserState::MetaData => {
        let length = self.length as usize;

        match block_data(input, self.block_type, self.length) {
          IResult::Done(_, data) => {
            self.data.push(Block {
              is_last: self.is_last,
              length: self.length,
              data: data,
            });

            if self.is_last {
              ConsumerState::ConsumerDone
            } else {
              self.state = ParserState::Header;

              ConsumerState::Await(length, 4)
            }
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, length),
        }
      }
    }
  }

  fn failed(&mut self, error_code: u32) {
    println!("Failed with error code: {}", error_code);
  }

  fn end(&mut self) {}
}
<commit_msg>Add documentation for the `BlockData` struct<commit_after>use nom::{IResult, Consumer, ConsumerState};
use metadata::parser::{header, block_data};

use std::collections::HashMap;

/// Data associated with a single metadata block.
#[derive(Debug)]
pub struct Block {
  /// Marks whether the current metadata block is the last.
  pub is_last: bool,
  /// The length, in bytes, of the block being parsed. This does not include
  /// the metadata block header.
  pub length: u32,
  /// Block data containing on of the eight different types of metadata.
  pub data: BlockData,
}

/// General enum that hold all the different metadata block data.
#[derive(Debug, PartialEq, Eq)]
pub enum BlockData {
  /// Information regarding the entire audio stream.
  StreamInfo(StreamInfo),
  /// Block that represents a number of padded bytes.
  Padding(u32),
  /// Data used by third-party applications.
  Application(Application),
  /// Table of multiple points to seek, or skip, to within the FLAC file.
  SeekTable(Vec<SeekPoint>),
  /// Stores human-readable name/value pairs.
  VorbisComment(VorbisComment),
  /// Stores cue information
  CueSheet(CueSheet),
  /// Stores pictures associated with the FLAC file.
  Picture(Picture),
  /// A type of block data that isn't know or doesn't match the type above.
  Unknown(Vec<u8>),
}

/// Information regarding the entire audio stream
#[derive(Debug, PartialEq, Eq)]
pub struct StreamInfo {
  pub min_block_size: u16,
  pub max_block_size: u16,
  pub min_frame_size: u32,
  pub max_frame_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub bits_per_sample: u8,
  pub total_samples: u64,
  pub md5_sum: [u8; 16],
}

/// Data used by third-party applications.
#[derive(Debug, PartialEq, Eq)]
pub struct Application {
  pub id: String,
  pub data: Vec<u8>,
}

/// Seek, or skip, to a point within the FLAC file.
#[derive(Debug, PartialEq, Eq)]
pub struct SeekPoint {
  pub sample_number: u64,
  pub stream_offset: u64,
  pub frame_samples: u16,
}

/// Stores human-readable name/value pairs.
#[derive(Debug, PartialEq, Eq)]
pub struct VorbisComment {
  pub vendor_string: String,
  pub comments: HashMap<String, String>,
}

/// Stores cue information.
///
/// Generally for storing information from Compact Disk Digital Audio, but
/// can be used as a cueing mechanism for playback.
#[derive(Debug, PartialEq, Eq)]
pub struct CueSheet {
  pub media_catalog_number: String,
  pub lead_in: u64,
  pub is_cd: bool,
  pub tracks: Vec<CueSheetTrack>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrack {
  pub offset: u64,
  pub number: u8,
  pub isrc: String,
  pub is_audio: bool,
  pub is_pre_emphasis: bool,
  pub indices: Vec<CueSheetTrackIndex>,
}

#[derive(Debug, PartialEq, Eq)]
pub struct CueSheetTrackIndex {
  pub offset: u64,
  pub number: u8,
}

/// Stores pictures associated with the FLAC file.
///
/// More than likely these pictures will be cover art, but you can have more
/// than one within a file, which are distinguished by `PictureType`and it's
/// mime type string.
#[derive(Debug, PartialEq, Eq)]
pub struct Picture {
  pub picture_type: PictureType,
  pub mime_type: String,
  pub description: String,
  pub width: u32,
  pub height: u32,
  pub depth: u32,
  pub colors: u32,
  pub data: Vec<u8>,
}

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum PictureType {
  Other,
  FileIconStandard,
  FileIcon,
  FrontCover,
  BackCover,
  LeafletPage,
  Media,
  LeadArtist,
  Artist,
  Conductor,
  Band,
  Composer,
  Lyricist,
  RecordingLocation,
  DuringRecording,
  DuringPerformace,
  VideoScreenCapture,
  Fish,
  Illustration,
  BandLogo,
  PublisherLogo,
}

enum ParserState {
  FLAC,
  Header,
  MetaData,
}

pub struct MetaDataConsumer {
  state: ParserState,
  is_last: bool,
  block_type: u8,
  length: u32,
  pub data: Vec<Block>
}

impl MetaDataConsumer {
  pub fn new() -> MetaDataConsumer {
    MetaDataConsumer {
      state: ParserState::FLAC,
      is_last: false,
      block_type: 127,
      length: 0,
      data: Vec::new(),
    }
  }
}

impl Consumer for MetaDataConsumer {
  fn consume(&mut self, input: &[u8]) -> ConsumerState {
    match self.state {
      ParserState::FLAC     => {
        match tag!(input, "fLaC") {
          IResult::Done(_, _) => {
            self.state = ParserState::Header;
            ConsumerState::Await(4, 4)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      }
      ParserState::Header   => {
        match header(input) {
          IResult::Done(_, data) => {
            let (is_last, block_type, length) = data;

            self.state      = ParserState::MetaData;
            self.is_last    = is_last;
            self.block_type = block_type;
            self.length     = length;

            ConsumerState::Await(4, length as usize)
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, 4),
        }
      },
      ParserState::MetaData => {
        let length = self.length as usize;

        match block_data(input, self.block_type, self.length) {
          IResult::Done(_, data) => {
            self.data.push(Block {
              is_last: self.is_last,
              length: self.length,
              data: data,
            });

            if self.is_last {
              ConsumerState::ConsumerDone
            } else {
              self.state = ParserState::Header;

              ConsumerState::Await(length, 4)
            }
          }
          IResult::Error(_)      => ConsumerState::ConsumerError(0),
          IResult::Incomplete(_) => ConsumerState::Await(0, length),
        }
      }
    }
  }

  fn failed(&mut self, error_code: u32) {
    println!("Failed with error code: {}", error_code);
  }

  fn end(&mut self) {}
}
<|endoftext|>