<commit_before>#![cfg_attr(not(feature = "gtk_3_10"), allow(unused_variables, unused_mut))]

extern crate gtk;
extern crate gdk;

use gtk::prelude::*;
use gtk::SpinButtonUpdatePolicy;
use gdk::enums::modifier_type;

/// Expands to its argument if GTK+ 3.10 support is configured and to `()` otherwise
#[cfg(not(feature = "gtk_3_10"))]
macro_rules! with_gtk_3_10 {
    ($ex:expr) => (
        ()
    );
    ($bl:block) => {
        ()
    }
}

/// Expands to its argument if GTK+ 3.10 support is configured and to `()` otherwise
#[cfg(feature = "gtk_3_10")]
macro_rules! with_gtk_3_10 {
    ($ex:expr) => (
        $ex
    );
    ($bl:block) => {
        $bl
    }
}

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

fn about_clicked(button: &gtk::Button) {
    let dialog = gtk::AboutDialog::new();
    if let Some(window) = button.get_toplevel().and_then(|w| w.downcast::<gtk::Window>().ok()) {
        dialog.set_transient_for(Some(&window));
    }

    let crew = [
        "James T. Kirk",
        "Spock",
        "Leonard McCoy",
    ];

    dialog.set_authors(&crew);
    dialog.set_artists(&crew[1..]);

    println!("Authors: {:?}", dialog.get_authors());
    println!("Artists: {:?}", dialog.get_artists());
    println!("Documenters: {:?}", dialog.get_documenters());

    dialog.run();
    dialog.destroy();
}

fn main() {
    if gtk::init().is_err() {
        println!("Failed to initialize GTK.");
        return;
    }
    println!("Major: {}, Minor: {}", gtk::get_major_version(), gtk::get_minor_version());
    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    let frame = gtk::Frame::new(Some("Yep a frame"));
    let _box = gtk::Box::new(gtk::Orientation::Horizontal, 10);
    let v_box = gtk::Box::new(gtk::Orientation::Horizontal, 10);
    let button_box = gtk::ButtonBox::new(gtk::Orientation::Horizontal);
    let label = gtk::Label::new(Some("Yeah a wonderful label too !"));
    let button = gtk::Button::new_with_label("Whattttt a button !");
    let button_about = gtk::Button::new_with_label("About?");
    let button_recent = gtk::Button::new_with_label("Choose a recent one !");
    let button_font = gtk::Button::new_with_label("Choose a font !");
    let app_button = gtk::Button::new_with_label("App ?");
    let file_button = gtk::Button::new_with_label("file ?");
    let font_button = gtk::FontButton::new();
    let toggle_button = gtk::ToggleButton::new_with_label("Toggle Me !");
    let check_button = gtk::CheckButton::new_with_label("Labeled check button");
    let color_button = gtk::ColorButton::new();
    let menu_button = with_gtk_3_10!(
        gtk::MenuButton::new()
    );
    let link_button = gtk::LinkButton::new("www.rust-lang.org");
    let volume_button = gtk::VolumeButton::new();
    let entry = gtk::Entry::new();
    let search_entry = with_gtk_3_10!(
        gtk::SearchEntry::new()
    );
    let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
    let separator2 = gtk::Separator::new(gtk::Orientation::Horizontal);
    let switch = gtk::Switch::new();
    let switch2 = gtk::Switch::new();
    let scale = gtk::Scale::new_with_range(gtk::Orientation::Horizontal, 0., 100., 1.);
    let level_bar = with_gtk_3_10!(
        gtk::LevelBar::new_for_interval(0., 100.)
    );
    let spin_button = gtk::SpinButton::new_with_range(0., 100., 1.);
    let spinner = gtk::Spinner::new();
    let image = gtk::Image::new_from_file("./test/resources/gtk.jpg");
    let progress_bar = gtk::ProgressBar::new();
    let arrow = gtk::Arrow::new(gtk::ArrowType::Right, gtk::ShadowType::EtchedOut);
    let calendar = gtk::Calendar::new();
    let info_bar = gtk::InfoBar::new();
    let tmp_button = with_gtk_3_10!(
        gtk::Button::new_from_icon_name("edit-clear", gtk::IconSize::Button as i32)
    );

    println!("test");

    with_gtk_3_10! {{
        info_bar.set_show_close_button(true);
    }}

    /*info_bar.connect(signals::Response::new(|response_id| {
        info_bar.hide()
    }));*/ //TODO: Why does this not work?

    progress_bar.set_fraction(0.7);
    spinner.start();
    with_gtk_3_10! {{
        level_bar.set_value(37.);
    }}
    switch2.set_active(true);
    frame.set_border_width(10);
    _box.set_border_width(5);
    entry.set_placeholder_text(Some("An Entry with a placeholder !"));
    volume_button.set_orientation(gtk::Orientation::Horizontal);
    label.set_justify(gtk::Justification::Left);
    window.set_title("Yeah a beautiful window with gtk !");
    window.set_position(gtk::WindowPosition::Center);
    window.add(&frame);

    scale.set_digits(1);
    scale.connect_format_value(|scale, value| {
        let digits = scale.get_digits() as usize;
        format!("<{:.*}>", digits, value)
    });

    spin_button.set_update_policy(SpinButtonUpdatePolicy::IfValid);
    spin_button.connect_input(|spin_button| {
        let text = spin_button.get_text().unwrap();
        println!("spin_button_input: \"{}\"", text);
        match text.parse::<f64>() {
            Ok(value) if value >= 90. => {
                println!("circular right");
                Some(Ok(10.))
            }
            Ok(value) if value <= 10. => {
                println!("circular left");
                Some(Ok(90.))
            }
            Ok(value) => Some(Ok(value)),
            Err(_) => Some(Err(())),
        }
    });

    let entry_clone = entry.clone();
    button.connect_clicked(clone!(window => move |_| {
        let dialog = gtk::Dialog::new_with_buttons(Some("Hello!"), Some(&window), gtk::DIALOG_MODAL,
            &[("No", 0), ("Yes", 1), ("Yes!", 2)]);

        let ret = dialog.run();

        dialog.destroy();

        entry_clone.set_text(&format!("Clicked {}", ret));
    }));

    // use a plain function instead of a closure
    button_about.connect_clicked(about_clicked);

    button_font.connect_clicked(clone!(window => move |_| {
        let dialog = gtk::FontChooserDialog::new(Some("Font chooser test"), Some(&window));

        dialog.run();
        dialog.destroy();
    }));

    button_recent.connect_clicked(clone!(window => move |_| {
        let dialog = gtk::RecentChooserDialog::new(Some("Recent chooser test"), Some(&window));
        dialog.add_buttons(&[
            ("Ok", gtk::ResponseType::Ok.into()),
            ("Cancel", gtk::ResponseType::Cancel.into())
        ]);

        dialog.run();
        dialog.destroy();
    }));

    file_button.connect_clicked(clone!(window => move |_| {
        //entry.set_text("Clicked!");
        let dialog = gtk::FileChooserDialog::new(Some("Choose a file"), Some(&window),
            gtk::FileChooserAction::Open);
        dialog.add_buttons(&[
            ("Open", gtk::ResponseType::Ok.into()),
            ("Cancel", gtk::ResponseType::Cancel.into())
        ]);

        dialog.set_select_multiple(true);
        dialog.run();
        let files = dialog.get_filenames();
        dialog.destroy();

        println!("Files: {:?}", files);
    }));

    app_button.connect_clicked(clone!(window => move |_| {
        //entry.set_text("Clicked!");
        let dialog = gtk::AppChooserDialog::new_for_content_type(Some(&window), gtk::DIALOG_MODAL,
            "sh");

        dialog.run();
        dialog.destroy();
    }));

    let entry_clone = entry.clone();
    window.connect_key_press_event(move |_, key| {
        let keyval = key.as_ref().keyval;
        let keystate = key.as_ref().state;

        println!("key pressed: {} / {:?}", keyval, keystate);
        println!("text: {}", entry_clone.get_text().unwrap());

        if keystate.intersects(modifier_type::ControlMask) {
            println!("You pressed Ctrl!");
        }

        Inhibit(false)
    });

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    frame.add(&_box);
    with_gtk_3_10! {{
        button_box.add(&tmp_button)
    }};
    button_box.add(&button);
    button_box.add(&button_about);
    button_box.add(&button_font);
    button_box.add(&button_recent);
    button_box.add(&file_button);
    button_box.add(&app_button);
    button_box.add(&font_button);
    button_box.add(&toggle_button);
    button_box.add(&color_button);
    button_box.add(&volume_button);
    v_box.add(&switch);
    with_gtk_3_10! {{
        v_box.add(&menu_button);
    }}
    v_box.add(&switch2);
    v_box.add(&check_button);
    v_box.add(&link_button);
    v_box.add(&spin_button);
    _box.add(&info_bar);
    _box.add(&v_box);
    _box.add(&scale);
    with_gtk_3_10! {{
        _box.add(&level_bar);
    }}
    _box.add(&button_box);
    _box.add(&progress_bar);
    _box.add(&separator);
    _box.add(&label);
    _box.add(&entry);
    _box.add(&separator2);
    with_gtk_3_10! {{
        _box.add(&search_entry);
    }}
    _box.add(&spinner);
    _box.add(&image);
    _box.add(&arrow);
    _box.add(&calendar);
    _box.set_orientation(gtk::Orientation::Vertical);
    // window.set_decorated(false);
    window.set_decorated(true);
    window.show_all();
    gtk::main();
}
<commit_msg>Fix converting generated enums to i32<commit_after>#![cfg_attr(not(feature = "gtk_3_10"), allow(unused_variables, unused_mut))]

