<commit_before>//! Code for the internal Lua thread which handles all Lua requests.

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

use hlua::{Lua, LuaError};

use super::types::*;
use super::rust_interop;
use super::init_path;

lazy_static! {
    /// Sends requests to the Lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the Lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

const ERR_LOCK_RUNNING: &'static str = "Lua thread: unable to lock RUNNING";
const ERR_LOCK_SENDER: &'static str = "Lua thread: unable to lock SENDER";

/// Struct sent to the Lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

// Reexported in lua/mod.rs:11
/// Whether the Lua thread is currently available.
pub fn running() -> bool {
    *RUNNING.read().expect(ERR_LOCK_RUNNING)
}

// Reexported in lua/mod.rs:11
/// Errors which may arise from attempting
/// to sending a message to the Lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

// Reexported in lua/mod.rs:11
/// Attemps to send a LuaQuery to the Lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().expect(ERR_LOCK_SENDER);
        match *maybe_sender {
            Some(ref real_sender) => {
                // Senders are designed to be cloneable
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    // Create a response channel
    let (response_tx, response_rx) = channel();
    let message = LuaMessage { reply: response_tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(response_rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the Lua thread.
pub fn init() {
    trace!("Initializing...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = Lua::new();
    debug!("Loading Lua libraries...");
    lua.openlibs();
    trace!("Loading way-cooler libraries...");
    rust_interop::register_libraries(&mut lua);

    let (use_config, maybe_init_file) = init_path::get_config();
    if use_config {
        match maybe_init_file {
            Ok(init_file) => {
                debug!("Found config file...");
                // TODO defaults here are important
                let _: () = lua.execute_from_reader(init_file)
                    .expect("Unable to load config file");
                debug!("Read config file");
            }
            Err(reason) => {
                panic!("Unable to load init file: {}", reason)
            }
        }
    }
    else {
        trace!("Skipping config search");
    }

    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    debug!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || { main_loop(receiver, &mut lua) });
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                handle_message(message, lua);
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
            panic!("Lua thread received termination request.");
        },

        LuaQuery::Restart => {
            use std::time::Duration;
            trace!("Received restart signal!");
            error!("Lua thread restart not supported!");

            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            // The only real way to restart
            let _new_handle = thread::Builder::new()
                .name("Lua re-init".to_string())
                .spawn(move || {
                    thread::sleep(Duration::from_secs(4));
                    init();
                });

            panic!("Lua thread: Restarting!");
        },

        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            info!("Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let Ok
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },
        LuaQuery::ExecRust(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::HandleKey(press) => {
            trace!("Lua: handling keypress {}", &press);
            let press_ix = press.get_lua_index_string();
            // Access the index
            let code = format!("__key_map['{}']()", press_ix);
            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error handling {}: {:?}", &press, error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Handled keypress okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        }
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}
<commit_msg>No longer panic when Lua thread closing<commit_after>//! Code for the internal Lua thread which handles all Lua requests.

use std::thread;
use std::fs::{File};
use std::path::Path;
use std::fmt::{Debug, Formatter};
use std::fmt::Result as FmtResult;
use std::sync::{Mutex, RwLock};
use std::sync::mpsc::{channel, Sender, Receiver};

use hlua::{Lua, LuaError};

use super::types::*;
use super::rust_interop;
use super::init_path;

lazy_static! {
    /// Sends requests to the Lua thread
    static ref SENDER: Mutex<Option<Sender<LuaMessage>>> = Mutex::new(None);

    /// Whether the Lua thread is currently running
    pub static ref RUNNING: RwLock<bool> = RwLock::new(false);
}

const ERR_LOCK_RUNNING: &'static str = "Lua thread: unable to lock RUNNING";
const ERR_LOCK_SENDER: &'static str = "Lua thread: unable to lock SENDER";

/// Struct sent to the Lua query
struct LuaMessage {
    reply: Sender<LuaResponse>,
    query: LuaQuery
}

unsafe impl Send for LuaMessage { }
unsafe impl Sync for LuaMessage { }

impl Debug for LuaMessage {
    fn fmt(&self, f: &mut Formatter) -> FmtResult {
        write!(f, "LuaMessage({:?})", self.query)
    }
}

// Reexported in lua/mod.rs:11
/// Whether the Lua thread is currently available.
pub fn running() -> bool {
    *RUNNING.read().expect(ERR_LOCK_RUNNING)
}

// Reexported in lua/mod.rs:11
/// Errors which may arise from attempting
/// to sending a message to the Lua thread.
#[derive(Debug)]
pub enum LuaSendError {
    /// The thread crashed, was shut down, or rebooted.
    ThreadClosed,
    /// The thread has not been initialized yet (maybe not used)
    ThreadUninitialized,
    /// The sender had an issue, most likey because the thread panicked.
    /// Following the `Sender` API, the original value sent is returned.
    Sender(LuaQuery)
}

// Reexported in lua/mod.rs:11
/// Attemps to send a LuaQuery to the Lua thread.
pub fn send(query: LuaQuery) -> Result<Receiver<LuaResponse>, LuaSendError> {
    if !running() {
        return Err(LuaSendError::ThreadClosed);
    }
    let thread_sender: Sender<LuaMessage>;
    {
        let maybe_sender = SENDER.lock().expect(ERR_LOCK_SENDER);
        match *maybe_sender {
            Some(ref real_sender) => {
                // Senders are designed to be cloneable
                thread_sender = real_sender.clone();
            },
            // If the sender doesn't exist yet, the thread doesn't either
            None => {
                return Err(LuaSendError::ThreadUninitialized);
            }
        }
    }
    // Create a response channel
    let (response_tx, response_rx) = channel();
    let message = LuaMessage { reply: response_tx, query: query };
    match thread_sender.send(message) {
        Ok(_) => Ok(response_rx),
        Err(e) => Err(LuaSendError::Sender(e.0.query))
    }
}

/// Initialize the Lua thread.
pub fn init() {
    trace!("Initializing...");
    let (tx, receiver) = channel();
    *SENDER.lock().expect(ERR_LOCK_SENDER) = Some(tx);
    let mut lua = Lua::new();
    debug!("Loading Lua libraries...");
    lua.openlibs();
    trace!("Loading way-cooler libraries...");
    rust_interop::register_libraries(&mut lua);

    let (use_config, maybe_init_file) = init_path::get_config();
    if use_config {
        match maybe_init_file {
            Ok(init_file) => {
                debug!("Found config file...");
                // TODO defaults here are important
                let _: () = lua.execute_from_reader(init_file)
                    .expect("Unable to load config file");
                debug!("Read config file");
            }
            Err(reason) => {
                panic!("Unable to load init file: {}", reason)
            }
        }
    }
    else {
        trace!("Skipping config search");
    }

    // Only ready after loading libs
    *RUNNING.write().expect(ERR_LOCK_RUNNING) = true;
    debug!("Entering main loop...");
    let _lua_handle = thread::Builder::new()
        .name("Lua thread".to_string())
        .spawn(move || { main_loop(receiver, &mut lua) });
}

/// Main loop of the Lua thread:
///
/// ## Loop
/// * Wait for a message from the receiver
/// * Handle message
/// * Send response
fn main_loop(receiver: Receiver<LuaMessage>, lua: &mut Lua) {
    loop {
        trace!("Lua: awaiting request");
        let request = receiver.recv();
        match request {
            Err(e) => {
                error!("Lua thread: unable to receive message: {}", e);
                error!("Lua thread: now panicking!");
                *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;

                panic!("Lua thread: lost contact with host, exiting!");
            }
            Ok(message) => {
                trace!("Handling a request");
                handle_message(message, lua);
            }
        }
    }
}

/// Handle each LuaQuery option sent to the thread
fn handle_message(request: LuaMessage, lua: &mut Lua) {
    match request.query {
        LuaQuery::Terminate => {
            trace!("Received terminate signal");
            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            info!("Lua thread terminating!");
        },

        LuaQuery::Restart => {
            use std::time::Duration;
            trace!("Received restart signal!");
            error!("Lua thread restart not supported!");

            *RUNNING.write().expect(ERR_LOCK_RUNNING) = false;
            thread_send(request.reply, LuaResponse::Pong);

            // The only real way to restart
            let _new_handle = thread::Builder::new()
                .name("Lua re-init".to_string())
                .spawn(move || {
                    thread::sleep(Duration::from_secs(4));
                    init();
                });

            panic!("Lua thread: Restarting!");
        },

        LuaQuery::Execute(code) => {
            trace!("Received request to execute {}", code);

            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error executing code: {:?}", error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Code executed okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        },

        LuaQuery::ExecFile(name) => {
            info!("Executing {}", name);

            let path = Path::new(&name);
            let try_file = File::open(path);

            if let Ok(file) = try_file {
                let result = lua.execute_from_reader::<(), File>(file);
                if let Err(err) = result {
                    warn!("Error executing {}!", name);

                    thread_send(request.reply, LuaResponse::Error(err));
                }
                else {
                    trace!("Execution of {} successful.", name);
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
            else { // Could not open file
                // Unwrap_err is used because we're in the else of let Ok
                let read_error =
                    LuaError::ReadError(try_file.unwrap_err());

                thread_send(request.reply, LuaResponse::Error(read_error));
            }
        },
        LuaQuery::ExecRust(func) => {
            let result = func(lua);
            thread_send(request.reply, LuaResponse::Variable(Some(result)));
        },
        LuaQuery::HandleKey(press) => {
            trace!("Lua: handling keypress {}", &press);
            let press_ix = press.get_lua_index_string();
            // Access the index
            let code = format!("__key_map['{}']()", press_ix);
            match lua.execute::<()>(&code) {
                Err(error) => {
                    warn!("Error handling {}: {:?}", &press, error);
                    thread_send(request.reply, LuaResponse::Error(error));
                }
                Ok(_) => {
                    trace!("Handled keypress okay.");
                    thread_send(request.reply, LuaResponse::Pong);
                }
            }
        }
        LuaQuery::Ping => {
            thread_send(request.reply, LuaResponse::Pong);
        },
    }
}

fn thread_send(sender: Sender<LuaResponse>, response: LuaResponse) {
    match sender.send(response) {
        Err(err) => {
            match err.0 {
                LuaResponse::Pong => {}, // Those are boring
                _ => {
                    warn!("thread: Someone dropped an important Lua response!");
                }
            }
        }
        Ok(_) => {}
    }
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io;
use std::io::Read;
use std::io::Write;
use std::path::Path;

pub trait Filesystem {
  type FSRead: Read;
  type FSWrite: Write;
  fn open<P: AsRef<Path>>(p: P) -> io::Result<Self::FSRead>;
  fn save<P: AsRef<Path>>(p: P) -> io::Result<Self::FSWrite>;
}

pub struct DefaultFilesystem;
impl Filesystem for DefaultFilesystem {
    type FSRead = File;
    type FSWrite = File;

    fn open<P: AsRef<Path>>(p: P) -> io::Result<Self::FSRead> {
        File::open(p)
    }
    fn save<P: AsRef<Path>>(p: P) -> io::Result<Self::FSWrite> {
        File::create(p)
    }
}
<commit_msg>Add some permission tests to the Filesystem trait<commit_after>use std::env;
use std::fs;
use std::fs::File;
use std::io;
use std::io::Read;
use std::io::Write;
use std::path::{PathBuf, Path};

pub trait Filesystem {
  type FSRead: Read;
  type FSWrite: Write;
  fn make_absolute<P: AsRef<Path>>(p: P) -> io::Result<PathBuf>;
  fn open<P: AsRef<Path>>(p: P) -> io::Result<Self::FSRead>;
  fn can_open<P: AsRef<Path>>(p: P) -> io::Result<()>;
  fn save<P: AsRef<Path>>(p: P) -> io::Result<Self::FSWrite>;
  fn can_save<P: AsRef<Path>>(p: P) -> io::Result<()>;
}

pub struct DefaultFilesystem;
impl Filesystem for DefaultFilesystem {
    type FSRead = File;
    type FSWrite = File;

    fn make_absolute<P: AsRef<Path>>(p: P) -> io::Result<PathBuf> {
        let mut path = try!(env::current_dir());
        path.push(p);
        Ok(path)
    }

    fn open<P: AsRef<Path>>(p: P) -> io::Result<Self::FSRead> {
        File::open(p)
    }

    fn can_open<P: AsRef<Path>>(p: P) -> io::Result<()> {
        let path = try!(Self::make_absolute(p));

        {
            let parent = match path.parent() {
                Some(path) => path,
                None => return Err(io::Error::new(io::ErrorKind::Other, "Invalid path")),
            };

            let res = try!(fs::metadata(parent));
            // TODO: Add actual testing of permissions, etc...
        }

        let res = try!(fs::metadata(path));
        // TODO: Add actual testing of permissions, etc...

        Ok(())
    }

    fn save<P: AsRef<Path>>(p: P) -> io::Result<Self::FSWrite> {
        File::create(p)
    }

    fn can_save<P: AsRef<Path>>(p: P) -> io::Result<()> {
        let path = try!(Self::make_absolute(p));

        {
            let parent = match path.parent() {
                Some(path) => path,
                None => return Err(io::Error::new(io::ErrorKind::Other, "Invalid path")),
            };

            let res = try!(fs::metadata(parent));
            // TODO: Add actual testing of permissions, etc...
        }

        let res = fs::metadata(path);
        match res {
            Ok(_) => Err(io::Error::new(io::ErrorKind::AlreadyExists, "Already exists")),
            Err(ref e) if e.kind() == io::ErrorKind::NotFound => Ok(()),
            e @ _ => e.map(|_| ()),
        }
    }
}
<|endoftext|>


<commit_before>use screen::*;
use object;
use piston_window::{self, PistonWindow, Transformed};
use gfx_device_gl;

pub struct Battle {
    player: object::Object,
    up: bool,
    down: bool,
    left: bool,
    right: bool,
}

fn load_sprite(window: &PistonWindow,
               assets_path: &::std::path::Path,
               name: &str)
               -> piston_window::Texture<gfx_device_gl::Resources> {
    // TODO: Create and use default sprite in case of failure during loading?
    let sprite = assets_path.join(name);
    piston_window::Texture::from_path(&mut *window.factory.borrow_mut(),
                                      &sprite,
                                      piston_window::Flip::None,
                                      &piston_window::TextureSettings::new())
        .unwrap()
}

impl Battle {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        Battle {
            player: object::Object::new(Some(load_sprite(&window, &context.assets_path, "skeleton.png"))),
            up: false,
            down: false,
            left: false,
            right: false,
        }
    }
}

impl Screen for Battle {
    fn on_input(&mut self, input: &piston_window::Input, _: &PistonWindow, _: &mut Context) -> InputResults {
        use piston_window::{Input, Button, Key};

        let result = Vec::new();

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Up) => {
                        self.up = true;
                    }
                    Button::Keyboard(Key::Down) => {
                        self.down = true;
                    }
                    Button::Keyboard(Key::Left) => {
                        self.left = true;
                    }
                    Button::Keyboard(Key::Right) => {
                        self.right = true;
                    }
                    _ => {}
                }
            }
            &Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Up) => {
                        self.up = false;
                    }
                    Button::Keyboard(Key::Down) => {
                        self.down = false;
                    }
                    Button::Keyboard(Key::Left) => {
                        self.left = false;
                    }
                    Button::Keyboard(Key::Right) => {
                        self.right = false;
                    }
                    _ => {}
                }
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            self.player.render(graphics, &center);
        });
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        if self.up {
            self.player.mov(0.0, -150.0 * args.dt);
        }
        if self.down {
            self.player.mov(0.0, 150.0 * args.dt);
        }
        if self.left {
            self.player.mov(-150.0 * args.dt, 0.0);
        }
        if self.right {
            self.player.mov(150.0 * args.dt, 0.0);
        }
    }
}
<commit_msg>TODO note<commit_after>use screen::*;
use object;
use piston_window::{self, PistonWindow, Transformed};
use gfx_device_gl;

pub struct Battle {
    player: object::Object,
    up: bool,
    down: bool,
    left: bool,
    right: bool,
}

fn load_sprite(window: &PistonWindow,
               assets_path: &::std::path::Path,
               name: &str)
               -> piston_window::Texture<gfx_device_gl::Resources> {
    // TODO: Create and use default sprite in case of failure during loading?
    let sprite = assets_path.join(name);
    piston_window::Texture::from_path(&mut *window.factory.borrow_mut(),
                                      &sprite,
                                      piston_window::Flip::None,
                                      &piston_window::TextureSettings::new())
        .unwrap()
}

impl Battle {
    pub fn new(window: &PistonWindow, context: &mut Context) -> Self {
        Battle {
            player: object::Object::new(Some(load_sprite(&window, &context.assets_path, "skeleton.png"))),
            up: false,
            down: false,
            left: false,
            right: false,
        }
    }
}

impl Screen for Battle {
    fn on_input(&mut self, input: &piston_window::Input, _: &PistonWindow, _: &mut Context) -> InputResults {
        use piston_window::{Input, Button, Key};

        let result = Vec::new();

        match input {
            &Input::Press(button) => {
                match button {
                    Button::Keyboard(Key::Up) => {
                        self.up = true;
                    }
                    Button::Keyboard(Key::Down) => {
                        self.down = true;
                    }
                    Button::Keyboard(Key::Left) => {
                        self.left = true;
                    }
                    Button::Keyboard(Key::Right) => {
                        self.right = true;
                    }
                    _ => {}
                }
            }
            &Input::Release(button) => {
                match button {
                    Button::Keyboard(Key::Up) => {
                        self.up = false;
                    }
                    Button::Keyboard(Key::Down) => {
                        self.down = false;
                    }
                    Button::Keyboard(Key::Left) => {
                        self.left = false;
                    }
                    Button::Keyboard(Key::Right) => {
                        self.right = false;
                    }
                    _ => {}
                }
            }
            _ => {}
        }

        // TODO: Handle esc.

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &PistonWindow) {
        window.draw_2d(|context, graphics| {
            piston_window::clear([0.0, 0.0, 0.0, 1.0], graphics);

            let center = context.transform.trans((args.width / 2) as f64, (args.height / 2) as f64);
            self.player.render(graphics, &center);
        });
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {
        if self.up {
            self.player.mov(0.0, -150.0 * args.dt);
        }
        if self.down {
            self.player.mov(0.0, 150.0 * args.dt);
        }
        if self.left {
            self.player.mov(-150.0 * args.dt, 0.0);
        }
        if self.right {
            self.player.mov(150.0 * args.dt, 0.0);
        }
    }
}
<|endoftext|>


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

use crate::prelude::*;
use core::fmt;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

impl Serialize for Uuid {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            serializer
                .serialize_str(&self.to_hyphenated().encode_lower(&mut [0; 36]))
        } else {
            serializer.serialize_bytes(self.as_bytes())
        }
    }
}

impl<'de> Deserialize<'de> for Uuid {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<Self, D::Error> {
        if deserializer.is_human_readable() {
            struct UuidStringVisitor;

            impl<'vi> de::Visitor<'vi> for UuidStringVisitor {
                type Value = Uuid;

                fn expecting(
                    &self,
                    formatter: &mut fmt::Formatter<'_>,
                ) -> fmt::Result {
                    write!(formatter, "a UUID string")
                }

                fn visit_str<E: de::Error>(
                    self,
                    value: &str,
                ) -> Result<Uuid, E> {
                    value.parse::<Uuid>().map_err(E::custom)
                }

                fn visit_bytes<E: de::Error>(
                    self,
                    value: &[u8],
                ) -> Result<Uuid, E> {
                    Uuid::from_slice(value).map_err(E::custom)
                }
            }

            deserializer.deserialize_str(UuidStringVisitor)
        } else {
            struct UuidBytesVisitor;

            impl<'vi> de::Visitor<'vi> for UuidBytesVisitor {
                type Value = Uuid;

                fn expecting(
                    &self,
                    formatter: &mut fmt::Formatter<'_>,
                ) -> fmt::Result {
                    write!(formatter, "bytes")
                }

                fn visit_bytes<E: de::Error>(
                    self,
                    value: &[u8],
                ) -> Result<Uuid, E> {
                    Uuid::from_slice(value).map_err(E::custom)
                }
            }

            deserializer.deserialize_bytes(UuidBytesVisitor)
        }
    }
}

#[cfg(test)]
mod serde_tests {
    use serde_test;

    use crate::prelude::*;

    #[test]
    fn test_serialize_readable() {
        use serde_test::Configure;

        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
        let u = Uuid::parse_str(uuid_str).unwrap();
        serde_test::assert_tokens(
            &u.readable(),
            &[serde_test::Token::Str(uuid_str)],
        );
    }

    #[test]
    fn test_serialize_compact() {
        use serde_test::Configure;

        let uuid_bytes = b"F9168C5E-CEB2-4F";
        let u = Uuid::from_slice(uuid_bytes).unwrap();
        serde_test::assert_tokens(
            &u.compact(),
            &[serde_test::Token::Bytes(uuid_bytes)],
        );
    }
}
<commit_msg>Improve deserialization error message<commit_after>// Copyright 2013-2014 The Rust Project Developers.
// Copyright 2018 The Uuid Project Developers.
//
// See the COPYRIGHT file at the top-level directory of this distribution.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use crate::prelude::*;
use core::fmt;
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};

