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

use azure;
use command_line::command_line_init;
use eutil::fptr_is_null;
use libc::{c_int, c_void};
use native;
use servo;
use servo_util::opts;
use std::mem;
use types::{cef_app_t, cef_main_args_t, cef_settings_t};

#[no_mangle]
pub extern "C" fn cef_initialize(args: *cef_main_args_t, settings: *mut cef_settings_t,
                      application: *mut cef_app_t, windows_sandbox_info: *c_void) -> c_int {
    if args.is_null() {
        return 0;
    }
    unsafe {
        command_line_init((*args).argc, (*args).argv);
        let cb = (*application).get_browser_process_handler;
        if !fptr_is_null(mem::transmute(cb)) {
            let handler = cb(application);
            if handler.is_not_null() {
                let hcb = (*handler).on_context_initialized;
                if !fptr_is_null(mem::transmute(hcb)) {
                    hcb(handler);
                }
            }
        }
    }
    return 1
}

#[no_mangle]
pub extern "C" fn cef_shutdown() {
}

#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
    let mut urls = Vec::new();
    urls.push("http://www.w3c-test.org".to_string());
    let opts = opts::Opts {
        urls: urls,
        render_backend: azure::azure_hl::SkiaBackend,
        n_render_threads: 1,
        cpu_painting: false,
        tile_size: 512,
        device_pixels_per_px: None,
        profiler_period: None,
        layout_threads: 1,
        //layout_threads: cmp::max(rt::default_sched_threads() * 3 / 4, 1),
        exit_after_load: false,
        output_file: None,
        headless: false,
        hard_fail: false,
        bubble_widths_separately: false,
    };
    native::start(0, 0 as **u8, proc() {
       servo::run(opts);
    });
}

#[no_mangle]
pub extern "C" fn cef_quit_message_loop() {
}

#[no_mangle]
pub extern "C" fn cef_execute_process(args: *cef_main_args_t, app: *mut cef_app_t, windows_sandbox_info: *mut c_void) -> c_int {
   -1
}
<commit_msg>use a more appropriate embedding url<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use azure;
use command_line::command_line_init;
use eutil::fptr_is_null;
use libc::{c_int, c_void};
use native;
use servo;
use servo_util::opts;
use std::mem;
use types::{cef_app_t, cef_main_args_t, cef_settings_t};

#[no_mangle]
pub extern "C" fn cef_initialize(args: *cef_main_args_t, settings: *mut cef_settings_t,
                      application: *mut cef_app_t, windows_sandbox_info: *c_void) -> c_int {
    if args.is_null() {
        return 0;
    }
    unsafe {
        command_line_init((*args).argc, (*args).argv);
        let cb = (*application).get_browser_process_handler;
        if !fptr_is_null(mem::transmute(cb)) {
            let handler = cb(application);
            if handler.is_not_null() {
                let hcb = (*handler).on_context_initialized;
                if !fptr_is_null(mem::transmute(hcb)) {
                    hcb(handler);
                }
            }
        }
    }
    return 1
}

#[no_mangle]
pub extern "C" fn cef_shutdown() {
}

#[no_mangle]
pub extern "C" fn cef_run_message_loop() {
    let mut urls = Vec::new();
    urls.push("http://s27.postimg.org/vqbtrolyr/servo.jpg".to_string());
    let opts = opts::Opts {
        urls: urls,
        render_backend: azure::azure_hl::SkiaBackend,
        n_render_threads: 1,
        cpu_painting: false,
        tile_size: 512,
        device_pixels_per_px: None,
        profiler_period: None,
        layout_threads: 1,
        //layout_threads: cmp::max(rt::default_sched_threads() * 3 / 4, 1),
        exit_after_load: false,
        output_file: None,
        headless: false,
        hard_fail: false,
        bubble_widths_separately: false,
    };
    native::start(0, 0 as **u8, proc() {
       servo::run(opts);
    });
}

#[no_mangle]
pub extern "C" fn cef_quit_message_loop() {
}

#[no_mangle]
pub extern "C" fn cef_execute_process(args: *cef_main_args_t, app: *mut cef_app_t, windows_sandbox_info: *mut c_void) -> c_int {
   -1
}
<|endoftext|>


<commit_before>use std::io;
use std::result;
use tracker::errors::{Result, ErrorKind};

pub(super) struct Reader {
    data: Vec<u8>,
    idx: usize,
    state: ReadState,
}

enum ReadState {
    ParsingHeaders,
    ParsingResponse,
}

enum ReadRes {
    Done,
    Again,
    Empty,
}

impl ReadState {
    fn ready(&self) -> bool {
        match *self {
            ReadState::ParsingHeaders => false,
            ReadState::ParsingResponse => true,
        }
    }
}

impl Reader {
    pub fn new() -> Reader {
        Reader {
            data: Vec::with_capacity(75),
            idx: 0,
            state: ReadState::ParsingHeaders,
        }
    }

    pub fn readable<R: io::Read>(&mut self, conn: &mut R) -> Result<bool> {
        while let ReadRes::Again = self.read(conn)? { }
        Ok(self.state.ready())
    }

    fn read<R: io::Read>(&mut self, conn: &mut R) -> Result<ReadRes> {
        match conn.read(&mut self.data[self.idx..]) {
            Ok(0) if self.state.ready() => Ok(ReadRes::Done),
            Ok(0) => Err(ErrorKind::EOF.into()),
            Ok(v) => {
                if self.state.ready() {
                    self.idx += v;
                    if self.idx == self.data.len() {
                        self.data.resize(self.idx + 30, 0);
                    }
                } else {
                    for i in 0..v {
                        if self.data[i..i+4] == b"\r\n\r\n"[..] {
                            self.data = self.data.split_off(i+4);
                            self.state = ReadState::ParsingResponse;
                            break;
                        }
                    }
                }
                Ok(ReadRes::Again)
            }
            Err(e) => {
                if e.kind() == io::ErrorKind::WouldBlock {
                    Ok(ReadRes::Empty)
                } else {
                    return Err(ErrorKind::IO.into());
                }
            }
        }
    }

    pub fn consume(self) -> Vec<u8> {
        self.data
    }
}
<commit_msg>Add tests to http parser, fix bugs<commit_after>use std::io;
use tracker::errors::{Result, ErrorKind};

pub(super) struct Reader {
    data: Vec<u8>,
    idx: usize,
    state: ReadState,
}

enum ReadState {
    ParsingHeaders,
    ParsingResponse,
}

enum ReadRes {
    Done,
    Again,
    Empty,
}

impl ReadState {
    fn ready(&self) -> bool {
        match *self {
            ReadState::ParsingHeaders => false,
            ReadState::ParsingResponse => true,
        }
    }
}

impl Reader {
    pub fn new() -> Reader {
        Reader {
            data: vec![0; 50],
            idx: 0,
            state: ReadState::ParsingHeaders,
        }
    }

    pub fn readable<R: io::Read>(&mut self, conn: &mut R) -> Result<bool> {
        while let ReadRes::Again = self.read(conn)? { }
        Ok(self.state.ready())
    }

    fn read<R: io::Read>(&mut self, conn: &mut R) -> Result<ReadRes> {
        match conn.read(&mut self.data[self.idx..]) {
            Ok(0) if self.state.ready() => Ok(ReadRes::Done),
            Ok(0) => Err(ErrorKind::EOF.into()),
            Ok(v) => {
                if self.state.ready() {
                    self.idx += v;
                } else {
                    for i in 0..(v-3) {
                        if self.data[i..i+4] == b"\r\n\r\n"[..] {
                            self.data = self.data.split_off(i+4);
                            self.idx = v - (i + 4);
                            self.state = ReadState::ParsingResponse;
                            break;
                        }
                    }
                }
                if self.idx == self.data.len() {
                    self.data.resize(self.idx + 30, 0);
                }
                Ok(ReadRes::Again)
            }
            Err(e) => {
                if e.kind() == io::ErrorKind::WouldBlock {
                    Ok(ReadRes::Empty)
                } else {
                    return Err(ErrorKind::IO.into());
                }
            }
        }
    }

    pub fn consume(mut self) -> Vec<u8> {
        self.data.truncate(self.idx);
        self.data
    }
}

#[cfg(test)]
mod tests {
    use super::Reader;
    use std::io::Cursor;

    #[test]
    fn test_empty_resp() {
        let mut r = Reader::new();
        let data = "SomeHeader: Foo\r\nConnection: Close\r\n\r\n";
        let mut c = Cursor::new(data);
        assert_eq!(r.readable(&mut c).unwrap(), true);
        assert_eq!(r.consume(), Vec::<u8>::new());
    }

    #[test]
    fn test_premature_resp() {
        let mut r = Reader::new();
        let data = "SomeHeader: Foo\r\nConnection: C";
        let mut c = Cursor::new(data);
        assert_eq!(r.readable(&mut c).is_err(), true);
    }

    #[test]
    fn test_valid_resp() {
        let mut r = Reader::new();
        let data = "SomeHeader: Foo\r\nConnection: Close\r\n\r\nhello world spam";
        let mut c = Cursor::new(data);
        assert_eq!(r.readable(&mut c).unwrap(), true);
        assert_eq!(r.consume(), b"hello world spam");
    }
}
<|endoftext|>


<commit_before>extern crate cbor;
extern crate rustc_serialize;
extern crate secstr;
extern crate rusterpassword;
extern crate libc;
extern crate libsodium_sys as sodium;
extern crate sodiumoxide;
extern crate chrono;