extern crate gtk;
extern crate gdk;

use gtk::prelude::*;
use gtk::SpinButtonUpdatePolicy;
use gdk::enums::modifier_type;

/// Expands to its argument if GTK+ 3.10 support is configured and to `()` otherwise
#[cfg(not(feature = "gtk_3_10"))]
macro_rules! with_gtk_3_10 {
    ($ex:expr) => (
        ()
    );
    ($bl:block) => {
        ()
    }
}

/// Expands to its argument if GTK+ 3.10 support is configured and to `()` otherwise
#[cfg(feature = "gtk_3_10")]
macro_rules! with_gtk_3_10 {
    ($ex:expr) => (
        $ex
    );
    ($bl:block) => {
        $bl
    }
}

// make moving clones into closures more convenient
macro_rules! clone {
    (@param _) => ( _ );
    (@param $x:ident) => ( $x );
    ($($n:ident),+ => move || $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move || $body
        }
    );
    ($($n:ident),+ => move |$($p:tt),+| $body:expr) => (
        {
            $( let $n = $n.clone(); )+
            move |$(clone!(@param $p),)+| $body
        }
    );
}

fn about_clicked(button: &gtk::Button) {
    let dialog = gtk::AboutDialog::new();
    if let Some(window) = button.get_toplevel().and_then(|w| w.downcast::<gtk::Window>().ok()) {
        dialog.set_transient_for(Some(&window));
    }

    let crew = [
        "James T. Kirk",
        "Spock",
        "Leonard McCoy",
    ];

    dialog.set_authors(&crew);
    dialog.set_artists(&crew[1..]);

    println!("Authors: {:?}", dialog.get_authors());
    println!("Artists: {:?}", dialog.get_artists());
    println!("Documenters: {:?}", dialog.get_documenters());

    dialog.run();
    dialog.destroy();
}

fn main() {
    if gtk::init().is_err() {
        println!("Failed to initialize GTK.");
        return;
    }
    println!("Major: {}, Minor: {}", gtk::get_major_version(), gtk::get_minor_version());
    let window = gtk::Window::new(gtk::WindowType::Toplevel);
    let frame = gtk::Frame::new(Some("Yep a frame"));
    let _box = gtk::Box::new(gtk::Orientation::Horizontal, 10);
    let v_box = gtk::Box::new(gtk::Orientation::Horizontal, 10);
    let button_box = gtk::ButtonBox::new(gtk::Orientation::Horizontal);
    let label = gtk::Label::new(Some("Yeah a wonderful label too !"));
    let button = gtk::Button::new_with_label("Whattttt a button !");
    let button_about = gtk::Button::new_with_label("About?");
    let button_recent = gtk::Button::new_with_label("Choose a recent one !");
    let button_font = gtk::Button::new_with_label("Choose a font !");
    let app_button = gtk::Button::new_with_label("App ?");
    let file_button = gtk::Button::new_with_label("file ?");
    let font_button = gtk::FontButton::new();
    let toggle_button = gtk::ToggleButton::new_with_label("Toggle Me !");
    let check_button = gtk::CheckButton::new_with_label("Labeled check button");
    let color_button = gtk::ColorButton::new();
    let menu_button = with_gtk_3_10!(
        gtk::MenuButton::new()
    );
    let link_button = gtk::LinkButton::new("www.rust-lang.org");
    let volume_button = gtk::VolumeButton::new();
    let entry = gtk::Entry::new();
    let search_entry = with_gtk_3_10!(
        gtk::SearchEntry::new()
    );
    let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
    let separator2 = gtk::Separator::new(gtk::Orientation::Horizontal);
    let switch = gtk::Switch::new();
    let switch2 = gtk::Switch::new();
    let scale = gtk::Scale::new_with_range(gtk::Orientation::Horizontal, 0., 100., 1.);
    let level_bar = with_gtk_3_10!(
        gtk::LevelBar::new_for_interval(0., 100.)
    );
    let spin_button = gtk::SpinButton::new_with_range(0., 100., 1.);
    let spinner = gtk::Spinner::new();
    let image = gtk::Image::new_from_file("./test/resources/gtk.jpg");
    let progress_bar = gtk::ProgressBar::new();
    let arrow = gtk::Arrow::new(gtk::ArrowType::Right, gtk::ShadowType::EtchedOut);
    let calendar = gtk::Calendar::new();
    let info_bar = gtk::InfoBar::new();
    let tmp_button = with_gtk_3_10!(
        gtk::Button::new_from_icon_name("edit-clear", gtk::IconSize::Button.into())
    );

    println!("test");

    with_gtk_3_10! {{
        info_bar.set_show_close_button(true);
    }}

    /*info_bar.connect(signals::Response::new(|response_id| {
        info_bar.hide()
    }));*/ //TODO: Why does this not work?

    progress_bar.set_fraction(0.7);
    spinner.start();
    with_gtk_3_10! {{
        level_bar.set_value(37.);
    }}
    switch2.set_active(true);
    frame.set_border_width(10);
    _box.set_border_width(5);
    entry.set_placeholder_text(Some("An Entry with a placeholder !"));
    volume_button.set_orientation(gtk::Orientation::Horizontal);
    label.set_justify(gtk::Justification::Left);
    window.set_title("Yeah a beautiful window with gtk !");
    window.set_position(gtk::WindowPosition::Center);
    window.add(&frame);

    scale.set_digits(1);
    scale.connect_format_value(|scale, value| {
        let digits = scale.get_digits() as usize;
        format!("<{:.*}>", digits, value)
    });

    spin_button.set_update_policy(SpinButtonUpdatePolicy::IfValid);
    spin_button.connect_input(|spin_button| {
        let text = spin_button.get_text().unwrap();
        println!("spin_button_input: \"{}\"", text);
        match text.parse::<f64>() {
            Ok(value) if value >= 90. => {
                println!("circular right");
                Some(Ok(10.))
            }
            Ok(value) if value <= 10. => {
                println!("circular left");
                Some(Ok(90.))
            }
            Ok(value) => Some(Ok(value)),
            Err(_) => Some(Err(())),
        }
    });

    let entry_clone = entry.clone();
    button.connect_clicked(clone!(window => move |_| {
        let dialog = gtk::Dialog::new_with_buttons(Some("Hello!"), Some(&window), gtk::DIALOG_MODAL,
            &[("No", 0), ("Yes", 1), ("Yes!", 2)]);

        let ret = dialog.run();

        dialog.destroy();

        entry_clone.set_text(&format!("Clicked {}", ret));
    }));

    // use a plain function instead of a closure
    button_about.connect_clicked(about_clicked);

    button_font.connect_clicked(clone!(window => move |_| {
        let dialog = gtk::FontChooserDialog::new(Some("Font chooser test"), Some(&window));

        dialog.run();
        dialog.destroy();
    }));

    button_recent.connect_clicked(clone!(window => move |_| {
        let dialog = gtk::RecentChooserDialog::new(Some("Recent chooser test"), Some(&window));
        dialog.add_buttons(&[
            ("Ok", gtk::ResponseType::Ok.into()),
            ("Cancel", gtk::ResponseType::Cancel.into())
        ]);

        dialog.run();
        dialog.destroy();
    }));

    file_button.connect_clicked(clone!(window => move |_| {
        //entry.set_text("Clicked!");
        let dialog = gtk::FileChooserDialog::new(Some("Choose a file"), Some(&window),
            gtk::FileChooserAction::Open);
        dialog.add_buttons(&[
            ("Open", gtk::ResponseType::Ok.into()),
            ("Cancel", gtk::ResponseType::Cancel.into())
        ]);

        dialog.set_select_multiple(true);
        dialog.run();
        let files = dialog.get_filenames();
        dialog.destroy();

        println!("Files: {:?}", files);
    }));

    app_button.connect_clicked(clone!(window => move |_| {
        //entry.set_text("Clicked!");
        let dialog = gtk::AppChooserDialog::new_for_content_type(Some(&window), gtk::DIALOG_MODAL,
            "sh");

        dialog.run();
        dialog.destroy();
    }));

    let entry_clone = entry.clone();
    window.connect_key_press_event(move |_, key| {
        let keyval = key.as_ref().keyval;
        let keystate = key.as_ref().state;

        println!("key pressed: {} / {:?}", keyval, keystate);
        println!("text: {}", entry_clone.get_text().unwrap());

        if keystate.intersects(modifier_type::ControlMask) {
            println!("You pressed Ctrl!");
        }

        Inhibit(false)
    });

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    frame.add(&_box);
    with_gtk_3_10! {{
        button_box.add(&tmp_button)
    }};
    button_box.add(&button);
    button_box.add(&button_about);
    button_box.add(&button_font);
    button_box.add(&button_recent);
    button_box.add(&file_button);
    button_box.add(&app_button);
    button_box.add(&font_button);
    button_box.add(&toggle_button);
    button_box.add(&color_button);
    button_box.add(&volume_button);
    v_box.add(&switch);
    with_gtk_3_10! {{
        v_box.add(&menu_button);
    }}
    v_box.add(&switch2);
    v_box.add(&check_button);
    v_box.add(&link_button);
    v_box.add(&spin_button);
    _box.add(&info_bar);
    _box.add(&v_box);
    _box.add(&scale);
    with_gtk_3_10! {{
        _box.add(&level_bar);
    }}
    _box.add(&button_box);
    _box.add(&progress_bar);
    _box.add(&separator);
    _box.add(&label);
    _box.add(&entry);
    _box.add(&separator2);
    with_gtk_3_10! {{
        _box.add(&search_entry);
    }}
    _box.add(&spinner);
    _box.add(&image);
    _box.add(&arrow);
    _box.add(&calendar);
    _box.set_orientation(gtk::Orientation::Vertical);
    // window.set_decorated(false);
    window.set_decorated(true);
    window.show_all();
    gtk::main();
}
<|endoftext|>


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