impl Serialize for Uuid {
    fn serialize<S: Serializer>(
        &self,
        serializer: S,
    ) -> Result<S::Ok, S::Error> {
        if serializer.is_human_readable() {
            serializer
                .serialize_str(&self.to_hyphenated().encode_lower(&mut [0; 36]))
        } else {
            serializer.serialize_bytes(self.as_bytes())
        }
    }
}

impl<'de> Deserialize<'de> for Uuid {
    fn deserialize<D: Deserializer<'de>>(
        deserializer: D,
    ) -> Result<Self, D::Error> {
        fn de_error<E: de::Error>(e: crate::Error) -> E {
            E::custom(format_args!("UUID parsing failed: {}", e))
        }

        if deserializer.is_human_readable() {
            struct UuidStringVisitor;

            impl<'vi> de::Visitor<'vi> for UuidStringVisitor {
                type Value = Uuid;

                fn expecting(
                    &self,
                    formatter: &mut fmt::Formatter<'_>,
                ) -> fmt::Result {
                    write!(formatter, "a UUID string")
                }

                fn visit_str<E: de::Error>(
                    self,
                    value: &str,
                ) -> Result<Uuid, E> {
                    value.parse::<Uuid>().map_err(de_error)
                }

                fn visit_bytes<E: de::Error>(
                    self,
                    value: &[u8],
                ) -> Result<Uuid, E> {
                    Uuid::from_slice(value).map_err(de_error)
                }
            }

            deserializer.deserialize_str(UuidStringVisitor)
        } else {
            struct UuidBytesVisitor;

            impl<'vi> de::Visitor<'vi> for UuidBytesVisitor {
                type Value = Uuid;

                fn expecting(
                    &self,
                    formatter: &mut fmt::Formatter<'_>,
                ) -> fmt::Result {
                    write!(formatter, "bytes")
                }

                fn visit_bytes<E: de::Error>(
                    self,
                    value: &[u8],
                ) -> Result<Uuid, E> {
                    Uuid::from_slice(value).map_err(de_error)
                }
            }

            deserializer.deserialize_bytes(UuidBytesVisitor)
        }
    }
}

