<commit_before>extern crate chrono;
extern crate regex;
extern crate toml;

use self::chrono::{Duration, NaiveTime};
use self::regex::Regex;
use self::toml::Value as Toml;

use constant::CONFIG_FILE_NAME;
use error::{CannotHappenError, CliError, ConfigError, ConfigErrorKind};
use lib::io::*;
use std::borrow::Borrow;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Error as IoError, Read};
use std::path::PathBuf;
use std::str::FromStr;

const CONFIG_KEY_BURN_AFTER  : &'static str = "burn.after";
const CONFIG_KEY_SWEEP_PERIOD: &'static str = "sweep.period";
const CONFIG_KEY_SWEEP_TIME  : &'static str = "sweep.time";

pub enum ConfigKey {
    BurnAfter,
    SweepPeriod,
    SweepTime,
}

impl ConfigKey {
    pub fn from<S: AsRef<str>>(key: S) -> Result<ConfigKey, ConfigError> {
        match key.as_ref().trim() {
            CONFIG_KEY_BURN_AFTER   => Ok(ConfigKey::BurnAfter),
            CONFIG_KEY_SWEEP_PERIOD => Ok(ConfigKey::SweepPeriod),
            CONFIG_KEY_SWEEP_TIME   => Ok(ConfigKey::SweepTime),
            _                       => Err(ConfigError::new(ConfigErrorKind::InvalidKey)),
        }
    }

    fn to_str(&self) -> &str {
        match *self {
            ConfigKey::BurnAfter   => CONFIG_KEY_BURN_AFTER,
            ConfigKey::SweepPeriod => CONFIG_KEY_SWEEP_PERIOD,
            ConfigKey::SweepTime   => CONFIG_KEY_SWEEP_TIME,
        }
    }

    fn to_pair(&self) -> (&str, &str) {
        let key = self
            .to_str()
            .split('.')
            .collect::<Vec<&str>>();
        (key[0], key[1]) // unsafe!
    }
}

type EditableTomlCore = BTreeMap<String, BTreeMap<String, String>>;

#[derive(Clone)]
struct EditableToml(EditableTomlCore);

impl EditableToml {
    fn from(toml: Toml) -> Result<Self, ConfigError> {
        toml::decode::<EditableTomlCore>(toml)
            .map(|c| EditableToml(c))
            .ok_or(ConfigError::new(ConfigErrorKind::Something))
    }

    fn overwrite<CK: Borrow<ConfigKey>>(&mut self, key: CK, value: String) {
        let &mut EditableToml(ref mut core) = self;

        let (first, second) = key.borrow().to_pair();
        let second          = second.to_string();

        if core.contains_key(first) {
            core.get_mut(first).map(|e| e.insert(second, value));
        } else {
            let mut entry = BTreeMap::new();
            entry.insert(second, value);

            core.insert(first.to_string(), entry);
        }
    }

    fn to_toml(self) -> Toml {
        let EditableToml(core) = self;
        toml::encode(&core)
    }
}

pub struct Config {
    toml: Toml,
}

impl Config {
    fn path() -> PathBuf {
        path_buf![super::working_dir(), CONFIG_FILE_NAME]
    }

    pub fn exist() -> bool {
        Self::path().is_file()
    }

    fn to_string(&self) -> String {
        toml::encode_str(&self.toml)
    }

    pub fn create(&self) -> Result<(), IoError> {
        print_with_tag(Tag::Info, format!("Create \"{}\" file", CONFIG_FILE_NAME));

        super::create_setting_file(Self::path(), self.to_string())
    }

    fn _new(toml: Toml) -> Self {
        Config { toml: toml }
    }

    pub fn default() -> Self {
        let mut editable = EditableToml(BTreeMap::new());
        editable.overwrite(ConfigKey::BurnAfter  , "2 weeks".to_string());
        editable.overwrite(ConfigKey::SweepPeriod, "daily"  .to_string());
        editable.overwrite(ConfigKey::SweepTime  , "00:00"  .to_string());

        Self::_new(editable.to_toml())
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, format!("Read \"{}\" file", CONFIG_FILE_NAME));

        let mut f = try!(File::open(Self::path()));

        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));

        let result = contents
            .parse()
            .map_err(|e: Vec<_>| e.into_iter().next());
        let toml = match result {
            Ok(toml)    => toml,
            Err(option) => match option {
                Some(e) => return Err(From::from(e)),
                None    => return Err(From::from(CannotHappenError)),
            },
        };

        Ok(Self::_new(toml))
    }

    pub fn get<CK: Borrow<ConfigKey>>(&self, key: CK) -> Result<String, CliError> {
        let key = key.borrow();

        let result = self.toml
            .lookup(key.to_str())
            .ok_or(ConfigError::new(match *key {
                ConfigKey::BurnAfter   => ConfigErrorKind::NotFoundBurnAfter,
                ConfigKey::SweepPeriod => unimplemented!(),
                ConfigKey::SweepTime   => unimplemented!(),
            }));
        let value = try!(result);

        value
            .as_str()
            .ok_or(From::from(ConfigError::new(ConfigErrorKind::NonStringValue)))
            .and_then(|s| Self::validate(key, s))
    }

    pub fn to_duration(value: String) -> Result<Duration, CliError> {
        let mut value   = value.split(' ');
        let (num, unit) = match (value.next(), value.next()) {
            (Some(num), Some(unit)) => (num, unit),
            _                       => return Err(From::from(CannotHappenError)),
        };
        let num = try!(num.parse::<u32>()) as i64;

        let duration = match unit {
            "day"  | "days"  => Duration::days(num),
            "week" | "weeks" => Duration::weeks(num),
            _                => return Err(From::from(CannotHappenError)),
        };

        Ok(duration)
    }

    pub fn set<CK: Borrow<ConfigKey>>(mut self, key: CK, value: String) -> Result<Self, ConfigError> {
        let mut editable = try!(EditableToml::from(self.toml));

        editable.overwrite(key, value);

        self.toml = editable.to_toml();

        Ok(self)
    }

    pub fn validate<CK: Borrow<ConfigKey>, S: AsRef<str>>(key: CK, value: S) -> Result<String, CliError> {
        let value = value.as_ref().trim();

        match *key.borrow() {
            ConfigKey::BurnAfter => {
                let pair = try!(Regex::new(r"^(?P<num>\d+)\s?(?P<unit>days?|weeks?)$"))
                    .captures(value)
                    .map_or((None, None), |caps| (caps.name("num"), caps.name("unit")));
                let (num, unit) = match pair {
                    (Some(num), Some(unit)) => (num, unit),
                    _                       => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
                };
                Ok(format!("{} {}", num, unit))
            },
            ConfigKey::SweepPeriod => {
                match value {
                    "daily" | "weekly" => Ok(value.to_string()),
                    _                  => Err(From::from(ConfigError::new(ConfigErrorKind::SweepPeriod))),
                }
            },
            ConfigKey::SweepTime => {
                match NaiveTime::from_str(format!("{}:00", value).as_ref()) {
                    Ok(_)  => Ok(value.to_string()),
                    // should set Err(e) to Error::cause()
                    Err(_) => Err(From::from(ConfigError::new(ConfigErrorKind::SweepTime))),
                }
            },
        }
    }
}

#[test]
fn config_key_to_pair_should_return_pair() {
    let key1              = ConfigKey::BurnAfter;
    let (first1, second1) = key1.to_pair();
    assert_eq!(CONFIG_KEY_BURN_AFTER.to_string(), format!("{}.{}", first1, second1));

    let key2              = ConfigKey::SweepPeriod;
    let (first2, second2) = key2.to_pair();
    assert_eq!(CONFIG_KEY_SWEEP_PERIOD.to_string(), format!("{}.{}", first2, second2));

    let key3            = ConfigKey::SweepTime;
    let (first3, second3) = key3.to_pair();
    assert_eq!(CONFIG_KEY_SWEEP_TIME.to_string(), format!("{}.{}", first3, second3));

    assert_eq!(first2, first3);
}

#[test]
fn editable_toml_overwrite_should_add_value() {
    let b_tree_map: EditableTomlCore = BTreeMap::new();
    let mut correct                  = b_tree_map.clone();
    let mut editable                 = EditableToml(b_tree_map);

    let v1 = "value1".to_string();

    let mut entry         = BTreeMap::new();
    let key1              = ConfigKey::BurnAfter;
    let (first1, second1) = key1.to_pair();
    entry.insert(second1.to_string(), v1.clone());
    correct.insert(first1.to_string(), entry);

    editable.overwrite(ConfigKey::BurnAfter, v1);
    let EditableToml(calculated) = editable.clone();

    assert_eq!(&correct, &calculated);

    let v2 = "value2".to_string();
    let v3 = "value3".to_string();

    let mut entry         = BTreeMap::new();
    let key2              = ConfigKey::SweepPeriod;
    let (first2, second2) = key2.to_pair();
    let key3              = ConfigKey::SweepTime;
    let (_, second3)      = key3.to_pair();
    entry.insert(second2.to_string(), v2.clone());
    entry.insert(second3.to_string(), v3.clone());
    correct.insert(first2.to_string(), entry);

    editable.overwrite(ConfigKey::SweepPeriod, v2);
    editable.overwrite(ConfigKey::SweepTime  , v3);
    let &EditableToml(ref calculated) = &editable;

    assert_eq!(&correct, calculated);
}

#[test]
fn default_should_return_config() {
}

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

    #[test]
    fn get_should_return_ok() {
    }
    #[test]
    fn get_should_return_err() {
    }

    #[test]
    fn set_should_return_ok() {
    }
    #[test]
    fn set_should_retrun_err() {
    }

    #[test]
    fn to_duration_should_return_ok() {
    }
    #[test]
    fn to_duration_should_return_err() {
    }

    #[test]
    fn validate_should_return_ok() {
    }
    #[test]
    fn validate_should_return_err() {
    }
}
<commit_msg>[Refactoring] Create constants for "config"'s default values<commit_after>extern crate chrono;
extern crate regex;
extern crate toml;

use self::chrono::{Duration, NaiveTime};
use self::regex::Regex;
use self::toml::Value as Toml;

use constant::CONFIG_FILE_NAME;
use error::{CannotHappenError, CliError, ConfigError, ConfigErrorKind};
use lib::io::*;
use std::borrow::Borrow;
use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Error as IoError, Read};
use std::path::PathBuf;
use std::str::FromStr;