use std::io::BufRead;

use crate::error::{Error, Result};

#[derive(Debug, Deserialize, Serialize)]
pub struct Plan {
    pub name: String,
    pub origin: String,
    pub version: Option<String>,
}

impl Plan {
    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
        let mut name: Option<String> = None;
        let mut origin: Option<String> = None;
        let mut version: Option<String> = None;
        for line in bytes.lines() {
            if let Ok(line) = line {
                // Rather than just blindly accepting values, let's trim all the
                // whitespace first, verify that we actually have 2 things separated
                // by an equal sign, and strip out quotes of any kind.
                //
                // To do this properly, we probably need some kind of bash parser,
                // or a plan file syntax that's in a different language that we do
                // have a parser for (LUA!), but both of those things are beyond the
                // scope of this task.
                let parts: Vec<&str> = line.splitn(2, "=").map(|x| x.trim()).collect();

                if parts.len() != 2 {
                    continue;
                }

                let mut val = parts[1].replace("\"", "");
                val = val.replace("'", "");

                match parts[0] {
                    "pkg_name" => name = Some(val),
                    "pkg_origin" => origin = Some(val),
                    "pkg_version" => version = Some(val),
                    _ => (),
                }
            }
        }

        if name.is_none() || origin.is_none() {
            return Err(Error::PlanMalformed);
        }

        Ok(Plan {
            name: name.unwrap(),
            origin: origin.unwrap(),
            version: version,
        })
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn parsing_plan_with_no_quotes_works() {
        let content = r#"
        pkg_origin=neurosis
        pkg_name=testapp
        pkg_version=0.1.3
        pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"
        pkg_license=()
        pkg_upstream_url=https://github.com/habitat-sh/habitat-example-plans
        pkg_source=nosuchfile.tar.gz
        pkg_deps=()
        pkg_expose=()

        do_download() {
          return 0
        }

        do_verify() {
          return 0
        }

        do_unpack() {
          return 0
        }

        do_build() {
          return 0
        }

        do_install() {
          return 0
        }
        "#;
        let plan = Plan::from_bytes(content.as_bytes()).unwrap();
        assert_eq!(plan.origin, "neurosis".to_string());
        assert_eq!(plan.name, "testapp".to_string());
        assert_eq!(plan.version, Some("0.1.3".to_string()));
    }

    #[test]
    fn parsing_plan_with_double_quotes_works() {
        let content = r#"
        pkg_origin="neurosis"
        pkg_name="testapp"
        pkg_version="0.1.3"
        pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"
        pkg_license=()
        pkg_upstream_url=https://github.com/habitat-sh/habitat-example-plans
        pkg_source=nosuchfile.tar.gz
        pkg_deps=()
        pkg_expose=()

        do_download() {
          return 0
        }

        do_verify() {
          return 0
        }

        do_unpack() {
          return 0
        }

        do_build() {
          return 0
        }

        do_install() {
          return 0
        }
        "#;
        let plan = Plan::from_bytes(content.as_bytes()).unwrap();
        assert_eq!(plan.origin, "neurosis".to_string());
        assert_eq!(plan.name, "testapp".to_string());
        assert_eq!(plan.version, Some("0.1.3".to_string()));
    }

    #[test]
    fn parsing_plan_with_single_quotes_works() {
        let content = r#"
        pkg_origin='neurosis'
        pkg_name='testapp'
        pkg_version='0.1.3'
        pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"
        pkg_license=()
        pkg_upstream_url=https://github.com/habitat-sh/habitat-example-plans
        pkg_source=nosuchfile.tar.gz
        pkg_deps=()
        pkg_expose=()

        do_download() {
          return 0
        }

        do_verify() {
          return 0
        }

        do_unpack() {
          return 0
        }

        do_build() {
          return 0
        }

        do_install() {
          return 0
        }
        "#;
        let plan = Plan::from_bytes(content.as_bytes()).unwrap();
        assert_eq!(plan.origin, "neurosis".to_string());
        assert_eq!(plan.name, "testapp".to_string());
        assert_eq!(plan.version, Some("0.1.3".to_string()));
    }
}
<commit_msg>Plan object support for Windows plan.ps1<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::io::BufRead;

use crate::error::{Error, Result};

#[derive(Debug, Deserialize, Serialize)]
pub struct Plan {
  pub name: String,
  pub origin: String,
  pub version: Option<String>,
}

impl Plan {
  pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
    let mut name: Option<String> = None;
    let mut origin: Option<String> = None;
    let mut version: Option<String> = None;
    for line in bytes.lines() {
      if let Ok(line) = line {
        // Rather than just blindly accepting values, let's trim all the
        // whitespace first, verify that we actually have 2 things separated
        // by an equal sign, and strip out quotes of any kind.
        //
        // To do this properly, we probably need some kind of bash parser,
        // or a plan file syntax that's in a different language that we do
        // have a parser for (LUA!), but both of those things are beyond the
        // scope of this task.
        let parts: Vec<&str> = line.splitn(2, "=").map(|x| x.trim()).collect();

        if parts.len() != 2 {
          continue;
        }

        let mut val = parts[1].replace("\"", "");
        val = val.replace("'", "");

        match parts[0] {
          "pkg_name" | "$pkg_name" => name = Some(val),
          "pkg_origin" | "$pkg_origin" => origin = Some(val),
          "pkg_version" | "$pkg_version" => version = Some(val),
          _ => (),
        }
      }
    }

    if name.is_none() || origin.is_none() {
      return Err(Error::PlanMalformed);
    }

    Ok(Plan {
      name: name.unwrap(),
      origin: origin.unwrap(),
      version: version,
    })
  }
}

#[cfg(test)]
mod test {
  use super::*;

  #[test]
  fn parsing_plan_with_no_quotes_works() {
    let content = r#"
        pkg_origin=neurosis
        pkg_name=testapp
        pkg_version=0.1.3
        pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"
        pkg_license=()
        pkg_upstream_url=https://github.com/habitat-sh/habitat-example-plans
        pkg_source=nosuchfile.tar.gz
        pkg_deps=()
        pkg_expose=()

        do_download() {
          return 0
        }

        do_verify() {
          return 0
        }

        do_unpack() {
          return 0
        }

        do_build() {
          return 0
        }

        do_install() {
          return 0
        }
        "#;
    let plan = Plan::from_bytes(content.as_bytes()).unwrap();
    assert_eq!(plan.origin, "neurosis".to_string());
    assert_eq!(plan.name, "testapp".to_string());
    assert_eq!(plan.version, Some("0.1.3".to_string()));
  }

  #[test]
  fn parsing_plan_with_double_quotes_works() {
    let content = r#"
        pkg_origin="neurosis"
        pkg_name="testapp"
        pkg_version="0.1.3"
        pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"
        pkg_license=()
        pkg_upstream_url=https://github.com/habitat-sh/habitat-example-plans
        pkg_source=nosuchfile.tar.gz
        pkg_deps=()
        pkg_expose=()

        do_download() {
          return 0
        }

        do_verify() {
          return 0
        }

        do_unpack() {
          return 0
        }

        do_build() {
          return 0
        }

        do_install() {
          return 0
        }
        "#;
    let plan = Plan::from_bytes(content.as_bytes()).unwrap();
    assert_eq!(plan.origin, "neurosis".to_string());
    assert_eq!(plan.name, "testapp".to_string());
    assert_eq!(plan.version, Some("0.1.3".to_string()));
  }

  #[test]
  fn parsing_plan_with_single_quotes_works() {
    let content = r#"
        pkg_origin='neurosis'
        pkg_name='testapp'
        pkg_version='0.1.3'
        pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"
        pkg_license=()
        pkg_upstream_url=https://github.com/habitat-sh/habitat-example-plans
        pkg_source=nosuchfile.tar.gz
        pkg_deps=()
        pkg_expose=()

        do_download() {
          return 0
        }

        do_verify() {
          return 0
        }

        do_unpack() {
          return 0
        }

        do_build() {
          return 0
        }

        do_install() {
          return 0
        }
        "#;
    let plan = Plan::from_bytes(content.as_bytes()).unwrap();
    assert_eq!(plan.origin, "neurosis".to_string());
    assert_eq!(plan.name, "testapp".to_string());
    assert_eq!(plan.version, Some("0.1.3".to_string()));
  }

