<commit_before>// (C)opyleft 2013-2015 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]
#![feature(collections)]

extern crate collections;
extern crate rand;

use std::cmp;
use std::f64;
use std::hash::{Hash, Hasher, SipHasher};
use collections::BitVec;

#[cfg(test)]
use rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: BitVec,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher; 2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = BitVec::from_elem(bitmap_bits as usize, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * f64::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

/// Record the presence of an item.
    pub fn set<T>(& mut self, item: T) where T: Hash {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool where T: Hash {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T)
                               -> bool where T: Hash {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * f64::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: & mut [u64; 2],
                  item: &T, k_i: u32) -> u64 where T: Hash {
        if k_i < 2 {
            let sip = &mut self.sips[k_i as usize].clone();
            item.hash(sip);
            let hash = sip.finish();
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::thread_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<commit_msg>"extern crate collections" is not required any more<commit_after>// (C)opyleft 2013-2015 Frank Denis

/*!
 * Bloom filter for Rust
 *
 * This is a simple but fast Bloom filter implementation, that requires only
 * 2 hash functions, generated with SipHash-2-4 using randomized keys.
 */

#![crate_name="bloomfilter"]
#![crate_type = "rlib"]
#![warn(non_camel_case_types, non_upper_case_globals, unused_qualifications)]
#![feature(collections)]

extern crate rand;

use std::cmp;
use std::f64;
use std::hash::{Hash, Hasher, SipHasher};
use std::collections::BitVec;

#[cfg(test)]
use rand::Rng;

/// Bloom filter structure
pub struct Bloom {
    bitmap: BitVec,
    bitmap_bits: u64,
    k_num: u32,
    sips: [SipHasher; 2]
}

impl Bloom {
/// Create a new bloom filter structure.
/// bitmap_size is the size in bytes (not bits) that will be allocated in memory
/// items_count is an estimation of the maximum number of items to store.
    pub fn new(bitmap_size: usize, items_count: usize) -> Bloom {
        assert!(bitmap_size > 0 && items_count > 0);
        let bitmap_bits = (bitmap_size as u64) * 8u64;
        let k_num = Bloom::optimal_k_num(bitmap_bits, items_count);
        let bitmap = BitVec::from_elem(bitmap_bits as usize, false);
        let sips = [ Bloom::sip_new(), Bloom::sip_new() ];
        Bloom {
            bitmap: bitmap,
            bitmap_bits: bitmap_bits,
            k_num: k_num,
            sips: sips
        }
    }

/// Create a new bloom filter structure.
/// items_count is an estimation of the maximum number of items to store.
/// fp_p is the wanted rate of false positives, in ]0.0, 1.0[
    pub fn new_for_fp_rate(items_count: usize, fp_p: f64) -> Bloom {
        let bitmap_size = Bloom::compute_bitmap_size(items_count, fp_p);
        Bloom::new(bitmap_size, items_count)
    }

/// Compute a recommended bitmap size for items_count items
/// and a fp_p rate of false positives.
/// fp_p obviously has to be within the ]0.0, 1.0[ range.
    pub fn compute_bitmap_size(items_count: usize, fp_p: f64) -> usize {
        assert!(items_count > 0);
        assert!(fp_p > 0.0 && fp_p < 1.0);
        let log2 = f64::consts::LN_2;
        let log2_2 = log2 * log2;
        ((items_count as f64) * f64::ln(fp_p) / (-8.0 * log2_2)).ceil() as usize
    }

/// Record the presence of an item.
    pub fn set<T>(& mut self, item: T) where T: Hash {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            self.bitmap.set(bit_offset, true);
        }
    }

/// Check if an item is present in the set.
/// There can be false positives, but no false negatives.
    pub fn check<T>(&self, item: T) -> bool where T: Hash {
        let mut hashes = [ 0u64, 0u64 ];
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                return false;
            }
        }
        true
    }

/// Record the presence of an item in the set,
/// and return the previous state of this item.
    pub fn check_and_set<T>(&mut self, item: T)
                               -> bool where T: Hash {
        let mut hashes = [ 0u64, 0u64 ];
        let mut found = true;
        for k_i in (0..self.k_num) {
            let bit_offset = (self.bloom_hash(& mut hashes, &item, k_i)
                              % self.bitmap_bits) as usize;
            if self.bitmap.get(bit_offset).unwrap() == false {
                found = false;
                self.bitmap.set(bit_offset, true);
            }
        }
        found
    }

/// Return the number of bits in the filter
    pub fn number_of_bits(&self) -> u64 {
        self.bitmap_bits
    }

/// Return the number of hash functions used for `check` and `set`
    pub fn number_of_hash_functions(&self) -> u32 {
        self.k_num
    }

    fn optimal_k_num(bitmap_bits: u64, items_count: usize) -> u32 {
        let m = bitmap_bits as f64;
        let n = items_count as f64;
        let k_num = (m / n * f64::ln(2.0f64)).ceil() as u32;
        cmp::max(k_num, 1)
    }

    fn bloom_hash<T>(&self, hashes: & mut [u64; 2],
                  item: &T, k_i: u32) -> u64 where T: Hash {
        if k_i < 2 {
            let sip = &mut self.sips[k_i as usize].clone();
            item.hash(sip);
            let hash = sip.finish();
            hashes[k_i as usize] = hash;
            hash
        } else {
            hashes[0] + (((k_i as u64) * hashes[1]) % 0xffffffffffffffc5)
        }
    }

    fn sip_new() -> SipHasher {
        let mut rng = rand::thread_rng();
        SipHasher::new_with_keys(rand::Rand::rand(& mut rng),
                                 rand::Rand::rand(& mut rng))
    }
}

#[test]
fn bloom_test_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check(key) == false);
    bloom.set(&key);
    assert!(bloom.check(key.clone()) == true);
}

#[test]
fn bloom_test_check_and_set() {
    let mut bloom = Bloom::new(10, 80);
    let key: &Vec<u8> = &rand::thread_rng().gen_iter::<u8>().take(16).collect();
    assert!(bloom.check_and_set(key) == false);
    assert!(bloom.check_and_set(key.clone()) == true);
}
<|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/. */

//! Abstractions for global scopes.
//!
//! This module contains smart pointers to global scopes, to simplify writing
//! code that works in workers as well as window scopes.

use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::root_from_object;
use dom::bindings::js::{JS, Root};
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::window::{self, ScriptHelpers};
use dom::workerglobalscope::WorkerGlobalScope;
use ipc_channel::ipc::IpcSender;
use js::jsapi::GetGlobalForObjectCrossCompartment;
use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue};
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
use msg::constellation_msg::{ConstellationChan, PipelineId};
use net_traits::ResourceThread;
use profile_traits::mem;
use script_thread::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThread};
use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest};
use timers::{ScheduledCallback, TimerHandle};
use url::Url;
use util::mem::HeapSizeOf;

