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

//! The compiler code necessary to implement the `#[deriving]` extensions.
//!
//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
//! the standard library, and "std" is the core library.

use ast::{Item, MetaItem, MetaList, MetaNameValue, MetaWord};
use ext::base::ExtCtxt;
use codemap::Span;
use ptr::P;

pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod rand;
pub mod show;
pub mod zero;
pub mod default;
pub mod primitive;

#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/totaleq.rs"]
pub mod totaleq;
#[path="cmp/ord.rs"]
pub mod ord;
#[path="cmp/totalord.rs"]
pub mod totalord;

pub mod generic;

pub fn expand_meta_deriving(cx: &mut ExtCtxt,
                            _span: Span,
                            mitem: &MetaItem,
                            item: &Item,
                            push: |P<Item>|) {
    match mitem.node {
        MetaNameValue(_, ref l) => {
            cx.span_err(l.span, "unexpected value in `deriving`");
        }
        MetaWord(_) => {
            cx.span_warn(mitem.span, "empty trait list in `deriving`");
        }
        MetaList(_, ref titems) if titems.len() == 0 => {
            cx.span_warn(mitem.span, "empty trait list in `deriving`");
        }
        MetaList(_, ref titems) => {
            for titem in titems.iter().rev() {
                match titem.node {
                    MetaNameValue(ref tname, _) |
                    MetaList(ref tname, _) |
                    MetaWord(ref tname) => {
                        macro_rules! expand(($func:path) => ($func(cx, titem.span,
                                                                   &**titem, item,
                                                                   |i| push(i))));
                        match tname.get() {
                            "Clone" => expand!(clone::expand_deriving_clone),

                            "Hash" => expand!(hash::expand_deriving_hash),

                            "Encodable" => expand!(encodable::expand_deriving_encodable),
                            "Decodable" => expand!(decodable::expand_deriving_decodable),

                            "PartialEq" => expand!(eq::expand_deriving_eq),
                            "Eq" => expand!(totaleq::expand_deriving_totaleq),
                            "PartialOrd" => expand!(ord::expand_deriving_ord),
                            "Ord" => expand!(totalord::expand_deriving_totalord),

                            "Rand" => expand!(rand::expand_deriving_rand),

                            "Show" => expand!(show::expand_deriving_show),

                            "Zero" => expand!(zero::expand_deriving_zero),
                            "Default" => expand!(default::expand_deriving_default),

                            "FromPrimitive" => expand!(primitive::expand_deriving_from_primitive),

                            "Send" => expand!(bounds::expand_deriving_bound),
                            "Sync" => expand!(bounds::expand_deriving_bound),
                            "Copy" => expand!(bounds::expand_deriving_bound),

                            ref tname => {
                                cx.span_err(titem.span,
                                            format!("unknown `deriving` \
                                                     trait: `{}`",
                                                    *tname).as_slice());
                            }
                        };
                    }
                }
            }
        }
    }
}
<commit_msg>rustc: Start the deprecation of libserialize<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! The compiler code necessary to implement the `#[deriving]` extensions.
//!
//! FIXME (#2810): hygiene. Search for "__" strings (in other files too). We also assume "extra" is
//! the standard library, and "std" is the core library.

use ast::{Item, MetaItem, MetaList, MetaNameValue, MetaWord};
use ext::base::ExtCtxt;
use codemap::Span;
use ptr::P;

pub mod bounds;
pub mod clone;
pub mod encodable;
pub mod decodable;
pub mod hash;
pub mod rand;
pub mod show;
pub mod zero;
pub mod default;
pub mod primitive;

#[path="cmp/eq.rs"]
pub mod eq;
#[path="cmp/totaleq.rs"]
pub mod totaleq;
#[path="cmp/ord.rs"]
pub mod ord;
#[path="cmp/totalord.rs"]
pub mod totalord;

pub mod generic;