  #[test]
  fn parsing_windows_plan_works() {
    let content = r#"
        $pkg_name="testapp"
        $pkg_origin="neurosis"
        $pkg_version="1.04"
        $pkg_maintainer="The Habitat Maintainers <humans@habitat.sh>"

        function Invoke-Unpack {
        }

        function Invoke-Install {
        }
        "#;
    let plan = Plan::from_bytes(content.as_bytes()).unwrap();
    assert_eq!(plan.origin, "neurosis".to_string());
    assert_eq!(plan.name, "testapp".to_string());
    assert_eq!(plan.version, Some("1.04".to_string()));
  }
}
<|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.

//! A module for working with borrowed data.

#![stable(feature = "rust1", since = "1.0.0")]

/// A trait identifying how borrowed data behaves.
///
/// In Rust, it is common to provide different representations of a type for
/// different use cases. For instance, storage location and management for a
/// value can be specifically chosen as appropriate for a particular use via
/// pointer types such as [`Box<T>`] or [`Rc<T>`]. Beyond these generic
/// wrappers that can be used with any type, some types provide optional
/// facets providing potentially costly functionality. An example for such a
/// type is [`String`] which adds the ability to extend a string to the basic
/// [`str`]. This requires keeping additional information unnecessary for a
/// simple, immutable string.
///
/// These types signal that they are a specialized representation of a basic
/// type `T` by implementing `Borrow<T>`. The method `borrow` provides a way
/// to convert a reference to the type into a reference to this basic type
/// `T`.
///
/// Further, when providing implementations for additional traits, it needs
/// to be considered whether they should behave identical to those of the
/// underlying type as a consequence of acting as a representation of that
/// underlying type.
///
/// Generic code typically uses `Borrow<T>` when it not only needs access
/// to a reference of the underlying type but relies on the identical
/// behavior of these additional trait implementations. These traits are
/// likely to appear as additional trait bounds.
///
/// If generic code merely needs to work for all types that can
/// provide a reference to related type `T`, it is often better to use
/// [`AsRef<T>`] as more types can safely implement it.
///
/// If a type implementing `Borrow<T>` also wishes to allow mutable access
/// to the underlying type `T`, it can do so by implementing the companion
/// trait [`BorrowMut`].
///
/// Note also that it is perfectly fine for a single type to have multiple
/// implementations of `Borrow<T>` for different `T`s. In fact, a blanket
/// implementation lets every type be at least a borrow of itself.
///
/// [`AsRef<T>`]: ../../std/convert/trait.AsRef.html
/// [`BorrowMut`]: trait.BorrowMut.html
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
/// [`Mutex<T>`]: ../../std/sync/struct.Mutex.html
/// [`Rc<T>`]: ../../std/rc/struct.Rc.html
/// [`str`]: ../../std/primitive.str.html
/// [`String`]: ../../std/string/struct.String.html
///
/// # Examples
///
/// As a data collection, [`HashMap<K, V>`] owns both keys and values. If
/// the key’s actual data is wrapped in a managing type of some kind, it
/// should, however, still be possible to search for a value using a
/// reference to the key’s data. For instance, if the key is a string, then
/// it is likely stored with the hash map as a [`String`], while it should
/// be possible to search using a [`&str`][`str`]. Thus, `insert` needs to
/// operate on a `String` while `get` needs to be able to use a `&str`.
///
/// Slightly simplified, the relevant parts of `HashMap<K, V>` look like
/// this:
///
/// ```
/// use std::borrow::Borrow;
/// use std::hash::Hash;
///
/// pub struct HashMap<K, V> {
///     # marker: ::std::marker::PhantomData<(K, V)>,
///     // fields omitted
/// }
///
/// impl<K, V> HashMap<K, V> {
///     pub fn insert(&self, key: K, value: V) -> Option<V>
///     where K: Hash + Eq
///     {
///         # unimplemented!()
///         // ...
///     }
///
///     pub fn get<Q>(&self, k: &Q) -> Option<&V>
///     where
///         K: Borrow<Q>,
///         Q: Hash + Eq + ?Sized
///     {
///         # unimplemented!()
///         // ...
///     }
/// }
/// ```
///
/// The entire hash map is generic over a key type `K`. Because these keys
/// are stored with the hash map, this type has to own the key’s data.
/// When inserting a key-value pair, the map is given such a `K` and needs
/// to find the correct hash bucket and check if the key is already present
/// based on that `K`. It therefore requires `K: Hash + Eq`.
///
/// When searching for a value in the map, however, having to provide a
/// reference to a `K` as the key to search for would require to always
/// create such an owned value. For string keys, this would mean a `String`
/// value needs to be created just for the search for cases where only a
/// `str` is available.
///
/// Instead, the `get` method is generic over the type of the underlying key
/// data, called `Q` in the method signature above. It states that `K` is a
/// representation of `Q` by requiring that `K: Borrow<Q>`. By additionally
/// requiring `Q: Hash + Eq`, it demands that `K` and `Q` have
/// implementations of the `Hash` and `Eq` traits that produce identical
/// results.
///
/// The implementation of `get` relies in particular on identical
/// implementations of `Hash` by determining the key’s hash bucket by calling
/// `Hash::hash` on the `Q` value even though it inserted the key based on
/// the hash value calculated from the `K` value.
///
/// As a consequence, the hash map breaks if a `K` wrapping a `Q` value
/// produces a different hash than `Q`. For instance, imagine you have a
/// type that wraps a string but compares ASCII letters ignoring their case:
///
/// ```
/// pub struct CaseInsensitiveString(String);
///
/// impl PartialEq for CaseInsensitiveString {
///     fn eq(&self, other: &Self) -> bool {
///         self.0.eq_ignore_ascii_case(&other.0)
///     }
/// }
///
/// impl Eq for CaseInsensitiveString { }
/// ```
///
/// Because two equal values need to produce the same hash value, the
/// implementation of `Hash` needs to reflect that, too:
///
/// ```
/// # use std::hash::{Hash, Hasher};
/// # pub struct CaseInsensitiveString(String);
/// impl Hash for CaseInsensitiveString {
///     fn hash<H: Hasher>(&self, state: &mut H) {
///         for c in self.0.as_bytes() {
///             c.to_ascii_lowercase().hash(state)
///         }
///     }
/// }
/// ```
///
/// Can `CaseInsensitiveString` implement `Borrow<str>`? It certainly can
/// provide a reference to a string slice via its contained owned string.
/// But because its `Hash` implementation differs, it behaves differently
/// from `str` and therefore must not, in fact, implement `Borrow<str>`.
/// If it wants to allow others access to the underlying `str`, it can do
/// that via `AsRef<str>` which doesn’t carry any extra requirements.
///
/// [`Hash`]: ../../std/hash/trait.Hash.html
/// [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
/// [`String`]: ../../std/string/struct.String.html
/// [`str`]: ../../std/primitive.str.html
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
    /// Immutably borrows from an owned value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::borrow::Borrow;
    ///
    /// fn check<T: Borrow<str>>(s: T) {
    ///     assert_eq!("Hello", s.borrow());
    /// }
    ///
    /// let s = "Hello".to_string();
    ///
    /// check(s);
    ///
    /// let s = "Hello";
    ///
    /// check(s);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow(&self) -> &Borrowed;
}

