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

use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerNonNull, EventHandlerNonNull};
use dom::bindings::codegen::Bindings::WindowBinding;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable};
use dom::bindings::trace::{Traceable, Untraceable};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::browsercontext::BrowserContext;
use dom::console::Console;
use dom::document::Document;
use dom::eventtarget::{EventTarget, WindowTypeId, EventTargetHelpers};
use dom::location::Location;
use dom::navigator::Navigator;
use dom::performance::Performance;

use layout_interface::{ReflowForDisplay, DocumentDamageLevel};
use script_task::{ExitWindowMsg, FireTimerMsg, Page, ScriptChan, TriggerLoadMsg, TriggerFragmentMsg};
use servo_msg::compositor_msg::ScriptListener;
use servo_net::image_cache_task::ImageCacheTask;
use servo_util::str::DOMString;
use servo_util::task::{spawn_named};
use servo_util::url::parse_url;

use js::jsapi::JSContext;
use js::jsapi::{JS_GC, JS_GetRuntime};
use js::jsval::JSVal;

use collections::hashmap::HashMap;
use std::cell::{Cell, RefCell};
use std::cmp;
use std::comm::{channel, Sender};
use std::comm::Select;
use std::hash::{Hash, sip};
use std::io::timer::Timer;
use std::rc::Rc;

use time;

use serialize::{Encoder, Encodable};
use url::Url;

#[deriving(Eq, Encodable, TotalEq)]
pub struct TimerId(i32);

#[deriving(Encodable)]
pub struct TimerHandle {
    pub handle: TimerId,
    pub data: TimerData,
    pub cancel_chan: Untraceable<Option<Sender<()>>>,
}

impl Hash for TimerId {
    fn hash(&self, state: &mut sip::SipState) {
        let TimerId(id) = *self;
        id.hash(state);
    }
}

impl TimerHandle {
    fn cancel(&mut self) {
        self.cancel_chan.as_ref().map(|chan| chan.send(()));
    }
}

#[deriving(Encodable)]
pub struct Window {
    pub eventtarget: EventTarget,
    pub script_chan: ScriptChan,
    pub console: Cell<Option<JS<Console>>>,
    pub location: Cell<Option<JS<Location>>>,
    pub navigator: Cell<Option<JS<Navigator>>>,
    pub image_cache_task: ImageCacheTask,
    pub active_timers: Traceable<RefCell<HashMap<TimerId, TimerHandle>>>,
    pub next_timer_handle: Untraceable<Cell<i32>>,
    pub compositor: Untraceable<Box<ScriptListener>>,
    pub browser_context: Traceable<RefCell<Option<BrowserContext>>>,
    pub page: Rc<Page>,
    pub performance: Cell<Option<JS<Performance>>>,
    pub navigationStart: u64,
    pub navigationStartPrecise: f64,
}

impl Window {
    pub fn get_cx(&self) -> *mut JSContext {
        let js_info = self.page().js_info();
        (**js_info.get_ref().js_context).ptr
    }

    pub fn page<'a>(&'a self) -> &'a Page {
        &*self.page
    }
    pub fn get_url(&self) -> Url {
        self.page().get_url()
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        for (_, timer_handle) in self.active_timers.borrow_mut().mut_iter() {
            timer_handle.cancel();
        }
    }
}

// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
//      to the function when calling it)
#[deriving(Encodable)]
pub struct TimerData {
    pub is_interval: bool,
    pub funval: Traceable<JSVal>,
}

pub trait WindowMethods {
    fn Alert(&self, s: DOMString);
    fn Close(&self);
    fn Document(&self) -> Temporary<Document>;
    fn Location(&self) -> Temporary<Location>;
    fn Console(&self) -> Temporary<Console>;
    fn Navigator(&self) -> Temporary<Navigator>;
    fn SetTimeout(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32;
    fn ClearTimeout(&self, handle: i32);
    fn SetInterval(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32;
    fn ClearInterval(&self, handle: i32);
    fn Window(&self) -> Temporary<Window>;
    fn Self(&self) -> Temporary<Window>;
    fn Performance(&self) -> Temporary<Performance>;
    fn GetOnclick(&self) -> Option<EventHandlerNonNull>;
    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>);
    fn GetOnload(&self) -> Option<EventHandlerNonNull>;
    fn SetOnload(&self, listener: Option<EventHandlerNonNull>);
    fn GetOnunload(&self) -> Option<EventHandlerNonNull>;
    fn SetOnunload(&self, listener: Option<EventHandlerNonNull>);
    fn GetOnerror(&self) -> Option<OnErrorEventHandlerNonNull>;
    fn SetOnerror(&self, listener: Option<OnErrorEventHandlerNonNull>);
    fn Debug(&self, message: DOMString);
    fn Gc(&self);
}

impl<'a> WindowMethods for JSRef<'a, Window> {
    fn Alert(&self, s: DOMString) {
        // Right now, just print to the console
        println!("ALERT: {:s}", s);
    }

    fn Close(&self) {
        let ScriptChan(ref chan) = self.script_chan;
        chan.send(ExitWindowMsg(self.page.id.clone()));
    }

    fn Document(&self) -> Temporary<Document> {
        let frame = self.page().frame();
        Temporary::new(frame.get_ref().document.clone())
    }

    fn Location(&self) -> Temporary<Location> {
        if self.location.get().is_none() {
            let page = self.deref().page.clone();
            let location = Location::new(self, page);
            self.location.assign(Some(location));
        }
        Temporary::new(self.location.get().get_ref().clone())
    }

    fn Console(&self) -> Temporary<Console> {
        if self.console.get().is_none() {
            let console = Console::new(self);
            self.console.assign(Some(console));
        }
        Temporary::new(self.console.get().get_ref().clone())
    }

    fn Navigator(&self) -> Temporary<Navigator> {
        if self.navigator.get().is_none() {
            let navigator = Navigator::new(self);
            self.navigator.assign(Some(navigator));
        }
        Temporary::new(self.navigator.get().get_ref().clone())
    }

    fn SetTimeout(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
        self.set_timeout_or_interval(callback, timeout, false)
    }

    fn ClearTimeout(&self, handle: i32) {
        let mut timers = self.active_timers.deref().borrow_mut();
        let mut timer_handle = timers.pop(&TimerId(handle));
        match timer_handle {
            Some(ref mut handle) => handle.cancel(),
            None => { }
        }
        timers.remove(&TimerId(handle));
    }

    fn SetInterval(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
        self.set_timeout_or_interval(callback, timeout, true)
    }

    fn ClearInterval(&self, handle: i32) {
        self.ClearTimeout(handle);
    }

    fn Window(&self) -> Temporary<Window> {
        Temporary::from_rooted(self)
    }

    fn Self(&self) -> Temporary<Window> {
        self.Window()
    }

    fn Performance(&self) -> Temporary<Performance> {
        if self.performance.get().is_none() {
            let performance = Performance::new(self);
            self.performance.assign(Some(performance));
        }
        Temporary::new(self.performance.get().get_ref().clone())
    }

    fn GetOnclick(&self) -> Option<EventHandlerNonNull> {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.get_event_handler_common("click")
    }

    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>) {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.set_event_handler_common("click", listener)
    }

    fn GetOnload(&self) -> Option<EventHandlerNonNull> {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.get_event_handler_common("load")
    }

    fn SetOnload(&self, listener: Option<EventHandlerNonNull>) {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.set_event_handler_common("load", listener)
    }

    fn GetOnunload(&self) -> Option<EventHandlerNonNull> {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.get_event_handler_common("unload")
    }

    fn SetOnunload(&self, listener: Option<EventHandlerNonNull>) {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.set_event_handler_common("unload", listener)
    }

    fn GetOnerror(&self) -> Option<OnErrorEventHandlerNonNull> {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.get_event_handler_common("error")
    }

    fn SetOnerror(&self, listener: Option<OnErrorEventHandlerNonNull>) {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.set_event_handler_common("error", listener)
    }

    fn Debug(&self, message: DOMString) {
        debug!("{:s}", message);
    }

    fn Gc(&self) {
        unsafe {
            JS_GC(JS_GetRuntime(self.get_cx()));
        }
    }
}

impl Reflectable for Window {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.eventtarget.mut_reflector()
    }
}

pub trait WindowHelpers {
    fn damage_and_reflow(&self, damage: DocumentDamageLevel);
    fn wait_until_safe_to_modify_dom(&self);
    fn init_browser_context(&self, doc: &JSRef<Document>);
    fn load_url(&self, href: DOMString);
}

trait PrivateWindowHelpers {
    fn set_timeout_or_interval(&self, callback: JSVal, timeout: i32, is_interval: bool) -> i32;
}

impl<'a> WindowHelpers for JSRef<'a, Window> {
    fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
        // FIXME This should probably be ReflowForQuery, not Display. All queries currently
        // currently rely on the display list, which means we can't destroy it by
        // doing a query reflow.
        self.page().damage(damage);
        self.page().reflow(ReflowForDisplay, self.script_chan.clone(), *self.compositor);
    }

    fn wait_until_safe_to_modify_dom(&self) {
        // FIXME: This disables concurrent layout while we are modifying the DOM, since
        //        our current architecture is entirely unsafe in the presence of races.
        self.page().join_layout();
    }

    fn init_browser_context(&self, doc: &JSRef<Document>) {
        *self.browser_context.deref().borrow_mut() = Some(BrowserContext::new(doc));
    }

    /// Commence a new URL load which will either replace this window or scroll to a fragment.
    fn load_url(&self, href: DOMString) {
        let base_url = Some(self.page().get_url());
        debug!("current page url is {:?}", base_url);
        let url = parse_url(href.as_slice(), base_url);
        let ScriptChan(ref script_chan) = self.script_chan;
        if href.as_slice().starts_with("#") {
            script_chan.send(TriggerFragmentMsg(self.page.id, url));
        } else {
            script_chan.send(TriggerLoadMsg(self.page.id, url));
        }
    }
}

impl<'a> PrivateWindowHelpers for JSRef<'a, Window> {
    fn set_timeout_or_interval(&self, callback: JSVal, timeout: i32, is_interval: bool) -> i32 {
        let timeout = cmp::max(0, timeout) as u64;
        let handle = self.next_timer_handle.deref().get();
        self.next_timer_handle.deref().set(handle + 1);

        // Post a delayed message to the per-window timer task; it will dispatch it
        // to the relevant script handler that will deal with it.
        let tm = Timer::new().unwrap();
        let (cancel_chan, cancel_port) = channel();
        let chan = self.script_chan.clone();
        let page_id = self.page.id.clone();
        let spawn_name = if is_interval {
            "Window:SetInterval"
        } else {
            "Window:SetTimeout"
        };
        spawn_named(spawn_name, proc() {
            let mut tm = tm;
            let timeout_port = if is_interval {
                tm.periodic(timeout)
            } else {
                tm.oneshot(timeout)
            };
            let cancel_port = cancel_port;

            let select = Select::new();
            let mut timeout_handle = select.handle(&timeout_port);
            unsafe { timeout_handle.add() };
            let mut cancel_handle = select.handle(&cancel_port);
            unsafe { cancel_handle.add() };

            loop {
                let id = select.wait();
                if id == timeout_handle.id() {
                    timeout_port.recv();
                    let ScriptChan(ref chan) = chan;
                    chan.send(FireTimerMsg(page_id, TimerId(handle)));
                    if !is_interval {
                        break;
                    }
                } else if id == cancel_handle.id() {
                    break;
                }
            }
        });
        let timer_id = TimerId(handle);
        let timer = TimerHandle {
            handle: timer_id,
            cancel_chan: Untraceable::new(Some(cancel_chan)),
            data: TimerData {
                is_interval: is_interval,
                funval: Traceable::new(callback),
            }
        };
        self.active_timers.deref().borrow_mut().insert(timer_id, timer);
        handle
    }
}