const CONFIG_KEY_BURN_AFTER  : &'static str = "burn.after";
const CONFIG_KEY_SWEEP_PERIOD: &'static str = "sweep.period";
const CONFIG_KEY_SWEEP_TIME  : &'static str = "sweep.time";

const CONFIG_DEFAULT_VALUE_BURN_AFTER  : &'static str = "2 weeks";
const CONFIG_DEFAULT_VALUE_SWEEP_PERIOD: &'static str = "daily";
const CONFIG_DEFAULT_VALUE_SWEEP_TIME  : &'static str = "00:00";

pub enum ConfigKey {
    BurnAfter,
    SweepPeriod,
    SweepTime,
}

impl ConfigKey {
    pub fn from<S: AsRef<str>>(key: S) -> Result<ConfigKey, ConfigError> {
        match key.as_ref().trim() {
            CONFIG_KEY_BURN_AFTER   => Ok(ConfigKey::BurnAfter),
            CONFIG_KEY_SWEEP_PERIOD => Ok(ConfigKey::SweepPeriod),
            CONFIG_KEY_SWEEP_TIME   => Ok(ConfigKey::SweepTime),
            _                       => Err(ConfigError::new(ConfigErrorKind::InvalidKey)),
        }
    }

    fn to_str(&self) -> &str {
        match *self {
            ConfigKey::BurnAfter   => CONFIG_KEY_BURN_AFTER,
            ConfigKey::SweepPeriod => CONFIG_KEY_SWEEP_PERIOD,
            ConfigKey::SweepTime   => CONFIG_KEY_SWEEP_TIME,
        }
    }

    fn to_pair(&self) -> (&str, &str) {
        let key = self
            .to_str()
            .split('.')
            .collect::<Vec<&str>>();
        (key[0], key[1]) // unsafe!
    }
}

type EditableTomlCore = BTreeMap<String, BTreeMap<String, String>>;

#[derive(Clone)]
struct EditableToml(EditableTomlCore);

impl EditableToml {
    fn from(toml: Toml) -> Result<Self, ConfigError> {
        toml::decode::<EditableTomlCore>(toml)
            .map(|c| EditableToml(c))
            .ok_or(ConfigError::new(ConfigErrorKind::Something))
    }

    fn overwrite<CK: Borrow<ConfigKey>>(&mut self, key: CK, value: String) {
        let &mut EditableToml(ref mut core) = self;

        let (first, second) = key.borrow().to_pair();
        let second          = second.to_string();

        if core.contains_key(first) {
            core.get_mut(first).map(|e| e.insert(second, value));
        } else {
            let mut entry = BTreeMap::new();
            entry.insert(second, value);

            core.insert(first.to_string(), entry);
        }
    }

    fn to_toml(self) -> Toml {
        let EditableToml(core) = self;
        toml::encode(&core)
    }
}

pub struct Config {
    toml: Toml,
}

impl Config {
    fn path() -> PathBuf {
        path_buf![super::working_dir(), CONFIG_FILE_NAME]
    }

    pub fn exist() -> bool {
        Self::path().is_file()
    }

    fn to_string(&self) -> String {
        toml::encode_str(&self.toml)
    }

    pub fn create(&self) -> Result<(), IoError> {
        print_with_tag(Tag::Info, format!("Create \"{}\" file", CONFIG_FILE_NAME));

        super::create_setting_file(Self::path(), self.to_string())
    }

    fn _new(toml: Toml) -> Self {
        Config { toml: toml }
    }

    pub fn default() -> Self {
        let mut editable = EditableToml(BTreeMap::new());
        editable.overwrite(ConfigKey::BurnAfter  , CONFIG_DEFAULT_VALUE_BURN_AFTER  .to_string());
        editable.overwrite(ConfigKey::SweepPeriod, CONFIG_DEFAULT_VALUE_SWEEP_PERIOD.to_string());
        editable.overwrite(ConfigKey::SweepTime  , CONFIG_DEFAULT_VALUE_SWEEP_TIME  .to_string());

        Self::_new(editable.to_toml())
    }

    pub fn read() -> Result<Self, CliError> {
        print_with_tag(Tag::Info, format!("Read \"{}\" file", CONFIG_FILE_NAME));

        let mut f = try!(File::open(Self::path()));

        let mut contents = String::new();
        try!(f.read_to_string(&mut contents));

        let result = contents
            .parse()
            .map_err(|e: Vec<_>| e.into_iter().next());
        let toml = match result {
            Ok(toml)    => toml,
            Err(option) => match option {
                Some(e) => return Err(From::from(e)),
                None    => return Err(From::from(CannotHappenError)),
            },
        };

        Ok(Self::_new(toml))
    }

    pub fn get<CK: Borrow<ConfigKey>>(&self, key: CK) -> Result<String, CliError> {
        let key = key.borrow();

        let result = self.toml
            .lookup(key.to_str())
            .ok_or(ConfigError::new(match *key {
                ConfigKey::BurnAfter   => ConfigErrorKind::NotFoundBurnAfter,
                ConfigKey::SweepPeriod => unimplemented!(),
                ConfigKey::SweepTime   => unimplemented!(),
            }));
        let value = try!(result);

        value
            .as_str()
            .ok_or(From::from(ConfigError::new(ConfigErrorKind::NonStringValue)))
            .and_then(|s| Self::validate(key, s))
    }

    pub fn to_duration(value: String) -> Result<Duration, CliError> {
        let mut value   = value.split(' ');
        let (num, unit) = match (value.next(), value.next()) {
            (Some(num), Some(unit)) => (num, unit),
            _                       => return Err(From::from(CannotHappenError)),
        };
        let num = try!(num.parse::<u32>()) as i64;

        let duration = match unit {
            "day"  | "days"  => Duration::days(num),
            "week" | "weeks" => Duration::weeks(num),
            _                => return Err(From::from(CannotHappenError)),
        };

        Ok(duration)
    }

    pub fn set<CK: Borrow<ConfigKey>>(mut self, key: CK, value: String) -> Result<Self, ConfigError> {
        let mut editable = try!(EditableToml::from(self.toml));

        editable.overwrite(key, value);

        self.toml = editable.to_toml();

        Ok(self)
    }

    pub fn validate<CK: Borrow<ConfigKey>, S: AsRef<str>>(key: CK, value: S) -> Result<String, CliError> {
        let value = value.as_ref().trim();

        match *key.borrow() {
            ConfigKey::BurnAfter => {
                let pair = try!(Regex::new(r"^(?P<num>\d+)\s?(?P<unit>days?|weeks?)$"))
                    .captures(value)
                    .map_or((None, None), |caps| (caps.name("num"), caps.name("unit")));
                let (num, unit) = match pair {
                    (Some(num), Some(unit)) => (num, unit),
                    _                       => return Err(From::from(ConfigError::new(ConfigErrorKind::BurnAfter))),
                };
                Ok(format!("{} {}", num, unit))
            },
            ConfigKey::SweepPeriod => {
                match value {
                    "daily" | "weekly" => Ok(value.to_string()),
                    _                  => Err(From::from(ConfigError::new(ConfigErrorKind::SweepPeriod))),
                }
            },
            ConfigKey::SweepTime => {
                match NaiveTime::from_str(format!("{}:00", value).as_ref()) {
                    Ok(_)  => Ok(value.to_string()),
                    // should set Err(e) to Error::cause()
                    Err(_) => Err(From::from(ConfigError::new(ConfigErrorKind::SweepTime))),
                }
            },
        }
    }
}

#[test]
fn config_key_to_pair_should_return_pair() {
    let key1              = ConfigKey::BurnAfter;
    let (first1, second1) = key1.to_pair();
    assert_eq!(CONFIG_KEY_BURN_AFTER.to_string(), format!("{}.{}", first1, second1));

    let key2              = ConfigKey::SweepPeriod;
    let (first2, second2) = key2.to_pair();
    assert_eq!(CONFIG_KEY_SWEEP_PERIOD.to_string(), format!("{}.{}", first2, second2));

    let key3            = ConfigKey::SweepTime;
    let (first3, second3) = key3.to_pair();
    assert_eq!(CONFIG_KEY_SWEEP_TIME.to_string(), format!("{}.{}", first3, second3));

    assert_eq!(first2, first3);
}

#[test]
fn editable_toml_overwrite_should_add_value() {
    let b_tree_map: EditableTomlCore = BTreeMap::new();
    let mut correct                  = b_tree_map.clone();
    let mut editable                 = EditableToml(b_tree_map);

    let v1 = "value1".to_string();

    let mut entry         = BTreeMap::new();
    let key1              = ConfigKey::BurnAfter;
    let (first1, second1) = key1.to_pair();
    entry.insert(second1.to_string(), v1.clone());
    correct.insert(first1.to_string(), entry);

    editable.overwrite(ConfigKey::BurnAfter, v1);
    let EditableToml(calculated) = editable.clone();

    assert_eq!(&correct, &calculated);

    let v2 = "value2".to_string();
    let v3 = "value3".to_string();

    let mut entry         = BTreeMap::new();
    let key2              = ConfigKey::SweepPeriod;
    let (first2, second2) = key2.to_pair();
    let key3              = ConfigKey::SweepTime;
    let (_, second3)      = key3.to_pair();
    entry.insert(second2.to_string(), v2.clone());
    entry.insert(second3.to_string(), v3.clone());
    correct.insert(first2.to_string(), entry);

    editable.overwrite(ConfigKey::SweepPeriod, v2);
    editable.overwrite(ConfigKey::SweepTime  , v3);
    let &EditableToml(ref calculated) = &editable;

    assert_eq!(&correct, calculated);
}

#[test]
fn default_should_return_config() {
}

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

    #[test]
    fn get_should_return_ok() {
    }
    #[test]
    fn get_should_return_err() {
    }

    #[test]
    fn set_should_return_ok() {
    }
    #[test]
    fn set_should_retrun_err() {
    }

    #[test]
    fn to_duration_should_return_ok() {
    }
    #[test]
    fn to_duration_should_return_err() {
    }

    #[test]
    fn validate_should_return_ok() {
    }
    #[test]
    fn validate_should_return_err() {
    }
}
<|endoftext|>


<commit_before>// # Snippet example
//
// This example shows how to return a representative snippet of
// your hit result.
// Snippet are an extracted of a target document, and returned in HTML format.
// The keyword searched by the user are highlighted with a `<b>` tag.
extern crate tempdir;