use secstr::SecStr;
use rusterpassword::gen_site_seed;
use chrono::{DateTime, UTC};
use cbor::{Encoder, Decoder, CborError};
use libc::size_t;
use std::collections::btree_map::{BTreeMap, Keys};
use sodiumoxide::crypto::secretbox::xsalsa20poly1305 as secbox;

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Vault {
    pub version: u16,
    pub padding: Vec<u8>,
    pub entries: BTreeMap<String, EncryptedEntry>,
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub struct EncryptedEntry {
    pub nonce: Vec<u8>,
    pub counter: u32,
    pub ciphertext: Vec<u8>,
    pub metadata: EntryMetadata,
}

#[derive(PartialEq, Clone, Debug, RustcDecodable, RustcEncodable)]
pub struct EntryMetadata {
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub tags: Vec<String>,
}

impl EntryMetadata {
    pub fn new() -> EntryMetadata {
        EntryMetadata {
            created_at: UTC::now(),
            updated_at: UTC::now(),
            tags: Vec::new(),
        }
    }
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub struct Entry {
    pub fields: BTreeMap<String, Field>
}

impl Entry {
    pub fn new() -> Entry {
        Entry { fields: BTreeMap::new() }
    }
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum Field {
    Derived { counter: u32, site_name: Option<String>, usage: DerivedUsage },
    Stored { data: SecStr, usage: StoredUsage }
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum DerivedUsage {
    Password(PasswordTemplate)
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum StoredUsage {
    Password
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum PasswordTemplate {
    // Same numbers as in the rusterpassword C API
    Maximum = 60,
    Long    = 50,
    Medium  = 40,
    Short   = 30,
    Basic   = 20,
    Pin     = 10,
}

#[derive(Debug)]
pub enum EntryError {
    WrongEntriesKeyLength,
    WrongNonceLength,
    SeedGenerationError,
    DecryptionError,
    CodecError(CborError),
    DataError,
    EntryNotFound,
}

impl From<CborError> for EntryError {
    fn from(err: CborError) -> EntryError {
        EntryError::CodecError(err)
    }
}

pub type EntryResult<T> = Result<T, EntryError>;

impl Vault {

    pub fn entry_names(&self) -> Keys<String, EncryptedEntry> {
        self.entries.keys()
    }

    pub fn get_entry(&self, entries_key: &SecStr, name: &str) -> EntryResult<(Entry, EntryMetadata)> {
        if let Some(ee) = self.entries.get(name) {
            let nonce_wrapped = try!(secbox::Nonce::from_slice(&ee.nonce).ok_or(EntryError::WrongNonceLength));
            let entry_key_wrapped = try!(gen_entry_key(entries_key, name, ee.counter));
            let plaintext = SecStr::new(try!(secbox::open(&ee.ciphertext, &nonce_wrapped, &entry_key_wrapped).map_err(|_| EntryError::DecryptionError)));
            let entry = try!(try!(Decoder::from_bytes(plaintext.unsecure()).decode::<Entry>().next().ok_or(EntryError::DataError)));
            Ok((entry, ee.metadata.clone()))
        } else {
            Err(EntryError::EntryNotFound)
        }
    }

    pub fn put_entry(&mut self, entries_key: &SecStr, name: &str, entry: &Entry, metadata: &mut EntryMetadata) -> EntryResult<()> {
        let counter = self.entries.get(name).map(|ee| ee.counter + 1).unwrap_or(1);
        let nonce_wrapped = secbox::gen_nonce();
        let secbox::Nonce(nonce) = nonce_wrapped;
        let entry_key_wrapped = try!(gen_entry_key(entries_key, name, counter));
        let mut e = Encoder::from_memory();
        try!(e.encode(&[&*entry]));
        let plaintext = SecStr::new(e.into_bytes());
        let ciphertext = secbox::seal(plaintext.unsecure(), &nonce_wrapped, &entry_key_wrapped);
        metadata.updated_at = UTC::now();
        self.entries.insert(name.to_owned(), EncryptedEntry {
            nonce: nonce.to_vec(), counter: counter, ciphertext: ciphertext, metadata: metadata.clone()
        });
        Ok(())
    }

}

fn gen_entry_key(entries_key: &SecStr, name: &str, counter: u32) -> EntryResult<secbox::Key> {
    let entry_key = try!(gen_site_seed(entries_key, name, counter).map_err(|_| EntryError::SeedGenerationError));
    Ok(try!(secbox::Key::from_slice(entry_key.unsecure()).ok_or(EntryError::WrongEntriesKeyLength)))
}

pub fn gen_entries_key(master_key: &SecStr) -> SecStr {
    let mut msg = vec![];
    msg.extend(b"technology.unrelenting.freepass");
    let mut dst = Vec::<u8>::with_capacity(64);
    unsafe {
        sodium::crypto_generichash_blake2b(
            dst.as_mut_ptr() as *mut u8, 64,
            msg.as_ptr(), msg.len() as u64,
            master_key.unsecure().as_ptr() as *const u8,
            master_key.unsecure().len() as size_t);
        dst.set_len(64);
    }
    SecStr::new(dst)
}

#[cfg(test)]
mod tests {
    use super::*;
    use secstr::*;
    use rusterpassword::*;
    use std::collections::btree_map::BTreeMap;

    #[test]
    fn test_roundtrip_entry() {
        let mut fs = BTreeMap::new();
        fs.insert("password".to_owned(), Field::Derived { counter: 4, site_name: Some("twitter.com".to_owned()), usage: DerivedUsage::Password(PasswordTemplate::Maximum) });
        fs.insert("old_password".to_owned(), Field::Stored { data: SecStr::from("h0rse"), usage: StoredUsage::Password });
        let twitter = Entry { fields: fs };
        let mut metadata = EntryMetadata::new();
        let mut vault = Vault { version: 0, padding: b"".to_vec(), entries: BTreeMap::new() };
        let master_key = gen_master_key(SecStr::from("Correct Horse Battery Staple"), "Clarke Griffin").unwrap();
        let entries_key = gen_entries_key(&master_key);
        vault.put_entry(&entries_key, "twitter", &twitter, &mut metadata).unwrap();
        assert!(vault.get_entry(&entries_key, "twitter").unwrap() == (twitter, metadata));
    }
}
<commit_msg>test use new<commit_after>extern crate cbor;
extern crate rustc_serialize;
extern crate secstr;
extern crate rusterpassword;
extern crate libc;
extern crate libsodium_sys as sodium;
extern crate sodiumoxide;
extern crate chrono;

use secstr::SecStr;
use rusterpassword::gen_site_seed;
use chrono::{DateTime, UTC};
use cbor::{Encoder, Decoder, CborError};
use libc::size_t;
use std::collections::btree_map::{BTreeMap, Keys};
use sodiumoxide::crypto::secretbox::xsalsa20poly1305 as secbox;

#[derive(Debug, RustcDecodable, RustcEncodable)]
pub struct Vault {
    pub version: u16,
    pub padding: Vec<u8>,
    pub entries: BTreeMap<String, EncryptedEntry>,
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub struct EncryptedEntry {
    pub nonce: Vec<u8>,
    pub counter: u32,
    pub ciphertext: Vec<u8>,
    pub metadata: EntryMetadata,
}

#[derive(PartialEq, Clone, Debug, RustcDecodable, RustcEncodable)]
pub struct EntryMetadata {
    pub created_at: DateTime<UTC>,
    pub updated_at: DateTime<UTC>,
    pub tags: Vec<String>,
}

impl EntryMetadata {
    pub fn new() -> EntryMetadata {
        EntryMetadata {
            created_at: UTC::now(),
            updated_at: UTC::now(),
            tags: Vec::new(),
        }
    }
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub struct Entry {
    pub fields: BTreeMap<String, Field>
}

impl Entry {
    pub fn new() -> Entry {
        Entry { fields: BTreeMap::new() }
    }
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum Field {
    Derived { counter: u32, site_name: Option<String>, usage: DerivedUsage },
    Stored { data: SecStr, usage: StoredUsage }
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum DerivedUsage {
    Password(PasswordTemplate)
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum StoredUsage {
    Password
}

#[derive(PartialEq, Debug, RustcDecodable, RustcEncodable)]
pub enum PasswordTemplate {
    // Same numbers as in the rusterpassword C API
    Maximum = 60,
    Long    = 50,
    Medium  = 40,
    Short   = 30,
    Basic   = 20,
    Pin     = 10,
}

#[derive(Debug)]
pub enum EntryError {
    WrongEntriesKeyLength,
    WrongNonceLength,
    SeedGenerationError,
    DecryptionError,
    CodecError(CborError),
    DataError,
    EntryNotFound,
}

impl From<CborError> for EntryError {
    fn from(err: CborError) -> EntryError {
        EntryError::CodecError(err)
    }
}

pub type EntryResult<T> = Result<T, EntryError>;

impl Vault {

    pub fn entry_names(&self) -> Keys<String, EncryptedEntry> {
        self.entries.keys()
    }

    pub fn get_entry(&self, entries_key: &SecStr, name: &str) -> EntryResult<(Entry, EntryMetadata)> {
        if let Some(ee) = self.entries.get(name) {
            let nonce_wrapped = try!(secbox::Nonce::from_slice(&ee.nonce).ok_or(EntryError::WrongNonceLength));
            let entry_key_wrapped = try!(gen_entry_key(entries_key, name, ee.counter));
            let plaintext = SecStr::new(try!(secbox::open(&ee.ciphertext, &nonce_wrapped, &entry_key_wrapped).map_err(|_| EntryError::DecryptionError)));
            let entry = try!(try!(Decoder::from_bytes(plaintext.unsecure()).decode::<Entry>().next().ok_or(EntryError::DataError)));
            Ok((entry, ee.metadata.clone()))
        } else {
            Err(EntryError::EntryNotFound)
        }
    }

    pub fn put_entry(&mut self, entries_key: &SecStr, name: &str, entry: &Entry, metadata: &mut EntryMetadata) -> EntryResult<()> {
        let counter = self.entries.get(name).map(|ee| ee.counter + 1).unwrap_or(1);
        let nonce_wrapped = secbox::gen_nonce();
        let secbox::Nonce(nonce) = nonce_wrapped;
        let entry_key_wrapped = try!(gen_entry_key(entries_key, name, counter));
        let mut e = Encoder::from_memory();
        try!(e.encode(&[&*entry]));
        let plaintext = SecStr::new(e.into_bytes());
        let ciphertext = secbox::seal(plaintext.unsecure(), &nonce_wrapped, &entry_key_wrapped);
        metadata.updated_at = UTC::now();
        self.entries.insert(name.to_owned(), EncryptedEntry {
            nonce: nonce.to_vec(), counter: counter, ciphertext: ciphertext, metadata: metadata.clone()
        });
        Ok(())
    }

}

fn gen_entry_key(entries_key: &SecStr, name: &str, counter: u32) -> EntryResult<secbox::Key> {
    let entry_key = try!(gen_site_seed(entries_key, name, counter).map_err(|_| EntryError::SeedGenerationError));
    Ok(try!(secbox::Key::from_slice(entry_key.unsecure()).ok_or(EntryError::WrongEntriesKeyLength)))
}

pub fn gen_entries_key(master_key: &SecStr) -> SecStr {
    let mut msg = vec![];
    msg.extend(b"technology.unrelenting.freepass");
    let mut dst = Vec::<u8>::with_capacity(64);
    unsafe {
        sodium::crypto_generichash_blake2b(
            dst.as_mut_ptr() as *mut u8, 64,
            msg.as_ptr(), msg.len() as u64,
            master_key.unsecure().as_ptr() as *const u8,
            master_key.unsecure().len() as size_t);
        dst.set_len(64);
    }
    SecStr::new(dst)
}

#[cfg(test)]
mod tests {
    use super::*;
    use secstr::*;
    use rusterpassword::*;
    use std::collections::btree_map::BTreeMap;

    #[test]
    fn test_roundtrip_entry() {
        let mut twitter = Entry::new();
        twitter.fields.insert("password".to_owned(), Field::Derived {
            counter: 4, site_name: Some("twitter.com".to_owned()), usage: DerivedUsage::Password(PasswordTemplate::Maximum)
        });
        twitter.fields.insert("old_password".to_owned(), Field::Stored {
            data: SecStr::from("h0rse"), usage: StoredUsage::Password
        });
        let mut metadata = EntryMetadata::new();
        let mut vault = Vault { version: 0, padding: b"".to_vec(), entries: BTreeMap::new() };
        let master_key = gen_master_key(SecStr::from("Correct Horse Battery Staple"), "Clarke Griffin").unwrap();
        let entries_key = gen_entries_key(&master_key);
        vault.put_entry(&entries_key, "twitter", &twitter, &mut metadata).unwrap();
        assert!(vault.get_entry(&entries_key, "twitter").unwrap() == (twitter, metadata));
    }
}
<|endoftext|>


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

/// Liberally derived from the [Firefox JS implementation]
/// (http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/root.js).
/// Connection point for all new remote devtools interactions, providing lists of know actors
/// that perform more specific actions (tabs, addons, browser chrome, etc.)

use actor::{Actor, ActorMessageStatus, ActorRegistry};
use actors::tab::{TabActor, TabActorMsg};
use protocol::JsonPacketStream;
use rustc_serialize::json;
use std::net::TcpStream;

#[derive(RustcEncodable)]
struct ActorTraits {
    sources: bool,
    highlightable: bool,
    customHighlighters: Vec<String>,
}

#[derive(RustcEncodable)]
struct ErrorReply {
    from: String,
    error: String,
    message: String,
}

#[derive(RustcEncodable)]
struct ListTabsReply {
    from: String,
    selected: u32,
    tabs: Vec<TabActorMsg>,
}

#[derive(RustcEncodable)]
pub struct RootActorMsg {
    from: String,
    applicationType: String,
    traits: ActorTraits,
}

pub struct RootActor {
    pub tabs: Vec<String>,
}

impl Actor for RootActor {
    fn name(&self) -> String {
        "root".to_owned()
    }

    fn handle_message(&self,
                      registry: &ActorRegistry,
                      msg_type: &str,
                      _msg: &json::Object,
                      stream: &mut TcpStream) -> Result<ActorMessageStatus, ()> {
        Ok(match msg_type {
            "listAddons" => {
                let actor = ErrorReply {
                    from: "root".to_owned(),
                    error: "noAddons".to_owned(),
                    message: "This root actor has no browser addons.".to_owned(),
                };
                stream.write_json_packet(&actor);
                ActorMessageStatus::Processed
            }

            //https://wiki.mozilla.org/Remote_Debugging_Protocol#Listing_Browser_Tabs
            "listTabs" => {
                let actor = ListTabsReply {
                    from: "root".to_owned(),
                    selected: 0,
                    tabs: self.tabs.iter().map(|tab| {
                        registry.find::<TabActor>(tab).encodable()
                    }).collect()
                };
                stream.write_json_packet(&actor);
                ActorMessageStatus::Processed
            }

            _ => ActorMessageStatus::Ignored
        })
    }
}

impl RootActor {
    pub fn encodable(&self) -> RootActorMsg {
        RootActorMsg {
            from: "root".to_owned(),
            applicationType: "browser".to_owned(),
            traits: ActorTraits {
                sources: true,
                highlightable: true,
                customHighlighters: vec!("BoxModelHighlighter".to_owned()),
            },
        }
    }
}
<commit_msg>Properly return an empty list in devtools' listAddons<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/// Liberally derived from the [Firefox JS implementation]
/// (http://mxr.mozilla.org/mozilla-central/source/toolkit/devtools/server/actors/root.js).
/// Connection point for all new remote devtools interactions, providing lists of know actors
/// that perform more specific actions (tabs, addons, browser chrome, etc.)

use actor::{Actor, ActorMessageStatus, ActorRegistry};
use actors::tab::{TabActor, TabActorMsg};
use protocol::JsonPacketStream;
use rustc_serialize::json;
use std::net::TcpStream;

#[derive(RustcEncodable)]
struct ActorTraits {
    sources: bool,
    highlightable: bool,
    customHighlighters: Vec<String>,
}

#[derive(RustcEncodable)]
struct ListAddonsReply {
    from: String,
    addons: Vec<AddonMsg>,
}

#[derive(RustcEncodable)]
enum AddonMsg {}

#[derive(RustcEncodable)]
struct ListTabsReply {
    from: String,
    selected: u32,
    tabs: Vec<TabActorMsg>,
}

#[derive(RustcEncodable)]
pub struct RootActorMsg {
    from: String,
    applicationType: String,
    traits: ActorTraits,
}

pub struct RootActor {
    pub tabs: Vec<String>,
}

impl Actor for RootActor {
    fn name(&self) -> String {
        "root".to_owned()
    }

    fn handle_message(&self,
                      registry: &ActorRegistry,
                      msg_type: &str,
                      _msg: &json::Object,
                      stream: &mut TcpStream) -> Result<ActorMessageStatus, ()> {
        Ok(match msg_type {
            "listAddons" => {
                let actor = ListAddonsReply {
                    from: "root".to_owned(),
                    addons: vec![],
                };
                stream.write_json_packet(&actor);
                ActorMessageStatus::Processed
            }

            //https://wiki.mozilla.org/Remote_Debugging_Protocol#Listing_Browser_Tabs
            "listTabs" => {
                let actor = ListTabsReply {
                    from: "root".to_owned(),
                    selected: 0,
                    tabs: self.tabs.iter().map(|tab| {
                        registry.find::<TabActor>(tab).encodable()
                    }).collect()
                };
                stream.write_json_packet(&actor);
                ActorMessageStatus::Processed
            }

            _ => ActorMessageStatus::Ignored
        })
    }
}

impl RootActor {
    pub fn encodable(&self) -> RootActorMsg {
        RootActorMsg {
            from: "root".to_owned(),
            applicationType: "browser".to_owned(),
            traits: ActorTraits {
                sources: true,
                highlightable: true,
                customHighlighters: vec!("BoxModelHighlighter".to_owned()),
            },
        }
    }
}
<|endoftext|>


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

use dom::bindings::codegen::Bindings::DOMParserBinding;
use dom::bindings::codegen::Bindings::DOMParserBinding::DOMParserMethods;
use dom::bindings::codegen::Bindings::DOMParserBinding::SupportedTypeValues::{Text_html, Text_xml};
use dom::bindings::error::{Fallible, FailureUnknown};
use dom::bindings::global::GlobalRef;
use dom::bindings::global;
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflector, Reflectable, reflect_dom_object};
use dom::document::{Document, HTMLDocument, NonHTMLDocument, NotFromParser};
use dom::window::Window;
use servo_util::str::DOMString;

#[dom_struct]
pub struct DOMParser {
    window: JS<Window>, //XXXjdm Document instead?
    reflector_: Reflector
}

impl DOMParser {
    fn new_inherited(window: JSRef<Window>) -> DOMParser {
        DOMParser {
            window: JS::from_rooted(window),
            reflector_: Reflector::new()
        }
    }

    pub fn new(window: JSRef<Window>) -> Temporary<DOMParser> {
        reflect_dom_object(box DOMParser::new_inherited(window), global::Window(window),
                           DOMParserBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef) -> Fallible<Temporary<DOMParser>> {
        Ok(DOMParser::new(global.as_window()))
    }
}

impl<'a> DOMParserMethods for JSRef<'a, DOMParser> {
    fn ParseFromString(self,
                       _s: DOMString,
                       ty: DOMParserBinding::SupportedType)
                       -> Fallible<Temporary<Document>> {
        let window = self.window.root();
        //FIXME: these should probably be FromParser when we actually parse the string (#3756).
        match ty {
            Text_html => {
                Ok(Document::new(*window, None, HTMLDocument, Some("text/html".to_string()),
                                 NotFromParser))
            }
            Text_xml => {
                Ok(Document::new(*window, None, NonHTMLDocument, Some("text/xml".to_string()),
                                 NotFromParser))
            }
            _ => {
                Err(FailureUnknown)
            }
        }
    }
}

impl Reflectable for DOMParser {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }
}
<commit_msg>auto merge of #4297 : ChrisParis/servo/parse, r=Ms2ger<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::DocumentBinding::DocumentReadyStateValues;
use dom::bindings::codegen::Bindings::DOMParserBinding;
use dom::bindings::codegen::Bindings::DOMParserBinding::DOMParserMethods;
use dom::bindings::codegen::Bindings::DOMParserBinding::SupportedTypeValues::{Text_html, Text_xml};
use dom::bindings::error::{Fallible, FailureUnknown};
use dom::bindings::global::GlobalRef;
use dom::bindings::global;
use dom::bindings::js::{JS, JSRef, Temporary};
use dom::bindings::utils::{Reflector, Reflectable, reflect_dom_object};
use dom::document::{Document, DocumentHelpers, HTMLDocument, NonHTMLDocument};
use dom::document::{FromParser, NotFromParser};
use dom::servohtmlparser::ServoHTMLParser;
use dom::window::Window;
use parse::Parser;
use servo_util::str::DOMString;

#[dom_struct]
pub struct DOMParser {
    window: JS<Window>, //XXXjdm Document instead?
    reflector_: Reflector
}

impl DOMParser {
    fn new_inherited(window: JSRef<Window>) -> DOMParser {
        DOMParser {
            window: JS::from_rooted(window),
            reflector_: Reflector::new()
        }
    }

    pub fn new(window: JSRef<Window>) -> Temporary<DOMParser> {
        reflect_dom_object(box DOMParser::new_inherited(window), global::Window(window),
                           DOMParserBinding::Wrap)
    }

    pub fn Constructor(global: &GlobalRef) -> Fallible<Temporary<DOMParser>> {
        Ok(DOMParser::new(global.as_window()))
    }
}

impl<'a> DOMParserMethods for JSRef<'a, DOMParser> {
    // http://domparsing.spec.whatwg.org/#the-domparser-interface
    fn ParseFromString(self,
                       s: DOMString,
                       ty: DOMParserBinding::SupportedType)
                       -> Fallible<Temporary<Document>> {
        let window = self.window.root().clone();
        let url = Some(window.get_url());
        let content_type = DOMParserBinding::SupportedTypeValues::strings[ty as uint].to_string();
        match ty {
            Text_html => {
                let document = Document::new(window, url.clone(), HTMLDocument,
                                             Some(content_type), FromParser).root().clone();
                let parser = ServoHTMLParser::new(url.clone(), document).root().clone();
                parser.parse_chunk(s);
                parser.finish();
                document.set_ready_state(DocumentReadyStateValues::Complete);
                Ok(Temporary::from_rooted(document))
            }
            Text_xml => {
                //FIXME: this should probably be FromParser when we actually parse the string (#3756).
                Ok(Document::new(window, url.clone(), NonHTMLDocument, Some(content_type),
                                 NotFromParser))
            }
            _ => {
                Err(FailureUnknown)
            }
        }
    }
}

impl Reflectable for DOMParser {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        &self.reflector_
    }
}
<|endoftext|>


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

//! Different checks done during the style sharing process in order to determine
//! quickly whether it's worth to share style, and whether two different
//! elements can indeed share the same style.

use bloom::StyleBloom;
use context::{SelectorFlagsMap, SharedStyleContext};
use dom::TElement;
use selectors::NthIndexCache;
use sharing::{StyleSharingCandidate, StyleSharingTarget};

/// Determines whether a target and a candidate have compatible parents for sharing.
pub fn parents_allow_sharing<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>
) -> bool
    where E: TElement,
{
    // If the identity of the parent style isn't equal, we can't share. We check
    // this first, because the result is cached.
    if target.parent_style_identity() != candidate.parent_style_identity() {
        return false;
    }

    // Siblings can always share.
    let parent = target.inheritance_parent().unwrap();
    let candidate_parent = candidate.element.inheritance_parent().unwrap();
    if parent == candidate_parent {
        return true;
    }

    // Cousins are a bit more complicated.
    //
    // If a parent element was already styled and we traversed past it without
    // restyling it, that may be because our clever invalidation logic was able
    // to prove that the styles of that element would remain unchanged despite
    // changes to the id or class attributes. However, style sharing relies in
    // the strong guarantee that all the classes and ids up the respective parent
    // chains are identical. As such, if we skipped styling for one (or both) of
    // the parents on this traversal, we can't share styles across cousins.
    //
    // This is a somewhat conservative check. We could tighten it by having the
    // invalidation logic explicitly flag elements for which it ellided styling.
    let parent_data = parent.borrow_data().unwrap();
    let candidate_parent_data = candidate_parent.borrow_data().unwrap();
    if !parent_data.safe_for_cousin_sharing() || !candidate_parent_data.safe_for_cousin_sharing() {
        return false;
    }

    true
}

/// Whether two elements have the same same style attribute (by pointer identity).
pub fn have_same_style_attribute<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>
) -> bool
    where E: TElement,
{
    match (target.style_attribute(), candidate.style_attribute()) {
        (None, None) => true,
        (Some(_), None) | (None, Some(_)) => false,
        (Some(a), Some(b)) => &*a as *const _ == &*b as *const _
    }
}

/// Whether two elements have the same same presentational attributes.
pub fn have_same_presentational_hints<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>
) -> bool
    where E: TElement,
{
    target.pres_hints() == candidate.pres_hints()
}

/// Whether a given element has the same class attribute than a given candidate.
///
/// We don't try to share style across elements with different class attributes.
pub fn have_same_class<E>(target: &mut StyleSharingTarget<E>,
                          candidate: &mut StyleSharingCandidate<E>)
                          -> bool
    where E: TElement,
{
    target.class_list() == candidate.class_list()
}

/// Whether a given element and a candidate match the same set of "revalidation"
/// selectors.
///
/// Revalidation selectors are those that depend on the DOM structure, like
/// :first-child, etc, or on attributes that we don't check off-hand (pretty
/// much every attribute selector except `id` and `class`.
#[inline]
pub fn revalidate<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>,
    shared_context: &SharedStyleContext,
    bloom: &StyleBloom<E>,
    nth_index_cache: &mut NthIndexCache,
    selector_flags_map: &mut SelectorFlagsMap<E>,
) -> bool
where
    E: TElement,
{
    let stylist = &shared_context.stylist;

    let for_element = target.revalidation_match_results(
        stylist,
        bloom,
        nth_index_cache,
        selector_flags_map,
    );

    let for_candidate = candidate.revalidation_match_results(
        stylist,
        bloom,
        nth_index_cache,
    );

    // This assert "ensures", to some extent, that the two candidates have
    // matched the same rulehash buckets, and as such, that the bits we're
    // comparing represent the same set of selectors.
    debug_assert_eq!(for_element.len(), for_candidate.len());

    for_element == for_candidate
}

/// Checks whether we might have rules for either of the two ids.
#[inline]
pub fn may_match_different_id_rules<E>(
    shared_context: &SharedStyleContext,
    element: E,
    candidate: E,
) -> bool
where
    E: TElement,
{
    let element_id = element.get_id();
    let candidate_id = candidate.get_id();

    if element_id == candidate_id {
        return false;
    }

    let stylist = &shared_context.stylist;

    let may_have_rules_for_element = match element_id {
        Some(ref id) => stylist.may_have_rules_for_id(id, element),
        None => false
    };

    if may_have_rules_for_element {
        return true;
    }

    match candidate_id {
        Some(ref id) => stylist.may_have_rules_for_id(id, candidate),
        None => false
    }
}
<commit_msg>style: Sharing formatting nits.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Different checks done during the style sharing process in order to determine
//! quickly whether it's worth to share style, and whether two different
//! elements can indeed share the same style.

use bloom::StyleBloom;
use context::{SelectorFlagsMap, SharedStyleContext};
use dom::TElement;
use selectors::NthIndexCache;
use sharing::{StyleSharingCandidate, StyleSharingTarget};

/// Determines whether a target and a candidate have compatible parents for
/// sharing.
pub fn parents_allow_sharing<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>
) -> bool
where
    E: TElement,
{
    // If the identity of the parent style isn't equal, we can't share. We check
    // this first, because the result is cached.
    if target.parent_style_identity() != candidate.parent_style_identity() {
        return false;
    }

    // Siblings can always share.
    let parent = target.inheritance_parent().unwrap();
    let candidate_parent = candidate.element.inheritance_parent().unwrap();
    if parent == candidate_parent {
        return true;
    }

    // Cousins are a bit more complicated.
    //
    // If a parent element was already styled and we traversed past it without
    // restyling it, that may be because our clever invalidation logic was able
    // to prove that the styles of that element would remain unchanged despite
    // changes to the id or class attributes. However, style sharing relies in
    // the strong guarantee that all the classes and ids up the respective parent
    // chains are identical. As such, if we skipped styling for one (or both) of
    // the parents on this traversal, we can't share styles across cousins.
    //
    // This is a somewhat conservative check. We could tighten it by having the
    // invalidation logic explicitly flag elements for which it ellided styling.
    let parent_data = parent.borrow_data().unwrap();
    let candidate_parent_data = candidate_parent.borrow_data().unwrap();
    if !parent_data.safe_for_cousin_sharing() || !candidate_parent_data.safe_for_cousin_sharing() {
        return false;
    }

    true
}

/// Whether two elements have the same same style attribute (by pointer identity).
pub fn have_same_style_attribute<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>
) -> bool
where
    E: TElement,
{
    match (target.style_attribute(), candidate.style_attribute()) {
        (None, None) => true,
        (Some(_), None) | (None, Some(_)) => false,
        (Some(a), Some(b)) => &*a as *const _ == &*b as *const _
    }
}

/// Whether two elements have the same same presentational attributes.
pub fn have_same_presentational_hints<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>
) -> bool
where
    E: TElement,
{
    target.pres_hints() == candidate.pres_hints()
}

/// Whether a given element has the same class attribute than a given candidate.
///
/// We don't try to share style across elements with different class attributes.
pub fn have_same_class<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>,
) -> bool
where
    E: TElement,
{
    target.class_list() == candidate.class_list()
}

/// Whether a given element and a candidate match the same set of "revalidation"
/// selectors.
///
/// Revalidation selectors are those that depend on the DOM structure, like
/// :first-child, etc, or on attributes that we don't check off-hand (pretty
/// much every attribute selector except `id` and `class`.
#[inline]
pub fn revalidate<E>(
    target: &mut StyleSharingTarget<E>,
    candidate: &mut StyleSharingCandidate<E>,
    shared_context: &SharedStyleContext,
    bloom: &StyleBloom<E>,
    nth_index_cache: &mut NthIndexCache,
    selector_flags_map: &mut SelectorFlagsMap<E>,
) -> bool
where
    E: TElement,
{
    let stylist = &shared_context.stylist;

    let for_element = target.revalidation_match_results(
        stylist,
        bloom,
        nth_index_cache,
        selector_flags_map,
    );

    let for_candidate = candidate.revalidation_match_results(
        stylist,
        bloom,
        nth_index_cache,
    );

    // This assert "ensures", to some extent, that the two candidates have
    // matched the same rulehash buckets, and as such, that the bits we're
    // comparing represent the same set of selectors.
    debug_assert_eq!(for_element.len(), for_candidate.len());

    for_element == for_candidate
}

/// Checks whether we might have rules for either of the two ids.
#[inline]
pub fn may_match_different_id_rules<E>(
    shared_context: &SharedStyleContext,
    element: E,
    candidate: E,
) -> bool
where
    E: TElement,
{
    let element_id = element.get_id();
    let candidate_id = candidate.get_id();

    if element_id == candidate_id {
        return false;
    }

    let stylist = &shared_context.stylist;

    let may_have_rules_for_element = match element_id {
        Some(ref id) => stylist.may_have_rules_for_id(id, element),
        None => false
    };

    if may_have_rules_for_element {
        return true;
    }

    match candidate_id {
        Some(ref id) => stylist.may_have_rules_for_id(id, candidate),
        None => false
    }
}
<|endoftext|>


<commit_before>//! Convolves the input tensor.
//!
//! Does this convolution with a set of learnable filters, each producing one
//! feature map in the output tensor.
use std::rc::Rc;
use co::{IBackend, DeviceType, SharedTensor};
use conn;
use layer::*;
use util::{ArcLock, native_backend, cast_vec_usize_to_i32};
use super::FilterLayer;

#[derive(Debug, Clone)]
/// Convolution Layer
pub struct Convolution<B: conn::Convolution<f32>> {
    axis: usize,
    num_output: usize,
    filter_shape: Vec<usize>,
    stride: Vec<usize>,
    padding: Vec<usize>,

    convolution_configs: Option<Rc<B::CC>>,
}

impl<B: conn::Convolution<f32>> Convolution<B> {
    /// Create a Convolution layer from a ConvolutionConfig.
    pub fn from_config(config: &ConvolutionConfig) -> Convolution<B> {
        Convolution {
            num_output: config.num_output,

            filter_shape: config.filter_shape.clone(),
            stride: config.stride.clone(),
            padding: config.padding.clone(),

            axis: config.axis(),

            convolution_configs: None,
        }
    }

    fn calculate_filter_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let spatial_dims = self.spatial_filter_dims(num_spatial_dims);
        let filter_n = self.num_output; // number of output feature maps
        let filter_c = input_shape[self.axis]; // number of input feature maps
        let filter_h = spatial_dims[0];
        let filter_w = spatial_dims[1];

        vec![filter_n, filter_c, filter_h, filter_w]
    }

    fn create_filter(&self, device: &DeviceType, input_shape: &[usize]) -> SharedTensor<f32> {
        let filter_shape = self.calculate_filter_shape(input_shape);

        SharedTensor::<f32>::new(device, &filter_shape).unwrap()
    }
}