pub fn expand_meta_deriving(cx: &mut ExtCtxt,
                            _span: Span,
                            mitem: &MetaItem,
                            item: &Item,
                            push: |P<Item>|) {
    match mitem.node {
        MetaNameValue(_, ref l) => {
            cx.span_err(l.span, "unexpected value in `deriving`");
        }
        MetaWord(_) => {
            cx.span_warn(mitem.span, "empty trait list in `deriving`");
        }
        MetaList(_, ref titems) if titems.len() == 0 => {
            cx.span_warn(mitem.span, "empty trait list in `deriving`");
        }
        MetaList(_, ref titems) => {
            for titem in titems.iter().rev() {
                match titem.node {
                    MetaNameValue(ref tname, _) |
                    MetaList(ref tname, _) |
                    MetaWord(ref tname) => {
                        macro_rules! expand(($func:path) => ($func(cx, titem.span,
                                                                   &**titem, item,
                                                                   |i| push(i))));
                        match tname.get() {
                            "Clone" => expand!(clone::expand_deriving_clone),

                            "Hash" => expand!(hash::expand_deriving_hash),

                            "RustcEncodable" => {
                                expand!(encodable::expand_deriving_encodable)
                            }
                            "RustcDecodable" => {
                                expand!(decodable::expand_deriving_decodable)
                            }
                            "Encodable" => {
                                // NOTE: uncomment after a stage0 snap
                                // cx.span_warn(titem.span,
                                //              "deriving(Encodable) is deprecated \
                                //               in favor of deriving(RustcEncodable)");

                                expand!(encodable::expand_deriving_encodable)
                            }
                            "Decodable" =>
                                // NOTE: uncomment after a stage0 snap
                                // cx.span_warn(titem.span,
                                //              "deriving(Decodable) is deprecated \
                                //               in favor of deriving(RustcDecodable)");

                                expand!(decodable::expand_deriving_decodable)
                            }

                            "PartialEq" => expand!(eq::expand_deriving_eq),
                            "Eq" => expand!(totaleq::expand_deriving_totaleq),
                            "PartialOrd" => expand!(ord::expand_deriving_ord),
                            "Ord" => expand!(totalord::expand_deriving_totalord),

                            "Rand" => expand!(rand::expand_deriving_rand),

                            "Show" => expand!(show::expand_deriving_show),

                            "Zero" => expand!(zero::expand_deriving_zero),
                            "Default" => expand!(default::expand_deriving_default),

                            "FromPrimitive" => expand!(primitive::expand_deriving_from_primitive),

                            "Send" => expand!(bounds::expand_deriving_bound),
                            "Sync" => expand!(bounds::expand_deriving_bound),
                            "Copy" => expand!(bounds::expand_deriving_bound),

                            ref tname => {
                                cx.span_err(titem.span,
                                            format!("unknown `deriving` \
                                                     trait: `{}`",
                                                    *tname).as_slice());
                            }
                        };
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>#![feature(no_std)]
#![feature(ptr_as_ref)]

#![no_std]

use core::ptr;
use core::cmp;

mod fit;

mod types;

pub trait Allocator {
    unsafe fn allocate(&mut self, size: usize, align: usize) -> *mut u8;
    unsafe fn deallocate(&mut self, ptr: *mut u8, old_size: usize, align: usize);

    unsafe fn reallocate(&mut self, ptr: *mut u8, old_size: usize, size: usize,
                  align: usize) -> *mut u8 {
        let new_ptr = self.allocate(size, align);

        if new_ptr.is_null() {
            return ptr::null_mut();
        }

        ptr::copy(ptr, new_ptr, cmp::min(size, old_size));

        self.deallocate(ptr, old_size, align);

        new_ptr
    }
}
<commit_msg>heap: Add macro align_up!<commit_after>//! Implementation of various allocator algorithm:
//! - First Fit

#![feature(no_std)]
#![feature(ptr_as_ref)]

#![no_std]

use core::ptr;
use core::cmp;

macro_rules! align_up {
    ( $val:expr, $align:expr ) => {
        if ($val & ($align - 1)) == 0 {
            $val
        } else {
            ($val + $align - 1) & !($align - 1)
        }
    }
}

mod fit;

mod types;

/// Trait implemented by every allocator
pub trait Allocator {
    unsafe fn allocate(&mut self, size: usize, align: usize) -> *mut u8;
    unsafe fn deallocate(&mut self, ptr: *mut u8, old_size: usize, align: usize);

    unsafe fn reallocate(&mut self, ptr: *mut u8, old_size: usize, size: usize,
                  align: usize) -> *mut u8 {
        let new_ptr = self.allocate(size, align);

        if new_ptr.is_null() {
            return ptr::null_mut();
        }

        ptr::copy(ptr, new_ptr, cmp::min(size, old_size));

        self.deallocate(ptr, old_size, align);

        new_ptr
    }
}
<|endoftext|>


<commit_before>extern crate glob;
extern crate rustc_serialize;
extern crate csv;

use glob::glob;
use rustc_serialize::json::Json;
use std::env;
use std::fs::File;
use std::result::Result;
use std::io::Read;
use std::collections::HashMap;
use std::error::Error;

const OUTPUT_FILE: &'static str = "output.csv";

fn main() {
	let args: Vec<String>= env::args().collect();

	if args.len() < 3 {
		panic!("Args are: <field name> <folder>");
	}

	let field = &args[1];
	let folder = &args[2];

	let mut frequencies: HashMap<String, i64> = HashMap::new();

	let search_path = format!("{}/*.json", folder);
	let file_paths = glob(&search_path).unwrap();
	for path in file_paths.filter_map(Result::ok) {
		let path = path.to_str().unwrap();

		let contents = file_contents(path);
		let data = Json::from_str(&contents).ok().expect("Malformed JSON");

		let key = get_string_value(&data, field);
		let counter = match frequencies.get(&key) {
			None => 0,
			Some(&x) => x,
		};
		frequencies.insert(key, counter + 1);
	}

	let mut sorted_frequencies: Vec<(&String, &i64)> = frequencies.iter().collect();
	sorted_frequencies.sort_by(|a, b| a.1.cmp(b.1).reverse());

	let mut csv_writer = match csv::Writer::from_file(OUTPUT_FILE) {
		Err(why) => panic!("Failed to create CSV writer: {}", Error::description(&why)),
		Ok(x) => x,
	};
	for record in sorted_frequencies.iter().filter(|&x| x.0 != "") {
		let result = csv_writer.encode(record);
		assert!(result.is_ok());
	};
}

fn get_string_value(json: &Json, key: &str) -> String {
	let value = json.find(key).expect("Field is missing");
	let result = value.as_string().expect("Field is not a string");
	result.to_string()
}

fn file_contents(file_path: &str) -> String {
	let mut file = match File::open(file_path) {
		Err(why) => panic!("Failed to open {}: {}", file_path, Error::description(&why)),
		Ok(file) => file,
	};
	let mut contents = String::new();
	match file.read_to_string(&mut contents) {
		Err(why) => panic!("Failed to read {}: {}", file_path, Error::description(&why)),
		Ok(_) => contents,
	}
}
<commit_msg>Added test<commit_after>extern crate glob;
extern crate rustc_serialize;
extern crate csv;

use glob::glob;
use rustc_serialize::json::Json;
use std::env;
use std::fs::File;
use std::result::Result;
use std::io::Read;
use std::collections::HashMap;
use std::error::Error;

const OUTPUT_FILE: &'static str = "output.csv";

#[allow(dead_code)]
fn main() {
	let args: Vec<String>= env::args().collect();

	if args.len() < 3 {
		panic!("Args are: <field name> <folder>");
	}

	let field = &args[1];
	let folder = &args[2];
	process(field, folder);
}

fn process(field: &str, folder: &str) -> bool {
	let mut frequencies: HashMap<String, i64> = HashMap::new();

	let search_path = format!("{}/*.json", folder);
	let file_paths = glob(&search_path).unwrap();
	for path in file_paths.filter_map(Result::ok) {
		let path = path.to_str().unwrap();

		let contents = file_contents(path);
		let data = Json::from_str(&contents).ok().expect("Malformed JSON");

		let key = get_string_value(&data, field);
		let counter = match frequencies.get(&key) {
			None => 0,
			Some(&x) => x,
		};
		frequencies.insert(key, counter + 1);
	}

	let mut sorted_frequencies: Vec<(&String, &i64)> = frequencies.iter().collect();
	sorted_frequencies.sort_by(|a, b| a.1.cmp(b.1).reverse());

	let mut csv_writer = match csv::Writer::from_file(OUTPUT_FILE) {
		Err(why) => panic!("Failed to create CSV writer: {}", Error::description(&why)),
		Ok(x) => x,
	};
	for record in sorted_frequencies.iter().filter(|&x| x.0 != "") {
		let result = csv_writer.encode(record);
		assert!(result.is_ok());
	};

	true
}

fn get_string_value(json: &Json, key: &str) -> String {
	let value = json.find(key).expect("Field is missing");
	let result = value.as_string().expect("Field is not a string");
	result.to_string()
}

fn file_contents(file_path: &str) -> String {
	let mut file = match File::open(file_path) {
		Err(why) => panic!("Failed to open {}: {}", file_path, Error::description(&why)),
		Ok(file) => file,
	};
	let mut contents = String::new();
	match file.read_to_string(&mut contents) {
		Err(why) => panic!("Failed to read {}: {}", file_path, Error::description(&why)),
		Ok(_) => contents,
	}
}

#[test]
fn it_works() {
	assert!(process("Name", "../../test_data"));
}
<|endoftext|>


<commit_before>use story_builder::article_provider::*;
use story_builder::thread_pool::*;
use std::borrow::Borrow;
use std::ops::Deref;
use std::sync::Arc;
use std::thread;
use std::thread::JoinHandle;
use std::collections::HashSet;

pub struct StoryBuilder {
    article_provider: Arc<ThreadedAP>,
    max_depth: u8,
    visited_nodes: HashSet<String>,
}

impl StoryBuilder {
    pub fn new(article_provider: Arc<ThreadedAP>) -> StoryBuilder {
        StoryBuilder {
            article_provider,
            max_depth: 5, // default value for now
            visited_nodes: HashSet::new(),
        }
    }

    pub fn build_story(&mut self, start_topic: &str, end_topic: &str) -> Result<String, String> {
        let start_topic = start_topic.to_lowercase();
        let end_topic = end_topic.to_lowercase();
        // If one of the topics is an empty string, do not try to make a story out of it.
        if start_topic == "" {
            return Err("Missing start topic.".to_owned());
        }
        if end_topic == "" {
            return Err("Missing end topic.".to_owned());
        }

        // If both topics are the same,
        // there is no point in trying to figure out the story.
        if start_topic == end_topic {
            return Err("No story to build; same start and end topics.".to_owned());
        }

        // Load the first article
        let start_article = match self.article_provider.get(&start_topic) {
            Some(start_article) => start_article,
            None => {
                return Err(self.build_suggestions_msg(&start_topic));
            }
        };
        self.visited_nodes.insert(start_topic);
        // Load the end article
        match self.article_provider.get(&end_topic) {
            Some(end_topic) => end_topic,
            None => {
                return Err(self.build_suggestions_msg(&end_topic));
            }
        };

        /* To build a story, we need to build a tree starting at the start_article
           node and going down in a "breadth-first" way; that way, once we find
           the end note, we know it is the shortest path to it. Also, going depth-first
           will be impossibly long to complete sincethe depth of the wikipedia
           article tree is almost infinite. */
        /* We look for a paragraph that holds a reference to our end topic
           somewhere in the last level we fetched: */

        // Start by creating a thread pool:
        let article_provider = self.article_provider.clone();
        // Store the reference to the article provider in the job to prevent having to send
        // it to each thread with each job request
        struct StoryBuilderJob {article_provider: Arc<ThreadedAP>}
        impl Job<(Arc<ArticleNode>, String, String), (Arc<ArticleNode>, String, Option<Box<ThreadedArticle>>)> for StoryBuilderJob {
            fn step(&self, input: (Arc<ArticleNode>, String, String)) -> (Arc<ArticleNode>, String, Option<Box<ThreadedArticle>>) {
                // Receive: reference to the parent article, paragraph being processed, topic to fetch
                let (parent, paragraph, topic) = input;
                // Return: ref to the parent article, paragraph, article returned from the AP
                (parent, paragraph, self.article_provider.get(&topic))
            }
        }
        let job = Arc::new(StoryBuilderJob {article_provider});
        let mut threads = ThreadPool::new(1, job);

        let mut last_level: Vec<Arc<ArticleNode>> = vec![Arc::new(ArticleNode::new(start_article))]; // starts with start article
        for i in 0..self.max_depth {
            // To prevent overloading the system, stop after X level deep
            // Start by loading the next level of articles:
            if i > 0 {
                // Any other iteration: go one level deeper:
                let mut current_level = vec![];

                for arc_article_node in last_level.iter() {
                    /* Iterate on each paragraph of this article, then map on it to
                       get the article for each related topic in it. */
                    for paragraph in arc_article_node.deref().get_paragraphs().iter() {
                        for topic in paragraph.topics.iter() {
                            let topic = topic.to_lowercase();
                            // Do not access the same article more than once!!
                            if !self.visited_nodes.contains(&topic) {
                                let topic_for_thread = topic.clone();
                                let par_text = paragraph.text.clone();
                                let parent_article_node = arc_article_node.clone();
                                threads.send((parent_article_node, par_text, topic_for_thread));
                                self.visited_nodes.insert(topic);
                            }
                        }
                    }
                }
                // Then, read all results:
                /*for output in threads.iter() {
                    match output {
                        (parent_article, source_paragraph, Some(a)) => {
                            let mut new_node = ArticleNode::new(a);
                            new_node.attach_to(parent_article, source_paragraph);
                            current_level.push(Arc::new(new_node));
                        }
                        _ => (),
                    }
                }*/

                last_level = current_level;
            }
            // Replace the previous level with this level.

            for article_node in last_level.iter() {
                if let Some(text) = StoryBuilder::find_text_for_topic_in_article(
                    article_node.deref().deref().borrow(),
                    &end_topic,
                ) {
                    // Found the topic. Format and return.
                    return Ok(StoryBuilder::build_final_text(
                        article_node.clone(),
                        text,
                        &end_topic,
                    ));
                }
            }
        }

        Err(
            format!(
                "Reached depth of <{}> without finding <{}>. Stopping search.",
                self.max_depth,
                end_topic
            ).to_owned(),
        )
    }

    fn build_suggestions_msg(&self, topic: &str) -> String {
        let mut msg = String::from(format!(
            "Cannot find wikipedia article for <{}>, try one of the following suggestions:\r\n",
            topic
        ));
        for sugg in self.article_provider.search(topic) {
            msg.push_str(&format!("- {}\r\n", &sugg));
        }

        msg
    }

    fn find_text_for_topic_in_article<'b>(
        article: &'b (ThreadedArticle),
        topic: &str,
    ) -> Option<&'b str> {
        if let Some(paragraph) = article.get_paragraphs().iter().find(|par| {
            // if any of the topics in the paragraph is <end>, return it.
            par.topics.iter().any(|t| &t.to_lowercase() == topic)
        }) {
            // We found the paragraph; return it directly.
            return Some(&paragraph.text);
        } else {
            None
        }
    }

    fn build_final_text(
        article_node: Arc<ArticleNode>,
        final_text: &str,
        final_topic: &str,
    ) -> String {
        let mut texts: Vec<String> = Vec::new();
        let mut last_topic = final_topic.to_owned();
        texts.push(format!("{}\r\n", final_text));
        {
            let n: &ArticleNode = article_node.borrow();
            if let Some(n_text) = n.text() {
                let new_topic = n.get_topic().to_owned();
                texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                last_topic = new_topic;
                texts.push(format!("{}\r\n", n_text));
            }
        }

        let mut node = article_node;
        loop {
            node = match node.parent() {
                Some(arc) => {
                    {
                        let n: &ArticleNode = arc.borrow();
                        if let Some(n_text) = n.text() {
                            let new_topic = n.get_topic().to_owned();
                            texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                            last_topic = new_topic;
                            texts.push(format!("{}\r\n", n_text));
                        }
                    }
                    arc
                }
                _ => {
                    let new_topic = node.get_topic().to_owned();
                    texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                    return texts.into_iter().rev().collect();
                }
            }
        }
    }
}

struct ArticleNode {
    data: Box<ThreadedArticle>,
    parent: Option<Arc<ArticleNode>>,
    text: Option<String>,
}

impl ArticleNode {
    fn new(data: Box<ThreadedArticle>) -> ArticleNode {
        ArticleNode {
            data,
            parent: None,
            text: None,
        }
    }
    fn attach_to(&mut self, parent: Arc<ArticleNode>, paragraph_text: String) {
        self.parent = Some(parent);
        self.text = Some(paragraph_text);
    }
    fn parent(&self) -> Option<Arc<ArticleNode>> {
        self.parent.clone()
    }
    fn text(&self) -> Option<String> {
        self.text.clone()
    }
}

impl<'n> Deref for ArticleNode {
    type Target = Box<ThreadedArticle>;

    fn deref(&self) -> &Box<ThreadedArticle> {
        &self.data
    }
}

#[cfg(test)]
mod tests;
<commit_msg>Re-activated output reading from thread_pool iterator<commit_after>use story_builder::article_provider::*;
use story_builder::thread_pool::*;
use std::borrow::Borrow;
use std::ops::Deref;
use std::sync::Arc;
use std::thread;
use std::thread::JoinHandle;
use std::collections::HashSet;

pub struct StoryBuilder {
    article_provider: Arc<ThreadedAP>,
    max_depth: u8,
    visited_nodes: HashSet<String>,
}

impl StoryBuilder {
    pub fn new(article_provider: Arc<ThreadedAP>) -> StoryBuilder {
        StoryBuilder {
            article_provider,
            max_depth: 5, // default value for now
            visited_nodes: HashSet::new(),
        }
    }

    pub fn build_story(&mut self, start_topic: &str, end_topic: &str) -> Result<String, String> {
        let start_topic = start_topic.to_lowercase();
        let end_topic = end_topic.to_lowercase();
        // If one of the topics is an empty string, do not try to make a story out of it.
        if start_topic == "" {
            return Err("Missing start topic.".to_owned());
        }
        if end_topic == "" {
            return Err("Missing end topic.".to_owned());
        }

        // If both topics are the same,
        // there is no point in trying to figure out the story.
        if start_topic == end_topic {
            return Err("No story to build; same start and end topics.".to_owned());
        }

        // Load the first article
        let start_article = match self.article_provider.get(&start_topic) {
            Some(start_article) => start_article,
            None => {
                return Err(self.build_suggestions_msg(&start_topic));
            }
        };
        self.visited_nodes.insert(start_topic);
        // Load the end article
        match self.article_provider.get(&end_topic) {
            Some(end_topic) => end_topic,
            None => {
                return Err(self.build_suggestions_msg(&end_topic));
            }
        };

        /* To build a story, we need to build a tree starting at the start_article
           node and going down in a "breadth-first" way; that way, once we find
           the end note, we know it is the shortest path to it. Also, going depth-first
           will be impossibly long to complete sincethe depth of the wikipedia
           article tree is almost infinite. */
        /* We look for a paragraph that holds a reference to our end topic
           somewhere in the last level we fetched: */

        // Start by creating a thread pool:
        let article_provider = self.article_provider.clone();
        // Store the reference to the article provider in the job to prevent having to send
        // it to each thread with each job request
        struct StoryBuilderJob {article_provider: Arc<ThreadedAP>}
        impl Job<(Arc<ArticleNode>, String, String), (Arc<ArticleNode>, String, Option<Box<ThreadedArticle>>)> for StoryBuilderJob {
            fn step(&self, input: (Arc<ArticleNode>, String, String)) -> (Arc<ArticleNode>, String, Option<Box<ThreadedArticle>>) {
                // Receive: reference to the parent article, paragraph being processed, topic to fetch
                let (parent, paragraph, topic) = input;
                // Return: ref to the parent article, paragraph, article returned from the AP
                (parent, paragraph, self.article_provider.get(&topic))
            }
        }
        let job = Arc::new(StoryBuilderJob {article_provider});
        let mut threads = ThreadPool::new(1, job);

        let mut last_level: Vec<Arc<ArticleNode>> = vec![Arc::new(ArticleNode::new(start_article))]; // starts with start article
        for i in 0..self.max_depth {
            // To prevent overloading the system, stop after X level deep
            // Start by loading the next level of articles:
            if i > 0 {
                // Any other iteration: go one level deeper:
                let mut current_level = vec![];

                for arc_article_node in last_level.iter() {
                    /* Iterate on each paragraph of this article, then map on it to
                       get the article for each related topic in it. */
                    for paragraph in arc_article_node.deref().get_paragraphs().iter() {
                        for topic in paragraph.topics.iter() {
                            let topic = topic.to_lowercase();
                            // Do not access the same article more than once!!
                            if !self.visited_nodes.contains(&topic) {
                                let topic_for_thread = topic.clone();
                                let par_text = paragraph.text.clone();
                                let parent_article_node = arc_article_node.clone();
                                threads.send((parent_article_node, par_text, topic_for_thread));
                                self.visited_nodes.insert(topic);
                            }
                        }
                    }
                }
                // Then, read all results:
                for output in threads.iter() {
                    match output {
                        (parent_article, source_paragraph, Some(a)) => {
                            let mut new_node = ArticleNode::new(a);
                            new_node.attach_to(parent_article, source_paragraph);
                            current_level.push(Arc::new(new_node));
                        }
                        _ => (),
                    }
                }

                last_level = current_level;
            }
            // Replace the previous level with this level.

            for article_node in last_level.iter() {
                if let Some(text) = StoryBuilder::find_text_for_topic_in_article(
                    article_node.deref().deref().borrow(),
                    &end_topic,
                ) {
                    // Found the topic. Format and return.
                    return Ok(StoryBuilder::build_final_text(
                        article_node.clone(),
                        text,
                        &end_topic,
                    ));
                }
            }
        }

        Err(
            format!(
                "Reached depth of <{}> without finding <{}>. Stopping search.",
                self.max_depth,
                end_topic
            ).to_owned(),
        )
    }

    fn build_suggestions_msg(&self, topic: &str) -> String {
        let mut msg = String::from(format!(
            "Cannot find wikipedia article for <{}>, try one of the following suggestions:\r\n",
            topic
        ));
        for sugg in self.article_provider.search(topic) {
            msg.push_str(&format!("- {}\r\n", &sugg));
        }

        msg
    }

    fn find_text_for_topic_in_article<'b>(
        article: &'b (ThreadedArticle),
        topic: &str,
    ) -> Option<&'b str> {
        if let Some(paragraph) = article.get_paragraphs().iter().find(|par| {
            // if any of the topics in the paragraph is <end>, return it.
            par.topics.iter().any(|t| &t.to_lowercase() == topic)
        }) {
            // We found the paragraph; return it directly.
            return Some(&paragraph.text);
        } else {
            None
        }
    }

    fn build_final_text(
        article_node: Arc<ArticleNode>,
        final_text: &str,
        final_topic: &str,
    ) -> String {
        let mut texts: Vec<String> = Vec::new();
        let mut last_topic = final_topic.to_owned();
        texts.push(format!("{}\r\n", final_text));
        {
            let n: &ArticleNode = article_node.borrow();
            if let Some(n_text) = n.text() {
                let new_topic = n.get_topic().to_owned();
                texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                last_topic = new_topic;
                texts.push(format!("{}\r\n", n_text));
            }
        }

        let mut node = article_node;
        loop {
            node = match node.parent() {
                Some(arc) => {
                    {
                        let n: &ArticleNode = arc.borrow();
                        if let Some(n_text) = n.text() {
                            let new_topic = n.get_topic().to_owned();
                            texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                            last_topic = new_topic;
                            texts.push(format!("{}\r\n", n_text));
                        }
                    }
                    arc
                }
                _ => {
                    let new_topic = node.get_topic().to_owned();
                    texts.push(format!("-> ({} to {})\r\n", &new_topic, last_topic));
                    return texts.into_iter().rev().collect();
                }
            }
        }
    }
}

