<commit_before>pub mod rustnsobject;

extern crate objc;
extern crate objc_foundation;
extern crate cocoa;
extern crate libc;

pub use ::TStatusBar;
pub use ::NSCallback;

use objc::runtime::Class;

use self::cocoa::base::{nil, YES};
use self::cocoa::appkit::NSStatusBar;
use self::cocoa::foundation::{NSAutoreleasePool,NSString};
use self::cocoa::appkit::{NSApp,
                          NSApplication,
                          NSApplicationActivationPolicyAccessory,
                          NSMenu,
                          NSMenuItem,
                          NSImage,
                          NSVariableStatusItemLength,
                          NSStatusItem,
                          NSButton};

use self::rustnsobject::{NSObj, NSObjTrait, NSObjCallbackTrait};

use std::sync::mpsc::Sender;

use std::ptr;
use std::cell::Cell;
use std::ffi::CStr;
use std::thread::sleep;
use std::time::Duration;

extern crate objc_id;
use self::objc_id::Id;

pub type Object = objc::runtime::Object;

pub struct OSXStatusBar {
    object: NSObj,
    app: *mut objc::runtime::Object,
    status_bar_item: *mut objc::runtime::Object,
    menu_bar: *mut objc::runtime::Object,

    // Run loop state
    // Keeping these in persistent state instead of recalculating saves quite a
    // bit of CPU during idle.
    pool: Cell<*mut objc::runtime::Object>,
    run_count: Cell<u64>,
    run_mode: *mut objc::runtime::Object,
    run_date: *mut objc::runtime::Object,
}

impl TStatusBar for OSXStatusBar {
    type S = OSXStatusBar;
    fn new(tx: Sender<String>) -> OSXStatusBar {
        let mut bar;
        unsafe {
            let app = NSApp();
            let status_bar = NSStatusBar::systemStatusBar(nil);
            let date_cls = Class::get("NSDate").unwrap();
            bar = OSXStatusBar {
                app: app,
                status_bar_item: status_bar.statusItemWithLength_(NSVariableStatusItemLength),
                menu_bar: NSMenu::new(nil),
                object: NSObj::alloc(tx).setup(),
                pool: Cell::new(nil),
                run_count: Cell::new(0),
                run_mode: NSString::alloc(nil).init_str("kCFRunLoopDefaultMode"),
                run_date: msg_send![date_cls, distantPast],
            };
            bar.app.setActivationPolicy_(NSApplicationActivationPolicyAccessory);
            msg_send![bar.status_bar_item, setHighlightMode:YES];
            let img_path = match bundled_resource_path("spotify", "png") {
                Some(path) => path,
                None => "spotify.png".to_string(),
            };
            let img = NSString::alloc(nil).init_str(&img_path);
            let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
            let _ = msg_send![img, release];
            //let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
            //let icon = NSImage::imageNamed_(img, img);
            let title = NSString::alloc(nil).init_str("connectr");
            NSButton::setTitle_(bar.status_bar_item, title);
            let _ = msg_send![title, release];
            bar.status_bar_item.button().setImage_(icon);
            let _ = msg_send![icon, release];
            bar.status_bar_item.setMenu_(bar.menu_bar);
            bar.object.cb_fn = Some(Box::new(
                move |s, sender| {
                    let cb = s.get_value(sender);
                    cb(sender, &s.tx);
                }
            ));
            let _: () = msg_send![app, finishLaunching];
        }
        bar
    }
    fn can_redraw(&mut self) -> bool {
        true
    }
    fn clear_items(&mut self) {
        unsafe {
            let old_menu = self.menu_bar;
            self.menu_bar = NSMenu::new(nil);
            self.status_bar_item.setMenu_(self.menu_bar);
            let _ = msg_send![old_menu, removeAllItems];
            let _ = msg_send![old_menu, release];
        }
    }
    fn set_tooltip(&mut self, text: &str) {
        unsafe {
            let img = NSString::alloc(nil).init_str(text);
            let _ = msg_send![self.status_bar_item.button(), setToolTip: img];
            let _ = msg_send![img, release];
        }
    }
    fn add_label(&mut self, label: &str) {
        unsafe {
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
            let _ = msg_send![txt, release];
            let _ = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _ = msg_send![app_menu_item, release];
        }
    }
    fn add_quit(&mut self, label: &str) {
        unsafe {
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, sel!(terminate:), quit_key);
            let _ = msg_send![txt, release];
            let _ = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _ = msg_send![app_menu_item, release];
        }
    }
    fn add_separator(&mut self) {
        unsafe {
            let cls = Class::get("NSMenuItem").unwrap();
            let sep: *mut Object = msg_send![cls, separatorItem];
            self.menu_bar.addItem_(sep);
        }
    }
    fn add_item(&mut self, item: &str, callback: NSCallback, selected: bool) -> *mut Object {
        unsafe {
            let txt = NSString::alloc(nil).init_str(item);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
            let _ = msg_send![txt, release];
            let _ = msg_send![quit_key, release];
            self.object.add_callback(app_menu_item, callback);
            let objc = self.object.take_objc();
            let _: () = msg_send![app_menu_item, setTarget: objc];
            if selected {
                let _: () = msg_send![app_menu_item, setState: 1];
            }
            let item: *mut Object = app_menu_item;
            self.menu_bar.addItem_(app_menu_item);
            let _ = msg_send![app_menu_item, release];
            item
        }
    }
    fn update_item(&mut self, item: *mut Object, label: &str) {
        unsafe {
            let ns_label = NSString::alloc(nil).init_str(label);
            let _: () = msg_send![item, setTitle: ns_label];
            let _ = msg_send![ns_label, release];
        }
    }
    fn sel_item(&mut self, sender: u64) {
        let target: *mut Object = sender as *mut Object;
        unsafe {
            let _: () = msg_send![target, setState: 1];
        }
    }
    fn unsel_item(&mut self, sender: u64) {
        let target: *mut Object = sender as *mut Object;
        unsafe {
            let _: () = msg_send![target, setState: 0];
        }
    }
    fn run(&mut self, block: bool) {
        loop {
            unsafe {
                let run_count = self.run_count.get();
                // Create a new release pool every once in a while, draining the old one
                if run_count % 100 == 0 {
                    let old_pool = self.pool.get();
                    if run_count != 0 {
                        let _ = msg_send![old_pool, drain];
                    }
                    self.pool.set(NSAutoreleasePool::new(nil));
                }
                let mode = self.run_mode;
                let event: Id<Object> = msg_send![self.app, nextEventMatchingMask: -1
                                                  untilDate: self.run_date inMode:mode dequeue: YES];
                let _ = msg_send![self.app, sendEvent: event];
                let _ = msg_send![self.app, updateWindows];
                self.run_count.set(run_count + 1);
            }
            if !block { break; }
            sleep(Duration::from_millis(50));
        }
    }
}

//pub fn osx_alert(text: &str) {
//    unsafe {
//        let ns_text = NSString::alloc(nil).init_str(text);
//        let button = NSString::alloc(nil).init_str("ok");
//        let cls = Class::get("NSAlert").unwrap();
//        let alert: *mut Object = msg_send![cls, alloc];
//        let _ = msg_send![alert, init];
//        let _ = msg_send![alert, setMessageText: ns_text];
//        let _ = msg_send![alert, addButtonWithTitle: button];
//        let _ = msg_send![alert, runModal];
//        let _ = msg_send![ns_text, release];
//        let _ = msg_send![button, release];
//        let _ = msg_send![alert, release];
//    }
//}

pub fn resource_dir() -> Option<String> {
    unsafe {
        let cls = Class::get("NSBundle").unwrap();
        let bundle: *mut Object = msg_send![cls, mainBundle];
        let path: *mut Object = msg_send![bundle, resourcePath];
        let cstr: *const libc::c_char = msg_send![path, UTF8String];
        if cstr != ptr::null() {
            let rstr = CStr::from_ptr(cstr).to_string_lossy().into_owned();
            return Some(rstr);
        }
        None
    }
}

pub fn bundled_resource_path(name: &str, extension: &str) -> Option<String> {
    unsafe {
        let cls = Class::get("NSBundle").unwrap();
        let bundle: *mut Object = msg_send![cls, mainBundle];
        let res = NSString::alloc(nil).init_str(name);
        let ext = NSString::alloc(nil).init_str(extension);
        let ini: *mut Object = msg_send![bundle, pathForResource:res ofType:ext];
        let _ = msg_send![res, release];
        let _ = msg_send![ext, release];
        let cstr: *const libc::c_char = msg_send![ini, UTF8String];
        if cstr != ptr::null() {
            let rstr = CStr::from_ptr(cstr).to_string_lossy().into_owned();
            return Some(rstr);
        }
        None
    }
}
<commit_msg>Use new icons on OS X<commit_after>pub mod rustnsobject;

extern crate objc;
extern crate objc_foundation;
extern crate cocoa;
extern crate libc;

pub use ::TStatusBar;
pub use ::NSCallback;

use objc::runtime::Class;

use self::cocoa::base::{nil, YES};
use self::cocoa::appkit::NSStatusBar;
use self::cocoa::foundation::{NSAutoreleasePool,NSString};
use self::cocoa::appkit::{NSApp,
                          NSApplication,
                          NSApplicationActivationPolicyAccessory,
                          NSMenu,
                          NSMenuItem,
                          NSImage,
                          NSVariableStatusItemLength,
                          NSStatusItem,
                          NSButton};

use self::rustnsobject::{NSObj, NSObjTrait, NSObjCallbackTrait};

use std::sync::mpsc::Sender;

use std::ptr;
use std::cell::Cell;
use std::ffi::CStr;
use std::thread::sleep;
use std::time::Duration;

extern crate objc_id;
use self::objc_id::Id;

pub type Object = objc::runtime::Object;

pub struct OSXStatusBar {
    object: NSObj,
    app: *mut objc::runtime::Object,
    status_bar_item: *mut objc::runtime::Object,
    menu_bar: *mut objc::runtime::Object,

    // Run loop state
    // Keeping these in persistent state instead of recalculating saves quite a
    // bit of CPU during idle.
    pool: Cell<*mut objc::runtime::Object>,
    run_count: Cell<u64>,
    run_mode: *mut objc::runtime::Object,
    run_date: *mut objc::runtime::Object,
}