#[cfg(test)]
mod serde_tests {
    use serde_test::{Compact, Configure, Readable, Token};

    use crate::prelude::*;

    #[test]
    fn test_serialize_readable() {
        let uuid_str = "f9168c5e-ceb2-4faa-b6bf-329bf39fa1e4";
        let u = Uuid::parse_str(uuid_str).unwrap();
        serde_test::assert_tokens(&u.readable(), &[Token::Str(uuid_str)]);
    }

    #[test]
    fn test_serialize_compact() {
        let uuid_bytes = b"F9168C5E-CEB2-4F";
        let u = Uuid::from_slice(uuid_bytes).unwrap();
        serde_test::assert_tokens(&u.compact(), &[Token::Bytes(uuid_bytes)]);
    }

    #[test]
    fn test_de_failure() {
        serde_test::assert_de_tokens_error::<Readable<Uuid>>(
            &[Token::Str("hello_world")],
            "UUID parsing failed: invalid length: expected one of [36, 32], found 11",
        );

        serde_test::assert_de_tokens_error::<Compact<Uuid>>(
            &[Token::Bytes(b"hello_world")],
            "UUID parsing failed: invalid bytes length: expected 16, found 11",
        );
    }
}
<|endoftext|>


<commit_before>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! A `manticore` "server" and "client" for a PA-RoT.
//!
//! This module provides structures for serving responses to a host making
//! requests to a PA-RoT.

use crate::cert;
use crate::crypto::sha256;
use crate::crypto::sig;
use crate::hardware;
use crate::mem::Arena;
use crate::mem::ArenaExt as _;
use crate::net;
use crate::protocol;
use crate::protocol::capabilities;
use crate::protocol::device_id;
use crate::server::Error;

use crate::server::handler::prelude::*;

/// Options struct for initializing a [`PaRot`].
pub struct Options<'a, Identity, Reset, Sha, Ciphers, TrustChain> {
    /// A handle to the "hardware identity" of the device.
    pub identity: &'a Identity,
    /// A handle for looking up reset-related information for the current
    /// device.
    pub reset: &'a Reset,

    /// A handle to a SHA-256 engine.
    pub sha: &'a Sha,
    /// A handle to a signature verification engine,
    pub ciphers: &'a mut Ciphers,
    /// The trust chain to use for the challenge.
    pub trust_chain: &'a TrustChain,

    /// This device's silicon identifier.
    pub device_id: device_id::DeviceIdentifier,
    /// Integration-provided description of the device's networking
    /// capabilities.
    pub networking: capabilities::Networking,
    /// Integration-provided "acceptable timeout" lengths.
    pub timeouts: capabilities::Timeouts,
}

/// A PA-RoT, or "Platform Root of Trust", server.
///
/// This type implements the request -> response "business logic" of the
/// host <-> PA-RoT interaction. That is, it accepts input and output buffers,
/// and from those, parses incoming requests and processes them into responses.
pub struct PaRot<'a, Identity, Reset, Sha, Ciphers, TrustChain> {
    opts: Options<'a, Identity, Reset, Sha, Ciphers, TrustChain>,
    ok_count: u16,
    err_count: u16,
}

impl<'a, Identity, Reset, Sha, Ciphers, TrustChain>
    PaRot<'a, Identity, Reset, Sha, Ciphers, TrustChain>
where
    Identity: hardware::Identity,
    Reset: hardware::Reset,
    Sha: sha256::Builder,
    Ciphers: sig::Ciphers,
    TrustChain: cert::TrustChain,
{
    /// Create a new `PaRot` with the given `Options`.
    pub fn new(
        opts: Options<'a, Identity, Reset, Sha, Ciphers, TrustChain>,
    ) -> Self {
        Self {
            opts,
            ok_count: 0,
            err_count: 0,
        }
    }

    /// Process a single incoming request.
    ///
    /// The request message will be read from `req`, while the response
    /// message will be written to `resp`.
    #[cfg_attr(test, inline(never))]
    pub fn process_request<'req, A: Arena>(
        &mut self,
        host_port: &mut dyn net::HostPort<'req>,
        arena: &'req A,
    ) -> Result<(), Error> {
        let result = Handler::<&mut Self, A>::new()
            .handle::<protocol::FirmwareVersion, _>(|ctx| {
                use protocol::firmware_version::FirmwareVersionResponse;
                if ctx.req.index == 0 {
                    return Ok(FirmwareVersionResponse {
                        version: ctx.server.opts.identity.firmware_version(),
                    });
                }

                let version = ctx
                    .server
                    .opts
                    .identity
                    .vendor_firmware_version(ctx.req.index)
                    .ok_or(UNSPECIFIED)?;
                Ok(FirmwareVersionResponse { version })
            })
            .handle::<protocol::DeviceCapabilities, _>(|ctx| {
                use protocol::capabilities::*;
                let mut crypto = ctx.req.capabilities.crypto;

                ctx.server.opts.ciphers.negotiate(&mut crypto);
                crypto.has_aes = false;
                crypto.aes_strength = AesKeyStrength::empty();

                let capabilities = Capabilities {
                    networking: ctx.server.opts.networking,
                    security: Security::empty(),

                    has_pfm_support: false,
                    has_policy_support: false,
                    has_firmware_protection: false,

                    crypto,
                };

                Ok(protocol::capabilities::DeviceCapabilitiesResponse {
                    capabilities,
                    timeouts: ctx.server.opts.timeouts,
                })
            })
            .handle::<protocol::DeviceId, _>(|ctx| {
                Ok(protocol::device_id::DeviceIdResponse {
                    id: ctx.server.opts.device_id,
                })
            })
            .handle::<protocol::DeviceInfo, _>(|ctx| {
                Ok(protocol::device_info::DeviceInfoResponse {
                    info: ctx.server.opts.identity.unique_device_identity(),
                })
            })
            .handle::<protocol::GetDigests, _>(|ctx| {
                let digests_len = ctx
                    .server
                    .opts
                    .trust_chain
                    .chain_len(ctx.req.slot)
                    .ok_or(UNSPECIFIED)?
                    .get();
                let digests = ctx
                    .arena
                    .alloc_slice::<sha256::Digest>(digests_len)
                    .map_err(|_| UNSPECIFIED)?;
                for (i, digest) in digests.iter_mut().enumerate() {
                    let cert = ctx
                        .server
                        .opts
                        .trust_chain
                        .cert(ctx.req.slot, i)
                        .ok_or(UNSPECIFIED)?;
                    ctx.server
                        .opts
                        .sha
                        .hash_contiguous(cert.raw(), digest)
                        .map_err(|_| UNSPECIFIED)?;
                }
                Ok(protocol::get_digests::GetDigestsResponse { digests })
            })
            .handle::<protocol::ResetCounter, _>(|ctx| {
                use protocol::reset_counter::*;
                // NOTE: Currently, we only handle "local resets" for port 0,
                // the "self" port.
                if ctx.req.reset_type != ResetType::Local
                    || ctx.req.port_id != 0
                {
                    return Err(UNSPECIFIED);
                }

                Ok(ResetCounterResponse {
                    count: ctx.server.opts.reset.resets_since_power_on() as u16,
                })
            })
            .handle::<protocol::DeviceUptime, _>(|ctx| {
                use protocol::device_uptime::*;
                // NOTE: CUrrently, we only handle port 0, the "self" port.
                if ctx.req.port_id != 0 {
                    return Err(UNSPECIFIED);
                }
                Ok(DeviceUptimeResponse {
                    uptime: ctx.server.opts.reset.uptime(),
                })
            })
            .handle::<protocol::RequestCounter, _>(|ctx| {
                use protocol::request_counter::*;
                Ok(RequestCounterResponse {
                    ok_count: ctx.server.ok_count,
                    err_count: ctx.server.err_count,
                })
            })
            .run(self, host_port, arena);

        match result {
            Ok(_) => self.ok_count += 1,
            Err(_) => self.err_count += 1,
        }
        result
    }

    /// Start and process a outgoing request.
    ///
    /// The request message will be read from `req`, while the response
    /// message will be written to `resp`.
    #[cfg_attr(test, inline(never))]
    pub fn process_response<'req>(
        &mut self,
        _device_port: &mut dyn net::DevicePort,
        _arena: &'req impl Arena,
    ) -> Result<(), Error> {
        unimplemented!()
    }
}