impl Window {
    pub fn new(cx: *mut JSContext,
               page: Rc<Page>,
               script_chan: ScriptChan,
               compositor: Box<ScriptListener>,
               image_cache_task: ImageCacheTask)
               -> JS<Window> {
        let win = box Window {
            eventtarget: EventTarget::new_inherited(WindowTypeId),
            script_chan: script_chan,
            console: Cell::new(None),
            compositor: Untraceable::new(compositor),
            page: page,
            location: Cell::new(None),
            navigator: Cell::new(None),
            image_cache_task: image_cache_task,
            active_timers: Traceable::new(RefCell::new(HashMap::new())),
            next_timer_handle: Untraceable::new(Cell::new(0)),
            browser_context: Traceable::new(RefCell::new(None)),
            performance: Cell::new(None),
            navigationStart: time::get_time().sec as u64,
            navigationStartPrecise: time::precise_time_s(),
        };

        WindowBinding::Wrap(cx, win)
    }
}
<commit_msg>auto merge of #2646 : Manishearth/servo/cleartimeout-opt, r=jdm<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::Bindings::EventHandlerBinding::{OnErrorEventHandlerNonNull, EventHandlerNonNull};
use dom::bindings::codegen::Bindings::WindowBinding;
use dom::bindings::codegen::InheritTypes::EventTargetCast;
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable};
use dom::bindings::trace::{Traceable, Untraceable};
use dom::bindings::utils::{Reflectable, Reflector};
use dom::browsercontext::BrowserContext;
use dom::console::Console;
use dom::document::Document;
use dom::eventtarget::{EventTarget, WindowTypeId, EventTargetHelpers};
use dom::location::Location;
use dom::navigator::Navigator;
use dom::performance::Performance;

use layout_interface::{ReflowForDisplay, DocumentDamageLevel};
use script_task::{ExitWindowMsg, FireTimerMsg, Page, ScriptChan, TriggerLoadMsg, TriggerFragmentMsg};
use servo_msg::compositor_msg::ScriptListener;
use servo_net::image_cache_task::ImageCacheTask;
use servo_util::str::DOMString;
use servo_util::task::{spawn_named};
use servo_util::url::parse_url;

use js::jsapi::JSContext;
use js::jsapi::{JS_GC, JS_GetRuntime};
use js::jsval::JSVal;

use collections::hashmap::HashMap;
use std::cell::{Cell, RefCell};
use std::cmp;
use std::comm::{channel, Sender};
use std::comm::Select;
use std::hash::{Hash, sip};
use std::io::timer::Timer;
use std::rc::Rc;

use time;

use serialize::{Encoder, Encodable};
use url::Url;

#[deriving(Eq, Encodable, TotalEq)]
pub struct TimerId(i32);

#[deriving(Encodable)]
pub struct TimerHandle {
    pub handle: TimerId,
    pub data: TimerData,
    pub cancel_chan: Untraceable<Option<Sender<()>>>,
}

impl Hash for TimerId {
    fn hash(&self, state: &mut sip::SipState) {
        let TimerId(id) = *self;
        id.hash(state);
    }
}

impl TimerHandle {
    fn cancel(&mut self) {
        self.cancel_chan.as_ref().map(|chan| chan.send_opt(()).ok());
    }
}

#[deriving(Encodable)]
pub struct Window {
    pub eventtarget: EventTarget,
    pub script_chan: ScriptChan,
    pub console: Cell<Option<JS<Console>>>,
    pub location: Cell<Option<JS<Location>>>,
    pub navigator: Cell<Option<JS<Navigator>>>,
    pub image_cache_task: ImageCacheTask,
    pub active_timers: Traceable<RefCell<HashMap<TimerId, TimerHandle>>>,
    pub next_timer_handle: Untraceable<Cell<i32>>,
    pub compositor: Untraceable<Box<ScriptListener>>,
    pub browser_context: Traceable<RefCell<Option<BrowserContext>>>,
    pub page: Rc<Page>,
    pub performance: Cell<Option<JS<Performance>>>,
    pub navigationStart: u64,
    pub navigationStartPrecise: f64,
}

impl Window {
    pub fn get_cx(&self) -> *mut JSContext {
        let js_info = self.page().js_info();
        (**js_info.get_ref().js_context).ptr
    }

    pub fn page<'a>(&'a self) -> &'a Page {
        &*self.page
    }
    pub fn get_url(&self) -> Url {
        self.page().get_url()
    }
}

#[unsafe_destructor]
impl Drop for Window {
    fn drop(&mut self) {
        for (_, timer_handle) in self.active_timers.borrow_mut().mut_iter() {
            timer_handle.cancel();
        }
    }
}

// Holder for the various JS values associated with setTimeout
// (ie. function value to invoke and all arguments to pass
//      to the function when calling it)
#[deriving(Encodable)]
pub struct TimerData {
    pub is_interval: bool,
    pub funval: Traceable<JSVal>,
}

pub trait WindowMethods {
    fn Alert(&self, s: DOMString);
    fn Close(&self);
    fn Document(&self) -> Temporary<Document>;
    fn Location(&self) -> Temporary<Location>;
    fn Console(&self) -> Temporary<Console>;
    fn Navigator(&self) -> Temporary<Navigator>;
    fn SetTimeout(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32;
    fn ClearTimeout(&self, handle: i32);
    fn SetInterval(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32;
    fn ClearInterval(&self, handle: i32);
    fn Window(&self) -> Temporary<Window>;
    fn Self(&self) -> Temporary<Window>;
    fn Performance(&self) -> Temporary<Performance>;
    fn GetOnclick(&self) -> Option<EventHandlerNonNull>;
    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>);
    fn GetOnload(&self) -> Option<EventHandlerNonNull>;
    fn SetOnload(&self, listener: Option<EventHandlerNonNull>);
    fn GetOnunload(&self) -> Option<EventHandlerNonNull>;
    fn SetOnunload(&self, listener: Option<EventHandlerNonNull>);
    fn GetOnerror(&self) -> Option<OnErrorEventHandlerNonNull>;
    fn SetOnerror(&self, listener: Option<OnErrorEventHandlerNonNull>);
    fn Debug(&self, message: DOMString);
    fn Gc(&self);
}

impl<'a> WindowMethods for JSRef<'a, Window> {
    fn Alert(&self, s: DOMString) {
        // Right now, just print to the console
        println!("ALERT: {:s}", s);
    }

    fn Close(&self) {
        let ScriptChan(ref chan) = self.script_chan;
        chan.send(ExitWindowMsg(self.page.id.clone()));
    }

    fn Document(&self) -> Temporary<Document> {
        let frame = self.page().frame();
        Temporary::new(frame.get_ref().document.clone())
    }

    fn Location(&self) -> Temporary<Location> {
        if self.location.get().is_none() {
            let page = self.deref().page.clone();
            let location = Location::new(self, page);
            self.location.assign(Some(location));
        }
        Temporary::new(self.location.get().get_ref().clone())
    }

    fn Console(&self) -> Temporary<Console> {
        if self.console.get().is_none() {
            let console = Console::new(self);
            self.console.assign(Some(console));
        }
        Temporary::new(self.console.get().get_ref().clone())
    }

    fn Navigator(&self) -> Temporary<Navigator> {
        if self.navigator.get().is_none() {
            let navigator = Navigator::new(self);
            self.navigator.assign(Some(navigator));
        }
        Temporary::new(self.navigator.get().get_ref().clone())
    }

    fn SetTimeout(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
        self.set_timeout_or_interval(callback, timeout, false)
    }

    fn ClearTimeout(&self, handle: i32) {
        let mut timers = self.active_timers.deref().borrow_mut();
        let mut timer_handle = timers.pop(&TimerId(handle));
        match timer_handle {
            Some(ref mut handle) => handle.cancel(),
            None => { }
        }
        timers.remove(&TimerId(handle));
    }

    fn SetInterval(&self, _cx: *mut JSContext, callback: JSVal, timeout: i32) -> i32 {
        self.set_timeout_or_interval(callback, timeout, true)
    }

    fn ClearInterval(&self, handle: i32) {
        self.ClearTimeout(handle);
    }

    fn Window(&self) -> Temporary<Window> {
        Temporary::from_rooted(self)
    }

    fn Self(&self) -> Temporary<Window> {
        self.Window()
    }

    fn Performance(&self) -> Temporary<Performance> {
        if self.performance.get().is_none() {
            let performance = Performance::new(self);
            self.performance.assign(Some(performance));
        }
        Temporary::new(self.performance.get().get_ref().clone())
    }

    fn GetOnclick(&self) -> Option<EventHandlerNonNull> {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.get_event_handler_common("click")
    }

    fn SetOnclick(&self, listener: Option<EventHandlerNonNull>) {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.set_event_handler_common("click", listener)
    }

    fn GetOnload(&self) -> Option<EventHandlerNonNull> {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.get_event_handler_common("load")
    }

    fn SetOnload(&self, listener: Option<EventHandlerNonNull>) {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.set_event_handler_common("load", listener)
    }

    fn GetOnunload(&self) -> Option<EventHandlerNonNull> {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.get_event_handler_common("unload")
    }

    fn SetOnunload(&self, listener: Option<EventHandlerNonNull>) {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.set_event_handler_common("unload", listener)
    }

    fn GetOnerror(&self) -> Option<OnErrorEventHandlerNonNull> {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.get_event_handler_common("error")
    }

    fn SetOnerror(&self, listener: Option<OnErrorEventHandlerNonNull>) {
        let eventtarget: &JSRef<EventTarget> = EventTargetCast::from_ref(self);
        eventtarget.set_event_handler_common("error", listener)
    }

    fn Debug(&self, message: DOMString) {
        debug!("{:s}", message);
    }

    fn Gc(&self) {
        unsafe {
            JS_GC(JS_GetRuntime(self.get_cx()));
        }
    }
}

impl Reflectable for Window {
    fn reflector<'a>(&'a self) -> &'a Reflector {
        self.eventtarget.reflector()
    }

    fn mut_reflector<'a>(&'a mut self) -> &'a mut Reflector {
        self.eventtarget.mut_reflector()
    }
}

pub trait WindowHelpers {
    fn damage_and_reflow(&self, damage: DocumentDamageLevel);
    fn wait_until_safe_to_modify_dom(&self);
    fn init_browser_context(&self, doc: &JSRef<Document>);
    fn load_url(&self, href: DOMString);
}

trait PrivateWindowHelpers {
    fn set_timeout_or_interval(&self, callback: JSVal, timeout: i32, is_interval: bool) -> i32;
}

impl<'a> WindowHelpers for JSRef<'a, Window> {
    fn damage_and_reflow(&self, damage: DocumentDamageLevel) {
        // FIXME This should probably be ReflowForQuery, not Display. All queries currently
        // currently rely on the display list, which means we can't destroy it by
        // doing a query reflow.
        self.page().damage(damage);
        self.page().reflow(ReflowForDisplay, self.script_chan.clone(), *self.compositor);
    }

    fn wait_until_safe_to_modify_dom(&self) {
        // FIXME: This disables concurrent layout while we are modifying the DOM, since
        //        our current architecture is entirely unsafe in the presence of races.
        self.page().join_layout();
    }

    fn init_browser_context(&self, doc: &JSRef<Document>) {
        *self.browser_context.deref().borrow_mut() = Some(BrowserContext::new(doc));
    }

    /// Commence a new URL load which will either replace this window or scroll to a fragment.
    fn load_url(&self, href: DOMString) {
        let base_url = Some(self.page().get_url());
        debug!("current page url is {:?}", base_url);
        let url = parse_url(href.as_slice(), base_url);
        let ScriptChan(ref script_chan) = self.script_chan;
        if href.as_slice().starts_with("#") {
            script_chan.send(TriggerFragmentMsg(self.page.id, url));
        } else {
            script_chan.send(TriggerLoadMsg(self.page.id, url));
        }
    }
}

