<commit_before>use crate::ty::context::TyCtxt;
use measureme::{StringComponent, StringId};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::SelfProfiler;
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::DefPathData;
use rustc_query_system::query::QueryCache;
use rustc_query_system::query::QueryState;
use std::fmt::Debug;
use std::io::Write;

pub struct QueryKeyStringCache {
    def_id_cache: FxHashMap<DefId, StringId>,
}

impl QueryKeyStringCache {
    pub fn new() -> QueryKeyStringCache {
        QueryKeyStringCache { def_id_cache: Default::default() }
    }
}

pub struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
    profiler: &'p SelfProfiler,
    tcx: TyCtxt<'tcx>,
    string_cache: &'c mut QueryKeyStringCache,
}

impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
    pub fn new(
        profiler: &'p SelfProfiler,
        tcx: TyCtxt<'tcx>,
        string_cache: &'c mut QueryKeyStringCache,
    ) -> QueryKeyStringBuilder<'p, 'c, 'tcx> {
        QueryKeyStringBuilder { profiler, tcx, string_cache }
    }

    // The current implementation is rather crude. In the future it might be a
    // good idea to base this on `ty::print` in order to get nicer and more
    // efficient query keys.
    fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
        if let Some(&string_id) = self.string_cache.def_id_cache.get(&def_id) {
            return string_id;
        }

        let def_key = self.tcx.def_key(def_id);

        let (parent_string_id, start_index) = match def_key.parent {
            Some(parent_index) => {
                let parent_def_id = DefId { index: parent_index, krate: def_id.krate };

                (self.def_id_to_string_id(parent_def_id), 0)
            }
            None => (StringId::INVALID, 2),
        };

        let dis_buffer = &mut [0u8; 16];
        let name;
        let dis;
        let end_index;

        match def_key.disambiguated_data.data {
            DefPathData::CrateRoot => {
                name = self.tcx.original_crate_name(def_id.krate);
                dis = "";
                end_index = 3;
            }
            other => {
                name = other.as_symbol();
                if def_key.disambiguated_data.disambiguator == 0 {
                    dis = "";
                    end_index = 3;
                } else {
                    write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator)
                        .unwrap();
                    let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap();
                    dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap();
                    end_index = 4;
                }
            }
        }

        let name = &*name.as_str();
        let components = [
            StringComponent::Ref(parent_string_id),
            StringComponent::Value("::"),
            StringComponent::Value(name),
            StringComponent::Value(dis),
        ];

        let string_id = self.profiler.alloc_string(&components[start_index..end_index]);

        self.string_cache.def_id_cache.insert(def_id, string_id);

        string_id
    }
}

pub trait IntoSelfProfilingString {
    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId;
}

// The default implementation of `IntoSelfProfilingString` just uses `Debug`
// which is slow and causes lots of duplication of string data.
// The specialized impls below take care of making the `DefId` case more
// efficient.
impl<T: Debug> IntoSelfProfilingString for T {
    default fn to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        let s = format!("{:?}", self);
        builder.profiler.alloc_string(&s[..])
    }
}

impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
        self.spec_to_self_profile_string(builder)
    }
}

#[rustc_specialization_trait]
pub trait SpecIntoSelfProfilingString: Debug {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId;
}

impl SpecIntoSelfProfilingString for DefId {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        builder.def_id_to_string_id(*self)
    }
}

impl SpecIntoSelfProfilingString for CrateNum {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
    }
}

impl SpecIntoSelfProfilingString for DefIndex {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
    }
}

impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
where
    T0: SpecIntoSelfProfilingString,
    T1: SpecIntoSelfProfilingString,
{
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        let val0 = self.0.to_self_profile_string(builder);
        let val1 = self.1.to_self_profile_string(builder);

        let components = &[
            StringComponent::Value("("),
            StringComponent::Ref(val0),
            StringComponent::Value(","),
            StringComponent::Ref(val1),
            StringComponent::Value(")"),
        ];

        builder.profiler.alloc_string(components)
    }
}

/// Allocate the self-profiling query strings for a single query cache. This
/// method is called from `alloc_self_profile_query_strings` which knows all
/// the queries via macro magic.
pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
    tcx: TyCtxt<'tcx>,
    query_name: &'static str,
    query_state: &QueryState<TyCtxt<'tcx>, C>,
    string_cache: &mut QueryKeyStringCache,
) where
    C: QueryCache,
    C::Key: Debug + Clone,
{
    tcx.prof.with_profiler(|profiler| {
        let event_id_builder = profiler.event_id_builder();

        // Walk the entire query cache and allocate the appropriate
        // string representations. Each cache entry is uniquely
        // identified by its dep_node_index.
        if profiler.query_key_recording_enabled() {
            let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache);

            let query_name = profiler.get_or_alloc_cached_string(query_name);

            // Since building the string representation of query keys might
            // need to invoke queries itself, we cannot keep the query caches
            // locked while doing so. Instead we copy out the
            // `(query_key, dep_node_index)` pairs and release the lock again.
            let query_keys_and_indices: Vec<_> = query_state
                .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());

            // Now actually allocate the strings. If allocating the strings
            // generates new entries in the query cache, we'll miss them but
            // we don't actually care.
            for (query_key, dep_node_index) in query_keys_and_indices {
                // Translate the DepNodeIndex into a QueryInvocationId
                let query_invocation_id = dep_node_index.into();

                // Create the string version of the query-key
                let query_key = query_key.to_self_profile_string(&mut query_string_builder);
                let event_id = event_id_builder.from_label_and_arg(query_name, query_key);

                // Doing this in bulk might be a good idea:
                profiler.map_query_invocation_id_to_string(
                    query_invocation_id,
                    event_id.to_string_id(),
                );
            }
        } else {
            // In this branch we don't allocate query keys
            let query_name = profiler.get_or_alloc_cached_string(query_name);
            let event_id = event_id_builder.from_label(query_name).to_string_id();

            query_state.iter_results(|results| {
                let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();

                profiler.bulk_map_query_invocation_id_to_single_string(
                    query_invocation_ids.into_iter(),
                    event_id,
                );
            });
        }
    });
}
<commit_msg>self-profile: Cache more query key strings when doing self-profiling.<commit_after>use crate::ty::context::TyCtxt;
use crate::ty::WithOptConstParam;
use measureme::{StringComponent, StringId};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::SelfProfiler;
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::DefPathData;
use rustc_query_system::query::QueryCache;
use rustc_query_system::query::QueryState;
use std::fmt::Debug;
use std::io::Write;

pub struct QueryKeyStringCache {
    def_id_cache: FxHashMap<DefId, StringId>,
}

impl QueryKeyStringCache {
    pub fn new() -> QueryKeyStringCache {
        QueryKeyStringCache { def_id_cache: Default::default() }
    }
}

pub struct QueryKeyStringBuilder<'p, 'c, 'tcx> {
    profiler: &'p SelfProfiler,
    tcx: TyCtxt<'tcx>,
    string_cache: &'c mut QueryKeyStringCache,
}

impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> {
    pub fn new(
        profiler: &'p SelfProfiler,
        tcx: TyCtxt<'tcx>,
        string_cache: &'c mut QueryKeyStringCache,
    ) -> QueryKeyStringBuilder<'p, 'c, 'tcx> {
        QueryKeyStringBuilder { profiler, tcx, string_cache }
    }

    // The current implementation is rather crude. In the future it might be a
    // good idea to base this on `ty::print` in order to get nicer and more
    // efficient query keys.
    fn def_id_to_string_id(&mut self, def_id: DefId) -> StringId {
        if let Some(&string_id) = self.string_cache.def_id_cache.get(&def_id) {
            return string_id;
        }

        let def_key = self.tcx.def_key(def_id);

        let (parent_string_id, start_index) = match def_key.parent {
            Some(parent_index) => {
                let parent_def_id = DefId { index: parent_index, krate: def_id.krate };

                (self.def_id_to_string_id(parent_def_id), 0)
            }
            None => (StringId::INVALID, 2),
        };

        let dis_buffer = &mut [0u8; 16];
        let name;
        let dis;
        let end_index;

        match def_key.disambiguated_data.data {
            DefPathData::CrateRoot => {
                name = self.tcx.original_crate_name(def_id.krate);
                dis = "";
                end_index = 3;
            }
            other => {
                name = other.as_symbol();
                if def_key.disambiguated_data.disambiguator == 0 {
                    dis = "";
                    end_index = 3;
                } else {
                    write!(&mut dis_buffer[..], "[{}]", def_key.disambiguated_data.disambiguator)
                        .unwrap();
                    let end_of_dis = dis_buffer.iter().position(|&c| c == b']').unwrap();
                    dis = std::str::from_utf8(&dis_buffer[..end_of_dis + 1]).unwrap();
                    end_index = 4;
                }
            }
        }

        let name = &*name.as_str();
        let components = [
            StringComponent::Ref(parent_string_id),
            StringComponent::Value("::"),
            StringComponent::Value(name),
            StringComponent::Value(dis),
        ];

        let string_id = self.profiler.alloc_string(&components[start_index..end_index]);

        self.string_cache.def_id_cache.insert(def_id, string_id);

        string_id
    }
}

pub trait IntoSelfProfilingString {
    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId;
}

// The default implementation of `IntoSelfProfilingString` just uses `Debug`
// which is slow and causes lots of duplication of string data.
// The specialized impls below take care of making the `DefId` case more
// efficient.
impl<T: Debug> IntoSelfProfilingString for T {
    default fn to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        let s = format!("{:?}", self);
        builder.profiler.alloc_string(&s[..])
    }
}