struct ArticleNode {
    data: Box<ThreadedArticle>,
    parent: Option<Arc<ArticleNode>>,
    text: Option<String>,
}

impl ArticleNode {
    fn new(data: Box<ThreadedArticle>) -> ArticleNode {
        ArticleNode {
            data,
            parent: None,
            text: None,
        }
    }
    fn attach_to(&mut self, parent: Arc<ArticleNode>, paragraph_text: String) {
        self.parent = Some(parent);
        self.text = Some(paragraph_text);
    }
    fn parent(&self) -> Option<Arc<ArticleNode>> {
        self.parent.clone()
    }
    fn text(&self) -> Option<String> {
        self.text.clone()
    }
}

impl<'n> Deref for ArticleNode {
    type Target = Box<ThreadedArticle>;

    fn deref(&self) -> &Box<ThreadedArticle> {
        &self.data
    }
}

#[cfg(test)]
mod tests;
<|endoftext|>


<commit_before>use subframe;
use subframe::{Subframe, MAX_FIXED_ORDER};

pub fn fixed_restore_signal(order: usize,
                            residual: &[i32],
                            output: &mut [i32]) {
  debug_assert!(order <= MAX_FIXED_ORDER);

  let polynomial = [ &[][..]
                   , &[1][..]
                   , &[-1, 2][..]
                   , &[1, -3, 3][..]
                   , &[-1, 4, -6, 4][..]
                   ];

  let coefficients = polynomial[order];

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter()
                      .zip(&output[i..offset])
                      .fold(0, |result, (coefficient, signal)|
                            result + coefficient * signal);

    output[offset] = residual[i] + prediction;
  }
}

pub fn decode(subframe: &Subframe, output: &mut [i32]) {
  match subframe.data {
    subframe::Data::Constant(_) => unimplemented!(),
    subframe::Data::Verbatim(_) => unimplemented!(),
    subframe::Data::Fixed(_)    => unimplemented!(),
    subframe::Data::LPC(_)      => unimplemented!(),
  }

  if subframe.wasted_bits > 0 {
    for value in output {
      *value <<= subframe.wasted_bits;
    }
  }
}
<commit_msg>Add `fixed_restore_signal` to root decode function<commit_after>use subframe;
use subframe::{Subframe, MAX_FIXED_ORDER};

pub fn fixed_restore_signal(order: usize,
                            residual: &[i32],
                            output: &mut [i32]) {
  debug_assert!(order <= MAX_FIXED_ORDER);

  let polynomial = [ &[][..]
                   , &[1][..]
                   , &[-1, 2][..]
                   , &[1, -3, 3][..]
                   , &[-1, 4, -6, 4][..]
                   ];

  let coefficients = polynomial[order];

  for i in 0..residual.len() {
    let offset     = i + order;
    let prediction = coefficients.iter()
                      .zip(&output[i..offset])
                      .fold(0, |result, (coefficient, signal)|
                            result + coefficient * signal);

    output[offset] = residual[i] + prediction;
  }
}

pub fn decode(subframe: &Subframe, output: &mut [i32]) {
  match subframe.data {
    subframe::Data::Constant(_)      => unimplemented!(),
    subframe::Data::Verbatim(_)      => unimplemented!(),
    subframe::Data::Fixed(ref fixed) => {
      let order = fixed.order as usize;

      for i in 0..order {
        output[i] = fixed.warmup[i];
      }

      fixed_restore_signal(order, &fixed.residual, output);
    }
    subframe::Data::LPC(_)           => unimplemented!(),
  }

  if subframe.wasted_bits > 0 {
    for value in output {
      *value <<= subframe.wasted_bits;
    }
  }
}
<|endoftext|>


<commit_before>use std::cmp::max;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};

use grep::matcher::{Captures, Matcher};
use grep::regex::{RegexMatcher, RegexMatcherBuilder};
use grep::searcher::{
    BinaryDetection, Searcher, SearcherBuilder, Sink, SinkContext, SinkContextKind, SinkMatch,
};
use ignore::Walk;
use structopt::StructOpt;
use text_io::read;

#[derive(Debug, StructOpt)]
#[structopt(name = "fnr")]
/// Look for things, optionally replace them.
struct Opts {
    /// Run search in case insensitive mode
    #[structopt(short, long)]
    insensitive: bool,

    /// Print out replacements without actually performing them
    #[structopt(short, long)]
    dry_run: bool,

    #[structopt(short = "A", long, default_value = "0")]
    after: usize,
    #[structopt(short = "B", long, default_value = "0")]
    before: usize,
    #[structopt(short = "C", long, default_value = "0")]
    context: usize,

    #[structopt(short, long)]
    prompt: bool,

    /// What to search for.
    #[structopt(name = "FIND")]
    find: String,

    /// What to replace it with.
    #[structopt(name = "REPLACE")]
    replace: String,

    /// Locations to search. Current directory if not specified.
    #[structopt(name = "PATH", parse(from_os_str))]
    paths: Vec<PathBuf>,
}

#[derive(Debug, Clone)]
struct Line(u64, String);