/// A trait for mutably borrowing data.
///
/// Similar to `Borrow`, but for mutable borrows.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized> : Borrow<Borrowed> {
    /// Mutably borrows from an owned value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::borrow::BorrowMut;
    ///
    /// fn check<T: BorrowMut<[i32]>>(mut v: T) {
    ///     assert_eq!(&mut [1, 2, 3], v.borrow_mut());
    /// }
    ///
    /// let v = vec![1, 2, 3];
    ///
    /// check(v);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow_mut(&mut self) -> &mut Borrowed;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T { self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for T {
    fn borrow_mut(&mut self) -> &mut T { self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow<T> for &'a T {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow<T> for &'a mut T {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> BorrowMut<T> for &'a mut T {
    fn borrow_mut(&mut self) -> &mut T { &mut **self }
}
<commit_msg>Bring back the phrase 'borrowing as' for what Borrow does.<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.

//! A module for working with borrowed data.

#![stable(feature = "rust1", since = "1.0.0")]

/// A trait for borrowing data.
///
/// In Rust, it is common to provide different representations of a type for
/// different use cases. For instance, storage location and management for a
/// value can be specifically chosen as appropriate for a particular use via
/// pointer types such as [`Box<T>`] or [`Rc<T>`]. Beyond these generic
/// wrappers that can be used with any type, some types provide optional
/// facets providing potentially costly functionality. An example for such a
/// type is [`String`] which adds the ability to extend a string to the basic
/// [`str`]. This requires keeping additional information unnecessary for a
/// simple, immutable string.
///
/// These types provide access to the underlying data through references
/// to the type of that data. They are said to be ‘borrowed as’ that type.
/// For instance, a [`Box<T>`] can be borrowed as `T` while a [`String`]
/// can be borrowed as `str`.
///
/// Types express that they can be borrowed as some type `T` by implementing
/// `Borrow<T>`, providing a reference to a `T` in the trait’s
/// [`borrow`] method. A type is free to borrow as several different types.
/// If it wishes to mutably borrow as the type – allowing the underlying data
/// to be modified, it can additionally implement [`BorrowMut<T>`].
///
/// Further, when providing implementations for additional traits, it needs
/// to be considered whether they should behave identical to those of the
/// underlying type as a consequence of acting as a representation of that
/// underlying type. Generic code typically uses `Borrow<T>` when it relies
/// on the identical behavior of these additional trait implementations.
/// These traits will likely appear as additional trait bounds.
///
/// If generic code merely needs to work for all types that can
/// provide a reference to related type `T`, it is often better to use
/// [`AsRef<T>`] as more types can safely implement it.
///
/// [`AsRef<T>`]: ../../std/convert/trait.AsRef.html
/// [`BorrowMut<T>`]: trait.BorrowMut.html
/// [`Box<T>`]: ../../std/boxed/struct.Box.html
/// [`Mutex<T>`]: ../../std/sync/struct.Mutex.html
/// [`Rc<T>`]: ../../std/rc/struct.Rc.html
/// [`str`]: ../../std/primitive.str.html
/// [`String`]: ../../std/string/struct.String.html
/// [`borrow`]: #tymethod.borrow
///
///
/// # Examples
///
/// As a data collection, [`HashMap<K, V>`] owns both keys and values. If
/// the key’s actual data is wrapped in a managing type of some kind, it
/// should, however, still be possible to search for a value using a
/// reference to the key’s data. For instance, if the key is a string, then
/// it is likely stored with the hash map as a [`String`], while it should
/// be possible to search using a [`&str`][`str`]. Thus, `insert` needs to
/// operate on a `String` while `get` needs to be able to use a `&str`.
///
/// Slightly simplified, the relevant parts of `HashMap<K, V>` look like
/// this:
///
/// ```
/// use std::borrow::Borrow;
/// use std::hash::Hash;
///
/// pub struct HashMap<K, V> {
///     # marker: ::std::marker::PhantomData<(K, V)>,
///     // fields omitted
/// }
///
/// impl<K, V> HashMap<K, V> {
///     pub fn insert(&self, key: K, value: V) -> Option<V>
///     where K: Hash + Eq
///     {
///         # unimplemented!()
///         // ...
///     }
///
///     pub fn get<Q>(&self, k: &Q) -> Option<&V>
///     where
///         K: Borrow<Q>,
///         Q: Hash + Eq + ?Sized
///     {
///         # unimplemented!()
///         // ...
///     }
/// }
/// ```
///
/// The entire hash map is generic over a key type `K`. Because these keys
/// are stored with the hash map, this type has to own the key’s data.
/// When inserting a key-value pair, the map is given such a `K` and needs
/// to find the correct hash bucket and check if the key is already present
/// based on that `K`. It therefore requires `K: Hash + Eq`.
///
/// When searching for a value in the map, however, having to provide a
/// reference to a `K` as the key to search for would require to always
/// create such an owned value. For string keys, this would mean a `String`
/// value needs to be created just for the search for cases where only a
/// `str` is available.
///
/// Instead, the `get` method is generic over the type of the underlying key
/// data, called `Q` in the method signature above. It states that `K`
/// borrows as a `Q` by requiring that `K: Borrow<Q>`. By additionally
/// requiring `Q: Hash + Eq`, it signals the requirement that `K` and `Q`
/// have implementations of the `Hash` and `Eq` traits that produce identical
/// results.
///
/// The implementation of `get` relies in particular on identical
/// implementations of `Hash` by determining the key’s hash bucket by calling
/// `Hash::hash` on the `Q` value even though it inserted the key based on
/// the hash value calculated from the `K` value.
///
/// As a consequence, the hash map breaks if a `K` wrapping a `Q` value
/// produces a different hash than `Q`. For instance, imagine you have a
/// type that wraps a string but compares ASCII letters ignoring their case:
///
/// ```
/// pub struct CaseInsensitiveString(String);
///
/// impl PartialEq for CaseInsensitiveString {
///     fn eq(&self, other: &Self) -> bool {
///         self.0.eq_ignore_ascii_case(&other.0)
///     }
/// }
///
/// impl Eq for CaseInsensitiveString { }
/// ```
///
/// Because two equal values need to produce the same hash value, the
/// implementation of `Hash` needs to ignore ASCII case, too:
///
/// ```
/// # use std::hash::{Hash, Hasher};
/// # pub struct CaseInsensitiveString(String);
/// impl Hash for CaseInsensitiveString {
///     fn hash<H: Hasher>(&self, state: &mut H) {
///         for c in self.0.as_bytes() {
///             c.to_ascii_lowercase().hash(state)
///         }
///     }
/// }
/// ```
///
/// Can `CaseInsensitiveString` implement `Borrow<str>`? It certainly can
/// provide a reference to a string slice via its contained owned string.
/// But because its `Hash` implementation differs, it behaves differently
/// from `str` and therefore must not, in fact, implement `Borrow<str>`.
/// If it wants to allow others access to the underlying `str`, it can do
/// that via `AsRef<str>` which doesn’t carry any extra requirements.
///
/// [`Hash`]: ../../std/hash/trait.Hash.html
/// [`HashMap<K, V>`]: ../../std/collections/struct.HashMap.html
/// [`String`]: ../../std/string/struct.String.html
/// [`str`]: ../../std/primitive.str.html
///
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
    /// Immutably borrows from an owned value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::borrow::Borrow;
    ///
    /// fn check<T: Borrow<str>>(s: T) {
    ///     assert_eq!("Hello", s.borrow());
    /// }
    ///
    /// let s = "Hello".to_string();
    ///
    /// check(s);
    ///
    /// let s = "Hello";
    ///
    /// check(s);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow(&self) -> &Borrowed;
}