impl<T: SpecIntoSelfProfilingString> IntoSelfProfilingString for T {
    fn to_self_profile_string(&self, builder: &mut QueryKeyStringBuilder<'_, '_, '_>) -> StringId {
        self.spec_to_self_profile_string(builder)
    }
}

#[rustc_specialization_trait]
pub trait SpecIntoSelfProfilingString: Debug {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId;
}

impl SpecIntoSelfProfilingString for DefId {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        builder.def_id_to_string_id(*self)
    }
}

impl SpecIntoSelfProfilingString for CrateNum {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        builder.def_id_to_string_id(DefId { krate: *self, index: CRATE_DEF_INDEX })
    }
}

impl SpecIntoSelfProfilingString for DefIndex {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: *self })
    }
}

impl SpecIntoSelfProfilingString for LocalDefId {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        builder.def_id_to_string_id(DefId { krate: LOCAL_CRATE, index: self.local_def_index })
    }
}

impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> {
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        // We print `WithOptConstParam` values as tuples to make them shorter
        // and more readable, without losing information:
        //
        // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }"
        // becomes "(foo::bar, foo::baz)" and
        // "WithOptConstParam { did: foo::bar, const_param_did: None }"
        // becomes "(foo::bar, _)".

        let did = StringComponent::Ref(self.did.to_self_profile_string(builder));

        let const_param_did = if let Some(const_param_did) = self.const_param_did {
            let const_param_did = builder.def_id_to_string_id(const_param_did);
            StringComponent::Ref(const_param_did)
        } else {
            StringComponent::Value("_")
        };

        let components = [
            StringComponent::Value("("),
            did,
            StringComponent::Value(", "),
            const_param_did,
            StringComponent::Value(")"),
        ];

        builder.profiler.alloc_string(&components[..])
    }
}

impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
where
    T0: SpecIntoSelfProfilingString,
    T1: SpecIntoSelfProfilingString,
{
    fn spec_to_self_profile_string(
        &self,
        builder: &mut QueryKeyStringBuilder<'_, '_, '_>,
    ) -> StringId {
        let val0 = self.0.to_self_profile_string(builder);
        let val1 = self.1.to_self_profile_string(builder);

        let components = &[
            StringComponent::Value("("),
            StringComponent::Ref(val0),
            StringComponent::Value(","),
            StringComponent::Ref(val1),
            StringComponent::Value(")"),
        ];

        builder.profiler.alloc_string(components)
    }
}

/// Allocate the self-profiling query strings for a single query cache. This
/// method is called from `alloc_self_profile_query_strings` which knows all
/// the queries via macro magic.
pub(super) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
    tcx: TyCtxt<'tcx>,
    query_name: &'static str,
    query_state: &QueryState<TyCtxt<'tcx>, C>,
    string_cache: &mut QueryKeyStringCache,
) where
    C: QueryCache,
    C::Key: Debug + Clone,
{
    tcx.prof.with_profiler(|profiler| {
        let event_id_builder = profiler.event_id_builder();

        // Walk the entire query cache and allocate the appropriate
        // string representations. Each cache entry is uniquely
        // identified by its dep_node_index.
        if profiler.query_key_recording_enabled() {
            let mut query_string_builder = QueryKeyStringBuilder::new(profiler, tcx, string_cache);

            let query_name = profiler.get_or_alloc_cached_string(query_name);

            // Since building the string representation of query keys might
            // need to invoke queries itself, we cannot keep the query caches
            // locked while doing so. Instead we copy out the
            // `(query_key, dep_node_index)` pairs and release the lock again.
            let query_keys_and_indices: Vec<_> = query_state
                .iter_results(|results| results.map(|(k, _, i)| (k.clone(), i)).collect());

            // Now actually allocate the strings. If allocating the strings
            // generates new entries in the query cache, we'll miss them but
            // we don't actually care.
            for (query_key, dep_node_index) in query_keys_and_indices {
                // Translate the DepNodeIndex into a QueryInvocationId
                let query_invocation_id = dep_node_index.into();

                // Create the string version of the query-key
                let query_key = query_key.to_self_profile_string(&mut query_string_builder);
                let event_id = event_id_builder.from_label_and_arg(query_name, query_key);

                // Doing this in bulk might be a good idea:
                profiler.map_query_invocation_id_to_string(
                    query_invocation_id,
                    event_id.to_string_id(),
                );
            }
        } else {
            // In this branch we don't allocate query keys
            let query_name = profiler.get_or_alloc_cached_string(query_name);
            let event_id = event_id_builder.from_label(query_name).to_string_id();

            query_state.iter_results(|results| {
                let query_invocation_ids: Vec<_> = results.map(|v| v.2.into()).collect();

                profiler.bulk_map_query_invocation_id_to_single_string(
                    query_invocation_ids.into_iter(),
                    event_id,
                );
            });
        }
    });
}
<|endoftext|>


<commit_before>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::iter::FromIterator;
use std::collections::HashMap;
use std::rc::Rc;
use std::ascii::AsciiExt;
use rustc_serialize::json::{Json, Object, ToJson};
use super::{Error, Result};
use utils::{DateTime, FromRaw};
use metadata::{Date, Field, Keywords, Text};

const CREATED_FIELD: &'static Field = &Date("created") as &Field;
const MODIFIED_FIELD: &'static Field = &Date("modified") as &Field;
const KEYWORDS_FIELD: &'static Field = &Keywords("keywords") as &Field;

#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
pub struct DocumentMetadata {
    pub url: String,
    pub title: String,
    pub language: Option<String>,
    pub modified: Option<DateTime>,
    pub created: Option<DateTime>,
    pub keywords: Vec<String>,
}

impl Default for DocumentMetadata {
    fn default() -> DocumentMetadata {
        DocumentMetadata {
            url: "".into(),
            title: "".into(),
            language: None,
            modified: None,
            created: None,
            keywords: Vec::new(),
        }
    }
}

impl DocumentMetadata {
    pub fn from_raw<T>(raw: T) -> Result<DocumentMetadata>
        where T: Iterator<Item = (String, String)>
    {
        let mut metadata = DocumentMetadata::default();
        let mut raw_metadata: HashMap<String, String> = raw.map(|(key, value)| {
            (key.to_ascii_lowercase(), value)
        }).collect();

        if let Some(title) = raw_metadata.remove("title") {
            metadata.title = title.trim().into();
        }

        if let Some(language) = raw_metadata.remove("language") {
            metadata.language = Some(language.trim().into());
        }

        if let Some(keywords) = raw_metadata.remove("keywords") {
            metadata.keywords = try! { KEYWORDS_FIELD.from_raw(keywords.as_ref()) }.into();
        }

        if let Some(ref created) = raw_metadata.remove("created") {
            metadata.created = try! { CREATED_FIELD.from_raw(created) }.into();
        }

        if let Some(ref modified) = raw_metadata.remove("modified") {
            metadata.modified = try! { MODIFIED_FIELD.from_raw(modified) }.into();
        }

        Ok(metadata)
    }
}

#[test]
fn test_from_raw() {
    let raw_metadata: Vec<(String, String)> = vec! [
        ("title".into(), "Foo bar".into()),
        ("language".into(), "en".into()),
        ("created".into(), "2015-12-23T02:12:35+01:00".into()),
        ("keywords".into(), "foo, bar".into()),
    ];

    let metadata = DocumentMetadata::from_raw(raw_metadata.into_iter());
    assert!(metadata.is_ok());
    if let Ok(result) = metadata {
        assert_eq!(result.title, "Foo bar");
        assert_eq!(result.keywords.as_ref(), ["foo", "bar"]);
    }
}

impl ToJson for DocumentMetadata {
    fn to_json(&self) -> Json {
        let mut obj = Object::new();
        obj.insert("url".into(), self.url.to_json());
        obj.insert("title".into(), self.title.to_json());
        obj.insert("language".into(), self.language.to_json());
        obj.insert("modified".into(), self.modified.to_json());
        obj.insert("created".into(), self.created.to_json());
        obj.insert("keywords".into(), self.keywords.to_json());
        Json::Object(obj)
    }
}

pub enum DocumentContent {
    Text(String),
    Index(Vec<Rc<DocumentMetadata>>),
}

impl From<String> for DocumentContent {
    fn from(text: String) -> DocumentContent {
        DocumentContent::Text(text)
    }
}

impl FromIterator<Rc<DocumentMetadata>> for DocumentContent {
    fn from_iter<T>(documents: T) -> Self where T: IntoIterator<Item=Rc<DocumentMetadata>> {
        DocumentContent::Index(documents.into_iter().collect())
    }
}

pub struct Document {
    pub metadata: DocumentMetadata,
    pub content: DocumentContent,
}

impl Document {
    pub fn new(metadata: DocumentMetadata, content: DocumentContent) -> Document {
        Document { metadata: metadata, content: content }
    }
}

impl ToJson for Document {
    fn to_json(&self) -> Json {
        let mut obj = match self.metadata.to_json() {
            Json::Object(o) => o,
            _ => unreachable!("DocumentMetadata#to_json() must return a Json::Object."),
        };

        match self.content {
            DocumentContent::Text(ref content) => {
                obj.insert("content".into(), content.to_json());
            }
            DocumentContent::Index(ref documents) => {
                obj.insert("documents".into(), Json::Array(documents.iter()
                                                           .map(|doc| doc.to_json())
                                                           .collect()
                                                           ));
            }
        }

        Json::Object(obj)
    }
}