impl<'a> PrivateWindowHelpers for JSRef<'a, Window> {
    fn set_timeout_or_interval(&self, callback: JSVal, timeout: i32, is_interval: bool) -> i32 {
        let timeout = cmp::max(0, timeout) as u64;
        let handle = self.next_timer_handle.deref().get();
        self.next_timer_handle.deref().set(handle + 1);

        // Post a delayed message to the per-window timer task; it will dispatch it
        // to the relevant script handler that will deal with it.
        let tm = Timer::new().unwrap();
        let (cancel_chan, cancel_port) = channel();
        let chan = self.script_chan.clone();
        let page_id = self.page.id.clone();
        let spawn_name = if is_interval {
            "Window:SetInterval"
        } else {
            "Window:SetTimeout"
        };
        spawn_named(spawn_name, proc() {
            let mut tm = tm;
            let timeout_port = if is_interval {
                tm.periodic(timeout)
            } else {
                tm.oneshot(timeout)
            };
            let cancel_port = cancel_port;

            let select = Select::new();
            let mut timeout_handle = select.handle(&timeout_port);
            unsafe { timeout_handle.add() };
            let mut cancel_handle = select.handle(&cancel_port);
            unsafe { cancel_handle.add() };

            loop {
                let id = select.wait();
                if id == timeout_handle.id() {
                    timeout_port.recv();
                    let ScriptChan(ref chan) = chan;
                    chan.send(FireTimerMsg(page_id, TimerId(handle)));
                    if !is_interval {
                        break;
                    }
                } else if id == cancel_handle.id() {
                    break;
                }
            }
        });
        let timer_id = TimerId(handle);
        let timer = TimerHandle {
            handle: timer_id,
            cancel_chan: Untraceable::new(Some(cancel_chan)),
            data: TimerData {
                is_interval: is_interval,
                funval: Traceable::new(callback),
            }
        };
        self.active_timers.deref().borrow_mut().insert(timer_id, timer);
        handle
    }
}

impl Window {
    pub fn new(cx: *mut JSContext,
               page: Rc<Page>,
               script_chan: ScriptChan,
               compositor: Box<ScriptListener>,
               image_cache_task: ImageCacheTask)
               -> JS<Window> {
        let win = box Window {
            eventtarget: EventTarget::new_inherited(WindowTypeId),
            script_chan: script_chan,
            console: Cell::new(None),
            compositor: Untraceable::new(compositor),
            page: page,
            location: Cell::new(None),
            navigator: Cell::new(None),
            image_cache_task: image_cache_task,
            active_timers: Traceable::new(RefCell::new(HashMap::new())),
            next_timer_handle: Untraceable::new(Cell::new(0)),
            browser_context: Traceable::new(RefCell::new(None)),
            performance: Cell::new(None),
            navigationStart: time::get_time().sec as u64,
            navigationStartPrecise: time::precise_time_s(),
        };

        WindowBinding::Wrap(cx, win)
    }
}
<|endoftext|>