/// A trait for mutably borrowing data.
///
/// Similar to `Borrow`, but for mutable borrows.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized> : Borrow<Borrowed> {
    /// Mutably borrows from an owned value.
    ///
    /// # Examples
    ///
    /// ```
    /// use std::borrow::BorrowMut;
    ///
    /// fn check<T: BorrowMut<[i32]>>(mut v: T) {
    ///     assert_eq!(&mut [1, 2, 3], v.borrow_mut());
    /// }
    ///
    /// let v = vec![1, 2, 3];
    ///
    /// check(v);
    /// ```
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow_mut(&mut self) -> &mut Borrowed;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T { self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for T {
    fn borrow_mut(&mut self) -> &mut T { self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow<T> for &'a T {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow<T> for &'a mut T {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> BorrowMut<T> for &'a mut T {
    fn borrow_mut(&mut self) -> &mut T { &mut **self }
}
<|endoftext|>


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

#[link(name = "rustc",
       vers = "0.8-pre",
       uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf",
       url = "https://github.com/mozilla/rust/tree/master/src/rustc")];

#[comment = "The Rust compiler"];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];

extern mod extra;
extern mod syntax;

use driver::driver::{host_triple, optgroups, early_error};
use driver::driver::{str_input, file_input, build_session_options};
use driver::driver::{build_session, build_configuration, parse_pretty};
use driver::driver::{pp_mode, pretty_print_input, list_metadata};
use driver::driver::{compile_input};
use driver::session;
use middle::lint;

use std::io;
use std::num;
use std::os;
use std::result;
use std::str;
use std::task;
use std::vec;
use extra::getopts::{groups, opt_present};
use extra::getopts;
use syntax::codemap;
use syntax::diagnostic;

pub mod middle {
    pub mod trans;
    pub mod ty;
    pub mod subst;
    pub mod resolve;
    pub mod typeck;
    pub mod check_loop;
    pub mod check_match;
    pub mod check_const;
    pub mod lint;
    pub mod borrowck;
    pub mod dataflow;
    pub mod mem_categorization;
    pub mod liveness;
    pub mod kind;
    pub mod freevars;
    pub mod pat_util;
    pub mod region;
    pub mod const_eval;
    pub mod astencode;
    pub mod lang_items;
    pub mod privacy;
    pub mod moves;
    pub mod entry;
    pub mod effect;
    pub mod reachable;
    pub mod graph;
    pub mod cfg;
}

pub mod front {
    pub mod config;
    pub mod test;
    pub mod std_inject;
}

pub mod back {
    pub mod link;
    pub mod abi;
    pub mod upcall;
    pub mod arm;
    pub mod mips;
    pub mod x86;
    pub mod x86_64;
    pub mod rpath;
    pub mod target_strs;
    pub mod passes;
}

pub mod metadata;

pub mod driver;

pub mod util {
    pub mod common;
    pub mod ppaux;
}

pub mod lib {
    pub mod llvm;
}

// A curious inner module that allows ::std::foo to be available in here for
// macros.
/*
mod std {
    pub use std::clone;
    pub use std::cmp;
    pub use std::os;
    pub use std::str;
    pub use std::sys;
    pub use std::to_bytes;
    pub use std::unstable;
    pub use extra::serialize;
}
*/

#[cfg(stage0)]
pub fn version(argv0: &str) {
    let mut vers = ~"unknown version";
    let env_vers = env!("CFG_VERSION");
    if env_vers.len() != 0 { vers = env_vers.to_owned(); }
    printfln!("%s %s", argv0, vers);
    printfln!("host: %s", host_triple());
}

#[cfg(not(stage0))]
pub fn version(argv0: &str) {
    let vers = match option_env!("CFG_VERSION") {
        Some(vers) => vers,
        None => "unknown version"
    };
    printfln!("%s %s", argv0, vers);
    printfln!("host: %s", host_triple());
}

pub fn usage(argv0: &str) {
    let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
    printfln!("%s\
Additional help:
    -W help             Print 'lint' options and default settings
    -Z help             Print internal options for debugging rustc\n",
              groups::usage(message, optgroups()));
}

pub fn describe_warnings() {
    use extra::sort::Sort;
    println("
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny, and deny all overrides)
");

    let lint_dict = lint::get_lint_dict();
    let mut lint_dict = lint_dict.move_iter()
                                 .map(|(k, v)| (v, k))
                                 .collect::<~[(lint::LintSpec, &'static str)]>();
    lint_dict.qsort();

    let mut max_key = 0;
    for &(_, name) in lint_dict.iter() {
        max_key = num::max(name.len(), max_key);
    }
    fn padded(max: uint, s: &str) -> ~str {
        str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
    }
    println("\nAvailable lint checks:\n");
    printfln!("    %s  %7.7s  %s",
              padded(max_key, "name"), "default", "meaning");
    printfln!("    %s  %7.7s  %s\n",
              padded(max_key, "----"), "-------", "-------");
    for (spec, name) in lint_dict.move_iter() {
        let name = name.replace("_", "-");
        printfln!("    %s  %7.7s  %s",
                  padded(max_key, name),
                  lint::level_to_str(spec.default),
                  spec.desc);
    }
    io::println("");
}

pub fn describe_debug_flags() {
    println("\nAvailable debug options:\n");
    let r = session::debugging_opts_map();
    for tuple in r.iter() {
        match *tuple {
            (ref name, ref desc, _) => {
                printfln!("    -Z %-20s -- %s", *name, *desc);
            }
        }
    }
}

pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    ::std::logging::console_off();

    let mut args = (*args).clone();
    let binary = args.shift().to_managed();

    if args.is_empty() { usage(binary); return; }

    let matches =
        &match getopts::groups::getopts(args, optgroups()) {
          Ok(m) => m,
          Err(f) => {
            early_error(demitter, getopts::fail_str(f));
          }
        };

    if opt_present(matches, "h") || opt_present(matches, "help") {
        usage(binary);
        return;
    }

    // Display the available lint options if "-W help" or only "-W" is given.
    let lint_flags = vec::append(getopts::opt_strs(matches, "W"),
                                 getopts::opt_strs(matches, "warn"));

    let show_lint_options = lint_flags.iter().any(|x| x == &~"help") ||
        (opt_present(matches, "W") && lint_flags.is_empty());

    if show_lint_options {
        describe_warnings();
        return;
    }

    let r = getopts::opt_strs(matches, "Z");
    if r.iter().any(|x| x == &~"help") {
        describe_debug_flags();
        return;
    }

    if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
        back::passes::list_passes();
        return;
    }

    if opt_present(matches, "v") || opt_present(matches, "version") {
        version(binary);
        return;
    }
    let input = match matches.free.len() {
      0u => early_error(demitter, ~"no input filename given"),
      1u => {
        let ifile = matches.free[0].as_slice();
        if "-" == ifile {
            let src = str::from_bytes(io::stdin().read_whole_stream());
            str_input(src.to_managed())
        } else {
            file_input(Path(ifile))
        }
      }
      _ => early_error(demitter, ~"multiple input filenames provided")
    };

    let sopts = build_session_options(binary, matches, demitter);
    let sess = build_session(sopts, demitter);
    let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
    let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
    let cfg = build_configuration(sess, binary, &input);
    let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
        parse_pretty(sess, a)
    };
    match pretty {
      Some::<pp_mode>(ppm) => {
        pretty_print_input(sess, cfg, &input, ppm);
        return;
      }
      None::<pp_mode> => {/* continue */ }
    }
    let ls = opt_present(matches, "ls");
    if ls {
        match input {
          file_input(ref ifile) => {
            list_metadata(sess, &(*ifile), io::stdout());
          }
          str_input(_) => {
            early_error(demitter, ~"can not list metadata for stdin");
          }
        }
        return;
    }

    compile_input(sess, cfg, &input, &odir, &ofile);
}