<commit_msg>Remove warnings<commit_after>// Helianto -- static website generator
// Copyright © 2015-2016 Mickaël RAYBAUD-ROIG
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

use std::iter::FromIterator;
use std::collections::HashMap;
use std::rc::Rc;
use std::ascii::AsciiExt;
use rustc_serialize::json::{Json, Object, ToJson};
use super::Result;
use utils::{DateTime, FromRaw};
use metadata::{Date, Field, Keywords};

const CREATED_FIELD: &'static Field = &Date("created") as &Field;
const MODIFIED_FIELD: &'static Field = &Date("modified") as &Field;
const KEYWORDS_FIELD: &'static Field = &Keywords("keywords") as &Field;

#[derive(Debug, Clone, RustcEncodable, RustcDecodable)]
pub struct DocumentMetadata {
    pub url: String,
    pub title: String,
    pub language: Option<String>,
    pub modified: Option<DateTime>,
    pub created: Option<DateTime>,
    pub keywords: Vec<String>,
}

impl Default for DocumentMetadata {
    fn default() -> DocumentMetadata {
        DocumentMetadata {
            url: "".into(),
            title: "".into(),
            language: None,
            modified: None,
            created: None,
            keywords: Vec::new(),
        }
    }
}

impl DocumentMetadata {
    pub fn from_raw<T>(raw: T) -> Result<DocumentMetadata>
        where T: Iterator<Item = (String, String)>
    {
        let mut metadata = DocumentMetadata::default();
        let mut raw_metadata: HashMap<String, String> = raw.map(|(key, value)| {
            (key.to_ascii_lowercase(), value)
        }).collect();

        if let Some(title) = raw_metadata.remove("title") {
            metadata.title = title.trim().into();
        }

        if let Some(language) = raw_metadata.remove("language") {
            metadata.language = Some(language.trim().into());
        }

        if let Some(keywords) = raw_metadata.remove("keywords") {
            metadata.keywords = try! { KEYWORDS_FIELD.from_raw(keywords.as_ref()) }.into();
        }

        if let Some(ref created) = raw_metadata.remove("created") {
            metadata.created = try! { CREATED_FIELD.from_raw(created) }.into();
        }

        if let Some(ref modified) = raw_metadata.remove("modified") {
            metadata.modified = try! { MODIFIED_FIELD.from_raw(modified) }.into();
        }

        Ok(metadata)
    }
}

#[test]
fn test_from_raw() {
    let raw_metadata: Vec<(String, String)> = vec! [
        ("title".into(), "Foo bar".into()),
        ("language".into(), "en".into()),
        ("created".into(), "2015-12-23T02:12:35+01:00".into()),
        ("keywords".into(), "foo, bar".into()),
    ];

    let metadata = DocumentMetadata::from_raw(raw_metadata.into_iter());
    assert!(metadata.is_ok());
    if let Ok(result) = metadata {
        assert_eq!(result.title, "Foo bar");
        assert_eq!(result.keywords.as_ref(), ["foo", "bar"]);
    }
}

impl ToJson for DocumentMetadata {
    fn to_json(&self) -> Json {
        let mut obj = Object::new();
        obj.insert("url".into(), self.url.to_json());
        obj.insert("title".into(), self.title.to_json());
        obj.insert("language".into(), self.language.to_json());
        obj.insert("modified".into(), self.modified.to_json());
        obj.insert("created".into(), self.created.to_json());
        obj.insert("keywords".into(), self.keywords.to_json());
        Json::Object(obj)
    }
}

pub enum DocumentContent {
    Text(String),
    Index(Vec<Rc<DocumentMetadata>>),
}

impl From<String> for DocumentContent {
    fn from(text: String) -> DocumentContent {
        DocumentContent::Text(text)
    }
}

impl FromIterator<Rc<DocumentMetadata>> for DocumentContent {
    fn from_iter<T>(documents: T) -> Self where T: IntoIterator<Item=Rc<DocumentMetadata>> {
        DocumentContent::Index(documents.into_iter().collect())
    }
}

pub struct Document {
    pub metadata: DocumentMetadata,
    pub content: DocumentContent,
}

impl Document {
    pub fn new(metadata: DocumentMetadata, content: DocumentContent) -> Document {
        Document { metadata: metadata, content: content }
    }
}

impl ToJson for Document {
    fn to_json(&self) -> Json {
        let mut obj = match self.metadata.to_json() {
            Json::Object(o) => o,
            _ => unreachable!("DocumentMetadata#to_json() must return a Json::Object."),
        };

        match self.content {
            DocumentContent::Text(ref content) => {
                obj.insert("content".into(), content.to_json());
            }
            DocumentContent::Index(ref documents) => {
                obj.insert("documents".into(), Json::Array(documents.iter()
                                                           .map(|doc| doc.to_json())
                                                           .collect()
                                                           ));
            }
        }

        Json::Object(obj)
    }
}

<|endoftext|>


<commit_before>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::alloc::AllocBox;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum, JsKey, JsPtrTag};
use js_types::js_var::JsType::*;

use jsrs_parser::lalr::parse_Stmt;
use jsrs_common::ast::*;
use jsrs_common::ast::Exp::*;
use jsrs_common::ast::BinOp::*;
use jsrs_common::ast::Stmt::*;

type VarWithPtr = (JsVar, Option<JsPtrEnum>);

// Helper to avoid repeating this everywhere
fn scalar(v: JsType) -> (JsVar, Option<JsPtrEnum>) {
    (JsVar::new(v), None)
}

/// Evaluate a string containing some JavaScript statements (or sequences of statements).
/// Returns a JsVar which is the return value of those statements.
pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => {
            eval_stmt(&stmt, state).0
        }
        Err(e) => panic!("parse error: {:?}", e),
    }
}

/// Evaluate a single JS statement (which may be a block or sequence of statements).
/// Returns tuple of (evaluated final value, return value), where return value requires that
/// `return` be used to generate it.
pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> (JsVar, Option<JsVar>) {
    match *s {
        // var_string = exp;
        Assign(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());

            // Clone the js_var to store into the ScopeManager
            let cloned = js_var.clone();
            match state.alloc(cloned, js_ptr) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

        // exp;
        BareExp(ref exp) => (eval_exp(exp, &mut state).0, None),

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            match state.alloc(js_var.clone(), js_ptr) {
                Ok(_) => (js_var, None),
                e @ Err(_) => panic!("{:?}", e),
            }
        },

        // Empty statement (?)
        Empty => (JsVar::new(JsUndef), None),

        // if (condition) { if_block } else { else_block }
        If(ref condition, ref if_block, ref else_block) => {
            // evaluate expression
            if eval_exp(&condition, state).0.as_bool() {
                // condition = true, evaluate if-block.
                eval_stmt(&*if_block, state)
            } else {
                // condition = false
                // evaluate else-block if it exists, otherwise return undefined.
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    (JsVar::new(JsUndef), None)
                }
            }
        },

        // return exp
        Ret(ref exp) => {
            let js_var = eval_exp(&exp, &mut state).0;
            (js_var.clone(), Some(js_var))
        }

        // a sequence of any two expressions
        Seq(ref s1, ref s2) => {
            eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },

        // while (condition) { block }
        While(ref condition, ref block) => {
            let mut ret_val = None;
            loop {
                if eval_exp(&condition, state).0.as_bool() {
                    // TODO: check to see if a return stmt has been reached.
                    let (_, v) = eval_stmt(&*block, state);
                    ret_val = v;
                } else {
                    // condition is no longer true, return a return value
                    return (JsVar::new(JsUndef), ret_val);
                }
            }
        }
    }
}