#[derive(Debug)]
struct SearchMatch {
    line: Line,
    context_pre: Vec<Line>,
    context_post: Vec<Line>,
}

impl SearchMatch {
    fn as_change(&self, line: String) -> Change {
        return Change {
            line_number: self.line.0,
            new_line: line,
        };
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum MatchState {
    Init,
    Before,
    Match,
    After,
}

#[derive(Debug)]
struct SearchMatchCollector {
    state: MatchState,

    cur_context_pre: Vec<Line>,
    cur_context_post: Vec<Line>,
    cur_match_line: Option<Line>,

    matches: Vec<SearchMatch>,
}

impl SearchMatchCollector {
    fn new() -> SearchMatchCollector {
        return SearchMatchCollector {
            state: MatchState::Init,
            cur_match_line: None,
            cur_context_pre: Vec::new(),
            cur_context_post: Vec::new(),
            matches: Vec::new(),
        };
    }

    fn maybe_emit(&mut self) {
        if let Some(line) = &self.cur_match_line {
            // TODO: clones are wasteful here.
            let m = SearchMatch {
                line: line.clone(),
                context_pre: self.cur_context_pre.clone(),
                context_post: self.cur_context_post.clone(),
            };

            self.matches.push(m);
            self.reset();
        }
    }

    fn reset(&mut self) {
        self.state = MatchState::Init;

        self.cur_match_line = None;
        self.cur_context_pre.clear();
        self.cur_context_post.clear();
    }

    #[inline]
    fn transition(&mut self, next: MatchState) {
        match (self.state, next) {
            // Beginning a new match or ending a previous one
            (MatchState::Match, MatchState::Before)       // Have before context, no after context
            | (MatchState::Match, MatchState::Match)      // No before context, no after context
            | (MatchState::After, MatchState::Before)     // Have before context, have after context
            | (MatchState::After, MatchState::Match) => { // Have after context, no before context
                self.maybe_emit();
            }

            (_prev, next) => {
                self.state = next;
            }
        }
    }

    fn collect(&mut self) -> &Vec<SearchMatch> {
        self.maybe_emit();
        return &self.matches;
    }
}

impl Drop for SearchMatchCollector {
    fn drop(&mut self) {
        self.maybe_emit();
    }
}

impl Sink for SearchMatchCollector {
    type Error = std::io::Error;

    fn matched(
        &mut self,
        _searcher: &Searcher,
        mat: &SinkMatch<'_>,
    ) -> Result<bool, std::io::Error> {
        self.transition(MatchState::Match);

        // TODO: handle errors
        let line = Line(
            mat.line_number().expect("grab line number"),
            String::from_utf8_lossy(mat.bytes()).to_string(),
        );

        self.cur_match_line = Some(line);

        Ok(true)
    }

    fn context(
        &mut self,
        _searcher: &Searcher,
        ctx: &SinkContext<'_>,
    ) -> Result<bool, std::io::Error> {
        // TODO: handle errors.
        // TODO: can we avoid the additional .to_string() by storing a COW instead?
        let line = Line(
            ctx.line_number().expect("grab line number"),
            String::from_utf8_lossy(ctx.bytes()).to_string(),
        );

        match ctx.kind() {
            &SinkContextKind::Before => {
                self.transition(MatchState::Before);
                self.cur_context_pre.push(line);
            }
            &SinkContextKind::After => {
                self.transition(MatchState::After);
                self.cur_context_post.push(line);
            }
            &SinkContextKind::Other => {}
        }

        Ok(true)
    }
}

trait Replacer {
    fn replace(&self, input: &str) -> Option<String>;
}

struct RegexReplacer<'a> {
    matcher: &'a RegexMatcher,
    template: &'a str,
}

impl<'a> Replacer for RegexReplacer<'a> {
    fn replace(&self, input: &str) -> Option<String> {
        let mut caps = self.matcher.new_captures().unwrap();
        let mut dst = vec![];

        self.matcher
            .replace_with_captures(input.as_bytes(), &mut caps, &mut dst, |caps, dst| {
                caps.interpolate(
                    |name| self.matcher.capture_index(name),
                    input.as_bytes(),
                    self.template.as_bytes(),
                    dst,
                );
                false
            })
            .unwrap();

        Some(String::from_utf8_lossy(&dst).to_string())
    }
}

type MatchDecider = dyn Fn(&SearchMatch) -> ReplacementDecision;

#[derive(Debug)]
struct Change {
    line_number: u64,
    // TODO: use slice here
    new_line: String,
}

struct SearchMatchProcessor<'a> {
    replacer: &'a dyn Replacer,
    acceptor: &'a MatchDecider,

    decide_all: Option<bool>,
}

impl<'a> SearchMatchProcessor<'a> {
    fn new(replacer: &'a dyn Replacer, acceptor: &'a MatchDecider) -> SearchMatchProcessor<'a> {
        return SearchMatchProcessor {
            replacer,
            acceptor,
            decide_all: None,
        };
    }

    fn handle_path(&mut self, path: &Path, matches: &Vec<SearchMatch>) {
        if matches.is_empty() || Some(false) == self.decide_all {
            return;
        }
        println!(
            "--- {}: {} match{}",
            path.display(),
            matches.len(),
            if matches.len() == 1 { "" } else { "es" }
        );
        let mut accept_remaining = false;

        let mut change_list = vec![];
        for m in matches {
            let replacement = if let Some(r) = self.replacer.replace(&m.line.1) {
                r
            } else {
                println!("TODO: replacer failed on line");
                continue;
            };
            self.display(m, &replacement);

            let change = if accept_remaining || Some(true) == self.decide_all {
                m.as_change(replacement)
            } else {
                match (self.acceptor)(m) {
                    ReplacementDecision::IgnoreThis => continue,
                    ReplacementDecision::IgnoreFile => break,
                    ReplacementDecision::IgnoreRest => {
                        self.decide_all = Some(false);
                        break;
                    }
                    ReplacementDecision::AcceptThis => m.as_change(replacement),
                    ReplacementDecision::AcceptFile => {
                        accept_remaining = true;
                        m.as_change(replacement)
                    }
                    ReplacementDecision::EditThis => {
                        print!("Replace with [^D to skip] ");
                        std::io::stdout().flush().unwrap();
                        let mut line: String = read!("{}\n");
                        if line == "" {
                            println!("... skipped ...");
                            continue;
                        }

                        line.push('\n');
                        self.display(m, &line);
                        println!("--");
                        m.as_change(line)
                    }
                }
            };

            change_list.push(change);
        }

        // For --prompt, confirm before applying here
        if !change_list.is_empty() {
            self.apply_changes(path, &mut change_list);
        }

        println!("");
    }

    fn display(&self, m: &SearchMatch, replacement: &str) {
        // TODO: only show this gap if non-consecutive
        println!("    ...");
        for line in &m.context_pre {
            print!("    {}: {}", line.0, line.1);
        }

        // TODO: Multiple matches on same line
        // TODO: Disable colors when not atty
        // TODO: Align line number with padding.
        print!("\x1B[31m-   {}: {}\x1B[0m", m.line.0, m.line.1);
        print!("\x1B[32m+   {}: {}\x1B[0m", m.line.0, replacement);

        for line in &m.context_post {
            print!("    {}: {}", line.0, line.1);
        }
    }

    fn apply_changes(&self, path: &Path, mut changes: &[Change]) {
        let dst_path = path.with_extension("~");
        let src = File::open(path).expect("couldn't open file");
        let dst = File::create(&dst_path).expect("couldn't create file");

        let mut reader = BufReader::new(src);
        let mut writer = BufWriter::new(dst);

        let mut line_num = 0;
        loop {
            let mut line = String::new();
            let bytes_read = reader.read_line(&mut line).expect("read line");
            // EOF reached
            if bytes_read == 0 {
                break;
            }

            line_num += 1;

            if !changes.is_empty() && changes[0].line_number == line_num {
                writer.write(changes[0].new_line.as_bytes()).unwrap();
                changes = &changes[1..];
            } else {
                writer.write(line.as_bytes()).unwrap();
            }
        }
    }
}

#[derive(Debug)]
enum ReplacementDecision {
    IgnoreThis,
    IgnoreFile,
    IgnoreRest,
    AcceptThis,
    AcceptFile,
    EditThis,
}