impl TStatusBar for OSXStatusBar {
    type S = OSXStatusBar;
    fn new(tx: Sender<String>) -> OSXStatusBar {
        let mut bar;
        unsafe {
            let app = NSApp();
            let status_bar = NSStatusBar::systemStatusBar(nil);
            let date_cls = Class::get("NSDate").unwrap();
            bar = OSXStatusBar {
                app: app,
                status_bar_item: status_bar.statusItemWithLength_(NSVariableStatusItemLength),
                menu_bar: NSMenu::new(nil),
                object: NSObj::alloc(tx).setup(),
                pool: Cell::new(nil),
                run_count: Cell::new(0),
                run_mode: NSString::alloc(nil).init_str("kCFRunLoopDefaultMode"),
                run_date: msg_send![date_cls, distantPast],
            };
            // Don't become foreground app on launch
            bar.app.setActivationPolicy_(NSApplicationActivationPolicyAccessory);

            // Default mode for menu bar items: blue highlight when selected
            msg_send![bar.status_bar_item, setHighlightMode:YES];

            // Set title.  Only displayed if image fails to load.
            let title = NSString::alloc(nil).init_str("connectr");
            NSButton::setTitle_(bar.status_bar_item, title);
            let _ = msg_send![title, release];

            // Look for icon in OS X bundle if there is one, otherwise current dir.
            // See docs/icons.md for explanation of icon files.
            // TODO: Use the full list of search paths.
            let icon_name = "connectr_80px_300dpi";
            let img_path = match bundled_resource_path(icon_name, "png") {
                Some(path) => path,
                None => format!("{}.png", icon_name),
            };

            // Set the status bar image.  Switching on setTemplate switches it to
            // using OS X system-style icons that are masked to all white.  I
            // prefer color, but that should maybe be configurable.
            let img = NSString::alloc(nil).init_str(&img_path);
            let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
            //let _ = msg_send![icon, setTemplate: YES]; // enable to make icon white
            bar.status_bar_item.button().setImage_(icon);
            let _ = msg_send![img, release];
            let _ = msg_send![icon, release];

            // Add the same image again as an alternate image.  I'm not sure how the
            // blending is performed, but it behaves differently and better if an
            // alt image is specified.  Without an alt image, the icon darkens too
            // much in 'dark mode' when selected, and is too light in 'light mode'.
            let img = NSString::alloc(nil).init_str(&img_path);
            let icon = NSImage::alloc(nil).initWithContentsOfFile_(img);
            let _ = msg_send![bar.status_bar_item.button(), setAlternateImage: icon];
            let _ = msg_send![img, release];
            let _ = msg_send![icon, release];

            bar.status_bar_item.setMenu_(bar.menu_bar);
            bar.object.cb_fn = Some(Box::new(
                move |s, sender| {
                    let cb = s.get_value(sender);
                    cb(sender, &s.tx);
                }
            ));
            let _: () = msg_send![app, finishLaunching];
        }
        bar
    }
    fn can_redraw(&mut self) -> bool {
        true
    }
    fn clear_items(&mut self) {
        unsafe {
            let old_menu = self.menu_bar;
            self.menu_bar = NSMenu::new(nil);
            self.status_bar_item.setMenu_(self.menu_bar);
            let _ = msg_send![old_menu, removeAllItems];
            let _ = msg_send![old_menu, release];
        }
    }
    fn set_tooltip(&mut self, text: &str) {
        unsafe {
            let img = NSString::alloc(nil).init_str(text);
            let _ = msg_send![self.status_bar_item.button(), setToolTip: img];
            let _ = msg_send![img, release];
        }
    }
    fn add_label(&mut self, label: &str) {
        unsafe {
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
            let _ = msg_send![txt, release];
            let _ = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _ = msg_send![app_menu_item, release];
        }
    }
    fn add_quit(&mut self, label: &str) {
        unsafe {
            let txt = NSString::alloc(nil).init_str(label);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, sel!(terminate:), quit_key);
            let _ = msg_send![txt, release];
            let _ = msg_send![quit_key, release];
            self.menu_bar.addItem_(app_menu_item);
            let _ = msg_send![app_menu_item, release];
        }
    }
    fn add_separator(&mut self) {
        unsafe {
            let cls = Class::get("NSMenuItem").unwrap();
            let sep: *mut Object = msg_send![cls, separatorItem];
            self.menu_bar.addItem_(sep);
        }
    }
    fn add_item(&mut self, item: &str, callback: NSCallback, selected: bool) -> *mut Object {
        unsafe {
            let txt = NSString::alloc(nil).init_str(item);
            let quit_key = NSString::alloc(nil).init_str("");
            let app_menu_item = NSMenuItem::alloc(nil)
                .initWithTitle_action_keyEquivalent_(txt, self.object.selector(), quit_key);
            let _ = msg_send![txt, release];
            let _ = msg_send![quit_key, release];
            self.object.add_callback(app_menu_item, callback);
            let objc = self.object.take_objc();
            let _: () = msg_send![app_menu_item, setTarget: objc];
            if selected {
                let _: () = msg_send![app_menu_item, setState: 1];
            }
            let item: *mut Object = app_menu_item;
            self.menu_bar.addItem_(app_menu_item);
            let _ = msg_send![app_menu_item, release];
            item
        }
    }
    fn update_item(&mut self, item: *mut Object, label: &str) {
        unsafe {
            let ns_label = NSString::alloc(nil).init_str(label);
            let _: () = msg_send![item, setTitle: ns_label];
            let _ = msg_send![ns_label, release];
        }
    }
    fn sel_item(&mut self, sender: u64) {
        let target: *mut Object = sender as *mut Object;
        unsafe {
            let _: () = msg_send![target, setState: 1];
        }
    }
    fn unsel_item(&mut self, sender: u64) {
        let target: *mut Object = sender as *mut Object;
        unsafe {
            let _: () = msg_send![target, setState: 0];
        }
    }
    fn run(&mut self, block: bool) {
        loop {
            unsafe {
                let run_count = self.run_count.get();
                // Create a new release pool every once in a while, draining the old one
                if run_count % 100 == 0 {
                    let old_pool = self.pool.get();
                    if run_count != 0 {
                        let _ = msg_send![old_pool, drain];
                    }
                    self.pool.set(NSAutoreleasePool::new(nil));
                }
                let mode = self.run_mode;
                let event: Id<Object> = msg_send![self.app, nextEventMatchingMask: -1
                                                  untilDate: self.run_date inMode:mode dequeue: YES];
                let _ = msg_send![self.app, sendEvent: event];
                let _ = msg_send![self.app, updateWindows];
                self.run_count.set(run_count + 1);
            }
            if !block { break; }
            sleep(Duration::from_millis(50));
        }
    }
}

//pub fn osx_alert(text: &str) {
//    unsafe {
//        let ns_text = NSString::alloc(nil).init_str(text);
//        let button = NSString::alloc(nil).init_str("ok");
//        let cls = Class::get("NSAlert").unwrap();
//        let alert: *mut Object = msg_send![cls, alloc];
//        let _ = msg_send![alert, init];
//        let _ = msg_send![alert, setMessageText: ns_text];
//        let _ = msg_send![alert, addButtonWithTitle: button];
//        let _ = msg_send![alert, runModal];
//        let _ = msg_send![ns_text, release];
//        let _ = msg_send![button, release];
//        let _ = msg_send![alert, release];
//    }
//}

pub fn resource_dir() -> Option<String> {
    unsafe {
        let cls = Class::get("NSBundle").unwrap();
        let bundle: *mut Object = msg_send![cls, mainBundle];
        let path: *mut Object = msg_send![bundle, resourcePath];
        let cstr: *const libc::c_char = msg_send![path, UTF8String];
        if cstr != ptr::null() {
            let rstr = CStr::from_ptr(cstr).to_string_lossy().into_owned();
            return Some(rstr);
        }
        None
    }
}

pub fn bundled_resource_path(name: &str, extension: &str) -> Option<String> {
    unsafe {
        let cls = Class::get("NSBundle").unwrap();
        let bundle: *mut Object = msg_send![cls, mainBundle];
        let res = NSString::alloc(nil).init_str(name);
        let ext = NSString::alloc(nil).init_str(extension);
        let ini: *mut Object = msg_send![bundle, pathForResource:res ofType:ext];
        let _ = msg_send![res, release];
        let _ = msg_send![ext, release];
        let cstr: *const libc::c_char = msg_send![ini, UTF8String];
        if cstr != ptr::null() {
            let rstr = CStr::from_ptr(cstr).to_string_lossy().into_owned();
            return Some(rstr);
        }
        None
    }
}
<|endoftext|>


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

// The outlines relation `T: 'a` or `'a: 'b`. This code frequently
// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
// RFC for reference.

use middle::infer::InferCtxt;
use middle::ty::{self, RegionEscape, Ty};