// ---
// Importing tantivy...
#[macro_use]
extern crate tantivy;
use tantivy::collector::TopCollector;
use tantivy::query::QueryParser;
use tantivy::schema::*;
use tantivy::Index;
use tantivy::SnippetGenerator;
use tempdir::TempDir;

fn main() -> tantivy::Result<()> {
    // Let's create a temporary directory for the
    // sake of this example
    let index_path = TempDir::new("tantivy_example_dir")?;

    // # Defining the schema
    let mut schema_builder = SchemaBuilder::default();
    schema_builder.add_text_field("body", TEXT);
    let schema = schema_builder.build();

    // # Indexing documents
    let index = Index::create_in_dir(&index_path, schema.clone())?;

    let mut index_writer = index.writer(50_000_000)?;

    let title = schema.get_field("title").unwrap();
    let body = schema.get_field("body").unwrap();

    // we'll only need one doc for this example.
    index_writer.add_document(doc!(
        title => "Of Mice and Men",
        body => "A few miles south of Soledad, the Salinas River drops in close to the hillside \
                bank and runs deep and green. The water is warm too, for it has slipped twinkling \
                over the yellow sands in the sunlight before reaching the narrow pool. On one \
                side of the river the golden foothill slopes curve up to the strong and rocky \
                Gabilan Mountains, but on the valley side the water is lined with trees—willows \
                fresh and green with every spring, carrying in their lower leaf junctures the \
                debris of the winter’s flooding; and sycamores with mottled, white, recumbent \
                limbs and branches that arch over the pool"
    ));
    // ...
    index_writer.commit()?;

    index.load_searchers()?;

    let searcher = index.searcher();
    let query_parser = QueryParser::for_index(&index, vec![title, body]);
    let query = query_parser.parse_query("sycamore spring")?;

    let mut top_collector = TopCollector::with_limit(10);
    searcher.search(&*query, &mut top_collector)?;

    let snippet_generator = SnippetGenerator::new(&*searcher, &*query, body)?;

    let doc_addresses = top_collector.docs();
    for doc_address in doc_addresses {
        let doc = searcher.doc(&doc_address)?;
        let snippet = snippet_generator.snippet_from_doc(&doc);
        println!("title: {}", doc.get_first(title).unwrap().text().unwrap());
        println!("snippet: {}", snippet.to_html());
    }

    Ok(())
}
<commit_msg>Fixing snippet example<commit_after>// # Snippet example
//
// This example shows how to return a representative snippet of
// your hit result.
// Snippet are an extracted of a target document, and returned in HTML format.
// The keyword searched by the user are highlighted with a `<b>` tag.
extern crate tempdir;

// ---
// Importing tantivy...
#[macro_use]
extern crate tantivy;
use tantivy::collector::TopCollector;
use tantivy::query::QueryParser;
use tantivy::schema::*;
use tantivy::Index;
use tantivy::SnippetGenerator;
use tempdir::TempDir;

fn main() -> tantivy::Result<()> {
    // Let's create a temporary directory for the
    // sake of this example
    let index_path = TempDir::new("tantivy_example_dir")?;

    // # Defining the schema
    let mut schema_builder = SchemaBuilder::default();
    let title = schema_builder.add_text_field("title", TEXT | STORED);
    let body = schema_builder.add_text_field("body", TEXT | STORED);
    let schema = schema_builder.build();

    // # Indexing documents
    let index = Index::create_in_dir(&index_path, schema.clone())?;

    let mut index_writer = index.writer(50_000_000)?;

    // we'll only need one doc for this example.
    index_writer.add_document(doc!(
        title => "Of Mice and Men",
        body => "A few miles south of Soledad, the Salinas River drops in close to the hillside \
                bank and runs deep and green. The water is warm too, for it has slipped twinkling \
                over the yellow sands in the sunlight before reaching the narrow pool. On one \
                side of the river the golden foothill slopes curve up to the strong and rocky \
                Gabilan Mountains, but on the valley side the water is lined with trees—willows \
                fresh and green with every spring, carrying in their lower leaf junctures the \
                debris of the winter’s flooding; and sycamores with mottled, white, recumbent \
                limbs and branches that arch over the pool"
    ));
    // ...
    index_writer.commit()?;

    index.load_searchers()?;

    let searcher = index.searcher();
    let query_parser = QueryParser::for_index(&index, vec![title, body]);
    let query = query_parser.parse_query("sycamore spring")?;

    let mut top_collector = TopCollector::with_limit(10);
    searcher.search(&*query, &mut top_collector)?;

    let snippet_generator = SnippetGenerator::new(&*searcher, &*query, body)?;

    let doc_addresses = top_collector.docs();
    for doc_address in doc_addresses {
        let doc = searcher.doc(&doc_address)?;
        let snippet = snippet_generator.snippet_from_doc(&doc);
        println!("title: {}", doc.get_first(title).unwrap().text().unwrap());
        println!("snippet: {}", snippet.to_html());
    }

    Ok(())
}
<|endoftext|>


<commit_before>use std::collections::HashMap;

use ast::{Function, Expr, Statement};
use rich_number::RichNumber;
use eval_tree_node::EvalTreeNode;
use prelude::setup_prelude;

const LOWEST_PRECEDENCE: u8 = 0;
const HIGHEST_PRECEDENCE: u8 = 9;
const FUNCTION_PRECEDENCE: u8 = HIGHEST_PRECEDENCE;

const FUNCTION_FIXITY: Fixity = Fixity::Prefix;

#[derive(PartialEq, Debug)]
pub enum EvalError {
    UndefinedSymbol(String),
    UnexpectedSymbols,
    ExpectedParams(usize),
    InvalidSymbolDefinition {
        expected_params: usize,
        actual_params: usize,
    },
}

pub type EvalResult = Result<ContextItem, EvalError>;

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

#[derive(PartialEq, Debug, Clone)]
pub enum ContextItem {
    Number(RichNumber),
    Definition {
        // number from 0 to 9 where 9 is the highest precedence
        precedence: u8,
        fixity: Fixity,
        function: Function,
    },
    BuiltInMethod {
        precedence: u8,
        fixity: Fixity,
        params: usize,
        function: fn(Vec<ContextItem>) -> EvalResult,
    },
    Constant(String),
    Boolean(bool),
    Nothing,
}

impl ContextItem {
    /// Creates a Definition ContextItem from a function
    /// with the defaults assumed for all functions
    pub fn function_defaults(function: Function) -> ContextItem {
        ContextItem::Definition {
            precedence: FUNCTION_PRECEDENCE,
            fixity: FUNCTION_FIXITY,
            function: function,
        }
    }

    pub fn unwrap_number(self) -> RichNumber {
        match self {
            ContextItem::Number(num) => num,
            _ => panic!("Expected to unwrap a Number"),
        }
    }

    pub fn unwrap_boolean(self) -> bool {
        match self {
            ContextItem::Boolean(value) => value,
            _ => panic!("Expected to unwrap a Boolean"),
        }
    }

    /// The most reliable way to get the precedence of any ContextItem
    /// ContextItems with no defined precedence return None
    pub fn resolve_precedence(&self) -> Option<&u8> {
        match *self {
            ContextItem::Definition { ref precedence, .. } => Some(precedence),
            ContextItem::BuiltInMethod { ref precedence, .. } => Some(precedence),
            _ => None,
        }
    }

    /// The most reliable way to get the fixity of any ContextItem
    /// ContextItems with no defined fixity return None
    pub fn resolve_fixity(&self) -> Option<Fixity> {
        match *self {
            ContextItem::Definition { fixity, .. } => Some(fixity),
            ContextItem::BuiltInMethod { fixity, .. } => Some(fixity),
            _ => None,
        }
    }

    /// The most reliable way to get the number of parameters of any ContextItem
    /// ContextItems with no defined number of parameters return None
    pub fn resolve_params(&self) -> Option<usize> {
        match *self {
            ContextItem::Definition {
                function: Function {
                    ref params,
                    ..
                },
                ..
            } => Some(params.len()),
            ContextItem::BuiltInMethod { ref params, .. } => Some(*params),
            _ => None,
        }
    }
}

pub struct EvalContext {
    symbol_table: HashMap<String, ContextItem>,
}

impl EvalContext {
    pub fn new() -> EvalContext {
        EvalContext {
            symbol_table: HashMap::new(),
        }
    }

    pub fn prelude() -> EvalContext {
        let mut context = EvalContext::new();
        setup_prelude(&mut context);
        context
    }

    /// Gets a single value without evaluating it from the current context
    pub fn get(&self, name: &str) -> Option<ContextItem> {
        self.symbol_table.get(name).map(|item| (*item).clone())
    }

    /// Convenience method for setting a number in the context
    pub fn set_number(&mut self, name: &str, value: RichNumber) {
        self.set(name, ContextItem::Number(value))
    }

    /// Defines a function in the context
    pub fn define(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        function: Function,
    ) {
        debug_assert!(precedence >= LOWEST_PRECEDENCE && precedence <= HIGHEST_PRECEDENCE);

        self.set(name, ContextItem::Definition {
            fixity: fixity,
            precedence: precedence,
            function: function,
        });
    }

    /// Defines a function linked to actual code rather than an expression
    pub fn define_builtin_method(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        params: usize,
        function: fn(Vec<ContextItem>) -> EvalResult,
    ) {

        self.set(name, ContextItem::BuiltInMethod {
            fixity: fixity,
            precedence: precedence,
            params: params,
            function: function,
        });
    }

    /// Creates a constant value
    pub fn set_constant(&mut self, name: &str, value: String) {
        self.set(name, ContextItem::Constant(value));
    }

    /// Creates a boolean value
    pub fn set_boolean(&mut self, name: &str, value: bool) {
        self.set(name, ContextItem::Boolean(value));
    }

    /// Adds to the current context (silently replaces if already present)
    pub fn set(&mut self, name: &str, value: ContextItem) {
        self.symbol_table.insert(name.to_owned(), value);
    }

    pub fn apply(&mut self, statement: Statement) -> EvalResult {
        match statement {
            Statement::NamedFunction {name, definition} => {
                self.define(&name, FUNCTION_FIXITY, FUNCTION_PRECEDENCE, definition);
                Ok(ContextItem::Nothing)
            },
            Statement::AnonymousFunction(_) => Ok(ContextItem::Nothing),
            Statement::Assignment {name, value} => {
                let value = try!(self.evaluate(value));
                self.set(&name, value);
                Ok(ContextItem::Nothing)
            },
            Statement::Expression(value) => self.evaluate(value),
        }
    }