impl<B: conn::Convolution<f32>> FilterLayer for Convolution<B> {
    /// Calculates the number of spatial dimensions for the pooling operation.
    fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
        match input_shape.len() {
            4 => 2,
            _ => panic!("Only 2D convolutions supported at the moment")
        }
    }

    fn calculate_output_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let filter = self.spatial_filter_dims(num_spatial_dims);
        let padding = self.padding_dims(num_spatial_dims);
        let stride = self.stride_dims(num_spatial_dims);
        let mut output_shape = Vec::new();
        for dim in &input_shape[0..self.axis].to_vec() {
            output_shape.push(*dim);
        }
        output_shape.push(self.num_output);
        for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[(self.axis + 1)..], &filter, &padding, &stride) {
            output_shape.push(spatial_dim);
        }

        output_shape
    }

    fn filter_shape(&self) -> &[usize] {
        &self.filter_shape
    }

    fn stride(&self) -> &[usize] {
        &self.stride
    }

    fn padding(&self) -> &[usize] {
        &self.padding
    }
}

impl<B: IBackend + conn::Convolution<f32>> ILayer<B> for Convolution<B> {
    impl_ilayer_common!();

    fn reshape(&mut self,
               backend: ::std::rc::Rc<B>,
               input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>) {
        for i in 0..input_data.len() {
            let inp = input_data[0].read().unwrap();
            let mut output_data = output_data[0].write().unwrap();
            let mut output_gradient = output_gradient[0].write().unwrap();
            let input_shape = inp.desc();
            let output_shape = self.calculate_output_shape(input_shape);
            output_data.resize(&output_shape).unwrap();
            output_gradient.resize(&output_shape).unwrap();

            let device = <B as IBackend>::device(&backend);
            let num_spatial_dims = self.num_spatial_dims(inp.desc());
            let mut filter = self.create_filter(device, input_shape);
            let stride = cast_vec_usize_to_i32(self.stride_dims(num_spatial_dims));
            let padding = cast_vec_usize_to_i32(self.padding_dims(num_spatial_dims));

            // add copy on native as workaround for bug in new_convolution_config
            let native = native_backend();
            let _ = filter.add_device(native.device());
            let config = backend.new_convolution_config(&inp, &output_data, &mut filter,
                                                        conn::ConvForwardAlgo::Auto, conn::ConvBackwardFilterAlgo::Auto, conn::ConvBackwardDataAlgo::Auto,
                                                        &stride, &padding).unwrap();
            weights_data[0].write().unwrap().resize(filter.desc()).unwrap();
            weights_gradient[0].write().unwrap().resize(filter.desc()).unwrap();
            self.convolution_configs = Some(Rc::new(config));
        }
    }
}