#[derive(Debug)]
pub enum Component<'tcx> {
    Region(ty::Region),
    Param(ty::ParamTy),
    UnresolvedInferenceVariable(ty::InferTy),

    // Projections like `T::Foo` are tricky because a constraint like
    // `T::Foo: 'a` can be satisfied in so many ways. There may be a
    // where-clause that says `T::Foo: 'a`, or the defining trait may
    // include a bound like `type Foo: 'static`, or -- in the most
    // conservative way -- we can prove that `T: 'a` (more generally,
    // that all components in the projection outlive `'a`). This code
    // is not in a position to judge which is the best technique, so
    // we just product the projection as a component and leave it to
    // the consumer to decide (but see `EscapingProjection` below).
    Projection(ty::ProjectionTy<'tcx>),

    // In the case where a projection has escaping regions -- meaning
    // regions bound within the type itself -- we always use
    // the most conservative rule, which requires that all components
    // outlive the bound. So for example if we had a type like this:
    //
    //     for<'a> Trait1<  <T as Trait2<'a,'b>>::Foo  >
    //                      ~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // then the inner projection (underlined) has an escaping region
    // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
    // outlives `'b: 'c`, and we don't consider whether the trait
    // declares that `Foo: 'static` etc. Therefore, we just return the
    // free components of such a projection (in this case, `'b`).
    //
    // However, in the future, we may want to get smarter, and
    // actually return a "higher-ranked projection" here. Therefore,
    // we mark that these components are part of an escaping
    // projection, so that implied bounds code can avoid relying on
    // them. This gives us room to improve the regionck reasoning in
    // the future without breaking backwards compat.
    EscapingProjection(Vec<Component<'tcx>>),

    RFC1214(Vec<Component<'tcx>>),
}

/// Returns all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold.
pub fn components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                           ty0: Ty<'tcx>)
                           -> Vec<Component<'tcx>> {
    let mut components = vec![];
    compute_components(infcx, ty0, &mut components);
    debug!("outlives({:?}) = {:?}", ty0, components);
    components
}

fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                               ty: Ty<'tcx>,
                               out: &mut Vec<Component<'tcx>>) {
    // Descend through the types, looking for the various "base"
    // components and collecting them into `out`. This is not written
    // with `collect()` because of the need to sometimes skip subtrees
    // in the `subtys` iterator (e.g., when encountering a
    // projection).
    match ty.sty {
        ty::TyClosure(_, ref substs) => {
            // FIXME(#27086). We do not accumulate from substs, since they
            // don't represent reachable data. This means that, in
            // practice, some of the lifetime parameters might not
            // be in scope when the body runs, so long as there is
            // no reachable data with that lifetime. For better or
            // worse, this is consistent with fn types, however,
            // which can also encapsulate data in this fashion
            // (though it's somewhat harder, and typically
            // requires virtual dispatch).
            //
            // Note that changing this (in a naive way, at least)
            // causes regressions for what appears to be perfectly
            // reasonable code like this:
            //
            // ```
            // fn foo<'a>(p: &Data<'a>) {
            //    bar(|q: &mut Parser| q.read_addr())
            // }
            // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
            // }
            // ```
            //
            // Note that `p` (and `'a`) are not used in the
            // closure at all, but to meet the requirement that
            // the closure type `C: 'static` (so it can be coerced
            // to the object type), we get the requirement that
            // `'a: 'static` since `'a` appears in the closure
            // type `C`.
            //
            // A smarter fix might "prune" unused `func_substs` --
            // this would avoid breaking simple examples like
            // this, but would still break others (which might
            // indeed be invalid, depending on your POV). Pruning
            // would be a subtle process, since we have to see
            // what func/type parameters are used and unused,
            // taking into consideration UFCS and so forth.

            for &upvar_ty in &substs.upvar_tys {
                compute_components(infcx, upvar_ty, out);
            }
        }

        // Bare functions and traits are both binders. In the RFC,
        // this means we would add the bound regions to the "bound
        // regions list".  In our representation, no such list is
        // maintained explicitly, because bound regions themselves can
        // be readily identified. However, because the outlives
        // relation did not used to be applied to fn/trait-object
        // arguments, we due wrap the resulting components in an
        // RFC1214 wrapper so we can issue warnings.
        ty::TyBareFn(..) | ty::TyTrait(..) => {
            // OutlivesFunction, OutlivesObject, OutlivesFragment
            let subcomponents = capture_components(infcx, ty);
            out.push(Component::RFC1214(subcomponents));
        }

        // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
        // is implied by the environment is done in regionck.
        ty::TyParam(p) => {
            out.push(Component::Param(p));
        }

        // For projections, we prefer to generate an obligation like
        // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
        // regionck more ways to prove that it holds. However,
        // regionck is not (at least currently) prepared to deal with
        // higher-ranked regions that may appear in the
        // trait-ref. Therefore, if we see any higher-ranke regions,
        // we simply fallback to the most restrictive rule, which
        // requires that `Pi: 'a` for all `i`.
        ty::TyProjection(ref data) => {
            if !data.has_escaping_regions() {
                // best case: no escaping regions, so push the
                // projection and skip the subtree (thus generating no
                // constraints for Pi). This defers the choice between
                // the rules OutlivesProjectionEnv,
                // OutlivesProjectionTraitDef, and
                // OutlivesProjectionComponents to regionck.
                out.push(Component::Projection(*data));
            } else {
                // fallback case: hard code
                // OutlivesProjectionComponents.  Continue walking
                // through and constrain Pi.
                let subcomponents = capture_components(infcx, ty);
                out.push(Component::EscapingProjection(subcomponents));
            }
        }

        // If we encounter an inference variable, try to resolve it
        // and proceed with resolved version. If we cannot resolve it,
        // then record the unresolved variable as a component.
        ty::TyInfer(_) => {
            let ty = infcx.resolve_type_vars_if_possible(&ty);
            if let ty::TyInfer(infer_ty) = ty.sty {
                out.push(Component::UnresolvedInferenceVariable(infer_ty));
            } else {
                compute_components(infcx, ty, out);
            }
        }

        // Most types do not introduce any region binders, nor
        // involve any other subtle cases, and so the WF relation
        // simply constraints any regions referenced directly by
        // the type and then visits the types that are lexically
        // contained within. (The comments refer to relevant rules
        // from RFC1214.)
        ty::TyBool(..) |        // OutlivesScalar
        ty::TyChar(..) |        // OutlivesScalar
        ty::TyInt(..) |         // OutlivesScalar
        ty::TyUint(..) |        // OutlivesScalar
        ty::TyFloat(..) |       // OutlivesScalar
        ty::TyEnum(..) |        // OutlivesNominalType
        ty::TyStruct(..) |      // OutlivesNominalType
        ty::TyBox(..) |         // OutlivesNominalType (ish)
        ty::TyStr(..) |         // OutlivesScalar (ish)
        ty::TyArray(..) |       // ...
        ty::TySlice(..) |       // ...
        ty::TyRawPtr(..) |      // ...
        ty::TyRef(..) |         // OutlivesReference
        ty::TyTuple(..) |       // ...
        ty::TyError(..) => {
            push_region_constraints(out, ty.regions());
            for subty in ty.walk_shallow() {
                compute_components(infcx, subty, out);
            }
        }
    }
}

fn capture_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                               ty: Ty<'tcx>)
                               -> Vec<Component<'tcx>> {
    let mut temp = vec![];
    push_region_constraints(&mut temp, ty.regions());
    for subty in ty.walk_shallow() {
        compute_components(infcx, subty, &mut temp);
    }
    temp
}

fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region>) {
    for r in regions {
        if !r.is_bound() {
            out.push(Component::Region(r));
        }
    }
}
<commit_msg>outlives.rs: correct typo<commit_after>// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

// The outlines relation `T: 'a` or `'a: 'b`. This code frequently
// refers to rules defined in RFC 1214 (`OutlivesFooBar`), so see that
// RFC for reference.

use middle::infer::InferCtxt;
use middle::ty::{self, RegionEscape, Ty};