/// Evaluate an expression into a JsVar.
pub fn eval_exp(e: &Exp, mut state: &mut ScopeManager) -> (JsVar, Option<JsPtrEnum>) {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state).0;
            let val2 = eval_exp(e2, state).0;

            match *op {
                And => scalar(JsBool(val1.as_bool() && val2.as_bool())),
                Or  => scalar(JsBool(val1.as_bool() || val2.as_bool())),

                Ge  => scalar(JsBool(val1.as_bool() >= val2.as_bool())),
                Gt  => scalar(JsBool(val1.as_bool() >  val2.as_bool())),
                Le  => scalar(JsBool(val1.as_bool() <= val2.as_bool())),
                Lt  => scalar(JsBool(val1.as_bool() <  val2.as_bool())),
                Neq => scalar(JsBool(val1.as_bool() != val2.as_bool())),
                Eql => scalar(JsBool(val1.as_bool() == val2.as_bool())),

                Minus => scalar(JsNum(val1.as_number() - val2.as_number())),
                Plus  => scalar(JsNum(val1.as_number() + val2.as_number())),
                Slash => scalar(JsNum(val1.as_number() / val2.as_number())),
                Star  => scalar(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => scalar(JsBool(b)),

        // fun_name([arg_exp1, arg_exps])
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state).0;

            // Create vector of arguments, evaluated to JsVars.
            let mut args = Vec::new();
            for exp in arg_exps {
                args.push(eval_exp(exp, state));
            }

            match state.load(&fun_binding.binding) {
                Ok((_, Some(JsPtrEnum::JsFn(js_fn_struct)))) => {
                    state.push_scope(e);

                    for param in js_fn_struct.params {
                        let mut arg = if args.is_empty() {
                            scalar(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.0.binding = Binding::new(param.to_owned());
                        state.alloc(arg.0, arg.1)
                            .expect("Unable to store function argument in scope");
                    }

                    let (_, v) = eval_stmt(&js_fn_struct.stmt, state);

                    // Should we yield here? Not sure, so for now it doesn't
                    state.pop_scope(false).expect("Unable to clear scope for function");
                    // TODO handle obj
                    v.map(|x| (x, None)).unwrap_or(scalar(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {:?} is not defined", fun_name)
            }
        },

        // function([param1, params]) { body }
        // function opt_binding([param1, params]) { body }
        &Defun(ref opt_binding, ref params, ref body) => {
            if let &Some(ref binding) = opt_binding {
                let js_fun = JsFnStruct::new(opt_binding, params, &**body);
                state.alloc(JsVar::bind(binding.to_owned(), JsPtr(JsPtrTag::JsFn)),
                    Some(JsPtrEnum::JsFn(js_fun.clone())))
                    .expect("Error storing function into state");
                (JsVar::bind(binding.to_owned(), JsPtr(JsPtrTag::JsFn)),
                Some(JsPtrEnum::JsFn(js_fun)))
            } else {
                panic!("functions without bindings are not yet supported.")
            }
        },

        // var.binding
        &InstanceVar(ref instance_exp, ref var) => {
            // TODO: this needs better type-reasoning and errors
            let (instance_var, var_ptr) = eval_exp(instance_exp, state);
            if let JsPtr(_) = instance_var.t {
                if let Some(JsPtrEnum::JsObj(obj_struct)) = var_ptr {
                    let try_inner_var = obj_struct.dict.get(&JsKey::JsStr(JsStrStruct::new(var)));
                    if let Some(inner_var) = try_inner_var {
                        return (inner_var.clone(), None);
                    }
                } else {
                }
            } else {
                panic!("illegal access of instance variable"); // TODO: better error here?
            }
        },

        &Method(_, _, _) => {
            unimplemented!();
        },

        &Null => {
            scalar(JsNull)
        },

        &Float(f) => scalar(JsType::JsNum(f)),
        &Neg(ref exp) => scalar(JsNum(-eval_exp(exp, state).0.as_number())),
        &Pos(ref exp) => scalar(JsNum(eval_exp(exp, state).0.as_number())),

        &PostDec(ref exp) => (eval_float_post_op!(exp, f, f - 1.0, state), None),
        &PostInc(ref exp) => (eval_float_post_op!(exp, f, f + 1.0, state), None),
        &PreDec(ref exp)  => (eval_float_pre_op!(exp, f, f - 1.0, state),  None),
        &PreInc(ref exp)  => (eval_float_pre_op!(exp, f, f + 1.0, state),  None),

        &NewObject(_, _) => unimplemented!(),
        &Object(ref fields) => {
            let mut kv_tuples = Vec::new();
            for f in fields {
                let f_key = JsKey::JsStr(JsStrStruct::new(&f.0));
                // TODO: handle obj as key/value pair
                let f_exp = eval_exp(&*f.1, state).0;
                kv_tuples.push((f_key, f_exp, None));
            }
            let obj = JsObjStruct::new(None, "", kv_tuples, &mut AllocBox::new());
            (JsVar::new(JsPtr(JsPtrTag::JsObj)), Some(JsPtrEnum::JsObj(obj)))
        },

        &Undefined => scalar(JsUndef),
        &Var(ref var_binding) => {
            state.load(&Binding::new(var_binding.clone()))
                .expect("ReferenceError: {} is not defined")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::hash_set::HashSet;
    use french_press::init_gc;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(5.0f64), eval_string("5.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.0f64), eval_string("0.0;\n", &mut state).t);
        assert_eq!(JsType::JsUndef, eval_string("undefined;\n", &mut state).t);
    }

    //// TODO: handle `var` and no `var` separately
    //#[test]
    //fn test_store_state() {
    //    let mut state = HashMap::new();
    //    assert_eq!(JsUndefined, eval_string("var a = 1;\n", &mut state));
    //    assert_eq!(JsNumber(2.0f64), eval_string("a = 2;\n", &mut state));
    //    assert_eq!(JsUndefined, eval_string("var b = 3;\n", &mut state));
    //    assert_eq!(JsNumber(4.0f64), eval_string("c = 4;\n", &mut state));
    //}

    #[test]
    fn test_inc_dec() {
        let mut state = init_gc();
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.load(&Binding::new("a")).unwrap());

        //assert_eq!(JsType::JsNum(1.0f64), eval_string("a++;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("++a;\n", &mut state));
        //assert_eq!(&JsNumber(3.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("a--;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(1.0f64), eval_string("--a;\n", &mut state));
        //assert_eq!(&JsNumber(1.0f64), state.get("a").unwrap());
    }

    #[test]
    fn test_binexp() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(6.0f64),  eval_string("2.0 + 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.5f64),  eval_string("2.0 / 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(-2.0f64), eval_string("2.0 - 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(8.0f64),  eval_string("2.0 * 4.0;\n", &mut state).t);
    }
}
<commit_msg>Fix build?<commit_after>#[macro_use]
mod macros;

use coerce::{AsBool,AsNumber};

use french_press::ScopeManager;
use french_press::alloc::AllocBox;
use js_types::binding::Binding;
use js_types::js_fn::JsFnStruct;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_var::{JsVar, JsType, JsPtrEnum, JsKey, JsPtrTag};
use js_types::js_var::JsType::*;

use jsrs_parser::lalr::parse_Stmt;
use jsrs_common::ast::*;
use jsrs_common::ast::Exp::*;
use jsrs_common::ast::BinOp::*;
use jsrs_common::ast::Stmt::*;

type VarWithPtr = (JsVar, Option<JsPtrEnum>);

// Helper to avoid repeating this everywhere
fn scalar(v: JsType) -> (JsVar, Option<JsPtrEnum>) {
    (JsVar::new(v), None)
}

/// Evaluate a string containing some JavaScript statements (or sequences of statements).
/// Returns a JsVar which is the return value of those statements.
pub fn eval_string(string: &str, state: &mut ScopeManager) -> JsVar {
    match parse_Stmt(string) {
        Ok(stmt) => {
            eval_stmt(&stmt, state).0
        }
        Err(e) => panic!("parse error: {:?}", e),
    }
}

/// Evaluate a single JS statement (which may be a block or sequence of statements).
/// Returns tuple of (evaluated final value, return value), where return value requires that
/// `return` be used to generate it.
pub fn eval_stmt(s: &Stmt, mut state: &mut ScopeManager) -> (JsVar, Option<JsVar>) {
    match *s {
        // var_string = exp;
        Assign(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());

            // Clone the js_var to store into the ScopeManager
            let cloned = js_var.clone();
            match state.alloc(cloned, js_ptr) {
                Ok(_) => (),
                e @ Err(_) => println!("{:?}", e),
            }

            (js_var, None)
        },

        // exp;
        BareExp(ref exp) => (eval_exp(exp, &mut state).0, None),

        // var var_string = exp
        Decl(ref var_string, ref exp) => {
            let (mut js_var, js_ptr) = eval_exp(exp, state);
            js_var.binding = Binding::new(var_string.clone());
            match state.alloc(js_var.clone(), js_ptr) {
                Ok(_) => (js_var, None),
                e @ Err(_) => panic!("{:?}", e),
            }
        },

        // Empty statement (?)
        Empty => (JsVar::new(JsUndef), None),

        // if (condition) { if_block } else { else_block }
        If(ref condition, ref if_block, ref else_block) => {
            // evaluate expression
            if eval_exp(&condition, state).0.as_bool() {
                // condition = true, evaluate if-block.
                eval_stmt(&*if_block, state)
            } else {
                // condition = false
                // evaluate else-block if it exists, otherwise return undefined.
                if let Some(ref block) = *else_block {
                    eval_stmt(&*block, state)
                } else {
                    (JsVar::new(JsUndef), None)
                }
            }
        },

        // return exp
        Ret(ref exp) => {
            let js_var = eval_exp(&exp, &mut state).0;
            (js_var.clone(), Some(js_var))
        }

        // a sequence of any two expressions
        Seq(ref s1, ref s2) => {
            eval_stmt(&*s1, &mut state);
            eval_stmt(&*s2, &mut state)
        },

        // while (condition) { block }
        While(ref condition, ref block) => {
            let mut ret_val = None;
            loop {
                if eval_exp(&condition, state).0.as_bool() {
                    // TODO: check to see if a return stmt has been reached.
                    let (_, v) = eval_stmt(&*block, state);
                    ret_val = v;
                } else {
                    // condition is no longer true, return a return value
                    return (JsVar::new(JsUndef), ret_val);
                }
            }
        }
    }
}

/// Evaluate an expression into a JsVar.
pub fn eval_exp(e: &Exp, mut state: &mut ScopeManager) -> (JsVar, Option<JsPtrEnum>) {
    match e {
        // e1 [op] e2
        &BinExp(ref e1, ref op, ref e2) => {
            let val1 = eval_exp(e1, state).0;
            let val2 = eval_exp(e2, state).0;

            match *op {
                And => scalar(JsBool(val1.as_bool() && val2.as_bool())),
                Or  => scalar(JsBool(val1.as_bool() || val2.as_bool())),

                Ge  => scalar(JsBool(val1.as_bool() >= val2.as_bool())),
                Gt  => scalar(JsBool(val1.as_bool() >  val2.as_bool())),
                Le  => scalar(JsBool(val1.as_bool() <= val2.as_bool())),
                Lt  => scalar(JsBool(val1.as_bool() <  val2.as_bool())),
                Neq => scalar(JsBool(val1.as_bool() != val2.as_bool())),
                Eql => scalar(JsBool(val1.as_bool() == val2.as_bool())),

                Minus => scalar(JsNum(val1.as_number() - val2.as_number())),
                Plus  => scalar(JsNum(val1.as_number() + val2.as_number())),
                Slash => scalar(JsNum(val1.as_number() / val2.as_number())),
                Star  => scalar(JsNum(val1.as_number() * val2.as_number())),
            }
        }
        &Bool(b) => scalar(JsBool(b)),

        // fun_name([arg_exp1, arg_exps])
        &Call(ref fun_name, ref arg_exps) => {
            let fun_binding = eval_exp(fun_name, state).0;

            // Create vector of arguments, evaluated to JsVars.
            let mut args = Vec::new();
            for exp in arg_exps {
                args.push(eval_exp(exp, state));
            }

            match state.load(&fun_binding.binding) {
                Ok((_, Some(JsPtrEnum::JsFn(js_fn_struct)))) => {
                    state.push_scope(e);

                    for param in js_fn_struct.params {
                        let mut arg = if args.is_empty() {
                            scalar(JsUndef)
                        } else {
                            args.remove(0)
                        };

                        arg.0.binding = Binding::new(param.to_owned());
                        state.alloc(arg.0, arg.1)
                            .expect("Unable to store function argument in scope");
                    }

                    let (_, v) = eval_stmt(&js_fn_struct.stmt, state);

                    // Should we yield here? Not sure, so for now it doesn't
                    state.pop_scope(false).expect("Unable to clear scope for function");
                    // TODO handle obj
                    v.map(|x| (x, None)).unwrap_or(scalar(JsUndef))
                }
                Ok(_) => panic!("Invalid call object"),
                _ => panic!("ReferenceError: {:?} is not defined", fun_name)
            }
        },

        // function([param1, params]) { body }
        // function opt_binding([param1, params]) { body }
        &Defun(ref opt_binding, ref params, ref body) => {
            if let &Some(ref binding) = opt_binding {
                let js_fun = JsFnStruct::new(opt_binding, params, &**body);
                state.alloc(JsVar::bind(binding.to_owned(), JsPtr(JsPtrTag::JsFn)),
                    Some(JsPtrEnum::JsFn(js_fun.clone())))
                    .expect("Error storing function into state");
                (JsVar::bind(binding.to_owned(), JsPtr(JsPtrTag::JsFn)),
                Some(JsPtrEnum::JsFn(js_fun)))
            } else {
                panic!("functions without bindings are not yet supported.")
            }
        },

        // var.binding
        &InstanceVar(ref instance_exp, ref var) => {
            // TODO: this needs better type-reasoning and errors
            let (instance_var, var_ptr) = eval_exp(instance_exp, state);
            if let JsPtr(_) = instance_var.t {
                if let Some(JsPtrEnum::JsObj(obj_struct)) = var_ptr {
                    let try_inner_var = obj_struct.dict.get(&JsKey::JsStr(JsStrStruct::new(var)));
                    if let Some(inner_var) = try_inner_var {
                        return (inner_var.clone(), None);
                    } else {
                        panic!("illegal access of instance variable"); // TODO: better error here?
                    }
                } else {
                    panic!("illegal access of instance variable"); // TODO: better error here?
                }
            } else {
                panic!("illegal access of instance variable"); // TODO: better error here?
            }
        },

        &Method(_, _, _) => {
            unimplemented!();
        },

        &Null => {
            scalar(JsNull)
        },

        &Float(f) => scalar(JsType::JsNum(f)),
        &Neg(ref exp) => scalar(JsNum(-eval_exp(exp, state).0.as_number())),
        &Pos(ref exp) => scalar(JsNum(eval_exp(exp, state).0.as_number())),

        &PostDec(ref exp) => (eval_float_post_op!(exp, f, f - 1.0, state), None),
        &PostInc(ref exp) => (eval_float_post_op!(exp, f, f + 1.0, state), None),
        &PreDec(ref exp)  => (eval_float_pre_op!(exp, f, f - 1.0, state),  None),
        &PreInc(ref exp)  => (eval_float_pre_op!(exp, f, f + 1.0, state),  None),

        &NewObject(_, _) => unimplemented!(),
        &Object(ref fields) => {
            let mut kv_tuples = Vec::new();
            for f in fields {
                let f_key = JsKey::JsStr(JsStrStruct::new(&f.0));
                // TODO: handle obj as key/value pair
                let f_exp = eval_exp(&*f.1, state).0;
                kv_tuples.push((f_key, f_exp, None));
            }
            let obj = JsObjStruct::new(None, "", kv_tuples, &mut AllocBox::new());
            (JsVar::new(JsPtr(JsPtrTag::JsObj)), Some(JsPtrEnum::JsObj(obj)))
        },

        &Undefined => scalar(JsUndef),
        &Var(ref var_binding) => {
            state.load(&Binding::new(var_binding.clone()))
                .expect("ReferenceError: {} is not defined")
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use std::collections::hash_set::HashSet;
    use french_press::init_gc;
    use js_types::js_var::JsType;
    use js_types::binding::Binding;

    #[test]
    fn test_eval_literals() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(5.0f64), eval_string("5.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.0f64), eval_string("0.0;\n", &mut state).t);
        assert_eq!(JsType::JsUndef, eval_string("undefined;\n", &mut state).t);
    }

    //// TODO: handle `var` and no `var` separately
    //#[test]
    //fn test_store_state() {
    //    let mut state = HashMap::new();
    //    assert_eq!(JsUndefined, eval_string("var a = 1;\n", &mut state));
    //    assert_eq!(JsNumber(2.0f64), eval_string("a = 2;\n", &mut state));
    //    assert_eq!(JsUndefined, eval_string("var b = 3;\n", &mut state));
    //    assert_eq!(JsNumber(4.0f64), eval_string("c = 4;\n", &mut state));
    //}

    #[test]
    fn test_inc_dec() {
        let mut state = init_gc();
        //assert_eq!(JsType::JsNum(1.0f64), eval_string("var a = 1;\n", &mut state).t);
        //assert_eq!(&JsType::JsNum(1.0), state.load(&Binding::new("a")).unwrap());

        //assert_eq!(JsType::JsNum(1.0f64), eval_string("a++;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("++a;\n", &mut state));
        //assert_eq!(&JsNumber(3.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(3.0f64), eval_string("a--;\n", &mut state));
        //assert_eq!(&JsNumber(2.0f64), state.get("a").unwrap());

        //assert_eq!(JsNumber(1.0f64), eval_string("--a;\n", &mut state));
        //assert_eq!(&JsNumber(1.0f64), state.get("a").unwrap());
    }

    #[test]
    fn test_binexp() {
        let mut state = init_gc();
        assert_eq!(JsType::JsNum(6.0f64),  eval_string("2.0 + 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(0.5f64),  eval_string("2.0 / 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(-2.0f64), eval_string("2.0 - 4.0;\n", &mut state).t);
        assert_eq!(JsType::JsNum(8.0f64),  eval_string("2.0 * 4.0;\n", &mut state).t);
    }
}
<|endoftext|>


<commit_before>//! Work in progress implementation of executors for Futures.
//!
//! Note that this interface is very likely to change and not stay as-is, and it
//! is not currently used much by futures beyond `DEFAULT`.

use std::cell::{Cell, RefCell};
use std::sync::Arc;

/// Encapsulation of a value which has the ability to execute arbitrary code.
///
/// This trait is object safe and intended to be used through pointers like
/// `Box` and `Arc.
pub trait Executor: Send + Sync + 'static {
    /// Executes the given closure `f`, perhaps on a different thread or
    /// deferred to a later time.
    ///
    /// This method may not execute `f` immediately, but it will arrange for the
    /// callback to be invoked "in the near future".
    fn execute<F>(&self, f: F)
        where F: FnOnce() + Send + 'static,
              Self: Sized
    {
        self.execute_boxed(Box::new(f))
    }

    /// Object-safe method of the above interface used when implementing trait
    /// objects.
    ///
    /// This should not be called direclty and instead `execute` should be used.
    fn execute_boxed(&self, f: Box<ExecuteCallback>);
}

/// The default executor, used by futures by default currently.
pub static DEFAULT: Limited = Limited;

impl<T: Executor + ?Sized + Send + Sync + 'static> Executor for Box<T> {
    fn execute_boxed(&self, f: Box<ExecuteCallback>) {
        (**self).execute_boxed(f)
    }
}

impl<T: Executor + ?Sized + Send + Sync + 'static> Executor for Arc<T> {
    fn execute_boxed(&self, f: Box<ExecuteCallback>) {
        (**self).execute_boxed(f)
    }
}

/// Essentially `Box<FnOnce() + Send>`, just as a trait.
pub trait ExecuteCallback: Send + 'static {
    #[allow(missing_docs)]
    fn call(self: Box<Self>);
}

impl<F: FnOnce() + Send + 'static> ExecuteCallback for F {
    fn call(self: Box<F>) {
        (*self)()
    }
}

/// Implementation of an `Executor` which just executes everything immediately
/// as soon as it's passed in.
pub struct Inline;

impl Executor for Inline {
    fn execute<F: FnOnce() + Send + 'static>(&self, f: F) {
        f()
    }

    fn execute_boxed(&self, f: Box<ExecuteCallback>) {
        f.call()
    }
}

/// Implementation of an executor which executes all callbacks immediately, but
/// bounds the amount of recursion to prevent blowing the stack.
pub struct Limited;

thread_local!(static LIMITED: LimitState = LimitState::new());

const LIMIT: usize = 100;

struct LimitState {
    count: Cell<usize>,
    deferred: RefCell<Vec<Box<ExecuteCallback>>>,
}

impl Executor for Limited {
    fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
        LIMITED.with(|state| state.execute(f))
    }
    fn execute_boxed(&self, f: Box<ExecuteCallback>) {
        self.execute(|| f.call());
    }
}