fn prompt_for_decision() -> ReplacementDecision {
    loop {
        print!("Stage this replacement [Y,n,q,a,e,d,?] ");
        std::io::stdout().flush().unwrap();
        let line: String = read!("{}\n");
        // TODO: ^D should not result in acceptance

        return match line.as_str() {
            "y" | "Y" => ReplacementDecision::AcceptThis,
            "n" => ReplacementDecision::IgnoreThis,
            "q" => ReplacementDecision::IgnoreRest,
            "a" => ReplacementDecision::AcceptFile,
            "d" => ReplacementDecision::IgnoreFile,
            "e" => ReplacementDecision::EditThis,

            "?" | _ => {
                println!(
                    "\x1B[31m
Y - replace this line
n - do not replace this line
q - quit; do not replace this line or any remaining ones
a - replace this line and all remaining ones in this file
d - do not replace this line nor any remaining ones in this file
e - edit this replacement
? - show help
\x1B[0m"
                );
                continue;
            }
        };
    }
}

fn main() {
    let opts: Opts = Opts::from_args();
    println!("Parsed opts: {:?}", opts);

    let matcher = RegexMatcherBuilder::new()
        .case_insensitive(opts.insensitive)
        .build(&opts.find)
        .expect("bad pattern");

    let mut searcher = SearcherBuilder::new()
        .binary_detection(BinaryDetection::quit(0x00))
        .line_number(true)
        .before_context(max(opts.context, opts.before))
        .after_context(max(opts.context, opts.after))
        .build();

    // TODO: Confirm that template does not reference more capture groups than exist.
    let replacer = RegexReplacer {
        matcher: &matcher,
        template: &opts.replace,
    };

    if opts.dry_run && opts.prompt {
        println!("WARN: --prompt does not make sense with --dry-run, skipping");
    }

    let acceptor = if opts.dry_run {
        |_: &SearchMatch| ReplacementDecision::IgnoreThis
    } else if opts.prompt {
        |_: &SearchMatch| prompt_for_decision()
    } else {
        |_: &SearchMatch| ReplacementDecision::AcceptThis
    };
    let mut proc = SearchMatchProcessor::new(&replacer, &acceptor);

    let paths = if opts.paths.is_empty() {
        vec![Path::new("./").to_owned()]
    } else {
        opts.paths
    };

    for path in paths {
        // TODO: Support files as well as directories here
        for dir_entry in Walk::new(path) {
            let dir_entry = dir_entry.unwrap();
            let path = dir_entry.path();
            if !path.is_file() {
                continue;
            }

            let mut sink = SearchMatchCollector::new();

            searcher
                .search_path(&matcher, dir_entry.path(), &mut sink)
                .expect("search failed");

            let matches = sink.collect();
            proc.handle_path(path, matches);
        }
    }

    if opts.dry_run {
        println!("--dry-run enabled, no changes applied.");
    }

    println!("All done.");
}
<commit_msg>Rewrite original file<commit_after>use std::cmp::max;
use std::fs::File;
use std::io::{BufRead, BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};

use grep::matcher::{Captures, Matcher};
use grep::regex::{RegexMatcher, RegexMatcherBuilder};
use grep::searcher::{
    BinaryDetection, Searcher, SearcherBuilder, Sink, SinkContext, SinkContextKind, SinkMatch,
};
use ignore::Walk;
use structopt::StructOpt;
use text_io::read;

#[derive(Debug, StructOpt)]
#[structopt(name = "fnr")]
/// Look for things, optionally replace them.
struct Opts {
    /// Run search in case insensitive mode
    #[structopt(short, long)]
    insensitive: bool,

    /// Print out replacements without actually performing them
    #[structopt(short, long)]
    dry_run: bool,

    #[structopt(short = "A", long, default_value = "0")]
    after: usize,
    #[structopt(short = "B", long, default_value = "0")]
    before: usize,
    #[structopt(short = "C", long, default_value = "0")]
    context: usize,

    #[structopt(short, long)]
    prompt: bool,

    /// What to search for.
    #[structopt(name = "FIND")]
    find: String,

    /// What to replace it with.
    #[structopt(name = "REPLACE")]
    replace: String,

    /// Locations to search. Current directory if not specified.
    #[structopt(name = "PATH", parse(from_os_str))]
    paths: Vec<PathBuf>,
}

#[derive(Debug, Clone)]
struct Line(u64, String);

#[derive(Debug)]
struct SearchMatch {
    line: Line,
    context_pre: Vec<Line>,
    context_post: Vec<Line>,
}

impl SearchMatch {
    fn as_change(&self, line: String) -> Change {
        return Change {
            line_number: self.line.0,
            new_line: line,
        };
    }
}

#[derive(Debug, Copy, Clone, PartialEq)]
enum MatchState {
    Init,
    Before,
    Match,
    After,
}

#[derive(Debug)]
struct SearchMatchCollector {
    state: MatchState,

    cur_context_pre: Vec<Line>,
    cur_context_post: Vec<Line>,
    cur_match_line: Option<Line>,

    matches: Vec<SearchMatch>,
}

impl SearchMatchCollector {
    fn new() -> SearchMatchCollector {
        return SearchMatchCollector {
            state: MatchState::Init,
            cur_match_line: None,
            cur_context_pre: Vec::new(),
            cur_context_post: Vec::new(),
            matches: Vec::new(),
        };
    }

    fn maybe_emit(&mut self) {
        if let Some(line) = &self.cur_match_line {
            // TODO: clones are wasteful here.
            let m = SearchMatch {
                line: line.clone(),
                context_pre: self.cur_context_pre.clone(),
                context_post: self.cur_context_post.clone(),
            };

            self.matches.push(m);
            self.reset();
        }
    }

    fn reset(&mut self) {
        self.state = MatchState::Init;

        self.cur_match_line = None;
        self.cur_context_pre.clear();
        self.cur_context_post.clear();
    }

    #[inline]
    fn transition(&mut self, next: MatchState) {
        match (self.state, next) {
            // Beginning a new match or ending a previous one
            (MatchState::Match, MatchState::Before)       // Have before context, no after context
            | (MatchState::Match, MatchState::Match)      // No before context, no after context
            | (MatchState::After, MatchState::Before)     // Have before context, have after context
            | (MatchState::After, MatchState::Match) => { // Have after context, no before context
                self.maybe_emit();
            }

            (_prev, next) => {
                self.state = next;
            }
        }
    }

    fn collect(&mut self) -> &Vec<SearchMatch> {
        self.maybe_emit();
        return &self.matches;
    }
}

impl Drop for SearchMatchCollector {
    fn drop(&mut self) {
        self.maybe_emit();
    }
}

impl Sink for SearchMatchCollector {
    type Error = std::io::Error;

    fn matched(
        &mut self,
        _searcher: &Searcher,
        mat: &SinkMatch<'_>,
    ) -> Result<bool, std::io::Error> {
        self.transition(MatchState::Match);

        // TODO: handle errors
        let line = Line(
            mat.line_number().expect("grab line number"),
            String::from_utf8_lossy(mat.bytes()).to_string(),
        );

        self.cur_match_line = Some(line);

        Ok(true)
    }

    fn context(
        &mut self,
        _searcher: &Searcher,
        ctx: &SinkContext<'_>,
    ) -> Result<bool, std::io::Error> {
        // TODO: handle errors.
        // TODO: can we avoid the additional .to_string() by storing a COW instead?
        let line = Line(
            ctx.line_number().expect("grab line number"),
            String::from_utf8_lossy(ctx.bytes()).to_string(),
        );

        match ctx.kind() {
            &SinkContextKind::Before => {
                self.transition(MatchState::Before);
                self.cur_context_pre.push(line);
            }
            &SinkContextKind::After => {
                self.transition(MatchState::After);
                self.cur_context_post.push(line);
            }
            &SinkContextKind::Other => {}
        }

        Ok(true)
    }
}

trait Replacer {
    fn replace(&self, input: &str) -> Option<String>;
}

struct RegexReplacer<'a> {
    matcher: &'a RegexMatcher,
    template: &'a str,
}

impl<'a> Replacer for RegexReplacer<'a> {
    fn replace(&self, input: &str) -> Option<String> {
        let mut caps = self.matcher.new_captures().unwrap();
        let mut dst = vec![];

        self.matcher
            .replace_with_captures(input.as_bytes(), &mut caps, &mut dst, |caps, dst| {
                caps.interpolate(
                    |name| self.matcher.capture_index(name),
                    input.as_bytes(),
                    self.template.as_bytes(),
                    dst,
                );
                false
            })
            .unwrap();

        Some(String::from_utf8_lossy(&dst).to_string())
    }
}

type MatchDecider = dyn Fn(&SearchMatch) -> ReplacementDecision;

#[derive(Debug)]
struct Change {
    line_number: u64,
    // TODO: use slice here
    new_line: String,
}

struct SearchMatchProcessor<'a> {
    replacer: &'a dyn Replacer,
    acceptor: &'a MatchDecider,

    decide_all: Option<bool>,
}

impl<'a> SearchMatchProcessor<'a> {
    fn new(replacer: &'a dyn Replacer, acceptor: &'a MatchDecider) -> SearchMatchProcessor<'a> {
        return SearchMatchProcessor {
            replacer,
            acceptor,
            decide_all: None,
        };
    }

    fn handle_path(&mut self, path: &Path, matches: &Vec<SearchMatch>) {
        if matches.is_empty() || Some(false) == self.decide_all {
            return;
        }
        println!(
            "--- {}: {} match{}",
            path.display(),
            matches.len(),
            if matches.len() == 1 { "" } else { "es" }
        );
        let mut accept_remaining = false;

        let mut change_list = vec![];
        for m in matches {
            let replacement = if let Some(r) = self.replacer.replace(&m.line.1) {
                r
            } else {
                println!("TODO: replacer failed on line");
                continue;
            };
            self.display(m, &replacement);

            let change = if accept_remaining || Some(true) == self.decide_all {
                m.as_change(replacement)
            } else {
                match (self.acceptor)(m) {
                    ReplacementDecision::IgnoreThis => continue,
                    ReplacementDecision::IgnoreFile => break,
                    ReplacementDecision::IgnoreRest => {
                        self.decide_all = Some(false);
                        break;
                    }
                    ReplacementDecision::AcceptThis => m.as_change(replacement),
                    ReplacementDecision::AcceptFile => {
                        accept_remaining = true;
                        m.as_change(replacement)
                    }
                    ReplacementDecision::EditThis => {
                        print!("Replace with [^D to skip] ");
                        std::io::stdout().flush().unwrap();
                        let mut line: String = read!("{}\n");
                        if line == "" {
                            println!("... skipped ...");
                            continue;
                        }

                        line.push('\n');
                        self.display(m, &line);
                        println!("--");
                        m.as_change(line)
                    }
                }
            };

            change_list.push(change);
        }

        // For --prompt, confirm before applying here
        if !change_list.is_empty() {
            self.apply_changes(path, &mut change_list);
        }

        println!("");
    }

    fn display(&self, m: &SearchMatch, replacement: &str) {
        // TODO: only show this gap if non-consecutive
        println!("    ...");
        for line in &m.context_pre {
            print!("    {}: {}", line.0, line.1);
        }

        // TODO: Multiple matches on same line
        // TODO: Disable colors when not atty
        // TODO: Align line number with padding.
        print!("\x1B[31m-   {}: {}\x1B[0m", m.line.0, m.line.1);
        print!("\x1B[32m+   {}: {}\x1B[0m", m.line.0, replacement);

        for line in &m.context_post {
            print!("    {}: {}", line.0, line.1);
        }
    }

    fn apply_changes(&self, path: &Path, mut changes: &[Change]) {
        let dst_path = path.with_extension("~");
        let src = File::open(path).expect("couldn't open file");
        let dst = File::create(&dst_path).expect("couldn't create file");

        let mut reader = BufReader::new(src);
        let mut writer = BufWriter::new(dst);

        let mut line_num = 0;
        loop {
            let mut line = String::new();
            let bytes_read = reader.read_line(&mut line).expect("read line");
            // EOF reached
            if bytes_read == 0 {
                break;
            }

            line_num += 1;

            if !changes.is_empty() && changes[0].line_number == line_num {
                writer.write(changes[0].new_line.as_bytes()).unwrap();
                changes = &changes[1..];
            } else {
                writer.write(line.as_bytes()).unwrap();
            }
        }

        std::fs::rename(dst_path, path).expect("rename file");
    }
}

#[derive(Debug)]
enum ReplacementDecision {
    IgnoreThis,
    IgnoreFile,
    IgnoreRest,
    AcceptThis,
    AcceptFile,
    EditThis,
}

