<commit_before>//! Loads "sysroot" crate.
//!
//! One confusing point here is that normally sysroot is a bunch of `.rlib`s,
//! but we can't process `.rlib` and need source code instead. The source code
//! is typically installed with `rustup component add rust-src` command.

use std::{convert::TryFrom, env, ops, path::PathBuf, process::Command};

use anyhow::{format_err, Result};
use arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};

use crate::utf8_stdout;

#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct Sysroot {
    crates: Arena<SysrootCrateData>,
}

pub(crate) type SysrootCrate = Idx<SysrootCrateData>;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SysrootCrateData {
    pub name: String,
    pub root: AbsPathBuf,
    pub deps: Vec<SysrootCrate>,
}

impl ops::Index<SysrootCrate> for Sysroot {
    type Output = SysrootCrateData;
    fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
        &self.crates[index]
    }
}

impl Sysroot {
    pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate)> + '_ {
        // core is added as a dependency before std in order to
        // mimic rustcs dependency order
        ["core", "alloc", "std"].iter().filter_map(move |&it| Some((it, self.by_name(it)?)))
    }

    pub fn proc_macro(&self) -> Option<SysrootCrate> {
        self.by_name("proc_macro")
    }

    pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
        self.crates.iter().map(|(id, _data)| id)
    }

    pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
        log::debug!("Discovering sysroot for {}", cargo_toml.display());
        let current_dir = cargo_toml.parent().unwrap();
        let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?;
        let res = Sysroot::load(&sysroot_src_dir)?;
        Ok(res)
    }

    pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
        let mut sysroot = Sysroot { crates: Arena::default() };

        for name in SYSROOT_CRATES.trim().lines() {
            let root = [format!("{}/src/lib.rs", name), format!("lib{}/lib.rs", name)]
                .iter()
                .map(|it| sysroot_src_dir.join(it))
                .find(|it| it.exists());

            if let Some(root) = root {
                sysroot.crates.alloc(SysrootCrateData {
                    name: name.into(),
                    root,
                    deps: Vec::new(),
                });
            }
        }

        if let Some(std) = sysroot.by_name("std") {
            for dep in STD_DEPS.trim().lines() {
                if let Some(dep) = sysroot.by_name(dep) {
                    sysroot.crates[std].deps.push(dep)
                }
            }
        }

        if let Some(alloc) = sysroot.by_name("alloc") {
            if let Some(core) = sysroot.by_name("core") {
                sysroot.crates[alloc].deps.push(core);
            }
        }

        if sysroot.by_name("core").is_none() {
            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
            } else {
                ""
            };
            anyhow::bail!(
                "could not find libcore in sysroot path `{}`{}",
                sysroot_src_dir.as_ref().display(),
                var_note,
            );
        }

        Ok(sysroot)
    }

    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
        let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
        Some(id)
    }
}

fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
    if let Ok(path) = env::var("RUST_SRC_PATH") {
        let path = AbsPathBuf::try_from(path.as_str())
            .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
        let core = path.join("core");
        if core.exists() {
            log::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
            return Ok(path);
        }
        log::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
    }

    let sysroot_path = {
        let mut rustc = Command::new(toolchain::rustc());
        rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
        log::debug!("Discovering sysroot by {:?}", rustc);
        let stdout = utf8_stdout(rustc)?;
        AbsPathBuf::assert(PathBuf::from(stdout))
    };

    get_rust_src(&sysroot_path)
        .or_else(|| {
            let mut rustup = Command::new(toolchain::rustup());
            rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
            utf8_stdout(rustup).ok()?;
            get_rust_src(&sysroot_path)
        })
        .ok_or_else(|| {
            format_err!(
                "\
can't load standard library from sysroot
{}
(discovered via `rustc --print sysroot`)
try running `rustup component add rust-src` or set `RUST_SRC_PATH`",
                sysroot_path.display(),
            )
        })
}

fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
    // Try the new path first since the old one still exists.
    let rust_src = sysroot_path.join("lib/rustlib/src/rust");
    log::debug!("Checking sysroot (looking for `library` and `src` dirs): {}", rust_src.display());
    ["library", "src"].iter().map(|it| rust_src.join(it)).find(|it| it.exists())
}

impl SysrootCrateData {
    pub fn root_dir(&self) -> &AbsPath {
        self.root.parent().unwrap()
    }
}

const SYSROOT_CRATES: &str = "
alloc
core
panic_abort
panic_unwind
proc_macro
profiler_builtins
rtstartup
std
stdarch
term
test
unwind";

const STD_DEPS: &str = "
alloc
core
panic_abort
panic_unwind
profiler_builtins
rtstartup
proc_macro
stdarch
term
test
unwind";
<commit_msg>Change recommendation when source can't be loaded from sysroot<commit_after>//! Loads "sysroot" crate.
//!
//! One confusing point here is that normally sysroot is a bunch of `.rlib`s,
//! but we can't process `.rlib` and need source code instead. The source code
//! is typically installed with `rustup component add rust-src` command.

use std::{convert::TryFrom, env, ops, path::PathBuf, process::Command};

use anyhow::{format_err, Result};
use arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};

use crate::utf8_stdout;

#[derive(Default, Debug, Clone, Eq, PartialEq)]
pub struct Sysroot {
    crates: Arena<SysrootCrateData>,
}

pub(crate) type SysrootCrate = Idx<SysrootCrateData>;

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct SysrootCrateData {
    pub name: String,
    pub root: AbsPathBuf,
    pub deps: Vec<SysrootCrate>,
}

impl ops::Index<SysrootCrate> for Sysroot {
    type Output = SysrootCrateData;
    fn index(&self, index: SysrootCrate) -> &SysrootCrateData {
        &self.crates[index]
    }
}

impl Sysroot {
    pub fn public_deps(&self) -> impl Iterator<Item = (&'static str, SysrootCrate)> + '_ {
        // core is added as a dependency before std in order to
        // mimic rustcs dependency order
        ["core", "alloc", "std"].iter().filter_map(move |&it| Some((it, self.by_name(it)?)))
    }

    pub fn proc_macro(&self) -> Option<SysrootCrate> {
        self.by_name("proc_macro")
    }

    pub fn crates<'a>(&'a self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + 'a {
        self.crates.iter().map(|(id, _data)| id)
    }

    pub fn discover(cargo_toml: &AbsPath) -> Result<Sysroot> {
        log::debug!("Discovering sysroot for {}", cargo_toml.display());
        let current_dir = cargo_toml.parent().unwrap();
        let sysroot_src_dir = discover_sysroot_src_dir(current_dir)?;
        let res = Sysroot::load(&sysroot_src_dir)?;
        Ok(res)
    }

    pub fn load(sysroot_src_dir: &AbsPath) -> Result<Sysroot> {
        let mut sysroot = Sysroot { crates: Arena::default() };

        for name in SYSROOT_CRATES.trim().lines() {
            let root = [format!("{}/src/lib.rs", name), format!("lib{}/lib.rs", name)]
                .iter()
                .map(|it| sysroot_src_dir.join(it))
                .find(|it| it.exists());

            if let Some(root) = root {
                sysroot.crates.alloc(SysrootCrateData {
                    name: name.into(),
                    root,
                    deps: Vec::new(),
                });
            }
        }

        if let Some(std) = sysroot.by_name("std") {
            for dep in STD_DEPS.trim().lines() {
                if let Some(dep) = sysroot.by_name(dep) {
                    sysroot.crates[std].deps.push(dep)
                }
            }
        }

        if let Some(alloc) = sysroot.by_name("alloc") {
            if let Some(core) = sysroot.by_name("core") {
                sysroot.crates[alloc].deps.push(core);
            }
        }

        if sysroot.by_name("core").is_none() {
            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
            } else {
                ""
            };
            anyhow::bail!(
                "could not find libcore in sysroot path `{}`{}",
                sysroot_src_dir.as_ref().display(),
                var_note,
            );
        }

        Ok(sysroot)
    }

    fn by_name(&self, name: &str) -> Option<SysrootCrate> {
        let (id, _data) = self.crates.iter().find(|(_id, data)| data.name == name)?;
        Some(id)
    }
}

fn discover_sysroot_src_dir(current_dir: &AbsPath) -> Result<AbsPathBuf> {
    if let Ok(path) = env::var("RUST_SRC_PATH") {
        let path = AbsPathBuf::try_from(path.as_str())
            .map_err(|path| format_err!("RUST_SRC_PATH must be absolute: {}", path.display()))?;
        let core = path.join("core");
        if core.exists() {
            log::debug!("Discovered sysroot by RUST_SRC_PATH: {}", path.display());
            return Ok(path);
        }
        log::debug!("RUST_SRC_PATH is set, but is invalid (no core: {:?}), ignoring", core);
    }

    let sysroot_path = {
        let mut rustc = Command::new(toolchain::rustc());
        rustc.current_dir(current_dir).args(&["--print", "sysroot"]);
        log::debug!("Discovering sysroot by {:?}", rustc);
        let stdout = utf8_stdout(rustc)?;
        AbsPathBuf::assert(PathBuf::from(stdout))
    };

    get_rust_src(&sysroot_path)
        .or_else(|| {
            let mut rustup = Command::new(toolchain::rustup());
            rustup.current_dir(current_dir).args(&["component", "add", "rust-src"]);
            utf8_stdout(rustup).ok()?;
            get_rust_src(&sysroot_path)
        })
        .ok_or_else(|| {
            format_err!(
                "\
can't load standard library from sysroot
{}
(discovered via `rustc --print sysroot`)
try installing the Rust source the same way you installed rustc",
                sysroot_path.display(),
            )
        })
}

fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
    // Try the new path first since the old one still exists.
    let rust_src = sysroot_path.join("lib/rustlib/src/rust");
    log::debug!("Checking sysroot (looking for `library` and `src` dirs): {}", rust_src.display());
    ["library", "src"].iter().map(|it| rust_src.join(it)).find(|it| it.exists())
}

impl SysrootCrateData {
    pub fn root_dir(&self) -> &AbsPath {
        self.root.parent().unwrap()
    }
}

const SYSROOT_CRATES: &str = "
alloc
core
panic_abort
panic_unwind
proc_macro
profiler_builtins
rtstartup
std
stdarch
term
test
unwind";

const STD_DEPS: &str = "
alloc
core
panic_abort
panic_unwind
profiler_builtins
rtstartup
proc_macro
stdarch
term
test
unwind";
<|endoftext|>


<commit_before>use std::str::Chars;
use std::iter::Peekable;
use std::iter::Enumerate;

use ::syntax::lexer::{Token, Lexer, Span};
use ::syntax::next_is;

pub struct RustSyntax;