/// Stopgap error code until we have richer errors for Manticore and Cerberus.
const UNSPECIFIED: protocol::Error = protocol::Error {
    code: protocol::ErrorCode::Unspecified,
    data: [0; 4],
};

#[cfg(test)]
mod test {
    use super::*;
    use core::time::Duration;

    use crate::crypto::ring;
    use crate::hardware::fake;
    use crate::hardware::Identity as _;
    use crate::io::Cursor;
    use crate::mem::BumpArena;
    use crate::net::DevicePort;
    use crate::protocol::capabilities::*;
    use crate::protocol::wire::FromWire;
    use crate::protocol::wire::ToWire;
    use crate::protocol::Header;

    const NETWORKING: Networking = Networking {
        max_message_size: 1024,
        max_packet_size: 256,
        mode: RotMode::Platform,
        roles: BusRole::HOST,
    };

    const TIMEOUTS: Timeouts = Timeouts {
        regular: Duration::from_millis(30),
        crypto: Duration::from_millis(200),
    };

    const DEVICE_ID: device_id::DeviceIdentifier =
        device_id::DeviceIdentifier {
            vendor_id: 1,
            device_id: 2,
            subsys_vendor_id: 3,
            subsys_id: 4,
        };

    fn simulate_request<'a, C: protocol::Command<'a>, A: Arena>(
        scratch_space: &'a mut [u8],
        port_out: &'a mut Option<net::InMemHost<'a>>,
        arena: &'a mut A,
        server: &mut PaRot<
            fake::Identity,
            fake::Reset,
            ring::sha256::Builder,
            ring::sig::Ciphers,
            cert::SimpleChain<0>,
        >,
        request: C::Req,
    ) -> Result<Result<C::Resp, protocol::Error>, Error> {
        use crate::protocol::Response;

        let len = scratch_space.len();
        let (req_scratch, port_scratch) = scratch_space.split_at_mut(len / 2);
        let mut cursor = Cursor::new(req_scratch);
        request
            .to_wire(&mut cursor)
            .expect("failed to write request");
        let request_bytes = cursor.take_consumed_bytes();

        let mut host_port = net::InMemHost::new(port_scratch);
        host_port.request(
            Header {
                is_request: true,
                command: <C::Req as protocol::Request<'a>>::TYPE,
            },
            request_bytes,
        );
        *port_out = Some(host_port);
        let host_port = port_out.as_mut().unwrap();

        server.process_request(host_port, arena)?;

        let (header, mut resp) = host_port.response().unwrap();
        assert!(!header.is_request);

        if header.command == protocol::Error::TYPE {
            let resp_val = FromWire::from_wire(&mut resp, arena)
                .expect("failed to read response");
            assert_eq!(resp.len(), 0);
            return Ok(Err(resp_val));
        }

        let resp_val = FromWire::from_wire(&mut resp, arena)
            .expect("failed to read response");
        assert_eq!(resp.len(), 0);
        Ok(Ok(resp_val))
    }

    fn simulate_response<'a, C: protocol::Command<'a>, A: Arena>(
        scratch_space: &'a mut [u8],
        port_out: &mut Option<net::InMemDevice<'a>>,
        arena: &'a mut A,
        request: C::Req,
    ) -> Result<C::Resp, Error> {
        let len = scratch_space.len();
        let (req_scratch, _port_scratch) = scratch_space.split_at_mut(len / 2);
        let mut cursor = Cursor::new(req_scratch);
        request
            .to_wire(&mut cursor)
            .expect("failed to write request");
        let request_bytes = cursor.take_consumed_bytes();

        let header = Header {
            is_request: true,
            command: <C::Req as protocol::Request<'a>>::TYPE,
        };

        *port_out = Some(net::InMemDevice::new());
        let device_port = port_out.as_mut().unwrap();
        device_port.send(0x10, header, request_bytes).unwrap();
        device_port.response(
            Header {
                is_request: false,
                command: <C::Req as protocol::Request<'a>>::TYPE,
            },
            &[1, 0, 2, 0, 3, 0, 4, 0],
        );
        device_port.wait_for_response(100)?;

        let response = device_port.receive_response()?;
        assert_eq!(response.header().unwrap(), header);

        let payload = response.payload().unwrap();
        // Kludge to work around DevicePort not supporting ReadZero yet.
        let mut out =
            arena.alloc_slice::<u8>(payload.remaining_data()).unwrap();
        payload.read_bytes(out).unwrap();
        let resp_val = FromWire::from_wire(&mut out, arena)
            .expect("failed to read response");
        Ok(resp_val)
    }

    #[test]
    fn sanity() {
        let identity = fake::Identity::new(
            b"test version",
            &[(1, b"vendor fw 1"), (3, b"vendor fw 3")],
            b"random bits",
        );
        let reset = fake::Reset::new(0, Duration::from_millis(1));
        let mut ciphers = ring::sig::Ciphers::new();
        let sha = ring::sha256::Builder::new();
        let trust_chain = cert::SimpleChain::parse(
            &[],
            cert::CertFormat::RiotX509,
            &mut ciphers,
        )
        .unwrap();
        let mut server = PaRot::new(Options {
            identity: &identity,
            reset: &reset,
            sha: &sha,
            ciphers: &mut ciphers,
            trust_chain: &trust_chain,
            device_id: DEVICE_ID,
            networking: NETWORKING,
            timeouts: TIMEOUTS,
        });

        let mut scratch = [0; 1024];
        let mut arena = [0; 64];
        let mut arena = BumpArena::new(&mut arena);

        let mut port = None;
        let req =
            protocol::firmware_version::FirmwareVersionRequest { index: 0 };
        let resp = simulate_request::<protocol::FirmwareVersion, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            &mut server,
            req,
        )
        .expect("got error from server")
        .expect("got error message from server");
        assert_eq!(resp.version, identity.firmware_version());

        arena.reset();

        let mut port = None;
        let req =
            protocol::firmware_version::FirmwareVersionRequest { index: 1 };
        let resp = simulate_request::<protocol::FirmwareVersion, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            &mut server,
            req,
        )
        .expect("got error from server")
        .expect("got error message from server");
        assert_eq!(Some(resp.version), identity.vendor_firmware_version(1));

        arena.reset();

        let mut port = None;
        let req =
            protocol::firmware_version::FirmwareVersionRequest { index: 2 };
        let resp = simulate_request::<protocol::FirmwareVersion, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            &mut server,
            req,
        )
        .expect("got error from server")
        .expect_err("got non-error message from server");
        assert_eq!(resp.code, protocol::ErrorCode::Unspecified);

        arena.reset();

        let mut port = None;
        let req = protocol::device_id::DeviceIdRequest;
        let resp = simulate_request::<protocol::DeviceId, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            &mut server,
            req,
        )
        .expect("got error from server")
        .expect("got error message from server");
        assert_eq!(resp.id, DEVICE_ID);

        arena.reset();

        let mut port = None;
        let req = protocol::device_id::DeviceIdRequest;
        let resp = simulate_response::<protocol::DeviceId, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            req,
        )
        .expect("got error from client");
        assert_eq!(resp.id, DEVICE_ID);
    }
}
<commit_msg>[server] Implement request processing for GET_CERTIFICATE<commit_after>// Copyright lowRISC contributors.
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

//! A `manticore` "server" and "client" for a PA-RoT.
//!
//! This module provides structures for serving responses to a host making
//! requests to a PA-RoT.

use crate::cert;
use crate::crypto::sha256;
use crate::crypto::sig;
use crate::hardware;
use crate::mem::Arena;
use crate::mem::ArenaExt as _;
use crate::net;
use crate::protocol;
use crate::protocol::capabilities;
use crate::protocol::device_id;
use crate::server::Error;

use crate::server::handler::prelude::*;

/// Options struct for initializing a [`PaRot`].
pub struct Options<'a, Identity, Reset, Sha, Ciphers, TrustChain> {
    /// A handle to the "hardware identity" of the device.
    pub identity: &'a Identity,
    /// A handle for looking up reset-related information for the current
    /// device.
    pub reset: &'a Reset,

    /// A handle to a SHA-256 engine.
    pub sha: &'a Sha,
    /// A handle to a signature verification engine,
    pub ciphers: &'a mut Ciphers,
    /// The trust chain to use for the challenge.
    pub trust_chain: &'a TrustChain,

    /// This device's silicon identifier.
    pub device_id: device_id::DeviceIdentifier,
    /// Integration-provided description of the device's networking
    /// capabilities.
    pub networking: capabilities::Networking,
    /// Integration-provided "acceptable timeout" lengths.
    pub timeouts: capabilities::Timeouts,
}

/// A PA-RoT, or "Platform Root of Trust", server.
///
/// This type implements the request -> response "business logic" of the
/// host <-> PA-RoT interaction. That is, it accepts input and output buffers,
/// and from those, parses incoming requests and processes them into responses.
pub struct PaRot<'a, Identity, Reset, Sha, Ciphers, TrustChain> {
    opts: Options<'a, Identity, Reset, Sha, Ciphers, TrustChain>,
    ok_count: u16,
    err_count: u16,
}

impl<'a, Identity, Reset, Sha, Ciphers, TrustChain>
    PaRot<'a, Identity, Reset, Sha, Ciphers, TrustChain>