#[derive(Debug)]
pub enum Component<'tcx> {
    Region(ty::Region),
    Param(ty::ParamTy),
    UnresolvedInferenceVariable(ty::InferTy),

    // Projections like `T::Foo` are tricky because a constraint like
    // `T::Foo: 'a` can be satisfied in so many ways. There may be a
    // where-clause that says `T::Foo: 'a`, or the defining trait may
    // include a bound like `type Foo: 'static`, or -- in the most
    // conservative way -- we can prove that `T: 'a` (more generally,
    // that all components in the projection outlive `'a`). This code
    // is not in a position to judge which is the best technique, so
    // we just product the projection as a component and leave it to
    // the consumer to decide (but see `EscapingProjection` below).
    Projection(ty::ProjectionTy<'tcx>),

    // In the case where a projection has escaping regions -- meaning
    // regions bound within the type itself -- we always use
    // the most conservative rule, which requires that all components
    // outlive the bound. So for example if we had a type like this:
    //
    //     for<'a> Trait1<  <T as Trait2<'a,'b>>::Foo  >
    //                      ~~~~~~~~~~~~~~~~~~~~~~~~~
    //
    // then the inner projection (underlined) has an escaping region
    // `'a`. We consider that outer trait `'c` to meet a bound if `'b`
    // outlives `'b: 'c`, and we don't consider whether the trait
    // declares that `Foo: 'static` etc. Therefore, we just return the
    // free components of such a projection (in this case, `'b`).
    //
    // However, in the future, we may want to get smarter, and
    // actually return a "higher-ranked projection" here. Therefore,
    // we mark that these components are part of an escaping
    // projection, so that implied bounds code can avoid relying on
    // them. This gives us room to improve the regionck reasoning in
    // the future without breaking backwards compat.
    EscapingProjection(Vec<Component<'tcx>>),

    RFC1214(Vec<Component<'tcx>>),
}

/// Returns all the things that must outlive `'a` for the condition
/// `ty0: 'a` to hold.
pub fn components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                           ty0: Ty<'tcx>)
                           -> Vec<Component<'tcx>> {
    let mut components = vec![];
    compute_components(infcx, ty0, &mut components);
    debug!("outlives({:?}) = {:?}", ty0, components);
    components
}

fn compute_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                               ty: Ty<'tcx>,
                               out: &mut Vec<Component<'tcx>>) {
    // Descend through the types, looking for the various "base"
    // components and collecting them into `out`. This is not written
    // with `collect()` because of the need to sometimes skip subtrees
    // in the `subtys` iterator (e.g., when encountering a
    // projection).
    match ty.sty {
        ty::TyClosure(_, ref substs) => {
            // FIXME(#27086). We do not accumulate from substs, since they
            // don't represent reachable data. This means that, in
            // practice, some of the lifetime parameters might not
            // be in scope when the body runs, so long as there is
            // no reachable data with that lifetime. For better or
            // worse, this is consistent with fn types, however,
            // which can also encapsulate data in this fashion
            // (though it's somewhat harder, and typically
            // requires virtual dispatch).
            //
            // Note that changing this (in a naive way, at least)
            // causes regressions for what appears to be perfectly
            // reasonable code like this:
            //
            // ```
            // fn foo<'a>(p: &Data<'a>) {
            //    bar(|q: &mut Parser| q.read_addr())
            // }
            // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
            // }
            // ```
            //
            // Note that `p` (and `'a`) are not used in the
            // closure at all, but to meet the requirement that
            // the closure type `C: 'static` (so it can be coerced
            // to the object type), we get the requirement that
            // `'a: 'static` since `'a` appears in the closure
            // type `C`.
            //
            // A smarter fix might "prune" unused `func_substs` --
            // this would avoid breaking simple examples like
            // this, but would still break others (which might
            // indeed be invalid, depending on your POV). Pruning
            // would be a subtle process, since we have to see
            // what func/type parameters are used and unused,
            // taking into consideration UFCS and so forth.

            for &upvar_ty in &substs.upvar_tys {
                compute_components(infcx, upvar_ty, out);
            }
        }

        // Bare functions and traits are both binders. In the RFC,
        // this means we would add the bound regions to the "bound
        // regions list".  In our representation, no such list is
        // maintained explicitly, because bound regions themselves can
        // be readily identified. However, because the outlives
        // relation did not used to be applied to fn/trait-object
        // arguments, we wrap the resulting components in an RFC1214
        // wrapper so we can issue warnings.
        ty::TyBareFn(..) | ty::TyTrait(..) => {
            // OutlivesFunction, OutlivesObject, OutlivesFragment
            let subcomponents = capture_components(infcx, ty);
            out.push(Component::RFC1214(subcomponents));
        }

        // OutlivesTypeParameterEnv -- the actual checking that `X:'a`
        // is implied by the environment is done in regionck.
        ty::TyParam(p) => {
            out.push(Component::Param(p));
        }

        // For projections, we prefer to generate an obligation like
        // `<P0 as Trait<P1...Pn>>::Foo: 'a`, because this gives the
        // regionck more ways to prove that it holds. However,
        // regionck is not (at least currently) prepared to deal with
        // higher-ranked regions that may appear in the
        // trait-ref. Therefore, if we see any higher-ranke regions,
        // we simply fallback to the most restrictive rule, which
        // requires that `Pi: 'a` for all `i`.
        ty::TyProjection(ref data) => {
            if !data.has_escaping_regions() {
                // best case: no escaping regions, so push the
                // projection and skip the subtree (thus generating no
                // constraints for Pi). This defers the choice between
                // the rules OutlivesProjectionEnv,
                // OutlivesProjectionTraitDef, and
                // OutlivesProjectionComponents to regionck.
                out.push(Component::Projection(*data));
            } else {
                // fallback case: hard code
                // OutlivesProjectionComponents.  Continue walking
                // through and constrain Pi.
                let subcomponents = capture_components(infcx, ty);
                out.push(Component::EscapingProjection(subcomponents));
            }
        }

        // If we encounter an inference variable, try to resolve it
        // and proceed with resolved version. If we cannot resolve it,
        // then record the unresolved variable as a component.
        ty::TyInfer(_) => {
            let ty = infcx.resolve_type_vars_if_possible(&ty);
            if let ty::TyInfer(infer_ty) = ty.sty {
                out.push(Component::UnresolvedInferenceVariable(infer_ty));
            } else {
                compute_components(infcx, ty, out);
            }
        }

        // Most types do not introduce any region binders, nor
        // involve any other subtle cases, and so the WF relation
        // simply constraints any regions referenced directly by
        // the type and then visits the types that are lexically
        // contained within. (The comments refer to relevant rules
        // from RFC1214.)
        ty::TyBool(..) |        // OutlivesScalar
        ty::TyChar(..) |        // OutlivesScalar
        ty::TyInt(..) |         // OutlivesScalar
        ty::TyUint(..) |        // OutlivesScalar
        ty::TyFloat(..) |       // OutlivesScalar
        ty::TyEnum(..) |        // OutlivesNominalType
        ty::TyStruct(..) |      // OutlivesNominalType
        ty::TyBox(..) |         // OutlivesNominalType (ish)
        ty::TyStr(..) |         // OutlivesScalar (ish)
        ty::TyArray(..) |       // ...
        ty::TySlice(..) |       // ...
        ty::TyRawPtr(..) |      // ...
        ty::TyRef(..) |         // OutlivesReference
        ty::TyTuple(..) |       // ...
        ty::TyError(..) => {
            push_region_constraints(out, ty.regions());
            for subty in ty.walk_shallow() {
                compute_components(infcx, subty, out);
            }
        }
    }
}

fn capture_components<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
                               ty: Ty<'tcx>)
                               -> Vec<Component<'tcx>> {
    let mut temp = vec![];
    push_region_constraints(&mut temp, ty.regions());
    for subty in ty.walk_shallow() {
        compute_components(infcx, subty, &mut temp);
    }
    temp
}

fn push_region_constraints<'tcx>(out: &mut Vec<Component<'tcx>>, regions: Vec<ty::Region>) {
    for r in regions {
        if !r.is_bound() {
            out.push(Component::Region(r));
        }
    }
}
<|endoftext|>


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

use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::ty::TyCtxt;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use std::path::{PathBuf, Path};

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 40;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          disambiguator: &Display,
                          src: MirSource,
                          mir: &Mir<'tcx>) {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return,
        Some(ref filters) => filters,
    };
    let node_id = src.item_id();
    let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
    let is_matched =
        filters.split("&")
               .any(|filter| {
                   filter == "all" ||
                       pass_name.contains(filter) ||
                       node_path.contains(filter)
               });
    if !is_matched {
        return;
    }

    let promotion_id = match src {
        MirSource::Promoted(_, id) => format!("-{:?}", id),
        _ => String::new()
    };

    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let file_name = format!("rustc.node{}{}.{}.{}.mir",
                            node_id, promotion_id, pass_name, disambiguator);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR for `{}`", node_path)?;
        writeln!(file, "// node_id = {}", node_id)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "// disambiguator = {}", disambiguator)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, src, mir, &mut file)?;
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                         iter: I,
                                         w: &mut Write)
                                         -> io::Result<()>
    where I: Iterator<Item=DefId>, 'tcx: 'a
{
    let mut first = true;
    for def_id in iter.filter(DefId::is_local) {
        let mir = &tcx.item_mir(def_id);

        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let id = tcx.hir.as_local_node_id(def_id).unwrap();
        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w)?;

        for (i, mir) in mir.promoted.iter_enumerated() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?;
        }
    }
    Ok(())
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write)
                              -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        write_basic_block(tcx, block, mir, w)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write)
                     -> io::Result<()> {
    let data = &mir[block];

    // Basic block label at the top.
    writeln!(w, "{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.source_info))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().source_info))?;

    writeln!(w, "{}}}", INDENT)
}

fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

/// Prints user-defined variables in a scope tree.
///
/// Returns the total number of variables printed.
fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    scope_tree: &FxHashMap<VisibilityScope, Vec<VisibilityScope>>,
                    w: &mut Write,
                    parent: VisibilityScope,
                    depth: usize)
                    -> io::Result<()> {
    let indent = depth * INDENT.len();

    let children = match scope_tree.get(&parent) {
        Some(childs) => childs,
        None => return Ok(()),
    };

    for &child in children {
        let data = &mir.visibility_scopes[child];
        assert_eq!(data.parent_scope, Some(parent));
        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;

        // User variable types (including the user's name in a comment).
        for local in mir.vars_iter() {
            let var = &mir.local_decls[local];
            let (name, source_info) = if var.source_info.unwrap().scope == child {
                (var.name.unwrap(), var.source_info.unwrap())
            } else {
                // Not a variable or not declared in this scope.
                continue;
            };

            let mut_str = if var.mutability == Mutability::Mut {
                "mut "
            } else {
                ""
            };

            let indent = indent + INDENT.len();
            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
                                       INDENT,
                                       indent,
                                       mut_str,
                                       local,
                                       var.ty);
            writeln!(w, "{0:1$} // \"{2}\" in {3}",
                     indented_var,
                     ALIGN,
                     name,
                     comment(tcx, source_info))?;
        }

        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;

        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    write_mir_sig(tcx, src, mir, w)?;
    writeln!(w, " {{")?;

    // construct a scope tree and write it out
    let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap();
    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
        if let Some(parent) = scope_data.parent_scope {
            scope_tree.entry(parent)
                      .or_insert(vec![])
                      .push(VisibilityScope::new(index));
        } else {
            // Only the argument scope has no parent, because it's the root.
            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
        }
    }

    // Print return pointer
    let indented_retptr = format!("{}let mut {:?}: {};",
                                  INDENT,
                                  RETURN_POINTER,
                                  mir.return_ty);
    writeln!(w, "{0:1$} // return pointer",
             indented_retptr,
             ALIGN)?;

    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;

    write_temp_decls(mir, w)?;

    // Add an empty line before the first block is printed.
    writeln!(w, "")?;

    Ok(())
}

fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                 -> io::Result<()>
{
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
    }

    write!(w, " {}", tcx.node_path_str(src.item_id()))?;

    if let MirSource::Fn(_) = src {
        write!(w, "(")?;

        // fn argument types.
        for (i, arg) in mir.args_iter().enumerate() {
            if i != 0 {
                write!(w, ", ")?;
            }
            write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
        }

        write!(w, ") -> {}", mir.return_ty)
    } else {
        assert_eq!(mir.arg_count, 0);
        write!(w, ": {} =", mir.return_ty)
    }
}

fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
    // Compiler-introduced temporary types.
    for temp in mir.temps_iter() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?;
    }

    Ok(())
}
<commit_msg>Add warning about volatility of MIR output<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::mir::*;
use rustc::mir::transform::MirSource;
use rustc::ty::TyCtxt;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::indexed_vec::{Idx};
use std::fmt::Display;
use std::fs;
use std::io::{self, Write};
use std::path::{PathBuf, Path};

const INDENT: &'static str = "    ";
/// Alignment for lining up comments following MIR statements
const ALIGN: usize = 40;