fn prompt_for_decision() -> ReplacementDecision {
    loop {
        print!("Stage this replacement [Y,n,q,a,e,d,?] ");
        std::io::stdout().flush().unwrap();
        let line: String = read!("{}\n");
        // TODO: ^D should not result in acceptance

        return match line.as_str() {
            "y" | "Y" => ReplacementDecision::AcceptThis,
            "n" => ReplacementDecision::IgnoreThis,
            "q" => ReplacementDecision::IgnoreRest,
            "a" => ReplacementDecision::AcceptFile,
            "d" => ReplacementDecision::IgnoreFile,
            "e" => ReplacementDecision::EditThis,

            "?" | _ => {
                println!(
                    "\x1B[31m
Y - replace this line
n - do not replace this line
q - quit; do not replace this line or any remaining ones
a - replace this line and all remaining ones in this file
d - do not replace this line nor any remaining ones in this file
e - edit this replacement
? - show help
\x1B[0m"
                );
                continue;
            }
        };
    }
}

fn main() {
    let opts: Opts = Opts::from_args();
    println!("Parsed opts: {:?}", opts);

    let matcher = RegexMatcherBuilder::new()
        .case_insensitive(opts.insensitive)
        .build(&opts.find)
        .expect("bad pattern");

    let mut searcher = SearcherBuilder::new()
        .binary_detection(BinaryDetection::quit(0x00))
        .line_number(true)
        .before_context(max(opts.context, opts.before))
        .after_context(max(opts.context, opts.after))
        .build();

    // TODO: Confirm that template does not reference more capture groups than exist.
    let replacer = RegexReplacer {
        matcher: &matcher,
        template: &opts.replace,
    };

    if opts.dry_run && opts.prompt {
        println!("WARN: --prompt does not make sense with --dry-run, skipping");
    }

    let acceptor = if opts.dry_run {
        |_: &SearchMatch| ReplacementDecision::IgnoreThis
    } else if opts.prompt {
        |_: &SearchMatch| prompt_for_decision()
    } else {
        |_: &SearchMatch| ReplacementDecision::AcceptThis
    };
    let mut proc = SearchMatchProcessor::new(&replacer, &acceptor);

    let paths = if opts.paths.is_empty() {
        vec![Path::new("./").to_owned()]
    } else {
        opts.paths
    };

    for path in paths {
        // TODO: Support files as well as directories here
        for dir_entry in Walk::new(path) {
            let dir_entry = dir_entry.unwrap();
            let path = dir_entry.path();
            if !path.is_file() {
                continue;
            }

            let mut sink = SearchMatchCollector::new();

            searcher
                .search_path(&matcher, dir_entry.path(), &mut sink)
                .expect("search failed");

            let matches = sink.collect();
            proc.handle_path(path, matches);
        }
    }

    if opts.dry_run {
        println!("--dry-run enabled, no changes applied.");
    }

    println!("All done.");
}
<|endoftext|>


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

use dom::bindings::codegen::BindingDeclarations::HTMLMeterElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLMeterElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLMeterElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLMeterElement {
    pub htmlelement: HTMLElement
}

impl HTMLMeterElementDerived for EventTarget {
    fn is_htmlmeterelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLMeterElementTypeId))
    }
}

impl HTMLMeterElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLMeterElement {
        HTMLMeterElement {
            htmlelement: HTMLElement::new_inherited(HTMLMeterElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLMeterElement> {
        let element = HTMLMeterElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLMeterElementBinding::Wrap)
    }
}

pub trait HTMLMeterElementMethods {
    fn Value(&self) -> f64;
    fn SetValue(&mut self, _value: f64) -> ErrorResult;
    fn Min(&self) -> f64;
    fn SetMin(&mut self, _min: f64) -> ErrorResult;
    fn Max(&self) -> f64;
    fn SetMax(&mut self, _max: f64) -> ErrorResult;
    fn Low(&self) -> f64;
    fn SetLow(&mut self, _low: f64) -> ErrorResult;
    fn High(&self) -> f64;
    fn SetHigh(&mut self, _high: f64) -> ErrorResult;
    fn Optimum(&self) -> f64;
    fn SetOptimum(&mut self, _optimum: f64) -> ErrorResult;
}

impl<'a> HTMLMeterElementMethods for JSRef<'a, HTMLMeterElement> {
    fn Value(&self) -> f64 {
        0.0
    }

    fn SetValue(&mut self, _value: f64) -> ErrorResult {
        Ok(())
    }

    fn Min(&self) -> f64 {
        0.0
    }

    fn SetMin(&mut self, _min: f64) -> ErrorResult {
        Ok(())
    }

    fn Max(&self) -> f64 {
        0.0
    }

    fn SetMax(&mut self, _max: f64) -> ErrorResult {
        Ok(())
    }

    fn Low(&self) -> f64 {
        0.0
    }

    fn SetLow(&mut self, _low: f64) -> ErrorResult {
        Ok(())
    }

    fn High(&self) -> f64 {
        0.0
    }

    fn SetHigh(&mut self, _high: f64) -> ErrorResult {
        Ok(())
    }

    fn Optimum(&self) -> f64 {
        0.0
    }

    fn SetOptimum(&mut self, _optimum: f64) -> ErrorResult {
        Ok(())
    }
}

<commit_msg>Remove needless '&mut self' from HTMLMeterElementMethods.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use dom::bindings::codegen::BindingDeclarations::HTMLMeterElementBinding;
use dom::bindings::codegen::InheritTypes::HTMLMeterElementDerived;
use dom::bindings::js::{JSRef, Temporary};
use dom::bindings::error::ErrorResult;
use dom::document::Document;
use dom::element::HTMLMeterElementTypeId;
use dom::eventtarget::{EventTarget, NodeTargetTypeId};
use dom::htmlelement::HTMLElement;
use dom::node::{Node, ElementNodeTypeId};
use servo_util::str::DOMString;

#[deriving(Encodable)]
pub struct HTMLMeterElement {
    pub htmlelement: HTMLElement
}

impl HTMLMeterElementDerived for EventTarget {
    fn is_htmlmeterelement(&self) -> bool {
        self.type_id == NodeTargetTypeId(ElementNodeTypeId(HTMLMeterElementTypeId))
    }
}

impl HTMLMeterElement {
    pub fn new_inherited(localName: DOMString, document: &JSRef<Document>) -> HTMLMeterElement {
        HTMLMeterElement {
            htmlelement: HTMLElement::new_inherited(HTMLMeterElementTypeId, localName, document)
        }
    }

    pub fn new(localName: DOMString, document: &JSRef<Document>) -> Temporary<HTMLMeterElement> {
        let element = HTMLMeterElement::new_inherited(localName, document);
        Node::reflect_node(box element, document, HTMLMeterElementBinding::Wrap)
    }
}

pub trait HTMLMeterElementMethods {
    fn Value(&self) -> f64;
    fn SetValue(&self, _value: f64) -> ErrorResult;
    fn Min(&self) -> f64;
    fn SetMin(&self, _min: f64) -> ErrorResult;
    fn Max(&self) -> f64;
    fn SetMax(&self, _max: f64) -> ErrorResult;
    fn Low(&self) -> f64;
    fn SetLow(&self, _low: f64) -> ErrorResult;
    fn High(&self) -> f64;
    fn SetHigh(&self, _high: f64) -> ErrorResult;
    fn Optimum(&self) -> f64;
    fn SetOptimum(&self, _optimum: f64) -> ErrorResult;
}

impl<'a> HTMLMeterElementMethods for JSRef<'a, HTMLMeterElement> {
    fn Value(&self) -> f64 {
        0.0
    }

    fn SetValue(&self, _value: f64) -> ErrorResult {
        Ok(())
    }

    fn Min(&self) -> f64 {
        0.0
    }

    fn SetMin(&self, _min: f64) -> ErrorResult {
        Ok(())
    }

    fn Max(&self) -> f64 {
        0.0
    }

    fn SetMax(&self, _max: f64) -> ErrorResult {
        Ok(())
    }

    fn Low(&self) -> f64 {
        0.0
    }

    fn SetLow(&self, _low: f64) -> ErrorResult {
        Ok(())
    }

    fn High(&self) -> f64 {
        0.0
    }

    fn SetHigh(&self, _high: f64) -> ErrorResult {
        Ok(())
    }

    fn Optimum(&self) -> f64 {
        0.0
    }

    fn SetOptimum(&self, _optimum: f64) -> ErrorResult {
        Ok(())
    }
}

<|endoftext|>


<commit_before>use na::Real;
use pipeline::events::{ContactEvent, ContactEvents, ProximityEvent, ProximityEvents};
use pipeline::narrow_phase::{
    ContactAlgorithm, ContactDispatcher, ContactPairs, NarrowPhase, ProximityAlgorithm,
    ProximityDispatcher, ProximityPairs,
};
use pipeline::world::{CollisionObjectHandle, CollisionObjectSlab, GeometricQueryType};
use query::Proximity;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use utils::{DeterministicState, SortedPair};
use utils::IdAllocator;

// FIXME: move this to the `narrow_phase` module.
/// Collision detector dispatcher for collision objects.
pub struct DefaultNarrowPhase<N> {
    id_alloc: IdAllocator,
    contact_dispatcher: Box<ContactDispatcher<N>>,
    contact_generators:
    HashMap<SortedPair<CollisionObjectHandle>, ContactAlgorithm<N>, DeterministicState>,

    proximity_dispatcher: Box<ProximityDispatcher<N>>,
    proximity_detectors:
    HashMap<SortedPair<CollisionObjectHandle>, ProximityAlgorithm<N>, DeterministicState>,
}

impl<N: 'static> DefaultNarrowPhase<N> {
    /// Creates a new `DefaultNarrowPhase`.
    pub fn new(
        contact_dispatcher: Box<ContactDispatcher<N>>,
        proximity_dispatcher: Box<ProximityDispatcher<N>>,
    ) -> DefaultNarrowPhase<N> {
        DefaultNarrowPhase {
            id_alloc: IdAllocator::new(),
            contact_dispatcher: contact_dispatcher,
            contact_generators: HashMap::with_hasher(DeterministicState::new()),

            proximity_dispatcher: proximity_dispatcher,
            proximity_detectors: HashMap::with_hasher(DeterministicState::new()),
        }
    }
}

impl<N: Real, T> NarrowPhase<N, T> for DefaultNarrowPhase<N> {
    fn update(
        &mut self,
        objects: &CollisionObjectSlab<N, T>,
        contact_events: &mut ContactEvents,
        proximity_events: &mut ProximityEvents,
        timestamp: usize,
    ) {
        for (key, value) in self.contact_generators.iter_mut() {
            let co1 = &objects[key.0];
            let co2 = &objects[key.1];

            if co1.timestamp == timestamp || co2.timestamp == timestamp {
                let had_contacts = value.num_contacts() != 0;

                if let Some(prediction) = co1
                    .query_type()
                    .contact_queries_to_prediction(co2.query_type())
                    {
                        let _ = value.update(
                            &*self.contact_dispatcher,
                            0,
                            &co1.position(),
                            co1.shape().as_ref(),
                            0,
                            &co2.position(),
                            co2.shape().as_ref(),
                            &prediction,
                            &mut self.id_alloc,
                        );
                    } else {
                    panic!("Unable to compute contact between collision objects with query types different from `GeometricQueryType::Contacts(..)`.")
                }

                if value.num_contacts() == 0 {
                    if had_contacts {
                        contact_events.push(ContactEvent::Stopped(co1.handle(), co2.handle()));
                    }
                } else {
                    if !had_contacts {
                        contact_events.push(ContactEvent::Started(co1.handle(), co2.handle()));
                    }
                }
            }
        }

        for (key, value) in self.proximity_detectors.iter_mut() {
            let co1 = &objects[key.0];
            let co2 = &objects[key.1];

            if co1.timestamp == timestamp || co2.timestamp == timestamp {
                let prev_prox = value.proximity();

                let _ = value.update(
                    &*self.proximity_dispatcher,
                    &co1.position(),
                    co1.shape().as_ref(),
                    &co2.position(),
                    co2.shape().as_ref(),
                    co1.query_type().query_limit() + co2.query_type().query_limit(),
                );

                let new_prox = value.proximity();

                if new_prox != prev_prox {
                    proximity_events.push(ProximityEvent::new(
                        co1.handle(),
                        co2.handle(),
                        prev_prox,
                        new_prox,
                    ));
                }
            }
        }
    }