    fn evaluate(&mut self, expr: Expr) -> EvalResult {
        let root = try!(EvalTreeNode::from_expr(self, expr));

        unimplemented!();
    }

    /// Builds an evaluation tree and returns the root node
    fn build_eval_tree(&self, expr: Expr) -> Result<EvalTreeNode, EvalError> {

        unimplemented!();
    }

}

#[cfg(test)]
mod tests {
    use super::*;
    use ast::*;
    use api::parse;
    use rich_number::RichNumber;

    #[test]
    fn get_set_in_context() {
        let mut context = EvalContext::new();
        assert_eq!(context.get("a"), None);

        let value = RichNumber::from(2f64);
        context.set_number("a", value.clone());
        assert_eq!(context.get("a").map(|n| n.unwrap_number()), Some(value));
    }

    #[test]
    fn define_variable() {
        let mut context = EvalContext::new();
        apply_string(&mut context, "x = 3");

        assert_eq!(context.get("x").map(|n| n.unwrap_number()), Some(RichNumber::from(3f64)));
    }

    #[test]
    fn basic_operators_and_precedence() {
        let result = apply_single("2 * 3 ** 2 - (100e-1 + -77.2) / 13").unwrap();
        assert_eq!(result.unwrap_number(), RichNumber::from(23.1692307692f64));
    }

    fn test_single_boolean(string: &str, expected: bool) {
        let result = apply_single(string).unwrap();
        assert_eq!(result.unwrap_boolean(), expected);
    }

    fn apply_single(string: &str) -> EvalResult {
        let mut context = EvalContext::new();
        let statement = parse_statement(string);

        context.apply(statement)
    }

    fn parse_statement(string: &str) -> Statement {
        let mut parsed = parse(string).unwrap();
        assert!(parsed.len() == 1, "parse_statement() was passed more than one statement");

        parsed.pop().unwrap()
    }

    fn apply_string(mut context: &mut EvalContext, string: &str) {
        apply_program(context, parse(string).unwrap());
    }

    fn apply_program(mut context: &mut EvalContext, program: Program) {
        for statement in program {
            context.apply(statement).expect("Error while applying statement");
        }
    }
}

<commit_msg>Printing out the evaluted tree<commit_after>use std::collections::HashMap;

use ast::{Function, Expr, Statement};
use rich_number::RichNumber;
use eval_tree_node::EvalTreeNode;
use prelude::setup_prelude;

const LOWEST_PRECEDENCE: u8 = 0;
const HIGHEST_PRECEDENCE: u8 = 9;
const FUNCTION_PRECEDENCE: u8 = HIGHEST_PRECEDENCE;

const FUNCTION_FIXITY: Fixity = Fixity::Prefix;

#[derive(PartialEq, Debug)]
pub enum EvalError {
    UndefinedSymbol(String),
    UnexpectedSymbols,
    ExpectedParams(usize),
    InvalidSymbolDefinition {
        expected_params: usize,
        actual_params: usize,
    },
}

pub type EvalResult = Result<ContextItem, EvalError>;

#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub enum Fixity {
    Prefix,
    Infix,
    Postfix,
}

#[derive(PartialEq, Debug, Clone)]
pub enum ContextItem {
    Number(RichNumber),
    Definition {
        // number from 0 to 9 where 9 is the highest precedence
        precedence: u8,
        fixity: Fixity,
        function: Function,
    },
    BuiltInMethod {
        precedence: u8,
        fixity: Fixity,
        params: usize,
        function: fn(Vec<ContextItem>) -> EvalResult,
    },
    Constant(String),
    Boolean(bool),
    Nothing,
}

impl ContextItem {
    /// Creates a Definition ContextItem from a function
    /// with the defaults assumed for all functions
    pub fn function_defaults(function: Function) -> ContextItem {
        ContextItem::Definition {
            precedence: FUNCTION_PRECEDENCE,
            fixity: FUNCTION_FIXITY,
            function: function,
        }
    }

    pub fn unwrap_number(self) -> RichNumber {
        match self {
            ContextItem::Number(num) => num,
            _ => panic!("Expected to unwrap a Number"),
        }
    }

    pub fn unwrap_boolean(self) -> bool {
        match self {
            ContextItem::Boolean(value) => value,
            _ => panic!("Expected to unwrap a Boolean"),
        }
    }

    /// The most reliable way to get the precedence of any ContextItem
    /// ContextItems with no defined precedence return None
    pub fn resolve_precedence(&self) -> Option<&u8> {
        match *self {
            ContextItem::Definition { ref precedence, .. } => Some(precedence),
            ContextItem::BuiltInMethod { ref precedence, .. } => Some(precedence),
            _ => None,
        }
    }

    /// The most reliable way to get the fixity of any ContextItem
    /// ContextItems with no defined fixity return None
    pub fn resolve_fixity(&self) -> Option<Fixity> {
        match *self {
            ContextItem::Definition { fixity, .. } => Some(fixity),
            ContextItem::BuiltInMethod { fixity, .. } => Some(fixity),
            _ => None,
        }
    }

    /// The most reliable way to get the number of parameters of any ContextItem
    /// ContextItems with no defined number of parameters return None
    pub fn resolve_params(&self) -> Option<usize> {
        match *self {
            ContextItem::Definition {
                function: Function {
                    ref params,
                    ..
                },
                ..
            } => Some(params.len()),
            ContextItem::BuiltInMethod { ref params, .. } => Some(*params),
            _ => None,
        }
    }
}

pub struct EvalContext {
    symbol_table: HashMap<String, ContextItem>,
}

impl EvalContext {
    pub fn new() -> EvalContext {
        EvalContext {
            symbol_table: HashMap::new(),
        }
    }

    pub fn prelude() -> EvalContext {
        let mut context = EvalContext::new();
        setup_prelude(&mut context);
        context
    }

    /// Gets a single value without evaluating it from the current context
    pub fn get(&self, name: &str) -> Option<ContextItem> {
        self.symbol_table.get(name).map(|item| (*item).clone())
    }

    /// Convenience method for setting a number in the context
    pub fn set_number(&mut self, name: &str, value: RichNumber) {
        self.set(name, ContextItem::Number(value))
    }

    /// Defines a function in the context
    pub fn define(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        function: Function,
    ) {
        debug_assert!(precedence >= LOWEST_PRECEDENCE && precedence <= HIGHEST_PRECEDENCE);

        self.set(name, ContextItem::Definition {
            fixity: fixity,
            precedence: precedence,
            function: function,
        });
    }

    /// Defines a function linked to actual code rather than an expression
    pub fn define_builtin_method(
        &mut self,
        name: &str,
        fixity: Fixity,
        precedence: u8,
        params: usize,
        function: fn(Vec<ContextItem>) -> EvalResult,
    ) {

        self.set(name, ContextItem::BuiltInMethod {
            fixity: fixity,
            precedence: precedence,
            params: params,
            function: function,
        });
    }

    /// Creates a constant value
    pub fn set_constant(&mut self, name: &str, value: String) {
        self.set(name, ContextItem::Constant(value));
    }

    /// Creates a boolean value
    pub fn set_boolean(&mut self, name: &str, value: bool) {
        self.set(name, ContextItem::Boolean(value));
    }

    /// Adds to the current context (silently replaces if already present)
    pub fn set(&mut self, name: &str, value: ContextItem) {
        self.symbol_table.insert(name.to_owned(), value);
    }

    pub fn apply(&mut self, statement: Statement) -> EvalResult {
        match statement {
            Statement::NamedFunction {name, definition} => {
                self.define(&name, FUNCTION_FIXITY, FUNCTION_PRECEDENCE, definition);
                Ok(ContextItem::Nothing)
            },
            Statement::AnonymousFunction(_) => Ok(ContextItem::Nothing),
            Statement::Assignment {name, value} => {
                let value = try!(self.evaluate(value));
                self.set(&name, value);
                Ok(ContextItem::Nothing)
            },
            Statement::Expression(value) => self.evaluate(value),
        }
    }

    fn evaluate(&mut self, expr: Expr) -> EvalResult {
        let root = try!(EvalTreeNode::from_expr(self, expr));

        println!("{:#?}", root);

        unimplemented!();
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use ast::*;
    use api::parse;
    use rich_number::RichNumber;

    #[test]
    fn get_set_in_context() {
        let mut context = EvalContext::new();
        assert_eq!(context.get("a"), None);

        let value = RichNumber::from(2f64);
        context.set_number("a", value.clone());
        assert_eq!(context.get("a").map(|n| n.unwrap_number()), Some(value));
    }

    #[test]
    fn define_variable() {
        let mut context = EvalContext::new();
        apply_string(&mut context, "x = 3");

        assert_eq!(context.get("x").map(|n| n.unwrap_number()), Some(RichNumber::from(3f64)));
    }

    #[test]
    fn basic_operators_and_precedence() {
        let result = apply_single("2 * 3 ** 2 - (100e-1 + -77.2) / 13").unwrap();
        assert_eq!(result.unwrap_number(), RichNumber::from(23.1692307692f64));
    }

    fn test_single_boolean(string: &str, expected: bool) {
        let result = apply_single(string).unwrap();
        assert_eq!(result.unwrap_boolean(), expected);
    }

    fn apply_single(string: &str) -> EvalResult {
        let mut context = EvalContext::new();
        let statement = parse_statement(string);

        context.apply(statement)
    }

    fn parse_statement(string: &str) -> Statement {
        let mut parsed = parse(string).unwrap();
        assert!(parsed.len() == 1, "parse_statement() was passed more than one statement");

        parsed.pop().unwrap()
    }

    fn apply_string(mut context: &mut EvalContext, string: &str) {
        apply_program(context, parse(string).unwrap());
    }

    fn apply_program(mut context: &mut EvalContext, program: Program) {
        for statement in program {
            context.apply(statement).expect("Error while applying statement");
        }
    }
}

<|endoftext|>


<commit_before>// Copyright 2013-2015 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.

//! Dynamic library facilities.
//!
//! A simple wrapper over the platform's dynamic library facilities

#![unstable(feature = "std_misc")]
#![allow(missing_docs)]

use prelude::v1::*;

use env;
use ffi::{CString, OsString};
use mem;
use path::{Path, PathBuf};

pub struct DynamicLibrary {
    handle: *mut u8
}

impl Drop for DynamicLibrary {
    fn drop(&mut self) {
        match dl::check_for_errors_in(|| {
            unsafe {
                dl::close(self.handle)
            }
        }) {
            Ok(()) => {},
            Err(str) => panic!("{}", str)
        }
    }
}

impl DynamicLibrary {
    // FIXME (#12938): Until DST lands, we cannot decompose &str into
    // & and str, so we cannot usefully take ToCStr arguments by
    // reference (without forcing an additional & around &str). So we
    // are instead temporarily adding an instance for &Path, so that
    // we can take ToCStr as owned. When DST lands, the &Path instance
    // should be removed, and arguments bound by ToCStr should be
    // passed by reference. (Here: in the `open` method.)