impl<B: IBackend + conn::Convolution<f32>> ComputeOutput<f32, B> for Convolution<B> {
    fn compute_output(&self,
                      backend: &B,
                      weights: &[&SharedTensor<f32>],
                      input_data: &[&SharedTensor<f32>],
                      output_data: &mut [&mut SharedTensor<f32>]) {
        let filter_data = weights[0];
        let conv_config = self.convolution_configs.as_ref().unwrap();
        backend.convolution_plain(filter_data, input_data[0], output_data[0], conv_config).unwrap();
    }
}

impl<B: IBackend + conn::Convolution<f32>> ComputeInputGradient<f32, B> for Convolution<B> {
    fn compute_input_gradient(&self,
                              backend: &B,
                              weights_data: &[&SharedTensor<f32>],
                              _output_data: &[&SharedTensor<f32>],
                              output_gradients: &[&SharedTensor<f32>],
                              input_data: &[&SharedTensor<f32>],
                              input_gradients: &mut [&mut SharedTensor<f32>]) {
        let filter_data = weights_data[0];
        let conv_config = self.convolution_configs.as_ref().unwrap();
        // compute gradient w.r.t. input
        backend.convolution_grad_data_plain(filter_data, output_gradients[0], input_gradients[0], conv_config).unwrap();
    }
}