impl Lexer for RustSyntax {
    fn handle_char(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize, idx: usize) -> Option<Span> {
        match ch {
            '#' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '!') || next_is(&mut iter, '[') {
                    let mut s = String::from("#");
                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Attribute(s),
                    });
                }
                return Some(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash})
            }

            '/' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '/') {
                    let mut s = String::from("/");
                    s.push(iter.next().unwrap().1);

                    let mut doc_comment = false;
                    if next_is(&mut iter, '/') {
                        doc_comment = true;
                    }

                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }

                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: if doc_comment{ Token::DocComment(s) } else { Token::SingleLineComment(s) },
                    });
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::ForwardSlash,
                });
            }

            '"' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\"");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '"' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::String(s),
                });
            }

            '\'' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\'");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '\'' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '\'' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::Special(s),
                });
            }

            _ => None,
        }

    }

    fn handle_ident(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span {
        let mut ident = String::new();
        ident.push(ch);
        let start = iter.peek().unwrap().0 - 1;

        while self.is_ident(iter.peek()) {
            ident.push(iter.next().unwrap().1)
        }

        Span {
            y_pos: y_pos,
            start: start,
            end: start + ident.len() - 1,
            token: Token::Ident(ident),
        }
    }
}

<commit_msg>Highlight :: in rust<commit_after>use std::str::Chars;
use std::iter::Peekable;
use std::iter::Enumerate;

use ::syntax::lexer::{Token, Lexer, Span};
use ::syntax::next_is;

pub struct RustSyntax;

impl Lexer for RustSyntax {
    fn handle_char(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize, idx: usize) -> Option<Span> {
        match ch {
            '#' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '!') || next_is(&mut iter, '[') {
                    let mut s = String::from("#");
                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Attribute(s),
                    });
                }
                return Some(Span{y_pos: y_pos, start: idx, end: idx + 1, token: Token::Hash})
            }

            '/' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, '/') {
                    let mut s = String::from("/");
                    s.push(iter.next().unwrap().1);

                    let mut doc_comment = false;
                    if next_is(&mut iter, '/') {
                        doc_comment = true;
                    }

                    while let Some(&(e, c)) = iter.peek() {
                        if c == '\n' { break }
                        end = e;
                        s.push(iter.next().unwrap().1)
                    }

                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: if doc_comment{ Token::DocComment(s) } else { Token::SingleLineComment(s) },
                    });
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::ForwardSlash,
                });
            }

            '"' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\"");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '"' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::String(s),
                });
            }

            '\'' => {
                let st = idx;
                let mut end = idx;
                let mut s = String::from("\'");
                while let Some(&(e, c)) = iter.peek() {
                    end = e;
                    s.push(iter.next().unwrap().1);
                    if c == '\\' {
                        if let Some(&(e, c_)) = iter.peek() {
                            // this is handling escaped single quotes...
                            if c_ == '\'' {
                                s.push(iter.next().unwrap().1);
                                continue;
                            }
                        }
                    }
                    if c == '\'' {
                        break;
                    }
                }
                return Some(Span {
                    y_pos: y_pos,
                    start: st,
                    end: end,
                    token: Token::Special(s),
                });
            }

            ':' => {
                let st = idx;
                let mut end = idx;
                if next_is(&mut iter, ':') {
                    let (e, c) = iter.next().unwrap();
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: e,
                        token: Token::Special(String::from("::")),
                    });
                } else {
                    return Some(Span {
                        y_pos: y_pos,
                        start: st,
                        end: end,
                        token: Token::Colon,
                    });
                }
            }

            _ => None,
        }

    }

    fn handle_ident(&self, ch: char, mut iter: &mut Peekable<Enumerate<Chars>>, y_pos: usize) -> Span {
        let mut ident = String::new();
        ident.push(ch);
        let start = iter.peek().unwrap().0 - 1;

        while self.is_ident(iter.peek()) {
            ident.push(iter.next().unwrap().1)
        }

        Span {
            y_pos: y_pos,
            start: start,
            end: start + ident.len() - 1,
            token: Token::Ident(ident),
        }
    }
}

<|endoftext|>


<commit_before>use super::MemoryBankController;

/// RomOnly is the simplest MBC, as in, there's actually no controller at all.
/// This maps the ROM directly to addresses 0x0000 to 0x7FFF
/// Some cartridges that specify no MBC might also pack up to 8KB of RAM at the
/// addresses 0xA000 to 0xBFFF.
pub struct RomOnly {
    data: Vec<u8>,
    ram: Vec<u8>,
}

impl RomOnly {

    /// Creates a new RomOnly MBC with no data (all initialized to 0).
    /// This is only useful for testing purposes, only the bootloader will run and in most cases the emulator
    /// might crash after trying to execute all memory.
    pub fn new() -> Self {
        RomOnly { data: vec![0; 0x8000], ram: vec![0; 0x2000] }
    }

    /// Creates a new RomOnly MBC with the provided data.
    pub fn with_data(rom_data: Vec<u8>) -> Self {
        RomOnly {
            data: rom_data,
            ram: vec![0; 8192],
        }
    }
}

impl MemoryBankController for RomOnly {

    fn read(&self, addr: u16) -> u8 {
        match addr {
            0...0x7FFF => self.data[addr as usize],
            0xA000...0xBFFF => self.ram[(addr - 0xA000) as usize],
            _ => panic!("RomOnly MBC attempted read at ${:04x}", addr),
        }
    }

    fn write(&mut self, addr: u16, data: u8) {
        match addr {
            0...0x7FFF => {
                // nothing happens when writing to ROM
            },
            0xA000...0xBFFF => self.ram[(addr - 0xA000) as usize] = data,
            _ => panic!("RomOnly MBC attempted write at ${:04x}", addr),
        };
    }
}<commit_msg>Added tests for RomOnly<commit_after>use super::MemoryBankController;

/// RomOnly is the simplest MBC, as in, there's actually no controller at all.
/// This maps the ROM directly to addresses 0x0000 to 0x7FFF
/// Some cartridges that specify no MBC might also pack up to 8KB of RAM at the
/// addresses 0xA000 to 0xBFFF.
pub struct RomOnly {
    data: Vec<u8>,
    ram: Vec<u8>,
}

impl RomOnly {

    /// Creates a new RomOnly MBC with no data (all initialized to 0).
    /// This is only useful for testing purposes, only the bootloader will run and in most cases the emulator
    /// might crash after trying to execute all memory.
    pub fn new() -> Self {
        RomOnly { data: vec![0; 0x8000], ram: vec![0; 0x2000] }
    }

    /// Creates a new RomOnly MBC with the provided data.
    pub fn with_data(rom_data: Vec<u8>) -> Self {
        RomOnly {
            data: rom_data,
            ram: vec![0; 8192],
        }
    }
}

impl MemoryBankController for RomOnly {

    fn read(&self, addr: u16) -> u8 {
        match addr {
            0...0x7FFF => self.data[addr as usize],
            0xA000...0xBFFF => self.ram[(addr - 0xA000) as usize],
            _ => panic!("RomOnly MBC attempted read at ${:04x}", addr),
        }
    }

    fn write(&mut self, addr: u16, data: u8) {
        match addr {
            0...0x7FFF => {
                // nothing happens when writing to ROM
            },
            0xA000...0xBFFF => self.ram[(addr - 0xA000) as usize] = data,
            _ => panic!("RomOnly MBC attempted write at ${:04x}", addr),
        };
    }
}

#[test]
fn nombc_loads_vec() {
    let mbc = RomOnly::with_data(vec![0xFF; 0x8000]);

    // ROM
    assert_eq!(0xFF, mbc.read(0x0));
    assert_eq!(0xFF, mbc.read(0x7FFF));
    // RAM
    assert_eq!(0x0, mbc.read(0xA000));
    assert_eq!(0x0, mbc.read(0xBFFF));
}

#[test]
fn nombc_write() {
    let mut mbc = RomOnly::with_data(vec![0xFF; 0x8000]);

    // ROM write should do nothing
    mbc.write(0x0, 0xAF);
    mbc.write(0x7FFF, 0xAF);
    assert_eq!(0xFF, mbc.read(0x0));
    assert_eq!(0xFF, mbc.read(0x7FFF));
    // RAM write
    mbc.write(0xA000, 0xAF);
    mbc.write(0xBFFF, 0xAF);
    assert_eq!(0xAF, mbc.read(0xA000));
    assert_eq!(0xAF, mbc.read(0xBFFF));
}<|endoftext|>


<commit_before>use std::num::FloatMath;
use linalg;
use linalg::Matrix4;
use linalg::Vector;
use linalg::Point;
use linalg::Normal;
use linalg::Ray;

/// Transform describes an affine transformation in 3D space
/// and stores both the transformation and its inverse
#[deriving(Show, Copy, PartialEq)]
pub struct Transform {
    pub mat: Matrix4,
    pub inv: Matrix4,
}