impl LimitState {
    fn new() -> LimitState {
        LimitState {
            count: Cell::new(0),
            deferred: RefCell::new(Vec::new()),
        }
    }

    fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
        match self.count.get() {
            0 => {
                self.count.set(1);
                f();
                loop {
                    let cb = self.deferred.borrow_mut().pop();
                    match cb {
                        Some(f) => f.call(),
                        None => break,
                    }
                }
                self.count.set(0);
            }
            n if n < LIMIT => {
                self.count.set(n + 1);
                f();
                self.count.set(n);
            }
            _ => self.deferred.borrow_mut().push(Box::new(f)),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};

    use super::{Executor, Limited};

    #[test]
    fn limited() {
        fn doit(ex: Arc<Executor>, hits: Arc<AtomicUsize>, i: usize) {
            if i == 0 {
                return
            }
            hits.fetch_add(1, Ordering::SeqCst);
            let ex2 = ex.clone();
            ex.execute(move || {
                doit(ex2, hits, i - 1);
            })
        }

        let n = 1_000_000;
        let hits = Arc::new(AtomicUsize::new(0));
        doit(Arc::new(Limited), hits.clone(), n);
        assert_eq!(hits.load(Ordering::SeqCst), n);
    }
}
<commit_msg>Add missing backtick<commit_after>//! Work in progress implementation of executors for Futures.
//!
//! Note that this interface is very likely to change and not stay as-is, and it
//! is not currently used much by futures beyond `DEFAULT`.