    /// Lazily open a dynamic library. When passed None it gives a
    /// handle to the calling process
    pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
        let maybe_library = dl::open(filename.map(|path| path.as_os_str()));

        // The dynamic library must not be constructed if there is
        // an error opening the library so the destructor does not
        // run.
        match maybe_library {
            Err(err) => Err(err),
            Ok(handle) => Ok(DynamicLibrary { handle: handle })
        }
    }

    /// Prepends a path to this process's search path for dynamic libraries
    pub fn prepend_search_path(path: &Path) {
        let mut search_path = DynamicLibrary::search_path();
        search_path.insert(0, path.to_path_buf());
        env::set_var(DynamicLibrary::envvar(), &DynamicLibrary::create_path(&search_path));
    }

    /// From a slice of paths, create a new vector which is suitable to be an
    /// environment variable for this platforms dylib search path.
    pub fn create_path(path: &[PathBuf]) -> OsString {
        let mut newvar = OsString::new();
        for (i, path) in path.iter().enumerate() {
            if i > 0 { newvar.push(DynamicLibrary::separator()); }
            newvar.push(path);
        }
        return newvar;
    }

    /// Returns the environment variable for this process's dynamic library
    /// search path
    pub fn envvar() -> &'static str {
        if cfg!(windows) {
            "PATH"
        } else if cfg!(target_os = "macos") {
            "DYLD_LIBRARY_PATH"
        } else {
            "LD_LIBRARY_PATH"
        }
    }

    fn separator() -> &'static str {
        if cfg!(windows) { ";" } else { ":" }
    }

    /// Returns the current search path for dynamic libraries being used by this
    /// process
    pub fn search_path() -> Vec<PathBuf> {
        match env::var_os(DynamicLibrary::envvar()) {
            Some(var) => env::split_paths(&var).collect(),
            None => Vec::new(),
        }
    }

    /// Accesses the value at the symbol of the dynamic library.
    pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
        // This function should have a lifetime constraint of 'a on
        // T but that feature is still unimplemented

        let raw_string = CString::new(symbol).unwrap();
        let maybe_symbol_value = dl::check_for_errors_in(|| {
            dl::symbol(self.handle, raw_string.as_ptr())
        });

        // The value must not be constructed if there is an error so
        // the destructor does not run.
        match maybe_symbol_value {
            Err(err) => Err(err),
            Ok(symbol_value) => Ok(mem::transmute(symbol_value))
        }
    }
}

#[cfg(all(test, not(target_os = "ios")))]
mod test {
    use super::*;
    use prelude::v1::*;
    use libc;
    use mem;
    use path::Path;

    #[test]
    #[cfg_attr(any(windows, target_os = "android"), ignore)] // FIXME #8818, #10379
    fn test_loading_cosine() {
        // The math library does not need to be loaded since it is already
        // statically linked in
        let libm = match DynamicLibrary::open(None) {
            Err(error) => panic!("Could not load self as module: {}", error),
            Ok(libm) => libm
        };

        let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
            match libm.symbol("cos") {
                Err(error) => panic!("Could not load function cos: {}", error),
                Ok(cosine) => mem::transmute::<*mut u8, _>(cosine)
            }
        };

        let argument = 0.0;
        let expected_result = 1.0;
        let result = cosine(argument);
        if result != expected_result {
            panic!("cos({}) != {} but equaled {} instead", argument,
                   expected_result, result)
        }
    }

    #[test]
    #[cfg(any(target_os = "linux",
              target_os = "macos",
              target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    fn test_errors_do_not_crash() {
        // Open /dev/null as a library to get an error, and make sure
        // that only causes an error, and not a crash.
        let path = Path::new("/dev/null");
        match DynamicLibrary::open(Some(&path)) {
            Err(_) => {}
            Ok(_) => panic!("Successfully opened the empty library.")
        }
    }
}

#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "openbsd"))]
mod dl {
    use prelude::v1::*;

    use ffi::{CStr, OsStr};
    use str;
    use libc;
    use ptr;

    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
        check_for_errors_in(|| {
            unsafe {
                match filename {
                    Some(filename) => open_external(filename),
                    None => open_internal(),
                }
            }
        })
    }

    const LAZY: libc::c_int = 1;

    unsafe fn open_external(filename: &OsStr) -> *mut u8 {
        let s = filename.to_cstring().unwrap();
        dlopen(s.as_ptr(), LAZY) as *mut u8
    }

    unsafe fn open_internal() -> *mut u8 {
        dlopen(ptr::null(), LAZY) as *mut u8
    }

    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
        F: FnOnce() -> T,
    {
        use sync::{StaticMutex, MUTEX_INIT};
        static LOCK: StaticMutex = MUTEX_INIT;
        unsafe {
            // dlerror isn't thread safe, so we need to lock around this entire
            // sequence
            let _guard = LOCK.lock();
            let _old_error = dlerror();

            let result = f();

            let last_error = dlerror() as *const _;
            let ret = if ptr::null() == last_error {
                Ok(result)
            } else {
                let s = CStr::from_ptr(last_error).to_bytes();
                Err(str::from_utf8(s).unwrap().to_string())
            };

            ret
        }
    }

    pub unsafe fn symbol(handle: *mut u8,
                         symbol: *const libc::c_char) -> *mut u8 {
        dlsym(handle as *mut libc::c_void, symbol) as *mut u8
    }
    pub unsafe fn close(handle: *mut u8) {
        dlclose(handle as *mut libc::c_void); ()
    }

    extern {
        fn dlopen(filename: *const libc::c_char,
                  flag: libc::c_int) -> *mut libc::c_void;
        fn dlerror() -> *mut libc::c_char;
        fn dlsym(handle: *mut libc::c_void,
                 symbol: *const libc::c_char) -> *mut libc::c_void;
        fn dlclose(handle: *mut libc::c_void) -> libc::c_int;
    }
}

#[cfg(target_os = "windows")]
mod dl {
    use prelude::v1::*;

    use ffi::OsStr;
    use libc;
    use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
    use sys::os;
    use os::windows::prelude::*;
    use ptr;
    use sys::c::compat::kernel32::SetThreadErrorMode;

    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
        // disable "dll load failed" error dialog.
        let mut use_thread_mode = true;
        let prev_error_mode = unsafe {
            // SEM_FAILCRITICALERRORS 0x01
            let new_error_mode = 1;
            let mut prev_error_mode = 0;
            // Windows >= 7 supports thread error mode.
            let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
            if result == 0 {
                let err = os::errno();
                if err as libc::c_int == ERROR_CALL_NOT_IMPLEMENTED {
                    use_thread_mode = false;
                    // SetThreadErrorMode not found. use fallback solution:
                    // SetErrorMode() Note that SetErrorMode is process-wide so
                    // this can cause race condition!  However, since even
                    // Windows APIs do not care of such problem (#20650), we
                    // just assume SetErrorMode race is not a great deal.
                    prev_error_mode = SetErrorMode(new_error_mode);
                }
            }
            prev_error_mode
        };

        unsafe {
            SetLastError(0);
        }

        let result = match filename {
            Some(filename) => {
                let filename_str: Vec<_> =
                    filename.encode_wide().chain(Some(0).into_iter()).collect();
                let result = unsafe {
                    LoadLibraryW(filename_str.as_ptr() as *const libc::c_void)
                };
                // beware: Vec/String may change errno during drop!
                // so we get error here.
                if result == ptr::null_mut() {
                    let errno = os::errno();
                    Err(os::error_string(errno))
                } else {
                    Ok(result as *mut u8)
                }
            }
            None => {
                let mut handle = ptr::null_mut();
                let succeeded = unsafe {
                    GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &mut handle)
                };
                if succeeded == libc::FALSE {
                    let errno = os::errno();
                    Err(os::error_string(errno))
                } else {
                    Ok(handle as *mut u8)
                }
            }
        };

        unsafe {
            if use_thread_mode {
                SetThreadErrorMode(prev_error_mode, ptr::null_mut());
            } else {
                SetErrorMode(prev_error_mode);
            }
        }

        result
    }

    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
        F: FnOnce() -> T,
    {
        unsafe {
            SetLastError(0);

            let result = f();

            let error = os::errno();
            if 0 == error {
                Ok(result)
            } else {
                Err(format!("Error code {}", error))
            }
        }
    }

    pub unsafe fn symbol(handle: *mut u8, symbol: *const libc::c_char) -> *mut u8 {
        GetProcAddress(handle as *mut libc::c_void, symbol) as *mut u8
    }
    pub unsafe fn close(handle: *mut u8) {
        FreeLibrary(handle as *mut libc::c_void); ()
    }

    #[allow(non_snake_case)]
    extern "system" {
        fn SetLastError(error: libc::size_t);
        fn LoadLibraryW(name: *const libc::c_void) -> *mut libc::c_void;
        fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *const u16,
                              handle: *mut *mut libc::c_void) -> libc::BOOL;
        fn GetProcAddress(handle: *mut libc::c_void,
                          name: *const libc::c_char) -> *mut libc::c_void;
        fn FreeLibrary(handle: *mut libc::c_void);
        fn SetErrorMode(uMode: libc::c_uint) -> libc::c_uint;
    }
}
<commit_msg>Rollup merge of #24706 - tamird:remove-DST-comment, r=alexcrichton<commit_after>// Copyright 2013-2015 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.

//! Dynamic library facilities.
//!
//! A simple wrapper over the platform's dynamic library facilities

#![unstable(feature = "std_misc")]
#![allow(missing_docs)]

use prelude::v1::*;

use env;
use ffi::{CString, OsString};
use mem;
use path::{Path, PathBuf};

pub struct DynamicLibrary {
    handle: *mut u8
}

impl Drop for DynamicLibrary {
    fn drop(&mut self) {
        match dl::check_for_errors_in(|| {
            unsafe {
                dl::close(self.handle)
            }
        }) {
            Ok(()) => {},
            Err(str) => panic!("{}", str)
        }
    }
}