where
    Identity: hardware::Identity,
    Reset: hardware::Reset,
    Sha: sha256::Builder,
    Ciphers: sig::Ciphers,
    TrustChain: cert::TrustChain,
{
    /// Create a new `PaRot` with the given `Options`.
    pub fn new(
        opts: Options<'a, Identity, Reset, Sha, Ciphers, TrustChain>,
    ) -> Self {
        Self {
            opts,
            ok_count: 0,
            err_count: 0,
        }
    }

    /// Process a single incoming request.
    ///
    /// The request message will be read from `req`, while the response
    /// message will be written to `resp`.
    #[cfg_attr(test, inline(never))]
    pub fn process_request<'req, A: Arena>(
        &mut self,
        host_port: &mut dyn net::HostPort<'req>,
        arena: &'req A,
    ) -> Result<(), Error> {
        let result = Handler::<&mut Self, A>::new()
            .handle::<protocol::FirmwareVersion, _>(|ctx| {
                use protocol::firmware_version::FirmwareVersionResponse;
                if ctx.req.index == 0 {
                    return Ok(FirmwareVersionResponse {
                        version: ctx.server.opts.identity.firmware_version(),
                    });
                }

                let version = ctx
                    .server
                    .opts
                    .identity
                    .vendor_firmware_version(ctx.req.index)
                    .ok_or(UNSPECIFIED)?;
                Ok(FirmwareVersionResponse { version })
            })
            .handle::<protocol::DeviceCapabilities, _>(|ctx| {
                use protocol::capabilities::*;
                let mut crypto = ctx.req.capabilities.crypto;

                ctx.server.opts.ciphers.negotiate(&mut crypto);
                crypto.has_aes = false;
                crypto.aes_strength = AesKeyStrength::empty();

                let capabilities = Capabilities {
                    networking: ctx.server.opts.networking,
                    security: Security::empty(),

                    has_pfm_support: false,
                    has_policy_support: false,
                    has_firmware_protection: false,

                    crypto,
                };

                Ok(protocol::capabilities::DeviceCapabilitiesResponse {
                    capabilities,
                    timeouts: ctx.server.opts.timeouts,
                })
            })
            .handle::<protocol::DeviceId, _>(|ctx| {
                Ok(protocol::device_id::DeviceIdResponse {
                    id: ctx.server.opts.device_id,
                })
            })
            .handle::<protocol::DeviceInfo, _>(|ctx| {
                Ok(protocol::device_info::DeviceInfoResponse {
                    info: ctx.server.opts.identity.unique_device_identity(),
                })
            })
            .handle::<protocol::GetDigests, _>(|ctx| {
                let digests_len = ctx
                    .server
                    .opts
                    .trust_chain
                    .chain_len(ctx.req.slot)
                    .ok_or(UNSPECIFIED)?
                    .get();
                let digests = ctx
                    .arena
                    .alloc_slice::<sha256::Digest>(digests_len)
                    .map_err(|_| UNSPECIFIED)?;
                for (i, digest) in digests.iter_mut().enumerate() {
                    let cert = ctx
                        .server
                        .opts
                        .trust_chain
                        .cert(ctx.req.slot, i)
                        .ok_or(UNSPECIFIED)?;
                    ctx.server
                        .opts
                        .sha
                        .hash_contiguous(cert.raw(), digest)
                        .map_err(|_| UNSPECIFIED)?;
                }
                Ok(protocol::get_digests::GetDigestsResponse { digests })
            })
            .handle::<protocol::GetCert, _>(|ctx| {
                let cert = ctx
                    .server
                    .opts
                    .trust_chain
                    .cert(ctx.req.slot, ctx.req.cert_number as usize)
                    .ok_or(UNSPECIFIED)?;

                let start = cert.raw().len().min(ctx.req.offset as usize);
                let end = cert.raw().len().min(ctx.req.len as usize);
                Ok(protocol::get_cert::GetCertResponse {
                    slot: ctx.req.slot,
                    cert_number: ctx.req.cert_number,
                    data: &cert.raw()[start..end],
                })
            })
            .handle::<protocol::ResetCounter, _>(|ctx| {
                use protocol::reset_counter::*;
                // NOTE: Currently, we only handle "local resets" for port 0,
                // the "self" port.
                if ctx.req.reset_type != ResetType::Local
                    || ctx.req.port_id != 0
                {
                    return Err(UNSPECIFIED);
                }

                Ok(ResetCounterResponse {
                    count: ctx.server.opts.reset.resets_since_power_on() as u16,
                })
            })
            .handle::<protocol::DeviceUptime, _>(|ctx| {
                use protocol::device_uptime::*;
                // NOTE: CUrrently, we only handle port 0, the "self" port.
                if ctx.req.port_id != 0 {
                    return Err(UNSPECIFIED);
                }
                Ok(DeviceUptimeResponse {
                    uptime: ctx.server.opts.reset.uptime(),
                })
            })
            .handle::<protocol::RequestCounter, _>(|ctx| {
                use protocol::request_counter::*;
                Ok(RequestCounterResponse {
                    ok_count: ctx.server.ok_count,
                    err_count: ctx.server.err_count,
                })
            })
            .run(self, host_port, arena);

        match result {
            Ok(_) => self.ok_count += 1,
            Err(_) => self.err_count += 1,
        }
        result
    }

    /// Start and process a outgoing request.
    ///
    /// The request message will be read from `req`, while the response
    /// message will be written to `resp`.
    #[cfg_attr(test, inline(never))]
    pub fn process_response<'req>(
        &mut self,
        _device_port: &mut dyn net::DevicePort,
        _arena: &'req impl Arena,
    ) -> Result<(), Error> {
        unimplemented!()
    }
}

/// Stopgap error code until we have richer errors for Manticore and Cerberus.
const UNSPECIFIED: protocol::Error = protocol::Error {
    code: protocol::ErrorCode::Unspecified,
    data: [0; 4],
};

#[cfg(test)]
mod test {
    use super::*;
    use core::time::Duration;

    use crate::crypto::ring;
    use crate::hardware::fake;
    use crate::hardware::Identity as _;
    use crate::io::Cursor;
    use crate::mem::BumpArena;
    use crate::net::DevicePort;
    use crate::protocol::capabilities::*;
    use crate::protocol::wire::FromWire;
    use crate::protocol::wire::ToWire;
    use crate::protocol::Header;

    const NETWORKING: Networking = Networking {
        max_message_size: 1024,
        max_packet_size: 256,
        mode: RotMode::Platform,
        roles: BusRole::HOST,
    };

    const TIMEOUTS: Timeouts = Timeouts {
        regular: Duration::from_millis(30),
        crypto: Duration::from_millis(200),
    };

    const DEVICE_ID: device_id::DeviceIdentifier =
        device_id::DeviceIdentifier {
            vendor_id: 1,
            device_id: 2,
            subsys_vendor_id: 3,
            subsys_id: 4,
        };

    fn simulate_request<'a, C: protocol::Command<'a>, A: Arena>(
        scratch_space: &'a mut [u8],
        port_out: &'a mut Option<net::InMemHost<'a>>,
        arena: &'a mut A,
        server: &mut PaRot<
            fake::Identity,
            fake::Reset,
            ring::sha256::Builder,
            ring::sig::Ciphers,
            cert::SimpleChain<0>,
        >,
        request: C::Req,
    ) -> Result<Result<C::Resp, protocol::Error>, Error> {
        use crate::protocol::Response;

        let len = scratch_space.len();
        let (req_scratch, port_scratch) = scratch_space.split_at_mut(len / 2);
        let mut cursor = Cursor::new(req_scratch);
        request
            .to_wire(&mut cursor)
            .expect("failed to write request");
        let request_bytes = cursor.take_consumed_bytes();

        let mut host_port = net::InMemHost::new(port_scratch);
        host_port.request(
            Header {
                is_request: true,
                command: <C::Req as protocol::Request<'a>>::TYPE,
            },
            request_bytes,
        );
        *port_out = Some(host_port);
        let host_port = port_out.as_mut().unwrap();

        server.process_request(host_port, arena)?;

        let (header, mut resp) = host_port.response().unwrap();
        assert!(!header.is_request);

        if header.command == protocol::Error::TYPE {
            let resp_val = FromWire::from_wire(&mut resp, arena)
                .expect("failed to read response");
            assert_eq!(resp.len(), 0);
            return Ok(Err(resp_val));
        }

        let resp_val = FromWire::from_wire(&mut resp, arena)
            .expect("failed to read response");
        assert_eq!(resp.len(), 0);
        Ok(Ok(resp_val))
    }

    fn simulate_response<'a, C: protocol::Command<'a>, A: Arena>(
        scratch_space: &'a mut [u8],
        port_out: &mut Option<net::InMemDevice<'a>>,
        arena: &'a mut A,
        request: C::Req,
    ) -> Result<C::Resp, Error> {
        let len = scratch_space.len();
        let (req_scratch, _port_scratch) = scratch_space.split_at_mut(len / 2);
        let mut cursor = Cursor::new(req_scratch);
        request
            .to_wire(&mut cursor)
            .expect("failed to write request");
        let request_bytes = cursor.take_consumed_bytes();

        let header = Header {
            is_request: true,
            command: <C::Req as protocol::Request<'a>>::TYPE,
        };

        *port_out = Some(net::InMemDevice::new());
        let device_port = port_out.as_mut().unwrap();
        device_port.send(0x10, header, request_bytes).unwrap();
        device_port.response(
            Header {
                is_request: false,
                command: <C::Req as protocol::Request<'a>>::TYPE,
            },
            &[1, 0, 2, 0, 3, 0, 4, 0],
        );
        device_port.wait_for_response(100)?;

        let response = device_port.receive_response()?;
        assert_eq!(response.header().unwrap(), header);

        let payload = response.payload().unwrap();
        // Kludge to work around DevicePort not supporting ReadZero yet.
        let mut out =
            arena.alloc_slice::<u8>(payload.remaining_data()).unwrap();
        payload.read_bytes(out).unwrap();
        let resp_val = FromWire::from_wire(&mut out, arena)
            .expect("failed to read response");
        Ok(resp_val)
    }

    #[test]
    fn sanity() {
        let identity = fake::Identity::new(
            b"test version",
            &[(1, b"vendor fw 1"), (3, b"vendor fw 3")],
            b"random bits",
        );
        let reset = fake::Reset::new(0, Duration::from_millis(1));
        let mut ciphers = ring::sig::Ciphers::new();
        let sha = ring::sha256::Builder::new();
        let trust_chain = cert::SimpleChain::parse(
            &[],
            cert::CertFormat::RiotX509,
            &mut ciphers,
        )
        .unwrap();
        let mut server = PaRot::new(Options {
            identity: &identity,
            reset: &reset,
            sha: &sha,
            ciphers: &mut ciphers,
            trust_chain: &trust_chain,
            device_id: DEVICE_ID,
            networking: NETWORKING,
            timeouts: TIMEOUTS,
        });

        let mut scratch = [0; 1024];
        let mut arena = [0; 64];
        let mut arena = BumpArena::new(&mut arena);

        let mut port = None;
        let req =
            protocol::firmware_version::FirmwareVersionRequest { index: 0 };
        let resp = simulate_request::<protocol::FirmwareVersion, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            &mut server,
            req,
        )
        .expect("got error from server")
        .expect("got error message from server");
        assert_eq!(resp.version, identity.firmware_version());