#[deriving(Eq)]
pub enum monitor_msg {
    fatal,
    done,
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
pub fn monitor(f: ~fn(diagnostic::Emitter)) {
    use std::comm::*;

    // XXX: This is a hack for newsched since it doesn't support split stacks.
    // rustc needs a lot of stack!
    static STACK_SIZE: uint = 6000000;

    let (p, ch) = stream();
    let ch = SharedChan::new(ch);
    let ch_capture = ch.clone();
    let mut task_builder = task::task();
    task_builder.supervised();
    task_builder.opts.stack_size = Some(STACK_SIZE);
    match do task_builder.try {
        let ch = ch_capture.clone();
        let ch_capture = ch.clone();
        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter: @fn(Option<(@codemap::CodeMap, codemap::span)>,
                          &str,
                          diagnostic::level) =
                          |cmsp, msg, lvl| {
            if lvl == diagnostic::fatal {
                ch_capture.send(fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        struct finally {
            ch: SharedChan<monitor_msg>,
        }

        impl Drop for finally {
            fn drop(&self) { self.ch.send(done); }
        }

        let _finally = finally { ch: ch };

        f(demitter);

        // Due reasons explain in #7732, if there was a jit execution context it
        // must be consumed and passed along to our parent task.
        back::link::jit::consume_engine()
    } {
        result::Ok(_) => { /* fallthrough */ }
        result::Err(_) => {
            // Task failed without emitting a fatal diagnostic
            if p.recv() == done {
                diagnostic::emit(
                    None,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::error);

                let xs = [
                    ~"the compiler hit an unexpected failure path. \
                     this is a bug",
                    ~"try running with RUST_LOG=rustc=1,::rt::backtrace \
                     to get further details and report the results \
                     to github.com/mozilla/rust/issues"
                ];
                for note in xs.iter() {
                    diagnostic::emit(None, *note, diagnostic::note)
                }
            }
            // Fail so the process returns a failure code
            fail!();
        }
    }
}

pub fn main() {
    let args = os::args();
    do monitor |demitter| {
        run_compiler(&args, demitter);
    }
}
<commit_msg>auto merge of #8427 : brson/rust/rustc-stack, r=thestinger<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

#[link(name = "rustc",
       vers = "0.8-pre",
       uuid = "0ce89b41-2f92-459e-bbc1-8f5fe32f16cf",
       url = "https://github.com/mozilla/rust/tree/master/src/rustc")];

#[comment = "The Rust compiler"];
#[license = "MIT/ASL2"];
#[crate_type = "lib"];

extern mod extra;
extern mod syntax;

use driver::driver::{host_triple, optgroups, early_error};
use driver::driver::{str_input, file_input, build_session_options};
use driver::driver::{build_session, build_configuration, parse_pretty};
use driver::driver::{pp_mode, pretty_print_input, list_metadata};
use driver::driver::{compile_input};
use driver::session;
use middle::lint;

use std::io;
use std::num;
use std::os;
use std::result;
use std::str;
use std::task;
use std::vec;
use extra::getopts::{groups, opt_present};
use extra::getopts;
use syntax::codemap;
use syntax::diagnostic;

pub mod middle {
    pub mod trans;
    pub mod ty;
    pub mod subst;
    pub mod resolve;
    pub mod typeck;
    pub mod check_loop;
    pub mod check_match;
    pub mod check_const;
    pub mod lint;
    pub mod borrowck;
    pub mod dataflow;
    pub mod mem_categorization;
    pub mod liveness;
    pub mod kind;
    pub mod freevars;
    pub mod pat_util;
    pub mod region;
    pub mod const_eval;
    pub mod astencode;
    pub mod lang_items;
    pub mod privacy;
    pub mod moves;
    pub mod entry;
    pub mod effect;
    pub mod reachable;
    pub mod graph;
    pub mod cfg;
}

pub mod front {
    pub mod config;
    pub mod test;
    pub mod std_inject;
}

pub mod back {
    pub mod link;
    pub mod abi;
    pub mod upcall;
    pub mod arm;
    pub mod mips;
    pub mod x86;
    pub mod x86_64;
    pub mod rpath;
    pub mod target_strs;
    pub mod passes;
}

pub mod metadata;

pub mod driver;

pub mod util {
    pub mod common;
    pub mod ppaux;
}

pub mod lib {
    pub mod llvm;
}

// A curious inner module that allows ::std::foo to be available in here for
// macros.
/*
mod std {
    pub use std::clone;
    pub use std::cmp;
    pub use std::os;
    pub use std::str;
    pub use std::sys;
    pub use std::to_bytes;
    pub use std::unstable;
    pub use extra::serialize;
}
*/

#[cfg(stage0)]
pub fn version(argv0: &str) {
    let mut vers = ~"unknown version";
    let env_vers = env!("CFG_VERSION");
    if env_vers.len() != 0 { vers = env_vers.to_owned(); }
    printfln!("%s %s", argv0, vers);
    printfln!("host: %s", host_triple());
}

#[cfg(not(stage0))]
pub fn version(argv0: &str) {
    let vers = match option_env!("CFG_VERSION") {
        Some(vers) => vers,
        None => "unknown version"
    };
    printfln!("%s %s", argv0, vers);
    printfln!("host: %s", host_triple());
}

pub fn usage(argv0: &str) {
    let message = fmt!("Usage: %s [OPTIONS] INPUT", argv0);
    printfln!("%s\
Additional help:
    -W help             Print 'lint' options and default settings
    -Z help             Print internal options for debugging rustc\n",
              groups::usage(message, optgroups()));
}

pub fn describe_warnings() {
    use extra::sort::Sort;
    println("
Available lint options:
    -W <foo>           Warn about <foo>
    -A <foo>           Allow <foo>
    -D <foo>           Deny <foo>
    -F <foo>           Forbid <foo> (deny, and deny all overrides)
");

    let lint_dict = lint::get_lint_dict();
    let mut lint_dict = lint_dict.move_iter()
                                 .map(|(k, v)| (v, k))
                                 .collect::<~[(lint::LintSpec, &'static str)]>();
    lint_dict.qsort();

    let mut max_key = 0;
    for &(_, name) in lint_dict.iter() {
        max_key = num::max(name.len(), max_key);
    }
    fn padded(max: uint, s: &str) -> ~str {
        str::from_bytes(vec::from_elem(max - s.len(), ' ' as u8)) + s
    }
    println("\nAvailable lint checks:\n");
    printfln!("    %s  %7.7s  %s",
              padded(max_key, "name"), "default", "meaning");
    printfln!("    %s  %7.7s  %s\n",
              padded(max_key, "----"), "-------", "-------");
    for (spec, name) in lint_dict.move_iter() {
        let name = name.replace("_", "-");
        printfln!("    %s  %7.7s  %s",
                  padded(max_key, name),
                  lint::level_to_str(spec.default),
                  spec.desc);
    }
    io::println("");
}

pub fn describe_debug_flags() {
    println("\nAvailable debug options:\n");
    let r = session::debugging_opts_map();
    for tuple in r.iter() {
        match *tuple {
            (ref name, ref desc, _) => {
                printfln!("    -Z %-20s -- %s", *name, *desc);
            }
        }
    }
}

pub fn run_compiler(args: &~[~str], demitter: diagnostic::Emitter) {
    // Don't display log spew by default. Can override with RUST_LOG.
    ::std::logging::console_off();

    let mut args = (*args).clone();
    let binary = args.shift().to_managed();

    if args.is_empty() { usage(binary); return; }

    let matches =
        &match getopts::groups::getopts(args, optgroups()) {
          Ok(m) => m,
          Err(f) => {
            early_error(demitter, getopts::fail_str(f));
          }
        };

    if opt_present(matches, "h") || opt_present(matches, "help") {
        usage(binary);
        return;
    }

    // Display the available lint options if "-W help" or only "-W" is given.
    let lint_flags = vec::append(getopts::opt_strs(matches, "W"),
                                 getopts::opt_strs(matches, "warn"));

    let show_lint_options = lint_flags.iter().any(|x| x == &~"help") ||
        (opt_present(matches, "W") && lint_flags.is_empty());

    if show_lint_options {
        describe_warnings();
        return;
    }

    let r = getopts::opt_strs(matches, "Z");
    if r.iter().any(|x| x == &~"help") {
        describe_debug_flags();
        return;
    }

    if getopts::opt_maybe_str(matches, "passes") == Some(~"list") {
        back::passes::list_passes();
        return;
    }

    if opt_present(matches, "v") || opt_present(matches, "version") {
        version(binary);
        return;
    }
    let input = match matches.free.len() {
      0u => early_error(demitter, ~"no input filename given"),
      1u => {
        let ifile = matches.free[0].as_slice();
        if "-" == ifile {
            let src = str::from_bytes(io::stdin().read_whole_stream());
            str_input(src.to_managed())
        } else {
            file_input(Path(ifile))
        }
      }
      _ => early_error(demitter, ~"multiple input filenames provided")
    };

    let sopts = build_session_options(binary, matches, demitter);
    let sess = build_session(sopts, demitter);
    let odir = getopts::opt_maybe_str(matches, "out-dir").map_move(|o| Path(o));
    let ofile = getopts::opt_maybe_str(matches, "o").map_move(|o| Path(o));
    let cfg = build_configuration(sess, binary, &input);
    let pretty = do getopts::opt_default(matches, "pretty", "normal").map_move |a| {
        parse_pretty(sess, a)
    };
    match pretty {
      Some::<pp_mode>(ppm) => {
        pretty_print_input(sess, cfg, &input, ppm);
        return;
      }
      None::<pp_mode> => {/* continue */ }
    }
    let ls = opt_present(matches, "ls");
    if ls {
        match input {
          file_input(ref ifile) => {
            list_metadata(sess, &(*ifile), io::stdout());
          }
          str_input(_) => {
            early_error(demitter, ~"can not list metadata for stdin");
          }
        }
        return;
    }

    compile_input(sess, cfg, &input, &odir, &ofile);
}

#[deriving(Eq)]
pub enum monitor_msg {
    fatal,
    done,
}

/*
This is a sanity check that any failure of the compiler is performed
through the diagnostic module and reported properly - we shouldn't be calling
plain-old-fail on any execution path that might be taken. Since we have
console logging off by default, hitting a plain fail statement would make the
compiler silently exit, which would be terrible.

This method wraps the compiler in a subtask and injects a function into the
diagnostic emitter which records when we hit a fatal error. If the task
fails without recording a fatal error then we've encountered a compiler
bug and need to present an error.
*/
pub fn monitor(f: ~fn(diagnostic::Emitter)) {
    use std::comm::*;

    // XXX: This is a hack for newsched since it doesn't support split stacks.
    // rustc needs a lot of stack!
    static STACK_SIZE: uint = 6000000;

    let (p, ch) = stream();
    let ch = SharedChan::new(ch);
    let ch_capture = ch.clone();
    let mut task_builder = task::task();
    task_builder.supervised();

    // XXX: Hacks on hacks. If the env is trying to override the stack size
    // then *don't* set it explicitly.
    if os::getenv("RUST_MIN_STACK").is_none() {
        task_builder.opts.stack_size = Some(STACK_SIZE);
    }

    match do task_builder.try {
        let ch = ch_capture.clone();
        let ch_capture = ch.clone();
        // The 'diagnostics emitter'. Every error, warning, etc. should
        // go through this function.
        let demitter: @fn(Option<(@codemap::CodeMap, codemap::span)>,
                          &str,
                          diagnostic::level) =
                          |cmsp, msg, lvl| {
            if lvl == diagnostic::fatal {
                ch_capture.send(fatal);
            }
            diagnostic::emit(cmsp, msg, lvl);
        };

        struct finally {
            ch: SharedChan<monitor_msg>,
        }

        impl Drop for finally {
            fn drop(&self) { self.ch.send(done); }
        }

        let _finally = finally { ch: ch };

        f(demitter);

        // Due reasons explain in #7732, if there was a jit execution context it
        // must be consumed and passed along to our parent task.
        back::link::jit::consume_engine()
    } {
        result::Ok(_) => { /* fallthrough */ }
        result::Err(_) => {
            // Task failed without emitting a fatal diagnostic
            if p.recv() == done {
                diagnostic::emit(
                    None,
                    diagnostic::ice_msg("unexpected failure"),
                    diagnostic::error);

                let xs = [
                    ~"the compiler hit an unexpected failure path. \
                     this is a bug",
                    ~"try running with RUST_LOG=rustc=1,::rt::backtrace \
                     to get further details and report the results \
                     to github.com/mozilla/rust/issues"
                ];
                for note in xs.iter() {
                    diagnostic::emit(None, *note, diagnostic::note)
                }
            }
            // Fail so the process returns a failure code
            fail!();
        }
    }
}

pub fn main() {
    let args = os::args();
    do monitor |demitter| {
        run_compiler(&args, demitter);
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::vec::IntoIter;

use rand::{Rand, Rng};

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Point2D {
    pub x: f64,
    pub y: f64
}

impl Point2D {
    pub fn new(x: f64, y: f64) -> Point2D {
        Point2D { x: x, y: y }
    }

    pub fn distance_to<T: AsRef<Point2D>>(&self, that: T) -> f64 {
        self.distance_squared_to(that).sqrt()
    }

    pub fn distance_squared_to<T: AsRef<Point2D>>(&self, that: T) -> f64 {
        (self.x - that.as_ref().x).powi(2) + (self.y - that.as_ref().y).powi(2)
    }
}

impl fmt::Display for Point2D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

impl AsRef<Point2D> for Point2D {
    fn as_ref(&self) -> &Point2D {
        &self
    }
}

impl Rand for Point2D {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        Point2D {
            x: rng.next_f64(),
            y: rng.next_f64()
        }
    }
}

#[test]
fn test_point2d() {
    let p1 = Point2D::new(0.0, 0.0);
    let p2 = Point2D::new(1.0, 1.0);

    // maybe bad :(
    assert_eq!(p1.distance_to(p2), (2.0f64).sqrt());
}

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
/// Implementation of 2D axis-aligned rectangle
pub struct RectHV {
    pub xmin: f64,
    pub ymin: f64,
    pub xmax: f64,
    pub ymax: f64
}

impl RectHV {
    pub fn new(xmin: f64, ymin: f64, xmax: f64, ymax: f64) -> RectHV {
        RectHV { xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax }
    }

    pub fn width(&self) -> f64 {
        self.xmax - self.xmin
    }

    pub fn height(&self) -> f64 {
        self.ymax - self.ymin
    }

    pub fn contains<T: AsRef<Point2D>>(&self, p: T) -> bool {
        let p = p.as_ref();
        p.x >= self.xmin && p.y >= self.ymin &&
            p.x <= self.xmax && p.y <= self.ymax
    }

    /// does this axis-aligned rectangle intersect that one?
    pub fn intersects<T: AsRef<RectHV>>(&self, that: T) -> bool {
        let that = that.as_ref();
        self.xmax >= that.xmin && self.ymax >= that.ymin &&
            that.xmax >= self.xmin && that.ymax >= self.ymin
    }

    /// distance from p to closest point on this axis-aligned rectangle
    pub fn distance_to<T: AsRef<Point2D>>(&self, p: T) -> f64 {
        self.distance_squared_to(p).sqrt()
    }

    /// distance squared from p to closest point on this axis-aligned rectangle
    pub fn distance_squared_to<T: AsRef<Point2D>>(&self, p: T) -> f64 {
        let p = p.as_ref();
        let mut dx = 0.0;
        let mut dy = 0.0;
        if p.x < self.xmin {
            dx = p.x - self.xmin;
        } else if p.x > self.xmax {
            dx = p.x - self.xmax;
        }
        if p.y < self.ymin {
            dy = p.y - self.ymin;
        } else if p.y > self.ymax {
            dy = p.y - self.ymax;
        }
        dx.powi(2) + dy.powi(2)
    }
}

impl fmt::Display for RectHV {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}, {}] x [{}, {}]", self.xmin, self.xmax, self.ymin, self.ymax)
    }
}

impl AsRef<RectHV> for RectHV {
    fn as_ref(&self) -> &RectHV {
        &self
    }
}

#[test]
fn test_rect() {
    let r1 = RectHV::new(0.0, 0.0, 1.1, 1.1);
    let r2 = RectHV::new(1.2, 2.0, 3.1, 4.1);
    assert!(!r1.intersects(r2));
}

pub struct PointSet {
    ps: Vec<Point2D>
}

impl PointSet {
    pub fn new() -> PointSet {
        PointSet { ps: Vec::new() }
    }

    pub fn size(&self) -> usize {
        self.ps.len()
    }

    pub fn insert(&mut self, p: Point2D) {
        if !self.ps.contains(&p) {
            self.ps.push(p)
        }
    }

    pub fn contains<T: AsRef<Point2D>>(&self, p: T) -> bool {
        self.ps.contains(p.as_ref())
    }

    pub fn range_search<T: AsRef<RectHV>>(&self, rect: T) -> IntoIter<&Point2D> {
        let mut result = Vec::new();
        for p in self.ps.iter() {
            if rect.as_ref().contains(p) {
                result.push(p);
            }
        }
        result.into_iter()
    }

    pub fn nearest<T: AsRef<Point2D>>(&self, p: T) -> Option<&Point2D> {
        // Ord :(
        self.ps.iter().min_by(|q| (q.distance_squared_to(p.as_ref()) * 10000.0) as u64)
    }
}

#[test]
fn test_point_set() {
    use rand::thread_rng;

    let mut rng = thread_rng();
    let mut ps = PointSet::new();
    for _ in 0 .. 100 {
        ps.insert(rng.gen())
    }

    assert!(ps.nearest(Point2D::new(0.5, 0.5)).is_some());
    assert!(ps.range_search(RectHV::new(0.4, 0.4, 0.6, 0.6)).count() > 0);
}
<commit_msg>geometric_search/primitive: change PointSet to use RedBlackBST implementation<commit_after>use std::fmt;
use std::vec::IntoIter;
use rand::{Rand, Rng};
use super::super::symbol_tables::ST;
use super::super::balanced_search_trees::RedBlackBST;

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
pub struct Point2D {
    pub x: f64,
    pub y: f64
}

impl Point2D {
    pub fn new(x: f64, y: f64) -> Point2D {
        Point2D { x: x, y: y }
    }

    pub fn distance_to<T: AsRef<Point2D>>(&self, that: T) -> f64 {
        self.distance_squared_to(that).sqrt()
    }

    pub fn distance_squared_to<T: AsRef<Point2D>>(&self, that: T) -> f64 {
        (self.x - that.as_ref().x).powi(2) + (self.y - that.as_ref().y).powi(2)
    }
}

impl fmt::Display for Point2D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

impl AsRef<Point2D> for Point2D {
    fn as_ref(&self) -> &Point2D {
        &self
    }
}

impl Rand for Point2D {
    fn rand<R: Rng>(rng: &mut R) -> Self {
        Point2D {
            x: rng.next_f64(),
            y: rng.next_f64()
        }
    }
}

#[test]
fn test_point2d() {
    let p1 = Point2D::new(0.0, 0.0);
    let p2 = Point2D::new(1.0, 1.0);

    // maybe bad :(
    assert_eq!(p1.distance_to(p2), (2.0f64).sqrt());
}

#[derive(Clone, Copy, PartialEq, PartialOrd, Debug)]
/// Implementation of 2D axis-aligned rectangle
pub struct RectHV {
    pub xmin: f64,
    pub ymin: f64,
    pub xmax: f64,
    pub ymax: f64
}

impl RectHV {
    pub fn new(xmin: f64, ymin: f64, xmax: f64, ymax: f64) -> RectHV {
        RectHV { xmin: xmin, ymin: ymin, xmax: xmax, ymax: ymax }
    }

    pub fn width(&self) -> f64 {
        self.xmax - self.xmin
    }

    pub fn height(&self) -> f64 {
        self.ymax - self.ymin
    }

    pub fn contains<T: AsRef<Point2D>>(&self, p: T) -> bool {
        let p = p.as_ref();
        p.x >= self.xmin && p.y >= self.ymin &&
            p.x <= self.xmax && p.y <= self.ymax
    }

    /// does this axis-aligned rectangle intersect that one?
    pub fn intersects<T: AsRef<RectHV>>(&self, that: T) -> bool {
        let that = that.as_ref();
        self.xmax >= that.xmin && self.ymax >= that.ymin &&
            that.xmax >= self.xmin && that.ymax >= self.ymin
    }

    /// distance from p to closest point on this axis-aligned rectangle
    pub fn distance_to<T: AsRef<Point2D>>(&self, p: T) -> f64 {
        self.distance_squared_to(p).sqrt()
    }

    /// distance squared from p to closest point on this axis-aligned rectangle
    pub fn distance_squared_to<T: AsRef<Point2D>>(&self, p: T) -> f64 {
        let p = p.as_ref();
        let mut dx = 0.0;
        let mut dy = 0.0;
        if p.x < self.xmin {
            dx = p.x - self.xmin;
        } else if p.x > self.xmax {
            dx = p.x - self.xmax;
        }
        if p.y < self.ymin {
            dy = p.y - self.ymin;
        } else if p.y > self.ymax {
            dy = p.y - self.ymax;
        }
        dx.powi(2) + dy.powi(2)
    }
}

impl fmt::Display for RectHV {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "[{}, {}] x [{}, {}]", self.xmin, self.xmax, self.ymin, self.ymax)
    }
}

impl AsRef<RectHV> for RectHV {
    fn as_ref(&self) -> &RectHV {
        &self
    }
}

#[test]
fn test_rect() {
    let r1 = RectHV::new(0.0, 0.0, 1.1, 1.1);
    let r2 = RectHV::new(1.2, 2.0, 3.1, 4.1);
    assert!(!r1.intersects(r2));
}

/// represents a set of points in the unit square
/// implemented using RedBlackBST
pub struct PointSet {
    pset: RedBlackBST<Point2D, ()>
}

impl PointSet {
    pub fn new() -> PointSet {
        PointSet { pset: RedBlackBST::new() }
    }