impl DynamicLibrary {
    /// Lazily open a dynamic library. When passed None it gives a
    /// handle to the calling process
    pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
        let maybe_library = dl::open(filename.map(|path| path.as_os_str()));

        // The dynamic library must not be constructed if there is
        // an error opening the library so the destructor does not
        // run.
        match maybe_library {
            Err(err) => Err(err),
            Ok(handle) => Ok(DynamicLibrary { handle: handle })
        }
    }

    /// Prepends a path to this process's search path for dynamic libraries
    pub fn prepend_search_path(path: &Path) {
        let mut search_path = DynamicLibrary::search_path();
        search_path.insert(0, path.to_path_buf());
        env::set_var(DynamicLibrary::envvar(), &DynamicLibrary::create_path(&search_path));
    }

    /// From a slice of paths, create a new vector which is suitable to be an
    /// environment variable for this platforms dylib search path.
    pub fn create_path(path: &[PathBuf]) -> OsString {
        let mut newvar = OsString::new();
        for (i, path) in path.iter().enumerate() {
            if i > 0 { newvar.push(DynamicLibrary::separator()); }
            newvar.push(path);
        }
        return newvar;
    }

    /// Returns the environment variable for this process's dynamic library
    /// search path
    pub fn envvar() -> &'static str {
        if cfg!(windows) {
            "PATH"
        } else if cfg!(target_os = "macos") {
            "DYLD_LIBRARY_PATH"
        } else {
            "LD_LIBRARY_PATH"
        }
    }

    fn separator() -> &'static str {
        if cfg!(windows) { ";" } else { ":" }
    }

    /// Returns the current search path for dynamic libraries being used by this
    /// process
    pub fn search_path() -> Vec<PathBuf> {
        match env::var_os(DynamicLibrary::envvar()) {
            Some(var) => env::split_paths(&var).collect(),
            None => Vec::new(),
        }
    }

    /// Accesses the value at the symbol of the dynamic library.
    pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
        // This function should have a lifetime constraint of 'a on
        // T but that feature is still unimplemented

        let raw_string = CString::new(symbol).unwrap();
        let maybe_symbol_value = dl::check_for_errors_in(|| {
            dl::symbol(self.handle, raw_string.as_ptr())
        });

        // The value must not be constructed if there is an error so
        // the destructor does not run.
        match maybe_symbol_value {
            Err(err) => Err(err),
            Ok(symbol_value) => Ok(mem::transmute(symbol_value))
        }
    }
}

#[cfg(all(test, not(target_os = "ios")))]
mod test {
    use super::*;
    use prelude::v1::*;
    use libc;
    use mem;
    use path::Path;

    #[test]
    #[cfg_attr(any(windows, target_os = "android"), ignore)] // FIXME #8818, #10379
    fn test_loading_cosine() {
        // The math library does not need to be loaded since it is already
        // statically linked in
        let libm = match DynamicLibrary::open(None) {
            Err(error) => panic!("Could not load self as module: {}", error),
            Ok(libm) => libm
        };

        let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
            match libm.symbol("cos") {
                Err(error) => panic!("Could not load function cos: {}", error),
                Ok(cosine) => mem::transmute::<*mut u8, _>(cosine)
            }
        };

        let argument = 0.0;
        let expected_result = 1.0;
        let result = cosine(argument);
        if result != expected_result {
            panic!("cos({}) != {} but equaled {} instead", argument,
                   expected_result, result)
        }
    }

    #[test]
    #[cfg(any(target_os = "linux",
              target_os = "macos",
              target_os = "freebsd",
              target_os = "dragonfly",
              target_os = "bitrig",
              target_os = "openbsd"))]
    fn test_errors_do_not_crash() {
        // Open /dev/null as a library to get an error, and make sure
        // that only causes an error, and not a crash.
        let path = Path::new("/dev/null");
        match DynamicLibrary::open(Some(&path)) {
            Err(_) => {}
            Ok(_) => panic!("Successfully opened the empty library.")
        }
    }
}

#[cfg(any(target_os = "linux",
          target_os = "android",
          target_os = "macos",
          target_os = "ios",
          target_os = "freebsd",
          target_os = "dragonfly",
          target_os = "bitrig",
          target_os = "openbsd"))]
mod dl {
    use prelude::v1::*;

    use ffi::{CStr, OsStr};
    use str;
    use libc;
    use ptr;

    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
        check_for_errors_in(|| {
            unsafe {
                match filename {
                    Some(filename) => open_external(filename),
                    None => open_internal(),
                }
            }
        })
    }

    const LAZY: libc::c_int = 1;

    unsafe fn open_external(filename: &OsStr) -> *mut u8 {
        let s = filename.to_cstring().unwrap();
        dlopen(s.as_ptr(), LAZY) as *mut u8
    }

    unsafe fn open_internal() -> *mut u8 {
        dlopen(ptr::null(), LAZY) as *mut u8
    }

    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
        F: FnOnce() -> T,
    {
        use sync::{StaticMutex, MUTEX_INIT};
        static LOCK: StaticMutex = MUTEX_INIT;
        unsafe {
            // dlerror isn't thread safe, so we need to lock around this entire
            // sequence
            let _guard = LOCK.lock();
            let _old_error = dlerror();

            let result = f();

            let last_error = dlerror() as *const _;
            let ret = if ptr::null() == last_error {
                Ok(result)
            } else {
                let s = CStr::from_ptr(last_error).to_bytes();
                Err(str::from_utf8(s).unwrap().to_string())
            };

            ret
        }
    }

    pub unsafe fn symbol(handle: *mut u8,
                         symbol: *const libc::c_char) -> *mut u8 {
        dlsym(handle as *mut libc::c_void, symbol) as *mut u8
    }
    pub unsafe fn close(handle: *mut u8) {
        dlclose(handle as *mut libc::c_void); ()
    }

    extern {
        fn dlopen(filename: *const libc::c_char,
                  flag: libc::c_int) -> *mut libc::c_void;
        fn dlerror() -> *mut libc::c_char;
        fn dlsym(handle: *mut libc::c_void,
                 symbol: *const libc::c_char) -> *mut libc::c_void;
        fn dlclose(handle: *mut libc::c_void) -> libc::c_int;
    }
}

#[cfg(target_os = "windows")]
mod dl {
    use prelude::v1::*;

    use ffi::OsStr;
    use libc;
    use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
    use sys::os;
    use os::windows::prelude::*;
    use ptr;
    use sys::c::compat::kernel32::SetThreadErrorMode;

    pub fn open(filename: Option<&OsStr>) -> Result<*mut u8, String> {
        // disable "dll load failed" error dialog.
        let mut use_thread_mode = true;
        let prev_error_mode = unsafe {
            // SEM_FAILCRITICALERRORS 0x01
            let new_error_mode = 1;
            let mut prev_error_mode = 0;
            // Windows >= 7 supports thread error mode.
            let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
            if result == 0 {
                let err = os::errno();
                if err as libc::c_int == ERROR_CALL_NOT_IMPLEMENTED {
                    use_thread_mode = false;
                    // SetThreadErrorMode not found. use fallback solution:
                    // SetErrorMode() Note that SetErrorMode is process-wide so
                    // this can cause race condition!  However, since even
                    // Windows APIs do not care of such problem (#20650), we
                    // just assume SetErrorMode race is not a great deal.
                    prev_error_mode = SetErrorMode(new_error_mode);
                }
            }
            prev_error_mode
        };

        unsafe {
            SetLastError(0);
        }

        let result = match filename {
            Some(filename) => {
                let filename_str: Vec<_> =
                    filename.encode_wide().chain(Some(0).into_iter()).collect();
                let result = unsafe {
                    LoadLibraryW(filename_str.as_ptr() as *const libc::c_void)
                };
                // beware: Vec/String may change errno during drop!
                // so we get error here.
                if result == ptr::null_mut() {
                    let errno = os::errno();
                    Err(os::error_string(errno))
                } else {
                    Ok(result as *mut u8)
                }
            }
            None => {
                let mut handle = ptr::null_mut();
                let succeeded = unsafe {
                    GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &mut handle)
                };
                if succeeded == libc::FALSE {
                    let errno = os::errno();
                    Err(os::error_string(errno))
                } else {
                    Ok(handle as *mut u8)
                }
            }
        };

        unsafe {
            if use_thread_mode {
                SetThreadErrorMode(prev_error_mode, ptr::null_mut());
            } else {
                SetErrorMode(prev_error_mode);
            }
        }

        result
    }

    pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
        F: FnOnce() -> T,
    {
        unsafe {
            SetLastError(0);

            let result = f();

            let error = os::errno();
            if 0 == error {
                Ok(result)
            } else {
                Err(format!("Error code {}", error))
            }
        }
    }

    pub unsafe fn symbol(handle: *mut u8, symbol: *const libc::c_char) -> *mut u8 {
        GetProcAddress(handle as *mut libc::c_void, symbol) as *mut u8
    }
    pub unsafe fn close(handle: *mut u8) {
        FreeLibrary(handle as *mut libc::c_void); ()
    }

    #[allow(non_snake_case)]
    extern "system" {
        fn SetLastError(error: libc::size_t);
        fn LoadLibraryW(name: *const libc::c_void) -> *mut libc::c_void;
        fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *const u16,
                              handle: *mut *mut libc::c_void) -> libc::BOOL;
        fn GetProcAddress(handle: *mut libc::c_void,
                          name: *const libc::c_char) -> *mut libc::c_void;
        fn FreeLibrary(handle: *mut libc::c_void);
        fn SetErrorMode(uMode: libc::c_uint) -> libc::c_uint;
    }
}
<|endoftext|>


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

//! A wrapper around any Read to treat it as an RNG.

#![allow(dead_code)]

use io::prelude::*;
use rand::Rng;

/// An RNG that reads random bytes straight from a `Read`. This will
/// work best with an infinite reader, but this is not required.
///
/// # Panics
///
/// It will panic if it there is insufficient data to fulfill a request.
pub struct ReaderRng<R> {
    reader: R
}

impl<R: Read> ReaderRng<R> {
    /// Create a new `ReaderRng` from a `Read`.
    pub fn new(r: R) -> ReaderRng<R> {
        ReaderRng {
            reader: r
        }
    }
}