        arena.reset();

        let mut port = None;
        let req =
            protocol::firmware_version::FirmwareVersionRequest { index: 1 };
        let resp = simulate_request::<protocol::FirmwareVersion, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            &mut server,
            req,
        )
        .expect("got error from server")
        .expect("got error message from server");
        assert_eq!(Some(resp.version), identity.vendor_firmware_version(1));

        arena.reset();

        let mut port = None;
        let req =
            protocol::firmware_version::FirmwareVersionRequest { index: 2 };
        let resp = simulate_request::<protocol::FirmwareVersion, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            &mut server,
            req,
        )
        .expect("got error from server")
        .expect_err("got non-error message from server");
        assert_eq!(resp.code, protocol::ErrorCode::Unspecified);

        arena.reset();

        let mut port = None;
        let req = protocol::device_id::DeviceIdRequest;
        let resp = simulate_request::<protocol::DeviceId, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            &mut server,
            req,
        )
        .expect("got error from server")
        .expect("got error message from server");
        assert_eq!(resp.id, DEVICE_ID);

        arena.reset();

        let mut port = None;
        let req = protocol::device_id::DeviceIdRequest;
        let resp = simulate_response::<protocol::DeviceId, _>(
            &mut scratch,
            &mut port,
            &mut arena,
            req,
        )
        .expect("got error from client");
        assert_eq!(resp.id, DEVICE_ID);
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use azure::azure_hl::Color;
use constellation_msg::{Key, KeyModifiers, KeyState, PipelineId};
use euclid::{Matrix4, Point2D, Rect};
use ipc_channel::ipc::IpcSender;
use std::fmt::{self, Debug, Formatter};

/// A newtype struct for denoting the age of messages; prevents race conditions.
#[derive(PartialEq, Eq, Debug, Copy, Clone, PartialOrd, Ord, Deserialize, Serialize)]
pub struct Epoch(pub u32);

impl Epoch {
    pub fn next(&mut self) {
        let Epoch(ref mut u) = *self;
        *u += 1;
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub struct FrameTreeId(pub u32);

impl FrameTreeId {
    pub fn next(&mut self) {
        let FrameTreeId(ref mut u) = *self;
        *u += 1;
    }
}

#[derive(Clone, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf)]
pub enum LayerType {
    /// A layer for the fragment body itself.
    FragmentBody,
    /// An extra layer created for a DOM fragments with overflow:scroll.
    OverflowScroll,
    /// A layer created to contain ::before pseudo-element content.
    BeforePseudoContent,
    /// A layer created to contain ::after pseudo-element content.
    AfterPseudoContent,
}

#[derive(Clone, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf)]
pub struct LayerId(
    /// The type of the layer. This serves to differentiate layers that share fragments.
    LayerType,
    /// The identifier for this layer's fragment, derived from the fragment memory address.
    usize,
    /// An index for identifying companion layers, synthesized to ensure that
    /// content on top of this layer's fragment has the proper rendering order.
    usize
);

impl Debug for LayerId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let LayerId(layer_type, id, companion) = *self;
        let type_string = match layer_type {
            LayerType::FragmentBody => "-FragmentBody",
            LayerType::OverflowScroll => "-OverflowScroll",
            LayerType::BeforePseudoContent => "-BeforePseudoContent",
            LayerType::AfterPseudoContent => "-AfterPseudoContent",
        };

        write!(f, "{}{}-{}", id, type_string, companion)
    }
}

impl LayerId {
    /// FIXME(#2011, pcwalton): This is unfortunate. Maybe remove this in the future.
    pub fn null() -> LayerId {
        LayerId(LayerType::FragmentBody, 0, 0)
    }

    pub fn new_of_type(layer_type: LayerType, fragment_id: usize) -> LayerId {
        LayerId(layer_type, fragment_id, 0)
    }

    pub fn companion_layer_id(&self) -> LayerId {
        let LayerId(layer_type, id, companion) = *self;
        LayerId(layer_type, id, companion + 1)
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LayerKind {
    NoTransform,
    HasTransform,
}

/// The scrolling policy of a layer.
#[derive(Clone, PartialEq, Eq, Copy, Deserialize, Serialize, Debug, HeapSizeOf)]
pub enum ScrollPolicy {
    /// These layers scroll when the parent receives a scrolling message.
    Scrollable,
    /// These layers do not scroll when the parent receives a scrolling message.
    FixedPosition,
}

/// All layer-specific information that the painting task sends to the compositor other than the
/// buffer contents of the layer itself.
#[derive(Copy, Clone)]
pub struct LayerProperties {
    /// An opaque ID. This is usually the address of the flow and index of the box within it.
    pub id: LayerId,
    /// The id of the parent layer.
    pub parent_id: Option<LayerId>,
    /// The position and size of the layer in pixels.
    pub rect: Rect<f32>,
    /// The background color of the layer.
    pub background_color: Color,
    /// The scrolling policy of this layer.
    pub scroll_policy: ScrollPolicy,
    /// The transform for this layer
    pub transform: Matrix4,
    /// The perspective transform for this layer
    pub perspective: Matrix4,
    /// The subpage that this layer represents. If this is `Some`, this layer represents an
    /// iframe.
    pub subpage_pipeline_id: Option<PipelineId>,
    /// Whether this layer establishes a new 3d rendering context.
    pub establishes_3d_context: bool,
    /// Whether this layer scrolls its overflow area.
    pub scrolls_overflow_area: bool,
}
<commit_msg>Remove some unused imports.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use azure::azure_hl::Color;
use constellation_msg::PipelineId;
use euclid::{Matrix4, Rect};
use std::fmt::{self, Debug, Formatter};

/// A newtype struct for denoting the age of messages; prevents race conditions.
#[derive(PartialEq, Eq, Debug, Copy, Clone, PartialOrd, Ord, Deserialize, Serialize)]
pub struct Epoch(pub u32);

impl Epoch {
    pub fn next(&mut self) {
        let Epoch(ref mut u) = *self;
        *u += 1;
    }
}

#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub struct FrameTreeId(pub u32);

impl FrameTreeId {
    pub fn next(&mut self) {
        let FrameTreeId(ref mut u) = *self;
        *u += 1;
    }
}

#[derive(Clone, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf)]
pub enum LayerType {
    /// A layer for the fragment body itself.
    FragmentBody,
    /// An extra layer created for a DOM fragments with overflow:scroll.
    OverflowScroll,
    /// A layer created to contain ::before pseudo-element content.
    BeforePseudoContent,
    /// A layer created to contain ::after pseudo-element content.
    AfterPseudoContent,
}

#[derive(Clone, PartialEq, Eq, Copy, Hash, Deserialize, Serialize, HeapSizeOf)]
pub struct LayerId(
    /// The type of the layer. This serves to differentiate layers that share fragments.
    LayerType,
    /// The identifier for this layer's fragment, derived from the fragment memory address.
    usize,
    /// An index for identifying companion layers, synthesized to ensure that
    /// content on top of this layer's fragment has the proper rendering order.
    usize
);

impl Debug for LayerId {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        let LayerId(layer_type, id, companion) = *self;
        let type_string = match layer_type {
            LayerType::FragmentBody => "-FragmentBody",
            LayerType::OverflowScroll => "-OverflowScroll",
            LayerType::BeforePseudoContent => "-BeforePseudoContent",
            LayerType::AfterPseudoContent => "-AfterPseudoContent",
        };

        write!(f, "{}{}-{}", id, type_string, companion)
    }
}

impl LayerId {
    /// FIXME(#2011, pcwalton): This is unfortunate. Maybe remove this in the future.
    pub fn null() -> LayerId {
        LayerId(LayerType::FragmentBody, 0, 0)
    }

    pub fn new_of_type(layer_type: LayerType, fragment_id: usize) -> LayerId {
        LayerId(layer_type, fragment_id, 0)
    }

    pub fn companion_layer_id(&self) -> LayerId {
        let LayerId(layer_type, id, companion) = *self;
        LayerId(layer_type, id, companion + 1)
    }
}

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LayerKind {
    NoTransform,
    HasTransform,
}

/// The scrolling policy of a layer.
#[derive(Clone, PartialEq, Eq, Copy, Deserialize, Serialize, Debug, HeapSizeOf)]
pub enum ScrollPolicy {
    /// These layers scroll when the parent receives a scrolling message.
    Scrollable,
    /// These layers do not scroll when the parent receives a scrolling message.
    FixedPosition,
}

/// All layer-specific information that the painting task sends to the compositor other than the
/// buffer contents of the layer itself.
#[derive(Copy, Clone)]
pub struct LayerProperties {
    /// An opaque ID. This is usually the address of the flow and index of the box within it.
    pub id: LayerId,
    /// The id of the parent layer.
    pub parent_id: Option<LayerId>,
    /// The position and size of the layer in pixels.
    pub rect: Rect<f32>,
    /// The background color of the layer.
    pub background_color: Color,
    /// The scrolling policy of this layer.
    pub scroll_policy: ScrollPolicy,
    /// The transform for this layer
    pub transform: Matrix4,
    /// The perspective transform for this layer
    pub perspective: Matrix4,
    /// The subpage that this layer represents. If this is `Some`, this layer represents an
    /// iframe.
    pub subpage_pipeline_id: Option<PipelineId>,
    /// Whether this layer establishes a new 3d rendering context.
    pub establishes_3d_context: bool,
    /// Whether this layer scrolls its overflow area.
    pub scrolls_overflow_area: bool,
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::XRFrameBinding;
use crate::dom::bindings::codegen::Bindings::XRFrameBinding::XRFrameMethods;
use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrsession::XRSession;
use crate::dom::xrview::XRView;
use crate::dom::xrviewerpose::XRViewerPose;
use dom_struct::dom_struct;
use webvr_traits::WebVRFrameData;

#[dom_struct]
pub struct XRFrame {
    reflector_: Reflector,
    session: Dom<XRSession>,
    #[ignore_malloc_size_of = "defined in rust-webvr"]
    data: WebVRFrameData,
}

impl XRFrame {
    fn new_inherited(session: &XRSession, data: WebVRFrameData) -> XRFrame {
        XRFrame {
            reflector_: Reflector::new(),
            session: Dom::from_ref(session),
            data,
        }
    }