impl Transform {
    /// Construct the identity transformation
    pub fn identity() -> Transform {
        Transform {
            mat: Matrix4::identity(),
            inv: Matrix4::identity(),
        }
    }
    /// Construct a transform from an existing matrix
    pub fn from_mat(mat: &Matrix4) -> Transform {
        Transform { mat: *mat, inv: mat.inverse() }
    }
    /// Construct a transform from an existing matrix/inverse pair
    pub fn from_pair(mat: &Matrix4, inv: &Matrix4) -> Transform {
        Transform { mat: *mat, inv: *inv }
    }
    /// Construct a transformation matrix to translate by the vector
    pub fn translate(v: &Vector) -> Transform {
        Transform {
            mat: Matrix4::new([1f32, 0f32, 0f32, v.x,
                               0f32, 1f32, 0f32, v.y,
                               0f32, 0f32, 1f32, v.z,
                               0f32, 0f32, 0f32, 1f32]),
            inv: Matrix4::new([1f32, 0f32, 0f32, -v.x,
                               0f32, 1f32, 0f32, -v.y,
                               0f32, 0f32, 1f32, -v.z,
                               0f32, 0f32, 0f32, 1f32]),
        }
    }
    /// Construct a transform to scale x, y and z by the values in the vector
    pub fn scale(v: &Vector) -> Transform {
        Transform {
            mat: Matrix4::new([v.x, 0f32, 0f32, 0f32,
                               0f32, v.y, 0f32, 0f32,
                               0f32, 0f32, v.z, 0f32,
                               0f32, 0f32, 0f32, 1f32]),
            inv: Matrix4::new([1f32 / v.x, 0f32, 0f32, 0f32,
                               0f32, 1f32 / v.y, 0f32, 0f32,
                               0f32, 0f32, 1f32 / v.z, 0f32,
                               0f32, 0f32, 0f32, 1f32]),
        }
    }
    /// Construct a transform to rotate `deg` degrees about the x axis
    pub fn rotate_x(deg: f32) -> Transform {
        let r = linalg::radians(deg);
        let s = FloatMath::sin(r);
        let c = FloatMath::cos(r);
        let m = Matrix4::new([1f32, 0f32, 0f32, 0f32,
                              0f32, c, -s, 0f32,
                              0f32, s, c, 0f32,
                              0f32, 0f32, 0f32, 1f32]);
        Transform { mat: m, inv: m.transpose() }
    }
    /// Construct a transform to rotate `deg` degrees about the y axis
    pub fn rotate_y(deg: f32) -> Transform {
        let r = linalg::radians(deg);
        let s = FloatMath::sin(r);
        let c = FloatMath::cos(r);
        let m = Matrix4::new([c, 0f32, s, 0f32,
                              0f32, 1f32, 0f32, 0f32,
                              -s, 0f32, c, 0f32,
                              0f32, 0f32, 0f32, 1f32]);
        Transform { mat: m, inv: m.transpose() }
    }
    /// Construct a transform to rotate `deg` degrees about the z axis
    pub fn rotate_z(deg: f32) -> Transform {
        let r = linalg::radians(deg);
        let s = FloatMath::sin(r);
        let c = FloatMath::cos(r);
        let m = Matrix4::new([c, -s, 0f32, 0f32,
                              s, c, 0f32, 0f32,
                              0f32, 0f32, 1f32, 0f32,
                              0f32, 0f32, 0f32, 1f32]);
        Transform { mat: m, inv: m.transpose() }
    }
    /// Construct a transform to rotate about `axis` by `deg` degrees
    pub fn rotate(axis: &Vector, deg: f32) -> Transform {
        let a = axis.normalized();
        let r = linalg::radians(deg);
        let s = FloatMath::sin(r);
        let c = FloatMath::cos(r);
        let mut m = Matrix4::identity();
        *m.at_mut(0, 0) = a.x * a.x + (1f32 - a.x * a.x) * c;
        *m.at_mut(0, 1) = a.x * a.y * (1f32 - c) - a.z * s;
        *m.at_mut(0, 2) = a.x * a.z * (1f32 - c) + a.y * s;
        *m.at_mut(0, 3) = 0f32;

        *m.at_mut(1, 0) = a.x * a.y * (1f32 - c) + a.z * s;
        *m.at_mut(1, 1) = a.y * a.y + (1f32 - a.y * a.y) * c;
        *m.at_mut(1, 2) = a.y * a.z * (1f32 - c) - a.x * s;
        *m.at_mut(1, 3) = 0f32;

        *m.at_mut(2, 0) = a.x * a.z * (1f32 - c) - a.y * s;
        *m.at_mut(2, 1) = a.y * a.z * (1f32 - c) + a.x * s;
        *m.at_mut(2, 2) = a.z * a.z + (1f32 - a.z * a.z) * c;
        *m.at_mut(2, 3) = 0f32;
        Transform { mat: m, inv: m.transpose() }
    }
    /// Construct the look at transform for a camera at `pos` looking at
    /// the point `center` oriented with up vector `up`
    pub fn look_at(pos: &Point, center: &Point, up: &Vector) -> Transform {
        let dir = (*center - *pos).normalized();
        let right = linalg::cross(&dir, up).normalized();
        let u = linalg::cross(&dir, &right).normalized();
        let mut m = Matrix4::identity();
        for i in range(0u, 3u) {
            *m.at_mut(i, 0) = right[i];
            *m.at_mut(i, 1) = u[i];
            *m.at_mut(i, 2) = dir[i];
            *m.at_mut(i, 3) = pos[i];
        }
        Transform { mat: m, inv: m.inverse() }
    }
    /// Construct a perspective transformation
    pub fn perspective(fovy: f32, near: f32, far: f32) -> Transform {
        let proj_div = Matrix4::new([1f32, 0f32, 0f32, 0f32,
                                     0f32, 1f32, 0f32, 0f32,
                                     0f32, 0f32, far / (far - near), -far * near / (far - near),
                                     0f32, 0f32, 1f32, 0f32]);
        let inv_tan = 1f32 / FloatMath::atan(linalg::radians(fovy) / 2f32);
        Transform::scale(&Vector::new(inv_tan, inv_tan, 1f32)) * Transform::from_mat(&proj_div)
    }
    /// Return the inverse of the transformation
    pub fn inverse(&self) -> Transform {
        Transform { mat: self.inv, inv: self.mat }
    }
    /// Apply the transformation to a point
    pub fn point(&self, p: &Point) -> Point {
        let mut res = Point::broadcast(0f32);
        for i in range(0u, 3u) {
            res[i] = *self.mat.at(i, 0) * p.x + *self.mat.at(i, 1) * p.y
                + *self.mat.at(i, 2) * p.z + *self.mat.at(i, 3);
        }
        let w = *self.mat.at(3, 0) * p.x + *self.mat.at(3, 1) * p.y
            + *self.mat.at(3, 2) * p.z + *self.mat.at(3, 3);
        if w != 1f32 {
            res / w
        } else {
            res
        }
    }
    /// Apply the transformation to a vector
    pub fn vector(&self, v: &Vector) -> Vector {
        let mut res = Vector::broadcast(0f32);
        for i in range(0u, 3u) {
            res[i] = *self.mat.at(i, 0) * v.x + *self.mat.at(i, 1) * v.y
                + *self.mat.at(i, 2) * v.z;
        }
        res
    }
    /// Apply the transformation to a normal
    pub fn normal(&self, n: &Normal) -> Normal {
        let mut res = Normal::broadcast(0f32);
        for i in range(0u, 3u) {
            res[i] = *self.inv.at(0, i) * n.x + *self.inv.at(1, i) * n.y
                + *self.inv.at(2, i) * n.z;
        }
        res
    }
    /// Apply the transformation to a ray
    pub fn ray(&self, ray: &Ray) -> Ray {
        let mut res = *ray;
        res.o = self.point(&res.o);
        res.d = self.vector(&res.d);
        res
    }
}

impl Mul<Transform, Transform> for Transform {
    /// Compose two transformations
    fn mul(self, rhs: Transform) -> Transform {
        Transform { mat: self.mat * rhs.mat, inv: rhs.inv * self.inv }
    }
}

<commit_msg>Don't actually need to set those 0's since it's already in identity mat<commit_after>use std::num::FloatMath;
use linalg;
use linalg::Matrix4;
use linalg::Vector;
use linalg::Point;
use linalg::Normal;
use linalg::Ray;

/// Transform describes an affine transformation in 3D space
/// and stores both the transformation and its inverse
#[deriving(Show, Copy, PartialEq)]
pub struct Transform {
    pub mat: Matrix4,
    pub inv: Matrix4,
}

impl Transform {
    /// Construct the identity transformation
    pub fn identity() -> Transform {
        Transform {
            mat: Matrix4::identity(),
            inv: Matrix4::identity(),
        }
    }
    /// Construct a transform from an existing matrix
    pub fn from_mat(mat: &Matrix4) -> Transform {
        Transform { mat: *mat, inv: mat.inverse() }
    }
    /// Construct a transform from an existing matrix/inverse pair
    pub fn from_pair(mat: &Matrix4, inv: &Matrix4) -> Transform {
        Transform { mat: *mat, inv: *inv }
    }
    /// Construct a transformation matrix to translate by the vector
    pub fn translate(v: &Vector) -> Transform {
        Transform {
            mat: Matrix4::new([1f32, 0f32, 0f32, v.x,
                               0f32, 1f32, 0f32, v.y,
                               0f32, 0f32, 1f32, v.z,
                               0f32, 0f32, 0f32, 1f32]),
            inv: Matrix4::new([1f32, 0f32, 0f32, -v.x,
                               0f32, 1f32, 0f32, -v.y,
                               0f32, 0f32, 1f32, -v.z,
                               0f32, 0f32, 0f32, 1f32]),
        }
    }
    /// Construct a transform to scale x, y and z by the values in the vector
    pub fn scale(v: &Vector) -> Transform {
        Transform {
            mat: Matrix4::new([v.x, 0f32, 0f32, 0f32,
                               0f32, v.y, 0f32, 0f32,
                               0f32, 0f32, v.z, 0f32,
                               0f32, 0f32, 0f32, 1f32]),
            inv: Matrix4::new([1f32 / v.x, 0f32, 0f32, 0f32,
                               0f32, 1f32 / v.y, 0f32, 0f32,
                               0f32, 0f32, 1f32 / v.z, 0f32,
                               0f32, 0f32, 0f32, 1f32]),
        }
    }
    /// Construct a transform to rotate `deg` degrees about the x axis
    pub fn rotate_x(deg: f32) -> Transform {
        let r = linalg::radians(deg);
        let s = FloatMath::sin(r);
        let c = FloatMath::cos(r);
        let m = Matrix4::new([1f32, 0f32, 0f32, 0f32,
                              0f32, c, -s, 0f32,
                              0f32, s, c, 0f32,
                              0f32, 0f32, 0f32, 1f32]);
        Transform { mat: m, inv: m.transpose() }
    }
    /// Construct a transform to rotate `deg` degrees about the y axis
    pub fn rotate_y(deg: f32) -> Transform {
        let r = linalg::radians(deg);
        let s = FloatMath::sin(r);
        let c = FloatMath::cos(r);
        let m = Matrix4::new([c, 0f32, s, 0f32,
                              0f32, 1f32, 0f32, 0f32,
                              -s, 0f32, c, 0f32,
                              0f32, 0f32, 0f32, 1f32]);
        Transform { mat: m, inv: m.transpose() }
    }
    /// Construct a transform to rotate `deg` degrees about the z axis
    pub fn rotate_z(deg: f32) -> Transform {
        let r = linalg::radians(deg);
        let s = FloatMath::sin(r);
        let c = FloatMath::cos(r);
        let m = Matrix4::new([c, -s, 0f32, 0f32,
                              s, c, 0f32, 0f32,
                              0f32, 0f32, 1f32, 0f32,
                              0f32, 0f32, 0f32, 1f32]);
        Transform { mat: m, inv: m.transpose() }
    }
    /// Construct a transform to rotate about `axis` by `deg` degrees
    pub fn rotate(axis: &Vector, deg: f32) -> Transform {
        let a = axis.normalized();
        let r = linalg::radians(deg);
        let s = FloatMath::sin(r);
        let c = FloatMath::cos(r);
        let mut m = Matrix4::identity();
        *m.at_mut(0, 0) = a.x * a.x + (1f32 - a.x * a.x) * c;
        *m.at_mut(0, 1) = a.x * a.y * (1f32 - c) - a.z * s;
        *m.at_mut(0, 2) = a.x * a.z * (1f32 - c) + a.y * s;

        *m.at_mut(1, 0) = a.x * a.y * (1f32 - c) + a.z * s;
        *m.at_mut(1, 1) = a.y * a.y + (1f32 - a.y * a.y) * c;
        *m.at_mut(1, 2) = a.y * a.z * (1f32 - c) - a.x * s;

        *m.at_mut(2, 0) = a.x * a.z * (1f32 - c) - a.y * s;
        *m.at_mut(2, 1) = a.y * a.z * (1f32 - c) + a.x * s;
        *m.at_mut(2, 2) = a.z * a.z + (1f32 - a.z * a.z) * c;
        Transform { mat: m, inv: m.transpose() }
    }
    /// Construct the look at transform for a camera at `pos` looking at
    /// the point `center` oriented with up vector `up`
    pub fn look_at(pos: &Point, center: &Point, up: &Vector) -> Transform {
        let dir = (*center - *pos).normalized();
        let right = linalg::cross(&dir, up).normalized();
        let u = linalg::cross(&dir, &right).normalized();
        let mut m = Matrix4::identity();
        for i in range(0u, 3u) {
            *m.at_mut(i, 0) = right[i];
            *m.at_mut(i, 1) = u[i];
            *m.at_mut(i, 2) = dir[i];
            *m.at_mut(i, 3) = pos[i];
        }
        Transform { mat: m, inv: m.inverse() }
    }
    /// Construct a perspective transformation
    pub fn perspective(fovy: f32, near: f32, far: f32) -> Transform {
        let proj_div = Matrix4::new([1f32, 0f32, 0f32, 0f32,
                                     0f32, 1f32, 0f32, 0f32,
                                     0f32, 0f32, far / (far - near), -far * near / (far - near),
                                     0f32, 0f32, 1f32, 0f32]);
        let inv_tan = 1f32 / FloatMath::atan(linalg::radians(fovy) / 2f32);
        Transform::scale(&Vector::new(inv_tan, inv_tan, 1f32)) * Transform::from_mat(&proj_div)
    }
    /// Return the inverse of the transformation
    pub fn inverse(&self) -> Transform {
        Transform { mat: self.inv, inv: self.mat }
    }
    /// Apply the transformation to a point
    pub fn point(&self, p: &Point) -> Point {
        let mut res = Point::broadcast(0f32);
        for i in range(0u, 3u) {
            res[i] = *self.mat.at(i, 0) * p.x + *self.mat.at(i, 1) * p.y
                + *self.mat.at(i, 2) * p.z + *self.mat.at(i, 3);
        }
        let w = *self.mat.at(3, 0) * p.x + *self.mat.at(3, 1) * p.y
            + *self.mat.at(3, 2) * p.z + *self.mat.at(3, 3);
        if w != 1f32 {
            res / w
        } else {
            res
        }
    }
    /// Apply the transformation to a vector
    pub fn vector(&self, v: &Vector) -> Vector {
        let mut res = Vector::broadcast(0f32);
        for i in range(0u, 3u) {
            res[i] = *self.mat.at(i, 0) * v.x + *self.mat.at(i, 1) * v.y
                + *self.mat.at(i, 2) * v.z;
        }
        res
    }
    /// Apply the transformation to a normal
    pub fn normal(&self, n: &Normal) -> Normal {
        let mut res = Normal::broadcast(0f32);
        for i in range(0u, 3u) {
            res[i] = *self.inv.at(0, i) * n.x + *self.inv.at(1, i) * n.y
                + *self.inv.at(2, i) * n.z;
        }
        res
    }
    /// Apply the transformation to a ray
    pub fn ray(&self, ray: &Ray) -> Ray {
        let mut res = *ray;
        res.o = self.point(&res.o);
        res.d = self.vector(&res.d);
        res
    }
}