<commit_before>/*
 * Copyright 2021 The Raksha Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use crate::{ast::*, souffle::datalog_ir::*};
use std::collections::HashSet;

pub struct SouffleEmitter {
    // This is a set of predicates that need to be declared. This set is
    // populated by side effect while traversing the program body.
    decls: HashSet<AstPredicate>,
}

impl SouffleEmitter {
    /// Produces Souffle code as a `String` when given A Datalog IR (DLIR) program.
    pub fn emit_program(p: &DLIRProgram) -> String {
        let mut emitter = SouffleEmitter::new();
        // It is important to generate the body first in this case
        // because the declarations are populated by side-effect while
        // generating the body.
        let body = emitter.emit_program_body(p);
        let outputs = emitter.emit_outputs(p);
        let decls = emitter.emit_declarations();
        vec![decls, body, outputs].join("\n")
    }

    fn new() -> SouffleEmitter {
        SouffleEmitter {
            decls: HashSet::new(),
        }
    }

    // This function produces a normalized version of predicates to
    // be used when generating declarations of the predicates. It replaces
    // argument names with generic numbered ones. It is applied
    // to predicates before they are added to the set of declarations so that
    // there are no duplicate delcarations (which would otherwise happen
    // whenever a predicate is referenced more than once with different
    // arguments).
    fn pred_to_declaration(p: &AstPredicate) -> AstPredicate {
        AstPredicate {
            name: p.name.clone(),
            args: (0..p.args.len())
                .map(|i| String::from("x") + &i.to_string())
                .collect(),
        }
    }

    fn emit_pred(&mut self, p: &AstPredicate) -> String {
        let decl = SouffleEmitter::pred_to_declaration(p);
        self.decls.insert(decl);
        format!("{}({})", &p.name, p.args.join(", "))
    }

    fn emit_assertion(&mut self, a: &DLIRAssertion) -> String {
        match a {
            DLIRAssertion::DLIRFactAssertion { p } => self.emit_pred(p) + ".",
            DLIRAssertion::DLIRCondAssertion { lhs, rhs } => {
                format!(
                    "{} :- {}.",
                    self.emit_pred(lhs),
                    rhs.iter()
                        .map(|ast_pred| self.emit_pred(ast_pred))
                        .collect::<Vec<_>>()
                        .join(", ")
                )
            }
        }
    }

    fn emit_program_body(&mut self, p: &DLIRProgram) -> String {
        p.assertions
            .iter()
            .map(|x| self.emit_assertion(&x))
            .collect::<Vec<_>>()
            .join("\n")
    }

    fn emit_decl(pred: &AstPredicate) -> String {
        format!(
            ".decl {}({})",
            &pred.name,
            &pred
                .args
                .iter()
                .map(|x| format!("{}: symbol", x))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }

    fn emit_declarations(&self) -> String {
        self.decls
            .iter()
            .map(|x| SouffleEmitter::emit_decl(x))
            .collect::<Vec<_>>()
            .join("\n")
    }

    fn emit_outputs(&self, p: &DLIRProgram) -> String {
        p.outputs
            .iter()
            .map(|o| String::from(".output ") + &o)
            .collect::<Vec<String>>()
            .join("\n")
    }
}
<commit_msg>Sort declarations in souffle_emitter. (#153)<commit_after>/*
 * Copyright 2021 The Raksha Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

use crate::{ast::*, souffle::datalog_ir::*};
use std::collections::HashSet;

pub struct SouffleEmitter {
    // This is a set of predicates that need to be declared. This set is
    // populated by side effect while traversing the program body.
    decls: HashSet<AstPredicate>,
}

impl SouffleEmitter {
    /// Produces Souffle code as a `String` when given A Datalog IR (DLIR) program.
    pub fn emit_program(p: &DLIRProgram) -> String {
        let mut emitter = SouffleEmitter::new();
        // It is important to generate the body first in this case
        // because the declarations are populated by side-effect while
        // generating the body.
        let body = emitter.emit_program_body(p);
        let outputs = emitter.emit_outputs(p);
        let decls = emitter.emit_declarations();
        vec![decls, body, outputs].join("\n")
    }

    fn new() -> SouffleEmitter {
        SouffleEmitter {
            decls: HashSet::new(),
        }
    }

    // This function produces a normalized version of predicates to
    // be used when generating declarations of the predicates. It replaces
    // argument names with generic numbered ones. It is applied
    // to predicates before they are added to the set of declarations so that
    // there are no duplicate delcarations (which would otherwise happen
    // whenever a predicate is referenced more than once with different
    // arguments).
    fn pred_to_declaration(p: &AstPredicate) -> AstPredicate {
        AstPredicate {
            name: p.name.clone(),
            args: (0..p.args.len())
                .map(|i| String::from("x") + &i.to_string())
                .collect(),
        }
    }

    fn emit_pred(&mut self, p: &AstPredicate) -> String {
        let decl = SouffleEmitter::pred_to_declaration(p);
        self.decls.insert(decl);
        format!("{}({})", &p.name, p.args.join(", "))
    }

    fn emit_assertion(&mut self, a: &DLIRAssertion) -> String {
        match a {
            DLIRAssertion::DLIRFactAssertion { p } => self.emit_pred(p) + ".",
            DLIRAssertion::DLIRCondAssertion { lhs, rhs } => {
                format!(
                    "{} :- {}.",
                    self.emit_pred(lhs),
                    rhs.iter()
                        .map(|ast_pred| self.emit_pred(ast_pred))
                        .collect::<Vec<_>>()
                        .join(", ")
                )
            }
        }
    }

    fn emit_program_body(&mut self, p: &DLIRProgram) -> String {
        p.assertions
            .iter()
            .map(|x| self.emit_assertion(&x))
            .collect::<Vec<_>>()
            .join("\n")
    }

    fn emit_decl(pred: &AstPredicate) -> String {
        format!(
            ".decl {}({})",
            &pred.name,
            &pred
                .args
                .iter()
                .map(|x| format!("{}: symbol", x))
                .collect::<Vec<_>>()
                .join(", ")
        )
    }

    fn emit_declarations(&self) -> String {
        let mut decls = self.decls
            .iter()
            .map(|x| SouffleEmitter::emit_decl(x))
            .collect::<Vec<_>>();
         decls.sort();
         decls.join("\n")
    }

    fn emit_outputs(&self, p: &DLIRProgram) -> String {
        p.outputs
            .iter()
            .map(|o| String::from(".output ") + &o)
            .collect::<Vec<String>>()
            .join("\n")
    }
}
<|endoftext|>


<commit_before>use std::io;

use game::*;
use frontends::ansi::{WindowAllocator, BufferType};
use debug;

const GAME_WINDOW_WIDTH: usize = 41;
const GAME_WINDOW_HEIGHT: usize = 31;

const ANSI_GAME_WINDOW_X: usize = 1;
const ANSI_GAME_WINDOW_Y: usize = 1;

const DEBUG_WINDOW_WIDTH: usize = 80;
const DEBUG_WINDOW_HEIGHT: usize = 10;

const DEBUG_WINDOW_RIGHT_X: usize = 0;
const DEBUG_WINDOW_BOTTOM_Y: usize = 0;

const DEBUG_WINDOW_BORDER_X: usize = 2;
const DEBUG_WINDOW_BORDER_Y: usize = 1;

pub fn launch(args: Arguments) -> ExternalResult<()> {
    let mut window_allocator = Box::new(WindowAllocator::new().unwrap());

    if window_allocator.width() <= GAME_WINDOW_WIDTH || window_allocator.height() <= GAME_WINDOW_HEIGHT {
        return Err(format!("Terminal too small. Must be at least {}x{}.",
                           GAME_WINDOW_WIDTH + ANSI_GAME_WINDOW_X,
                           GAME_WINDOW_HEIGHT + ANSI_GAME_WINDOW_Y));
    }

    let input_source = InputSourceRef::new(&window_allocator.make_input_source());

    let game_window = window_allocator.make_window(
        ANSI_GAME_WINDOW_X as isize,
        ANSI_GAME_WINDOW_Y as isize,
        GAME_WINDOW_WIDTH,
        GAME_WINDOW_HEIGHT,
        BufferType::Double);

    let renderer = frontends::ansi::AnsiKnowledgeRenderer::new(game_window, false);

    let mut game = GameCtx::new(Box::new(renderer), input_source, args.rng_seed, GAME_WINDOW_WIDTH, GAME_WINDOW_HEIGHT);

    let debug_buffer: Box<io::Write> = if args.debug {
        let mut debug_buffer = window_allocator.make_window_buffer(
            (window_allocator.width() - DEBUG_WINDOW_WIDTH - DEBUG_WINDOW_BORDER_X - DEBUG_WINDOW_RIGHT_X) as isize,
            (window_allocator.height() - DEBUG_WINDOW_HEIGHT - DEBUG_WINDOW_BORDER_Y - DEBUG_WINDOW_BOTTOM_Y) as isize,
            DEBUG_WINDOW_WIDTH,
            DEBUG_WINDOW_HEIGHT,
            DEBUG_WINDOW_BORDER_X,
            DEBUG_WINDOW_BORDER_Y);

        debug_buffer.draw_borders();

        Box::new(debug_buffer)
    } else {
        Box::new(debug::NullDebug)
    };

    debug::init(debug_buffer);

    game.run()?;

    Ok(())
}
<commit_msg>Fixed potential use-after-free bug<commit_after>use std::io;

use game::*;
use frontends::ansi::{WindowAllocator, BufferType};
use debug;

const GAME_WINDOW_WIDTH: usize = 41;
const GAME_WINDOW_HEIGHT: usize = 31;

const ANSI_GAME_WINDOW_X: usize = 1;
const ANSI_GAME_WINDOW_Y: usize = 1;

const DEBUG_WINDOW_WIDTH: usize = 80;
const DEBUG_WINDOW_HEIGHT: usize = 10;

const DEBUG_WINDOW_RIGHT_X: usize = 0;
const DEBUG_WINDOW_BOTTOM_Y: usize = 0;

const DEBUG_WINDOW_BORDER_X: usize = 2;
const DEBUG_WINDOW_BORDER_Y: usize = 1;

pub fn launch(args: Arguments) -> ExternalResult<()> {
    let mut window_allocator = Box::new(WindowAllocator::new().unwrap());

    if window_allocator.width() <= GAME_WINDOW_WIDTH || window_allocator.height() <= GAME_WINDOW_HEIGHT {
        return Err(format!("Terminal too small. Must be at least {}x{}.",
                           GAME_WINDOW_WIDTH + ANSI_GAME_WINDOW_X,
                           GAME_WINDOW_HEIGHT + ANSI_GAME_WINDOW_Y));
    }

    let input_source = window_allocator.make_input_source();
    let input_source_ref = InputSourceRef::new(&input_source);

    let game_window = window_allocator.make_window(
        ANSI_GAME_WINDOW_X as isize,
        ANSI_GAME_WINDOW_Y as isize,
        GAME_WINDOW_WIDTH,
        GAME_WINDOW_HEIGHT,
        BufferType::Double);

    let renderer = frontends::ansi::AnsiKnowledgeRenderer::new(game_window, false);

    let mut game = GameCtx::new(Box::new(renderer), input_source_ref, args.rng_seed, GAME_WINDOW_WIDTH, GAME_WINDOW_HEIGHT);

    let debug_buffer: Box<io::Write> = if args.debug {
        let mut debug_buffer = window_allocator.make_window_buffer(
            (window_allocator.width() - DEBUG_WINDOW_WIDTH - DEBUG_WINDOW_BORDER_X - DEBUG_WINDOW_RIGHT_X) as isize,
            (window_allocator.height() - DEBUG_WINDOW_HEIGHT - DEBUG_WINDOW_BORDER_Y - DEBUG_WINDOW_BOTTOM_Y) as isize,
            DEBUG_WINDOW_WIDTH,
            DEBUG_WINDOW_HEIGHT,
            DEBUG_WINDOW_BORDER_X,
            DEBUG_WINDOW_BORDER_Y);

        debug_buffer.draw_borders();

        Box::new(debug_buffer)
    } else {
        Box::new(debug::NullDebug)
    };

    debug::init(debug_buffer);

    game.run()?;

    Ok(())
}
<|endoftext|>


<commit_before>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(const_fn)]

extern crate common;
extern crate drivers;
extern crate hil;
extern crate sam4l;

use sam4l::pm;
use hil::Controller;
use hil::timer::*;
use hil::spi_master::*;

pub struct Firestorm {
    chip: sam4l::chip::Sam4l,
    console: &'static drivers::console::Console<'static, sam4l::usart::USART>,
    gpio: drivers::gpio::GPIO<[&'static hil::gpio::GPIOPin; 14]>,
    tmp006: &'static drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice>,
}

#[allow(unused_variables,dead_code)]
pub struct DummyCB {
  val: u8
}
impl hil::spi_master::SpiCallback for DummyCB {
#[allow(unused_variables,dead_code)]
        fn read_write_done(&'static self,
                           read: Option<&'static mut[u8]>,
                           writer: Option<&'static mut[u8]>) { }
}

pub static mut SPICB: DummyCB = DummyCB{val: 0x55 as u8};

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
        self.chip.service_pending_interrupts()
    }

    pub unsafe fn has_pending_interrupts(&mut self) -> bool {
        self.chip.has_pending_interrupts()
    }

    #[inline(never)]
    pub fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R where
            F: FnOnce(Option<&hil::Driver>) -> R {

        match driver_num {
            0 => f(Some(self.console)),
            1 => f(Some(&self.gpio)),
            2 => f(Some(self.tmp006)),
            _ => f(None)
        }
    }
}

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::mem;

    static mut FIRESTORM_BUF : [u8; 1024] = [0; 1024];
    static mut CONSOLE_BUF : [u8; 1024] = [0; 1024];
    static mut TIMER_BUF : [u8; 1024] = [0; 1024];
    static mut MUX_ALARM_BUF : [u8; 256] = [0; 256];
    static mut VIRT_ALARM_BUF : [u8; 256] = [0; 256];
    static mut TMP006_BUF : [u8; 1028] = [0; 1028];

    pm::enable_clock(pm::Clock::PBA(pm::PBAClock::SPI));
    /* TODO(alevy): replace above line with this. Currently, over allocating to make development
     * easier, but should be obviated when `size_of` at compile time hits.
    static mut FIRESTORM_BUF : [u8; 192] = [0; 192];
    // Just test that FIRESTORM_BUF is correct size
    // (will throw compiler error if too large or small)
    let _ : Firestorm = mem::transmute(FIRESTORM_BUF);
    let _ : Firestorm = mem::transmute(CONSOLE_BUF);
    */

    let ast = &sam4l::ast::AST;
    ast.select_clock(sam4l::ast::Clock::ClockRCSys);
    ast.set_prescalar(0);
    ast.clear_alarm();

    let console : &mut drivers::console::Console<sam4l::usart::USART> = mem::transmute(&mut CONSOLE_BUF);
    *console = drivers::console::Console::new(&mut sam4l::usart::USART3);

    let mut mux_alarm : &mut MuxAlarm<'static, sam4l::ast::Ast> = mem::transmute(&mut MUX_ALARM_BUF);
    *mux_alarm = MuxAlarm::new(ast);
    ast.configure(mux_alarm);

    let mut virtual_alarm : &mut VirtualMuxAlarm<'static, sam4l::ast::Ast> = mem::transmute(&mut VIRT_ALARM_BUF);
    *virtual_alarm = VirtualMuxAlarm::new(mux_alarm);

    let mut timer : &mut SingleTimer<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast>> = mem::transmute(&mut TIMER_BUF);
    *timer = SingleTimer::new(virtual_alarm);
    virtual_alarm.set_client(timer);

    let tmp006 : &mut drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice> = mem::transmute(&mut TMP006_BUF);
    *tmp006 = drivers::tmp006::TMP006::new(&sam4l::i2c::I2C2, timer);

    timer.set_client(tmp006);

    sam4l::usart::USART3.set_client(&*console);

    let firestorm : &'static mut Firestorm = mem::transmute(&mut FIRESTORM_BUF);
    *firestorm = Firestorm {
        chip: sam4l::chip::Sam4l::new(),
        console: &*console,
        gpio: drivers::gpio::GPIO::new(
            [ &mut sam4l::gpio::PC[10], &mut sam4l::gpio::PC[19]
            , &mut sam4l::gpio::PC[13], &mut sam4l::gpio::PA[9]
            , &mut sam4l::gpio::PA[17], &mut sam4l::gpio::PC[20]
            , &mut sam4l::gpio::PA[19], &mut sam4l::gpio::PA[14]
            , &mut sam4l::gpio::PA[16], &mut sam4l::gpio::PA[13]
            , &mut sam4l::gpio::PA[11], &mut sam4l::gpio::PA[10]
            , &mut sam4l::gpio::PA[12], &mut sam4l::gpio::PC[09]]),
        tmp006: &*tmp006
    };

    sam4l::usart::USART3.configure(sam4l::usart::USARTParams {
        //client: &console,
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });

    sam4l::gpio::PB[09].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PB[10].configure(Some(sam4l::gpio::PeripheralFunction::A));

    sam4l::gpio::PA[21].configure(Some(sam4l::gpio::PeripheralFunction::E));
    sam4l::gpio::PA[22].configure(Some(sam4l::gpio::PeripheralFunction::E));

    /*
    let pc6 = &sam4l::gpio::PC[6] as &hil::gpio::GPIOPin;
    pc6.enable_output();
    loop {
        pc6.toggle();
    }
    */

    // Configure SPI pins: CLK, MISO, MOSI, CS3
    sam4l::gpio::PC[ 6].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 4].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 5].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 1].configure(Some(sam4l::gpio::PeripheralFunction::A));
    SPI.set_active_peripheral(sam4l::spi::Peripheral::Peripheral1);
    SPI.init(&SPICB);
    SPI.enable();

    let mut flop: bool = false;
    loop {
        flop = !flop;
        if flop {
            SPI.read_write_bytes(Some(&mut buf1), Some(&mut buf2));
        } else {
            SPI.read_write_bytes(Some(&mut buf2), Some(&mut buf1));
            for x in 1..2000 {
                SPI.disable();
                SPI.enable();
            }
        }
    }
    // This is a simple byte-level test of SPI.
    /*let mut counter: u8 = 0;
    loop {
      let val1 = SPI.read_write_byte(0x55);
      let val2 = SPI.read_write_byte(counter);
      let val3 = SPI.read_write_byte(val1);
      let val4 = SPI.read_write_byte(val2);
      let val5 = SPI.read_write_byte(0);
      counter = counter + 1;
      for x in 1..2000 {
        SPI.disable();
        SPI.enable();
      }
    }*/

    firestorm.console.initialize();

    firestorm
}
pub static mut buf1: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
pub static mut buf2: [u8; 8] = [7, 6, 5, 4, 3, 2, 1, 0];
pub static mut SPI : sam4l::spi::Spi = sam4l::spi::Spi::new();

<commit_msg>Tested different sizes, correctly sizes to smaller one.<commit_after>#![crate_name = "platform"]
#![crate_type = "rlib"]
#![no_std]
#![feature(const_fn)]

extern crate common;
extern crate drivers;
extern crate hil;
extern crate sam4l;

use sam4l::pm;
use hil::Controller;
use hil::timer::*;
use hil::spi_master::*;

pub struct Firestorm {
    chip: sam4l::chip::Sam4l,
    console: &'static drivers::console::Console<'static, sam4l::usart::USART>,
    gpio: drivers::gpio::GPIO<[&'static hil::gpio::GPIOPin; 14]>,
    tmp006: &'static drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice>,
}

#[allow(unused_variables,dead_code)]
pub struct DummyCB {
  val: u8
}
impl hil::spi_master::SpiCallback for DummyCB {
#[allow(unused_variables,dead_code)]
        fn read_write_done(&'static self,
                           read: Option<&'static mut[u8]>,
                           writer: Option<&'static mut[u8]>) { }
}

pub static mut SPICB: DummyCB = DummyCB{val: 0x55 as u8};

impl Firestorm {
    pub unsafe fn service_pending_interrupts(&mut self) {
        self.chip.service_pending_interrupts()
    }

    pub unsafe fn has_pending_interrupts(&mut self) -> bool {
        self.chip.has_pending_interrupts()
    }