use std::cell::{Cell, RefCell};
use std::sync::Arc;

/// Encapsulation of a value which has the ability to execute arbitrary code.
///
/// This trait is object safe and intended to be used through pointers like
/// `Box` and `Arc`.
pub trait Executor: Send + Sync + 'static {
    /// Executes the given closure `f`, perhaps on a different thread or
    /// deferred to a later time.
    ///
    /// This method may not execute `f` immediately, but it will arrange for the
    /// callback to be invoked "in the near future".
    fn execute<F>(&self, f: F)
        where F: FnOnce() + Send + 'static,
              Self: Sized
    {
        self.execute_boxed(Box::new(f))
    }

    /// Object-safe method of the above interface used when implementing trait
    /// objects.
    ///
    /// This should not be called direclty and instead `execute` should be used.
    fn execute_boxed(&self, f: Box<ExecuteCallback>);
}

/// The default executor, used by futures by default currently.
pub static DEFAULT: Limited = Limited;

impl<T: Executor + ?Sized + Send + Sync + 'static> Executor for Box<T> {
    fn execute_boxed(&self, f: Box<ExecuteCallback>) {
        (**self).execute_boxed(f)
    }
}

impl<T: Executor + ?Sized + Send + Sync + 'static> Executor for Arc<T> {
    fn execute_boxed(&self, f: Box<ExecuteCallback>) {
        (**self).execute_boxed(f)
    }
}

/// Essentially `Box<FnOnce() + Send>`, just as a trait.
pub trait ExecuteCallback: Send + 'static {
    #[allow(missing_docs)]
    fn call(self: Box<Self>);
}

impl<F: FnOnce() + Send + 'static> ExecuteCallback for F {
    fn call(self: Box<F>) {
        (*self)()
    }
}

/// Implementation of an `Executor` which just executes everything immediately
/// as soon as it's passed in.
pub struct Inline;

impl Executor for Inline {
    fn execute<F: FnOnce() + Send + 'static>(&self, f: F) {
        f()
    }

    fn execute_boxed(&self, f: Box<ExecuteCallback>) {
        f.call()
    }
}

/// Implementation of an executor which executes all callbacks immediately, but
/// bounds the amount of recursion to prevent blowing the stack.
pub struct Limited;

thread_local!(static LIMITED: LimitState = LimitState::new());

const LIMIT: usize = 100;

struct LimitState {
    count: Cell<usize>,
    deferred: RefCell<Vec<Box<ExecuteCallback>>>,
}

impl Executor for Limited {
    fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
        LIMITED.with(|state| state.execute(f))
    }
    fn execute_boxed(&self, f: Box<ExecuteCallback>) {
        self.execute(|| f.call());
    }
}

impl LimitState {
    fn new() -> LimitState {
        LimitState {
            count: Cell::new(0),
            deferred: RefCell::new(Vec::new()),
        }
    }

    fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
        match self.count.get() {
            0 => {
                self.count.set(1);
                f();
                loop {
                    let cb = self.deferred.borrow_mut().pop();
                    match cb {
                        Some(f) => f.call(),
                        None => break,
                    }
                }
                self.count.set(0);
            }
            n if n < LIMIT => {
                self.count.set(n + 1);
                f();
                self.count.set(n);
            }
            _ => self.deferred.borrow_mut().push(Box::new(f)),
        }
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;
    use std::sync::atomic::{AtomicUsize, Ordering};

    use super::{Executor, Limited};

    #[test]
    fn limited() {
        fn doit(ex: Arc<Executor>, hits: Arc<AtomicUsize>, i: usize) {
            if i == 0 {
                return
            }
            hits.fetch_add(1, Ordering::SeqCst);
            let ex2 = ex.clone();
            ex.execute(move || {
                doit(ex2, hits, i - 1);
            })
        }

        let n = 1_000_000;
        let hits = Arc::new(AtomicUsize::new(0));
        doit(Arc::new(Limited), hits.clone(), n);
        assert_eq!(hits.load(Ordering::SeqCst), n);
    }
}
<|endoftext|>


<commit_before>//! The film module provides color types and a render target that the image
//! is written too. Functions are also provided for saving PPM and BMP images
//! while I wait to migrate over to the Piston image library due to some
//! compile issues TODO: https://github.com/PistonDevelopers/image

use std::io::{File, Open, Write, BufferedWriter};

pub use self::color::{Colorf, Color24};

pub mod color;

/// Write the sequence of bytes as a PPM image file with the desired name
pub fn write_ppm(name: &str, w: u32, h: u32, img: &[u8]) {
    let file = match File::open_mode(&Path::new(name), Open, Write) {
        Ok(f) => f,
        Err(e) => panic!("Failed to open {}: {}", name, e),
    };
    let mut writer = BufferedWriter::new(file);
    match write!(&mut writer, "P6\n{} {}\n255\n", w, h) {
        Err(e) => panic!("Failed to write pixel data to {}: {}", name, e),
        _ => {},
    }
    match writer.write(img) {
        Err(e) => panic!("Failed to write pixel data to {}: {}", name, e),
        _ => {},
    }
}

<commit_msg>Will just do ppm images for simplicity<commit_after>//! The film module provides color types and a render target that the image
//! is written too. Functions are also provided for saving PPM images
//! while I wait to migrate over to the Piston image library due to some
//! compile issues TODO: https://github.com/PistonDevelopers/image

use std::io::{File, Open, Write, BufferedWriter};

pub use self::color::{Colorf, Color24};

pub mod color;

/// Write the sequence of bytes as a PPM image file with the desired name
pub fn write_ppm(name: &str, w: u32, h: u32, img: &[u8]) {
    let file = match File::open_mode(&Path::new(name), Open, Write) {
        Ok(f) => f,
        Err(e) => panic!("Failed to open {}: {}", name, e),
    };
    let mut writer = BufferedWriter::new(file);
    match write!(&mut writer, "P6\n{} {}\n255\n", w, h) {
        Err(e) => panic!("Failed to write pixel data to {}: {}", name, e),
        _ => {},
    }
    match writer.write(img) {
        Err(e) => panic!("Failed to write pixel data to {}: {}", name, e),
        _ => {},
    }
}

<|endoftext|>


<commit_before>mod matchers;
use self::matchers::GivenPathInfo;

use std::error::Error;
use std::fs;
use std::path::Path;
use std::io::stderr;
use std::io::stdout;

use std::cell::RefCell;
use std::rc::Rc;
use std::io::Write;

pub struct Config {
    depth_first: bool,
    min_depth: u32,
    max_depth: u32,
}

impl Config {
    fn new() -> Config {
        Config {
            depth_first: false,
            min_depth: 0,
            max_depth: u32::max_value(),
        }
    }
}

/// Trait that encapsulates various dependencies (output, clocks, etc.) that we
/// might want to fake out for unit tests.
pub trait Dependencies<'a> {
    fn get_output(&'a self) -> &'a RefCell<Write>;
}

/// Struct that holds the dependencies we use when run as the real executable.
pub struct StandardDependencies {
    output: Rc<RefCell<Write>>,
}

impl StandardDependencies {
    pub fn new() -> StandardDependencies {
        StandardDependencies { output: Rc::new(RefCell::new(stdout())) }
    }
}