    fn interaction_started(
        &mut self,
        objects: &CollisionObjectSlab<N, T>,
        handle1: CollisionObjectHandle,
        handle2: CollisionObjectHandle,
    ) {
        let key = SortedPair::new(handle1, handle2);
        let co1 = &objects[key.0];
        let co2 = &objects[key.1];

        match (co1.query_type(), co2.query_type()) {
            (GeometricQueryType::Contacts(..), GeometricQueryType::Contacts(..)) => {
                let dispatcher = &self.contact_dispatcher;

                if let Entry::Vacant(entry) = self.contact_generators.entry(key) {
                    if let Some(detector) = dispatcher
                        .get_contact_algorithm(co1.shape().as_ref(), co2.shape().as_ref())
                    {
                        let _ = entry.insert(detector);
                    }
                }
            }
            (_, GeometricQueryType::Proximity(_)) | (GeometricQueryType::Proximity(_), _) => {
                let dispatcher = &self.proximity_dispatcher;

                if let Entry::Vacant(entry) = self.proximity_detectors.entry(key) {
                    if let Some(detector) = dispatcher
                        .get_proximity_algorithm(co1.shape().as_ref(), co2.shape().as_ref())
                    {
                        let _ = entry.insert(detector);
                    }
                }
            }
        }
    }

    fn interaction_stopped(
        &mut self,
        contact_events: &mut ContactEvents,
        proximity_events: &mut ProximityEvents,
        objects: &CollisionObjectSlab<N, T>,
        handle1: CollisionObjectHandle,
        handle2: CollisionObjectHandle,
    ) {
        let key = SortedPair::new(handle1, handle2);
        let co1 = &objects[key.0];
        let co2 = &objects[key.1];

        match (co1.query_type(), co2.query_type()) {
            (GeometricQueryType::Contacts(..), GeometricQueryType::Contacts(..)) => {
                if let Some(detector) = self.contact_generators.remove(&key) {
                    // Register a collision lost event if there was a contact.
                    if detector.num_contacts() != 0 {
                        contact_events.push(ContactEvent::Stopped(co1.handle(), co2.handle()));
                    }

                    detector.clear(&mut self.id_alloc);
                }
            }
            (_, GeometricQueryType::Proximity(_)) | (GeometricQueryType::Proximity(_), _) => {
                if let Some(detector) = self.proximity_detectors.remove(&key) {
                    // Register a proximity lost signal if they were not disjoint.
                    let prev_prox = detector.proximity();

                    if prev_prox != Proximity::Disjoint {
                        let event = ProximityEvent::new(
                            co1.handle(),
                            co2.handle(),
                            prev_prox,
                            Proximity::Disjoint,
                        );
                        proximity_events.push(event);
                    }
                }
            }
        }
    }

    fn handle_removal(
        &mut self,
        _: &CollisionObjectSlab<N, T>,
        handle1: CollisionObjectHandle,
        handle2: CollisionObjectHandle,
    ) {
        let key = SortedPair::new(handle1, handle2);
        let _ = self.proximity_detectors.remove(&key);

        if let Some(mut gen) = self.contact_generators.remove(&key) {
            gen.clear(&mut self.id_alloc);
        }
    }

    fn contact_pair(
        &self,
        handle1: CollisionObjectHandle,
        handle2: CollisionObjectHandle,
    ) -> Option<&ContactAlgorithm<N>> {
        let key = SortedPair::new(handle1, handle2);
        self.contact_generators.get(&key)
    }

    fn contact_pairs<'a>(
        &'a self,
        objects: &'a CollisionObjectSlab<N, T>,
    ) -> ContactPairs<'a, N, T> {
        ContactPairs::new(objects, self.contact_generators.iter())
    }

    fn proximity_pairs<'a>(
        &'a self,
        objects: &'a CollisionObjectSlab<N, T>,
    ) -> ProximityPairs<'a, N, T> {
        ProximityPairs::new(objects, self.proximity_detectors.iter())
    }
}
<commit_msg>Fix missing 'mut'.<commit_after>use na::Real;
use pipeline::events::{ContactEvent, ContactEvents, ProximityEvent, ProximityEvents};
use pipeline::narrow_phase::{
    ContactAlgorithm, ContactDispatcher, ContactPairs, NarrowPhase, ProximityAlgorithm,
    ProximityDispatcher, ProximityPairs,
};
use pipeline::world::{CollisionObjectHandle, CollisionObjectSlab, GeometricQueryType};
use query::Proximity;
use std::collections::hash_map::Entry;
use std::collections::HashMap;
use utils::{DeterministicState, SortedPair};
use utils::IdAllocator;

// FIXME: move this to the `narrow_phase` module.
/// Collision detector dispatcher for collision objects.
pub struct DefaultNarrowPhase<N> {
    id_alloc: IdAllocator,
    contact_dispatcher: Box<ContactDispatcher<N>>,
    contact_generators:
    HashMap<SortedPair<CollisionObjectHandle>, ContactAlgorithm<N>, DeterministicState>,

    proximity_dispatcher: Box<ProximityDispatcher<N>>,
    proximity_detectors:
    HashMap<SortedPair<CollisionObjectHandle>, ProximityAlgorithm<N>, DeterministicState>,
}

impl<N: 'static> DefaultNarrowPhase<N> {
    /// Creates a new `DefaultNarrowPhase`.
    pub fn new(
        contact_dispatcher: Box<ContactDispatcher<N>>,
        proximity_dispatcher: Box<ProximityDispatcher<N>>,
    ) -> DefaultNarrowPhase<N> {
        DefaultNarrowPhase {
            id_alloc: IdAllocator::new(),
            contact_dispatcher: contact_dispatcher,
            contact_generators: HashMap::with_hasher(DeterministicState::new()),

            proximity_dispatcher: proximity_dispatcher,
            proximity_detectors: HashMap::with_hasher(DeterministicState::new()),
        }
    }
}

impl<N: Real, T> NarrowPhase<N, T> for DefaultNarrowPhase<N> {
    fn update(
        &mut self,
        objects: &CollisionObjectSlab<N, T>,
        contact_events: &mut ContactEvents,
        proximity_events: &mut ProximityEvents,
        timestamp: usize,
    ) {
        for (key, value) in self.contact_generators.iter_mut() {
            let co1 = &objects[key.0];
            let co2 = &objects[key.1];

            if co1.timestamp == timestamp || co2.timestamp == timestamp {
                let had_contacts = value.num_contacts() != 0;

                if let Some(prediction) = co1
                    .query_type()
                    .contact_queries_to_prediction(co2.query_type())
                    {
                        let _ = value.update(
                            &*self.contact_dispatcher,
                            0,
                            &co1.position(),
                            co1.shape().as_ref(),
                            0,
                            &co2.position(),
                            co2.shape().as_ref(),
                            &prediction,
                            &mut self.id_alloc,
                        );
                    } else {
                    panic!("Unable to compute contact between collision objects with query types different from `GeometricQueryType::Contacts(..)`.")
                }

                if value.num_contacts() == 0 {
                    if had_contacts {
                        contact_events.push(ContactEvent::Stopped(co1.handle(), co2.handle()));
                    }
                } else {
                    if !had_contacts {
                        contact_events.push(ContactEvent::Started(co1.handle(), co2.handle()));
                    }
                }
            }
        }

        for (key, value) in self.proximity_detectors.iter_mut() {
            let co1 = &objects[key.0];
            let co2 = &objects[key.1];

            if co1.timestamp == timestamp || co2.timestamp == timestamp {
                let prev_prox = value.proximity();

                let _ = value.update(
                    &*self.proximity_dispatcher,
                    &co1.position(),
                    co1.shape().as_ref(),
                    &co2.position(),
                    co2.shape().as_ref(),
                    co1.query_type().query_limit() + co2.query_type().query_limit(),
                );

                let new_prox = value.proximity();

                if new_prox != prev_prox {
                    proximity_events.push(ProximityEvent::new(
                        co1.handle(),
                        co2.handle(),
                        prev_prox,
                        new_prox,
                    ));
                }
            }
        }
    }

    fn interaction_started(
        &mut self,
        objects: &CollisionObjectSlab<N, T>,
        handle1: CollisionObjectHandle,
        handle2: CollisionObjectHandle,
    ) {
        let key = SortedPair::new(handle1, handle2);
        let co1 = &objects[key.0];
        let co2 = &objects[key.1];

        match (co1.query_type(), co2.query_type()) {
            (GeometricQueryType::Contacts(..), GeometricQueryType::Contacts(..)) => {
                let dispatcher = &self.contact_dispatcher;

                if let Entry::Vacant(entry) = self.contact_generators.entry(key) {
                    if let Some(detector) = dispatcher
                        .get_contact_algorithm(co1.shape().as_ref(), co2.shape().as_ref())
                        {
                            let _ = entry.insert(detector);
                        }
                }
            }
            (_, GeometricQueryType::Proximity(_)) | (GeometricQueryType::Proximity(_), _) => {
                let dispatcher = &self.proximity_dispatcher;

                if let Entry::Vacant(entry) = self.proximity_detectors.entry(key) {
                    if let Some(detector) = dispatcher
                        .get_proximity_algorithm(co1.shape().as_ref(), co2.shape().as_ref())
                        {
                            let _ = entry.insert(detector);
                        }
                }
            }
        }
    }

    fn interaction_stopped(
        &mut self,
        contact_events: &mut ContactEvents,
        proximity_events: &mut ProximityEvents,
        objects: &CollisionObjectSlab<N, T>,
        handle1: CollisionObjectHandle,
        handle2: CollisionObjectHandle,
    ) {
        let key = SortedPair::new(handle1, handle2);
        let co1 = &objects[key.0];
        let co2 = &objects[key.1];

        match (co1.query_type(), co2.query_type()) {
            (GeometricQueryType::Contacts(..), GeometricQueryType::Contacts(..)) => {
                if let Some(mut detector) = self.contact_generators.remove(&key) {
                    // Register a collision lost event if there was a contact.
                    if detector.num_contacts() != 0 {
                        contact_events.push(ContactEvent::Stopped(co1.handle(), co2.handle()));
                    }

                    detector.clear(&mut self.id_alloc);
                }
            }
            (_, GeometricQueryType::Proximity(_)) | (GeometricQueryType::Proximity(_), _) => {
                if let Some(detector) = self.proximity_detectors.remove(&key) {
                    // Register a proximity lost signal if they were not disjoint.
                    let prev_prox = detector.proximity();

                    if prev_prox != Proximity::Disjoint {
                        let event = ProximityEvent::new(
                            co1.handle(),
                            co2.handle(),
                            prev_prox,
                            Proximity::Disjoint,
                        );
                        proximity_events.push(event);
                    }
                }
            }
        }
    }