impl Mul<Transform, Transform> for Transform {
    /// Compose two transformations
    fn mul(self, rhs: Transform) -> Transform {
        Transform { mat: self.mat * rhs.mat, inv: rhs.inv * self.inv }
    }
}

<|endoftext|>


<commit_before>//! The tags.

#![allow(non_upper_case_globals)]

use node::Attributes;
use parser::{Error, Reader, Result};

/// A tag.
#[derive(Clone, Debug)]
pub struct Tag<'l>(pub &'l str, pub Type, pub Attributes);

/// A [type][1] of a tag.
///
/// [1]: http://www.w3.org/TR/REC-xml/#sec-starttags
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Type {
    /// A start tag.
    Start,
    /// An end tag.
    End,
    /// An empty tag.
    Empty,
}

struct Parser<'l> {
    reader: Reader<'l>,
}

impl<'l> Tag<'l> {
    /// Parse a tag.
    #[inline]
    pub fn parse(content: &'l str) -> Result<Tag<'l>> {
        Parser::new(content).process()
    }
}

macro_rules! raise(
    ($parser:expr, $($argument:tt)*) => (
        return Err(Error::new($parser.reader.position(), format!($($argument)*)));
    );
);

impl<'l> Parser<'l> {
    #[inline]
    fn new(content: &'l str) -> Self {
        Parser {
            reader: Reader::new(content),
        }
    }

    fn process(&mut self) -> Result<Tag<'l>> {
        if self.reader.consume_char('/') {
            self.read_end_tag()
        } else {
            self.read_start_or_empty_tag()
        }
    }

    fn read_attribute(&mut self) -> Result<Option<(String, String)>> {
        let attribute = self.reader
            .capture(|reader| reader.consume_attribute())
            .and_then(|attribute| Some(String::from(attribute)));
        match attribute {
            Some(attribute) => {
                let k = (&attribute).find('=').unwrap();
                let name = (&attribute[0..k]).trim_right();
                let value = (&attribute[(k + 1)..]).trim_left();
                let value = &value[1..(value.len() - 1)];
                Ok(Some((String::from(name), String::from(value))))
            }
            _ => Ok(None),
        }
    }

    fn read_attributes(&mut self) -> Result<Attributes> {
        let mut attributes = Attributes::new();
        loop {
            self.reader.consume_whitespace();
            match try!(self.read_attribute()) {
                Some((name, value)) => {
                    attributes.insert(name, value.into());
                }
                _ => break,
            }
        }
        Ok(attributes)
    }

    fn read_end_tag(&mut self) -> Result<Tag<'l>> {
        let name = try!(self.read_name());
        self.reader.consume_whitespace();
        if !self.reader.is_done() {
            raise!(self, "found an end tag with excessive data");
        }
        Ok(Tag(name, Type::End, Attributes::default()))
    }

    fn read_name(&mut self) -> Result<&'l str> {
        let name = self.reader.capture(|reader| reader.consume_name());
        match name {
            Some(name) => Ok(name),
            _ => raise!(self, "expected a name"),
        }
    }

    fn read_start_or_empty_tag(&mut self) -> Result<Tag<'l>> {
        let name = try!(self.read_name());
        let attributes = try!(self.read_attributes());
        self.reader.consume_whitespace();
        let tail = self.reader.capture(|reader| reader.consume_all());
        match tail {
            Some("/") => Ok(Tag(name, Type::Empty, attributes)),
            Some(_) => raise!(self, "found an unexpected ending of a tag"),
            _ => Ok(Tag(name, Type::Start, attributes)),
        }
    }
}

macro_rules! implement {
    ($($const_name:ident: $tag_name:expr,)*) => ($(
        #[doc = $tag_name]
        pub const $const_name: &'static str = $tag_name;
    )*);
}

implement! {
    Animate: "animate",
    AnimateColor: "animateColor",
    AnimateMotion: "animateMotion",
    AnimateTransform: "animateTransform",
    Circle: "circle",
    ClipPath: "clipPath",
    Definitions: "defs",
    Description: "desc",
    Ellipse: "ellipse",
    Filter: "filter",
    Group: "g",
    Image: "image",
    Line: "line",
    LinearGradient: "linearGradient",
    Link: "a",
    Marker: "marker",
    Mask: "mask",
    MotionPath: "mpath",
    Path: "path",
    Pattern: "pattern",
    Polygon: "polygon",
    Polyline: "polyline",
    RadialGradient: "radialGradient",
    Rectangle: "rect",
    Script: "script",
    Stop: "stop",
    Style: "style",
    SVG: "svg",
    Symbol: "symbol",
    Text: "text",
    TextPath: "textPath",
    Title: "title",
    Use: "use",
}

#[cfg(test)]
mod tests {
    use super::{Parser, Tag, Type};

    #[test]
    fn parser_process() {
        macro_rules! test(
            ($content:expr, $kind:ident) => ({
                let mut parser = Parser::new($content);
                match parser.process().unwrap() {
                    Tag("foo", Type::$kind, _) => {}
                    _ => unreachable!(),
                }
            });
        );

        test!("foo", Start);
        test!("foo ", Start);
        test!("/foo", End);
        test!("/foo ", End);
        test!("foo/", Empty);
        test!("foo /", Empty);
    }

    #[test]
    fn parser_read_attribute() {
        macro_rules! test(
            ($content:expr, $name:expr, $value:expr) => ({
                let mut parser = Parser::new($content);
                let (name, value) = parser.read_attribute().unwrap().unwrap();
                assert_eq!(&*name, $name);
                assert_eq!(&*value, $value);
            });
        );

        test!("foo=''", "foo", "");
        test!("foo='bar'", "foo", "bar");
        test!("foo =\"bar\"", "foo", "bar");
        test!("foo= \"bar\"", "foo", "bar");
        test!("foo\t=\n'bar'  ", "foo", "bar");
    }
}
<commit_msg>Eliminate a few deprecation warnings<commit_after>//! The tags.

#![allow(non_upper_case_globals)]

use node::Attributes;
use parser::{Error, Reader, Result};

/// A tag.
#[derive(Clone, Debug)]
pub struct Tag<'l>(pub &'l str, pub Type, pub Attributes);

/// A [type][1] of a tag.
///
/// [1]: http://www.w3.org/TR/REC-xml/#sec-starttags
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Type {
    /// A start tag.
    Start,
    /// An end tag.
    End,
    /// An empty tag.
    Empty,
}

struct Parser<'l> {
    reader: Reader<'l>,
}

impl<'l> Tag<'l> {
    /// Parse a tag.
    #[inline]
    pub fn parse(content: &'l str) -> Result<Tag<'l>> {
        Parser::new(content).process()
    }
}

macro_rules! raise(
    ($parser:expr, $($argument:tt)*) => (
        return Err(Error::new($parser.reader.position(), format!($($argument)*)));
    );
);

impl<'l> Parser<'l> {
    #[inline]
    fn new(content: &'l str) -> Self {
        Parser {
            reader: Reader::new(content),
        }
    }

    fn process(&mut self) -> Result<Tag<'l>> {
        if self.reader.consume_char('/') {
            self.read_end_tag()
        } else {
            self.read_start_or_empty_tag()
        }
    }

    fn read_attribute(&mut self) -> Result<Option<(String, String)>> {
        let attribute = self.reader
            .capture(|reader| reader.consume_attribute())
            .and_then(|attribute| Some(String::from(attribute)));
        match attribute {
            Some(attribute) => {
                let k = (&attribute).find('=').unwrap();
                let name = (&attribute[0..k]).trim_end();
                let value = (&attribute[(k + 1)..]).trim_start();
                let value = &value[1..(value.len() - 1)];
                Ok(Some((String::from(name), String::from(value))))
            }
            _ => Ok(None),
        }
    }