impl<B: IBackend + conn::Convolution<f32>> ComputeParametersGradient<f32, B> for Convolution<B> {
    fn compute_parameters_gradient(&self,
                                   backend: &B,
                                   _output_data: &[&SharedTensor<f32>],
                                   output_gradients: &[&SharedTensor<f32>],
                                   input_data: &[&SharedTensor<f32>],
                                   parameters_gradients: &mut [&mut SharedTensor<f32>]) {
        // TODO: compute gradient w.r.t to bias
        let filter_gradient = &mut parameters_gradients[0];
        let conv_config = self.convolution_configs.as_ref().unwrap();
        // compute gradient w.r.t. filter
        backend.convolution_grad_filter_plain(input_data[0], output_gradients[0], filter_gradient, conv_config).unwrap();
    }
}

#[derive(Debug, Clone)]
/// Specifies configuration parameters for a Convolution Layer.
pub struct ConvolutionConfig {
    /// The number of output values
    pub num_output: usize,
    /// The size of the kernel
    pub filter_shape: Vec<usize>,
    /// The stride size
    pub stride: Vec<usize>,
    /// The padding size
    pub padding: Vec<usize>,
    /// The axis to interpret as "channels" when performing convolution.
    ///
    /// Preceding dimensions are treated as independent inputs, and
    /// succeeding dimensions are treated as "spatial".
    ///
    /// Defaults to `1`
    pub axis: Option<usize>,
}

impl ConvolutionConfig {
    /// The axis to interpret as "channels" when performing convolution.
    ///
    /// Preceding dimensions are treated as independent inputs, and
    /// succeeding dimensions are treated as "spatial".
    ///
    /// Defaults to `1`
    pub fn axis(&self) -> usize {
        self.axis.unwrap_or(1)
    }
}

#[cfg(test)]
mod tests {
    use co::*;
    use super::{Convolution, ConvolutionConfig};
    use super::super::FilterLayer;

    #[test]
    #[cfg(feature="cuda")]
    fn correct_shapes() {
        let cfg = ConvolutionConfig {
            num_output: 64,

            filter_shape: vec![11],
            padding: vec![2],
            stride: vec![4],

            axis: None,
        };
        let layer = Convolution::<Backend<Cuda>>::from_config(&cfg);
        let num_spatial_dims = layer.num_spatial_dims(&vec![1, 3, 224, 224]);
        assert_eq!(2, num_spatial_dims);
        assert_eq!(vec![11, 11], layer.spatial_filter_dims(2));
        assert_eq!(vec![2, 2], layer.padding_dims(2));
        assert_eq!(vec![4, 4], layer.stride_dims(2));
        assert_eq!(vec![64, 3, 11, 11], layer.calculate_filter_shape(&vec![1, 3, 224, 224]));
        assert_eq!(vec![1, 64, 55, 55], layer.calculate_output_shape(&vec![1, 3, 224, 224]));
    }
}
<commit_msg>fix/convolution: add missing weight initialization<commit_after>//! Convolves the input tensor.
//!
//! Does this convolution with a set of learnable filters, each producing one
//! feature map in the output tensor.
use std::rc::Rc;
use co::prelude::*;
use conn;
use layer::*;
use util::{ArcLock, native_backend, cast_vec_usize_to_i32};
use weight::FillerType;
use super::FilterLayer;

#[derive(Debug, Clone)]
/// Convolution Layer
pub struct Convolution<B: conn::Convolution<f32>> {
    axis: usize,
    num_output: usize,
    filter_shape: Vec<usize>,
    stride: Vec<usize>,
    padding: Vec<usize>,

    convolution_configs: Option<Rc<B::CC>>,
}

impl<B: conn::Convolution<f32>> Convolution<B> {
    /// Create a Convolution layer from a ConvolutionConfig.
    pub fn from_config(config: &ConvolutionConfig) -> Convolution<B> {
        Convolution {
            num_output: config.num_output,

            filter_shape: config.filter_shape.clone(),
            stride: config.stride.clone(),
            padding: config.padding.clone(),

            axis: config.axis(),

            convolution_configs: None,
        }
    }

    fn calculate_filter_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let spatial_dims = self.spatial_filter_dims(num_spatial_dims);
        let filter_n = self.num_output; // number of output feature maps
        let filter_c = input_shape[self.axis]; // number of input feature maps
        let filter_h = spatial_dims[0];
        let filter_w = spatial_dims[1];

        vec![filter_n, filter_c, filter_h, filter_w]
    }

    fn create_filter(&self, device: &DeviceType, input_shape: &[usize]) -> SharedTensor<f32> {
        let filter_shape = self.calculate_filter_shape(input_shape);

        SharedTensor::<f32>::new(device, &filter_shape).unwrap()
    }
}

impl<B: conn::Convolution<f32>> FilterLayer for Convolution<B> {
    /// Calculates the number of spatial dimensions for the pooling operation.
    fn num_spatial_dims(&self, input_shape: &[usize]) -> usize {
        match input_shape.len() {
            4 => 2,
            _ => panic!("Only 2D convolutions supported at the moment")
        }
    }

    fn calculate_output_shape(&self, input_shape: &[usize]) -> Vec<usize> {
        let num_spatial_dims = self.num_spatial_dims(input_shape);
        let filter = self.spatial_filter_dims(num_spatial_dims);
        let padding = self.padding_dims(num_spatial_dims);
        let stride = self.stride_dims(num_spatial_dims);
        let mut output_shape = Vec::new();
        for dim in &input_shape[0..self.axis].to_vec() {
            output_shape.push(*dim);
        }
        output_shape.push(self.num_output);
        for spatial_dim in Self::calculate_spatial_output_dims(&input_shape[(self.axis + 1)..], &filter, &padding, &stride) {
            output_shape.push(spatial_dim);
        }

        output_shape
    }

    fn filter_shape(&self) -> &[usize] {
        &self.filter_shape
    }

    fn stride(&self) -> &[usize] {
        &self.stride
    }

    fn padding(&self) -> &[usize] {
        &self.padding
    }
}

impl<B: IBackend + conn::Convolution<f32>> ILayer<B> for Convolution<B> {
    impl_ilayer_common!();

    fn reshape(&mut self,
               backend: ::std::rc::Rc<B>,
               input_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               input_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               weights_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_data: &mut Vec<ArcLock<SharedTensor<f32>>>,
               output_gradient: &mut Vec<ArcLock<SharedTensor<f32>>>) {
        for i in 0..input_data.len() {
            let inp = input_data[0].read().unwrap();
            let mut output_data = output_data[0].write().unwrap();
            let mut output_gradient = output_gradient[0].write().unwrap();
            let input_shape = inp.desc();
            let output_shape = self.calculate_output_shape(input_shape);
            output_data.resize(&output_shape).unwrap();
            output_gradient.resize(&output_shape).unwrap();

            let device = <B as IBackend>::device(&backend);
            let num_spatial_dims = self.num_spatial_dims(inp.desc());
            let mut filter = self.create_filter(device, input_shape);
            let stride = cast_vec_usize_to_i32(self.stride_dims(num_spatial_dims));
            let padding = cast_vec_usize_to_i32(self.padding_dims(num_spatial_dims));

            // add copy on native as workaround for bug in new_convolution_config
            let native = native_backend();
            let _ = filter.add_device(native.device());
            let config = backend.new_convolution_config(&inp, &output_data, &mut filter,
                                                        conn::ConvForwardAlgo::Auto, conn::ConvBackwardFilterAlgo::Auto, conn::ConvBackwardDataAlgo::Auto,
                                                        &stride, &padding).unwrap();
            // resize and fill weights
            weights_data[0].write().unwrap().resize(filter.desc()).unwrap();
            let filler = FillerType::Glorot {
                input_size: inp.desc().size(),
                output_size: output_shape.size(),
            };
            filler.fill(&mut weights_data[0].write().unwrap());
            weights_gradient[0].write().unwrap().resize(filter.desc()).unwrap();
            self.convolution_configs = Some(Rc::new(config));
        }
    }
}