/// If the session is properly configured, dumps a human-readable
/// representation of the mir into:
///
/// ```text
/// rustc.node<node_id>.<pass_name>.<disambiguator>
/// ```
///
/// Output from this function is controlled by passing `-Z dump-mir=<filter>`,
/// where `<filter>` takes the following forms:
///
/// - `all` -- dump MIR for all fns, all passes, all everything
/// - `substring1&substring2,...` -- `&`-separated list of substrings
///   that can appear in the pass-name or the `item_path_str` for the given
///   node-id. If any one of the substrings match, the data is dumped out.
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          pass_name: &str,
                          disambiguator: &Display,
                          src: MirSource,
                          mir: &Mir<'tcx>) {
    let filters = match tcx.sess.opts.debugging_opts.dump_mir {
        None => return,
        Some(ref filters) => filters,
    };
    let node_id = src.item_id();
    let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
    let is_matched =
        filters.split("&")
               .any(|filter| {
                   filter == "all" ||
                       pass_name.contains(filter) ||
                       node_path.contains(filter)
               });
    if !is_matched {
        return;
    }

    let promotion_id = match src {
        MirSource::Promoted(_, id) => format!("-{:?}", id),
        _ => String::new()
    };

    let mut file_path = PathBuf::new();
    if let Some(ref file_dir) = tcx.sess.opts.debugging_opts.dump_mir_dir {
        let p = Path::new(file_dir);
        file_path.push(p);
    };
    let file_name = format!("rustc.node{}{}.{}.{}.mir",
                            node_id, promotion_id, pass_name, disambiguator);
    file_path.push(&file_name);
    let _ = fs::File::create(&file_path).and_then(|mut file| {
        writeln!(file, "// MIR for `{}`", node_path)?;
        writeln!(file, "// node_id = {}", node_id)?;
        writeln!(file, "// pass_name = {}", pass_name)?;
        writeln!(file, "// disambiguator = {}", disambiguator)?;
        writeln!(file, "")?;
        write_mir_fn(tcx, src, mir, &mut file)?;
        Ok(())
    });
}

/// Write out a human-readable textual representation for the given MIR.
pub fn write_mir_pretty<'a, 'b, 'tcx, I>(tcx: TyCtxt<'b, 'tcx, 'tcx>,
                                         iter: I,
                                         w: &mut Write)
                                         -> io::Result<()>
    where I: Iterator<Item=DefId>, 'tcx: 'a
{
    writeln!(w, "// WARNING: This output format is intended for human consumers only")?;
    writeln!(w, "// and is subject to change without notice. Knock yourself out.")?;

    let mut first = true;
    for def_id in iter.filter(DefId::is_local) {
        let mir = &tcx.item_mir(def_id);

        if first {
            first = false;
        } else {
            // Put empty lines between all items
            writeln!(w, "")?;
        }

        let id = tcx.hir.as_local_node_id(def_id).unwrap();
        let src = MirSource::from_node(tcx, id);
        write_mir_fn(tcx, src, mir, w)?;

        for (i, mir) in mir.promoted.iter_enumerated() {
            writeln!(w, "")?;
            write_mir_fn(tcx, MirSource::Promoted(id, i), mir, w)?;
        }
    }
    Ok(())
}

pub fn write_mir_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                              src: MirSource,
                              mir: &Mir<'tcx>,
                              w: &mut Write)
                              -> io::Result<()> {
    write_mir_intro(tcx, src, mir, w)?;
    for block in mir.basic_blocks().indices() {
        write_basic_block(tcx, block, mir, w)?;
        if block.index() + 1 != mir.basic_blocks().len() {
            writeln!(w, "")?;
        }
    }

    writeln!(w, "}}")?;
    Ok(())
}

/// Write out a human-readable textual representation for the given basic block.
fn write_basic_block(tcx: TyCtxt,
                     block: BasicBlock,
                     mir: &Mir,
                     w: &mut Write)
                     -> io::Result<()> {
    let data = &mir[block];

    // Basic block label at the top.
    writeln!(w, "{}{:?}: {{", INDENT, block)?;

    // List of statements in the middle.
    let mut current_location = Location { block: block, statement_index: 0 };
    for statement in &data.statements {
        let indented_mir = format!("{0}{0}{1:?};", INDENT, statement);
        writeln!(w, "{0:1$} // {2}",
                 indented_mir,
                 ALIGN,
                 comment(tcx, statement.source_info))?;

        current_location.statement_index += 1;
    }

    // Terminator at the bottom.
    let indented_terminator = format!("{0}{0}{1:?};", INDENT, data.terminator().kind);
    writeln!(w, "{0:1$} // {2}",
             indented_terminator,
             ALIGN,
             comment(tcx, data.terminator().source_info))?;

    writeln!(w, "{}}}", INDENT)
}

fn comment(tcx: TyCtxt, SourceInfo { span, scope }: SourceInfo) -> String {
    format!("scope {} at {}", scope.index(), tcx.sess.codemap().span_to_string(span))
}

/// Prints user-defined variables in a scope tree.
///
/// Returns the total number of variables printed.
fn write_scope_tree(tcx: TyCtxt,
                    mir: &Mir,
                    scope_tree: &FxHashMap<VisibilityScope, Vec<VisibilityScope>>,
                    w: &mut Write,
                    parent: VisibilityScope,
                    depth: usize)
                    -> io::Result<()> {
    let indent = depth * INDENT.len();

    let children = match scope_tree.get(&parent) {
        Some(childs) => childs,
        None => return Ok(()),
    };

    for &child in children {
        let data = &mir.visibility_scopes[child];
        assert_eq!(data.parent_scope, Some(parent));
        writeln!(w, "{0:1$}scope {2} {{", "", indent, child.index())?;

        // User variable types (including the user's name in a comment).
        for local in mir.vars_iter() {
            let var = &mir.local_decls[local];
            let (name, source_info) = if var.source_info.unwrap().scope == child {
                (var.name.unwrap(), var.source_info.unwrap())
            } else {
                // Not a variable or not declared in this scope.
                continue;
            };

            let mut_str = if var.mutability == Mutability::Mut {
                "mut "
            } else {
                ""
            };

            let indent = indent + INDENT.len();
            let indented_var = format!("{0:1$}let {2}{3:?}: {4};",
                                       INDENT,
                                       indent,
                                       mut_str,
                                       local,
                                       var.ty);
            writeln!(w, "{0:1$} // \"{2}\" in {3}",
                     indented_var,
                     ALIGN,
                     name,
                     comment(tcx, source_info))?;
        }

        write_scope_tree(tcx, mir, scope_tree, w, child, depth + 1)?;

        writeln!(w, "{0:1$}}}", "", depth * INDENT.len())?;
    }

    Ok(())
}

/// Write out a human-readable textual representation of the MIR's `fn` type and the types of its
/// local variables (both user-defined bindings and compiler temporaries).
fn write_mir_intro<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                             src: MirSource,
                             mir: &Mir,
                             w: &mut Write)
                             -> io::Result<()> {
    write_mir_sig(tcx, src, mir, w)?;
    writeln!(w, " {{")?;

    // construct a scope tree and write it out
    let mut scope_tree: FxHashMap<VisibilityScope, Vec<VisibilityScope>> = FxHashMap();
    for (index, scope_data) in mir.visibility_scopes.iter().enumerate() {
        if let Some(parent) = scope_data.parent_scope {
            scope_tree.entry(parent)
                      .or_insert(vec![])
                      .push(VisibilityScope::new(index));
        } else {
            // Only the argument scope has no parent, because it's the root.
            assert_eq!(index, ARGUMENT_VISIBILITY_SCOPE.index());
        }
    }

    // Print return pointer
    let indented_retptr = format!("{}let mut {:?}: {};",
                                  INDENT,
                                  RETURN_POINTER,
                                  mir.return_ty);
    writeln!(w, "{0:1$} // return pointer",
             indented_retptr,
             ALIGN)?;

    write_scope_tree(tcx, mir, &scope_tree, w, ARGUMENT_VISIBILITY_SCOPE, 1)?;

    write_temp_decls(mir, w)?;

    // Add an empty line before the first block is printed.
    writeln!(w, "")?;

    Ok(())
}

fn write_mir_sig(tcx: TyCtxt, src: MirSource, mir: &Mir, w: &mut Write)
                 -> io::Result<()>
{
    match src {
        MirSource::Fn(_) => write!(w, "fn")?,
        MirSource::Const(_) => write!(w, "const")?,
        MirSource::Static(_, hir::MutImmutable) => write!(w, "static")?,
        MirSource::Static(_, hir::MutMutable) => write!(w, "static mut")?,
        MirSource::Promoted(_, i) => write!(w, "{:?} in", i)?
    }

    write!(w, " {}", tcx.node_path_str(src.item_id()))?;

    if let MirSource::Fn(_) = src {
        write!(w, "(")?;

        // fn argument types.
        for (i, arg) in mir.args_iter().enumerate() {
            if i != 0 {
                write!(w, ", ")?;
            }
            write!(w, "{:?}: {}", Lvalue::Local(arg), mir.local_decls[arg].ty)?;
        }

        write!(w, ") -> {}", mir.return_ty)
    } else {
        assert_eq!(mir.arg_count, 0);
        write!(w, ": {} =", mir.return_ty)
    }
}

fn write_temp_decls(mir: &Mir, w: &mut Write) -> io::Result<()> {
    // Compiler-introduced temporary types.
    for temp in mir.temps_iter() {
        writeln!(w, "{}let mut {:?}: {};", INDENT, temp, mir.local_decls[temp].ty)?;
    }

    Ok(())
}
<|endoftext|>


<commit_before>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// Calculates the offset of the specified field from the start of the struct.
/// This macro supports arbitrary amount of subscripts and recursive member-accesses.
///
/// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]`
///
/// ## Examples - Simple
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C, packed)]
/// struct Foo {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
/// fn main() {
///     assert_eq!(offset_of!(Foo, a), 0);
///     assert_eq!(offset_of!(Foo, b), 4);
///     assert_eq!(offset_of!(Foo, c[2]), 14);
/// }
/// ```
///
/// ## Examples - Advanced
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C, packed)]
/// struct UnnecessarilyComplicatedStruct {
///     member: [UnnecessarilyComplexStruct; 12]
/// }
///
/// #[repr(C, packed)]
/// struct UnnecessarilyComplexStruct {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
///
/// fn main() {
///     assert_eq!(offset_of!(UnnecessarilyComplicatedStruct, member[3].c[3]), 66);
/// }
/// ```
#[macro_export]
macro_rules! offset_of {
    ($father:ty, $($field:tt)+) => ({
        #[allow(unused_unsafe)]
        let root: $father = unsafe { $crate::mem::uninitialized() };

        let base = &root as *const _ as usize;

        // Future error: borrow of packed field requires unsafe function or block (error E0133)
        #[allow(unused_unsafe)]
        let member =  unsafe { &root.$($field)* as *const _ as usize };

        $crate::mem::forget(root);

        member - base
    });
}