    fn read_attributes(&mut self) -> Result<Attributes> {
        let mut attributes = Attributes::new();
        loop {
            self.reader.consume_whitespace();
            match try!(self.read_attribute()) {
                Some((name, value)) => {
                    attributes.insert(name, value.into());
                }
                _ => break,
            }
        }
        Ok(attributes)
    }

    fn read_end_tag(&mut self) -> Result<Tag<'l>> {
        let name = try!(self.read_name());
        self.reader.consume_whitespace();
        if !self.reader.is_done() {
            raise!(self, "found an end tag with excessive data");
        }
        Ok(Tag(name, Type::End, Attributes::default()))
    }

    fn read_name(&mut self) -> Result<&'l str> {
        let name = self.reader.capture(|reader| reader.consume_name());
        match name {
            Some(name) => Ok(name),
            _ => raise!(self, "expected a name"),
        }
    }

    fn read_start_or_empty_tag(&mut self) -> Result<Tag<'l>> {
        let name = try!(self.read_name());
        let attributes = try!(self.read_attributes());
        self.reader.consume_whitespace();
        let tail = self.reader.capture(|reader| reader.consume_all());
        match tail {
            Some("/") => Ok(Tag(name, Type::Empty, attributes)),
            Some(_) => raise!(self, "found an unexpected ending of a tag"),
            _ => Ok(Tag(name, Type::Start, attributes)),
        }
    }
}

macro_rules! implement {
    ($($const_name:ident: $tag_name:expr,)*) => ($(
        #[doc = $tag_name]
        pub const $const_name: &'static str = $tag_name;
    )*);
}

implement! {
    Animate: "animate",
    AnimateColor: "animateColor",
    AnimateMotion: "animateMotion",
    AnimateTransform: "animateTransform",
    Circle: "circle",
    ClipPath: "clipPath",
    Definitions: "defs",
    Description: "desc",
    Ellipse: "ellipse",
    Filter: "filter",
    Group: "g",
    Image: "image",
    Line: "line",
    LinearGradient: "linearGradient",
    Link: "a",
    Marker: "marker",
    Mask: "mask",
    MotionPath: "mpath",
    Path: "path",
    Pattern: "pattern",
    Polygon: "polygon",
    Polyline: "polyline",
    RadialGradient: "radialGradient",
    Rectangle: "rect",
    Script: "script",
    Stop: "stop",
    Style: "style",
    SVG: "svg",
    Symbol: "symbol",
    Text: "text",
    TextPath: "textPath",
    Title: "title",
    Use: "use",
}

#[cfg(test)]
mod tests {
    use super::{Parser, Tag, Type};

    #[test]
    fn parser_process() {
        macro_rules! test(
            ($content:expr, $kind:ident) => ({
                let mut parser = Parser::new($content);
                match parser.process().unwrap() {
                    Tag("foo", Type::$kind, _) => {}
                    _ => unreachable!(),
                }
            });
        );

        test!("foo", Start);
        test!("foo ", Start);
        test!("/foo", End);
        test!("/foo ", End);
        test!("foo/", Empty);
        test!("foo /", Empty);
    }

    #[test]
    fn parser_read_attribute() {
        macro_rules! test(
            ($content:expr, $name:expr, $value:expr) => ({
                let mut parser = Parser::new($content);
                let (name, value) = parser.read_attribute().unwrap().unwrap();
                assert_eq!(&*name, $name);
                assert_eq!(&*value, $value);
            });
        );

        test!("foo=''", "foo", "");
        test!("foo='bar'", "foo", "bar");
        test!("foo =\"bar\"", "foo", "bar");
        test!("foo= \"bar\"", "foo", "bar");
        test!("foo\t=\n'bar'  ", "foo", "bar");
    }
}
<|endoftext|>


<commit_before>use std;
use extra::comm::DuplexStream;

use player;

struct WorldState {
    player_state: ~player::PlayerState,
    ticks: int,
}

impl WorldState {
    pub fn new(player_state: ~player::PlayerState) -> WorldState {
        WorldState{ticks: 0, player_state: player_state}
    }

    pub fn clone(&self) -> WorldState {
        WorldState{ticks: self.ticks, player_state: self.player_state.clone()}
    }
}

fn update_world_state(world_state: &WorldState) -> WorldState {
    WorldState{ticks: world_state.ticks + 1, player_state: world_state.player_state.clone()}
}

/**
 Loop, updating the world state every time a value is sent on the timing port.
 Upon updating, the new world state is sent on the state server stream.
 */
pub fn world_handler(shared_timing_port: std::comm::SharedPort<()>, player_state: ~player::PlayerState, world_state_server: DuplexStream<WorldState, ()>) {
    let mut world_state = WorldState::new(player_state);

    'world : loop {
        shared_timing_port.recv();

        // update world state
        let updated_state = update_world_state(&world_state);
        world_state = updated_state;
        world_state_server.send(world_state.clone());
    }
}
<commit_msg>Fix impl of Clone for WorldState<commit_after>use std;
use extra::comm::DuplexStream;

use player;

struct WorldState {
    player_state: ~player::PlayerState,
    ticks: int,
}

impl WorldState {
    pub fn new(player_state: ~player::PlayerState) -> WorldState {
        WorldState{ticks: 0, player_state: player_state}
    }
}

impl Clone for WorldState {
    fn clone(&self) -> WorldState {
        WorldState{ticks: self.ticks, player_state: self.player_state.clone()}
    }
}

fn update_world_state(world_state: &WorldState) -> WorldState {
    WorldState{ticks: world_state.ticks + 1, player_state: world_state.player_state.clone()}
}

/**
 Loop, updating the world state every time a value is sent on the timing port.
 Upon updating, the new world state is sent on the state server stream.
 */
pub fn world_handler(shared_timing_port: std::comm::SharedPort<()>, player_state: ~player::PlayerState, world_state_server: DuplexStream<WorldState, ()>) {
    let mut world_state = WorldState::new(player_state);

    'world : loop {
        shared_timing_port.recv();

        // update world state
        let updated_state = update_world_state(&world_state);
        world_state = updated_state;
        world_state_server.send(world_state.clone());
    }
}
<|endoftext|>


<commit_before>use crate::{
    core::*,
    domains::Transition,
    fa::{Approximator, Parameterised, QFunction, Features},
    geometry::{MatrixView, MatrixViewMut},
    policies::{
        sample_probs_with_rng,
        DifferentiablePolicy,
        ParameterisedPolicy,
        FinitePolicy,
        Policy
    },
    utils::argmaxima,
};
use ndarray::Axis;
use rand::Rng;
use std::{f64, ops::AddAssign};

fn probabilities_from_values<'a>(values: impl Iterator<Item = &'a f64>, tau: f64) -> Vec<f64> {
    let mut z = 0.0;

    let ps: Vec<f64> = values
        .map(|v| {
            let v = (v / tau).exp();
            z += v;

            v
        })
        .collect();

    ps.into_iter().map(|v| (v / z).min(f64::MAX)).collect()
}

pub type Gibbs<F> = Softmax<F>;

pub struct Softmax<F> {
    fa: F,
    tau: Parameter,
}

impl<F> Softmax<F> {
    pub fn new<T: Into<Parameter>>(fa: F, tau: T) -> Self {
        let tau: Parameter = tau.into();

        if tau.value().abs() < 1e-7 {
            panic!("Tau parameter in Softmax must be non-zero.");
        }

        Softmax {
            fa,
            tau: tau.into(),
        }
    }

    pub fn standard(fa: F) -> Self {
        Self::new(fa, 1.0)
    }

    fn grad_log_phi<S>(&self, phi: &Features, a: usize) -> Matrix<f64>
        where F: QFunction<S>,
    {
        // (A x 1)
        let values = self.fa.evaluate(&phi).unwrap();
        let probabilities = probabilities_from_values(values.into_iter(), self.tau.value());

        // (N x A)
        let mut jac = self.fa.jacobian(&phi);

        // (N x 1)
        let phi = phi.expanded(self.fa.n_features());

        for (mut col, prob) in jac.gencolumns_mut().into_iter().zip(probabilities.into_iter()) {
            col.scaled_add(-prob, &phi);
        }

        jac.column_mut(a).add_assign(&phi);

        jac
    }
}

impl<F> Algorithm for Softmax<F> {
    fn handle_terminal(&mut self) { self.tau = self.tau.step(); }
}

impl<S, F: QFunction<S>> Policy<S> for Softmax<F> {
    type Action = usize;

    fn sample(&self, rng: &mut impl Rng, s: &S) -> usize {
        let ps = self.probabilities(s);

        sample_probs_with_rng(rng, ps.as_slice().unwrap())
    }

    fn mpa(&self, s: &S) -> usize {
        let ps = self.probabilities(s);

        argmaxima(ps.as_slice().unwrap()).1[0]
    }

    fn probability(&self, s: &S, a: &usize) -> f64 { self.probabilities(s)[*a] }
}

impl<S, F: QFunction<S>> FinitePolicy<S> for Softmax<F> {
    fn n_actions(&self) -> usize { self.fa.n_outputs() }

    fn probabilities(&self, s: &S) -> Vector<f64> {
        self.fa
            .evaluate(&self.fa.embed(s))
            .map(|qs| probabilities_from_values(qs.into_iter(), self.tau.value()).into())
            .unwrap()
    }
}

impl<S, F: QFunction<S>> DifferentiablePolicy<S> for Softmax<F> {
    fn grad_log(&self, input: &S, a: &usize) -> Matrix<f64> {
        self.grad_log_phi(&self.fa.embed(input), *a)
    }
}

impl<F: Parameterised> Parameterised for Softmax<F> {
    fn weights(&self) -> Matrix<f64> {
        self.fa.weights()
    }

    fn weights_view(&self) -> MatrixView<f64> {
        self.fa.weights_view()
    }

    fn weights_view_mut(&mut self) -> MatrixViewMut<f64> {
        self.fa.weights_view_mut()
    }
}

impl<S, F: QFunction<S> + Parameterised> ParameterisedPolicy<S> for Softmax<F> {
    fn update(&mut self, input: &S, a: &usize, error: f64) {
        let gl = self.grad_log_phi(&self.fa.embed(input), *a);

        self.fa.weights_view_mut().scaled_add(error, &gl);
    }
}

#[cfg(test)]
mod tests {
    use super::{Algorithm, Softmax, FinitePolicy, ParameterisedPolicy, Parameter, Policy};
    use crate::{
        domains::{Domain, MountainCar},
        fa::{Composable, LFA, basis::fixed::Polynomial, mocking::MockQ},
        geometry::Vector,
    };
    use rand::thread_rng;
    use std::f64::consts::E;

    #[test]
    #[should_panic]
    fn test_0d() {
        let p = Softmax::new(MockQ::new_shared(None), 1.0);

        p.sample(&mut thread_rng(), &vec![].into());
    }

    #[test]
    fn test_1d() {
        let p = Softmax::new(MockQ::new_shared(None), 1.0);
        let mut rng = thread_rng();

        for i in 1..100 {
            assert_eq!(p.sample(&mut rng, &vec![i as f64].into()), 0);
        }
    }