impl<R: Read> Rng for ReaderRng<R> {
    fn next_u32(&mut self) -> u32 {
        // This is designed for speed: reading a LE integer on a LE
        // platform just involves blitting the bytes into the memory
        // of the u32, similarly for BE on BE; avoiding byteswapping.
        let mut bytes = [0; 4];
        self.fill_bytes(&mut bytes);
        unsafe { *(bytes.as_ptr() as *const u32) }
    }
    fn next_u64(&mut self) -> u64 {
        // see above for explanation.
        let mut bytes = [0; 8];
        self.fill_bytes(&mut bytes);
        unsafe { *(bytes.as_ptr() as *const u64) }
    }
    fn fill_bytes(&mut self, mut v: &mut [u8]) {
        while !v.is_empty() {
            let t = v;
            match self.reader.read(t) {
                Ok(0) => panic!("ReaderRng.fill_bytes: EOF reached"),
                Ok(n) => v = t.split_at_mut(n).1,
                Err(e) => panic!("ReaderRng.fill_bytes: {}", e),
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::ReaderRng;
    use rand::Rng;

    #[test]
    fn test_reader_rng_u64() {
        // transmute from the target to avoid endianness concerns.
        let v = &[0, 0, 0, 0, 0, 0, 0, 1,
                  0, 0, 0, 0, 0, 0, 0, 2,
                  0, 0, 0, 0, 0, 0, 0, 3][..];
        let mut rng = ReaderRng::new(v);

        assert_eq!(rng.next_u64(), 1u64.to_be());
        assert_eq!(rng.next_u64(), 2u64.to_be());
        assert_eq!(rng.next_u64(), 3u64.to_be());
    }
    #[test]
    fn test_reader_rng_u32() {
        let v = &[0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 3][..];
        let mut rng = ReaderRng::new(v);

        assert_eq!(rng.next_u32(), 1u32.to_be());
        assert_eq!(rng.next_u32(), 2u32.to_be());
        assert_eq!(rng.next_u32(), 3u32.to_be());
    }
    #[test]
    fn test_reader_rng_fill_bytes() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8];
        let mut w = [0; 8];

        let mut rng = ReaderRng::new(&v[..]);
        rng.fill_bytes(&mut w);

        assert!(v == w);
    }

    #[test]
    #[should_panic]
    fn test_reader_rng_insufficient_bytes() {
        let mut rng = ReaderRng::new(&[][..]);
        let mut v = [0; 3];
        rng.fill_bytes(&mut v);
    }
}
<commit_msg>Rollup merge of #47443 - FenrirWolf:rand, r=alexcrichton<commit_after><|endoftext|>


<commit_before>// Reference: http://www.redblobgames.com/pathfinding/a-star/introduction.html

use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::cmp::Ordering;
use std::cmp;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct Position {
    pub x: usize,
    pub y: usize
}

// Used to maintain a priority queue of positions to explore.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct PositionPriority {
    minimum_cost: usize,
    position: Position,
}

// The priority queue depends on `Ord`.
impl Ord for PositionPriority {
    // Reverse the comparison so the position with the lowest cost is
    // explored first.
    fn cmp(&self, other: &PositionPriority) -> Ordering {
        other.minimum_cost.cmp(&self.minimum_cost)
    }
}

impl PartialOrd for PositionPriority {
    fn partial_cmp(&self, other: &PositionPriority) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

#[inline]
fn min_distance_heuristic(p1: Position, p2: Position) -> usize {
    let x_diff = match p1.x > p2.x {
        true => p1.x - p2.x,
        false => p2.x - p1.x,
    };
    let y_diff = match p1.y > p2.y {
        true => p1.y - p2.y,
        false => p2.y - p1.y,
    };

    x_diff + y_diff
}

#[inline]
fn neighbours(grid : &Vec<Vec<char>>, pos: Position) -> Vec<Position> {
    let mut v = Vec::new();

    if pos.x > 0 && grid[pos.y][pos.x-1] == ' ' {
        v.push(Position{x: pos.x-1, y: pos.y});
    }
    if pos.x + 1 < grid[pos.y].len() && grid[pos.y][pos.x+1] == ' ' {
        v.push(Position{x: pos.x+1, y: pos.y});
    }

    if pos.y > 0 && pos.x < grid[pos.y-1].len() && grid[pos.y-1][pos.x] == ' ' {
        v.push(Position{x: pos.x, y: pos.y-1});
    }
    if pos.y + 1 < grid.len() &&
       pos.x < grid[pos.y+1].len() &&
       grid[pos.y+1][pos.x] == ' ' {
        v.push(Position{x: pos.x, y: pos.y+1});
    }
    v
}

/// Generate the optimal path from start to goal given a mapping from positions
/// to the position that lead to that position.
#[inline]
fn reconstruct(came_from : &HashMap<Position, Position>,
               start: Position,
               goal: Position) -> Vec<Position> {
    let mut current = goal;
    let mut path = vec![current];
    while current != start {
        current = came_from[&current];
        path.push(current);
    }
    path.reverse();
    path
}

/// Find the optimal path from a starting position to a goal position. Return
/// None if no path is possible. The input grid is a 2-dimensional grid of
/// characters. Any character other than a space is considered an impassable
/// obstacle.
///
/// # Examples
///
/// ```
/// use bestpath::{find_path, Position};
///
/// let grid = vec![vec![' ', '*', '*', ' '],
///                 vec![' ', ' ', ' ', '*'],
///                 vec!['*', '*', ' ', ' '],
///                 vec![' ', '*', ' ', ' ']];
/// assert_eq!(Some(vec![Position{x: 0, y: 0},
///                      Position{x: 0, y: 1},
///                      Position{x: 1, y: 1},
///                      Position{x: 2, y: 1},
///                      Position{x: 2, y: 2}]),
///            find_path(&grid, Position{x: 0, y: 0}, Position{x: 2, y: 2}));
/// assert_eq!(None,
///            find_path(&grid, Position{x: 0, y: 0}, Position{x: 3, y: 0}));
/// ```
#[inline]
pub fn find_path(grid : &Vec<Vec<char>>, start: Position, goal: Position)
        -> Option<Vec<Position>>  {
    let mut frontier = BinaryHeap::new();
    frontier.push(PositionPriority { minimum_cost: 0, position: start });

    let mut came_from = HashMap::new();
    let mut cost_so_far = HashMap::new();
    cost_so_far.insert(start, 0);

    while let Some(PositionPriority { minimum_cost, position }) = frontier.pop() {
        if position == goal {
            return Some(reconstruct(&came_from, start, goal));
        }
        let cost = cost_so_far[&position];

        for next_position in neighbours(grid, position) {
            let new_cost = cost + 1;
            if let Some(existing_cost) = cost_so_far.get(&next_position) {
                if new_cost >= *existing_cost {
                    continue;
                }
            }
            cost_so_far.insert(next_position, new_cost);
            frontier.push(PositionPriority {
                minimum_cost: new_cost +
                    min_distance_heuristic(goal, next_position),
                position: next_position });
            came_from.insert(next_position, position);
        }
    }
    None
}

/// Generate a copy of the given grid with the path filled in. The starting
/// position is shown with a '@' , the goal postiion with a 'X' and all other
/// points on the path with a 'o'.
///
/// # Examples
///
/// ```
/// use bestpath::{find_path, format_path_map, Position};
///
/// let grid = vec![vec![' ', ' ', ' ', ' '],
///                 vec![' ', '*', ' ', '*'],
///                 vec!['*', '*', ' ', ' '],
///                 vec![' ', '*', ' ', ' ']];
/// let path = find_path(&grid,
///                      Position{x: 0, y: 1},
///                      Position{x: 3, y: 2}).unwrap();
/// assert_eq!(vec![vec!['o', 'o', 'o', ' '],
///                 vec!['@', '*', 'o', '*'],
///                 vec!['*', '*', 'o', 'X'],
///                 vec![' ', '*', ' ', ' ']],
///            format_path_map(&grid, &path));
/// ```
#[inline]
pub fn format_path_map(grid : &Vec<Vec<char>>, path: &Vec<Position>)
        -> Vec<Vec<char>> {
    let mut m = grid.clone();
    let last_path = path.len() - 1;
    for (i, p) in path.iter().enumerate() {
        m[p.y][p.x] = match i {
            0 => '@',
            _ if i == last_path => 'X',
            _ => 'o',
        }
    }
    m
}

#[allow(dead_code)]
fn print_grid(grid : &Vec<Vec<char>>) {
    println!("");
    for row in grid {
        for ch in row {
            print!(" {} ", ch);
        }
        println!("");
    }
}

#[test]
fn no_path() {
    let map =
        vec![vec![' ', ' ', '█', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', ' ', '█', '█', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', ' ', ' ', '█', ' ', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', '█', ' '],
             vec!['█', '█', '█', '█', '█', '█', '█'],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map, Position { x: 0, y: 0}, Position { x: 6, y: 6});
    assert_eq!(None, path);
}

#[test]
fn multiple_complex_paths_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', '█', '█', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', '█', ' ', '█', ' ', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', '█', '█', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', ' ', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', '█', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 6, y: 8}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'o', 'o', 'o', ' '],
             vec!['█', '█', ' ', '█', '█', 'o', ' '],
             vec![' ', '█', ' ', '█', '█', 'o', '█'],
             vec![' ', '█', ' ', '█', ' ', 'o', ' '],
             vec![' ', '█', ' ', '█', '█', 'o', '█'],
             vec![' ', '█', '█', ' ', ' ', 'o', 'o'],
             vec!['█', '█', ' ', ' ', '█', '█', 'o'],
             vec![' ', ' ', ' ', ' ', '█', '█', 'o'],
             vec![' ', ' ', ' ', ' ', '█', ' ', 'X']],
        path_map);
}

#[test]
fn verticle_map() {
    let map =
        vec![vec![' '],
             vec![' '],
             vec![' '],
             vec![' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 0, y: 3}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@'],
             vec!['o'],
             vec!['o'],
             vec!['X']],
        path_map);
}

#[test]
fn horizontal_map() {
    let map =
        vec![vec![' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 3, y: 0}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'X']],
        path_map);
}

#[test]
fn straight_diagonal_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 6, y: 6}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(13, path.len())  // There are many equivalent paths.
}

#[test]
fn single_walled_path_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█'],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 0, y: 6}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['█', '█', '█', '█', '█', '█', 'o'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['o', '█', '█', '█', '█', '█', '█'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['█', '█', '█', '█', '█', '█', 'o'],
             vec!['X', 'o', 'o', 'o', 'o', 'o', 'o']],
        path_map);
}