#[cfg(test)]
mod tests {
    #[repr(C, packed)]
    struct Foo {
        a: u32,
        b: [u8; 4],
        c: i64,
    }

    #[test]
    fn offset_simple() {
        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 8);
    }

    #[test]
    fn offset_index() {
        assert_eq!(offset_of!(Foo, b[2]), 6);
    }

    #[test]
    #[should_panic]
    fn offset_index_out_of_bounds() {
        offset_of!(Foo, b[4]);
    }

    #[test]
    fn tuple_struct() {
        #[repr(C, packed)]
        struct Tup(i32, i32);

        assert_eq!(offset_of!(Tup, 0), 0);
    }
}
<commit_msg>Add #[allow(const_err)] on test offset_index_out_of_bounds<commit_after>// Copyright (c) 2017 Gilad Naaman
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

/// Calculates the offset of the specified field from the start of the struct.
/// This macro supports arbitrary amount of subscripts and recursive member-accesses.
///
/// *Note*: This macro may not make much sense when used on structs that are not `#[repr(C, packed)]`
///
/// ## Examples - Simple
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C, packed)]
/// struct Foo {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
/// fn main() {
///     assert_eq!(offset_of!(Foo, a), 0);
///     assert_eq!(offset_of!(Foo, b), 4);
///     assert_eq!(offset_of!(Foo, c[2]), 14);
/// }
/// ```
///
/// ## Examples - Advanced
/// ```
/// #[macro_use]
/// extern crate memoffset;
///
/// #[repr(C, packed)]
/// struct UnnecessarilyComplicatedStruct {
///     member: [UnnecessarilyComplexStruct; 12]
/// }
///
/// #[repr(C, packed)]
/// struct UnnecessarilyComplexStruct {
///     a: u32,
///     b: u64,
///     c: [u8; 5]
/// }
///
///
/// fn main() {
///     assert_eq!(offset_of!(UnnecessarilyComplicatedStruct, member[3].c[3]), 66);
/// }
/// ```
#[macro_export]
macro_rules! offset_of {
    ($father:ty, $($field:tt)+) => ({
        #[allow(unused_unsafe)]
        let root: $father = unsafe { $crate::mem::uninitialized() };

        let base = &root as *const _ as usize;

        // Future error: borrow of packed field requires unsafe function or block (error E0133)
        #[allow(unused_unsafe)]
        let member =  unsafe { &root.$($field)* as *const _ as usize };

        $crate::mem::forget(root);

        member - base
    });
}

#[cfg(test)]
mod tests {
    #[repr(C, packed)]
    struct Foo {
        a: u32,
        b: [u8; 4],
        c: i64,
    }

    #[test]
    fn offset_simple() {
        assert_eq!(offset_of!(Foo, a), 0);
        assert_eq!(offset_of!(Foo, b), 4);
        assert_eq!(offset_of!(Foo, c), 8);
    }

    #[test]
    fn offset_index() {
        assert_eq!(offset_of!(Foo, b[2]), 6);
    }

    #[test]
    #[should_panic]
    #[allow(const_err)]
    fn offset_index_out_of_bounds() {
        offset_of!(Foo, b[4]);
    }

    #[test]
    fn tuple_struct() {
        #[repr(C, packed)]
        struct Tup(i32, i32);

        assert_eq!(offset_of!(Tup, 0), 0);
    }
}
<|endoftext|>


<commit_before>use rand;
use rand::Rng;
use std::f32::consts::PI;
use rand::distributions::{Normal, IndependentSample};

#[allow(unused)]
fn modulo(a: i64, b: i64) -> usize {
    (((a % b) + b) % b) as usize
}

pub struct Heightmap<T> {
    pub heights: Vec<T>,
    pub width: u16,
    pub height: u16,
}

impl<T> Heightmap<T> {
    #[allow(unused)]
    pub fn new(heights: Vec<T>, width: u16, height: u16) -> Self {
        assert_eq!(heights.len(), (width as usize) * (height as usize));
        Heightmap {
            heights,
            width,
            height,
        }
    }

    pub fn get(&self, x: u16, y: u16) -> Option<T>
    where
        T: Clone,
    {
        if x >= self.width || y >= self.height {
            return None;
        }

        self.heights
            .get(x as usize + y as usize * self.width as usize)
            .cloned()
    }

    #[allow(unused)]
    pub fn get_wrapping(&self, x: i64, y: i64) -> T
    where
        T: Clone,
    {
        let x = modulo(x, self.width as i64);
        let y = modulo(y, self.height as i64);
        self.heights[x + y * self.width as usize].clone()
    }

    /// Produces a Vec of arrays where each array consists of the height at that point followed by
    /// the slope in the x and y directions respectively.
    pub fn as_height_and_slopes(&self, spacing: f32) -> Vec<[f32; 3]>
    where
        f32: From<T>,
        T: Clone,
    {
        let mut result = Vec::with_capacity(self.width as usize * self.height as usize);
        let scale_factor = 0.5 / spacing;

        for y in 0..self.height {
            for x in 0..self.width {
                let mx: f32 = if x > 0 {
                    self.get(x - 1, y).unwrap().into()
                } else {
                    self.get(self.width - 1, y).unwrap().into()
                };
                let px: f32 = if x < self.width - 1 {
                    self.get(x + 1, y).unwrap().into()
                } else {
                    self.get(0, y).unwrap().into()
                };
                let my: f32 = if y > 0 {
                    self.get(x, y - 1).unwrap().into()
                } else {
                    self.get(x, self.height - 1).unwrap().into()
                };
                let py: f32 = if y < self.height - 1 {
                    self.get(x, y + 1).unwrap().into()
                } else {
                    self.get(x, 0).unwrap().into()
                };
                let v = [
                    self.heights[x as usize + y as usize * self.width as usize]
                        .clone()
                        .into(),
                    (mx - px) * scale_factor,
                    (my - py) * scale_factor,
                ];
                result.push(v);
            }
        }
        result
    }
}

#[allow(dead_code)]
pub fn perlin_noise(grid_resolution: usize, grid_spacing: usize) -> Heightmap<f32> {
    fn dot(a: (f32, f32), b: (f32, f32)) -> f32 {
        a.0 * b.0 + a.1 * b.1
    }

    fn fade(t: f32) -> f32 {
        t * t * t * (6.0 * t * t - 15.0 * t + 10.0)
    }

    fn interp(a: f32, b: f32, t: f32) -> f32 {
        let t = fade(t);
        a * (1.0 - t) + b * t
    }

    let mut rng = rand::thread_rng();
    let gradients: Vec<(f32, f32)> = (0..(grid_resolution * grid_resolution))
        .map(|_| rng.gen_range(0.0, 2.0 * PI).sin_cos())
        .collect();

    let mut heights =
        vec![-9999.0; grid_resolution * grid_resolution * grid_spacing * grid_spacing];
    for y in 0..grid_resolution {
        for x in 0..grid_resolution {
            let xp = (x + 1) % grid_resolution;
            let yp = (y + 1) % grid_resolution;
            let a = gradients[x + y * grid_resolution];
            let b = gradients[x + yp * grid_resolution];
            let c = gradients[xp + y * grid_resolution];
            let d = gradients[xp + yp * grid_resolution];

            for k in 0..grid_spacing {
                for h in 0..grid_spacing {
                    let v = (
                        h as f32 / grid_spacing as f32,
                        k as f32 / grid_spacing as f32,
                    );

                    let ad = dot(a, v);
                    let bd = dot(b, (v.0, v.1 - 1.0));
                    let cd = dot(c, (v.0 - 1.0, v.1));
                    let dd = dot(d, (v.0 - 1.0, v.1 - 1.0));

                    let height = interp(interp(ad, bd, v.1), interp(cd, dd, v.1), v.0);

                    let i = (h + x * grid_spacing) +
                        (k + y * grid_spacing) * grid_resolution * grid_spacing;
                    heights[i] = height;
                }
            }
        }
    }

    Heightmap {
        heights,
        width: (grid_resolution * grid_spacing) as u16,
        height: (grid_resolution * grid_spacing) as u16,
    }
}