    #[test]
    fn test_2d() {
        let p = Softmax::new(MockQ::new_shared(None), 1.0);
        let mut rng = thread_rng();
        let mut counts = Vector::from_vec(vec![0.0, 0.0]);

        for _ in 0..50000 {
            counts[p.sample(&mut rng, &vec![0.0, 1.0].into())] += 1.0;
        }

        assert!((counts / 50000.0).all_close(
            &Vector::from_vec(vec![1.0 / (1.0 + E), E / (1.0 + E)]),
            1e-2
        ));
    }

    #[test]
    fn test_probabilites_1() {
        let p = Softmax::new(MockQ::new_shared(None), 1.0);

        assert!(&p.probabilities(&vec![0.0, 1.0].into()).all_close(
            &Vector::from_vec(vec![1.0 / (1.0 + E), E / (1.0 + E)]),
            1e-6,
        ));
        assert!(p.probabilities(&vec![0.0, 2.0].into()).all_close(
            &Vector::from_vec(vec![1.0 / (1.0 + E * E), E * E / (1.0 + E * E)]),
            1e-6,
        ));
    }

    #[test]
    fn test_probabilities_2() {
        let fa = LFA::vector(Polynomial::new(1, vec![(0.0, 1.0)]).with_constant(), 3);
        let mut p = Softmax::standard(fa);

        p.update(&vec![0.0], &0, -1.0);
        p.update(&vec![0.0], &1, 1.0);
        p.update(&vec![0.0], &2, -1.0);

        let ps = p.probabilities(&vec![0.0]);

        assert!(ps[0] < ps[1]);
        assert!(ps[2] < ps[1]);
    }

    #[test]
    fn test_terminal() {
        let mut tau = Parameter::exponential(100.0, 1.0, 0.9);
        let mut p = Softmax::new(MockQ::new_shared(None), tau);

        for _ in 0..100 {
            tau = tau.step();
            p.handle_terminal();

            assert_eq!(tau.value(), p.tau.value());
        }
    }
}
<commit_msg>feat(policies): improve stability of Softmax by max-normalisation<commit_after>use crate::{
    core::*,
    domains::Transition,
    fa::{Approximator, Parameterised, QFunction, Features},
    geometry::{MatrixView, MatrixViewMut},
    policies::{
        sample_probs_with_rng,
        DifferentiablePolicy,
        ParameterisedPolicy,
        FinitePolicy,
        Policy
    },
    utils::argmaxima,
};
use ndarray::Axis;
use rand::Rng;
use std::{f64, ops::AddAssign};

fn softmax<'a>(values: &Vector<f64>, tau: f64, c: f64) -> Vec<f64> {
    let mut z = 0.0;

    let ps: Vec<f64> = values
        .into_iter()
        .map(|v| {
            let v = ((v - c) / tau).exp();
            z += v;

            v
        })
        .collect();

    ps.into_iter().map(|v| (v / z).min(f64::MAX)).collect()
}

fn softmax_stable<'a>(values: &Vector<f64>, tau: f64) -> Vec<f64> {
    let max_v = values.iter().fold(f64::NAN, |acc, &v| f64::max(acc, v));

    softmax(values, tau, max_v)
}

pub type Gibbs<F> = Softmax<F>;

pub struct Softmax<F> {
    fa: F,
    tau: Parameter,
}

impl<F> Softmax<F> {
    pub fn new<T: Into<Parameter>>(fa: F, tau: T) -> Self {
        let tau: Parameter = tau.into();

        if tau.value().abs() < 1e-7 {
            panic!("Tau parameter in Softmax must be non-zero.");
        }

        Softmax {
            fa,
            tau: tau.into(),
        }
    }

    pub fn standard(fa: F) -> Self {
        Self::new(fa, 1.0)
    }
}

impl<F> Softmax<F> {
    fn grad_log_phi<S>(&self, phi: &Features, a: usize) -> Matrix<f64>
        where F: QFunction<S>,
    {
        // (A x 1)
        let values = self.fa.evaluate(&phi).unwrap();
        let probabilities = softmax_stable(&values, self.tau.value());

        // (N x A)
        let mut jac = self.fa.jacobian(&phi);

        // (N x 1)
        let phi = phi.expanded(self.fa.n_features());

        for (mut col, prob) in jac.gencolumns_mut().into_iter().zip(probabilities.into_iter()) {
            col.scaled_add(-prob, &phi);
        }

        jac.column_mut(a).add_assign(&phi);

        jac
    }
}

impl<F> Algorithm for Softmax<F> {
    fn handle_terminal(&mut self) { self.tau = self.tau.step(); }
}

impl<S, F: QFunction<S>> Policy<S> for Softmax<F> {
    type Action = usize;

    fn sample(&self, rng: &mut impl Rng, s: &S) -> usize {
        let ps = self.probabilities(s);

        sample_probs_with_rng(rng, ps.as_slice().unwrap())
    }

    fn mpa(&self, s: &S) -> usize {
        let ps = self.probabilities(s);

        argmaxima(ps.as_slice().unwrap()).1[0]
    }

    fn probability(&self, s: &S, a: &usize) -> f64 { self.probabilities(s)[*a] }
}

impl<S, F: QFunction<S>> FinitePolicy<S> for Softmax<F> {
    fn n_actions(&self) -> usize { self.fa.n_outputs() }

    fn probabilities(&self, s: &S) -> Vector<f64> {
        self.fa
            .evaluate(&self.fa.embed(s))
            .map(|qs| softmax_stable(&qs, self.tau.value()).into())
            .unwrap()
    }
}

impl<S, F: QFunction<S>> DifferentiablePolicy<S> for Softmax<F> {
    fn grad_log(&self, input: &S, a: &usize) -> Matrix<f64> {
        self.grad_log_phi(&self.fa.embed(input), *a)
    }
}

impl<F: Parameterised> Parameterised for Softmax<F> {
    fn weights(&self) -> Matrix<f64> {
        self.fa.weights()
    }

    fn weights_view(&self) -> MatrixView<f64> {
        self.fa.weights_view()
    }

    fn weights_view_mut(&mut self) -> MatrixViewMut<f64> {
        self.fa.weights_view_mut()
    }
}

impl<S, F: QFunction<S> + Parameterised> ParameterisedPolicy<S> for Softmax<F> {
    fn update(&mut self, input: &S, a: &usize, error: f64) {
        let gl = self.grad_log_phi(&self.fa.embed(input), *a);

        self.fa.weights_view_mut().scaled_add(error, &gl);
    }
}

#[cfg(test)]
mod tests {
    use super::{Algorithm, Softmax, FinitePolicy, ParameterisedPolicy, Parameter, Policy};
    use crate::{
        domains::{Domain, MountainCar},
        fa::{Composable, LFA, basis::fixed::Polynomial, mocking::MockQ},
        geometry::Vector,
    };
    use rand::thread_rng;
    use std::f64::consts::E;

    #[test]
    #[should_panic]
    fn test_0d() {
        let p = Softmax::new(MockQ::new_shared(None), 1.0);

        p.sample(&mut thread_rng(), &vec![].into());
    }

    #[test]
    fn test_1d() {
        let p = Softmax::new(MockQ::new_shared(None), 1.0);
        let mut rng = thread_rng();

        for i in 1..100 {
            assert_eq!(p.sample(&mut rng, &vec![i as f64].into()), 0);
        }
    }

    #[test]
    fn test_2d() {
        let p = Softmax::new(MockQ::new_shared(None), 1.0);
        let mut rng = thread_rng();
        let mut counts = Vector::from_vec(vec![0.0, 0.0]);

        for _ in 0..50000 {
            counts[p.sample(&mut rng, &vec![0.0, 1.0].into())] += 1.0;
        }

        assert!((counts / 50000.0).all_close(
            &Vector::from_vec(vec![1.0 / (1.0 + E), E / (1.0 + E)]),
            1e-2
        ));
    }

    #[test]
    fn test_probabilites_1() {
        let p = Softmax::new(MockQ::new_shared(None), 1.0);

        assert!(&p.probabilities(&vec![0.0, 1.0].into()).all_close(
            &Vector::from_vec(vec![1.0 / (1.0 + E), E / (1.0 + E)]),
            1e-6,
        ));
        assert!(p.probabilities(&vec![0.0, 2.0].into()).all_close(
            &Vector::from_vec(vec![1.0 / (1.0 + E * E), E * E / (1.0 + E * E)]),
            1e-6,
        ));
    }

    #[test]
    fn test_probabilities_2() {
        let fa = LFA::vector(Polynomial::new(1, vec![(0.0, 1.0)]).with_constant(), 3);
        let mut p = Softmax::standard(fa);

        p.update(&vec![0.0], &0, -1.0);
        p.update(&vec![0.0], &1, 1.0);
        p.update(&vec![0.0], &2, -1.0);

        let ps = p.probabilities(&vec![0.0]);

        assert!(ps[0] < ps[1]);
        assert!(ps[2] < ps[1]);
    }

    #[test]
    fn test_terminal() {
        let mut tau = Parameter::exponential(100.0, 1.0, 0.9);
        let mut p = Softmax::new(MockQ::new_shared(None), tau);

        for _ in 0..100 {
            tau = tau.step();
            p.handle_terminal();

            assert_eq!(tau.value(), p.tau.value());
        }
    }
}
<|endoftext|>


<commit_before>use common::context::*;
use common::scheduler::*;

use graphics::bmp::*;

use programs::common::*;
use programs::editor::*;
use programs::executor::*;
use programs::filemanager::*;
use programs::package::*;
use programs::player::*;
use programs::viewer::*;

pub struct Session {
    pub display: Display,
    pub background: BMP,
    pub cursor: BMP,
    pub icon: BMP,
    pub mouse_point: Point,
    last_mouse_event: MouseEvent,
    pub items: Vec<Box<SessionItem>>,
    pub packages: Vec<Box<Package>>,
    pub windows: Vec<*mut Window>,
    pub windows_ordered: Vec<*mut Window>,
    pub redraw: usize
}

impl Session {
    pub fn new() -> Session {
        unsafe {
            Session {
                display: Display::root(),
                background: BMP::new(),
                cursor: BMP::new(),
                icon: BMP::new(),
                mouse_point: Point::new(0, 0),
                last_mouse_event: MouseEvent {
                    x: 0,
                    y: 0,
                    left_button: false,
                    middle_button: false,
                    right_button: false,
                    valid: false
                },
                items: Vec::new(),
                packages: Vec::new(),
                windows: Vec::new(),
                windows_ordered: Vec::new(),
                redraw: REDRAW_ALL
            }
        }
    }

    pub unsafe fn add_window(&mut self, add_window_ptr: *mut Window){
        self.windows.push(add_window_ptr);
        self.windows_ordered.push(add_window_ptr);
        self.redraw = max(self.redraw, REDRAW_ALL);
    }