    pub fn size(&self) -> usize {
        self.pset.size()
    }

    pub fn insert(&mut self, p: Point2D) {
        if !self.pset.contains(&p) {
            self.pset.put(p, ())
        }
    }

    pub fn contains<T: AsRef<Point2D>>(&self, p: T) -> bool {
        self.pset.contains(p.as_ref())
    }

    pub fn range_search<T: AsRef<RectHV>>(&self, rect: T) -> IntoIter<&Point2D> {
        let mut result = Vec::new();
        for p in self.pset.keys() {
            if rect.as_ref().contains(p) {
                result.push(p);
            }
        }
        result.into_iter()
    }

    pub fn nearest<T: AsRef<Point2D>>(&self, p: T) -> Option<&Point2D> {
        // Ord :(
        self.pset.keys().min_by(|q| (q.distance_squared_to(p.as_ref()) * 10000.0) as u64)
    }
}

#[test]
fn test_point_set() {
    use rand::thread_rng;

    let mut rng = thread_rng();
    let mut ps = PointSet::new();
    for _ in 0 .. 100 {
        ps.insert(rng.gen())
    }
    assert_eq!(ps.size(), 100);

    assert!(ps.nearest(Point2D::new(0.5, 0.5)).is_some());
    assert!(ps.range_search(RectHV::new(0.4, 0.4, 0.6, 0.6)).count() > 0);
}
<|endoftext|>