    pub fn new(
        global: &GlobalScope,
        session: &XRSession,
        data: WebVRFrameData,
    ) -> DomRoot<XRFrame> {
        reflect_dom_object(
            Box::new(XRFrame::new_inherited(session, data)),
            global,
            XRFrameBinding::Wrap,
        )
    }
}

impl XRFrameMethods for XRFrame {
    /// https://immersive-web.github.io/webxr/#dom-xrframe-session
    fn Session(&self) -> DomRoot<XRSession> {
        DomRoot::from_ref(&self.session)
    }

    /// https://immersive-web.github.io/webxr/#dom-xrframe-getviewerpose
    fn GetViewerPose(&self, reference: Option<&XRReferenceSpace>) -> Option<DomRoot<XRViewerPose>> {
        // We assume the reference space is eye level for now
        // since it's the only one 3DOF devices support
        if reference.is_some() {
            // it's not possible to obtain a reference
            // space at all yet
            return None;
        }
        let left = XRView::new(&self.global(), &self.session, XREye::Left, &self.data);
        let right = XRView::new(&self.global(), &self.session, XREye::Right, &self.data);
        Some(XRViewerPose::new(&self.global(), &left, &right))
    }
}
<commit_msg>Cleanup XRFrame<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::dom::bindings::codegen::Bindings::XRFrameBinding;
use crate::dom::bindings::codegen::Bindings::XRFrameBinding::XRFrameMethods;
use crate::dom::bindings::codegen::Bindings::XRViewBinding::XREye;
use crate::dom::bindings::reflector::{reflect_dom_object, DomObject, Reflector};
use crate::dom::bindings::root::{Dom, DomRoot};
use crate::dom::globalscope::GlobalScope;
use crate::dom::xrreferencespace::XRReferenceSpace;
use crate::dom::xrsession::XRSession;
use crate::dom::xrview::XRView;
use crate::dom::xrviewerpose::XRViewerPose;
use dom_struct::dom_struct;
use webvr_traits::WebVRFrameData;

#[dom_struct]
pub struct XRFrame {
    reflector_: Reflector,
    session: Dom<XRSession>,
    #[ignore_malloc_size_of = "defined in rust-webvr"]
    data: WebVRFrameData,
}

impl XRFrame {
    fn new_inherited(session: &XRSession, data: WebVRFrameData) -> XRFrame {
        XRFrame {
            reflector_: Reflector::new(),
            session: Dom::from_ref(session),
            data,
        }
    }

    pub fn new(
        global: &GlobalScope,
        session: &XRSession,
        data: WebVRFrameData,
    ) -> DomRoot<XRFrame> {
        reflect_dom_object(
            Box::new(XRFrame::new_inherited(session, data)),
            global,
            XRFrameBinding::Wrap,
        )
    }
}

impl XRFrameMethods for XRFrame {
    /// https://immersive-web.github.io/webxr/#dom-xrframe-session
    fn Session(&self) -> DomRoot<XRSession> {
        DomRoot::from_ref(&self.session)
    }

    /// https://immersive-web.github.io/webxr/#dom-xrframe-getviewerpose
    fn GetViewerPose(&self, reference: Option<&XRReferenceSpace>) -> Option<DomRoot<XRViewerPose>> {
        // We assume the reference space is eye level for now
        // since it's the only one 3DOF devices support
        if reference.is_some() {
            // it's not possible to obtain a reference
            // space at all yet
            None
        } else {
            let left = XRView::new(&self.global(), &self.session, XREye::Left, &self.data);
            let right = XRView::new(&self.global(), &self.session, XREye::Right, &self.data);
            Some(XRViewerPose::new(&self.global(), &left, &right))
        }
    }
}
<|endoftext|>


<commit_before>//! Removes markdown from strings.

use pulldown_cmark::{Event, Parser};

/// Removes all markdown, keeping the text and code blocks
///
/// Currently limited in styling, i.e. no ascii tables or lists
pub fn remove_markdown(markdown: &str) -> String {
    let mut out = String::new();
    let parser = Parser::new(markdown);

    for event in parser {
        match event {
            Event::Text(text) | Event::Code(text) => out.push_str(&text),
            Event::SoftBreak | Event::HardBreak | Event::Rule => out.push('\n'),
            _ => {}
        }
    }

    out
}
<commit_msg>add break after codeblocks<commit_after>//! Removes markdown from strings.

use pulldown_cmark::{Event, Parser, Tag};

/// Removes all markdown, keeping the text and code blocks
///
/// Currently limited in styling, i.e. no ascii tables or lists
pub fn remove_markdown(markdown: &str) -> String {
    let mut out = String::new();
    let parser = Parser::new(markdown);

    for event in parser {
        match event {
            Event::Text(text) | Event::Code(text) => out.push_str(&text),
            Event::SoftBreak | Event::HardBreak | Event::Rule | Event::End(Tag::CodeBlock(_)) => {
                out.push('\n')
            }
            _ => {}
        }
    }

    out
}
<|endoftext|>


<commit_before>use std::path::Path;

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::rect::Rect;
use sdl2::render::{BlendMode, Renderer, Texture, TextureQuery};
use sdl2::surface::Surface;
use sdl2::ttf::{Sdl2TtfContext, STYLE_BOLD};

use position::Position;
use text::Text;

const CONSOLE_WIDTH: u32 = 640;
const CONSOLE_HEIGHT: u32 = 720;

const FONT_FILE: &'static str = "../assets/FantasqueSansMono-Bold.ttf";
const FONT_COLOR: Color = Color::RGBA(45, 200, 45, 255);
const FONT_SIZE: u16 = 18;

pub struct Console<'a> {
    pub visible: bool,

    leader: Text,
    input_buffer: String,
    cursor_position: usize,
    buffer: Vec<String>,
    backbuffer_y: i32,
    texture: Texture,
    backbuffer_texture: Texture,
    ttf_context: &'a Sdl2TtfContext,
}

impl<'a> Console<'a> {
    /// Creates a new empty Console
    pub fn new(ttf_context: &'a Sdl2TtfContext, mut renderer: &mut Renderer) -> Console<'a> {
        let mut texture =
            renderer.create_texture_streaming(PixelFormatEnum::RGBA8888, CONSOLE_WIDTH, CONSOLE_HEIGHT)
                .unwrap();
        texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
                for y in 0..CONSOLE_HEIGHT {
                    for x in 0..CONSOLE_WIDTH {
                        let x = x as usize;
                        let y = y as usize;
                        let offset = y * pitch + x * 4;
                        buffer[offset + 0] = 182;
                        buffer[offset + 1] = 0;
                        buffer[offset + 2] = 0;
                        buffer[offset + 3] = 0;
                    }
                }
            })
            .unwrap();

        let mut backbuffer_texture =
            renderer.create_texture_streaming(PixelFormatEnum::RGBA8888, CONSOLE_WIDTH, CONSOLE_HEIGHT)
                .unwrap();
        backbuffer_texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
                for y in 0..CONSOLE_HEIGHT {
                    for x in 0..CONSOLE_WIDTH {
                        let x = x as usize;
                        let y = y as usize;
                        let offset = y * pitch + x * 4;
                        buffer[offset + 0] = 182;
                        buffer[offset + 1] = 0;
                        buffer[offset + 2] = 0;
                        buffer[offset + 3] = 0;
                    }
                }
            })
            .unwrap();

        Console {
            visible: false,
            leader: Text::new(&ttf_context,
                              &mut renderer,
                              "hakka>",
                              Position::XY(0, CONSOLE_HEIGHT as i32 - FONT_SIZE as i32),
                              FONT_SIZE,
                              FONT_COLOR,
                              FONT_FILE),
            input_buffer: "".into(),
            cursor_position: 0,
            buffer: Vec::new(),
            backbuffer_y: 0,
            texture: texture,
            backbuffer_texture: backbuffer_texture,
            ttf_context: ttf_context,
        }
    }

    pub fn process(&mut self, event: &Event) {
        match event {
            &Event::TextInput { ref text, .. } => {
                if self.visible {
                    if text == "`" {
                        return;
                    }
                    self.add_text(text);
                }
            }
            &Event::MouseWheel { y, .. } => {
                if self.visible {
                    if self.buffer.len() * FONT_SIZE as usize >
                       (CONSOLE_HEIGHT - (FONT_SIZE as u32 * 2)) as usize {
                        self.backbuffer_y += y * 2;
                        if self.backbuffer_y < 0 {
                            self.backbuffer_y = 0;
                        }
                    }
                }
            }
            &Event::KeyUp { keycode: Option::Some(Keycode::Backquote), .. } => {
                self.toggle();
            }
            &Event::KeyUp { keycode: Option::Some(Keycode::Left), .. } => {
                if self.visible {
                    self.cursor_left();
                }
            }
            &Event::KeyUp { keycode: Option::Some(Keycode::Right), .. } => {
                if self.visible {
                    self.cursor_right();
                }
            }
            &Event::KeyUp { keycode: Option::Some(Keycode::Return), .. } => {
                if self.visible {
                    self.commit();
                }
            }
            &Event::KeyDown { keycode: Option::Some(Keycode::Backspace), .. } => {
                if self.visible {
                    self.backspace();
                }
            }
            _ => (),
        }
    }

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

    /// Toggles the visibility of the Console
    pub fn toggle(&mut self) {
        self.visible = !self.visible;
    }

    pub fn add_text(&mut self, input: &str) {
        self.input_buffer.insert(self.cursor_position, input.chars().next().unwrap());
        self.cursor_position += 1;
    }

    pub fn commit(&mut self) {
        self.buffer.push(format!("hakka> {}", self.input_buffer.clone()));
        self.input_buffer.clear();
        self.cursor_position = 0;
    }

    pub fn cursor_left(&mut self) {
        if self.cursor_position > 0 {
            self.cursor_position -= 1;
        }
    }

    pub fn cursor_right(&mut self) {
        if self.cursor_position < self.input_buffer.len() {
            self.cursor_position += 1;
        }
    }

    pub fn backspace(&mut self) {
        if self.visible {
            if self.cursor_position > 0 {
                self.input_buffer.remove(self.cursor_position - 1);
                self.cursor_position -= 1;
            }
        }
    }

    /// Renders the Console
    pub fn render(&mut self, mut renderer: &mut Renderer) {
        if self.visible {

            renderer.set_blend_mode(BlendMode::Blend);
            self.texture.set_blend_mode(BlendMode::Blend);
            renderer.copy(&self.texture,
                      None,
                      Some(Rect::new(0, 0, CONSOLE_WIDTH, CONSOLE_HEIGHT)))
                .unwrap();
            self.render_leader(&mut renderer);
            self.generate_backbuffer_texture(&mut renderer);
            // self.render_buffer(&mut renderer);

            // Insert the cursor in its proper position
            let mut output_text = self.input_buffer.clone();
            if self.cursor_position < output_text.len() {
                output_text.insert(self.cursor_position, '|');
            } else {
                output_text.push_str("|");
            }

            // If no input.. only draw the cursor
            if self.input_buffer.len() == 0 {
                output_text = "|".into();
            }

            let text = Text::new(&self.ttf_context,
                                 &mut renderer,
                                 &output_text[..],
                                 Position::XY(60, CONSOLE_HEIGHT as i32 - FONT_SIZE as i32),
                                 FONT_SIZE,
                                 FONT_COLOR,
                                 FONT_FILE);
            text.render(&mut renderer);
        }
    }

    fn render_leader(&self, mut renderer: &mut Renderer) {
        self.leader.render(&mut renderer);
    }

    fn generate_backbuffer_texture(&mut self, mut renderer: &mut Renderer) {
        let mut font = self.ttf_context.load_font(Path::new(FONT_FILE), FONT_SIZE).unwrap();
        font.set_style(STYLE_BOLD);
        let mut main_surface = Surface::new(CONSOLE_WIDTH,
                                            (CONSOLE_HEIGHT - (FONT_SIZE as u32)),
                                            PixelFormatEnum::RGBA8888)
            .unwrap();
        let mut counter = 2;
        for line in self.buffer.iter().rev().take(100) {
            let mut y_pos = CONSOLE_HEIGHT as i32 - (FONT_SIZE as i32 * counter) +
                            self.backbuffer_y;
            counter += 1;

            if line.trim().len() == 0 {
                continue;
            }

            let surface = font.render(&line)
                .blended(FONT_COLOR)
                .unwrap();
            surface.blit(None,
                      &mut main_surface,
                      Some(Rect::new(0, y_pos, CONSOLE_HEIGHT, FONT_SIZE as u32)))
                .unwrap();
        }
        let texture = renderer.create_texture_from_surface(&main_surface)
            .unwrap();

        let TextureQuery { width, height, .. } = texture.query();

        renderer.copy(&texture, None, Some(Rect::new(0, 0, width, height)));
    }
}<commit_msg>Add Console.print method<commit_after>use std::path::Path;