impl<B: IBackend + conn::Convolution<f32>> ComputeOutput<f32, B> for Convolution<B> {
    fn compute_output(&self,
                      backend: &B,
                      weights: &[&SharedTensor<f32>],
                      input_data: &[&SharedTensor<f32>],
                      output_data: &mut [&mut SharedTensor<f32>]) {
        let filter_data = weights[0];
        let conv_config = self.convolution_configs.as_ref().unwrap();
        backend.convolution_plain(filter_data, input_data[0], output_data[0], conv_config).unwrap();
    }
}

impl<B: IBackend + conn::Convolution<f32>> ComputeInputGradient<f32, B> for Convolution<B> {
    fn compute_input_gradient(&self,
                              backend: &B,
                              weights_data: &[&SharedTensor<f32>],
                              _output_data: &[&SharedTensor<f32>],
                              output_gradients: &[&SharedTensor<f32>],
                              input_data: &[&SharedTensor<f32>],
                              input_gradients: &mut [&mut SharedTensor<f32>]) {
        let filter_data = weights_data[0];
        let conv_config = self.convolution_configs.as_ref().unwrap();
        // compute gradient w.r.t. input
        backend.convolution_grad_data_plain(filter_data, output_gradients[0], input_gradients[0], conv_config).unwrap();
    }
}

impl<B: IBackend + conn::Convolution<f32>> ComputeParametersGradient<f32, B> for Convolution<B> {
    fn compute_parameters_gradient(&self,
                                   backend: &B,
                                   _output_data: &[&SharedTensor<f32>],
                                   output_gradients: &[&SharedTensor<f32>],
                                   input_data: &[&SharedTensor<f32>],
                                   parameters_gradients: &mut [&mut SharedTensor<f32>]) {
        // TODO: compute gradient w.r.t to bias
        let filter_gradient = &mut parameters_gradients[0];
        let conv_config = self.convolution_configs.as_ref().unwrap();
        // compute gradient w.r.t. filter
        backend.convolution_grad_filter_plain(input_data[0], output_gradients[0], filter_gradient, conv_config).unwrap();
    }
}

#[derive(Debug, Clone)]
/// Specifies configuration parameters for a Convolution Layer.
pub struct ConvolutionConfig {
    /// The number of output values
    pub num_output: usize,
    /// The size of the kernel
    pub filter_shape: Vec<usize>,
    /// The stride size
    pub stride: Vec<usize>,
    /// The padding size
    pub padding: Vec<usize>,
    /// The axis to interpret as "channels" when performing convolution.
    ///
    /// Preceding dimensions are treated as independent inputs, and
    /// succeeding dimensions are treated as "spatial".
    ///
    /// Defaults to `1`
    pub axis: Option<usize>,
}

impl ConvolutionConfig {
    /// The axis to interpret as "channels" when performing convolution.
    ///
    /// Preceding dimensions are treated as independent inputs, and
    /// succeeding dimensions are treated as "spatial".
    ///
    /// Defaults to `1`
    pub fn axis(&self) -> usize {
        self.axis.unwrap_or(1)
    }
}

#[cfg(test)]
mod tests {
    use co::*;
    use super::{Convolution, ConvolutionConfig};
    use super::super::FilterLayer;

    #[test]
    #[cfg(feature="cuda")]
    fn correct_shapes() {
        let cfg = ConvolutionConfig {
            num_output: 64,

            filter_shape: vec![11],
            padding: vec![2],
            stride: vec![4],

            axis: None,
        };
        let layer = Convolution::<Backend<Cuda>>::from_config(&cfg);
        let num_spatial_dims = layer.num_spatial_dims(&vec![1, 3, 224, 224]);
        assert_eq!(2, num_spatial_dims);
        assert_eq!(vec![11, 11], layer.spatial_filter_dims(2));
        assert_eq!(vec![2, 2], layer.padding_dims(2));
        assert_eq!(vec![4, 4], layer.stride_dims(2));
        assert_eq!(vec![64, 3, 11, 11], layer.calculate_filter_shape(&vec![1, 3, 224, 224]));
        assert_eq!(vec![1, 64, 55, 55], layer.calculate_output_shape(&vec![1, 3, 224, 224]));
    }
}
<|endoftext|>


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

/*!
Sampling from random distributions.

This is a generalization of `Rand` to allow parameters to control the
exact properties of the generated values, e.g. the mean and standard
deviation of a normal distribution. The `Sample` trait is the most
general, and allows for generating values that change some state
internally. The `IndependentSample` trait is for generating values
that do not need to record state.

*/

use num;
use rand::{Rng,Rand};

pub use self::range::Range;

pub mod range;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
    /// Generate a random value of `Support`, using `rng` as the
    /// source of randomness.
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}

/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recored, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// XXX maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
    /// Generate a random value.
    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}

/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup>;

impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}

impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        rng.gen()
    }
}

mod ziggurat_tables;

// inlining should mean there is no performance penalty for this
#[inline]
fn ziggurat<R:Rng>(rng: &mut R,
                   center_u: bool,
                   X: ziggurat_tables::ZigTable,
                   F: ziggurat_tables::ZigTable,
                   F_DIFF: ziggurat_tables::ZigTable,
                   pdf: &'static fn(f64) -> f64, // probability density function
                   zero_case: &'static fn(&mut R, f64) -> f64) -> f64 {
    loop {
        let u = if center_u {2.0 * rng.gen() - 1.0} else {rng.gen()};
        let i: uint = rng.gen::<uint>() & 0xff;
        let x = u * X[i];

        let test_x = if center_u {num::abs(x)} else {x};

        // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i])
        if test_x < X[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if F[i+1] + F_DIFF[i+1] * rng.gen() < pdf(x) {
            return x;
        }
    }
}

/// A wrapper around an `f64` to generate N(0, 1) random numbers
/// (a.k.a.  a standard normal, or Gaussian).
///
/// See `Normal` for the general normal distribution. That this has to
/// be unwrapped before use as an `f64` (using either `*` or
/// `cast::transmute` is safe).
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
pub struct StandardNormal(f64);

impl Rand for StandardNormal {
    fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
        #[inline]
        fn pdf(x: f64) -> f64 {
            ((-x*x/2.0) as f64).exp()
        }
        #[inline]
        fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
            // compute a random number in the tail by hand

            // strange initial conditions, because the loop is not
            // do-while, so the condition should be true on the first
            // run, they get overwritten anyway (0 < 1, so these are
            // good).
            let mut x = 1.0f64;
            let mut y = 0.0f64;

            // FIXME #7755: infinities?
            while -2.0 * y < x * x {
                x = rng.gen::<f64>().ln() / ziggurat_tables::ZIG_NORM_R;
                y = rng.gen::<f64>().ln();
            }

            if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
        }

        StandardNormal(ziggurat(
            rng,
            true, // this is symmetric
            &ziggurat_tables::ZIG_NORM_X,
            &ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF,
            pdf, zero_case))
    }
}

/// The normal distribution `N(mean, std_dev**2)`.
///
/// This uses the ZIGNOR variant of the Ziggurat method, see
/// `StandardNormal` for more details.
///
/// # Example
///
/// ```
/// use std::rand;
/// use std::rand::distributions::{Normal, IndependentSample};
///
/// fn main() {
///     let normal = Normal::new(2.0, 3.0);
///     let v = normal.ind_sample(rand::task_rng());
///     println!("{} is from a N(2, 9) distribution", v)
/// }
/// ```
pub struct Normal {
    priv mean: f64,
    priv std_dev: f64
}

impl Normal {
    /// Construct a new `Normal` distribution with the given mean and
    /// standard deviation. Fails if `std_dev < 0`.
    pub fn new(mean: f64, std_dev: f64) -> Normal {
        assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
        Normal {
            mean: mean,
            std_dev: std_dev
        }
    }
}
impl Sample<f64> for Normal {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Normal {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.mean + self.std_dev * (*rng.gen::<StandardNormal>())
    }
}

/// A wrapper around an `f64` to generate Exp(1) random numbers.
///
/// See `Exp` for the general exponential distribution.Note that this
 // has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
/// exact description in the paper was adjusted to use tables for the
/// exponential distribution rather than normal.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
pub struct Exp1(f64);

// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
impl Rand for Exp1 {
    #[inline]
    fn rand<R:Rng>(rng: &mut R) -> Exp1 {
        #[inline]
        fn pdf(x: f64) -> f64 {
            (-x).exp()
        }
        #[inline]
        fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
            ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
        }

        Exp1(ziggurat(rng, false,
                      &ziggurat_tables::ZIG_EXP_X,
                      &ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF,
                      pdf, zero_case))
    }
}

/// The exponential distribution `Exp(lambda)`.
///
/// This distribution has density function: `f(x) = lambda *
/// exp(-lambda * x)` for `x > 0`.
///
/// # Example
///
/// ```
/// use std::rand;
/// use std::rand::distributions::{Exp, IndependentSample};
///
/// fn main() {
///     let exp = Exp::new(2.0);
///     let v = exp.ind_sample(rand::task_rng());
///     println!("{} is from a Exp(2) distribution", v);
/// }
/// ```
pub struct Exp {
    /// `lambda` stored as `1/lambda`, since this is what we scale by.
    priv lambda_inverse: f64
}

impl Exp {
    /// Construct a new `Exp` with the given shape parameter
    /// `lambda`. Fails if `lambda <= 0`.
    pub fn new(lambda: f64) -> Exp {
        assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
        Exp { lambda_inverse: 1.0 / lambda }
    }
}

impl Sample<f64> for Exp {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Exp {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        (*rng.gen::<Exp1>()) * self.lambda_inverse
    }
}

#[cfg(test)]
mod tests {
    use rand::*;
    use super::*;
    use iter::range;
    use option::{Some, None};

    struct ConstRand(uint);
    impl Rand for ConstRand {
        fn rand<R: Rng>(_: &mut R) -> ConstRand {
            ConstRand(0)
        }
    }

    #[test]
    fn test_rand_sample() {
        let mut rand_sample = RandSample::<ConstRand>;

        assert_eq!(*rand_sample.sample(task_rng()), 0);
        assert_eq!(*rand_sample.ind_sample(task_rng()), 0);
    }

    #[test]
    fn test_normal() {
        let mut norm = Normal::new(10.0, 10.0);
        let rng = task_rng();
        for _ in range(0, 1000) {
            norm.sample(rng);
            norm.ind_sample(rng);
        }
    }
    #[test]
    #[should_fail]
    fn test_normal_invalid_sd() {
        Normal::new(10.0, -1.0);
    }