impl<'a> Dependencies<'a> for StandardDependencies {
    fn get_output(&'a self) -> &'a RefCell<Write> {
        self.output.as_ref()
    }
}

/// The result of parsing the command-line arguments into useful forms.
struct ParsedInfo {
    matcher: Box<self::matchers::Matcher>,
    paths: Vec<String>,
    config: Config,
}

/// Function to generate a ParsedInfoi from the strings supplied on the command-line.
fn parse_args(args: &[&str]) -> Result<ParsedInfo, Box<Error>> {
    let mut paths = vec![];
    let mut i = 0;
    let mut config = Config::new();

    while i < args.len() && !args[i].starts_with('-') && args[i] != "!" && args[i] != "(" {
        paths.push(args[i].to_string());
        i += 1;
    }
    if i == 0 {
        paths.push(".".to_string());
    }
    let matcher = try!(matchers::build_top_level_matcher(&args[i..], &mut config));
    Ok(ParsedInfo {
        matcher: matcher,
        paths: paths,
        config: config,
    })
}

/// Function that goes through a directory's contents, checking files, and calling
/// itself recursively for subdirectories.
fn process_dir<'a>(dir: &Path,
                   depth: u32,
                   config: &Config,
                   deps: &'a Dependencies<'a>,
                   matcher: &Box<matchers::Matcher>)
                   -> Result<i32, Box<Error>> {
    let mut found_count = 0;
    let this_dir = GivenPathInfo::new(dir);
    if !config.depth_first {
        let mut matcher_io: matchers::MatcherIO<'a> = matchers::MatcherIO::new(deps);
        if depth >= config.min_depth && matcher.matches(&this_dir, &mut matcher_io) {
            found_count += 1;
        }
        if matcher_io.should_skip_current_dir() {
            return Ok(found_count);
        }
    }

    match fs::read_dir(dir) {
        Ok(entry_results) => {
            for entry_result in entry_results {
                let entry = try!(entry_result);
                let path = entry.path();
                if path.is_dir() {
                    if depth < config.max_depth {
                        found_count += try!(process_dir(&path, depth + 1, config, deps, matcher));
                    }
                } else {
                    if depth + 1 >= config.min_depth && depth < config.max_depth {
                        let mut matcher_io = matchers::MatcherIO::new(deps);
                        println!("about to call matcher");
                        if matcher.matches(&entry, &mut matcher_io) {
                            found_count += 1;
                        }
                    }
                }
            }
        }
        Err(e) => {
            writeln!(&mut stderr(),
                     "Error: {}: {}",
                     dir.to_string_lossy(),
                     e.description())
                .unwrap();
        }
    }
    if config.depth_first {
        let mut matcher_io = matchers::MatcherIO::new(deps);
        if depth >= config.min_depth && matcher.matches(&this_dir, &mut matcher_io) {
            found_count += 1;
        }
    }
    Ok(found_count)
}

fn do_find<'a>(args: &[&str], deps: &'a Dependencies<'a>) -> Result<i32, Box<Error>> {
    let paths_and_matcher = try!(parse_args(args));
    let mut found_count = 0;
    for path in paths_and_matcher.paths {
        let dir = Path::new(&path);
        found_count += try!(process_dir(&dir,
                                        0,
                                        &paths_and_matcher.config,
                                        deps,
                                        &paths_and_matcher.matcher));
    }
    Ok(found_count)
}

fn print_help() {
    println!("Usage: find [path...] [expression]

If no path is supplied then the current working directory is used by default.

Early alpha implementation. Currently the only expressions supported are
 -print
 -name case-sensitive_filename_pattern
 -iname case-insensitive_filename_pattern
 -type type_char
    currently type_char can only be f (for file) or d (for directory)
");
}

/// Does all the work for find.
///
/// All main has to do is pass in the command-line args and exit the process
/// with the exit code. Note that the first string in args is expected to be
/// the name of the executable.
pub fn find_main<'a>(args: &[&str], deps: &'a Dependencies<'a>) -> i32 {

    for arg in args {
        match arg.as_ref() {
            "-help" | "--help" => {
                print_help();
                return 0;
            }
            _ => (),
        }
    }
    match do_find(&args[1..], deps) {
        Ok(_) => 0,
        Err(e) => {
            writeln!(&mut stderr(), "Error: {}", e).unwrap();
            1
        }
    }
}

#[cfg(test)]
mod test {

    use std::cell::RefCell;
    use std::vec::Vec;
    use std::io::Cursor;
    use std::io::Read;
    use std::io::Write;
    use super::Dependencies;

    /// A struct that implements Dependencies, but uses faked implementations,
    /// allowing us to check output, set the time returned by clocks etc.
    pub struct FakeDependencies {
        pub output: RefCell<Cursor<Vec<u8>>>,
    }

    impl<'a> FakeDependencies {
        pub fn new() -> FakeDependencies {
            FakeDependencies { output: RefCell::new(Cursor::new(Vec::<u8>::new())) }
        }

        pub fn new_side_effects(&'a self) -> super::matchers::MatcherIO<'a> {
            super::matchers::MatcherIO::new(self)
        }

        pub fn get_output_as_string(&self) -> String {
            let mut cursor = self.output.borrow_mut();
            cursor.set_position(0);
            let mut contents = String::new();
            cursor.read_to_string(&mut contents).unwrap();
            contents
        }
    }

    impl<'a> Dependencies<'a> for FakeDependencies {
        fn get_output(&'a self) -> &'a RefCell<Write> {
            &self.output
        }
    }

    // disabled until we can get deterministic directory contents ordering
    //    #[test]
    //    fn find_main_not_depth_first() {
    //        let output = new_output();
    //
    //        let rc = super::find_main(&["find", "./test_data/simple"], output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/simple\n\
    //                   ./test_data/simple/abbbc\n\
    //                   ./test_data/simple/subdir\n\
    //                   ./test_data/simple/subdir/ABBBC\n");
    //    }
    //
    //    #[test]
    //    fn find_main_depth_first() {
    //        let output = new_output();
    //
    //        let rc = super::find_main(&["find", "./test_data/simple", "-depth"], output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/simple/subdir/ABBBC\n\
    //                   ./test_data/simple/subdir\n\
    //                   ./test_data/simple/abbbc\n\
    //                   ./test_data/simple\n");
    //    }
    //
    //    #[test]
    //    fn find_maxdepth() {
    //        let output = new_output();
    //        let rc = super::find_main(&["find", "./test_data/depth", "-maxdepth", "2"],
    //                                  output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth\n\
    //                   ./test_data/depth/f0\n\
    //                   ./test_data/depth/1\n\
    //                   ./test_data/depth/1/f1\n\
    //                   ./test_data/depth/1/2\n");
    //    }
    //
    //    #[test]
    //    fn find_maxdepth_depth_first() {
    //        let output = new_output();
    //        let rc = super::find_main(&["find", "./test_data/depth", "-maxdepth", "2", "-depth"],
    //                                  output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth/1/2\n\
    //                   ./test_data/depth/1/f1\n\
    //                   ./test_data/depth/1\n\
    //                   ./test_data/depth/f0\n\
    //                   ./test_data/depth\n");
    //    }
    //
    //    #[test]
    //    fn find_prune() {
    //        let output = new_output();
    //        let rc =
    //            super::find_main(&["find", "./test_data/depth", "-print", ",", "-name", "1", "-prune"],
    //                             output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth/1\n./test_data/depth/f0\n./test_data/depth\n");
    //    }

    #[test]
    fn find_zero_maxdepth() {
        let deps = FakeDependencies::new();
        let rc = super::find_main(&["find", "./test_data/depth", "-maxdepth", "0"], &deps);

        assert_eq!(rc, 0);
        assert_eq!(deps.get_output_as_string(), "./test_data/depth\n");
    }

    #[test]
    fn find_zero_maxdepth_depth_first() {
        let deps = FakeDependencies::new();
        let rc = super::find_main(&["find", "./test_data/depth", "-maxdepth", "0", "-depth"],
                                  &deps);

        assert_eq!(rc, 0);
        assert_eq!(deps.get_output_as_string(), "./test_data/depth\n");
    }