use sdl2::event::Event;
use sdl2::keyboard::Keycode;
use sdl2::pixels::{Color, PixelFormatEnum};
use sdl2::rect::Rect;
use sdl2::render::{BlendMode, Renderer, Texture, TextureQuery};
use sdl2::surface::Surface;
use sdl2::ttf::{Sdl2TtfContext, STYLE_BOLD};

use position::Position;
use text::Text;

const CONSOLE_WIDTH: u32 = 640;
const CONSOLE_HEIGHT: u32 = 720;

const FONT_FILE: &'static str = "../assets/FantasqueSansMono-Bold.ttf";
const FONT_COLOR: Color = Color::RGBA(45, 200, 45, 255);
const FONT_SIZE: u16 = 18;

pub struct Console<'a> {
    pub visible: bool,

    leader: Text,
    input_buffer: String,
    cursor_position: usize,
    buffer: Vec<String>,
    backbuffer_y: i32,
    texture: Texture,
    backbuffer_texture: Texture,
    ttf_context: &'a Sdl2TtfContext,
}

impl<'a> Console<'a> {
    /// Creates a new empty Console
    pub fn new(ttf_context: &'a Sdl2TtfContext, mut renderer: &mut Renderer) -> Console<'a> {
        let mut texture =
            renderer.create_texture_streaming(PixelFormatEnum::RGBA8888, CONSOLE_WIDTH, CONSOLE_HEIGHT)
                .unwrap();
        texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
                for y in 0..CONSOLE_HEIGHT {
                    for x in 0..CONSOLE_WIDTH {
                        let x = x as usize;
                        let y = y as usize;
                        let offset = y * pitch + x * 4;
                        buffer[offset + 0] = 182;
                        buffer[offset + 1] = 0;
                        buffer[offset + 2] = 0;
                        buffer[offset + 3] = 0;
                    }
                }
            })
            .unwrap();

        let mut backbuffer_texture =
            renderer.create_texture_streaming(PixelFormatEnum::RGBA8888, CONSOLE_WIDTH, CONSOLE_HEIGHT)
                .unwrap();
        backbuffer_texture.with_lock(None, |buffer: &mut [u8], pitch: usize| {
                for y in 0..CONSOLE_HEIGHT {
                    for x in 0..CONSOLE_WIDTH {
                        let x = x as usize;
                        let y = y as usize;
                        let offset = y * pitch + x * 4;
                        buffer[offset + 0] = 182;
                        buffer[offset + 1] = 0;
                        buffer[offset + 2] = 0;
                        buffer[offset + 3] = 0;
                    }
                }
            })
            .unwrap();

        Console {
            visible: false,
            leader: Text::new(&ttf_context,
                              &mut renderer,
                              "hakka>",
                              Position::XY(0, CONSOLE_HEIGHT as i32 - FONT_SIZE as i32),
                              FONT_SIZE,
                              FONT_COLOR,
                              FONT_FILE),
            input_buffer: "".into(),
            cursor_position: 0,
            buffer: Vec::new(),
            backbuffer_y: 0,
            texture: texture,
            backbuffer_texture: backbuffer_texture,
            ttf_context: ttf_context,
        }
    }

    pub fn process(&mut self, event: &Event) {
        match event {
            &Event::TextInput { ref text, .. } => {
                if self.visible {
                    if text == "`" {
                        return;
                    }
                    self.add_text(text);
                }
            }
            &Event::MouseWheel { y, .. } => {
                if self.visible {
                    if self.buffer.len() * FONT_SIZE as usize >
                       (CONSOLE_HEIGHT - (FONT_SIZE as u32 * 2)) as usize {
                        self.backbuffer_y += y * 2;
                        if self.backbuffer_y < 0 {
                            self.backbuffer_y = 0;
                        }
                    }
                }
            }
            &Event::KeyUp { keycode: Option::Some(Keycode::Backquote), .. } => {
                self.toggle();
            }
            &Event::KeyUp { keycode: Option::Some(Keycode::Left), .. } => {
                if self.visible {
                    self.cursor_left();
                }
            }
            &Event::KeyUp { keycode: Option::Some(Keycode::Right), .. } => {
                if self.visible {
                    self.cursor_right();
                }
            }
            &Event::KeyUp { keycode: Option::Some(Keycode::Return), .. } => {
                if self.visible {
                    self.commit();
                }
            }
            &Event::KeyDown { keycode: Option::Some(Keycode::Backspace), .. } => {
                if self.visible {
                    self.backspace();
                }
            }
            _ => (),
        }
    }

    pub fn print<S>(&mut self, text: S)
        where S: Into<String>
    {
        for line in text.into().lines() {
            self.println(line);
        }
    }

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

    /// Toggles the visibility of the Console
    pub fn toggle(&mut self) {
        self.visible = !self.visible;
    }

    pub fn add_text(&mut self, input: &str) {
        self.input_buffer.insert(self.cursor_position, input.chars().next().unwrap());
        self.cursor_position += 1;
    }

    pub fn commit(&mut self) {
        self.buffer.push(format!("hakka> {}", self.input_buffer.clone()));
        self.input_buffer.clear();
        self.cursor_position = 0;
    }

    pub fn cursor_left(&mut self) {
        if self.cursor_position > 0 {
            self.cursor_position -= 1;
        }
    }

    pub fn cursor_right(&mut self) {
        if self.cursor_position < self.input_buffer.len() {
            self.cursor_position += 1;
        }
    }

    pub fn backspace(&mut self) {
        if self.visible {
            if self.cursor_position > 0 {
                self.input_buffer.remove(self.cursor_position - 1);
                self.cursor_position -= 1;
            }
        }
    }

    /// Renders the Console
    pub fn render(&mut self, mut renderer: &mut Renderer) {
        if self.visible {

            renderer.set_blend_mode(BlendMode::Blend);
            self.texture.set_blend_mode(BlendMode::Blend);
            renderer.copy(&self.texture,
                      None,
                      Some(Rect::new(0, 0, CONSOLE_WIDTH, CONSOLE_HEIGHT)))
                .unwrap();
            self.render_leader(&mut renderer);
            self.generate_backbuffer_texture(&mut renderer);
            // self.render_buffer(&mut renderer);

            // Insert the cursor in its proper position
            let mut output_text = self.input_buffer.clone();
            if self.cursor_position < output_text.len() {
                output_text.insert(self.cursor_position, '|');
            } else {
                output_text.push_str("|");
            }

            // If no input.. only draw the cursor
            if self.input_buffer.len() == 0 {
                output_text = "|".into();
            }

            let text = Text::new(&self.ttf_context,
                                 &mut renderer,
                                 &output_text[..],
                                 Position::XY(60, CONSOLE_HEIGHT as i32 - FONT_SIZE as i32),
                                 FONT_SIZE,
                                 FONT_COLOR,
                                 FONT_FILE);
            text.render(&mut renderer);
        }
    }

    fn render_leader(&self, mut renderer: &mut Renderer) {
        self.leader.render(&mut renderer);
    }

    fn generate_backbuffer_texture(&mut self, mut renderer: &mut Renderer) {
        let mut font = self.ttf_context.load_font(Path::new(FONT_FILE), FONT_SIZE).unwrap();
        font.set_style(STYLE_BOLD);
        let mut main_surface = Surface::new(CONSOLE_WIDTH,
                                            (CONSOLE_HEIGHT - (FONT_SIZE as u32)),
                                            PixelFormatEnum::RGBA8888)
            .unwrap();
        let mut counter = 2;
        for line in self.buffer.iter().rev().take(100) {
            let mut y_pos = CONSOLE_HEIGHT as i32 - (FONT_SIZE as i32 * counter) +
                            self.backbuffer_y;
            counter += 1;

            if line.trim().len() == 0 {
                continue;
            }

            let surface = font.render(&line)
                .blended(FONT_COLOR)
                .unwrap();
            surface.blit(None,
                      &mut main_surface,
                      Some(Rect::new(0, y_pos, CONSOLE_HEIGHT, FONT_SIZE as u32)))
                .unwrap();
        }
        let texture = renderer.create_texture_from_surface(&main_surface)
            .unwrap();

        let TextureQuery { width, height, .. } = texture.query();

        renderer.copy(&texture, None, Some(Rect::new(0, 0, width, height)));
    }
}<|endoftext|>