    #[inline(never)]
    pub fn with_driver<F, R>(&mut self, driver_num: usize, f: F) -> R where
            F: FnOnce(Option<&hil::Driver>) -> R {

        match driver_num {
            0 => f(Some(self.console)),
            1 => f(Some(&self.gpio)),
            2 => f(Some(self.tmp006)),
            _ => f(None)
        }
    }
}

pub unsafe fn init<'a>() -> &'a mut Firestorm {
    use core::mem;

    static mut FIRESTORM_BUF : [u8; 1024] = [0; 1024];
    static mut CONSOLE_BUF : [u8; 1024] = [0; 1024];
    static mut TIMER_BUF : [u8; 1024] = [0; 1024];
    static mut MUX_ALARM_BUF : [u8; 256] = [0; 256];
    static mut VIRT_ALARM_BUF : [u8; 256] = [0; 256];
    static mut TMP006_BUF : [u8; 1028] = [0; 1028];

    pm::enable_clock(pm::Clock::PBA(pm::PBAClock::SPI));
    /* TODO(alevy): replace above line with this. Currently, over allocating to make development
     * easier, but should be obviated when `size_of` at compile time hits.
    static mut FIRESTORM_BUF : [u8; 192] = [0; 192];
    // Just test that FIRESTORM_BUF is correct size
    // (will throw compiler error if too large or small)
    let _ : Firestorm = mem::transmute(FIRESTORM_BUF);
    let _ : Firestorm = mem::transmute(CONSOLE_BUF);
    */

    let ast = &sam4l::ast::AST;
    ast.select_clock(sam4l::ast::Clock::ClockRCSys);
    ast.set_prescalar(0);
    ast.clear_alarm();

    let console : &mut drivers::console::Console<sam4l::usart::USART> = mem::transmute(&mut CONSOLE_BUF);
    *console = drivers::console::Console::new(&mut sam4l::usart::USART3);

    let mut mux_alarm : &mut MuxAlarm<'static, sam4l::ast::Ast> = mem::transmute(&mut MUX_ALARM_BUF);
    *mux_alarm = MuxAlarm::new(ast);
    ast.configure(mux_alarm);

    let mut virtual_alarm : &mut VirtualMuxAlarm<'static, sam4l::ast::Ast> = mem::transmute(&mut VIRT_ALARM_BUF);
    *virtual_alarm = VirtualMuxAlarm::new(mux_alarm);

    let mut timer : &mut SingleTimer<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast>> = mem::transmute(&mut TIMER_BUF);
    *timer = SingleTimer::new(virtual_alarm);
    virtual_alarm.set_client(timer);

    let tmp006 : &mut drivers::tmp006::TMP006<'static, sam4l::i2c::I2CDevice> = mem::transmute(&mut TMP006_BUF);
    *tmp006 = drivers::tmp006::TMP006::new(&sam4l::i2c::I2C2, timer);

    timer.set_client(tmp006);

    sam4l::usart::USART3.set_client(&*console);

    let firestorm : &'static mut Firestorm = mem::transmute(&mut FIRESTORM_BUF);
    *firestorm = Firestorm {
        chip: sam4l::chip::Sam4l::new(),
        console: &*console,
        gpio: drivers::gpio::GPIO::new(
            [ &mut sam4l::gpio::PC[10], &mut sam4l::gpio::PC[19]
            , &mut sam4l::gpio::PC[13], &mut sam4l::gpio::PA[9]
            , &mut sam4l::gpio::PA[17], &mut sam4l::gpio::PC[20]
            , &mut sam4l::gpio::PA[19], &mut sam4l::gpio::PA[14]
            , &mut sam4l::gpio::PA[16], &mut sam4l::gpio::PA[13]
            , &mut sam4l::gpio::PA[11], &mut sam4l::gpio::PA[10]
            , &mut sam4l::gpio::PA[12], &mut sam4l::gpio::PC[09]]),
        tmp006: &*tmp006
    };

    sam4l::usart::USART3.configure(sam4l::usart::USARTParams {
        //client: &console,
        baud_rate: 115200,
        data_bits: 8,
        parity: hil::uart::Parity::None
    });

    sam4l::gpio::PB[09].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PB[10].configure(Some(sam4l::gpio::PeripheralFunction::A));

    sam4l::gpio::PA[21].configure(Some(sam4l::gpio::PeripheralFunction::E));
    sam4l::gpio::PA[22].configure(Some(sam4l::gpio::PeripheralFunction::E));

    /*
    let pc6 = &sam4l::gpio::PC[6] as &hil::gpio::GPIOPin;
    pc6.enable_output();
    loop {
        pc6.toggle();
    }
    */

    // Configure SPI pins: CLK, MISO, MOSI, CS3
    sam4l::gpio::PC[ 6].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 4].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 5].configure(Some(sam4l::gpio::PeripheralFunction::A));
    sam4l::gpio::PC[ 1].configure(Some(sam4l::gpio::PeripheralFunction::A));
    SPI.set_active_peripheral(sam4l::spi::Peripheral::Peripheral1);
    SPI.init(&SPICB);
    SPI.enable();

    let mut flop: bool = false;
    loop {
        flop = !flop;
        if flop {
            SPI.read_write_bytes(Some(&mut buf1), Some(&mut buf2));
            //SPI.read_write_bytes(Some(&mut buf1), None);
            //SPI.read_write_bytes(None, Some(&mut buf2));
        } else {
            SPI.read_write_bytes(Some(&mut buf2), Some(&mut buf1));
            //SPI.read_write_bytes(Some(&mut buf2), None);
            //SPI.read_write_bytes(None, Some(&mut buf1));
            for x in 1..2000 {
                SPI.disable();
                SPI.enable();
            }
        }
    }
    // This is a simple byte-level test of SPI.
    /*let mut counter: u8 = 0;
    loop {
      let val1 = SPI.read_write_byte(0x55);
      let val2 = SPI.read_write_byte(counter);
      let val3 = SPI.read_write_byte(val1);
      let val4 = SPI.read_write_byte(val2);
      let val5 = SPI.read_write_byte(0);
      counter = counter + 1;
      for x in 1..2000 {
        SPI.disable();
        SPI.enable();
      }
    }*/

    firestorm.console.initialize();

    firestorm
}
pub static mut buf1: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 0];
pub static mut buf2: [u8; 8] = [7. 6, 5, 4, 3, 2, 1, 0];
pub static mut SPI : sam4l::spi::Spi = sam4l::spi::Spi::new();

<|endoftext|>


<commit_before>//! Framerate control

use libc;
use libc::{c_void, uint32_t, malloc};
use std::mem;
use sdl2::SdlResult;

mod ll {
    /* automatically generated by rust-bindgen */

    use libc::*;
    pub struct FPSmanager {
        pub framecount: uint32_t,
        pub rateticks: c_float,
        pub baseticks: uint32_t,
        pub lastticks: uint32_t,
        pub rate: uint32_t,
    }
    extern "C" {
        pub fn SDL_initFramerate(manager: *mut FPSmanager);
        pub fn SDL_setFramerate(manager: *mut FPSmanager, rate: uint32_t) -> c_int;
        pub fn SDL_getFramerate(manager: *mut FPSmanager) -> c_int;
        pub fn SDL_getFramecount(manager: *mut FPSmanager) -> c_int;
        pub fn SDL_framerateDelay(manager: *mut FPSmanager) -> uint32_t;
    }
}

/// Structure holding the state and timing information of the framerate controller.
pub struct FPSManager {
    raw: *mut ll::FPSmanager,
}

impl FPSManager {
    /// Create the framerate manager.
    pub fn new() -> FPSManager {
        unsafe {
            let raw = libc::malloc(mem::size_of::<ll::FPSmanager>() as u64) as *mut ll::FPSmanager;
            ll::SDL_initFramerate(raw);
            FPSManager { raw: raw }
        }
    }

    /// Set the framerate in Hz.
    pub fn set_framerate(&mut self, rate: uint) -> SdlResult<()> {
        let ret = unsafe { ll::SDL_setFramerate(self.raw, rate as uint32_t) };
        if ret == 0 { Ok(()) }
        else { Err("set_framerate error: beyond lower/upper limit.".to_string()) }
    }

    /// Return the current target framerate in Hz.
    pub fn get_framerate(&self) -> int {
        // will not get an error
        unsafe { ll::SDL_getFramerate(self.raw) as int }
    }

    /// Return the current framecount.
    pub fn get_frame_count(&self) -> int {
        // will not get an error
        unsafe { ll::SDL_getFramecount(self.raw) as int }
    }

    /// Delay execution to maintain a constant framerate and calculate fps.
    pub fn delay(&mut self) -> uint {
        unsafe { ll::SDL_framerateDelay(self.raw) as uint }
    }
}

impl Drop for FPSManager {
    fn drop(&mut self) {
        unsafe { libc::free(self.raw as *mut c_void) }
    }
}
<commit_msg>Pass FPSmanager size as size_t to malloc instead of u64.<commit_after>//! Framerate control

use libc;
use libc::{c_void, uint32_t, malloc, size_t};
use std::mem;
use sdl2::SdlResult;

mod ll {
    /* automatically generated by rust-bindgen */

    use libc::*;
    pub struct FPSmanager {
        pub framecount: uint32_t,
        pub rateticks: c_float,
        pub baseticks: uint32_t,
        pub lastticks: uint32_t,
        pub rate: uint32_t,
    }
    extern "C" {
        pub fn SDL_initFramerate(manager: *mut FPSmanager);
        pub fn SDL_setFramerate(manager: *mut FPSmanager, rate: uint32_t) -> c_int;
        pub fn SDL_getFramerate(manager: *mut FPSmanager) -> c_int;
        pub fn SDL_getFramecount(manager: *mut FPSmanager) -> c_int;
        pub fn SDL_framerateDelay(manager: *mut FPSmanager) -> uint32_t;
    }
}

/// Structure holding the state and timing information of the framerate controller.
pub struct FPSManager {
    raw: *mut ll::FPSmanager,
}

impl FPSManager {
    /// Create the framerate manager.
    pub fn new() -> FPSManager {
        unsafe {
            let size = mem::size_of::<ll::FPSmanager>() as size_t;
            let raw = libc::malloc(size) as *mut ll::FPSmanager;
            ll::SDL_initFramerate(raw);
            FPSManager { raw: raw }
        }
    }

    /// Set the framerate in Hz.
    pub fn set_framerate(&mut self, rate: uint) -> SdlResult<()> {
        let ret = unsafe { ll::SDL_setFramerate(self.raw, rate as uint32_t) };
        if ret == 0 { Ok(()) }
        else { Err("set_framerate error: beyond lower/upper limit.".to_string()) }
    }

    /// Return the current target framerate in Hz.
    pub fn get_framerate(&self) -> int {
        // will not get an error
        unsafe { ll::SDL_getFramerate(self.raw) as int }
    }

    /// Return the current framecount.
    pub fn get_frame_count(&self) -> int {
        // will not get an error
        unsafe { ll::SDL_getFramecount(self.raw) as int }
    }

    /// Delay execution to maintain a constant framerate and calculate fps.
    pub fn delay(&mut self) -> uint {
        unsafe { ll::SDL_framerateDelay(self.raw) as uint }
    }
}

impl Drop for FPSManager {
    fn drop(&mut self) {
        unsafe { libc::free(self.raw as *mut c_void) }
    }
}
<|endoftext|>


<commit_before>#![feature(slice_concat_ext)]

extern crate compiletest_rs as compiletest;

use std::slice::SliceConcatExt;
use std::path::{PathBuf, Path};
use std::io::Write;

macro_rules! eprintln {
    ($($arg:tt)*) => {
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), $($arg)*).unwrap();
    }
}

fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) {
    eprintln!("## Running compile-fail tests in {} against miri for target {}", path, target);
    let mut config = compiletest::default_config();
    config.mode = "compile-fail".parse().expect("Invalid mode");
    config.rustc_path = "target/debug/miri".into();
    if fullmir {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST");
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    } else {
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    }
    config.target = target.to_owned();
    compiletest::run_tests(&config);
}