    #[test]
    fn test_exp() {
        let mut exp = Exp::new(10.0);
        let rng = task_rng();
        for _ in range(0, 1000) {
            assert!(exp.sample(rng) >= 0.0);
            assert!(exp.ind_sample(rng) >= 0.0);
        }
    }
    #[test]
    #[should_fail]
    fn test_exp_invalid_lambda_zero() {
        Exp::new(0.0);
    }
    #[test]
    #[should_fail]
    fn test_exp_invalid_lambda_neg() {
        Exp::new(-10.0);
    }
}
<commit_msg>std::rand: optimise & document ziggurat.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*!
Sampling from random distributions.

This is a generalization of `Rand` to allow parameters to control the
exact properties of the generated values, e.g. the mean and standard
deviation of a normal distribution. The `Sample` trait is the most
general, and allows for generating values that change some state
internally. The `IndependentSample` trait is for generating values
that do not need to record state.

*/

use num;
use rand::{Rng,Rand};

pub use self::range::Range;

pub mod range;

/// Types that can be used to create a random instance of `Support`.
pub trait Sample<Support> {
    /// Generate a random value of `Support`, using `rng` as the
    /// source of randomness.
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Support;
}

/// `Sample`s that do not require keeping track of state.
///
/// Since no state is recored, each sample is (statistically)
/// independent of all others, assuming the `Rng` used has this
/// property.
// XXX maybe having this separate is overkill (the only reason is to
// take &self rather than &mut self)? or maybe this should be the
// trait called `Sample` and the other should be `DependentSample`.
pub trait IndependentSample<Support>: Sample<Support> {
    /// Generate a random value.
    fn ind_sample<R: Rng>(&self, &mut R) -> Support;
}

/// A wrapper for generating types that implement `Rand` via the
/// `Sample` & `IndependentSample` traits.
pub struct RandSample<Sup>;

impl<Sup: Rand> Sample<Sup> for RandSample<Sup> {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> Sup { self.ind_sample(rng) }
}

impl<Sup: Rand> IndependentSample<Sup> for RandSample<Sup> {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> Sup {
        rng.gen()
    }
}

mod ziggurat_tables;

/// Sample a random number using the Ziggurat method (specifically the
/// ZIGNOR variant from Doornik 2005). Most of the arguments are
/// directly from the paper:
///
/// * `rng`: source of randomness
/// * `symmetric`: whether this is a symmetric distribution, or one-sided with P(x < 0) = 0.
/// * `X`: the $x_i$ abscissae.
/// * `F`: precomputed values of the PDF at the $x_i$, (i.e. $f(x_i)$)
/// * `F_DIFF`: precomputed values of $f(x_i) - f(x_{i+1})$
/// * `pdf`: the probability density function
/// * `zero_case`: manual sampling from the tail when we chose the
///    bottom box (i.e. i == 0)

// the perf improvement (25-50%) is definitely worth the extra code
// size from force-inlining.
#[inline(always)]
fn ziggurat<R:Rng>(rng: &mut R,
                   symmetric: bool,
                   X: ziggurat_tables::ZigTable,
                   F: ziggurat_tables::ZigTable,
                   F_DIFF: ziggurat_tables::ZigTable,
                   pdf: &'static fn(f64) -> f64,
                   zero_case: &'static fn(&mut R, f64) -> f64) -> f64 {
    static SCALE: f64 = (1u64 << 53) as f64;
    loop {
        // reimplement the f64 generation as an optimisation suggested
        // by the Doornik paper: we have a lot of precision-space
        // (i.e. there are 11 bits of the 64 of a u64 to use after
        // creating a f64), so we might as well reuse some to save
        // generating a whole extra random number. (Seems to be 15%
        // faster.)
        let bits: u64 = rng.gen();
        let i = (bits & 0xff) as uint;
        let f = (bits >> 11) as f64 / SCALE;

        // u is either U(-1, 1) or U(0, 1) depending on if this is a
        // symmetric distribution or not.
        let u = if symmetric {2.0 * f - 1.0} else {f};
        let x = u * X[i];

        let test_x = if symmetric {num::abs(x)} else {x};

        // algebraically equivalent to |u| < X[i+1]/X[i] (or u < X[i+1]/X[i])
        if test_x < X[i + 1] {
            return x;
        }
        if i == 0 {
            return zero_case(rng, u);
        }
        // algebraically equivalent to f1 + DRanU()*(f0 - f1) < 1
        if F[i + 1] + F_DIFF[i + 1] * rng.gen() < pdf(x) {
            return x;
        }
    }
}

/// A wrapper around an `f64` to generate N(0, 1) random numbers
/// (a.k.a.  a standard normal, or Gaussian).
///
/// See `Normal` for the general normal distribution. That this has to
/// be unwrapped before use as an `f64` (using either `*` or
/// `cast::transmute` is safe).
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
pub struct StandardNormal(f64);

impl Rand for StandardNormal {
    fn rand<R:Rng>(rng: &mut R) -> StandardNormal {
        #[inline]
        fn pdf(x: f64) -> f64 {
            ((-x*x/2.0) as f64).exp()
        }
        #[inline]
        fn zero_case<R:Rng>(rng: &mut R, u: f64) -> f64 {
            // compute a random number in the tail by hand

            // strange initial conditions, because the loop is not
            // do-while, so the condition should be true on the first
            // run, they get overwritten anyway (0 < 1, so these are
            // good).
            let mut x = 1.0f64;
            let mut y = 0.0f64;

            // FIXME #7755: infinities?
            while -2.0 * y < x * x {
                x = rng.gen::<f64>().ln() / ziggurat_tables::ZIG_NORM_R;
                y = rng.gen::<f64>().ln();
            }

            if u < 0.0 { x - ziggurat_tables::ZIG_NORM_R } else { ziggurat_tables::ZIG_NORM_R - x }
        }

        StandardNormal(ziggurat(
            rng,
            true, // this is symmetric
            &ziggurat_tables::ZIG_NORM_X,
            &ziggurat_tables::ZIG_NORM_F, &ziggurat_tables::ZIG_NORM_F_DIFF,
            pdf, zero_case))
    }
}

/// The normal distribution `N(mean, std_dev**2)`.
///
/// This uses the ZIGNOR variant of the Ziggurat method, see
/// `StandardNormal` for more details.
///
/// # Example
///
/// ```
/// use std::rand;
/// use std::rand::distributions::{Normal, IndependentSample};
///
/// fn main() {
///     let normal = Normal::new(2.0, 3.0);
///     let v = normal.ind_sample(rand::task_rng());
///     println!("{} is from a N(2, 9) distribution", v)
/// }
/// ```
pub struct Normal {
    priv mean: f64,
    priv std_dev: f64
}

impl Normal {
    /// Construct a new `Normal` distribution with the given mean and
    /// standard deviation. Fails if `std_dev < 0`.
    pub fn new(mean: f64, std_dev: f64) -> Normal {
        assert!(std_dev >= 0.0, "Normal::new called with `std_dev` < 0");
        Normal {
            mean: mean,
            std_dev: std_dev
        }
    }
}
impl Sample<f64> for Normal {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Normal {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        self.mean + self.std_dev * (*rng.gen::<StandardNormal>())
    }
}

/// A wrapper around an `f64` to generate Exp(1) random numbers.
///
/// See `Exp` for the general exponential distribution.Note that this
 // has to be unwrapped before use as an `f64` (using either
/// `*` or `cast::transmute` is safe).
///
/// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The
/// exact description in the paper was adjusted to use tables for the
/// exponential distribution rather than normal.
///
/// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to
/// Generate Normal Random
/// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield
/// College, Oxford
pub struct Exp1(f64);

// This could be done via `-rng.gen::<f64>().ln()` but that is slower.
impl Rand for Exp1 {
    #[inline]
    fn rand<R:Rng>(rng: &mut R) -> Exp1 {
        #[inline]
        fn pdf(x: f64) -> f64 {
            (-x).exp()
        }
        #[inline]
        fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 {
            ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln()
        }

        Exp1(ziggurat(rng, false,
                      &ziggurat_tables::ZIG_EXP_X,
                      &ziggurat_tables::ZIG_EXP_F, &ziggurat_tables::ZIG_EXP_F_DIFF,
                      pdf, zero_case))
    }
}

/// The exponential distribution `Exp(lambda)`.
///
/// This distribution has density function: `f(x) = lambda *
/// exp(-lambda * x)` for `x > 0`.
///
/// # Example
///
/// ```
/// use std::rand;
/// use std::rand::distributions::{Exp, IndependentSample};
///
/// fn main() {
///     let exp = Exp::new(2.0);
///     let v = exp.ind_sample(rand::task_rng());
///     println!("{} is from a Exp(2) distribution", v);
/// }
/// ```
pub struct Exp {
    /// `lambda` stored as `1/lambda`, since this is what we scale by.
    priv lambda_inverse: f64
}

impl Exp {
    /// Construct a new `Exp` with the given shape parameter
    /// `lambda`. Fails if `lambda <= 0`.
    pub fn new(lambda: f64) -> Exp {
        assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0");
        Exp { lambda_inverse: 1.0 / lambda }
    }
}

impl Sample<f64> for Exp {
    fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) }
}
impl IndependentSample<f64> for Exp {
    fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        (*rng.gen::<Exp1>()) * self.lambda_inverse
    }
}

#[cfg(test)]
mod tests {
    use rand::*;
    use super::*;
    use iter::range;
    use option::{Some, None};

    struct ConstRand(uint);
    impl Rand for ConstRand {
        fn rand<R: Rng>(_: &mut R) -> ConstRand {
            ConstRand(0)
        }
    }

    #[test]
    fn test_rand_sample() {
        let mut rand_sample = RandSample::<ConstRand>;

        assert_eq!(*rand_sample.sample(task_rng()), 0);
        assert_eq!(*rand_sample.ind_sample(task_rng()), 0);
    }

    #[test]
    fn test_normal() {
        let mut norm = Normal::new(10.0, 10.0);
        let rng = task_rng();
        for _ in range(0, 1000) {
            norm.sample(rng);
            norm.ind_sample(rng);
        }
    }
    #[test]
    #[should_fail]
    fn test_normal_invalid_sd() {
        Normal::new(10.0, -1.0);
    }

    #[test]
    fn test_exp() {
        let mut exp = Exp::new(10.0);
        let rng = task_rng();
        for _ in range(0, 1000) {
            assert!(exp.sample(rng) >= 0.0);
            assert!(exp.ind_sample(rng) >= 0.0);
        }
    }
    #[test]
    #[should_fail]
    fn test_exp_invalid_lambda_zero() {
        Exp::new(0.0);
    }
    #[test]
    #[should_fail]
    fn test_exp_invalid_lambda_neg() {
        Exp::new(-10.0);
    }
}