/// Evaluate wavelet noise on a grid with the given resolution and grid spacing. ///
/// The output heightmap will have a width and height of `grid_resolution` * `grid_spacing`. Values
/// will have a mean of approximately zero, and a variance of 1.
pub fn wavelet_noise(grid_resolution: usize, grid_spacing: usize) -> Heightmap<f32> {
    // See: https://graphics.pixar.com/library/WaveletNoise/paper.pdf

    fn modulo(x: i32, n: usize) -> usize {
        let m = x % n as i32;
        if m < 0 {
            (m + n as i32) as usize
        } else {
            m as usize
        }
    }
    fn downsample(from: &[f32], to: &mut [f32], n: usize, stride: usize) {
        const ARAD: i32 = 16;
        #[cfg_attr(rustfmt, rustfmt_skip)]
        const COEFFS: [f32; 32] = [
            0.000334,-0.001528, 0.000410, 0.003545,-0.000938,-0.008233, 0.002172, 0.019120,
            -0.005040,-0.044412, 0.011655, 0.103311,-0.025936,-0.243780, 0.033979, 0.655340,
            0.655340, 0.033979,-0.243780,-0.025936, 0.103311, 0.011655,-0.044412,-0.005040,
            0.019120, 0.002172,-0.008233,-0.000938, 0.003546, 0.000410,-0.001528, 0.000334
        ];
        for i in 0..(n / 2) {
            to[i * stride] = 0.0;
            let min_k = 2 * (i as i32) - ARAD;
            let max_k = 2 * (i as i32) + ARAD;
            for k in min_k..(max_k) {
                let index = (ARAD + k - 2 * i as i32) as usize;
                to[i * stride] += COEFFS[index] * from[modulo(k, n) * stride];
            }
        }
    }
    fn upsample(from: &[f32], to: &mut [f32], n: usize, stride: usize) {
        let p_coeffs = [0.25, 0.75, 0.75, 0.25];
        for i in 0..n {
            to[i * stride] = 0.0;
            for k in (i / 2)..(i / 2 + 2) {
                to[i * stride] += p_coeffs[2 + i - 2 * k] * from[(k % (n / 2)) * stride];
            }
        }
    }
    fn generate_noise_tile(n: usize) -> Vec<f32> {
        assert!(n % 2 == 0); // size must be even!

        let mut temp1 = vec![0.0; n * n];
        let mut temp2 = vec![0.0; n * n];
        let mut noise = Vec::new();

        // Step 1. Fill the tile with random numbers in the range -1 to 1.
        let normal = Normal::new(0.0, 1.0);
        for _ in 0..(n * n) {
            noise.push(normal.ind_sample(&mut rand::thread_rng()) as f32);
        }

        // Steps 2 and 3. Downsample and upsample the tile
        for iy in 0..n {
            // each x row
            let i = iy * n;
            downsample(&noise[i..], &mut temp1[i..], n, 1);
            upsample(&temp1[i..], &mut temp2[i..], n, 1);
        }
        for ix in 0..n {
            // each y row
            let i = ix;
            downsample(&temp2[i..], &mut temp1[i..], n, n);
            upsample(&temp1[i..], &mut temp2[i..], n, n);
        }

        // Step 4. Subtract out the coarse-scale contribution
        for i in 0..(n * n) {
            noise[i] -= temp2[i];
        }
        // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
        let mut offset = n / 2;
        if offset % 2 == 0 {
            offset += 1;
        }
        let mut i = 0;
        for ix in 0..n {
            for iy in 0..n {
                temp1[i] = noise[((ix + offset) % n) + ((iy + offset) % n) * n];
                i += 1;
            }
        }
        for i in 0..(n * n) {
            noise[i] += temp1[i];
        }

        noise
    }

    /* Non-projected 2D noise */
    fn noise(noise_tile: &[f32], n: usize, p: [f32; 2]) -> f32 {
        let mut mid = [0; 2];
        let mut w = [[0.0; 3]; 2];

        /* Evaluate quadratic B-spline basis functions */
        for i in 0..2 {
            let center = p[i] - 0.5;
            let t = center.ceil() - center;

            mid[i] = center.ceil() as i32;
            w[i][0] = 0.5 * t * t;
            w[i][2] = 0.5 * (1.0 - t) * (1.0 - t);
            w[i][1] = 1.0 - w[i][0] - w[i][2];
        }
        /* Evaluate noise by weighting noise coefficients by basis function values */
        let mut result = 0.0;
        for fx in 0..3 {
            for fy in 0..3 {
                let cx = modulo(mid[0] + (fx as i32 - 1), n);
                let cy = modulo(mid[1] + (fy as i32 - 1), n);
                let weight = w[0][fx] * w[1][fy];
                result += weight * noise_tile[cx + cy * n];
            }
        }
        result
    }

    let noise_tile = generate_noise_tile(grid_resolution);

    let mut heights = Vec::new();
    for x in 0..(grid_resolution * grid_spacing) {
        for y in 0..(grid_resolution * grid_spacing) {
            let p = [
                x as f32 / grid_spacing as f32,
                y as f32 / grid_spacing as f32,
            ];
            heights.push(noise(&noise_tile, grid_resolution, p))
        }
    }

    let mean = heights.iter().sum::<f32>() / heights.len() as f32;
    let variance = heights.iter().map(|n| (n - mean) * (n - mean)).sum::<f32>() /
        heights.len() as f32;

    let inv_variance = 1.0 / variance;
    for h in &mut heights {
        *h *= inv_variance;
    }

    Heightmap {
        heights,
        width: (grid_resolution * grid_spacing) as u16,
        height: (grid_resolution * grid_spacing) as u16,
    }
}
<commit_msg>Fix bug in slope computation<commit_after>use rand;
use rand::Rng;
use std::f32::consts::PI;
use rand::distributions::{Normal, IndependentSample};

#[allow(unused)]
fn modulo(a: i64, b: i64) -> usize {
    (((a % b) + b) % b) as usize
}

pub struct Heightmap<T> {
    pub heights: Vec<T>,
    pub width: u16,
    pub height: u16,
}

impl<T> Heightmap<T> {
    #[allow(unused)]
    pub fn new(heights: Vec<T>, width: u16, height: u16) -> Self {
        assert_eq!(heights.len(), (width as usize) * (height as usize));
        Heightmap {
            heights,
            width,
            height,
        }
    }

    pub fn get(&self, x: u16, y: u16) -> Option<T>
    where
        T: Clone,
    {
        if x >= self.width || y >= self.height {
            return None;
        }

        self.heights
            .get(x as usize + y as usize * self.width as usize)
            .cloned()
    }

    #[allow(unused)]
    pub fn get_wrapping(&self, x: i64, y: i64) -> T
    where
        T: Clone,
    {
        let x = modulo(x, self.width as i64);
        let y = modulo(y, self.height as i64);
        self.heights[x + y * self.width as usize].clone()
    }

    /// Produces a Vec of arrays where each array consists of the height at that point followed by
    /// the slope in the x and y directions respectively.
    pub fn as_height_and_slopes(&self, spacing: f32) -> Vec<[f32; 3]>
    where
        f32: From<T>,
        T: Clone,
    {
        let mut result = Vec::with_capacity(self.width as usize * self.height as usize);
        let scale_factor = 0.5 / spacing;

        for y in 0..self.height {
            for x in 0..self.width {
                let mx: f32 = if x > 0 {
                    self.get(x - 1, y).unwrap().into()
                } else {
                    self.get(self.width - 1, y).unwrap().into()
                };
                let px: f32 = if x < self.width - 1 {
                    self.get(x + 1, y).unwrap().into()
                } else {
                    self.get(0, y).unwrap().into()
                };
                let my: f32 = if y > 0 {
                    self.get(x, y - 1).unwrap().into()
                } else {
                    self.get(x, self.height - 1).unwrap().into()
                };
                let py: f32 = if y < self.height - 1 {
                    self.get(x, y + 1).unwrap().into()
                } else {
                    self.get(x, 0).unwrap().into()
                };
                let v = [
                    self.heights[x as usize + y as usize * self.width as usize]
                        .clone()
                        .into(),
                    (px - mx) * scale_factor,
                    (py - my) * scale_factor,
                ];
                result.push(v);
            }
        }
        result
    }
}

#[allow(dead_code)]
pub fn perlin_noise(grid_resolution: usize, grid_spacing: usize) -> Heightmap<f32> {
    fn dot(a: (f32, f32), b: (f32, f32)) -> f32 {
        a.0 * b.0 + a.1 * b.1
    }

    fn fade(t: f32) -> f32 {
        t * t * t * (6.0 * t * t - 15.0 * t + 10.0)
    }

    fn interp(a: f32, b: f32, t: f32) -> f32 {
        let t = fade(t);
        a * (1.0 - t) + b * t
    }

    let mut rng = rand::thread_rng();
    let gradients: Vec<(f32, f32)> = (0..(grid_resolution * grid_resolution))
        .map(|_| rng.gen_range(0.0, 2.0 * PI).sin_cos())
        .collect();

    let mut heights =
        vec![-9999.0; grid_resolution * grid_resolution * grid_spacing * grid_spacing];
    for y in 0..grid_resolution {
        for x in 0..grid_resolution {
            let xp = (x + 1) % grid_resolution;
            let yp = (y + 1) % grid_resolution;
            let a = gradients[x + y * grid_resolution];
            let b = gradients[x + yp * grid_resolution];
            let c = gradients[xp + y * grid_resolution];
            let d = gradients[xp + yp * grid_resolution];

            for k in 0..grid_spacing {
                for h in 0..grid_spacing {
                    let v = (
                        h as f32 / grid_spacing as f32,
                        k as f32 / grid_spacing as f32,
                    );

                    let ad = dot(a, v);
                    let bd = dot(b, (v.0, v.1 - 1.0));
                    let cd = dot(c, (v.0 - 1.0, v.1));
                    let dd = dot(d, (v.0 - 1.0, v.1 - 1.0));

                    let height = interp(interp(ad, bd, v.1), interp(cd, dd, v.1), v.0);

                    let i = (h + x * grid_spacing) +
                        (k + y * grid_spacing) * grid_resolution * grid_spacing;
                    heights[i] = height;
                }
            }
        }
    }

    Heightmap {
        heights,
        width: (grid_resolution * grid_spacing) as u16,
        height: (grid_resolution * grid_spacing) as u16,
    }
}