    // disabled until we can get deterministic directory contents ordering
    //    #[test]
    //    fn find_mindepth() {
    //        let output = new_output();
    //        let rc = super::find_main(&["find", "./test_data/depth", "-mindepth", "3"],
    //                                  output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth/1/2/f2\n\
    //                   ./test_data/depth/1/2/3\n\
    //                   ./test_data/depth/1/2/3/f3\n");
    //    }
    //
    //    #[test]
    //    fn find_mindepth_depth_first() {
    //        let output = new_output();
    //        let rc = super::find_main(&["find", "./test_data/depth", "-mindepth", "3", "-depth"],
    //                                  output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth/1/2/3/f3\n\
    //                   ./test_data/depth/1/2/3\n\
    //                   ./test_data/depth/1/2/f2\n");
    //    }

}
<commit_msg>Removed leftover tracing println call<commit_after>mod matchers;
use self::matchers::GivenPathInfo;

use std::error::Error;
use std::fs;
use std::path::Path;
use std::io::stderr;
use std::io::stdout;

use std::cell::RefCell;
use std::rc::Rc;
use std::io::Write;

pub struct Config {
    depth_first: bool,
    min_depth: u32,
    max_depth: u32,
}

impl Config {
    fn new() -> Config {
        Config {
            depth_first: false,
            min_depth: 0,
            max_depth: u32::max_value(),
        }
    }
}

/// Trait that encapsulates various dependencies (output, clocks, etc.) that we
/// might want to fake out for unit tests.
pub trait Dependencies<'a> {
    fn get_output(&'a self) -> &'a RefCell<Write>;
}

/// Struct that holds the dependencies we use when run as the real executable.
pub struct StandardDependencies {
    output: Rc<RefCell<Write>>,
}

impl StandardDependencies {
    pub fn new() -> StandardDependencies {
        StandardDependencies { output: Rc::new(RefCell::new(stdout())) }
    }
}

impl<'a> Dependencies<'a> for StandardDependencies {
    fn get_output(&'a self) -> &'a RefCell<Write> {
        self.output.as_ref()
    }
}

/// The result of parsing the command-line arguments into useful forms.
struct ParsedInfo {
    matcher: Box<self::matchers::Matcher>,
    paths: Vec<String>,
    config: Config,
}

/// Function to generate a ParsedInfoi from the strings supplied on the command-line.
fn parse_args(args: &[&str]) -> Result<ParsedInfo, Box<Error>> {
    let mut paths = vec![];
    let mut i = 0;
    let mut config = Config::new();

    while i < args.len() && !args[i].starts_with('-') && args[i] != "!" && args[i] != "(" {
        paths.push(args[i].to_string());
        i += 1;
    }
    if i == 0 {
        paths.push(".".to_string());
    }
    let matcher = try!(matchers::build_top_level_matcher(&args[i..], &mut config));
    Ok(ParsedInfo {
        matcher: matcher,
        paths: paths,
        config: config,
    })
}

/// Function that goes through a directory's contents, checking files, and calling
/// itself recursively for subdirectories.
fn process_dir<'a>(dir: &Path,
                   depth: u32,
                   config: &Config,
                   deps: &'a Dependencies<'a>,
                   matcher: &Box<matchers::Matcher>)
                   -> Result<i32, Box<Error>> {
    let mut found_count = 0;
    let this_dir = GivenPathInfo::new(dir);
    if !config.depth_first {
        let mut matcher_io: matchers::MatcherIO<'a> = matchers::MatcherIO::new(deps);
        if depth >= config.min_depth && matcher.matches(&this_dir, &mut matcher_io) {
            found_count += 1;
        }
        if matcher_io.should_skip_current_dir() {
            return Ok(found_count);
        }
    }

    match fs::read_dir(dir) {
        Ok(entry_results) => {
            for entry_result in entry_results {
                let entry = try!(entry_result);
                let path = entry.path();
                if path.is_dir() {
                    if depth < config.max_depth {
                        found_count += try!(process_dir(&path, depth + 1, config, deps, matcher));
                    }
                } else {
                    if depth + 1 >= config.min_depth && depth < config.max_depth {
                        let mut matcher_io = matchers::MatcherIO::new(deps);
                        if matcher.matches(&entry, &mut matcher_io) {
                            found_count += 1;
                        }
                    }
                }
            }
        }
        Err(e) => {
            writeln!(&mut stderr(),
                     "Error: {}: {}",
                     dir.to_string_lossy(),
                     e.description())
                .unwrap();
        }
    }
    if config.depth_first {
        let mut matcher_io = matchers::MatcherIO::new(deps);
        if depth >= config.min_depth && matcher.matches(&this_dir, &mut matcher_io) {
            found_count += 1;
        }
    }
    Ok(found_count)
}

fn do_find<'a>(args: &[&str], deps: &'a Dependencies<'a>) -> Result<i32, Box<Error>> {
    let paths_and_matcher = try!(parse_args(args));
    let mut found_count = 0;
    for path in paths_and_matcher.paths {
        let dir = Path::new(&path);
        found_count += try!(process_dir(&dir,
                                        0,
                                        &paths_and_matcher.config,
                                        deps,
                                        &paths_and_matcher.matcher));
    }
    Ok(found_count)
}

fn print_help() {
    println!("Usage: find [path...] [expression]

If no path is supplied then the current working directory is used by default.

Early alpha implementation. Currently the only expressions supported are
 -print
 -name case-sensitive_filename_pattern
 -iname case-insensitive_filename_pattern
 -type type_char
    currently type_char can only be f (for file) or d (for directory)
");
}

/// Does all the work for find.
///
/// All main has to do is pass in the command-line args and exit the process
/// with the exit code. Note that the first string in args is expected to be
/// the name of the executable.
pub fn find_main<'a>(args: &[&str], deps: &'a Dependencies<'a>) -> i32 {

    for arg in args {
        match arg.as_ref() {
            "-help" | "--help" => {
                print_help();
                return 0;
            }
            _ => (),
        }
    }
    match do_find(&args[1..], deps) {
        Ok(_) => 0,
        Err(e) => {
            writeln!(&mut stderr(), "Error: {}", e).unwrap();
            1
        }
    }
}

#[cfg(test)]
mod test {

    use std::cell::RefCell;
    use std::vec::Vec;
    use std::io::Cursor;
    use std::io::Read;
    use std::io::Write;
    use super::Dependencies;

    /// A struct that implements Dependencies, but uses faked implementations,
    /// allowing us to check output, set the time returned by clocks etc.
    pub struct FakeDependencies {
        pub output: RefCell<Cursor<Vec<u8>>>,
    }

    impl<'a> FakeDependencies {
        pub fn new() -> FakeDependencies {
            FakeDependencies { output: RefCell::new(Cursor::new(Vec::<u8>::new())) }
        }

        pub fn new_side_effects(&'a self) -> super::matchers::MatcherIO<'a> {
            super::matchers::MatcherIO::new(self)
        }

        pub fn get_output_as_string(&self) -> String {
            let mut cursor = self.output.borrow_mut();
            cursor.set_position(0);
            let mut contents = String::new();
            cursor.read_to_string(&mut contents).unwrap();
            contents
        }
    }

    impl<'a> Dependencies<'a> for FakeDependencies {
        fn get_output(&'a self) -> &'a RefCell<Write> {
            &self.output
        }
    }

    // disabled until we can get deterministic directory contents ordering
    //    #[test]
    //    fn find_main_not_depth_first() {
    //        let output = new_output();
    //
    //        let rc = super::find_main(&["find", "./test_data/simple"], output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/simple\n\
    //                   ./test_data/simple/abbbc\n\
    //                   ./test_data/simple/subdir\n\
    //                   ./test_data/simple/subdir/ABBBC\n");
    //    }
    //
    //    #[test]
    //    fn find_main_depth_first() {
    //        let output = new_output();
    //
    //        let rc = super::find_main(&["find", "./test_data/simple", "-depth"], output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/simple/subdir/ABBBC\n\
    //                   ./test_data/simple/subdir\n\
    //                   ./test_data/simple/abbbc\n\
    //                   ./test_data/simple\n");
    //    }
    //
    //    #[test]
    //    fn find_maxdepth() {
    //        let output = new_output();
    //        let rc = super::find_main(&["find", "./test_data/depth", "-maxdepth", "2"],
    //                                  output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth\n\
    //                   ./test_data/depth/f0\n\
    //                   ./test_data/depth/1\n\
    //                   ./test_data/depth/1/f1\n\
    //                   ./test_data/depth/1/2\n");
    //    }
    //
    //    #[test]
    //    fn find_maxdepth_depth_first() {
    //        let output = new_output();
    //        let rc = super::find_main(&["find", "./test_data/depth", "-maxdepth", "2", "-depth"],
    //                                  output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth/1/2\n\
    //                   ./test_data/depth/1/f1\n\
    //                   ./test_data/depth/1\n\
    //                   ./test_data/depth/f0\n\
    //                   ./test_data/depth\n");
    //    }
    //
    //    #[test]
    //    fn find_prune() {
    //        let output = new_output();
    //        let rc =
    //            super::find_main(&["find", "./test_data/depth", "-print", ",", "-name", "1", "-prune"],
    //                             output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth/1\n./test_data/depth/f0\n./test_data/depth\n");
    //    }

    #[test]
    fn find_zero_maxdepth() {
        let deps = FakeDependencies::new();
        let rc = super::find_main(&["find", "./test_data/depth", "-maxdepth", "0"], &deps);

        assert_eq!(rc, 0);
        assert_eq!(deps.get_output_as_string(), "./test_data/depth\n");
    }

    #[test]
    fn find_zero_maxdepth_depth_first() {
        let deps = FakeDependencies::new();
        let rc = super::find_main(&["find", "./test_data/depth", "-maxdepth", "0", "-depth"],
                                  &deps);

        assert_eq!(rc, 0);
        assert_eq!(deps.get_output_as_string(), "./test_data/depth\n");
    }

    // disabled until we can get deterministic directory contents ordering
    //    #[test]
    //    fn find_mindepth() {
    //        let output = new_output();
    //        let rc = super::find_main(&["find", "./test_data/depth", "-mindepth", "3"],
    //                                  output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth/1/2/f2\n\
    //                   ./test_data/depth/1/2/3\n\
    //                   ./test_data/depth/1/2/3/f3\n");
    //    }
    //
    //    #[test]
    //    fn find_mindepth_depth_first() {
    //        let output = new_output();
    //        let rc = super::find_main(&["find", "./test_data/depth", "-mindepth", "3", "-depth"],
    //                                  output.clone());
    //
    //        assert_eq!(rc, 0);
    //        assert_eq!(get_output_as_string(&output),
    //                   "./test_data/depth/1/2/3/f3\n\
    //                   ./test_data/depth/1/2/3\n\
    //                   ./test_data/depth/1/2/f2\n");
    //    }

}
<|endoftext|>