/// A freely-copyable reference to a rooted global object.
#[derive(Copy, Clone)]
pub enum GlobalRef<'a> {
    /// A reference to a `Window` object.
    Window(&'a window::Window),
    /// A reference to a `WorkerGlobalScope` object.
    Worker(&'a WorkerGlobalScope),
}

/// A stack-based rooted reference to a global object.
pub enum GlobalRoot {
    /// A root for a `Window` object.
    Window(Root<window::Window>),
    /// A root for a `WorkerGlobalScope` object.
    Worker(Root<WorkerGlobalScope>),
}

impl<'a> GlobalRef<'a> {
    /// Get the `JSContext` for the `JSRuntime` associated with the thread
    /// this global object is on.
    pub fn get_cx(&self) -> *mut JSContext {
        match *self {
            GlobalRef::Window(ref window) => window.get_cx(),
            GlobalRef::Worker(ref worker) => worker.get_cx(),
        }
    }

    /// Extract a `Window`, causing thread failure if the global object is not
    /// a `Window`.
    pub fn as_window(&self) -> &window::Window {
        match *self {
            GlobalRef::Window(window) => window,
            GlobalRef::Worker(_) => panic!("expected a Window scope"),
        }
    }

    /// Get the `PipelineId` for this global scope.
    pub fn pipeline(&self) -> PipelineId {
        match *self {
            GlobalRef::Window(window) => window.pipeline(),
            GlobalRef::Worker(worker) => worker.pipeline(),
        }
    }

    /// Get a `mem::ProfilerChan` to send messages to the memory profiler thread.
    pub fn mem_profiler_chan(&self) -> mem::ProfilerChan {
        match *self {
            GlobalRef::Window(window) => window.mem_profiler_chan(),
            GlobalRef::Worker(worker) => worker.mem_profiler_chan(),
        }
    }

    /// Get a `ConstellationChan` to send messages to the constellation channel when available.
    pub fn constellation_chan(&self) -> ConstellationChan<ConstellationMsg> {
        match *self {
            GlobalRef::Window(window) => window.constellation_chan(),
            GlobalRef::Worker(worker) => worker.constellation_chan(),
        }
    }

    /// Get the scheduler channel to request timer events.
    pub fn scheduler_chan(&self) -> IpcSender<TimerEventRequest> {
        match *self {
            GlobalRef::Window(window) => window.scheduler_chan(),
            GlobalRef::Worker(worker) => worker.scheduler_chan(),
        }
    }

    /// Get an `IpcSender<ScriptToDevtoolsControlMsg>` to send messages to Devtools
    /// thread when available.
    pub fn devtools_chan(&self) -> Option<IpcSender<ScriptToDevtoolsControlMsg>> {
        match *self {
            GlobalRef::Window(window) => window.devtools_chan(),
            GlobalRef::Worker(worker) => worker.devtools_chan(),
        }
    }

    /// Get the `ResourceThread` for this global scope.
    pub fn resource_thread(&self) -> ResourceThread {
        match *self {
            GlobalRef::Window(ref window) => {
                let doc = window.Document();
                let doc = doc.r();
                let loader = doc.loader();
                (*loader.resource_thread).clone()
            }
            GlobalRef::Worker(ref worker) => worker.resource_thread().clone(),
        }
    }

    /// Get the worker's id.
    pub fn get_worker_id(&self) -> Option<WorkerId> {
        match *self {
            GlobalRef::Window(_) => None,
            GlobalRef::Worker(ref worker) => Some(worker.get_worker_id()),
        }
    }

    /// Get next worker id.
    pub fn get_next_worker_id(&self) -> WorkerId {
        match *self {
            GlobalRef::Window(ref window) => window.get_next_worker_id(),
            GlobalRef::Worker(ref worker) => worker.get_next_worker_id(),
        }
    }

    /// Get the URL for this global scope.
    pub fn get_url(&self) -> Url {
        match *self {
            GlobalRef::Window(ref window) => window.get_url(),
            GlobalRef::Worker(ref worker) => worker.get_url().clone(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn dom_manipulation_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.dom_manipulation_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn user_interaction_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.user_interaction_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn networking_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.networking_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn history_traversal_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.history_traversal_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn file_reading_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.file_reading_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// Create a new sender/receiver pair that can be used to implement an on-demand
    /// event loop. Used for implementing web APIs that require blocking semantics
    /// without resorting to nested event loops.
    pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) {
        match *self {
            GlobalRef::Window(ref window) => window.new_script_pair(),
            GlobalRef::Worker(ref worker) => worker.new_script_pair(),
        }
    }

    /// Process a single event as if it were the next event in the thread queue for
    /// this global.
    pub fn process_event(&self, msg: CommonScriptMsg) {
        match *self {
            GlobalRef::Window(_) => ScriptThread::process_event(msg),
            GlobalRef::Worker(ref worker) => worker.process_event(msg),
        }
    }

    /// Evaluate the JS messages on the `RootedValue` of this global
    pub fn evaluate_js_on_global_with_result(&self, code: &str, rval: MutableHandleValue) {
        match *self {
            GlobalRef::Window(window) => window.evaluate_js_on_global_with_result(code, rval),
            GlobalRef::Worker(worker) => worker.evaluate_js_on_global_with_result(code, rval),
        }
    }

    /// Set the `bool` value to indicate whether developer tools has requested
    /// updates from the global
    pub fn set_devtools_wants_updates(&self, send_updates: bool) {
        match *self {
            GlobalRef::Window(window) => window.set_devtools_wants_updates(send_updates),
            GlobalRef::Worker(worker) => worker.set_devtools_wants_updates(send_updates),
        }
    }

    /// Schedule the given `callback` to be invoked after at least `duration` milliseconds have
    /// passed.
    pub fn schedule_callback(&self,
                             callback: Box<ScheduledCallback>,
                             duration: MsDuration)
                             -> TimerHandle {
        match *self {
            GlobalRef::Window(window) => window.schedule_callback(callback, duration),
            GlobalRef::Worker(worker) => worker.schedule_callback(callback, duration),
        }
    }

    /// Unschedule a previously-scheduled callback.
    pub fn unschedule_callback(&self, handle: TimerHandle) {
        match *self {
            GlobalRef::Window(window) => window.unschedule_callback(handle),
            GlobalRef::Worker(worker) => worker.unschedule_callback(handle),
        }
    }

    /// Returns the receiver's reflector.
    pub fn reflector(&self) -> &Reflector {
        match *self {
            GlobalRef::Window(ref window) => window.reflector(),
            GlobalRef::Worker(ref worker) => worker.reflector(),
        }
    }
}

impl GlobalRoot {
    /// Obtain a safe reference to the global object that cannot outlive the
    /// lifetime of this root.
    pub fn r(&self) -> GlobalRef {
        match *self {
            GlobalRoot::Window(ref window) => GlobalRef::Window(window.r()),
            GlobalRoot::Worker(ref worker) => GlobalRef::Worker(worker.r()),
        }
    }
}

/// Returns the global object of the realm that the given DOM object's reflector was created in.
pub fn global_root_from_reflector<T: Reflectable>(reflector: &T) -> GlobalRoot {
    global_root_from_object(*reflector.reflector().get_jsobject())
}

/// Returns the global object of the realm that the given JS object was created in.
#[allow(unrooted_must_root)]
pub fn global_root_from_object(obj: *mut JSObject) -> GlobalRoot {
    unsafe {
        let global = GetGlobalForObjectCrossCompartment(obj);
        let clasp = JS_GetClass(global);
        assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
        match root_from_object(global) {
            Ok(window) => return GlobalRoot::Window(window),
            Err(_) => (),
        }

        match root_from_object(global) {
            Ok(worker) => return GlobalRoot::Worker(worker),
            Err(_) => (),
        }

        panic!("found DOM global that doesn't unwrap to Window or WorkerGlobalScope")
    }
}
<commit_msg>script: Remove some unused imports<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Abstractions for global scopes.
//!
//! This module contains smart pointers to global scopes, to simplify writing
//! code that works in workers as well as window scopes.

use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::conversions::root_from_object;
use dom::bindings::js::Root;
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::window::{self, ScriptHelpers};
use dom::workerglobalscope::WorkerGlobalScope;
use ipc_channel::ipc::IpcSender;
use js::jsapi::GetGlobalForObjectCrossCompartment;
use js::jsapi::{JSContext, JSObject, JS_GetClass, MutableHandleValue};
use js::{JSCLASS_IS_DOMJSCLASS, JSCLASS_IS_GLOBAL};
use msg::constellation_msg::{ConstellationChan, PipelineId};
use net_traits::ResourceThread;
use profile_traits::mem;
use script_thread::{CommonScriptMsg, ScriptChan, ScriptPort, ScriptThread};
use script_traits::{MsDuration, ScriptMsg as ConstellationMsg, TimerEventRequest};
use timers::{ScheduledCallback, TimerHandle};
use url::Url;

/// A freely-copyable reference to a rooted global object.
#[derive(Copy, Clone)]
pub enum GlobalRef<'a> {
    /// A reference to a `Window` object.
    Window(&'a window::Window),
    /// A reference to a `WorkerGlobalScope` object.
    Worker(&'a WorkerGlobalScope),
}

/// A stack-based rooted reference to a global object.
pub enum GlobalRoot {
    /// A root for a `Window` object.
    Window(Root<window::Window>),
    /// A root for a `WorkerGlobalScope` object.
    Worker(Root<WorkerGlobalScope>),
}

impl<'a> GlobalRef<'a> {
    /// Get the `JSContext` for the `JSRuntime` associated with the thread
    /// this global object is on.
    pub fn get_cx(&self) -> *mut JSContext {
        match *self {
            GlobalRef::Window(ref window) => window.get_cx(),
            GlobalRef::Worker(ref worker) => worker.get_cx(),
        }
    }

    /// Extract a `Window`, causing thread failure if the global object is not
    /// a `Window`.
    pub fn as_window(&self) -> &window::Window {
        match *self {
            GlobalRef::Window(window) => window,
            GlobalRef::Worker(_) => panic!("expected a Window scope"),
        }
    }

    /// Get the `PipelineId` for this global scope.
    pub fn pipeline(&self) -> PipelineId {
        match *self {
            GlobalRef::Window(window) => window.pipeline(),
            GlobalRef::Worker(worker) => worker.pipeline(),
        }
    }

    /// Get a `mem::ProfilerChan` to send messages to the memory profiler thread.
    pub fn mem_profiler_chan(&self) -> mem::ProfilerChan {
        match *self {
            GlobalRef::Window(window) => window.mem_profiler_chan(),
            GlobalRef::Worker(worker) => worker.mem_profiler_chan(),
        }
    }

    /// Get a `ConstellationChan` to send messages to the constellation channel when available.
    pub fn constellation_chan(&self) -> ConstellationChan<ConstellationMsg> {
        match *self {
            GlobalRef::Window(window) => window.constellation_chan(),
            GlobalRef::Worker(worker) => worker.constellation_chan(),
        }
    }

    /// Get the scheduler channel to request timer events.
    pub fn scheduler_chan(&self) -> IpcSender<TimerEventRequest> {
        match *self {
            GlobalRef::Window(window) => window.scheduler_chan(),
            GlobalRef::Worker(worker) => worker.scheduler_chan(),
        }
    }

    /// Get an `IpcSender<ScriptToDevtoolsControlMsg>` to send messages to Devtools
    /// thread when available.
    pub fn devtools_chan(&self) -> Option<IpcSender<ScriptToDevtoolsControlMsg>> {
        match *self {
            GlobalRef::Window(window) => window.devtools_chan(),
            GlobalRef::Worker(worker) => worker.devtools_chan(),
        }
    }

    /// Get the `ResourceThread` for this global scope.
    pub fn resource_thread(&self) -> ResourceThread {
        match *self {
            GlobalRef::Window(ref window) => {
                let doc = window.Document();
                let doc = doc.r();
                let loader = doc.loader();
                (*loader.resource_thread).clone()
            }
            GlobalRef::Worker(ref worker) => worker.resource_thread().clone(),
        }
    }

    /// Get the worker's id.
    pub fn get_worker_id(&self) -> Option<WorkerId> {
        match *self {
            GlobalRef::Window(_) => None,
            GlobalRef::Worker(ref worker) => Some(worker.get_worker_id()),
        }
    }

    /// Get next worker id.
    pub fn get_next_worker_id(&self) -> WorkerId {
        match *self {
            GlobalRef::Window(ref window) => window.get_next_worker_id(),
            GlobalRef::Worker(ref worker) => worker.get_next_worker_id(),
        }
    }

    /// Get the URL for this global scope.
    pub fn get_url(&self) -> Url {
        match *self {
            GlobalRef::Window(ref window) => window.get_url(),
            GlobalRef::Worker(ref worker) => worker.get_url().clone(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn dom_manipulation_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.dom_manipulation_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn user_interaction_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.user_interaction_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn networking_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.networking_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn history_traversal_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.history_traversal_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// `ScriptChan` used to send messages to the event loop of this global's
    /// thread.
    pub fn file_reading_thread_source(&self) -> Box<ScriptChan + Send> {
        match *self {
            GlobalRef::Window(ref window) => window.file_reading_thread_source(),
            GlobalRef::Worker(ref worker) => worker.script_chan(),
        }
    }

    /// Create a new sender/receiver pair that can be used to implement an on-demand
    /// event loop. Used for implementing web APIs that require blocking semantics
    /// without resorting to nested event loops.
    pub fn new_script_pair(&self) -> (Box<ScriptChan + Send>, Box<ScriptPort + Send>) {
        match *self {
            GlobalRef::Window(ref window) => window.new_script_pair(),
            GlobalRef::Worker(ref worker) => worker.new_script_pair(),
        }
    }

    /// Process a single event as if it were the next event in the thread queue for
    /// this global.
    pub fn process_event(&self, msg: CommonScriptMsg) {
        match *self {
            GlobalRef::Window(_) => ScriptThread::process_event(msg),
            GlobalRef::Worker(ref worker) => worker.process_event(msg),
        }
    }

    /// Evaluate the JS messages on the `RootedValue` of this global
    pub fn evaluate_js_on_global_with_result(&self, code: &str, rval: MutableHandleValue) {
        match *self {
            GlobalRef::Window(window) => window.evaluate_js_on_global_with_result(code, rval),
            GlobalRef::Worker(worker) => worker.evaluate_js_on_global_with_result(code, rval),
        }
    }

    /// Set the `bool` value to indicate whether developer tools has requested
    /// updates from the global
    pub fn set_devtools_wants_updates(&self, send_updates: bool) {
        match *self {
            GlobalRef::Window(window) => window.set_devtools_wants_updates(send_updates),
            GlobalRef::Worker(worker) => worker.set_devtools_wants_updates(send_updates),
        }
    }

    /// Schedule the given `callback` to be invoked after at least `duration` milliseconds have
    /// passed.
    pub fn schedule_callback(&self,
                             callback: Box<ScheduledCallback>,
                             duration: MsDuration)
                             -> TimerHandle {
        match *self {
            GlobalRef::Window(window) => window.schedule_callback(callback, duration),
            GlobalRef::Worker(worker) => worker.schedule_callback(callback, duration),
        }
    }

    /// Unschedule a previously-scheduled callback.
    pub fn unschedule_callback(&self, handle: TimerHandle) {
        match *self {
            GlobalRef::Window(window) => window.unschedule_callback(handle),
            GlobalRef::Worker(worker) => worker.unschedule_callback(handle),
        }
    }

    /// Returns the receiver's reflector.
    pub fn reflector(&self) -> &Reflector {
        match *self {
            GlobalRef::Window(ref window) => window.reflector(),
            GlobalRef::Worker(ref worker) => worker.reflector(),
        }
    }
}

impl GlobalRoot {
    /// Obtain a safe reference to the global object that cannot outlive the
    /// lifetime of this root.
    pub fn r(&self) -> GlobalRef {
        match *self {
            GlobalRoot::Window(ref window) => GlobalRef::Window(window.r()),
            GlobalRoot::Worker(ref worker) => GlobalRef::Worker(worker.r()),
        }
    }
}

/// Returns the global object of the realm that the given DOM object's reflector was created in.
pub fn global_root_from_reflector<T: Reflectable>(reflector: &T) -> GlobalRoot {
    global_root_from_object(*reflector.reflector().get_jsobject())
}

/// Returns the global object of the realm that the given JS object was created in.
#[allow(unrooted_must_root)]
pub fn global_root_from_object(obj: *mut JSObject) -> GlobalRoot {
    unsafe {
        let global = GetGlobalForObjectCrossCompartment(obj);
        let clasp = JS_GetClass(global);
        assert!(((*clasp).flags & (JSCLASS_IS_DOMJSCLASS | JSCLASS_IS_GLOBAL)) != 0);
        match root_from_object(global) {
            Ok(window) => return GlobalRoot::Window(window),
            Err(_) => (),
        }

        match root_from_object(global) {
            Ok(worker) => return GlobalRoot::Worker(worker),
            Err(_) => (),
        }

        panic!("found DOM global that doesn't unwrap to Window or WorkerGlobalScope")
    }
}
<|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::cell::DOMRefCell;
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::utils::WindowProxyHandler;
use dom::bindings::utils::get_array_index_from_id;
use dom::document::Document;
use dom::element::Element;
use dom::window::Window;
use js::JSCLASS_IS_GLOBAL;
use js::glue::{CreateWrapperProxyHandler, GetProxyPrivate, NewWindowProxy};
use js::glue::{ProxyTraps, SetProxyExtra};
use js::jsapi::{Handle, HandleId, HandleObject, JSAutoCompartment, JSAutoRequest, JSContext};
use js::jsapi::{JSErrNum, JSObject, JSPropertyDescriptor, JS_AlreadyHasOwnPropertyById};
use js::jsapi::{JS_DefinePropertyById6, JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo};
use js::jsapi::{JS_GetClass, JS_GetOwnPropertyDescriptorById, MutableHandle, MutableHandleValue};
use js::jsapi::{ObjectOpResult, RootedObject, RootedValue};
use js::jsval::{ObjectValue, PrivateValue, UndefinedValue};

#[dom_struct]
pub struct BrowsingContext {
    reflector: Reflector,
    history: DOMRefCell<Vec<SessionHistoryEntry>>,
    active_index: usize,
    frame_element: Option<JS<Element>>,
}

impl BrowsingContext {
    pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
        BrowsingContext {
            reflector: Reflector::new(),
            history: DOMRefCell::new(vec![]),
            active_index: 0,
            frame_element: frame_element.map(JS::from_ref),
        }
    }

    #[allow(unsafe_code)]
    pub fn new(window: &Window, frame_element: Option<&Element>) -> Root<BrowsingContext> {
        unsafe {
            let WindowProxyHandler(handler) = window.windowproxy_handler();
            assert!(!handler.is_null());

            let cx = window.get_cx();
            let _ar = JSAutoRequest::new(cx);
            let parent = window.reflector().get_jsobject();
            assert!(!parent.get().is_null());
            assert!(((*JS_GetClass(parent.get())).flags & JSCLASS_IS_GLOBAL) != 0);
            let _ac = JSAutoCompartment::new(cx, parent.get());
            let window_proxy = RootedObject::new(cx,
                NewWindowProxy(cx, parent, handler));
            assert!(!window_proxy.ptr.is_null());

            let object = box BrowsingContext::new_inherited(frame_element);

            let raw = Box::into_raw(object);
            SetProxyExtra(window_proxy.ptr, 0, PrivateValue(raw as *const _));

            (*raw).init_reflector(window_proxy.ptr);

            Root::from_ref(&*raw)
        }
    }

    pub fn init(&self, document: &Document) {
        assert!(self.history.borrow().is_empty());
        assert_eq!(self.active_index, 0);
        self.history.borrow_mut().push(SessionHistoryEntry::new(document));
    }

    pub fn active_document(&self) -> Root<Document> {
        Root::from_ref(&*self.history.borrow()[self.active_index].document)
    }

    pub fn active_window(&self) -> Root<Window> {
        Root::from_ref(self.active_document().window())
    }

    pub fn frame_element(&self) -> Option<&Element> {
        self.frame_element.r()
    }

    pub fn window_proxy(&self) -> *mut JSObject {
        let window_proxy = self.reflector.get_jsobject();
        assert!(!window_proxy.get().is_null());
        window_proxy.get()
    }
}

// This isn't a DOM struct, just a convenience struct
// without a reflector, so we don't mark this as #[dom_struct]
#[must_root]
#[privatize]
#[derive(JSTraceable, HeapSizeOf)]
pub struct SessionHistoryEntry {
    document: JS<Document>,
    children: Vec<JS<BrowsingContext>>,
}

impl SessionHistoryEntry {
    fn new(document: &Document) -> SessionHistoryEntry {
        SessionHistoryEntry {
            document: JS::from_ref(document),
            children: vec![],
        }
    }
}

#[allow(unsafe_code)]
unsafe fn GetSubframeWindow(cx: *mut JSContext,
                            proxy: HandleObject,
                            id: HandleId)
                            -> Option<Root<Window>> {
    let index = get_array_index_from_id(cx, id);
    if let Some(index) = index {
        let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
        let win = root_from_handleobject::<Window>(target.handle()).unwrap();
        let mut found = false;
        return win.IndexedGetter(index, &mut found);
    }

    None
}

#[allow(unsafe_code)]
unsafe extern "C" fn getOwnPropertyDescriptor(cx: *mut JSContext,
                                              proxy: HandleObject,
                                              id: HandleId,
                                              desc: MutableHandle<JSPropertyDescriptor>)
                                              -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if let Some(window) = window {
        let mut val = RootedValue::new(cx, UndefinedValue());
        window.to_jsval(cx, val.handle_mut());
        (*desc.ptr).value = val.ptr;
        fill_property_descriptor(&mut *desc.ptr, *proxy.ptr, true);
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    if !JS_GetOwnPropertyDescriptorById(cx, target.handle(), id, desc) {
        return false;
    }

    assert!(desc.get().obj.is_null() || desc.get().obj == target.ptr);
    if desc.get().obj == target.ptr {
        desc.get().obj = *proxy.ptr;
    }

    true
}

#[allow(unsafe_code)]
unsafe extern "C" fn defineProperty(cx: *mut JSContext,
                                    proxy: HandleObject,
                                    id: HandleId,
                                    desc: Handle<JSPropertyDescriptor>,
                                    res: *mut ObjectOpResult)
                                    -> bool {
    if get_array_index_from_id(cx, id).is_some() {
        // Spec says to Reject whether this is a supported index or not,
        // since we have no indexed setter or indexed creator.  That means
        // throwing in strict mode (FIXME: Bug 828137), doing nothing in
        // non-strict mode.
        (*res).code_ = JSErrNum::JSMSG_CANT_DEFINE_WINDOW_ELEMENT as ::libc::uintptr_t;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_DefinePropertyById6(cx, target.handle(), id, desc, res)
}

#[allow(unsafe_code)]
unsafe extern "C" fn hasOwn(cx: *mut JSContext,
                            proxy: HandleObject,
                            id: HandleId,
                            bp: *mut bool)
                            -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if window.is_some() {
        *bp = true;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    let mut found = false;
    if !JS_AlreadyHasOwnPropertyById(cx, target.handle(), id, &mut found) {
        return false;
    }

    *bp = found;
    true
}

#[allow(unsafe_code)]
unsafe extern "C" fn get(cx: *mut JSContext,
                         proxy: HandleObject,
                         receiver: HandleObject,
                         id: HandleId,
                         vp: MutableHandleValue)
                         -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if let Some(window) = window {
        window.to_jsval(cx, vp);
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_ForwardGetPropertyTo(cx, target.handle(), id, receiver, vp)
}

#[allow(unsafe_code)]
unsafe extern "C" fn set(cx: *mut JSContext,
                         proxy: HandleObject,
                         receiver: HandleObject,
                         id: HandleId,
                         vp: MutableHandleValue,
                         res: *mut ObjectOpResult)
                         -> bool {
    if get_array_index_from_id(cx, id).is_some() {
        // Reject (which means throw if and only if strict) the set.
        (*res).code_ = JSErrNum::JSMSG_READ_ONLY as ::libc::uintptr_t;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    let receiver = RootedValue::new(cx, ObjectValue(&**receiver.ptr));
    JS_ForwardSetPropertyTo(cx,
                            target.handle(),
                            id,
                            vp.to_handle(),
                            receiver.handle(),
                            res)
}

static PROXY_HANDLER: ProxyTraps = ProxyTraps {
    enter: None,
    getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
    defineProperty: Some(defineProperty),
    ownPropertyKeys: None,
    delete_: None,
    enumerate: None,
    preventExtensions: None,
    isExtensible: None,
    has: None,
    get: Some(get),
    set: Some(set),
    call: None,
    construct: None,
    getPropertyDescriptor: Some(get_property_descriptor),
    hasOwn: Some(hasOwn),
    getOwnEnumerablePropertyKeys: None,
    nativeCall: None,
    hasInstance: None,
    objectClassIs: None,
    className: None,
    fun_toString: None,
    boxedValue_unbox: None,
    defaultValue: None,
    trace: None,
    finalize: None,
    objectMoved: None,
    isCallable: None,
    isConstructor: None,
};

#[allow(unsafe_code)]
pub fn new_window_proxy_handler() -> WindowProxyHandler {
    unsafe {
        WindowProxyHandler(CreateWrapperProxyHandler(&PROXY_HANDLER))
    }
}
<commit_msg>Don't use the hasOwn hook anymore in browsingcontext<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::cell::DOMRefCell;
use dom::bindings::conversions::{ToJSValConvertible, root_from_handleobject};
use dom::bindings::js::{JS, Root, RootedReference};
use dom::bindings::proxyhandler::{fill_property_descriptor, get_property_descriptor};
use dom::bindings::reflector::{Reflectable, Reflector};
use dom::bindings::utils::WindowProxyHandler;
use dom::bindings::utils::get_array_index_from_id;
use dom::document::Document;
use dom::element::Element;
use dom::window::Window;
use js::JSCLASS_IS_GLOBAL;
use js::glue::{CreateWrapperProxyHandler, GetProxyPrivate, NewWindowProxy};
use js::glue::{ProxyTraps, SetProxyExtra};
use js::jsapi::{Handle, HandleId, HandleObject, JSAutoCompartment, JSAutoRequest, JSContext};
use js::jsapi::{JSErrNum, JSObject, JSPropertyDescriptor, JS_DefinePropertyById6};
use js::jsapi::{JS_ForwardGetPropertyTo, JS_ForwardSetPropertyTo, JS_GetClass};
use js::jsapi::{JS_GetOwnPropertyDescriptorById, JS_HasPropertyById, MutableHandle};
use js::jsapi::{MutableHandleValue, ObjectOpResult, RootedObject, RootedValue};
use js::jsval::{ObjectValue, PrivateValue, UndefinedValue};

#[dom_struct]
pub struct BrowsingContext {
    reflector: Reflector,
    history: DOMRefCell<Vec<SessionHistoryEntry>>,
    active_index: usize,
    frame_element: Option<JS<Element>>,
}

impl BrowsingContext {
    pub fn new_inherited(frame_element: Option<&Element>) -> BrowsingContext {
        BrowsingContext {
            reflector: Reflector::new(),
            history: DOMRefCell::new(vec![]),
            active_index: 0,
            frame_element: frame_element.map(JS::from_ref),
        }
    }

    #[allow(unsafe_code)]
    pub fn new(window: &Window, frame_element: Option<&Element>) -> Root<BrowsingContext> {
        unsafe {
            let WindowProxyHandler(handler) = window.windowproxy_handler();
            assert!(!handler.is_null());

            let cx = window.get_cx();
            let _ar = JSAutoRequest::new(cx);
            let parent = window.reflector().get_jsobject();
            assert!(!parent.get().is_null());
            assert!(((*JS_GetClass(parent.get())).flags & JSCLASS_IS_GLOBAL) != 0);
            let _ac = JSAutoCompartment::new(cx, parent.get());
            let window_proxy = RootedObject::new(cx,
                NewWindowProxy(cx, parent, handler));
            assert!(!window_proxy.ptr.is_null());

            let object = box BrowsingContext::new_inherited(frame_element);

            let raw = Box::into_raw(object);
            SetProxyExtra(window_proxy.ptr, 0, PrivateValue(raw as *const _));

            (*raw).init_reflector(window_proxy.ptr);

            Root::from_ref(&*raw)
        }
    }

    pub fn init(&self, document: &Document) {
        assert!(self.history.borrow().is_empty());
        assert_eq!(self.active_index, 0);
        self.history.borrow_mut().push(SessionHistoryEntry::new(document));
    }

    pub fn active_document(&self) -> Root<Document> {
        Root::from_ref(&*self.history.borrow()[self.active_index].document)
    }

    pub fn active_window(&self) -> Root<Window> {
        Root::from_ref(self.active_document().window())
    }

    pub fn frame_element(&self) -> Option<&Element> {
        self.frame_element.r()
    }

    pub fn window_proxy(&self) -> *mut JSObject {
        let window_proxy = self.reflector.get_jsobject();
        assert!(!window_proxy.get().is_null());
        window_proxy.get()
    }
}

// This isn't a DOM struct, just a convenience struct
// without a reflector, so we don't mark this as #[dom_struct]
#[must_root]
#[privatize]
#[derive(JSTraceable, HeapSizeOf)]
pub struct SessionHistoryEntry {
    document: JS<Document>,
    children: Vec<JS<BrowsingContext>>,
}

impl SessionHistoryEntry {
    fn new(document: &Document) -> SessionHistoryEntry {
        SessionHistoryEntry {
            document: JS::from_ref(document),
            children: vec![],
        }
    }
}

#[allow(unsafe_code)]
unsafe fn GetSubframeWindow(cx: *mut JSContext,
                            proxy: HandleObject,
                            id: HandleId)
                            -> Option<Root<Window>> {
    let index = get_array_index_from_id(cx, id);
    if let Some(index) = index {
        let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
        let win = root_from_handleobject::<Window>(target.handle()).unwrap();
        let mut found = false;
        return win.IndexedGetter(index, &mut found);
    }

    None
}

#[allow(unsafe_code)]
unsafe extern "C" fn getOwnPropertyDescriptor(cx: *mut JSContext,
                                              proxy: HandleObject,
                                              id: HandleId,
                                              desc: MutableHandle<JSPropertyDescriptor>)
                                              -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if let Some(window) = window {
        let mut val = RootedValue::new(cx, UndefinedValue());
        window.to_jsval(cx, val.handle_mut());
        (*desc.ptr).value = val.ptr;
        fill_property_descriptor(&mut *desc.ptr, *proxy.ptr, true);
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    if !JS_GetOwnPropertyDescriptorById(cx, target.handle(), id, desc) {
        return false;
    }

    assert!(desc.get().obj.is_null() || desc.get().obj == target.ptr);
    if desc.get().obj == target.ptr {
        desc.get().obj = *proxy.ptr;
    }

    true
}

#[allow(unsafe_code)]
unsafe extern "C" fn defineProperty(cx: *mut JSContext,
                                    proxy: HandleObject,
                                    id: HandleId,
                                    desc: Handle<JSPropertyDescriptor>,
                                    res: *mut ObjectOpResult)
                                    -> bool {
    if get_array_index_from_id(cx, id).is_some() {
        // Spec says to Reject whether this is a supported index or not,
        // since we have no indexed setter or indexed creator.  That means
        // throwing in strict mode (FIXME: Bug 828137), doing nothing in
        // non-strict mode.
        (*res).code_ = JSErrNum::JSMSG_CANT_DEFINE_WINDOW_ELEMENT as ::libc::uintptr_t;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_DefinePropertyById6(cx, target.handle(), id, desc, res)
}

#[allow(unsafe_code)]
unsafe extern "C" fn has(cx: *mut JSContext,
                         proxy: HandleObject,
                         id: HandleId,
                         bp: *mut bool)
                         -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if window.is_some() {
        *bp = true;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    let mut found = false;
    if !JS_HasPropertyById(cx, target.handle(), id, &mut found) {
        return false;
    }

    *bp = found;
    true
}

#[allow(unsafe_code)]
unsafe extern "C" fn get(cx: *mut JSContext,
                         proxy: HandleObject,
                         receiver: HandleObject,
                         id: HandleId,
                         vp: MutableHandleValue)
                         -> bool {
    let window = GetSubframeWindow(cx, proxy, id);
    if let Some(window) = window {
        window.to_jsval(cx, vp);
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    JS_ForwardGetPropertyTo(cx, target.handle(), id, receiver, vp)
}

#[allow(unsafe_code)]
unsafe extern "C" fn set(cx: *mut JSContext,
                         proxy: HandleObject,
                         receiver: HandleObject,
                         id: HandleId,
                         vp: MutableHandleValue,
                         res: *mut ObjectOpResult)
                         -> bool {
    if get_array_index_from_id(cx, id).is_some() {
        // Reject (which means throw if and only if strict) the set.
        (*res).code_ = JSErrNum::JSMSG_READ_ONLY as ::libc::uintptr_t;
        return true;
    }

    let target = RootedObject::new(cx, GetProxyPrivate(*proxy.ptr).to_object());
    let receiver = RootedValue::new(cx, ObjectValue(&**receiver.ptr));
    JS_ForwardSetPropertyTo(cx,
                            target.handle(),
                            id,
                            vp.to_handle(),
                            receiver.handle(),
                            res)
}

static PROXY_HANDLER: ProxyTraps = ProxyTraps {
    enter: None,
    getOwnPropertyDescriptor: Some(getOwnPropertyDescriptor),
    defineProperty: Some(defineProperty),
    ownPropertyKeys: None,
    delete_: None,
    enumerate: None,
    preventExtensions: None,
    isExtensible: None,
    has: Some(has),
    get: Some(get),
    set: Some(set),
    call: None,
    construct: None,
    getPropertyDescriptor: Some(get_property_descriptor),
    hasOwn: None,
    getOwnEnumerablePropertyKeys: None,
    nativeCall: None,
    hasInstance: None,
    objectClassIs: None,
    className: None,
    fun_toString: None,
    boxedValue_unbox: None,
    defaultValue: None,
    trace: None,
    finalize: None,
    objectMoved: None,
    isCallable: None,
    isConstructor: None,
};

#[allow(unsafe_code)]
pub fn new_window_proxy_handler() -> WindowProxyHandler {
    unsafe {
        WindowProxyHandler(CreateWrapperProxyHandler(&PROXY_HANDLER))
    }
}
<|endoftext|>


<commit_before>use crate::t;
use std::path::{Path, PathBuf};
use std::{
    env, fs,
    io::{self, Write},
};

pub fn setup(src_path: &Path, include_name: &str) {
    let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);

    if cfg_file.as_ref().map_or(false, |f| f.exists()) {
        let file = cfg_file.unwrap();
        println!(
            "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
            file.display()
        );
        println!(
            "help: try adding `profile = \"{}\"` at the top of {}",
            include_name,
            file.display()
        );
        println!(
            "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}",
            src_path.display(),
            include_name
        );
        std::process::exit(1);
    }

    let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml"));
    let settings = format!(
        "# Includes one of the default files in src/bootstrap/defaults\n\
    profile = \"{}\"\n",
        include_name
    );
    t!(fs::write(path, settings));

    let include_path =
        format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name);
    println!("`x.py` will now use the configuration at {}", include_path);

    let suggestions = match include_name {
        "codegen" | "compiler" => &["check", "build", "test"][..],
        "library" => &["check", "build", "test library/std", "doc"],
        "user" => &["dist", "build"],
        _ => return,
    };

    t!(install_git_hook_maybe(src_path));

    println!("To get started, try one of the following commands:");
    for cmd in suggestions {
        println!("- `x.py {}`", cmd);
    }

    if include_name != "user" {
        println!(
            "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
        );
    }
}

// Used to get the path for `Subcommand::Setup`
pub fn interactive_path() -> io::Result<String> {
    let mut input = String::new();
    println!(
        "Welcome to the Rust project! What do you want to do with x.py?
a) Contribute to the standard library
b) Contribute to the compiler
c) Contribute to the compiler, and also modify LLVM or codegen
d) Install Rust from source"
    );
    let template = loop {
        print!("Please choose one (a/b/c/d): ");
        io::stdout().flush()?;
        io::stdin().read_line(&mut input)?;
        break match input.trim().to_lowercase().as_str() {
            "a" | "lib" | "library" => "library",
            "b" | "compiler" => "compiler",
            "c" | "llvm" => "llvm",
            "d" | "user" | "maintainer" => "maintainer",
            _ => {
                println!("error: unrecognized option '{}'", input.trim());
                println!("note: press Ctrl+C to exit");
                continue;
            }
        };
    };
    Ok(template.to_owned())
}

// install a git hook to automatically run tidy --bless, if they want
fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
    let mut input = String::new();
    println!(
        "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` on each commit
to ensure your code is up to par. If you decide later that this behavior is undesirable,
simply delete the `pre-commit` file from .git/hooks."
    );

    let should_install = loop {
        print!("Would you like to install the git hook?: [y/N] ");
        io::stdout().flush()?;
        io::stdin().read_line(&mut input)?;
        break match input.trim().to_lowercase().as_str() {
            "y" | "yes" => true,
            // is this the right way to check for "entered nothing"?
            "n" | "no" | "" => false,
            _ => {
                println!("error: unrecognized option '{}'", input.trim());
                println!("note: press Ctrl+C to exit");
                continue;
            }
        };
    };

    if should_install {
        let src = src_path.join("/etc/pre-commit.rs");
        let dst = src_path.join("/.git/hooks/pre-commit");
        fs::hard_link(src, dst)?;
        println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`");
    } else {
        println!("Ok, skipping installation!");
    };

    Ok(())
}
<commit_msg>Make changes based on @jyn514's comments<commit_after>use crate::t;
use std::path::{Path, PathBuf};
use std::{
    env, fs,
    io::{self, Write},
};

pub fn setup(src_path: &Path, include_name: &str) {
    let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);

    if cfg_file.as_ref().map_or(false, |f| f.exists()) {
        let file = cfg_file.unwrap();
        println!(
            "error: you asked `x.py` to setup a new config file, but one already exists at `{}`",
            file.display()
        );
        println!(
            "help: try adding `profile = \"{}\"` at the top of {}",
            include_name,
            file.display()
        );
        println!(
            "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}",
            src_path.display(),
            include_name
        );
        std::process::exit(1);
    }

    let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml"));
    let settings = format!(
        "# Includes one of the default files in src/bootstrap/defaults\n\
    profile = \"{}\"\n",
        include_name
    );
    t!(fs::write(path, settings));

    let include_path =
        format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name);
    println!("`x.py` will now use the configuration at {}", include_path);

    let suggestions = match include_name {
        "codegen" | "compiler" => &["check", "build", "test"][..],
        "library" => &["check", "build", "test library/std", "doc"],
        "user" => &["dist", "build"],
        _ => return,
    };

    println!();

    t!(install_git_hook_maybe(src_path));

    println!();

    println!("To get started, try one of the following commands:");
    for cmd in suggestions {
        println!("- `x.py {}`", cmd);
    }

    if include_name != "user" {
        println!(
            "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html"
        );
    }
}

// Used to get the path for `Subcommand::Setup`
pub fn interactive_path() -> io::Result<String> {
    let mut input = String::new();
    println!(
        "Welcome to the Rust project! What do you want to do with x.py?
a) Contribute to the standard library
b) Contribute to the compiler
c) Contribute to the compiler, and also modify LLVM or codegen
d) Install Rust from source"
    );
    let template = loop {
        print!("Please choose one (a/b/c/d): ");
        io::stdout().flush()?;
        io::stdin().read_line(&mut input)?;
        break match input.trim().to_lowercase().as_str() {
            "a" | "lib" | "library" => "library",
            "b" | "compiler" => "compiler",
            "c" | "llvm" => "llvm",
            "d" | "user" | "maintainer" => "maintainer",
            _ => {
                println!("error: unrecognized option '{}'", input.trim());
                println!("note: press Ctrl+C to exit");
                continue;
            }
        };
    };
    Ok(template.to_owned())
}