#[cfg(test)]
mod bench {
    use extra::test::BenchHarness;
    use rand::*;
    use super::*;
    use iter::range;
    use option::{Some, None};
    use mem::size_of;

    static N: u64 = 100;

    #[bench]
    fn rand_normal(bh: &mut BenchHarness) {
        let mut rng = XorShiftRng::new();
        let mut normal = Normal::new(-2.71828, 3.14159);

        do bh.iter {
            for _ in range(0, N) {
                normal.sample(&mut rng);
            }
        }
        bh.bytes = size_of::<f64>() as u64 * N;
    }
    #[bench]
    fn rand_exp(bh: &mut BenchHarness) {
        let mut rng = XorShiftRng::new();
        let mut exp = Exp::new(2.71828 * 3.14159);

        do bh.iter {
            for _ in range(0, N) {
                exp.sample(&mut rng);
            }
        }
        bh.bytes = size_of::<f64>() as u64 * N;
    }
}
<|endoftext|>


<commit_before>use base::world::{self, Chunk, ChunkIndex};
use base::prop::Plant;
use base::math::*;
use glium::backend::Facade;
use glium::{self, DepthTest, DrawParameters, LinearBlendingFactor};
use glium::draw_parameters::BlendingFunction;
use glium::texture::Texture2d;
use Camera;
use std::collections::HashMap;
use std::rc::Rc;
use view::PlantRenderer;
use world::ChunkRenderer;
use world::HexagonOutline;
use GameContext;
use util::ToArr;

pub use world::chunk_view::ChunkView;
pub use view::PlantView;

/// Graphical representation of the `base::World`.
pub struct WorldView {
    chunks: HashMap<ChunkIndex, ChunkView>,
    chunk_renderer: Rc<ChunkRenderer>,
    plant_renderer: Rc<PlantRenderer>,
    pub outline: HexagonOutline,
    plant_views: HashMap<ChunkIndex, Vec<PlantView>>,
    plant_list: Vec<Plant>,
}

impl WorldView {
    pub fn new(context: Rc<GameContext>, plant_list: Vec<Plant>) -> Self {
        let plant_renderer = Rc::new(PlantRenderer::new(context.clone()));
        let chunk_renderer = Rc::new(ChunkRenderer::new(context.clone()));

        WorldView {
            chunks: HashMap::new(),
            chunk_renderer: chunk_renderer,
            plant_renderer: plant_renderer,
            outline: HexagonOutline::new(context),
            plant_views: HashMap::new(),
            plant_list: plant_list,
        }
    }

    pub fn refresh_chunk<F: Facade>(&mut self, chunk_pos: ChunkIndex, chunk: &Chunk, facade: &F) {
        self.chunks.insert(chunk_pos,
                           ChunkView::from_chunk(chunk,
                                                 AxialPoint::new(chunk_pos.0.q *
                                                                 (1 * world::CHUNK_SIZE as i32),
                                                                 chunk_pos.0.r *
                                                                 (1 * world::CHUNK_SIZE as i32)),
                                                 self.chunk_renderer.clone(),
                                                 self.plant_renderer.clone(),
                                                 facade));

        for (pillar_pos, pillar) in chunk.pillars() {
            for prop in pillar.props() {
                let plant = &self.plant_list[prop.plant_index];
                let real_pos = pillar_pos.to_real();
                let real_chunk_pos = (chunk_pos.0 * world::CHUNK_SIZE as i32).to_real();

                self.plant_views
                    .entry(chunk_pos)
                    .or_insert(Vec::new())
                    .push(PlantView::from_plant(Point3f::new(real_chunk_pos.x + real_pos.x,
                                                             real_chunk_pos.y + real_pos.y,
                                                             prop.baseline.units() as f32 *
                                                             world::PILLAR_STEP_HEIGHT),
                                                &plant,
                                                self.plant_renderer.clone(),
                                                facade));
            }
        }
    }

    pub fn get_chunk_view(&self, index: &ChunkIndex) -> Option<&ChunkView> {
        self.chunks.get(&index)
    }

    pub fn get_chunk_view_mut(&mut self, index: &ChunkIndex) -> Option<&mut ChunkView> {
        self.chunks.get_mut(&index)
    }

    pub fn remove_chunk(&mut self, chunk_pos: ChunkIndex) {
        self.chunks.remove(&chunk_pos);
        self.plant_views.remove(&chunk_pos);
    }

    pub fn draw_shadow<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        for chunkview in self.chunks.values() {
            chunkview.draw_shadow(surface, camera);
        }
    }

    pub fn draw<S: glium::Surface>(&self,
                                   surface: &mut S,
                                   camera: &Camera,
                                   shadow_map: &Texture2d,
                                   depth_view_proj: &Matrix4<f32>,
                                   sun_dir: Vector3f) {
        for chunkview in self.chunks.values() {
            chunkview.draw(surface, camera, shadow_map, depth_view_proj, sun_dir);
        }
        if self.outline.display {
            // Draw outline
            let outline_params = DrawParameters {
                depth: glium::Depth {
                    write: false,
                    test: DepthTest::Overwrite,
                    ..Default::default()
                },
                blend: glium::Blend {
                    color: BlendingFunction::Addition {
                        source: LinearBlendingFactor::SourceAlpha,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    },
                    ..Default::default()
                },
                ..Default::default()
            };

            let outline_uniforms = uniform! {
              outline_pos: self.outline.position().to_arr(),
              proj_matrix: camera.proj_matrix().to_arr(),
              view_matrix: camera.view_matrix().to_arr()
            };

            surface.draw(self.outline.vertices(),
                      self.outline.indices(),
                      self.outline.program(),
                      &outline_uniforms,
                      &outline_params)
                .unwrap();
        }

        for plantview_vec in self.plant_views.values() {
            for plantview in plantview_vec {
                plantview.draw(surface, camera, shadow_map, depth_view_proj, sun_dir);
            }
        }
    }
}
<commit_msg>further prepare instancing<commit_after>use base::world::{self, Chunk, ChunkIndex};
use base::prop::Plant;
use base::math::*;
use glium::backend::Facade;
use glium::{self, DepthTest, DrawParameters, LinearBlendingFactor};
use glium::draw_parameters::BlendingFunction;
use glium::texture::Texture2d;
use Camera;
use std::collections::HashMap;
use std::rc::Rc;
use view::PlantRenderer;
use world::ChunkRenderer;
use world::HexagonOutline;
use GameContext;
use util::ToArr;

pub use world::chunk_view::ChunkView;
pub use view::PlantView;

/// Graphical representation of the `base::World`.
pub struct WorldView {
    chunks: HashMap<ChunkIndex, ChunkView>,
    chunk_renderer: Rc<ChunkRenderer>,
    plant_renderer: Rc<PlantRenderer>,
    pub outline: HexagonOutline,
    plant_views: HashMap<ChunkIndex, Vec<PlantView>>,
    plant_list: Vec<Plant>,
}

impl WorldView {
    pub fn new(context: Rc<GameContext>, plant_list: Vec<Plant>) -> Self {
        let plant_renderer = Rc::new(PlantRenderer::new(context.clone()));
        let chunk_renderer = Rc::new(ChunkRenderer::new(context.clone()));

        WorldView {
            chunks: HashMap::new(),
            chunk_renderer: chunk_renderer,
            plant_renderer: plant_renderer,
            outline: HexagonOutline::new(context),
            plant_views: HashMap::new(),
            plant_list: plant_list,
        }
    }

    pub fn refresh_chunk<F: Facade>(&mut self, chunk_pos: ChunkIndex, chunk: &Chunk, facade: &F) {
        self.chunks.insert(chunk_pos,
                           ChunkView::from_chunk(chunk,
                                                 AxialPoint::new(chunk_pos.0.q *
                                                                 (1 * world::CHUNK_SIZE as i32),
                                                                 chunk_pos.0.r *
                                                                 (1 * world::CHUNK_SIZE as i32)),
                                                 self.chunk_renderer.clone(),
                                                 self.plant_renderer.clone(),
                                                 facade));

        for (pillar_pos, pillar) in chunk.pillars() {
            for prop in pillar.props() {
                let plant = &self.plant_list[prop.plant_index];
                let real_pos = pillar_pos.to_real();
                let real_chunk_pos = (chunk_pos.0 * world::CHUNK_SIZE as i32).to_real();

                self.plant_views
                    .entry(chunk_pos)
                    .or_insert(Vec::new())
                    .push(PlantView::from_plant(Point3f::new(real_chunk_pos.x + real_pos.x,
                                                             real_chunk_pos.y + real_pos.y,
                                                             prop.baseline.units() as f32 *
                                                             world::PILLAR_STEP_HEIGHT),
                                                &plant,
                                                self.plant_renderer.clone(),
                                                facade));
            }
        }
    }

    pub fn get_chunk_view(&self, index: &ChunkIndex) -> Option<&ChunkView> {
        self.chunks.get(&index)
    }

    pub fn get_chunk_view_mut(&mut self, index: &ChunkIndex) -> Option<&mut ChunkView> {
        self.chunks.get_mut(&index)
    }

    pub fn remove_chunk(&mut self, chunk_pos: ChunkIndex) {
        self.chunks.remove(&chunk_pos);
        self.plant_views.remove(&chunk_pos);
    }

    pub fn draw_shadow<S: glium::Surface>(&self, surface: &mut S, camera: &Camera) {
        for chunkview in self.chunks.values() {
            chunkview.draw_shadow(surface, camera);
        }
    }

    pub fn draw<S: glium::Surface>(&self,
                                   surface: &mut S,
                                   camera: &Camera,
                                   shadow_map: &Texture2d,
                                   depth_view_proj: &Matrix4<f32>,
                                   sun_dir: Vector3f) {
        for chunkview in self.chunks.values() {
            chunkview.draw(surface, camera, shadow_map, depth_view_proj, sun_dir);
        }
        if self.outline.display {
            // Draw outline
            let outline_params = DrawParameters {
                depth: glium::Depth {
                    write: false,
                    test: DepthTest::Overwrite,
                    ..Default::default()
                },
                blend: glium::Blend {
                    color: BlendingFunction::Addition {
                        source: LinearBlendingFactor::SourceAlpha,
                        destination: LinearBlendingFactor::OneMinusSourceAlpha,
                    },
                    ..Default::default()
                },
                ..Default::default()
            };

            let outline_uniforms = uniform! {
              outline_pos: self.outline.position().to_arr(),
              proj_matrix: camera.proj_matrix().to_arr(),
              view_matrix: camera.view_matrix().to_arr()
            };

            surface.draw(self.outline.vertices(),
                      self.outline.indices(),
                      self.outline.program(),
                      &outline_uniforms,
                      &outline_params)
                .unwrap();
        }

        for plantview_vec in self.plant_views.values() {
            for plantview in plantview_vec {
                plantview.draw(surface, camera, shadow_map, depth_view_proj, sun_dir);

                // plantview.draw(surface, camera);
            }
        }
    }
}
<|endoftext|>