/// Evaluate wavelet noise on a grid with the given resolution and grid spacing. ///
/// The output heightmap will have a width and height of `grid_resolution` * `grid_spacing`. Values
/// will have a mean of approximately zero, and a variance of 1.
pub fn wavelet_noise(grid_resolution: usize, grid_spacing: usize) -> Heightmap<f32> {
    // See: https://graphics.pixar.com/library/WaveletNoise/paper.pdf

    fn modulo(x: i32, n: usize) -> usize {
        let m = x % n as i32;
        if m < 0 {
            (m + n as i32) as usize
        } else {
            m as usize
        }
    }
    fn downsample(from: &[f32], to: &mut [f32], n: usize, stride: usize) {
        const ARAD: i32 = 16;
        #[cfg_attr(rustfmt, rustfmt_skip)]
        const COEFFS: [f32; 32] = [
            0.000334,-0.001528, 0.000410, 0.003545,-0.000938,-0.008233, 0.002172, 0.019120,
            -0.005040,-0.044412, 0.011655, 0.103311,-0.025936,-0.243780, 0.033979, 0.655340,
            0.655340, 0.033979,-0.243780,-0.025936, 0.103311, 0.011655,-0.044412,-0.005040,
            0.019120, 0.002172,-0.008233,-0.000938, 0.003546, 0.000410,-0.001528, 0.000334
        ];
        for i in 0..(n / 2) {
            to[i * stride] = 0.0;
            let min_k = 2 * (i as i32) - ARAD;
            let max_k = 2 * (i as i32) + ARAD;
            for k in min_k..(max_k) {
                let index = (ARAD + k - 2 * i as i32) as usize;
                to[i * stride] += COEFFS[index] * from[modulo(k, n) * stride];
            }
        }
    }
    fn upsample(from: &[f32], to: &mut [f32], n: usize, stride: usize) {
        let p_coeffs = [0.25, 0.75, 0.75, 0.25];
        for i in 0..n {
            to[i * stride] = 0.0;
            for k in (i / 2)..(i / 2 + 2) {
                to[i * stride] += p_coeffs[2 + i - 2 * k] * from[(k % (n / 2)) * stride];
            }
        }
    }
    fn generate_noise_tile(n: usize) -> Vec<f32> {
        assert!(n % 2 == 0); // size must be even!

        let mut temp1 = vec![0.0; n * n];
        let mut temp2 = vec![0.0; n * n];
        let mut noise = Vec::new();

        // Step 1. Fill the tile with random numbers in the range -1 to 1.
        let normal = Normal::new(0.0, 1.0);
        for _ in 0..(n * n) {
            noise.push(normal.ind_sample(&mut rand::thread_rng()) as f32);
        }

        // Steps 2 and 3. Downsample and upsample the tile
        for iy in 0..n {
            // each x row
            let i = iy * n;
            downsample(&noise[i..], &mut temp1[i..], n, 1);
            upsample(&temp1[i..], &mut temp2[i..], n, 1);
        }
        for ix in 0..n {
            // each y row
            let i = ix;
            downsample(&temp2[i..], &mut temp1[i..], n, n);
            upsample(&temp1[i..], &mut temp2[i..], n, n);
        }

        // Step 4. Subtract out the coarse-scale contribution
        for i in 0..(n * n) {
            noise[i] -= temp2[i];
        }
        // Avoid even/odd variance difference by adding odd-offset version of noise to itself.
        let mut offset = n / 2;
        if offset % 2 == 0 {
            offset += 1;
        }
        let mut i = 0;
        for ix in 0..n {
            for iy in 0..n {
                temp1[i] = noise[((ix + offset) % n) + ((iy + offset) % n) * n];
                i += 1;
            }
        }
        for i in 0..(n * n) {
            noise[i] += temp1[i];
        }

        noise
    }

    /* Non-projected 2D noise */
    fn noise(noise_tile: &[f32], n: usize, p: [f32; 2]) -> f32 {
        let mut mid = [0; 2];
        let mut w = [[0.0; 3]; 2];

        /* Evaluate quadratic B-spline basis functions */
        for i in 0..2 {
            let center = p[i] - 0.5;
            let t = center.ceil() - center;

            mid[i] = center.ceil() as i32;
            w[i][0] = 0.5 * t * t;
            w[i][2] = 0.5 * (1.0 - t) * (1.0 - t);
            w[i][1] = 1.0 - w[i][0] - w[i][2];
        }
        /* Evaluate noise by weighting noise coefficients by basis function values */
        let mut result = 0.0;
        for fx in 0..3 {
            for fy in 0..3 {
                let cx = modulo(mid[0] + (fx as i32 - 1), n);
                let cy = modulo(mid[1] + (fy as i32 - 1), n);
                let weight = w[0][fx] * w[1][fy];
                result += weight * noise_tile[cx + cy * n];
            }
        }
        result
    }

    let noise_tile = generate_noise_tile(grid_resolution);

    let mut heights = Vec::new();
    for x in 0..(grid_resolution * grid_spacing) {
        for y in 0..(grid_resolution * grid_spacing) {
            let p = [
                x as f32 / grid_spacing as f32,
                y as f32 / grid_spacing as f32,
            ];
            heights.push(noise(&noise_tile, grid_resolution, p))
        }
    }

    let mean = heights.iter().sum::<f32>() / heights.len() as f32;
    let variance = heights.iter().map(|n| (n - mean) * (n - mean)).sum::<f32>() /
        heights.len() as f32;

    let inv_variance = 1.0 / variance;
    for h in &mut heights {
        *h *= inv_variance;
    }

    Heightmap {
        heights,
        width: (grid_resolution * grid_spacing) as u16,
        height: (grid_resolution * grid_spacing) as u16,
    }
}
<|endoftext|>


<commit_before>use Parameter;
use fa::{VFunction, Linear};
use agents::PredictionAgent;
use geometry::Space;
use std::marker::PhantomData;

pub struct GTD2<S: Space, V: VFunction<S> + Linear<S>>
{
    v_func: V,
    a_func: V,

    alpha: Parameter,
    beta: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, V> GTD2<S, V>
    where V: VFunction<S> + Linear<S>
{
    pub fn new<T1, T2, T3>(v_func: V, a_func: V,
                           alpha: T1, beta: T2, gamma: T3) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>
    {
        if !v_func.equivalent(&a_func) {
            panic!("v_func and a_func must be equivalent function approximators.")
        }

        GTD2 {
            v_func: v_func,
            a_func: a_func,

            alpha: alpha.into(),
            beta: beta.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, V> PredictionAgent<S> for GTD2<S, V>
    where V: VFunction<S> + Linear<S>
{
    fn handle_transition(&mut self, s: &S::Repr, ns: &S::Repr, r: f64) -> Option<f64> {
        let phi_s = self.v_func.phi(s);
        let phi_ns = self.v_func.phi(ns);

        let td_error = r + self.gamma*self.v_func.evaluate_phi(&phi_ns) -
            self.v_func.evaluate_phi(&phi_s);
        let td_estimate = self.a_func.evaluate_phi(&phi_s);

        self.v_func.update_phi(&(&phi_s - &(self.gamma.value()*&phi_ns)), self.alpha*td_estimate);
        self.a_func.update_phi(&phi_s, self.beta*(td_error - td_estimate));

        Some(td_error)
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.beta = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

pub struct TDC<S: Space, V: VFunction<S> + Linear<S>>
{
    v_func: V,
    a_func: V,

    alpha: Parameter,
    beta: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, V> TDC<S, V>
    where V: VFunction<S> + Linear<S>
{
    pub fn new<T1, T2, T3>(v_func: V, a_func: V,
                           alpha: T1, beta: T2, gamma: T3) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>
    {
        if !v_func.equivalent(&a_func) {
            panic!("v_func and a_func must be equivalent function approximators.")
        }

        TDC {
            v_func: v_func,
            a_func: a_func,

            alpha: alpha.into(),
            beta: beta.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, V> PredictionAgent<S> for TDC<S, V>
    where V: VFunction<S> + Linear<S>
{
    fn handle_transition(&mut self, s: &S::Repr, ns: &S::Repr, r: f64) -> Option<f64> {
        let phi_s = self.v_func.phi(s);
        let phi_ns = self.v_func.phi(ns);

        let phi_diff = &phi_s - &(self.gamma.value()*&phi_ns);

        let td_error = r + self.gamma*self.v_func.evaluate_phi(&phi_ns) -
            self.v_func.evaluate_phi(&phi_s);
        let td_estimate = self.a_func.evaluate_phi(&phi_s);

        self.v_func.update_phi(&(&(td_estimate*&phi_s) - &(self.gamma.value()*td_estimate*&phi_ns)), self.alpha.value());
        self.a_func.update_phi(&phi_s, self.beta*(td_error - td_estimate));

        Some(td_error)
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.beta = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

<commit_msg>Correction to TDC algorithm<commit_after>use Parameter;
use fa::{VFunction, Linear};
use agents::PredictionAgent;
use geometry::Space;
use std::marker::PhantomData;

pub struct GTD2<S: Space, V: VFunction<S> + Linear<S>>
{
    v_func: V,
    a_func: V,

    alpha: Parameter,
    beta: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, V> GTD2<S, V>
    where V: VFunction<S> + Linear<S>
{
    pub fn new<T1, T2, T3>(v_func: V, a_func: V,
                           alpha: T1, beta: T2, gamma: T3) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>
    {
        if !v_func.equivalent(&a_func) {
            panic!("v_func and a_func must be equivalent function approximators.")
        }

        GTD2 {
            v_func: v_func,
            a_func: a_func,

            alpha: alpha.into(),
            beta: beta.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, V> PredictionAgent<S> for GTD2<S, V>
    where V: VFunction<S> + Linear<S>
{
    fn handle_transition(&mut self, s: &S::Repr, ns: &S::Repr, r: f64) -> Option<f64> {
        let phi_s = self.v_func.phi(s);
        let phi_ns = self.v_func.phi(ns);

        let td_error = r + self.gamma*self.v_func.evaluate_phi(&phi_ns) -
            self.v_func.evaluate_phi(&phi_s);
        let td_estimate = self.a_func.evaluate_phi(&phi_s);

        self.v_func.update_phi(&(&phi_s - &(self.gamma.value()*&phi_ns)), self.alpha*td_estimate);
        self.a_func.update_phi(&phi_s, self.beta*(td_error - td_estimate));

        Some(td_error)
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.beta = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

pub struct TDC<S: Space, V: VFunction<S> + Linear<S>>
{
    v_func: V,
    a_func: V,

    alpha: Parameter,
    beta: Parameter,
    gamma: Parameter,

    phantom: PhantomData<S>,
}

impl<S: Space, V> TDC<S, V>
    where V: VFunction<S> + Linear<S>
{
    pub fn new<T1, T2, T3>(v_func: V, a_func: V,
                           alpha: T1, beta: T2, gamma: T3) -> Self
        where T1: Into<Parameter>,
              T2: Into<Parameter>,
              T3: Into<Parameter>
    {
        if !v_func.equivalent(&a_func) {
            panic!("v_func and a_func must be equivalent function approximators.")
        }

        TDC {
            v_func: v_func,
            a_func: a_func,

            alpha: alpha.into(),
            beta: beta.into(),
            gamma: gamma.into(),

            phantom: PhantomData,
        }
    }
}

impl<S: Space, V> PredictionAgent<S> for TDC<S, V>
    where V: VFunction<S> + Linear<S>
{
    fn handle_transition(&mut self, s: &S::Repr, ns: &S::Repr, r: f64) -> Option<f64> {
        let phi_s = self.v_func.phi(s);
        let phi_ns = self.v_func.phi(ns);

        let td_error = r + self.gamma*self.v_func.evaluate_phi(&phi_ns) -
            self.v_func.evaluate_phi(&phi_s);
        let td_estimate = self.a_func.evaluate_phi(&phi_s);

        self.v_func.update_phi(&(&(td_error*&phi_s) - &(self.gamma.value()*td_estimate*&phi_ns)), self.alpha.value());
        self.a_func.update_phi(&phi_s, self.beta*(td_error - td_estimate));

        Some(td_error)
    }

    fn handle_terminal(&mut self, _: &S::Repr) {
        self.alpha = self.alpha.step();
        self.beta = self.alpha.step();
        self.gamma = self.gamma.step();
    }
}

<|endoftext|>