fn run_pass(path: &str) {
    eprintln!("## Running run-pass tests in {} against rustc", path);
    let mut config = compiletest::default_config();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    config.target_rustcflags = Some("-Dwarnings".to_string());
    config.host_rustcflags = Some("-Dwarnings".to_string());
    compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) {
    let opt_str = if opt {
        " with optimizations"
    } else {
        ""
    };
    eprintln!("## Running run-pass tests in {} against miri for target {}{}", path, target, opt_str);
    let mut config = compiletest::default_config();
    config.mode = "mir-opt".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.host = host.to_owned();
    config.rustc_path = "target/debug/miri".into();
    let mut flags = Vec::new();
    if fullmir {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST");
        flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
    }
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    } else {
        flags.push("-Zmir-opt-level=0".to_owned());
    }
    config.target_rustcflags = Some(flags.join(" "));
    // don't actually execute the final binary, it might be for other targets and we only care
    // about running miri, not the binary.
    config.runtool = Some("echo \"\" || ".to_owned());
    if target == host {
        std::env::set_var("MIRI_HOST_TARGET", "yes");
    }
    compiletest::run_tests(&config);
    std::env::set_var("MIRI_HOST_TARGET", "");
}

fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
    let mut path = path.into();
    path.push("lib");
    path.metadata().map(|m| m.is_dir()).unwrap_or(false)
}

fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
    let target_dir = sysroot.join("lib").join("rustlib");
    for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
        let entry = entry.unwrap();
        if !is_target_dir(entry.path()) { continue; }
        let target = entry.file_name().into_string().unwrap();
        f(target);
    }
}

fn get_sysroot() -> PathBuf {
    let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
        let sysroot = std::process::Command::new("rustc")
            .arg("--print")
            .arg("sysroot")
            .output()
            .expect("rustc not found")
            .stdout;
        String::from_utf8(sysroot).expect("sysroot is not utf8")
    });
    PathBuf::from(sysroot.trim())
}

fn get_host() -> String {
    let host = std::process::Command::new("rustc")
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
    let host = host.split("\nhost: ").nth(1).expect("no host: part in rustc -vV");
    let host = host.split('\n').next().expect("no \n after host");
    String::from(host)
}

#[test]
fn run_pass_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for &opt in [false, true].iter() {
        for_all_targets(&sysroot, |target| {
            miri_pass("tests/run-pass", &target, &host, false, opt);
        });
        miri_pass("tests/run-pass-fullmir", &host, &host, true, opt);
    }
}

#[test]
fn run_pass_rustc() {
    run_pass("tests/run-pass");
    run_pass("tests/run-pass-fullmir");
}

#[test]
fn compile_fail_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for_all_targets(&sysroot, |target| {
        compile_fail(&sysroot, "tests/compile-fail", &target, &host, false);
    });
    compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true);
}
<commit_msg>Choose release miri for release tests<commit_after>#![feature(slice_concat_ext)]

extern crate compiletest_rs as compiletest;

use std::slice::SliceConcatExt;
use std::path::{PathBuf, Path};
use std::io::Write;

macro_rules! eprintln {
    ($($arg:tt)*) => {
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), $($arg)*).unwrap();
    }
}

#[cfg(debug_assertions)]
const MIRI_PATH: &str = "target/debug/miri";
#[cfg(not(debug_assertions))]
const MIRI_PATH: &str = "target/release/miri";

fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) {
    eprintln!("## Running compile-fail tests in {} against miri for target {}", path, target);
    let mut config = compiletest::default_config();
    config.mode = "compile-fail".parse().expect("Invalid mode");
    config.rustc_path = MIRI_PATH.into();
    if fullmir {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST");
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    } else {
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    }
    config.target = target.to_owned();
    compiletest::run_tests(&config);
}

fn run_pass(path: &str) {
    eprintln!("## Running run-pass tests in {} against rustc", path);
    let mut config = compiletest::default_config();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    config.target_rustcflags = Some("-Dwarnings".to_string());
    config.host_rustcflags = Some("-Dwarnings".to_string());
    compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) {
    let opt_str = if opt {
        " with optimizations"
    } else {
        ""
    };
    eprintln!("## Running run-pass tests in {} against miri for target {}{}", path, target, opt_str);
    let mut config = compiletest::default_config();
    config.mode = "mir-opt".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.host = host.to_owned();
    config.rustc_path = MIRI_PATH.into();
    let mut flags = Vec::new();
    if fullmir {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST");
        flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
    }
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    } else {
        flags.push("-Zmir-opt-level=0".to_owned());
    }
    config.target_rustcflags = Some(flags.join(" "));
    // don't actually execute the final binary, it might be for other targets and we only care
    // about running miri, not the binary.
    config.runtool = Some("echo \"\" || ".to_owned());
    if target == host {
        std::env::set_var("MIRI_HOST_TARGET", "yes");
    }
    compiletest::run_tests(&config);
    std::env::set_var("MIRI_HOST_TARGET", "");
}

fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
    let mut path = path.into();
    path.push("lib");
    path.metadata().map(|m| m.is_dir()).unwrap_or(false)
}

fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
    let target_dir = sysroot.join("lib").join("rustlib");
    for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
        let entry = entry.unwrap();
        if !is_target_dir(entry.path()) { continue; }
        let target = entry.file_name().into_string().unwrap();
        f(target);
    }
}

fn get_sysroot() -> PathBuf {
    let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
        let sysroot = std::process::Command::new("rustc")
            .arg("--print")
            .arg("sysroot")
            .output()
            .expect("rustc not found")
            .stdout;
        String::from_utf8(sysroot).expect("sysroot is not utf8")
    });
    PathBuf::from(sysroot.trim())
}

fn get_host() -> String {
    let host = std::process::Command::new("rustc")
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
    let host = host.split("\nhost: ").nth(1).expect("no host: part in rustc -vV");
    let host = host.split('\n').next().expect("no \n after host");
    String::from(host)
}

#[test]
fn run_pass_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for &opt in [false, true].iter() {
        for_all_targets(&sysroot, |target| {
            miri_pass("tests/run-pass", &target, &host, false, opt);
        });
        miri_pass("tests/run-pass-fullmir", &host, &host, true, opt);
    }
}

#[test]
fn run_pass_rustc() {
    run_pass("tests/run-pass");
    run_pass("tests/run-pass-fullmir");
}

#[test]
fn compile_fail_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for_all_targets(&sysroot, |target| {
        compile_fail(&sysroot, "tests/compile-fail", &target, &host, false);
    });
    compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true);
}
<|endoftext|>


<commit_before>#![feature(slice_concat_ext)]

extern crate compiletest_rs as compiletest;

use std::slice::SliceConcatExt;
use std::path::{PathBuf, Path};
use std::io::Write;

macro_rules! eprintln {
    ($($arg:tt)*) => {
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), $($arg)*).unwrap();
    }
}

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) {
    eprintln!(
        "## Running compile-fail tests in {} against miri for target {}",
        path,
        target
    );
    let mut config = compiletest::default_config();
    config.mode = "compile-fail".parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    let mut flags = Vec::new();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    // if we are building as part of the rustc test suite, we already have fullmir for everything
    if fullmir && rustc_test_suite().is_none() {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap())
            .join(".xargo")
            .join("HOST");
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    } else {
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    }
    flags.push("-Zmir-emit-validate=1".to_owned());
    config.target_rustcflags = Some(flags.join(" "));
    config.target = target.to_owned();
    compiletest::run_tests(&config);
}

fn run_pass(path: &str) {
    eprintln!("## Running run-pass tests in {} against rustc", path);
    let mut config = compiletest::default_config();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    if let Some(rustc_path) = rustc_test_suite() {
        config.rustc_path = rustc_path;
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", get_sysroot().display()));
    config.host_rustcflags = Some("-Dwarnings".to_string());
    compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    );
    let mut config = compiletest::default_config();
    config.mode = "mir-opt".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.host = host.to_owned();
    config.rustc_path = miri_path();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    let mut flags = Vec::new();
    // if we are building as part of the rustc test suite, we already have fullmir for everything
    if fullmir && rustc_test_suite().is_none() {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap())
            .join(".xargo")
            .join("HOST");
        flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
    }
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    } else {
        flags.push("-Zmir-opt-level=0".to_owned());
        // For now, only validate without optimizations.  Inlining breaks validation.
        flags.push("-Zmir-emit-validate=1".to_owned());
    }
    config.target_rustcflags = Some(flags.join(" "));
    // don't actually execute the final binary, it might be for other targets and we only care
    // about running miri, not the binary.
    config.runtool = Some("echo \"\" || ".to_owned());
    if target == host {
        std::env::set_var("MIRI_HOST_TARGET", "yes");
    }
    compiletest::run_tests(&config);
    std::env::set_var("MIRI_HOST_TARGET", "");
}

fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
    let mut path = path.into();
    path.push("lib");
    path.metadata().map(|m| m.is_dir()).unwrap_or(false)
}

fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
    let target_dir = sysroot.join("lib").join("rustlib");
    for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
        let entry = entry.unwrap();
        if !is_target_dir(entry.path()) {
            continue;
        }
        let target = entry.file_name().into_string().unwrap();
        f(target);
    }
}

fn get_sysroot() -> PathBuf {
    let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
        let sysroot = std::process::Command::new("rustc")
            .arg("--print")
            .arg("sysroot")
            .output()
            .expect("rustc not found")
            .stdout;
        String::from_utf8(sysroot).expect("sysroot is not utf8")
    });
    PathBuf::from(sysroot.trim())
}

fn get_host() -> String {
    let host = std::process::Command::new("rustc")
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
    let host = host.split("\nhost: ").nth(1).expect(
        "no host: part in rustc -vV",
    );
    let host = host.split('\n').next().expect("no \n after host");
    String::from(host)
}

#[test]
fn run_pass_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for &opt in [false, true].iter() {
        for_all_targets(&sysroot, |target| {
            miri_pass("tests/run-pass", &target, &host, false, opt);
        });
        miri_pass("tests/run-pass-fullmir", &host, &host, true, opt);
    }
}

#[test]
fn run_pass_rustc() {
    run_pass("tests/run-pass");
    run_pass("tests/run-pass-fullmir");
}

#[test]
fn compile_fail_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for_all_targets(&sysroot, |target| {
        compile_fail(&sysroot, "tests/compile-fail", &target, &host, false);
    });
    compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true);
}
<commit_msg>Update compiletest.rs<commit_after>#![feature(slice_concat_ext)]

extern crate compiletest_rs as compiletest;

use std::slice::SliceConcatExt;
use std::path::{PathBuf, Path};
use std::io::Write;

macro_rules! eprintln {
    ($($arg:tt)*) => {
        let stderr = std::io::stderr();
        writeln!(stderr.lock(), $($arg)*).unwrap();
    }
}

fn miri_path() -> PathBuf {
    if rustc_test_suite().is_some() {
        PathBuf::from(option_env!("MIRI_PATH").unwrap())
    } else {
        PathBuf::from(concat!("target/", env!("PROFILE"), "/miri"))
    }
}

fn rustc_test_suite() -> Option<PathBuf> {
    option_env!("RUSTC_TEST_SUITE").map(PathBuf::from)
}

fn rustc_lib_path() -> PathBuf {
    option_env!("RUSTC_LIB_PATH").unwrap().into()
}

fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) {
    eprintln!(
        "## Running compile-fail tests in {} against miri for target {}",
        path,
        target
    );
    let mut config = compiletest::default_config();
    config.mode = "compile-fail".parse().expect("Invalid mode");
    config.rustc_path = miri_path();
    let mut flags = Vec::new();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    // if we are building as part of the rustc test suite, we already have fullmir for everything
    if fullmir && rustc_test_suite().is_none() {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap())
            .join(".xargo")
            .join("HOST");
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    } else {
        config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap()));
        config.src_base = PathBuf::from(path.to_string());
    }
    flags.push("-Zmir-emit-validate=1".to_owned());
    config.target_rustcflags = Some(flags.join(" "));
    config.target = target.to_owned();
    compiletest::run_tests(&config);
}

fn run_pass(path: &str) {
    eprintln!("## Running run-pass tests in {} against rustc", path);
    let mut config = compiletest::default_config();
    config.mode = "run-pass".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    if let Some(rustc_path) = rustc_test_suite() {
        config.rustc_path = rustc_path;
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
        config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", get_sysroot().display()));
    } else {
        config.target_rustcflags = Some("-Dwarnings".to_owned());
    }
    config.host_rustcflags = Some("-Dwarnings".to_string());
    compiletest::run_tests(&config);
}

fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) {
    let opt_str = if opt { " with optimizations" } else { "" };
    eprintln!(
        "## Running run-pass tests in {} against miri for target {}{}",
        path,
        target,
        opt_str
    );
    let mut config = compiletest::default_config();
    config.mode = "mir-opt".parse().expect("Invalid mode");
    config.src_base = PathBuf::from(path);
    config.target = target.to_owned();
    config.host = host.to_owned();
    config.rustc_path = miri_path();
    if rustc_test_suite().is_some() {
        config.run_lib_path = rustc_lib_path();
        config.compile_lib_path = rustc_lib_path();
    }
    let mut flags = Vec::new();
    // if we are building as part of the rustc test suite, we already have fullmir for everything
    if fullmir && rustc_test_suite().is_none() {
        if host != target {
            // skip fullmir on nonhost
            return;
        }
        let sysroot = Path::new(&std::env::var("HOME").unwrap())
            .join(".xargo")
            .join("HOST");
        flags.push(format!("--sysroot {}", sysroot.to_str().unwrap()));
    }
    if opt {
        flags.push("-Zmir-opt-level=3".to_owned());
    } else {
        flags.push("-Zmir-opt-level=0".to_owned());
        // For now, only validate without optimizations.  Inlining breaks validation.
        flags.push("-Zmir-emit-validate=1".to_owned());
    }
    config.target_rustcflags = Some(flags.join(" "));
    // don't actually execute the final binary, it might be for other targets and we only care
    // about running miri, not the binary.
    config.runtool = Some("echo \"\" || ".to_owned());
    if target == host {
        std::env::set_var("MIRI_HOST_TARGET", "yes");
    }
    compiletest::run_tests(&config);
    std::env::set_var("MIRI_HOST_TARGET", "");
}

fn is_target_dir<P: Into<PathBuf>>(path: P) -> bool {
    let mut path = path.into();
    path.push("lib");
    path.metadata().map(|m| m.is_dir()).unwrap_or(false)
}

fn for_all_targets<F: FnMut(String)>(sysroot: &Path, mut f: F) {
    let target_dir = sysroot.join("lib").join("rustlib");
    for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") {
        let entry = entry.unwrap();
        if !is_target_dir(entry.path()) {
            continue;
        }
        let target = entry.file_name().into_string().unwrap();
        f(target);
    }
}

fn get_sysroot() -> PathBuf {
    let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| {
        let sysroot = std::process::Command::new("rustc")
            .arg("--print")
            .arg("sysroot")
            .output()
            .expect("rustc not found")
            .stdout;
        String::from_utf8(sysroot).expect("sysroot is not utf8")
    });
    PathBuf::from(sysroot.trim())
}

fn get_host() -> String {
    let host = std::process::Command::new("rustc")
        .arg("-vV")
        .output()
        .expect("rustc not found for -vV")
        .stdout;
    let host = std::str::from_utf8(&host).expect("sysroot is not utf8");
    let host = host.split("\nhost: ").nth(1).expect(
        "no host: part in rustc -vV",
    );
    let host = host.split('\n').next().expect("no \n after host");
    String::from(host)
}

#[test]
fn run_pass_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for &opt in [false, true].iter() {
        for_all_targets(&sysroot, |target| {
            miri_pass("tests/run-pass", &target, &host, false, opt);
        });
        miri_pass("tests/run-pass-fullmir", &host, &host, true, opt);
    }
}

#[test]
fn run_pass_rustc() {
    run_pass("tests/run-pass");
    run_pass("tests/run-pass-fullmir");
}

#[test]
fn compile_fail_miri() {
    let sysroot = get_sysroot();
    let host = get_host();

    for_all_targets(&sysroot, |target| {
        compile_fail(&sysroot, "tests/compile-fail", &target, &host, false);
    });
    compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true);
}
<|endoftext|>


<commit_before>#![feature(test)]
#![feature(core)]
#![allow(unused_imports)]

#[macro_use]
extern crate eve;
extern crate test;
extern crate core;

use eve::interpreter::*;
use eve::value::*;
use eve::test::*;

#[allow(dead_code)]
fn main() {

	let input = Expression::Constant(3.to_value());
	let patterns = vec!(Pattern::Constant(1.to_value()),
					    Pattern::Constant(2.to_value()),
					    Pattern::Constant(3.to_value()),
					    Pattern::Constant(4.to_value()),
					    Pattern::Constant(3.to_value()),
					   );
	let handlers = exprvec!["one","two","three","four","five"];

	let m = Match{input: input, patterns: patterns, handlers: handlers};

	let result = evaluate(&m.to_expr());

	println!("{:?}",result);
}

#[test]
fn match_test(){

	let input = Expression::Constant(3.to_value());

	let patterns = vec!(Pattern::Constant(1.to_value()),
					    Pattern::Constant(2.to_value()),
					    Pattern::Constant(3.to_value()),
					    Pattern::Constant(4.to_value()),
					    Pattern::Constant(3.to_value()),
					   );
	let handlers = exprvec!["one","two","three","four","five"];

	let m = Match{input: input, patterns: patterns, handlers: handlers};

	let result = evaluate(&m.to_expr());

	println!("{:?}",result);
}

#[test]
fn opstest() {

	// Test Some General Math Ops: (((1.3 + 2) * 3) + (7 - 4) / 10) ^ 2.5
	let c1 = Call{fun: EveFn::Add, args: exprvec![1.3,2]};				// C1 = 1.3 + 2
	let c2 = Call{fun: EveFn::Multiply, args: exprvec![c1,3]};			// C2 = C1 * 3
	let c3 = Call{fun: EveFn::Subtract, args: exprvec![7,4]};			// C3 = 7 - 4
	let c4 = Call{fun: EveFn::Divide, args: exprvec![c3,10]};			// C4 = C3 / 10
	let c5 = Call{fun: EveFn::Add, args: exprvec![c2,c4]};				// C5 = C2 + C4
	let c6 = Call{fun: EveFn::Exponentiate, args: exprvec![c5,2.5]};	// C6 = C5 ^ 2.5
	let result = evaluate(&c6.to_expr());
	assert_eq!(result,(((1.3f64 + 2f64) * 3f64) + (7f64 - 4f64) / 10f64).powf(2.5f64).to_value());

}

#[test]
fn stringtest() {

	// Test a text replacement
	let c1 = Call{fun: EveFn::StrReplace, args: exprvec!["Hello World","l","q"] };
	let result = evaluate(&c1.to_expr());
	assert_eq!(result.as_str(),"HeWorqd");

}

#[test]
fn trigtest() {

	let pi = std::f64::consts::PI;

	// sin
	let c1 = Call{fun: EveFn::Sin, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.sin().to_value());

	// cos
	let c1 = Call{fun: EveFn::Cos, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.cos().to_value());

	// tan
	let c1 = Call{fun: EveFn::Tan, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.tan().to_value());

	// atan2
	let c1 = Call{fun: EveFn::ATan2, args: exprvec![1.2,2.3]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,1.2f64.atan2(2.3f64).to_value());
}

#[test]
fn bigmathtest() {

	let wa = 1.5;
	let ma = 2.3;
	let va = 11.3;
	let ga = 0.34;
	let mu = 1.50;
	let gd = 3.14;
	let g = 9.8;
	let wx = 0.04;
	let ps = 0.013;
	let rh = 1.74;

	let c1 = Call{fun: EveFn::Sin, args: exprvec![ga]}; 			// sin(ga)
	let c2 = Call{fun: EveFn::Exponentiate, args: exprvec![c1,2]}; 	// sin(ga)^2
	let c3 = Call{fun: EveFn::Multiply, args: exprvec![wx,c2]}; 	// wx*sin(ga)^2
	let c4 = Call{fun: EveFn::Sin, args: exprvec![ps]}; 			// sin(ps)
	let c5 = Call{fun: EveFn::Multiply, args: exprvec![c3,c4]}; 	// wx*sin(ga)^2*sin(ps)

	let c6 = Call{fun: EveFn::Cos, args: exprvec![ga]}; 			// cos(ga)
	let c7 = Call{fun: EveFn::Multiply, args: exprvec![g,c6]}; 		// g*cos(ga)
	let c8 = Call{fun: EveFn::Divide, args: exprvec![c7,va]}; 		// g*cos(ga)/va
	let c9 = Call{fun: EveFn::Add, args: exprvec![gd,c8]}; 			// gd+g*cos(ga)/va

	let c10 = Call{fun: EveFn::Subtract, args: exprvec![c9,c5]}; 	// (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let c11 = Call{fun: EveFn::Multiply, args: exprvec![wa,rh]};	// wa*rh
	let c12 = Call{fun: EveFn::Multiply, args: exprvec![c11,va]};	// wa*rh*va
	let c13 = Call{fun: EveFn::Cos, args: exprvec![mu]}; 			// cos(mu)
	let c14 = Call{fun: EveFn::Multiply, args: exprvec![c12,c13]};	// wa*rh*va*cos(mu)

	let c15 = Call{fun: EveFn::Multiply, args: exprvec![2,ma]};		// 2*ma

	let c16 = Call{fun: EveFn::Divide, args: exprvec![c15,c14]};	// 2*ma/wa*rh*va*cos(mu)

	let c17 = Call{fun: EveFn::Multiply, args: exprvec![c16,c10]};	// (2*ma/wa*rh*va*cos(mu)) * (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let result = evaluate(&c17.to_expr());

	assert_eq!(result,(2f64*ma/(wa*rh*va*mu.cos())*(gd+g*ga.cos()/va-wx*(ga.sin().powf(2f64))*ps.sin())).to_value());

}

#[bench]
fn opsbench(b: &mut test::Bencher) {

	// Test Some General Math Ops: (((1 + 2) * 3) + (7 - 4) / 10) ^ 2
	let c1 = Call{fun: EveFn::Add, args: exprvec![1.3,2]};				// C1 = 1.3 + 2
	let c2 = Call{fun: EveFn::Multiply, args: exprvec![c1,3]};			// C2 = C1 * 3
	let c3 = Call{fun: EveFn::Subtract, args: exprvec![7,4]};			// C3 = 7 - 4
	let c4 = Call{fun: EveFn::Divide, args: exprvec![c3,10]};			// C4 = C3 / 10
	let c5 = Call{fun: EveFn::Add, args: exprvec![c2,c4]};				// C5 = C2 + C4
	let c6 = Call{fun: EveFn::Exponentiate, args: exprvec![c5,2.5]};	// C6 = C5 ^ 2.5
	let e1 = c6.to_expr();
	b.iter(|| {
		evaluate(&e1)
	});
}