// install a git hook to automatically run tidy --bless, if they want
fn install_git_hook_maybe(src_path: &Path) -> io::Result<()> {
    let mut input = String::new();
    println!(
        "Rust's CI will automatically fail if it doesn't pass `tidy`, the internal tool for ensuring code quality.
If you'd like, x.py can install a git hook for you that will automatically run `tidy --bless` on each commit
to ensure your code is up to par. If you decide later that this behavior is undesirable,
simply delete the `pre-commit` file from .git/hooks."
    );

    let should_install = loop {
        print!("Would you like to install the git hook?: [y/N] ");
        io::stdout().flush()?;
        input.clear();
        io::stdin().read_line(&mut input)?;
        break match input.trim().to_lowercase().as_str() {
            "y" | "yes" => true,
            "n" | "no" | "" => false,
            _ => {
                println!("error: unrecognized option '{}'", input.trim());
                println!("note: press Ctrl+C to exit");
                continue;
            }
        };
    };

    Ok(if should_install {
        let src = src_path.join("src").join("etc").join("pre-commit.sh");
        let dst = src_path.join(".git").join("hooks").join("pre-commit");
        match fs::hard_link(src, dst) {
            Err(e) => println!(
                "x.py encountered an error -- do you already have the git hook installed?\n{}",
                e
            ),
            Ok(_) => println!("Linked `src/etc/pre-commit.sh` to `.git/hooks/pre-commit`"),
        };
    } else {
        println!("Ok, skipping installation!");
    })
}
<|endoftext|>