    fn handle_removal(
        &mut self,
        _: &CollisionObjectSlab<N, T>,
        handle1: CollisionObjectHandle,
        handle2: CollisionObjectHandle,
    ) {
        let key = SortedPair::new(handle1, handle2);
        let _ = self.proximity_detectors.remove(&key);

        if let Some(mut gen) = self.contact_generators.remove(&key) {
            gen.clear(&mut self.id_alloc);
        }
    }

    fn contact_pair(
        &self,
        handle1: CollisionObjectHandle,
        handle2: CollisionObjectHandle,
    ) -> Option<&ContactAlgorithm<N>> {
        let key = SortedPair::new(handle1, handle2);
        self.contact_generators.get(&key)
    }

    fn contact_pairs<'a>(
        &'a self,
        objects: &'a CollisionObjectSlab<N, T>,
    ) -> ContactPairs<'a, N, T> {
        ContactPairs::new(objects, self.contact_generators.iter())
    }

    fn proximity_pairs<'a>(
        &'a self,
        objects: &'a CollisionObjectSlab<N, T>,
    ) -> ProximityPairs<'a, N, T> {
        ProximityPairs::new(objects, self.proximity_detectors.iter())
    }
}
<|endoftext|>


<commit_before>use std::ops::Deref;
use glium::Display;

use layout::LayoutBuffer;
use resource::ResourceManager;
use util::BufferFromTree;
use state::StateBuffer;
use state::StateData;

use super::RenderData;
use super::TextureRule;

pub struct RenderBuffer {
    render_data: BufferFromTree<RenderData>,
}

impl Deref for RenderBuffer {
    type Target = [RenderData];

    fn deref<'a>(&'a self) -> &'a [RenderData] {
        self.render_data.deref()
    }
}

impl RenderBuffer {

    pub fn new<R>(
        display: &Display,
        resource_manager: &R,
        state_buffer: &StateBuffer) -> RenderBuffer
        where R: ResourceManager
    {
        let node_producer = |state: &StateData| {
            if let Some(img) = state.get_background_image() {
                let rule = state.get_background_rule().unwrap_or(TextureRule::Fit);
                Some(RenderData::new(
                    display,
                    resource_manager,
                    img,
                    rule
                ))
            } else {
                None
            }
        };

        RenderBuffer {
            render_data: BufferFromTree::from_buffer(
                state_buffer,
                node_producer
            )
        }
    }

    pub fn update_from_state<R: ResourceManager>(
        &mut self,
        display: &Display,
        resource_manager: &R,
        state_data: &StateBuffer)
    {

        for (&i, data) in self.render_data.enumerate_lookup_indices_mut().unwrap() {

            let state = unsafe { state_data.get_unchecked(i) };

            if let Some(img) = state.get_background_image() {

                data.update_texture(display, resource_manager, img);
            }
        }
    }

    pub fn update_from_layout(&mut self, display: &Display, layout_data: &LayoutBuffer) {

        for (&i, data) in self.render_data.enumerate_lookup_indices_mut().unwrap() {
            // This part is always safe because the initialization step
            // ensure that:
            //       self.layout_data.len() >= self.render_data
            let boxi = unsafe { layout_data.get_unchecked(i) };
            data.update_coords(display, &boxi);
        }
    }
}

// ======================================== //
//                   TESTS                  //
// ======================================== //

#[cfg(test)]
mod test {

    use super::RenderBuffer;
    use std::io::BufReader;
    use std::path::PathBuf;
    use glutin::WindowBuilder;
    use glium::DisplayBuild;
    use markup::{self, Node};
    use style;
    use state::StateBuffer;
    use oil_shared::style::Stylesheet;
    use oil_shared::deps::{Constructor, StyleDefinitions};
    use oil_parsers::{StdOutErrorReporter};
    use resource::{self, ResourceManager};

    fn stylesheet<R: ResourceManager>(st: &str, r: &mut R) -> Stylesheet {
        let reader = BufReader::new(st.as_bytes());
        let mut defs = StyleDefinitions::new();
        defs.insert("toto".to_string(),
            Constructor::Image(PathBuf::new(), None, None, None, None));
        style::parse(StdOutErrorReporter, reader, &defs, r)
    }

    fn markup_tree(mk: &str) -> markup::Node {
        let reader = BufReader::new(mk.as_bytes());
        let lib = markup::parse(StdOutErrorReporter, reader);
        let (_, root) = lib.views.into_iter().next().unwrap();
        root
    }

    #[test]
    fn lookup_table_should_contain_correct_indices() {

        let mut fake_resource_manager = resource::create_null_manager();
        let stylesheet = stylesheet(
            ".btn { background-image: $toto; }",
            &mut fake_resource_manager);
        let root = markup_tree(
            "<view>\
                <button class=\"btn\"></button>\
                <button class=\"\"></button>\
                <button class=\"btn\"></button>\
            </view>
            ");
        let state_buffer = StateBuffer::new(&root, &stylesheet);

        // FIXME(This match is here to have the travis test pass)
        if let Some(fake_display) = WindowBuilder::new()
            .with_dimensions(1, 1).with_visibility(false).build_glium().ok()
        {

            let mut buffer = RenderBuffer::new(
                &fake_display,
                &fake_resource_manager,
                &state_buffer
            );

            assert_eq!(buffer.render_data.len(), 2);
            let mut iter = buffer.render_data.enumerate_lookup_indices_mut().unwrap();
            let (&i, _) = iter.next().unwrap();
            assert_eq!(i, 1);
            let (&j, _) = iter.next().unwrap();
            assert_eq!(j, 3);
        }
    }
}
<commit_msg>Removing temporarily the test. Could be fixed by supporting glium in headless mode.<commit_after>use std::ops::Deref;
use glium::Display;

use layout::LayoutBuffer;
use resource::ResourceManager;
use util::BufferFromTree;
use state::StateBuffer;
use state::StateData;

use super::RenderData;
use super::TextureRule;

pub struct RenderBuffer {
    render_data: BufferFromTree<RenderData>,
}

impl Deref for RenderBuffer {
    type Target = [RenderData];

    fn deref<'a>(&'a self) -> &'a [RenderData] {
        self.render_data.deref()
    }
}

impl RenderBuffer {

    pub fn new<R>(
        display: &Display,
        resource_manager: &R,
        state_buffer: &StateBuffer) -> RenderBuffer
        where R: ResourceManager
    {
        let node_producer = |state: &StateData| {
            if let Some(img) = state.get_background_image() {
                let rule = state.get_background_rule().unwrap_or(TextureRule::Fit);
                Some(RenderData::new(
                    display,
                    resource_manager,
                    img,
                    rule
                ))
            } else {
                None
            }
        };

        RenderBuffer {
            render_data: BufferFromTree::from_buffer(
                state_buffer,
                node_producer
            )
        }
    }

    pub fn update_from_state<R: ResourceManager>(
        &mut self,
        display: &Display,
        resource_manager: &R,
        state_data: &StateBuffer)
    {

        for (&i, data) in self.render_data.enumerate_lookup_indices_mut().unwrap() {

            let state = unsafe { state_data.get_unchecked(i) };

            if let Some(img) = state.get_background_image() {

                data.update_texture(display, resource_manager, img);
            }
        }
    }

    pub fn update_from_layout(&mut self, display: &Display, layout_data: &LayoutBuffer) {

        for (&i, data) in self.render_data.enumerate_lookup_indices_mut().unwrap() {
            // This part is always safe because the initialization step
            // ensure that:
            //       self.layout_data.len() >= self.render_data
            let boxi = unsafe { layout_data.get_unchecked(i) };
            data.update_coords(display, &boxi);
        }
    }
}

// ======================================== //
//                   TESTS                  //
// ======================================== //

#[cfg(test)]
mod test {

    use super::RenderBuffer;
    use std::io::BufReader;
    use std::path::PathBuf;
    use glutin::WindowBuilder;
    use glium::DisplayBuild;
    use markup::{self, Node};
    use style;
    use state::StateBuffer;
    use oil_shared::style::Stylesheet;
    use oil_shared::deps::{Constructor, StyleDefinitions};
    use oil_parsers::{StdOutErrorReporter};
    use resource::{self, ResourceManager};

    fn stylesheet<R: ResourceManager>(st: &str, r: &mut R) -> Stylesheet {
        let reader = BufReader::new(st.as_bytes());
        let mut defs = StyleDefinitions::new();
        defs.insert("toto".to_string(),
            Constructor::Image(PathBuf::new(), None, None, None, None));
        style::parse(StdOutErrorReporter, reader, &defs, r)
    }

    fn markup_tree(mk: &str) -> markup::Node {
        let reader = BufReader::new(mk.as_bytes());
        let lib = markup::parse(StdOutErrorReporter, reader);
        let (_, root) = lib.views.into_iter().next().unwrap();
        root
    }

    // TODO(Nemikolh): Fix that test by allowing glium in headless.
    //                 Will require some refactoring.
    //#[test]
    // fn lookup_table_should_contain_correct_indices() {
    //
    //     let mut fake_resource_manager = resource::create_null_manager();
    //     let stylesheet = stylesheet(
    //         ".btn { background-image: $toto; }",
    //         &mut fake_resource_manager);
    //     let root = markup_tree(
    //         "<view>\
    //             <button class=\"btn\"></button>\
    //             <button class=\"\"></button>\
    //             <button class=\"btn\"></button>\
    //         </view>
    //         ");
    //     let state_buffer = StateBuffer::new(&root, &stylesheet);
    //
    //     // FIXME(This match is here to have the travis test pass)
    //     if let Some(fake_display) = WindowBuilder::new()
    //         .with_dimensions(1, 1).with_visibility(false).build_glium().ok()
    //     {
    //
    //         let mut buffer = RenderBuffer::new(
    //             &fake_display,
    //             &fake_resource_manager,
    //             &state_buffer
    //         );
    //
    //         assert_eq!(buffer.render_data.len(), 2);
    //         let mut iter = buffer.render_data.enumerate_lookup_indices_mut().unwrap();
    //         let (&i, _) = iter.next().unwrap();
    //         assert_eq!(i, 1);
    //         let (&j, _) = iter.next().unwrap();
    //         assert_eq!(j, 3);
    //     }
    // }
}
<|endoftext|>


<commit_before>
<commit_msg>remove unused examples file to let `cargo test` run<commit_after><|endoftext|>


<commit_before>// Just instantiate some data structures to make sure we got all their foreign items covered.
// Requires full MIR on Windows.

use std::sync;

fn main() {
    let m = sync::Mutex::new(0);
    let _ = m.lock();
    drop(m);

    let rw = sync::RwLock::new(0);
    let _ = rw.read();
    let _ = rw.write();
    drop(rw);
}
<commit_msg>no RwLock on Windows<commit_after>// Just instantiate some data structures to make sure we got all their foreign items covered.
// Requires full MIR on Windows.

use std::sync;

fn main() {
    let m = sync::Mutex::new(0);
    let _ = m.lock();
    drop(m);

    // We don't provide RwLock on Windows
    #[cfg(not(target_os = "windows"))]
    {
        let rw = sync::RwLock::new(0);
        let _ = rw.read();
        let _ = rw.write();
        drop(rw);
    }
}
<|endoftext|>