#[bench]
fn bigmathbench(b: &mut test::Bencher) {

	let wa = 1.5;
	let ma = 2.3;
	let va = 11.3;
	let ga = 0.34;
	let mu = 1.50;
	let gd = 3.14;
	let g = 9.8;
	let wx = 0.04;
	let ps = 0.013;
	let rh = 1.74;

	let c1 = Call{fun: EveFn::Sin, args: exprvec![ga]}; 			// sin(ga)
	let c2 = Call{fun: EveFn::Exponentiate, args: exprvec![c1,2]}; 	// sin(ga)^2
	let c3 = Call{fun: EveFn::Multiply, args: exprvec![wx,c2]}; 	// wx*sin(ga)^2
	let c4 = Call{fun: EveFn::Sin, args: exprvec![ps]}; 			// sin(ps)
	let c5 = Call{fun: EveFn::Multiply, args: exprvec![c3,c4]}; 	// wx*sin(ga)^2*sin(ps)

	let c6 = Call{fun: EveFn::Cos, args: exprvec![ga]}; 			// cos(ga)
	let c7 = Call{fun: EveFn::Multiply, args: exprvec![g,c6]}; 		// g*cos(ga)
	let c8 = Call{fun: EveFn::Divide, args: exprvec![c7,va]}; 		// g*cos(ga)/va
	let c9 = Call{fun: EveFn::Add, args: exprvec![gd,c8]}; 			// gd+g*cos(ga)/va

	let c10 = Call{fun: EveFn::Subtract, args: exprvec![c9,c5]}; 	// (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let c11 = Call{fun: EveFn::Multiply, args: exprvec![wa,rh]};	// wa*rh
	let c12 = Call{fun: EveFn::Multiply, args: exprvec![c11,va]};	// wa*rh*va
	let c13 = Call{fun: EveFn::Cos, args: exprvec![mu]}; 			// cos(mu)
	let c14 = Call{fun: EveFn::Multiply, args: exprvec![c12,c13]};	// wa*rh*va*cos(mu)

	let c15 = Call{fun: EveFn::Multiply, args: exprvec![2,ma]};		// 2*ma

	let c16 = Call{fun: EveFn::Divide, args: exprvec![c15,c14]};	// 2*ma/wa*rh*va*cos(mu)

	let c17 = Call{fun: EveFn::Multiply, args: exprvec![c16,c10]};	// (2*ma/wa*rh*va*cos(mu)) * (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let e1 = c17.to_expr();

	b.iter(|| {
		evaluate(&e1)
	});

}<commit_msg>Revert "Intentionally break test"<commit_after>#![feature(test)]
#![feature(core)]
#![allow(unused_imports)]

#[macro_use]
extern crate eve;
extern crate test;
extern crate core;

use eve::interpreter::*;
use eve::value::*;
use eve::test::*;

#[allow(dead_code)]
fn main() {

	let input = Expression::Constant(3.to_value());
	let patterns = vec!(Pattern::Constant(1.to_value()),
					    Pattern::Constant(2.to_value()),
					    Pattern::Constant(3.to_value()),
					    Pattern::Constant(4.to_value()),
					    Pattern::Constant(3.to_value()),
					   );
	let handlers = exprvec!["one","two","three","four","five"];

	let m = Match{input: input, patterns: patterns, handlers: handlers};

	let result = evaluate(&m.to_expr());

	println!("{:?}",result);
}

#[test]
fn match_test(){

	let input = Expression::Constant(3.to_value());

	let patterns = vec!(Pattern::Constant(1.to_value()),
					    Pattern::Constant(2.to_value()),
					    Pattern::Constant(3.to_value()),
					    Pattern::Constant(4.to_value()),
					    Pattern::Constant(3.to_value()),
					   );
	let handlers = exprvec!["one","two","three","four","five"];

	let m = Match{input: input, patterns: patterns, handlers: handlers};

	let result = evaluate(&m.to_expr());

	println!("{:?}",result);
}

#[test]
fn opstest() {

	// Test Some General Math Ops: (((1.3 + 2) * 3) + (7 - 4) / 10) ^ 2.5
	let c1 = Call{fun: EveFn::Add, args: exprvec![1.3,2]};				// C1 = 1.3 + 2
	let c2 = Call{fun: EveFn::Multiply, args: exprvec![c1,3]};			// C2 = C1 * 3
	let c3 = Call{fun: EveFn::Subtract, args: exprvec![7,4]};			// C3 = 7 - 4
	let c4 = Call{fun: EveFn::Divide, args: exprvec![c3,10]};			// C4 = C3 / 10
	let c5 = Call{fun: EveFn::Add, args: exprvec![c2,c4]};				// C5 = C2 + C4
	let c6 = Call{fun: EveFn::Exponentiate, args: exprvec![c5,2.5]};	// C6 = C5 ^ 2.5
	let result = evaluate(&c6.to_expr());
	assert_eq!(result,(((1.3f64 + 2f64) * 3f64) + (7f64 - 4f64) / 10f64).powf(2.5f64).to_value());

}

#[test]
fn stringtest() {

	// Test a text replacement
	let c1 = Call{fun: EveFn::StrReplace, args: exprvec!["Hello World","l","q"] };
	let result = evaluate(&c1.to_expr());
	assert_eq!(result.as_str(),"Heqqo Worqd");

}

#[test]
fn trigtest() {

	let pi = std::f64::consts::PI;

	// sin
	let c1 = Call{fun: EveFn::Sin, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.sin().to_value());

	// cos
	let c1 = Call{fun: EveFn::Cos, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.cos().to_value());

	// tan
	let c1 = Call{fun: EveFn::Tan, args: exprvec![pi]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,pi.tan().to_value());

	// atan2
	let c1 = Call{fun: EveFn::ATan2, args: exprvec![1.2,2.3]};
	let result = evaluate(&c1.to_expr());
	assert_eq!(result,1.2f64.atan2(2.3f64).to_value());
}

#[test]
fn bigmathtest() {

	let wa = 1.5;
	let ma = 2.3;
	let va = 11.3;
	let ga = 0.34;
	let mu = 1.50;
	let gd = 3.14;
	let g = 9.8;
	let wx = 0.04;
	let ps = 0.013;
	let rh = 1.74;

	let c1 = Call{fun: EveFn::Sin, args: exprvec![ga]}; 			// sin(ga)
	let c2 = Call{fun: EveFn::Exponentiate, args: exprvec![c1,2]}; 	// sin(ga)^2
	let c3 = Call{fun: EveFn::Multiply, args: exprvec![wx,c2]}; 	// wx*sin(ga)^2
	let c4 = Call{fun: EveFn::Sin, args: exprvec![ps]}; 			// sin(ps)
	let c5 = Call{fun: EveFn::Multiply, args: exprvec![c3,c4]}; 	// wx*sin(ga)^2*sin(ps)

	let c6 = Call{fun: EveFn::Cos, args: exprvec![ga]}; 			// cos(ga)
	let c7 = Call{fun: EveFn::Multiply, args: exprvec![g,c6]}; 		// g*cos(ga)
	let c8 = Call{fun: EveFn::Divide, args: exprvec![c7,va]}; 		// g*cos(ga)/va
	let c9 = Call{fun: EveFn::Add, args: exprvec![gd,c8]}; 			// gd+g*cos(ga)/va

	let c10 = Call{fun: EveFn::Subtract, args: exprvec![c9,c5]}; 	// (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let c11 = Call{fun: EveFn::Multiply, args: exprvec![wa,rh]};	// wa*rh
	let c12 = Call{fun: EveFn::Multiply, args: exprvec![c11,va]};	// wa*rh*va
	let c13 = Call{fun: EveFn::Cos, args: exprvec![mu]}; 			// cos(mu)
	let c14 = Call{fun: EveFn::Multiply, args: exprvec![c12,c13]};	// wa*rh*va*cos(mu)

	let c15 = Call{fun: EveFn::Multiply, args: exprvec![2,ma]};		// 2*ma

	let c16 = Call{fun: EveFn::Divide, args: exprvec![c15,c14]};	// 2*ma/wa*rh*va*cos(mu)

	let c17 = Call{fun: EveFn::Multiply, args: exprvec![c16,c10]};	// (2*ma/wa*rh*va*cos(mu)) * (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let result = evaluate(&c17.to_expr());

	assert_eq!(result,(2f64*ma/(wa*rh*va*mu.cos())*(gd+g*ga.cos()/va-wx*(ga.sin().powf(2f64))*ps.sin())).to_value());

}

#[bench]
fn opsbench(b: &mut test::Bencher) {

	// Test Some General Math Ops: (((1 + 2) * 3) + (7 - 4) / 10) ^ 2
	let c1 = Call{fun: EveFn::Add, args: exprvec![1.3,2]};				// C1 = 1.3 + 2
	let c2 = Call{fun: EveFn::Multiply, args: exprvec![c1,3]};			// C2 = C1 * 3
	let c3 = Call{fun: EveFn::Subtract, args: exprvec![7,4]};			// C3 = 7 - 4
	let c4 = Call{fun: EveFn::Divide, args: exprvec![c3,10]};			// C4 = C3 / 10
	let c5 = Call{fun: EveFn::Add, args: exprvec![c2,c4]};				// C5 = C2 + C4
	let c6 = Call{fun: EveFn::Exponentiate, args: exprvec![c5,2.5]};	// C6 = C5 ^ 2.5
	let e1 = c6.to_expr();
	b.iter(|| {
		evaluate(&e1)
	});
}

#[bench]
fn bigmathbench(b: &mut test::Bencher) {

	let wa = 1.5;
	let ma = 2.3;
	let va = 11.3;
	let ga = 0.34;
	let mu = 1.50;
	let gd = 3.14;
	let g = 9.8;
	let wx = 0.04;
	let ps = 0.013;
	let rh = 1.74;

	let c1 = Call{fun: EveFn::Sin, args: exprvec![ga]}; 			// sin(ga)
	let c2 = Call{fun: EveFn::Exponentiate, args: exprvec![c1,2]}; 	// sin(ga)^2
	let c3 = Call{fun: EveFn::Multiply, args: exprvec![wx,c2]}; 	// wx*sin(ga)^2
	let c4 = Call{fun: EveFn::Sin, args: exprvec![ps]}; 			// sin(ps)
	let c5 = Call{fun: EveFn::Multiply, args: exprvec![c3,c4]}; 	// wx*sin(ga)^2*sin(ps)

	let c6 = Call{fun: EveFn::Cos, args: exprvec![ga]}; 			// cos(ga)
	let c7 = Call{fun: EveFn::Multiply, args: exprvec![g,c6]}; 		// g*cos(ga)
	let c8 = Call{fun: EveFn::Divide, args: exprvec![c7,va]}; 		// g*cos(ga)/va
	let c9 = Call{fun: EveFn::Add, args: exprvec![gd,c8]}; 			// gd+g*cos(ga)/va

	let c10 = Call{fun: EveFn::Subtract, args: exprvec![c9,c5]}; 	// (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let c11 = Call{fun: EveFn::Multiply, args: exprvec![wa,rh]};	// wa*rh
	let c12 = Call{fun: EveFn::Multiply, args: exprvec![c11,va]};	// wa*rh*va
	let c13 = Call{fun: EveFn::Cos, args: exprvec![mu]}; 			// cos(mu)
	let c14 = Call{fun: EveFn::Multiply, args: exprvec![c12,c13]};	// wa*rh*va*cos(mu)

	let c15 = Call{fun: EveFn::Multiply, args: exprvec![2,ma]};		// 2*ma

	let c16 = Call{fun: EveFn::Divide, args: exprvec![c15,c14]};	// 2*ma/wa*rh*va*cos(mu)

	let c17 = Call{fun: EveFn::Multiply, args: exprvec![c16,c10]};	// (2*ma/wa*rh*va*cos(mu)) * (gd+g*cos(ga)/va) - (wx*sin(ga)^2*sin(ps))

	let e1 = c17.to_expr();

	b.iter(|| {
		evaluate(&e1)
	});

}<|endoftext|>