<commit_before>use combine::{eof, value, satisfy_map, token, between, many, many1, try, Parser, Stream,
              ParseError};
use combine::char::{string, spaces};
use combine::primitives::Error;

use api::{Api, ParamType, ParamListEntry, Array};
// use errors::*;
use paramset::ParamSet;
use super::lexer::Tokens;

pub fn parse<I: Stream<Item = Tokens>, A: Api>
    (input: I,
     api: &A)
     -> ::std::result::Result<(Vec<()>, I), ParseError<I>> {
    // TODO remove all the error conversions once https://github.com/brson/error-chain/issues/134 is fixed
    let attribute_begin = token(Tokens::ATTRIBUTEBEGIN).and_then(|_| api.attribute_begin().map_err(|e| Error::Message(e.description().to_owned().into())));
    let attribute_end = token(Tokens::ATTRIBUTEEND).and_then(|_| api.attribute_end().map_err(|e| Error::Message(e.description().to_owned().into())));
    let transform_begin = token(Tokens::TRANSFORMBEGIN).and_then(|_| api.transform_begin().map_err(|e| Error::Message(e.description().to_owned().into())));
    let transform_end = token(Tokens::TRANSFORMEND).and_then(|_| api.transform_end().map_err(|e| Error::Message(e.description().to_owned().into())));
    let world_begin = token(Tokens::WORLDBEGIN).and_then(|_| {
                                                             api.world_begin()
                                                   .map_err(|e| {
                                                                Error::Message(e.description()
                                                                                .to_owned()
                                                                                .into())
                                                            })
                                                         });
    let world_end = token(Tokens::WORLDEND).and_then(|_| {
                                                         api.world_end()
                                                 .map_err(|e| {
                                                              Error::Message(e.description()
                                                                                .to_owned()
                                                                                .into())
                                                          })
                                                     });
    let look_at =
        (token(Tokens::LOOKAT), num(), num(), num(), num(), num(), num(), num(), num(), num())
            .and_then(|(_, ex, ey, ez, lx, ly, lz, ux, uy, uz)| {
                          api.look_at(ex, ey, ez, lx, ly, lz, ux, uy, uz)
                              .map_err(|e| Error::Message(e.description().to_owned().into()))
                      });
    let coord_sys_transform =
        (token(Tokens::COORDSYSTRANSFORM), string_()).and_then(|(_, name)| {
            api.coord_sys_transform(name).map_err(|e| Error::Message(e.description().to_owned().into()))
        });
    let camera =
        (token(Tokens::CAMERA), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                      api.camera(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                  });
    let film = (token(Tokens::FILM), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.film(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let integrator = (token(Tokens::INTEGRATOR), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.integrator(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let arealightsource = (token(Tokens::AREALIGHTSOURCE), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.arealightsource(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let lightsource = (token(Tokens::LIGHTSOURCE), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.lightsource(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let material = (token(Tokens::MATERIAL), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                              api.material(name,
                                                                                &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                          });
    let make_named_material = (token(Tokens::MAKENAMEDMATERIAL), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.make_named_material(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let named_material = (token(Tokens::NAMEDMATERIAL), string_()).and_then(|(_, name)| {
                                                                              api.named_material(name).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                          });
    let sampler = (token(Tokens::SAMPLER), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                        api.sampler(name, &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                    });
    let shape = (token(Tokens::SHAPE), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                        api.shape(name, &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                    });

    let reverse_orientation =
        token(Tokens::REVERSEORIENTATION).and_then(|_| {
                                                       api.reverse_orientation()
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                   });
    let filter =
        (token(Tokens::PIXELFILTER), string_(), param_list())
            .and_then(|(_, name, mut params)| {
                          api.pixel_filter(name, &mut params)
                              .map_err(|e| Error::Message(e.description().to_owned().into()))
                      });
    let scale = (token(Tokens::SCALE), num(), num(), num()).and_then(|(_, sx, sy, sz)| {
                                                                         api.scale(sx, sy, sz)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                     });
    let rotate =
        (token(Tokens::ROTATE), num(), num(), num(), num()).and_then(|(_, angle, dx, dy, dz)| {
                                                                    api.rotate(angle, dx, dy, dz).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                });

    let texture = (token(Tokens::TEXTURE), string_(), string_(), string_(), param_list())
        .and_then(|(_, name, typ, texname, mut params)| {
                      api.texture(name, typ, texname, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let transform = (token::<I>(Tokens::TRANSFORM), num_array())
        .and_then(|(_, nums)| {
                        api.transform(nums[0], nums[1], nums[2], nums[3],
                                      nums[4], nums[5], nums[6], nums[7],
                                      nums[8], nums[9], nums[10], nums[11],
                                      nums[12], nums[13], nums[14], nums[15],
                                    )
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });

    let translate = (token(Tokens::TRANSLATE), num(), num(), num())
        .and_then(|(_, dx, dy, dz)| {
                      api.translate(dx, dy, dz)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });

    let parsers = many1::<Vec<_>, _>(choice!(try(attribute_begin),
                                             try(attribute_end),
                                             try(transform_begin),
                                             try(transform_end),
                                             try(world_begin),
                                             try(world_end),
                                             try(look_at),
                                             try(coord_sys_transform),
                                             try(camera),
                                             try(film),
                                             try(filter),
                                             try(integrator),
                                             try(arealightsource),
                                             try(lightsource),
                                             try(material),
                                             try(texture),
                                             try(make_named_material),
                                             try(named_material),
                                             try(sampler),
                                             try(shape),
                                             try(reverse_orientation),
                                             try(scale),
                                             try(rotate),
                                             try(translate),
                                             try(transform)));
    (parsers, eof()).map(|(res, _)| res).parse(input)
}

fn param_list<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamSet> + 'a>
{
    many(param_list_entry())
        .map(|x| {
                 let mut ps = ParamSet::default();
                 ps.init(x);
                 ps
             })
        .boxed()
}

fn param_type<'a, I: Stream<Item = char> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamType> + 'a>
{
    choice!(try(string("integer").with(value(ParamType::Int))),
            try(string("bool").with(value(ParamType::Bool))),
            try(string("float").with(value(ParamType::Float))),
            try(string("point2").with(value(ParamType::Point2))),
            try(string("vector2").with(value(ParamType::Vector2))),
            try(string("point3").with(value(ParamType::Point3))),
            try(string("vector3").with(value(ParamType::Vector3))),
            try(string("point").with(value(ParamType::Point3))),
            try(string("vector").with(value(ParamType::Vector3))),
            try(string("normal").with(value(ParamType::Normal))),
            try(string("color").with(value(ParamType::Rgb))),
            try(string("rgb").with(value(ParamType::Rgb))),
            try(string("xyz").with(value(ParamType::Xyz))),
            try(string("blackbody").with(value(ParamType::Blackbody))),
            try(string("spectrum").with(value(ParamType::Spectrum))),
            try(string("string").with(value(ParamType::String))),
            try(string("texture").with(value(ParamType::Texture))))
            .boxed()
}

fn param_list_entry_header<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = (ParamType, String)> + 'a>
{
    string_()
        .and_then(|s| match param_type().skip(spaces()).parse(&s[..]) {
                      Ok((t, n)) => Ok((t, n.to_owned())),
                      Err(error) => {
                          Err(Error::Message(format!("Invalid param list entry: {}", error).into()))
                      }
                  })
        .boxed()
}

fn param_list_entry<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamListEntry> + 'a>
{
    (param_list_entry_header(), array())
        .map(|(header, array)| ParamListEntry::new(header.0, header.1, array))
        .boxed()
}

fn array<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = Array> + 'a> {
    choice!(try(string_array().map(Array::StrArray)),
            try(num_array().map(Array::NumArray)))
            .boxed()
}

fn string_array<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = Vec<String>> + 'a>
{
    choice!(try(between(token(Tokens::LBRACK),
                        token(Tokens::RBRACK),
                        many1::<Vec<_>, _>(string_()))),
            try(string_().map(|x| vec![x])))
            .boxed()
}

fn num_array<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = Vec<f32>> + 'a>
{
    choice!(try(between(token(Tokens::LBRACK),
                        token(Tokens::RBRACK),
                        many1::<Vec<_>, _>(num()))),
            try(num().map(|x| vec![x])))
            .boxed()
}

fn num<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = f32> + 'a> {
    satisfy_map(|t| match t {
                    Tokens::NUMBER(n) => Some(n),
                    _ => None,
                })
            .boxed()
}

fn string_<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = String> + 'a> {
    satisfy_map(|t| match t {
                    Tokens::STR(s) => Some(s),
                    _ => None,
                })
            .boxed()
}

// #[test]
// fn test_parse() {
//     let tokens = vec![Tokens::ATTRIBUTEBEGIN, Tokens::ATTRIBUTEEND];
//     let api = ::api::RealApi::default();
//     api.init().unwrap();
//     parse(&tokens[..], &api).unwrap();
// }

#[test]
fn test_array() {
    let p = vec![Tokens::LBRACK,
                 Tokens::NUMBER(50.0),
                 Tokens::NUMBER(12.0),
                 Tokens::RBRACK];
    let foo = vec![];

    assert_eq!(array().parse(&p[..]),
               Ok((Array::NumArray(vec![50.0, 12.0]), &foo[..])));
}

#[test]
fn test_num_array() {
    let p = vec![Tokens::LBRACK, Tokens::NUMBER(50.0), Tokens::RBRACK];
    let foo = vec![];

    assert_eq!(num_array().parse(&p[..]), Ok((vec![50.0], &foo[..])));
}

#[test]
fn test_param_list_entry() {
    let p = vec![Tokens::STR("float fov".to_owned()),
                 Tokens::LBRACK,
                 Tokens::NUMBER(50.0),
                 Tokens::RBRACK];

    param_list_entry().parse(&p[..]).unwrap();
}

#[test]
fn test_param_type() {
    let p = "float";
    assert_eq!(param_type().parse(&p[..]), Ok((ParamType::Float, "")));

    let q = "floatxxx";
    assert_eq!(param_type().parse(&q[..]), Ok((ParamType::Float, "xxx")));
}

#[test]
fn test_param_list_entry_header() {
    let p = vec![Tokens::STR("float fov".to_owned())];
    let foo = vec![];

    assert_eq!(param_list_entry_header().parse(&p[..]),
               Ok(((ParamType::Float, "fov".to_owned()), &foo[..])));
}
<commit_msg>Accept Accelerator statements even if we don't honour it yet<commit_after>use combine::{eof, value, satisfy_map, token, between, many, many1, try, Parser, Stream,
              ParseError};
use combine::char::{string, spaces};
use combine::primitives::Error;

use api::{Api, ParamType, ParamListEntry, Array};
// use errors::*;
use paramset::ParamSet;
use super::lexer::Tokens;

pub fn parse<I: Stream<Item = Tokens>, A: Api>
    (input: I,
     api: &A)
     -> ::std::result::Result<(Vec<()>, I), ParseError<I>> {
    // TODO remove all the error conversions once https://github.com/brson/error-chain/issues/134 is fixed
    let accelerator = (token(Tokens::ACCELERATOR), string_(), param_list())
        .and_then(|(_, typ, mut params)| api.accelerator(typ, &mut params).map_err(|e| Error::Message(e.description().to_owned().into())));
    let attribute_begin = token(Tokens::ATTRIBUTEBEGIN).and_then(|_| api.attribute_begin().map_err(|e| Error::Message(e.description().to_owned().into())));
    let attribute_end = token(Tokens::ATTRIBUTEEND).and_then(|_| api.attribute_end().map_err(|e| Error::Message(e.description().to_owned().into())));
    let transform_begin = token(Tokens::TRANSFORMBEGIN).and_then(|_| api.transform_begin().map_err(|e| Error::Message(e.description().to_owned().into())));
    let transform_end = token(Tokens::TRANSFORMEND).and_then(|_| api.transform_end().map_err(|e| Error::Message(e.description().to_owned().into())));
    let world_begin = token(Tokens::WORLDBEGIN).and_then(|_| {
                                                             api.world_begin()
                                                   .map_err(|e| {
                                                                Error::Message(e.description()
                                                                                .to_owned()
                                                                                .into())
                                                            })
                                                         });
    let world_end = token(Tokens::WORLDEND).and_then(|_| {
                                                         api.world_end()
                                                 .map_err(|e| {
                                                              Error::Message(e.description()
                                                                                .to_owned()
                                                                                .into())
                                                          })
                                                     });
    let look_at =
        (token(Tokens::LOOKAT), num(), num(), num(), num(), num(), num(), num(), num(), num())
            .and_then(|(_, ex, ey, ez, lx, ly, lz, ux, uy, uz)| {
                          api.look_at(ex, ey, ez, lx, ly, lz, ux, uy, uz)
                              .map_err(|e| Error::Message(e.description().to_owned().into()))
                      });
    let coord_sys_transform =
        (token(Tokens::COORDSYSTRANSFORM), string_()).and_then(|(_, name)| {
            api.coord_sys_transform(name).map_err(|e| Error::Message(e.description().to_owned().into()))
        });
    let camera =
        (token(Tokens::CAMERA), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                      api.camera(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                  });
    let film = (token(Tokens::FILM), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.film(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let integrator = (token(Tokens::INTEGRATOR), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.integrator(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let arealightsource = (token(Tokens::AREALIGHTSOURCE), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.arealightsource(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let lightsource = (token(Tokens::LIGHTSOURCE), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.lightsource(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let material = (token(Tokens::MATERIAL), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                              api.material(name,
                                                                                &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                          });
    let make_named_material = (token(Tokens::MAKENAMEDMATERIAL), string_(), param_list())
        .and_then(|(_, name, mut params)| {
                      api.make_named_material(name, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let named_material = (token(Tokens::NAMEDMATERIAL), string_()).and_then(|(_, name)| {
                                                                              api.named_material(name).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                          });
    let sampler = (token(Tokens::SAMPLER), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                        api.sampler(name, &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                    });
    let shape = (token(Tokens::SHAPE), string_(), param_list()).and_then(|(_, name, mut params)| {
                                                                        api.shape(name, &mut params).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                    });

    let reverse_orientation =
        token(Tokens::REVERSEORIENTATION).and_then(|_| {
                                                       api.reverse_orientation()
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                   });
    let filter =
        (token(Tokens::PIXELFILTER), string_(), param_list())
            .and_then(|(_, name, mut params)| {
                          api.pixel_filter(name, &mut params)
                              .map_err(|e| Error::Message(e.description().to_owned().into()))
                      });
    let scale = (token(Tokens::SCALE), num(), num(), num()).and_then(|(_, sx, sy, sz)| {
                                                                         api.scale(sx, sy, sz)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                     });
    let rotate =
        (token(Tokens::ROTATE), num(), num(), num(), num()).and_then(|(_, angle, dx, dy, dz)| {
                                                                    api.rotate(angle, dx, dy, dz).map_err(|e| Error::Message(e.description().to_owned().into()))
                                                                });

    let texture = (token(Tokens::TEXTURE), string_(), string_(), string_(), param_list())
        .and_then(|(_, name, typ, texname, mut params)| {
                      api.texture(name, typ, texname, &mut params)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });
    let transform = (token::<I>(Tokens::TRANSFORM), num_array())
        .and_then(|(_, nums)| {
                        api.transform(nums[0], nums[1], nums[2], nums[3],
                                      nums[4], nums[5], nums[6], nums[7],
                                      nums[8], nums[9], nums[10], nums[11],
                                      nums[12], nums[13], nums[14], nums[15],
                                    )
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });

    let translate = (token(Tokens::TRANSLATE), num(), num(), num())
        .and_then(|(_, dx, dy, dz)| {
                      api.translate(dx, dy, dz)
                          .map_err(|e| Error::Message(e.description().to_owned().into()))
                  });

    let parsers = many1::<Vec<_>, _>(choice!(try(accelerator),
                                             try(attribute_begin),
                                             try(attribute_end),
                                             try(transform_begin),
                                             try(transform_end),
                                             try(world_begin),
                                             try(world_end),
                                             try(look_at),
                                             try(coord_sys_transform),
                                             try(camera),
                                             try(film),
                                             try(filter),
                                             try(integrator),
                                             try(arealightsource),
                                             try(lightsource),
                                             try(material),
                                             try(texture),
                                             try(make_named_material),
                                             try(named_material),
                                             try(sampler),
                                             try(shape),
                                             try(reverse_orientation),
                                             try(scale),
                                             try(rotate),
                                             try(translate),
                                             try(transform)));
    (parsers, eof()).map(|(res, _)| res).parse(input)
}

fn param_list<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamSet> + 'a>
{
    many(param_list_entry())
        .map(|x| {
                 let mut ps = ParamSet::default();
                 ps.init(x);
                 ps
             })
        .boxed()
}

fn param_type<'a, I: Stream<Item = char> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamType> + 'a>
{
    choice!(try(string("integer").with(value(ParamType::Int))),
            try(string("bool").with(value(ParamType::Bool))),
            try(string("float").with(value(ParamType::Float))),
            try(string("point2").with(value(ParamType::Point2))),
            try(string("vector2").with(value(ParamType::Vector2))),
            try(string("point3").with(value(ParamType::Point3))),
            try(string("vector3").with(value(ParamType::Vector3))),
            try(string("point").with(value(ParamType::Point3))),
            try(string("vector").with(value(ParamType::Vector3))),
            try(string("normal").with(value(ParamType::Normal))),
            try(string("color").with(value(ParamType::Rgb))),
            try(string("rgb").with(value(ParamType::Rgb))),
            try(string("xyz").with(value(ParamType::Xyz))),
            try(string("blackbody").with(value(ParamType::Blackbody))),
            try(string("spectrum").with(value(ParamType::Spectrum))),
            try(string("string").with(value(ParamType::String))),
            try(string("texture").with(value(ParamType::Texture))))
            .boxed()
}

fn param_list_entry_header<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = (ParamType, String)> + 'a>
{
    string_()
        .and_then(|s| match param_type().skip(spaces()).parse(&s[..]) {
                      Ok((t, n)) => Ok((t, n.to_owned())),
                      Err(error) => {
                          Err(Error::Message(format!("Invalid param list entry: {}", error).into()))
                      }
                  })
        .boxed()
}

fn param_list_entry<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = ParamListEntry> + 'a>
{
    (param_list_entry_header(), array())
        .map(|(header, array)| ParamListEntry::new(header.0, header.1, array))
        .boxed()
}

fn array<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = Array> + 'a> {
    choice!(try(string_array().map(Array::StrArray)),
            try(num_array().map(Array::NumArray)))
            .boxed()
}

fn string_array<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = Vec<String>> + 'a>
{
    choice!(try(between(token(Tokens::LBRACK),
                        token(Tokens::RBRACK),
                        many1::<Vec<_>, _>(string_()))),
            try(string_().map(|x| vec![x])))
            .boxed()
}

fn num_array<'a, I: Stream<Item = Tokens> + 'a>
    ()
    -> Box<Parser<Input = I, Output = Vec<f32>> + 'a>
{
    choice!(try(between(token(Tokens::LBRACK),
                        token(Tokens::RBRACK),
                        many1::<Vec<_>, _>(num()))),
            try(num().map(|x| vec![x])))
            .boxed()
}

fn num<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = f32> + 'a> {
    satisfy_map(|t| match t {
                    Tokens::NUMBER(n) => Some(n),
                    _ => None,
                })
            .boxed()
}

fn string_<'a, I: Stream<Item = Tokens> + 'a>() -> Box<Parser<Input = I, Output = String> + 'a> {
    satisfy_map(|t| match t {
                    Tokens::STR(s) => Some(s),
                    _ => None,
                })
            .boxed()
}

// #[test]
// fn test_parse() {
//     let tokens = vec![Tokens::ATTRIBUTEBEGIN, Tokens::ATTRIBUTEEND];
//     let api = ::api::RealApi::default();
//     api.init().unwrap();
//     parse(&tokens[..], &api).unwrap();
// }

#[test]
fn test_array() {
    let p = vec![Tokens::LBRACK,
                 Tokens::NUMBER(50.0),
                 Tokens::NUMBER(12.0),
                 Tokens::RBRACK];
    let foo = vec![];

    assert_eq!(array().parse(&p[..]),
               Ok((Array::NumArray(vec![50.0, 12.0]), &foo[..])));
}

#[test]
fn test_num_array() {
    let p = vec![Tokens::LBRACK, Tokens::NUMBER(50.0), Tokens::RBRACK];
    let foo = vec![];

    assert_eq!(num_array().parse(&p[..]), Ok((vec![50.0], &foo[..])));
}

#[test]
fn test_param_list_entry() {
    let p = vec![Tokens::STR("float fov".to_owned()),
                 Tokens::LBRACK,
                 Tokens::NUMBER(50.0),
                 Tokens::RBRACK];

    param_list_entry().parse(&p[..]).unwrap();
}

#[test]
fn test_param_type() {
    let p = "float";
    assert_eq!(param_type().parse(&p[..]), Ok((ParamType::Float, "")));

    let q = "floatxxx";
    assert_eq!(param_type().parse(&q[..]), Ok((ParamType::Float, "xxx")));
}

#[test]
fn test_param_list_entry_header() {
    let p = vec![Tokens::STR("float fov".to_owned())];
    let foo = vec![];

    assert_eq!(param_list_entry_header().parse(&p[..]),
               Ok(((ParamType::Float, "fov".to_owned()), &foo[..])));
}
<|endoftext|>


<commit_before>/// Maximum number of channels supported in the FLAC format.
pub const MAX_CHANNELS: usize = 8;

/// Audio frame that contains one sample for each channel.
pub struct Frame {
  /// Information regarding the current audio frame.
  pub header: Header,
  /// CRC-16 of all frame bytes before this footer.
  pub footer: Footer,
}

/// Channel assignment order.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelAssignment {
  /// Independent channels, from one up to eight.
  Independent,
  /// Left and side stereo.
  LeftSide,
  /// Right and side stereo.
  RightSide,
  /// Middle and side stereo.
  MiddleSide,
}

/// Numbering scheme used from the frame.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberType {
  /// Frame number of first sample in frame.
  Frame(u32),
  /// Sample number of first sample in frame.
  Sample(u64),
}

/// Information regarding the current audio frame.
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
  pub block_size: u32,
  pub sample_rate: u32,
  pub channels: u8,
  pub channel_assignment: ChannelAssignment,
  pub bits_per_sample: usize,
  pub number: NumberType,
  pub crc: u8,
}

/// End of the audio frame.
///
/// Contains a value that represents the CRC-16 of everything inside the
/// frame before the footer.
#[derive(Debug, PartialEq, Eq)]
pub struct Footer(pub u16);
<commit_msg>Add documentation for Header fields<commit_after>/// Maximum number of channels supported in the FLAC format.
pub const MAX_CHANNELS: usize = 8;

/// Audio frame that contains one sample for each channel.
pub struct Frame {
  /// Information regarding the current audio frame.
  pub header: Header,
  /// CRC-16 of all frame bytes before this footer.
  pub footer: Footer,
}

/// Channel assignment order.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelAssignment {
  /// Independent channels, from one up to eight.
  Independent,
  /// Left and side stereo.
  LeftSide,
  /// Right and side stereo.
  RightSide,
  /// Middle and side stereo.
  MiddleSide,
}

/// Numbering scheme used from the frame.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberType {
  /// Frame number of first sample in frame.
  Frame(u32),
  /// Sample number of first sample in frame.
  Sample(u64),
}

/// Information regarding the current audio frame.
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
  /// Number of samples per subframe.
  pub block_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels that also represent the number of subframes.
  pub channels: u8,
  pub channel_assignment: ChannelAssignment,
  /// Size, in bits, per sample.
  pub bits_per_sample: usize,
  pub number: NumberType,
  /// CRC-8 of all header bytes before this crc.
  pub crc: u8,
}

/// End of the audio frame.
///
/// Contains a value that represents the CRC-16 of everything inside the
/// frame before the footer.
#[derive(Debug, PartialEq, Eq)]
pub struct Footer(pub u16);
<|endoftext|>