#[test]
fn spiral_wall_path_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█', '█'],
             vec![' ', '█', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', '█', '█', ' '],
             vec![' ', '█', ' ', '█', ' ', ' ', '█', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█', ' '],
             vec![' ', '█', ' ', ' ', ' ', ' ', '█', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 4, y: 4}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['o', '█', '█', '█', '█', '█', '█', '█'],
             vec!['o', '█', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['o', '█', 'o', '█', '█', '█', '█', 'o'],
             vec!['o', '█', 'o', '█', 'X', 'o', '█', 'o'],
             vec!['o', '█', 'o', '█', '█', 'o', '█', 'o'],
             vec!['o', '█', 'o', 'o', 'o', 'o', '█', 'o'],
             vec!['o', '█', '█', '█', '█', '█', '█', 'o'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o']],
        path_map);
}
<commit_msg>Fix some style.<commit_after>// Reference: http://www.redblobgames.com/pathfinding/a-star/introduction.html

use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::cmp::Ordering;
use std::cmp;

#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct Position {
    pub x: usize,
    pub y: usize
}

// Used to maintain a priority queue of positions to explore.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
struct PositionPriority {
    minimum_cost: usize,
    position: Position,
}

// The priority queue depends on `Ord`.
impl Ord for PositionPriority {
    // Reverse the comparison so the position with the lowest cost is
    // explored first.
    fn cmp(&self, other: &PositionPriority) -> Ordering {
        other.minimum_cost.cmp(&self.minimum_cost)
    }
}

impl PartialOrd for PositionPriority {
    fn partial_cmp(&self, other: &PositionPriority) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

#[inline]
fn min_distance_heuristic(p1: Position, p2: Position) -> usize {
    let x_diff = match p1.x > p2.x {
        true => p1.x - p2.x,
        false => p2.x - p1.x,
    };
    let y_diff = match p1.y > p2.y {
        true => p1.y - p2.y,
        false => p2.y - p1.y,
    };

    x_diff + y_diff
}

#[inline]
fn neighbours(grid: &Vec<Vec<char>>, pos: Position) -> Vec<Position> {
    let mut v = Vec::new();

    if pos.x > 0 && grid[pos.y][pos.x-1] == ' ' {
        v.push(Position{x: pos.x-1, y: pos.y});
    }
    if pos.x + 1 < grid[pos.y].len() && grid[pos.y][pos.x+1] == ' ' {
        v.push(Position{x: pos.x+1, y: pos.y});
    }

    if pos.y > 0 && pos.x < grid[pos.y-1].len() && grid[pos.y-1][pos.x] == ' ' {
        v.push(Position{x: pos.x, y: pos.y-1});
    }
    if pos.y + 1 < grid.len() &&
       pos.x < grid[pos.y+1].len() &&
       grid[pos.y+1][pos.x] == ' ' {
        v.push(Position{x: pos.x, y: pos.y+1});
    }
    v
}

/// Generate the optimal path from start to goal given a mapping from positions
/// to the position that lead to that position.
#[inline]
fn reconstruct(came_from: &HashMap<Position, Position>,
               start: Position,
               goal: Position) -> Vec<Position> {
    let mut current = goal;
    let mut path = vec![current];
    while current != start {
        current = came_from[&current];
        path.push(current);
    }
    path.reverse();
    path
}

/// Find the optimal path from a starting position to a goal position. Return
/// None if no path is possible. The input grid is a 2-dimensional grid of
/// characters. Any character other than a space is considered an impassable
/// obstacle.
///
/// # Examples
///
/// ```
/// use bestpath::{find_path, Position};
///
/// let grid = vec![vec![' ', '*', '*', ' '],
///                 vec![' ', ' ', ' ', '*'],
///                 vec!['*', '*', ' ', ' '],
///                 vec![' ', '*', ' ', ' ']];
/// assert_eq!(Some(vec![Position{x: 0, y: 0},
///                      Position{x: 0, y: 1},
///                      Position{x: 1, y: 1},
///                      Position{x: 2, y: 1},
///                      Position{x: 2, y: 2}]),
///            find_path(&grid, Position{x: 0, y: 0}, Position{x: 2, y: 2}));
/// assert_eq!(None,
///            find_path(&grid, Position{x: 0, y: 0}, Position{x: 3, y: 0}));
/// ```
#[inline]
pub fn find_path(grid: &Vec<Vec<char>>, start: Position, goal: Position)
        -> Option<Vec<Position>>  {
    let mut frontier = BinaryHeap::new();
    frontier.push(PositionPriority { minimum_cost: 0, position: start });

    let mut came_from = HashMap::new();
    let mut cost_so_far = HashMap::new();
    cost_so_far.insert(start, 0);

    while let Some(PositionPriority { minimum_cost, position }) = frontier.pop() {
        if position == goal {
            return Some(reconstruct(&came_from, start, goal));
        }
        let cost = cost_so_far[&position];

        for next_position in neighbours(grid, position) {
            let new_cost = cost + 1;
            if let Some(existing_cost) = cost_so_far.get(&next_position) {
                if new_cost >= *existing_cost {
                    continue;
                }
            }
            cost_so_far.insert(next_position, new_cost);
            frontier.push(PositionPriority {
                minimum_cost: new_cost +
                    min_distance_heuristic(goal, next_position),
                position: next_position });
            came_from.insert(next_position, position);
        }
    }
    None
}

/// Generate a copy of the given grid with the path filled in. The starting
/// position is shown with a '@' , the goal postiion with a 'X' and all other
/// points on the path with a 'o'.
///
/// # Examples
///
/// ```
/// use bestpath::{find_path, format_path_map, Position};
///
/// let grid = vec![vec![' ', ' ', ' ', ' '],
///                 vec![' ', '*', ' ', '*'],
///                 vec!['*', '*', ' ', ' '],
///                 vec![' ', '*', ' ', ' ']];
/// let path = find_path(&grid,
///                      Position{x: 0, y: 1},
///                      Position{x: 3, y: 2}).unwrap();
/// assert_eq!(vec![vec!['o', 'o', 'o', ' '],
///                 vec!['@', '*', 'o', '*'],
///                 vec!['*', '*', 'o', 'X'],
///                 vec![' ', '*', ' ', ' ']],
///            format_path_map(&grid, &path));
/// ```
#[inline]
pub fn format_path_map(grid: &Vec<Vec<char>>, path: &Vec<Position>)
        -> Vec<Vec<char>> {
    let mut m = grid.clone();
    let last_path = path.len() - 1;
    for (i, p) in path.iter().enumerate() {
        m[p.y][p.x] = match i {
            0 => '@',
            _ if i == last_path => 'X',
            _ => 'o',
        }
    }
    m
}

#[allow(dead_code)]
fn print_grid(grid: &Vec<Vec<char>>) {
    println!("");
    for row in grid {
        for ch in row {
            print!(" {} ", ch);
        }
        println!("");
    }
}

#[test]
fn no_path() {
    let map =
        vec![vec![' ', ' ', '█', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', ' ', '█', '█', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', ' ', ' ', '█', ' ', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', '█', ' '],
             vec!['█', '█', '█', '█', '█', '█', '█'],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map, Position { x: 0, y: 0}, Position { x: 6, y: 6});
    assert_eq!(None, path);
}

#[test]
fn multiple_complex_paths_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', '█', '█', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', '█', ' ', '█', ' ', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█'],
             vec![' ', '█', '█', ' ', ' ', ' ', ' '],
             vec!['█', '█', ' ', ' ', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', '█', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 6, y: 8}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'o', 'o', 'o', ' '],
             vec!['█', '█', ' ', '█', '█', 'o', ' '],
             vec![' ', '█', ' ', '█', '█', 'o', '█'],
             vec![' ', '█', ' ', '█', ' ', 'o', ' '],
             vec![' ', '█', ' ', '█', '█', 'o', '█'],
             vec![' ', '█', '█', ' ', ' ', 'o', 'o'],
             vec!['█', '█', ' ', ' ', '█', '█', 'o'],
             vec![' ', ' ', ' ', ' ', '█', '█', 'o'],
             vec![' ', ' ', ' ', ' ', '█', ' ', 'X']],
        path_map);
}

#[test]
fn verticle_map() {
    let map =
        vec![vec![' '],
             vec![' '],
             vec![' '],
             vec![' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 0, y: 3}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@'],
             vec!['o'],
             vec!['o'],
             vec!['X']],
        path_map);
}

#[test]
fn horizontal_map() {
    let map =
        vec![vec![' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 3, y: 0}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'X']],
        path_map);
}

#[test]
fn straight_diagonal_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 6, y: 6}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(13, path.len())  // There are many equivalent paths.
}

#[test]
fn single_walled_path_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█'],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 0, y: 6}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['█', '█', '█', '█', '█', '█', 'o'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['o', '█', '█', '█', '█', '█', '█'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['█', '█', '█', '█', '█', '█', 'o'],
             vec!['X', 'o', 'o', 'o', 'o', 'o', 'o']],
        path_map);
}

#[test]
fn spiral_wall_path_to_goal() {
    let map =
        vec![vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█', '█'],
             vec![' ', '█', ' ', ' ', ' ', ' ', ' ', ' '],
             vec![' ', '█', ' ', '█', '█', '█', '█', ' '],
             vec![' ', '█', ' ', '█', ' ', ' ', '█', ' '],
             vec![' ', '█', ' ', '█', '█', ' ', '█', ' '],
             vec![' ', '█', ' ', ' ', ' ', ' ', '█', ' '],
             vec![' ', '█', '█', '█', '█', '█', '█', ' '],
             vec![' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']];

    let path = find_path(&map,
                         Position { x: 0, y: 0},
                         Position { x: 4, y: 4}).unwrap();
    let path_map = format_path_map(&map, &path);
    print_grid(&path_map);
    assert_eq!(
        vec![vec!['@', ' ', ' ', ' ', ' ', ' ', ' ', ' '],
             vec!['o', '█', '█', '█', '█', '█', '█', '█'],
             vec!['o', '█', 'o', 'o', 'o', 'o', 'o', 'o'],
             vec!['o', '█', 'o', '█', '█', '█', '█', 'o'],
             vec!['o', '█', 'o', '█', 'X', 'o', '█', 'o'],
             vec!['o', '█', 'o', '█', '█', 'o', '█', 'o'],
             vec!['o', '█', 'o', 'o', 'o', 'o', '█', 'o'],
             vec!['o', '█', '█', '█', '█', '█', '█', 'o'],
             vec!['o', 'o', 'o', 'o', 'o', 'o', 'o', 'o']],
        path_map);
}
<|endoftext|>