    pub unsafe fn remove_window(&mut self, remove_window_ptr: *mut Window){
        let mut i = 0;
        while i < self.windows.len() {
            let mut remove = false;

            match self.windows.get(i) {
                Option::Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                }else{
                    i += 1;
                },
                Option::None => break
            }

            if remove {
                self.windows.remove(i);
            }
        }

        i = 0;
        while i < self.windows_ordered.len() {
            let mut remove = false;

            match self.windows_ordered.get(i) {
                Option::Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                }else{
                    i += 1;
                },
                Option::None => break
            }

            if remove {
                self.windows_ordered.remove(i);
            }
        }

        self.redraw = max(self.redraw, REDRAW_ALL);
    }

    pub unsafe fn on_irq(&mut self, irq: u8){
        for item in self.items.iter() {
            let reenable = start_no_ints();
            item.on_irq(irq);
            end_no_ints(reenable);
        }
    }

    pub unsafe fn on_poll(&mut self){
        for item in self.items.iter() {
            let reenable = start_no_ints();
            item.on_poll();
            end_no_ints(reenable);
        }
    }

    pub fn open(&self, url: &URL) -> Box<Resource>{
        if url.scheme().len() == 0 {
            let mut list = String::new();

            for item in self.items.iter() {
                let scheme = item.scheme();
                if scheme.len() > 0 {
                    if list.len() > 0 {
                        list = list + "\n" + scheme;
                    }else{
                        list = scheme;
                    }
                }
            }

            return box VecResource::new(URL::new(), ResourceType::Dir, list.to_utf8());
        }else{
            for item in self.items.iter() {
                if item.scheme() == url.scheme() {
                    return item.open(url);
                }
            }
            return box NoneResource;
        }
    }

    //TODO: Remove
    fn item_main(&mut self, mut item: Box<SessionItem>, url: URL){
        Context::spawn(box move ||{
            item.main(url);
        });
    }

    fn on_key(&mut self, key_event: KeyEvent){
        if key_event.pressed && key_event.scancode == K_F3 {
            self.item_main(box FileManager::new(), URL::from_str("file:///"));
        }else if self.windows.len() > 0 {
            match self.windows.get(self.windows.len() - 1){
                Option::Some(window_ptr) => {
                    unsafe{
                        (**window_ptr).on_key(key_event);
                        self.redraw = max(self.redraw, REDRAW_ALL);
                    }
                },
                Option::None => ()
            }
        }
    }

    fn on_mouse(&mut self, mouse_event: MouseEvent){
        let mut catcher = -1;

        if mouse_event.y >= self.display.height as isize - 32 {
            if mouse_event.left_button &&  !self.last_mouse_event.left_button {
                let mut x = 0;
                if self.icon.data.len() > 0 {
                    if mouse_event.x >= x && mouse_event.x < x + self.icon.size.width as isize {
                        self.item_main(box FileManager::new(), URL::from_str("file:///"));
                    }
                    x += self.icon.size.width as isize;
                }else{
                    if mouse_event.x >= x && mouse_event.x < x + 16 {
                        self.item_main(box FileManager::new(), URL::from_str("file:///"));
                    }
                    x += 16;
                }

                for package in self.packages.iter() {
                    if package.icon.data.len() > 0 {
                        if mouse_event.x >= x && mouse_event.x < x + package.icon.size.width as isize {
                            d("Launch package ");
                            package.id.d();
                            dl();

                            let url = package.url.clone();
                            let id = package.id.clone();
                            Context::spawn(box move ||{
                                let mut executor = box Executor::new();
                                executor.main(URL::from_string(&(url.to_string() + "/" + &id + ".bin")));
                            });
                        }
                        x += package.icon.size.width as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 && (x as usize + (chars*8 + 3*4) * self.windows.len()) > self.display.width + 32 /* Some Extra */ {
                    chars -= 1;
                }

                x += 4;
                for i in 0..self.windows_ordered.len() {
                    match self.windows_ordered.get(i) {
                        Option::Some(window_ptr) => {
                            let w = (chars*8 + 2*4) as usize;
                            if mouse_event.x >= x && mouse_event.x < x + w as isize {
                                match self.windows_ordered.get(i) {
                                    Option::Some(window_ptr) => unsafe {
                                        for j in 0..self.windows.len() {
                                            match self.windows.get(j){
                                                Option::Some(catcher_window_ptr) => if catcher_window_ptr == window_ptr {
                                                    if j == self.windows.len() - 1 {
                                                        (**window_ptr).minimized = !(**window_ptr).minimized;
                                                    }else{
                                                        catcher = j as isize;
                                                        (**window_ptr).minimized = false;
                                                    }
                                                    break;
                                                },
                                                Option::None => break
                                            }
                                        }
                                        self.redraw = max(self.redraw, REDRAW_ALL);
                                    },
                                    Option::None => ()
                                }
                                break;
                            }
                            x += w as isize;
                        },
                        Option::None => ()
                    }
                }
            }
        }else{
            for reverse_i in 0..self.windows.len() {
                let i = self.windows.len() - 1 - reverse_i;
                match self.windows.get(i){
                    Option::Some(window_ptr) => unsafe{
                        if (**window_ptr).on_mouse(mouse_event, catcher < 0) {
                            catcher = i as isize;

                            self.redraw = max(self.redraw, REDRAW_ALL);
                        }
                    },
                    Option::None => ()
                }
            }
        }

        if catcher >= 0 && catcher < self.windows.len() as isize - 1 {
            match self.windows.remove(catcher as usize){
                Option::Some(window_ptr) => self.windows.push(window_ptr),
                Option::None => ()
            }
        }

        self.last_mouse_event = mouse_event;
    }

    pub unsafe fn redraw(&mut self){
        if self.redraw > REDRAW_NONE {
            if self.redraw >= REDRAW_ALL {
                self.display.set(Color::new(64, 64, 64));
                if self.background.data.len() > 0 {
                    self.background.draw(&self.display, Point::new((self.display.width as isize - self.background.size.width as isize)/2, (self.display.height as isize - self.background.size.height as isize)/2));
                }

                for i in 0..self.windows.len(){
                    match self.windows.get(i) {
                        Option::Some(window_ptr) => {
                            (**window_ptr).focused = i == self.windows.len() - 1;
                            (**window_ptr).draw(&self.display);
                        },
                        Option::None => ()
                    }
                }

                self.display.rect(Point::new(0, self.display.height as isize - 32), Size::new(self.display.width, 32), Color::new(0, 0, 0));

                let mut x = 0;
                if self.icon.data.len() > 0 {
                    self.icon.draw(&self.display, Point::new(x, self.display.height as isize - self.icon.size.height as isize));
                    x += self.icon.size.width as isize;
                }else{
                    self.display.char(Point::new(x + 4, self.display.height as isize - 24), 'R', Color::new(255, 255, 255));
                    x += 16;
                }

                for package in self.packages.iter() {
                    if package.icon.data.len() > 0 {
                        package.icon.draw(&self.display, Point::new(x, self.display.height as isize - package.icon.size.height as isize));
                        x += package.icon.size.width as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 && (x as usize + (chars*8 + 3*4) * self.windows.len()) > self.display.width + 32 /* Some Extra */ {
                    chars -= 1;
                }

                x += 4;
                for i in 0..self.windows_ordered.len() {
                    match self.windows_ordered.get(i) {
                        Option::Some(window_ptr) => {
                            let w = (chars*8 + 2*4) as usize;
                            self.display.rect(Point::new(x, self.display.height as isize - 32), Size::new(w, 32), (**window_ptr).border_color);
                            x += 4;

                            for i in 0..chars {
                                let c = (**window_ptr).title[i];
                                if c != '\0' {
                                    self.display.char(Point::new(x, self.display.height as isize - 24), c, (**window_ptr).title_color);
                                }
                                x += 8;
                            }
                            x += 8;
                        },
                        Option::None => ()
                    }
                }
            }

            let reenable = start_no_ints();

            self.display.flip();

            if self.cursor.data.len() > 0 {
                self.display.image_alpha_onscreen(self.mouse_point, self.cursor.data.as_ptr(), self.cursor.size);
            }else{
                self.display.char_onscreen(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9), 'X', Color::new(255, 255, 255));
            }

            self.redraw = REDRAW_NONE;

            end_no_ints(reenable);
        }
    }

    pub fn event(&mut self, event: Event){
        match event.to_option() {
            EventOption::Mouse(mouse_event) => self.on_mouse(mouse_event),
            EventOption::Key(key_event) => self.on_key(key_event),
            EventOption::Redraw(redraw_event) => self.redraw = max(self.redraw, redraw_event.redraw),
            EventOption::Open(open_event) => {
                let url_string = open_event.url_string;
                let url = URL::from_string(&url_string);

                if url_string.ends_with(".asm".to_string()) || url_string.ends_with(".md".to_string()) || url_string.ends_with(".rs".to_string()) || url_string.ends_with(".sh".to_string()){
                    self.item_main(box Editor::new(), url);
                }else if url_string.ends_with(".bin".to_string()){
                    self.item_main(box Executor::new(), url);
                }else if url_string.ends_with("/".to_string()){
                    self.item_main(box FileManager::new(), url);
                }else if url_string.ends_with(".wav".to_string()){
                    self.item_main(box Player::new(), url);
                }else if url_string.ends_with(".bmp".to_string()){
                    self.item_main(box Viewer::new(), url);
                }else{
                    d("No program found: ");
                    url.d();
                }
            }
            _ => ()
        }
    }
}
<commit_msg>Show package names - at a price<commit_after>use common::context::*;
use common::scheduler::*;

use graphics::bmp::*;

use programs::common::*;
use programs::editor::*;
use programs::executor::*;
use programs::filemanager::*;
use programs::package::*;
use programs::player::*;
use programs::viewer::*;

pub struct Session {
    pub display: Display,
    pub background: BMP,
    pub cursor: BMP,
    pub icon: BMP,
    pub mouse_point: Point,
    last_mouse_event: MouseEvent,
    pub items: Vec<Box<SessionItem>>,
    pub packages: Vec<Box<Package>>,
    pub windows: Vec<*mut Window>,
    pub windows_ordered: Vec<*mut Window>,
    pub redraw: usize
}

impl Session {
    pub fn new() -> Session {
        unsafe {
            Session {
                display: Display::root(),
                background: BMP::new(),
                cursor: BMP::new(),
                icon: BMP::new(),
                mouse_point: Point::new(0, 0),
                last_mouse_event: MouseEvent {
                    x: 0,
                    y: 0,
                    left_button: false,
                    middle_button: false,
                    right_button: false,
                    valid: false
                },
                items: Vec::new(),
                packages: Vec::new(),
                windows: Vec::new(),
                windows_ordered: Vec::new(),
                redraw: REDRAW_ALL
            }
        }
    }

    pub unsafe fn add_window(&mut self, add_window_ptr: *mut Window){
        self.windows.push(add_window_ptr);
        self.windows_ordered.push(add_window_ptr);
        self.redraw = max(self.redraw, REDRAW_ALL);
    }

    pub unsafe fn remove_window(&mut self, remove_window_ptr: *mut Window){
        let mut i = 0;
        while i < self.windows.len() {
            let mut remove = false;

            match self.windows.get(i) {
                Option::Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                }else{
                    i += 1;
                },
                Option::None => break
            }

            if remove {
                self.windows.remove(i);
            }
        }

        i = 0;
        while i < self.windows_ordered.len() {
            let mut remove = false;

            match self.windows_ordered.get(i) {
                Option::Some(window_ptr) => if *window_ptr == remove_window_ptr {
                    remove = true;
                }else{
                    i += 1;
                },
                Option::None => break
            }

            if remove {
                self.windows_ordered.remove(i);
            }
        }

        self.redraw = max(self.redraw, REDRAW_ALL);
    }

    pub unsafe fn on_irq(&mut self, irq: u8){
        for item in self.items.iter() {
            let reenable = start_no_ints();
            item.on_irq(irq);
            end_no_ints(reenable);
        }
    }

    pub unsafe fn on_poll(&mut self){
        for item in self.items.iter() {
            let reenable = start_no_ints();
            item.on_poll();
            end_no_ints(reenable);
        }
    }

    pub fn open(&self, url: &URL) -> Box<Resource>{
        if url.scheme().len() == 0 {
            let mut list = String::new();

            for item in self.items.iter() {
                let scheme = item.scheme();
                if scheme.len() > 0 {
                    if list.len() > 0 {
                        list = list + "\n" + scheme;
                    }else{
                        list = scheme;
                    }
                }
            }

            return box VecResource::new(URL::new(), ResourceType::Dir, list.to_utf8());
        }else{
            for item in self.items.iter() {
                if item.scheme() == url.scheme() {
                    return item.open(url);
                }
            }
            return box NoneResource;
        }
    }

    //TODO: Remove
    fn item_main(&mut self, mut item: Box<SessionItem>, url: URL){
        Context::spawn(box move ||{
            item.main(url);
        });
    }

    fn on_key(&mut self, key_event: KeyEvent){
        if key_event.pressed && key_event.scancode == K_F3 {
            self.item_main(box FileManager::new(), URL::from_str("file:///"));
        }else if self.windows.len() > 0 {
            match self.windows.get(self.windows.len() - 1){
                Option::Some(window_ptr) => {
                    unsafe{
                        (**window_ptr).on_key(key_event);
                        self.redraw = max(self.redraw, REDRAW_ALL);
                    }
                },
                Option::None => ()
            }
        }
    }

    fn on_mouse(&mut self, mouse_event: MouseEvent){
        let mut catcher = -1;

        if mouse_event.y >= self.display.height as isize - 32 {
            if mouse_event.left_button &&  !self.last_mouse_event.left_button {
                let mut x = 0;
                if self.icon.data.len() > 0 {
                    if mouse_event.x >= x && mouse_event.x < x + self.icon.size.width as isize {
                        self.item_main(box FileManager::new(), URL::from_str("file:///"));
                    }
                    x += self.icon.size.width as isize;
                }else{
                    if mouse_event.x >= x && mouse_event.x < x + 16 {
                        self.item_main(box FileManager::new(), URL::from_str("file:///"));
                    }
                    x += 16;
                }

                for package in self.packages.iter() {
                    if package.icon.data.len() > 0 {
                        if mouse_event.x >= x && mouse_event.x < x + package.icon.size.width as isize {
                            d("Launch package ");
                            package.id.d();
                            dl();

                            let url = package.url.clone();
                            let id = package.id.clone();
                            Context::spawn(box move ||{
                                let mut executor = box Executor::new();
                                executor.main(URL::from_string(&(url.to_string() + "/" + &id + ".bin")));
                            });
                        }
                        x += package.icon.size.width as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 && (x as usize + (chars*8 + 3*4) * self.windows.len()) > self.display.width + 32 /* Some Extra */ {
                    chars -= 1;
                }

                x += 4;
                for i in 0..self.windows_ordered.len() {
                    match self.windows_ordered.get(i) {
                        Option::Some(window_ptr) => {
                            let w = (chars*8 + 2*4) as usize;
                            if mouse_event.x >= x && mouse_event.x < x + w as isize {
                                match self.windows_ordered.get(i) {
                                    Option::Some(window_ptr) => unsafe {
                                        for j in 0..self.windows.len() {
                                            match self.windows.get(j){
                                                Option::Some(catcher_window_ptr) => if catcher_window_ptr == window_ptr {
                                                    if j == self.windows.len() - 1 {
                                                        (**window_ptr).minimized = !(**window_ptr).minimized;
                                                    }else{
                                                        catcher = j as isize;
                                                        (**window_ptr).minimized = false;
                                                    }
                                                    break;
                                                },
                                                Option::None => break
                                            }
                                        }
                                        self.redraw = max(self.redraw, REDRAW_ALL);
                                    },
                                    Option::None => ()
                                }
                                break;
                            }
                            x += w as isize;
                        },
                        Option::None => ()
                    }
                }
            }
        }else{
            for reverse_i in 0..self.windows.len() {
                let i = self.windows.len() - 1 - reverse_i;
                match self.windows.get(i){
                    Option::Some(window_ptr) => unsafe{
                        if (**window_ptr).on_mouse(mouse_event, catcher < 0) {
                            catcher = i as isize;

                            self.redraw = max(self.redraw, REDRAW_ALL);
                        }
                    },
                    Option::None => ()
                }
            }
        }

        if catcher >= 0 && catcher < self.windows.len() as isize - 1 {
            match self.windows.remove(catcher as usize){
                Option::Some(window_ptr) => self.windows.push(window_ptr),
                Option::None => ()
            }
        }

        self.last_mouse_event = mouse_event;
    }

    pub unsafe fn redraw(&mut self){
        if self.redraw > REDRAW_NONE {
            //if self.redraw >= REDRAW_ALL {
                self.display.set(Color::new(64, 64, 64));
                if self.background.data.len() > 0 {
                    self.background.draw(&self.display, Point::new((self.display.width as isize - self.background.size.width as isize)/2, (self.display.height as isize - self.background.size.height as isize)/2));
                }

                for i in 0..self.windows.len(){
                    match self.windows.get(i) {
                        Option::Some(window_ptr) => {
                            (**window_ptr).focused = i == self.windows.len() - 1;
                            (**window_ptr).draw(&self.display);
                        },
                        Option::None => ()
                    }
                }

                self.display.rect(Point::new(0, self.display.height as isize - 32), Size::new(self.display.width, 32), Color::new(0, 0, 0));

                let mut x = 0;
                if self.icon.data.len() > 0 {
                    let y = self.display.height as isize - self.icon.size.height as isize;
                    if self.mouse_point.y >= y && self.mouse_point.x >= x && self.mouse_point.x < x + self.icon.size.width as isize {
                        self.display.rect(Point::new(x, y), self.icon.size, Color::new(128, 128, 128));

                        let mut c_x = x;
                        for c in "Start".to_string().chars() {
                            self.display.char(Point::new(c_x, y - 16), c, Color::new(255, 255, 255));
                            c_x += 8;
                        }
                    }
                    self.icon.draw(&self.display, Point::new(x, y));
                    x += self.icon.size.width as isize;
                }else{
                    self.display.char(Point::new(x + 4, self.display.height as isize - 24), 'R', Color::new(255, 255, 255));
                    x += 16;
                }

                for package in self.packages.iter() {
                    if package.icon.data.len() > 0 {
                        let y = self.display.height as isize - package.icon.size.height as isize;
                        if self.mouse_point.y >= y && self.mouse_point.x >= x && self.mouse_point.x < x + package.icon.size.width as isize {
                            self.display.rect(Point::new(x, y), package.icon.size, Color::new(128, 128, 128));

                            let mut c_x = x;
                            for c in package.name.chars() {
                                self.display.char(Point::new(c_x, y - 16), c, Color::new(255, 255, 255));
                                c_x += 8;
                            }
                        }
                        package.icon.draw(&self.display, Point::new(x, y));
                        x += package.icon.size.width as isize;
                    }
                }

                let mut chars = 32;
                while chars > 4 && (x as usize + (chars*8 + 3*4) * self.windows.len()) > self.display.width + 32 /* Some Extra */ {
                    chars -= 1;
                }

                x += 4;
                for window_ptr in self.windows_ordered.iter() {
                    let w = (chars*8 + 2*4) as usize;
                    self.display.rect(Point::new(x, self.display.height as isize - 32), Size::new(w, 32), (**window_ptr).border_color);
                    x += 4;

                    for i in 0..chars {
                        let c = (**window_ptr).title[i];
                        if c != '\0' {
                            self.display.char(Point::new(x, self.display.height as isize - 24), c, (**window_ptr).title_color);
                        }
                        x += 8;
                    }
                    x += 8;
                }

                if self.cursor.data.len() > 0 {
                    self.display.image_alpha(self.mouse_point, self.cursor.data.as_ptr(), self.cursor.size);
                }else{
                    self.display.char(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9), 'X', Color::new(255, 255, 255));
                }
            //}

            let reenable = start_no_ints();

            self.display.flip();

            /*
            if self.cursor.data.len() > 0 {
                self.display.image_alpha_onscreen(self.mouse_point, self.cursor.data.as_ptr(), self.cursor.size);
            }else{
                self.display.char_onscreen(Point::new(self.mouse_point.x - 3, self.mouse_point.y - 9), 'X', Color::new(255, 255, 255));
            }
            */

            self.redraw = REDRAW_NONE;

            end_no_ints(reenable);
        }
    }

    pub fn event(&mut self, event: Event){
        match event.to_option() {
            EventOption::Mouse(mouse_event) => self.on_mouse(mouse_event),
            EventOption::Key(key_event) => self.on_key(key_event),
            EventOption::Redraw(redraw_event) => self.redraw = max(self.redraw, redraw_event.redraw),
            EventOption::Open(open_event) => {
                let url_string = open_event.url_string;
                let url = URL::from_string(&url_string);

                if url_string.ends_with(".asm".to_string()) || url_string.ends_with(".md".to_string()) || url_string.ends_with(".rs".to_string()) || url_string.ends_with(".sh".to_string()){
                    self.item_main(box Editor::new(), url);
                }else if url_string.ends_with(".bin".to_string()){
                    self.item_main(box Executor::new(), url);
                }else if url_string.ends_with("/".to_string()){
                    self.item_main(box FileManager::new(), url);
                }else if url_string.ends_with(".wav".to_string()){
                    self.item_main(box Player::new(), url);
                }else if url_string.ends_with(".bmp".to_string()){
                    self.item_main(box Viewer::new(), url);
                }else{
                    d("No program found: ");
                    url.d();
                }
            }
            _ => ()
        }
    }
}
<|endoftext|>