<commit_before>extern crate rand;
extern crate itertools;
use self::itertools::Itertools;
use super::*;
use super::wrap;

use super::super::cli::SocketLend;

use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Entry;

const RATIO_TO_COCATEGORIZE: f64 = 0.4;
const COCATEGORY_TRAVEL_DISTANCE: i32 = 0;
const COCATEGORIZE_MAGNITUDE: i32 = 65536;

impl<R: rand::Rng> Lexicon<R> {
    /// Make a new lexion. It needs its own Rng for internal purposes of learning.
    pub fn new(rng: R) -> Lexicon<R> {
        Lexicon{
            rng: rng,
            cocategorization_ratio: RATIO_TO_COCATEGORIZE,
            cocategory_travel_distance: COCATEGORY_TRAVEL_DISTANCE,
            cocategorize_magnitude: COCATEGORIZE_MAGNITUDE,
            words: Default::default(),
            sources: Default::default(),
            conversations: Default::default(),
            messages: Default::default(),
            active_conversations: Default::default(),
        }
    }

    /// Get a source by its unique name.
    pub fn source(&mut self, name: String) -> SourceCell {
        match self.sources.entry(name.clone()) {
            Entry::Vacant(v) => v.insert(wrap(Source{
                name: name,
                messages: 0,
                authors: BTreeMap::default(),
            })).clone(),
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    /// Get an author identifier from a particular source.
    pub fn author(&mut self, source: SourceCell, name: String) -> AuthorCell {
        match source.borrow_mut().authors.entry(name.clone()) {
            Entry::Vacant(v) => {
                let a = wrap(Author{
                    source: source.clone(),
                    name: name.clone(),
                });
                v.insert(a.clone());
                a
            },
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    /// Tell a message to the lexicon and potentially get a response back.
    pub fn tell(&mut self, source: SourceCell, author: AuthorCell, content: String) {
        let conversation = match self.active_conversations.entry(source.clone()) {
            Entry::Vacant(v) => {
                let c = wrap(Conversation{
                    source: source.clone(),
                    messages: Vec::new(),
                });
                v.insert(c.clone());
                self.conversations.push(c.clone());
                c
            },
            Entry::Occupied(o) => {
                o.get().clone()
            },
        };

        let message = wrap(Message{
            author: author.clone(),
            conversation: conversation.clone(),
            index: conversation.borrow().messages.len(),
            instances: Vec::new(),
        });

        self.messages.push(message.clone());

        // Add message to conversation
        {
            let mut cb = conversation.borrow_mut();
            cb.messages.push(message.clone());
        }

        for word in content.split(' ').map(|s| {
            let string = s.to_string();
            match self.words.entry(string.clone()) {
                Entry::Vacant(v) => {
                    let w = wrap(Word{
                        name: string,
                        instances: Vec::new(),
                    });
                    v.insert(w.clone());
                    w
                },
                Entry::Occupied(o) => {
                    o.get().clone()
                },
            }
        }) {
            // Create empty category for the word
            let category = wrap(Category::default());
            // Create instance of the word
            let instance = wrap(WordInstance{
                word: word.clone(),
                category: category.clone(),
                message: message.clone(),
                index: message.borrow().instances.len(),
            });
            // Insert word instance into the word, category, and message for future reference
            message.borrow_mut().instances.push(instance.clone());
            category.borrow_mut().instances.push(instance.clone());
            word.borrow_mut().instances.push(instance);
        }

        // Increment the messages by 1 for the source
        source.borrow_mut().messages += 1;

        // Learn the message immediately
        self.learn(message);
    }

    /// Switch conversations
    pub fn switch(&mut self, source: SourceCell) {
        let conversation = wrap(Conversation{
            source: source.clone(),
            messages: Vec::new(),
        });

        match self.active_conversations.entry(source.clone()) {
            Entry::Vacant(v) => {
                v.insert(conversation.clone());
            },
            Entry::Occupied(mut o) => {
                o.insert(conversation.clone());
            },
        };

        self.conversations.push(conversation.clone());
    }

    /// Say something based on the conversation context
    pub fn respond(&mut self, source: SourceCell) -> Option<(String, String)> {
        use std::collections::VecDeque;
        let base = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return None,
        };

        // Make a double-ended vec for building the message out of categories
        let mut instances = VecDeque::new();

        let mut orig_index = if let Some(con) = self.active_conversations.get(&source) {
            let cb = con.borrow();
            if let Some(conm) = cb.messages.last() {
                let mb = conm.borrow();
                instances.push_back(self.rng.choose(&mb.instances[..]).unwrap().clone());
                0
            } else {
                instances.push_back(self.rng.choose(&base.borrow().instances[..]).unwrap().clone());
                8192
            }
        } else {
            instances.push_back(self.rng.choose(&base.borrow().instances[..]).unwrap().clone());
            8192
        };

        let forward_instance_chooser = |b: &Category, rng: &mut R| {
            // Find the count of how many word instances exist total
            let mut count = b.instances.len();
            for cocategory in &b.precocategories {
                count += cocategory.borrow().instances.len();
            }
            // Generate an index based on the count
            let mut i = rng.gen_range(0, count);
            match b.instances.get(i) {
                // It was in the original category
                Some(ins) => ins.clone(),
                // It was in a cocategory
                None => {
                    // Subtract the cocategory length from the index
                    i -= b.instances.len();
                    for cocategory in &b.precocategories {
                        let b = cocategory.borrow();
                        // If it was in this category
                        if let Some(ins) = b.instances.get(i) {
                            // Clone the instance and return it
                            return ins.clone();
                        }
                        // Otherwise subtract by the amount of instances in this cocategory
                        i -= b.instances.len();
                    }
                    // The index should point to some category, so this is unreachable
                    unreachable!();
                },
            }
        };

        let backward_instance_chooser = |b: &Category, rng: &mut R| {
            // Find the count of how many word instances exist total
            let mut count = b.instances.len();
            for cocategory in &b.postcocategories {
                count += cocategory.borrow().instances.len();
            }
            // Generate an index based on the count
            let mut i = rng.gen_range(0, count);
            match b.instances.get(i) {
                // It was in the original category
                Some(ins) => ins.clone(),
                // It was in a cocategory
                None => {
                    // Subtract the cocategory length from the index
                    i -= b.instances.len();
                    for cocategory in &b.postcocategories {
                        let b = cocategory.borrow();
                        // If it was in this category
                        if let Some(ins) = b.instances.get(i) {
                            // Clone the instance and return it
                            return ins.clone();
                        }
                        // Otherwise subtract by the amount of instances in this cocategory
                        i -= b.instances.len();
                    }
                    // The index should point to some category, so this is unreachable
                    unreachable!();
                },
            }
        };

        // Iterate forwards weaving between messages and adding instances to the vec
        loop {
            let ins = instances.back().unwrap().borrow().next_instance();
            if let Some(i) = ins {
                let b = i.borrow();
                instances.push_back(forward_instance_chooser(&b.category.borrow(), &mut self.rng));
            } else {
                break;
            }
        }
        // Iterate backwards to reach the beginning of the message
        loop {
            let ins = instances.front().unwrap().borrow().prev_instance();
            if let Some(i) = ins {
                let b = i.borrow();
                instances.push_front(backward_instance_chooser(&b.category.borrow(), &mut self.rng));
                orig_index += 1;
            } else {
                break;
            }
        }

        Some((
            instances.iter()
                .map(|instance| {
                    let ins = instance.borrow();
                    let word = ins.word.borrow();
                    word.name.clone()
                })
                .join(" "),
            instances.iter()
                .cloned()
                .enumerate()
                .map(|(index, mut instance)| {
                    if index != orig_index {
                        for _ in 0..self.cocategory_travel_distance {
                            instance = {
                                let b = instance.borrow();
                                if self.rng.gen_range(0, 2) == 0 {
                                    backward_instance_chooser(&b.category.borrow(), &mut self.rng)
                                } else {
                                    forward_instance_chooser(&b.category.borrow(), &mut self.rng)
                                }
                            };
                        }
                    }
                    instance
                })
                .map(|instance| {
                    let ins = instance.borrow();
                    let word = ins.word.borrow();
                    word.name.clone()
                })
                .join(" ")
        ))
    }

    /// Have seifmios attempt to initiate a conversation at a source, but it may fail.
    pub fn initiate(&mut self, source: SourceCell) -> Option<(String, String)> {
        self.switch(source.clone());
        self.respond(source)
    }

    /// Thinks one iteration
    pub fn think(&mut self) {
        // Learn a random message if there are some
        let m = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return,
        };

        self.learn(m.clone());
    }

    pub fn learn(&mut self, message: MessageCell) {
        // Vector of absolute perfect matches
        let mut vones = Vec::new();

        // Look through each word in the message
        for word in &message.borrow().instances {
            let borrow = word.borrow();
            // Check each instance in that words instances
            for instance in &borrow.word.borrow().instances {
                // Get the message for each instance
                let omessage = instance.borrow().message.clone();
                // Find what kind of matches exist between the messages
                if let Mismatch::One(best) =
                    Message::category_and_word_mismatch((message.clone(), omessage.clone())) {
                    vones.push(best);
                }
            }
        }

        // Now that we have perfect matches, merge them into the same Category
        for ms in vones {
            // We only want to combine if they aren't already in the same category
            if ms.0.borrow().category != ms.1.borrow().category {
                let cats = (ms.0.borrow().category.clone(), ms.1.borrow().category.clone());
                Category::merge(cats);
            }
        }

        for _ in 0..self.cocategorize_magnitude {
            // Get two random categories (we already know messages exist from above)
            Category::cocategorize((
                {
                    let b = message.borrow();
                    let b = self.rng.choose(&b.instances[..]).unwrap().borrow();
                    b.category.clone()
                },
                {
                    let b = self.rng.choose(&self.messages[..]).unwrap().borrow();
                    let b = self.rng.choose(&b.instances[..]).unwrap().borrow();
                    b.category.clone()
                },
            ), self.cocategorization_ratio);
        }
    }

    /// Print all multiple categories and return the amount of categories total
    pub fn show_categories(&self, socket: &mut SocketLend) {
        let mut set = BTreeSet::new();
        for message in &self.messages {
            for instance in &message.borrow().instances {
                let ib = instance.borrow();
                set.insert(ib.category.clone());
            }
        }

        for cat in set {
            let catr = cat.borrow();
            if catr.instances.len() != 1 {
                socket.msg("Category:");
                for cocategory in &catr.precocategories {
                    socket.msg("\tPre-Cocategory:");
                    let catr = cocategory.borrow();
                    for instance in &catr.instances {
                        let ib = instance.borrow();
                        socket.msg(&format!("\t\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                    }
                }
                for cocategory in &catr.postcocategories {
                    socket.msg("\tPost-Cocategory:");
                    let catr = cocategory.borrow();
                    for instance in &catr.instances {
                        let ib = instance.borrow();
                        socket.msg(&format!("\t\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                    }
                }
                for instance in &catr.instances {
                    let ib = instance.borrow();
                    socket.msg(&format!("\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                }
            }
        }
    }

    pub fn find_relation(&self, words: (String, String), socket: &mut SocketLend) {
        let wls = (self.words.get(&words.0), self.words.get(&words.1));
        match wls {
            (Some(w0), Some(w1)) => {
                let b = w0.borrow();
                for instance in &b.instances {
                    let b = instance.borrow();
                    let cb = b.category.borrow();

                    for cins in &cb.instances {
                        if cins.borrow().word == *w1 {
                            socket.msg("Category:");
                            for instance in &cb.instances {
                                let ib = instance.borrow();
                                socket.msg(&format!("\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                            }
                            break;
                        }
                    }

                    // Check all the precategories
                    for prec in &cb.precocategories {
                        let cb = prec.borrow();
                        for cins in &cb.instances {
                            if cins.borrow().word == *w1 {
                                socket.msg("Pre-Cocategory:");
                                for instance in &cb.instances {
                                    let ib = instance.borrow();
                                    socket.msg(&format!("\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                                }
                                break;
                            }
                        }
                    }

                    // Check all the postcategories
                    for postc in &cb.postcocategories {
                        let cb = postc.borrow();
                        for cins in &cb.instances {
                            if cins.borrow().word == *w1 {
                                socket.msg("Post-Cocategory:");
                                for instance in &cb.instances {
                                    let ib = instance.borrow();
                                    socket.msg(&format!("\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                                }
                                break;
                            }
                        }
                    }
                }
            },
            (Some(_), None) => {
                socket.msg(&format!("Ignored: Word \"{}\" coldn't be found", words.0));
            },
            (None, Some(_)) => {
                socket.msg(&format!("Ignored: Word \"{}\" coldn't be found", words.1));
            },
            (None, None) => {
                socket.msg("Ignored: Neither word could be found");
            },
        }
    }
}
<commit_msg>fixed bug where displaying the relationship between two words had incorrect error messages<commit_after>extern crate rand;
extern crate itertools;
use self::itertools::Itertools;
use super::*;
use super::wrap;

use super::super::cli::SocketLend;

use std::collections::{BTreeMap, BTreeSet};
use std::collections::btree_map::Entry;

const RATIO_TO_COCATEGORIZE: f64 = 0.4;
const COCATEGORY_TRAVEL_DISTANCE: i32 = 0;
const COCATEGORIZE_MAGNITUDE: i32 = 65536;

impl<R: rand::Rng> Lexicon<R> {
    /// Make a new lexion. It needs its own Rng for internal purposes of learning.
    pub fn new(rng: R) -> Lexicon<R> {
        Lexicon{
            rng: rng,
            cocategorization_ratio: RATIO_TO_COCATEGORIZE,
            cocategory_travel_distance: COCATEGORY_TRAVEL_DISTANCE,
            cocategorize_magnitude: COCATEGORIZE_MAGNITUDE,
            words: Default::default(),
            sources: Default::default(),
            conversations: Default::default(),
            messages: Default::default(),
            active_conversations: Default::default(),
        }
    }

    /// Get a source by its unique name.
    pub fn source(&mut self, name: String) -> SourceCell {
        match self.sources.entry(name.clone()) {
            Entry::Vacant(v) => v.insert(wrap(Source{
                name: name,
                messages: 0,
                authors: BTreeMap::default(),
            })).clone(),
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    /// Get an author identifier from a particular source.
    pub fn author(&mut self, source: SourceCell, name: String) -> AuthorCell {
        match source.borrow_mut().authors.entry(name.clone()) {
            Entry::Vacant(v) => {
                let a = wrap(Author{
                    source: source.clone(),
                    name: name.clone(),
                });
                v.insert(a.clone());
                a
            },
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    /// Tell a message to the lexicon and potentially get a response back.
    pub fn tell(&mut self, source: SourceCell, author: AuthorCell, content: String) {
        let conversation = match self.active_conversations.entry(source.clone()) {
            Entry::Vacant(v) => {
                let c = wrap(Conversation{
                    source: source.clone(),
                    messages: Vec::new(),
                });
                v.insert(c.clone());
                self.conversations.push(c.clone());
                c
            },
            Entry::Occupied(o) => {
                o.get().clone()
            },
        };

        let message = wrap(Message{
            author: author.clone(),
            conversation: conversation.clone(),
            index: conversation.borrow().messages.len(),
            instances: Vec::new(),
        });

        self.messages.push(message.clone());

        // Add message to conversation
        {
            let mut cb = conversation.borrow_mut();
            cb.messages.push(message.clone());
        }

        for word in content.split(' ').map(|s| {
            let string = s.to_string();
            match self.words.entry(string.clone()) {
                Entry::Vacant(v) => {
                    let w = wrap(Word{
                        name: string,
                        instances: Vec::new(),
                    });
                    v.insert(w.clone());
                    w
                },
                Entry::Occupied(o) => {
                    o.get().clone()
                },
            }
        }) {
            // Create empty category for the word
            let category = wrap(Category::default());
            // Create instance of the word
            let instance = wrap(WordInstance{
                word: word.clone(),
                category: category.clone(),
                message: message.clone(),
                index: message.borrow().instances.len(),
            });
            // Insert word instance into the word, category, and message for future reference
            message.borrow_mut().instances.push(instance.clone());
            category.borrow_mut().instances.push(instance.clone());
            word.borrow_mut().instances.push(instance);
        }

        // Increment the messages by 1 for the source
        source.borrow_mut().messages += 1;

        // Learn the message immediately
        self.learn(message);
    }

    /// Switch conversations
    pub fn switch(&mut self, source: SourceCell) {
        let conversation = wrap(Conversation{
            source: source.clone(),
            messages: Vec::new(),
        });

        match self.active_conversations.entry(source.clone()) {
            Entry::Vacant(v) => {
                v.insert(conversation.clone());
            },
            Entry::Occupied(mut o) => {
                o.insert(conversation.clone());
            },
        };

        self.conversations.push(conversation.clone());
    }

    /// Say something based on the conversation context
    pub fn respond(&mut self, source: SourceCell) -> Option<(String, String)> {
        use std::collections::VecDeque;
        let base = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return None,
        };

        // Make a double-ended vec for building the message out of categories
        let mut instances = VecDeque::new();

        let mut orig_index = if let Some(con) = self.active_conversations.get(&source) {
            let cb = con.borrow();
            if let Some(conm) = cb.messages.last() {
                let mb = conm.borrow();
                instances.push_back(self.rng.choose(&mb.instances[..]).unwrap().clone());
                0
            } else {
                instances.push_back(self.rng.choose(&base.borrow().instances[..]).unwrap().clone());
                8192
            }
        } else {
            instances.push_back(self.rng.choose(&base.borrow().instances[..]).unwrap().clone());
            8192
        };

        let forward_instance_chooser = |b: &Category, rng: &mut R| {
            // Find the count of how many word instances exist total
            let mut count = b.instances.len();
            for cocategory in &b.precocategories {
                count += cocategory.borrow().instances.len();
            }
            // Generate an index based on the count
            let mut i = rng.gen_range(0, count);
            match b.instances.get(i) {
                // It was in the original category
                Some(ins) => ins.clone(),
                // It was in a cocategory
                None => {
                    // Subtract the cocategory length from the index
                    i -= b.instances.len();
                    for cocategory in &b.precocategories {
                        let b = cocategory.borrow();
                        // If it was in this category
                        if let Some(ins) = b.instances.get(i) {
                            // Clone the instance and return it
                            return ins.clone();
                        }
                        // Otherwise subtract by the amount of instances in this cocategory
                        i -= b.instances.len();
                    }
                    // The index should point to some category, so this is unreachable
                    unreachable!();
                },
            }
        };

        let backward_instance_chooser = |b: &Category, rng: &mut R| {
            // Find the count of how many word instances exist total
            let mut count = b.instances.len();
            for cocategory in &b.postcocategories {
                count += cocategory.borrow().instances.len();
            }
            // Generate an index based on the count
            let mut i = rng.gen_range(0, count);
            match b.instances.get(i) {
                // It was in the original category
                Some(ins) => ins.clone(),
                // It was in a cocategory
                None => {
                    // Subtract the cocategory length from the index
                    i -= b.instances.len();
                    for cocategory in &b.postcocategories {
                        let b = cocategory.borrow();
                        // If it was in this category
                        if let Some(ins) = b.instances.get(i) {
                            // Clone the instance and return it
                            return ins.clone();
                        }
                        // Otherwise subtract by the amount of instances in this cocategory
                        i -= b.instances.len();
                    }
                    // The index should point to some category, so this is unreachable
                    unreachable!();
                },
            }
        };

        // Iterate forwards weaving between messages and adding instances to the vec
        loop {
            let ins = instances.back().unwrap().borrow().next_instance();
            if let Some(i) = ins {
                let b = i.borrow();
                instances.push_back(forward_instance_chooser(&b.category.borrow(), &mut self.rng));
            } else {
                break;
            }
        }
        // Iterate backwards to reach the beginning of the message
        loop {
            let ins = instances.front().unwrap().borrow().prev_instance();
            if let Some(i) = ins {
                let b = i.borrow();
                instances.push_front(backward_instance_chooser(&b.category.borrow(), &mut self.rng));
                orig_index += 1;
            } else {
                break;
            }
        }

        Some((
            instances.iter()
                .map(|instance| {
                    let ins = instance.borrow();
                    let word = ins.word.borrow();
                    word.name.clone()
                })
                .join(" "),
            instances.iter()
                .cloned()
                .enumerate()
                .map(|(index, mut instance)| {
                    if index != orig_index {
                        for _ in 0..self.cocategory_travel_distance {
                            instance = {
                                let b = instance.borrow();
                                if self.rng.gen_range(0, 2) == 0 {
                                    backward_instance_chooser(&b.category.borrow(), &mut self.rng)
                                } else {
                                    forward_instance_chooser(&b.category.borrow(), &mut self.rng)
                                }
                            };
                        }
                    }
                    instance
                })
                .map(|instance| {
                    let ins = instance.borrow();
                    let word = ins.word.borrow();
                    word.name.clone()
                })
                .join(" ")
        ))
    }

    /// Have seifmios attempt to initiate a conversation at a source, but it may fail.
    pub fn initiate(&mut self, source: SourceCell) -> Option<(String, String)> {
        self.switch(source.clone());
        self.respond(source)
    }

    /// Thinks one iteration
    pub fn think(&mut self) {
        // Learn a random message if there are some
        let m = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return,
        };

        self.learn(m.clone());
    }

    pub fn learn(&mut self, message: MessageCell) {
        // Vector of absolute perfect matches
        let mut vones = Vec::new();

        // Look through each word in the message
        for word in &message.borrow().instances {
            let borrow = word.borrow();
            // Check each instance in that words instances
            for instance in &borrow.word.borrow().instances {
                // Get the message for each instance
                let omessage = instance.borrow().message.clone();
                // Find what kind of matches exist between the messages
                if let Mismatch::One(best) =
                    Message::category_and_word_mismatch((message.clone(), omessage.clone())) {
                    vones.push(best);
                }
            }
        }

        // Now that we have perfect matches, merge them into the same Category
        for ms in vones {
            // We only want to combine if they aren't already in the same category
            if ms.0.borrow().category != ms.1.borrow().category {
                let cats = (ms.0.borrow().category.clone(), ms.1.borrow().category.clone());
                Category::merge(cats);
            }
        }

        for _ in 0..self.cocategorize_magnitude {
            // Get two random categories (we already know messages exist from above)
            Category::cocategorize((
                {
                    let b = message.borrow();
                    let b = self.rng.choose(&b.instances[..]).unwrap().borrow();
                    b.category.clone()
                },
                {
                    let b = self.rng.choose(&self.messages[..]).unwrap().borrow();
                    let b = self.rng.choose(&b.instances[..]).unwrap().borrow();
                    b.category.clone()
                },
            ), self.cocategorization_ratio);
        }
    }

    /// Print all multiple categories and return the amount of categories total
    pub fn show_categories(&self, socket: &mut SocketLend) {
        let mut set = BTreeSet::new();
        for message in &self.messages {
            for instance in &message.borrow().instances {
                let ib = instance.borrow();
                set.insert(ib.category.clone());
            }
        }

        for cat in set {
            let catr = cat.borrow();
            if catr.instances.len() != 1 {
                socket.msg("Category:");
                for cocategory in &catr.precocategories {
                    socket.msg("\tPre-Cocategory:");
                    let catr = cocategory.borrow();
                    for instance in &catr.instances {
                        let ib = instance.borrow();
                        socket.msg(&format!("\t\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                    }
                }
                for cocategory in &catr.postcocategories {
                    socket.msg("\tPost-Cocategory:");
                    let catr = cocategory.borrow();
                    for instance in &catr.instances {
                        let ib = instance.borrow();
                        socket.msg(&format!("\t\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                    }
                }
                for instance in &catr.instances {
                    let ib = instance.borrow();
                    socket.msg(&format!("\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                }
            }
        }
    }

    pub fn find_relation(&self, words: (String, String), socket: &mut SocketLend) {
        let wls = (self.words.get(&words.0), self.words.get(&words.1));
        match wls {
            (Some(w0), Some(w1)) => {
                let b = w0.borrow();
                for instance in &b.instances {
                    let b = instance.borrow();
                    let cb = b.category.borrow();

                    for cins in &cb.instances {
                        if cins.borrow().word == *w1 {
                            socket.msg("Category:");
                            for instance in &cb.instances {
                                let ib = instance.borrow();
                                socket.msg(&format!("\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                            }
                            break;
                        }
                    }

                    // Check all the precategories
                    for prec in &cb.precocategories {
                        let cb = prec.borrow();
                        for cins in &cb.instances {
                            if cins.borrow().word == *w1 {
                                socket.msg("Pre-Cocategory:");
                                for instance in &cb.instances {
                                    let ib = instance.borrow();
                                    socket.msg(&format!("\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                                }
                                break;
                            }
                        }
                    }

                    // Check all the postcategories
                    for postc in &cb.postcocategories {
                        let cb = postc.borrow();
                        for cins in &cb.instances {
                            if cins.borrow().word == *w1 {
                                socket.msg("Post-Cocategory:");
                                for instance in &cb.instances {
                                    let ib = instance.borrow();
                                    socket.msg(&format!("\t{} ~ {}", ib.word.borrow().name, &*ib.message.borrow()));
                                }
                                break;
                            }
                        }
                    }
                }
            },
            (Some(_), None) => {
                socket.msg(&format!("Ignored: Word \"{}\" coldn't be found", words.1));
            },
            (None, Some(_)) => {
                socket.msg(&format!("Ignored: Word \"{}\" coldn't be found", words.0));
            },
            (None, None) => {
                socket.msg("Ignored: Neither word could be found");
            },
        }
    }
}
<|endoftext|>


<commit_before>//! # env
//!
//! Sets up the env vars before running the tasks.
//!

mod gitinfo;
mod rustinfo;

#[cfg(test)]
#[path = "./mod_test.rs"]
mod mod_test;

use self::rustinfo::Channel;
use log::Logger;
use std::env;
use std::path::PathBuf;
use types::{Config, CrateInfo, PackageInfo, Workspace};

/// Updates the env for the current execution based on the descriptor.
fn set_env(
    logger: &Logger,
    config: &Config,
) {
    logger.info::<()>("Setting Up Env.", &[], None);

    for (key, value) in &config.env {
        logger.verbose::<()>("Setting env: ", &[&key, "=", &value], None);
        env::set_var(&key, &value);
    }
}

fn setup_env_for_crate(logger: &Logger) {
    let crate_info = CrateInfo::load(&logger);

    let package_info = crate_info.package.unwrap_or(PackageInfo::new());

    if package_info.name.is_some() {
        let crate_name = package_info.name.unwrap();
        env::set_var("CARGO_MAKE_CRATE_NAME", &crate_name);

        let crate_fs_name = str::replace(&crate_name, "-", "_");
        env::set_var("CARGO_MAKE_CRATE_FS_NAME", &crate_fs_name);
    }

    if package_info.version.is_some() {
        env::set_var("CARGO_MAKE_CRATE_VERSION", &package_info.version.unwrap());
    }

    if package_info.description.is_some() {
        env::set_var("CARGO_MAKE_CRATE_DESCRIPTION", &package_info.description.unwrap());
    }

    if package_info.license.is_some() {
        env::set_var("CARGO_MAKE_CRATE_LICENSE", &package_info.license.unwrap());
    }

    if package_info.documentation.is_some() {
        env::set_var("CARGO_MAKE_CRATE_DOCUMENTATION", &package_info.documentation.unwrap());
    }

    if package_info.homepage.is_some() {
        env::set_var("CARGO_MAKE_CRATE_HOMEPAGE", &package_info.homepage.unwrap());
    }

    if package_info.repository.is_some() {
        env::set_var("CARGO_MAKE_CRATE_REPOSITORY", &package_info.repository.unwrap());
    }

    let is_workspace_var_value = if crate_info.workspace.is_none() {
        "FALSE"
    } else {
        "TRUE"
    };
    env::set_var("CARGO_MAKE_CRATE_IS_WORKSPACE", is_workspace_var_value);

    let workspace = crate_info.workspace.unwrap_or(Workspace::new());
    let members = workspace.members.unwrap_or(vec![]);
    let members_string = members.join(",");
    env::set_var("CARGO_MAKE_CRATE_WORKSPACE_MEMBERS", &members_string);
}

fn setup_env_for_git_repo(logger: &Logger) {
    let git_info = gitinfo::load(&logger);

    if git_info.branch.is_some() {
        env::set_var("CARGO_MAKE_GIT_BRANCH", &git_info.branch.unwrap());
    }

    if git_info.user_name.is_some() {
        env::set_var("CARGO_MAKE_GIT_USER_NAME", &git_info.user_name.unwrap());
    }

    if git_info.user_email.is_some() {
        env::set_var("CARGO_MAKE_GIT_USER_EMAIL", &git_info.user_email.unwrap());
    }
}

fn setup_env_for_rust(logger: &Logger) {
    let rust_info = rustinfo::load(&logger);

    if rust_info.version.is_some() {
        env::set_var("CARGO_MAKE_RUST_VERSION", &rust_info.version.unwrap());
    }

    if rust_info.channel.is_some() {
        let channel_option = rust_info.channel.unwrap();

        let channel = match channel_option {
            Channel::Stable => "stable",
            Channel::Beta => "beta",
            Channel::Nightly => "nightly",
        };

        env::set_var("CARGO_MAKE_RUST_CHANNEL", channel.to_string());
    }

    if rust_info.target_arch.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_ARCH", &rust_info.target_arch.unwrap());
    }

    if rust_info.target_env.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_ENV", &rust_info.target_env.unwrap());
    }

    if rust_info.target_os.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_OS", &rust_info.target_os.unwrap());
    }

    if rust_info.target_pointer_width.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_POINTER_WIDTH", &rust_info.target_pointer_width.unwrap());
    }

    if rust_info.target_vendor.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_VENDOR", &rust_info.target_vendor.unwrap());
    }
}

/// Sets up the env before the tasks execution.
pub fn setup_env(
    logger: &Logger,
    config: &Config,
    task: &str,
) {
    set_env(logger, config);

    env::set_var("CARGO_MAKE", "true");
    env::set_var("CARGO_MAKE_TASK", &task);

    let log_level = if logger.is_verbose_enabled() {
        "verbose"
    } else if logger.is_info_enabled() {
        "info"
    } else {
        "error"
    };

    env::set_var("CARGO_MAKE_LOG_LEVEL", log_level);

    // load crate info
    setup_env_for_crate(&logger);

    // load git info
    setup_env_for_git_repo(&logger);

    // load rust info
    setup_env_for_rust(&logger);
}

pub fn setup_cwd(
    logger: &Logger,
    cwd: Option<&str>,
) {
    let directory = cwd.unwrap_or(".");

    logger.verbose::<()>("Changing working directory to: ", &[&directory], None);

    let mut directory_path_buf = PathBuf::from(&directory);
    directory_path_buf = directory_path_buf.canonicalize().unwrap_or(directory_path_buf);
    let directory_path = directory_path_buf.as_path();

    match env::set_current_dir(&directory_path) {
        Err(error) => logger.error("Unable to set current working directory to: ", &[&directory], Some(error)),
        _ => {
            env::set_var("CARGO_MAKE_WORKING_DIRECTORY", directory_path);

            logger.verbose::<()>("Working directory changed to: ", &[&directory], None);
        }
    }
}
<commit_msg>windows workspace fix<commit_after>//! # env
//!
//! Sets up the env vars before running the tasks.
//!

mod gitinfo;
mod rustinfo;

#[cfg(test)]
#[path = "./mod_test.rs"]
mod mod_test;

use self::rustinfo::Channel;
use log::Logger;
use std::env;
use std::path::PathBuf;
use types::{Config, CrateInfo, PackageInfo, Workspace};

/// Updates the env for the current execution based on the descriptor.
fn set_env(
    logger: &Logger,
    config: &Config,
) {
    logger.info::<()>("Setting Up Env.", &[], None);

    for (key, value) in &config.env {
        logger.verbose::<()>("Setting env: ", &[&key, "=", &value], None);
        env::set_var(&key, &value);
    }
}

fn setup_env_for_crate(logger: &Logger) {
    let crate_info = CrateInfo::load(&logger);

    let package_info = crate_info.package.unwrap_or(PackageInfo::new());

    if package_info.name.is_some() {
        let crate_name = package_info.name.unwrap();
        env::set_var("CARGO_MAKE_CRATE_NAME", &crate_name);

        let crate_fs_name = str::replace(&crate_name, "-", "_");
        env::set_var("CARGO_MAKE_CRATE_FS_NAME", &crate_fs_name);
    }

    if package_info.version.is_some() {
        env::set_var("CARGO_MAKE_CRATE_VERSION", &package_info.version.unwrap());
    }

    if package_info.description.is_some() {
        env::set_var("CARGO_MAKE_CRATE_DESCRIPTION", &package_info.description.unwrap());
    }

    if package_info.license.is_some() {
        env::set_var("CARGO_MAKE_CRATE_LICENSE", &package_info.license.unwrap());
    }

    if package_info.documentation.is_some() {
        env::set_var("CARGO_MAKE_CRATE_DOCUMENTATION", &package_info.documentation.unwrap());
    }

    if package_info.homepage.is_some() {
        env::set_var("CARGO_MAKE_CRATE_HOMEPAGE", &package_info.homepage.unwrap());
    }

    if package_info.repository.is_some() {
        env::set_var("CARGO_MAKE_CRATE_REPOSITORY", &package_info.repository.unwrap());
    }

    let is_workspace_var_value = if crate_info.workspace.is_none() {
        "FALSE"
    } else {
        "TRUE"
    };
    env::set_var("CARGO_MAKE_CRATE_IS_WORKSPACE", is_workspace_var_value);

    let workspace = crate_info.workspace.unwrap_or(Workspace::new());
    let members = workspace.members.unwrap_or(vec![]);
    let members_string = members.join(",");
    env::set_var("CARGO_MAKE_CRATE_WORKSPACE_MEMBERS", &members_string);
}

fn setup_env_for_git_repo(logger: &Logger) {
    let git_info = gitinfo::load(&logger);

    if git_info.branch.is_some() {
        env::set_var("CARGO_MAKE_GIT_BRANCH", &git_info.branch.unwrap());
    }

    if git_info.user_name.is_some() {
        env::set_var("CARGO_MAKE_GIT_USER_NAME", &git_info.user_name.unwrap());
    }

    if git_info.user_email.is_some() {
        env::set_var("CARGO_MAKE_GIT_USER_EMAIL", &git_info.user_email.unwrap());
    }
}

fn setup_env_for_rust(logger: &Logger) {
    let rust_info = rustinfo::load(&logger);

    if rust_info.version.is_some() {
        env::set_var("CARGO_MAKE_RUST_VERSION", &rust_info.version.unwrap());
    }

    if rust_info.channel.is_some() {
        let channel_option = rust_info.channel.unwrap();

        let channel = match channel_option {
            Channel::Stable => "stable",
            Channel::Beta => "beta",
            Channel::Nightly => "nightly",
        };

        env::set_var("CARGO_MAKE_RUST_CHANNEL", channel.to_string());
    }

    if rust_info.target_arch.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_ARCH", &rust_info.target_arch.unwrap());
    }

    if rust_info.target_env.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_ENV", &rust_info.target_env.unwrap());
    }

    if rust_info.target_os.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_OS", &rust_info.target_os.unwrap());
    }

    if rust_info.target_pointer_width.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_POINTER_WIDTH", &rust_info.target_pointer_width.unwrap());
    }

    if rust_info.target_vendor.is_some() {
        env::set_var("CARGO_MAKE_RUST_TARGET_VENDOR", &rust_info.target_vendor.unwrap());
    }
}

/// Sets up the env before the tasks execution.
pub fn setup_env(
    logger: &Logger,
    config: &Config,
    task: &str,
) {
    set_env(logger, config);

    env::set_var("CARGO_MAKE", "true");
    env::set_var("CARGO_MAKE_TASK", &task);

    let log_level = if logger.is_verbose_enabled() {
        "verbose"
    } else if logger.is_info_enabled() {
        "info"
    } else {
        "error"
    };

    env::set_var("CARGO_MAKE_LOG_LEVEL", log_level);

    // load crate info
    setup_env_for_crate(&logger);

    // load git info
    setup_env_for_git_repo(&logger);

    // load rust info
    setup_env_for_rust(&logger);
}

pub fn setup_cwd(
    logger: &Logger,
    cwd: Option<&str>,
) {
    let directory = cwd.unwrap_or(".");

    logger.verbose::<()>("Changing working directory to: ", &[&directory], None);

    let mut directory_path_buf = PathBuf::from(&directory);
    if !cfg!(windows) {
        directory_path_buf = directory_path_buf.canonicalize().unwrap_or(directory_path_buf);
    }
    let directory_path = directory_path_buf.as_path();

    match env::set_current_dir(&directory_path) {
        Err(error) => logger.error("Unable to set current working directory to: ", &[&directory], Some(error)),
        _ => {
            env::set_var("CARGO_MAKE_WORKING_DIRECTORY", directory_path);

            logger.verbose::<()>("Working directory changed to: ", &[&directory], None);
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::BTreeMap;
use std::io;

use time;

use clog::Clog;
use git::Commit;
use error::Error;
use fmt::{FormatWriter, WriterResult};
use sectionmap::SectionMap;

/// Wraps a `std::io::Write` object to write `clog` output in a JSON format
///
/// # Example
///
/// ```no_run
/// # use std::fs::File;
/// # use clog::{SectionMap, Clog};
/// # use clog::fmt::JsonWriter;
/// let clog = Clog::new().unwrap_or_else(|e| {
///     e.exit();
/// });
///
/// // Get the commits we're interested in...
/// let sm = SectionMap::from_commits(clog.get_commits());
///
/// // Create a file to hold our results, which the JsonWriter will wrap (note, .unwrap() is only
/// // used to keep the example short and concise)
/// let mut file = File::create("my_changelog.json").ok().unwrap();
///
/// // Create the JSON Writer
/// let mut writer = JsonWriter::new(&mut file);
///
/// // Use the JsonWriter to write the changelog
/// clog.write_changelog_with(&mut writer).unwrap_or_else(|e| {
///     e.exit();
/// });
/// ```
pub struct JsonWriter<'a>(&'a mut io::Write);

impl<'a> JsonWriter<'a> {
    /// Creates a new instance of the `JsonWriter` struct using a `std::io::Write` object.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use std::io::{stdout, BufWriter};
    /// # use clog::Clog;
    /// # use clog::fmt::JsonWriter;
    /// let clog = Clog::new().unwrap_or_else(|e| {
    ///     e.exit();
    /// });
    ///
    /// // Create a JsonWriter to wrap stdout
    /// let out = stdout();
    /// let mut out_buf = BufWriter::new(out.lock());
    /// let mut writer = JsonWriter::new(&mut out_buf);
    /// ```
    pub fn new<T: io::Write>(writer: &'a mut T) -> JsonWriter<'a> {
        JsonWriter(writer)
    }
}

impl<'a> JsonWriter<'a> {
    /// Writes the initial header inforamtion for a release
    fn write_header(&mut self, options: &Clog) -> io::Result<()> {
        try!(write!(self.0, "\"header\":{{\"version\":{:?},\"patch_version\":{:?},\"subtitle\":{},",
            options.version,
            options.patch_ver,
            match options.subtitle.len() {
                0 => "null".to_owned(),
                _ => format!("{:?}", &*options.subtitle)
            }
        ));

        let date = time::now_utc();

        match date.strftime("%Y-%m-%d") {
            Ok(date) => {
                write!(
                    self.0,
                    "\"date\":\"{}\"}},",
                    date
                )
            },
            Err(_)   => {
                write!(
                    self.0,
                    "\"date\":null}},",
                )
            }
        }
    }

    /// Writes a particular section of a changelog
    fn write_section(&mut self, options: &Clog, section: &BTreeMap<&String, &Vec<Commit>>)
                            -> WriterResult {
        if section.len() == 0 {
            write!(self.0, "\"commits\":null").unwrap();
            return Ok(())
        }

        write!(self.0, "\"commits\":[").unwrap();
        for (component, entries) in section.iter() {
            let mut e_it = entries.iter().peekable();
            while let Some(entry) = e_it.next() {
                write!(self.0, "{{\"component\":").unwrap();
                if component.is_empty() {
                    write!(self.0, "null,").unwrap();
                } else {
                    write!(self.0, "{:?},", component).unwrap();
                }
                write!(
                    self.0 , "\"subject\":{:?},\"commit_link\":{:?},\"closes\":",
                    entry.subject,
                    options.link_style
                           .commit_link(&*entry.hash, &*options.repo)
                ).unwrap();

                if entry.closes.len() > 0 {
                    write!(self.0, "[").unwrap();
                    let mut c_it = entry.closes.iter().peekable();
                    while let Some(issue) = c_it.next() {
                        write!(self.0,
                            "{{\"issue\":{},\"issue_link\":{:?}}}",
                            issue,
                            options.link_style.issue_link(issue, &options.repo)
                        ).unwrap();
                        if c_it.peek().is_some() {
                            write!(self.0, ",").unwrap();
                        }
                    }
                    write!(self.0,
                        "]}}").unwrap();
                } else {
                    write!(self.0, "null}}").unwrap();
                }
                if e_it.peek().is_some() {
                    write!(self.0, ",").unwrap();
                }
            }
        }
        write!(self.0, "]").unwrap();
        Ok(())
    }

    /// Writes some contents to the `Write` writer object
    #[allow(dead_code)]
    fn write(&mut self, content: &str) -> io::Result<()> {
        write!(self.0, "{}", content)
    }
}

impl<'a> FormatWriter for JsonWriter<'a> {
    fn write_changelog(&mut self, options: &Clog, sm: &SectionMap) -> WriterResult {
        debugln!("Writing JSON changelog");
        write!(self.0, "{{").unwrap();
        if let Some(..) = self.write_header(options).err() {
        debugln!("Error writing JSON header");
            return Err(Error::WriteErr);
        }

        write!(self.0, "\"sections\":").unwrap();
        let mut s_it = sm.sections.iter().peekable();
        if s_it.peek().is_some() {
        debugln!("There are sections to write");
            write!(self.0, "[").unwrap();
            while let Some((sec, compmap)) = s_it.next() {
                debugln!("Writing section: {}", &*sec);
                write!(self.0, "{{\"title\":{:?},", &*sec).unwrap();

                try!(self.write_section(options, &compmap.iter().collect::<BTreeMap<_,_>>()));

                write!(self.0, "}}").unwrap();
                if s_it.peek().is_some() && s_it.peek().unwrap().0.len() > 0 {
                    debugln!("There are more sections, adding comma");
                    write!(self.0, ",").unwrap();
                } else {
                    debugln!("There are no more sections, no comma required");
                }
            }
            write!(self.0, "]").unwrap();
        } else {
            debugln!("There are no sections to write");
            write!(self.0, "null").unwrap();
        }

        write!(self.0, "}}").unwrap();
        debugln!("Finished writing sections, flushing");
        self.0.flush().unwrap();
        Ok(())
    }
}
<commit_msg>fix(JSON Writer): fixes a bug where needed commas are left out<commit_after>use std::collections::BTreeMap;
use std::io;

use time;

use clog::Clog;
use git::Commit;
use error::Error;
use fmt::{FormatWriter, WriterResult};
use sectionmap::SectionMap;

/// Wraps a `std::io::Write` object to write `clog` output in a JSON format
///
/// # Example
///
/// ```no_run
/// # use std::fs::File;
/// # use clog::{SectionMap, Clog};
/// # use clog::fmt::JsonWriter;
/// let clog = Clog::new().unwrap_or_else(|e| {
///     e.exit();
/// });
///
/// // Get the commits we're interested in...
/// let sm = SectionMap::from_commits(clog.get_commits());
///
/// // Create a file to hold our results, which the JsonWriter will wrap (note, .unwrap() is only
/// // used to keep the example short and concise)
/// let mut file = File::create("my_changelog.json").ok().unwrap();
///
/// // Create the JSON Writer
/// let mut writer = JsonWriter::new(&mut file);
///
/// // Use the JsonWriter to write the changelog
/// clog.write_changelog_with(&mut writer).unwrap_or_else(|e| {
///     e.exit();
/// });
/// ```
pub struct JsonWriter<'a>(&'a mut io::Write);

impl<'a> JsonWriter<'a> {
    /// Creates a new instance of the `JsonWriter` struct using a `std::io::Write` object.
    ///
    /// # Example
    ///
    /// ```no_run
    /// # use std::io::{stdout, BufWriter};
    /// # use clog::Clog;
    /// # use clog::fmt::JsonWriter;
    /// let clog = Clog::new().unwrap_or_else(|e| {
    ///     e.exit();
    /// });
    ///
    /// // Create a JsonWriter to wrap stdout
    /// let out = stdout();
    /// let mut out_buf = BufWriter::new(out.lock());
    /// let mut writer = JsonWriter::new(&mut out_buf);
    /// ```
    pub fn new<T: io::Write>(writer: &'a mut T) -> JsonWriter<'a> {
        JsonWriter(writer)
    }
}

impl<'a> JsonWriter<'a> {
    /// Writes the initial header inforamtion for a release
    fn write_header(&mut self, options: &Clog) -> io::Result<()> {
        try!(write!(self.0, "\"header\":{{\"version\":{:?},\"patch_version\":{:?},\"subtitle\":{},",
            options.version,
            options.patch_ver,
            match options.subtitle.len() {
                0 => "null".to_owned(),
                _ => format!("{:?}", &*options.subtitle)
            }
        ));

        let date = time::now_utc();

        match date.strftime("%Y-%m-%d") {
            Ok(date) => {
                write!(
                    self.0,
                    "\"date\":\"{}\"}},",
                    date
                )
            },
            Err(_)   => {
                write!(
                    self.0,
                    "\"date\":null}},",
                )
            }
        }
    }

    /// Writes a particular section of a changelog
    fn write_section(&mut self, options: &Clog, section: &BTreeMap<&String, &Vec<Commit>>)
                            -> WriterResult {
        if section.len() == 0 {
            write!(self.0, "\"commits\":null").unwrap();
            return Ok(())
        }

        write!(self.0, "\"commits\":[").unwrap();
        let mut s_it = section.iter().peekable();
        while let Some((component, entries)) = s_it.next() {
            let mut e_it = entries.iter().peekable();
            debugln!("Writing component: {}", &*component);
            while let Some(entry) = e_it.next() {
                debugln!("Writing commit: {}", &*entry.subject);
                write!(self.0, "{{\"component\":").unwrap();
                if component.is_empty() {
                    write!(self.0, "null,").unwrap();
                } else {
                    write!(self.0, "{:?},", component).unwrap();
                }
                write!(
                    self.0 , "\"subject\":{:?},\"commit_link\":{:?},\"closes\":",
                    entry.subject,
                    options.link_style
                           .commit_link(&*entry.hash, &*options.repo)
                ).unwrap();

                if entry.closes.len() > 0 {
                    write!(self.0, "[").unwrap();
                    let mut c_it = entry.closes.iter().peekable();
                    while let Some(issue) = c_it.next() {
                        write!(self.0,
                            "{{\"issue\":{},\"issue_link\":{:?}}}",
                            issue,
                            options.link_style.issue_link(issue, &options.repo)
                        ).unwrap();
                        if c_it.peek().is_some() {
                            debugln!("There are more close commits, adding comma");
                            write!(self.0, ",").unwrap();
                        } else {
                            debugln!("There are no more close commits, no comma required");
                        }
                    }
                    write!(self.0,
                        "]}}").unwrap();
                } else {
                    write!(self.0, "null}}").unwrap();
                }
                if e_it.peek().is_some() {
                    debugln!("There are more commits, adding comma");
                    write!(self.0, ",").unwrap();
                } else {
                    debugln!("There are no more commits, no comma required");
                }
            }
            if s_it.peek().is_some() {
                debugln!("There are more sections, adding comma");
                write!(self.0, ",").unwrap();
            } else {
                debugln!("There are no more commits, no comma required");
            }
        }
        write!(self.0, "]").unwrap();
        Ok(())
    }

    /// Writes some contents to the `Write` writer object
    #[allow(dead_code)]
    fn write(&mut self, content: &str) -> io::Result<()> {
        write!(self.0, "{}", content)
    }
}

impl<'a> FormatWriter for JsonWriter<'a> {
    fn write_changelog(&mut self, options: &Clog, sm: &SectionMap) -> WriterResult {
        debugln!("Writing JSON changelog");
        write!(self.0, "{{").unwrap();
        if let Some(..) = self.write_header(options).err() {
        debugln!("Error writing JSON header");
            return Err(Error::WriteErr);
        }

        write!(self.0, "\"sections\":").unwrap();
        let mut s_it = sm.sections.iter().peekable();
        if s_it.peek().is_some() {
        debugln!("There are sections to write");
            write!(self.0, "[").unwrap();
            while let Some((sec, compmap)) = s_it.next() {
                debugln!("Writing section: {}", &*sec);
                write!(self.0, "{{\"title\":{:?},", &*sec).unwrap();

                try!(self.write_section(options, &compmap.iter().collect::<BTreeMap<_,_>>()));

                write!(self.0, "}}").unwrap();
                if s_it.peek().is_some() { //&& s_it.peek().unwrap().0.len() > 0 {
                    debugln!("There are more sections, adding comma");
                    write!(self.0, ",").unwrap();
                } else {
                    debugln!("There are no more sections, no comma required");
                }
            }
            write!(self.0, "]").unwrap();
        } else {
            debugln!("There are no sections to write");
            write!(self.0, "null").unwrap();
        }

        write!(self.0, "}}").unwrap();
        debugln!("Finished writing sections, flushing");
        self.0.flush().unwrap();

        Ok(())
    }
}
<|endoftext|>


<commit_before>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...

use gfx::format::Swizzle;
use gfx::handle::RawRenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};
use gfx::Factory;

use conf;
use context::DebugId;
use error::*;
use graphics::*;
use Context;

/// A generic canvas independent of graphics backend. This type should probably
/// never be used directly; use `ggez::graphics::Canvas` instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RawRenderTargetView<Spec::Resources>,
    image: Image,
    debug_id: DebugId,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// `ggez::graphics::set_canvas()` function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
///
/// Resume drawing to the screen by calling `ggez::graphics::set_canvas(None)`.
///
/// A `Canvas` allows creating render targets to be used instead of
/// the screen.  This allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects
/// by using shaders that render to an image.
/// If you just want to draw multiple things efficiently, look at `SpriteBatch`.
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl Canvas {
    /// Create a new canvas with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u32,
        height: u32,
        samples: conf::NumSamples,
    ) -> GameResult<Canvas> {
        let debug_id = DebugId::get(ctx);
        let (w, h) = (width as u16, height as u16);
        let aa = match samples {
            conf::NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s as u8),
        };
        let kind = Kind::D2(w, h, aa);
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let texture_create_info = gfx::texture::Info {
            kind: kind,
            levels: levels,
            format: ctx.gfx_context.color_format.0,
            bind: Bind::SHADER_RESOURCE | Bind::RENDER_TARGET | Bind::TRANSFER_SRC,
            usage: Usage::Data,
        };
        let tex = factory.create_texture_raw(
            texture_create_info,
            Some(ctx.gfx_context.color_format.1),
            None,
        )?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: ctx.gfx_context.color_format.1,
            layer: None,
            min: 0,
            max: levels - 1,
            swizzle: Swizzle::new(),
        };
        let resource = factory.view_texture_as_shader_resource_raw(&tex, resource_desc)?;
        let render_desc = gfx::texture::RenderDesc {
            channel: ctx.gfx_context.color_format.1,
            level: 0,
            layer: None,
        };
        let target = factory.view_texture_as_render_target_raw(&tex, render_desc)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                texture_handle: tex,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
                debug_id,
            },
            debug_id,
        })
    }

    /// Create a new canvas with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use graphics;
        let (w, h) = graphics::get_drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(ctx, w, h, conf::NumSamples::One)
    }

    /// Gets the backend `Image` that is being rendered to.
    pub fn get_image(&self) -> &Image {
        &self.image
    }

    /// Destroys the Canvas and returns the `Image` it contains.
    pub fn into_inner(self) -> Image {
        // This texture is created with different settings
        // than the default; does that matter?
        self.image
    }
}

impl Drawable for Canvas {
    fn draw_ex(&self, ctx: &mut Context, param: DrawParam) -> GameResult<()> {
        self.debug_id.assert(ctx);
        // Gotta flip the image on the Y axis here
        // to account for OpenGL's origin being at the bottom-left.
        let mut flipped_param = param;
        flipped_param.scale.y *= -1.0;
        flipped_param.dest.y += self.image.height() as f32 * param.scale.y;
        self.image.draw_ex(ctx, flipped_param)?;
        Ok(())
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn get_blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

/// Set the canvas to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            surface.debug_id.assert(ctx);
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<commit_msg>Add grumpy admonishment to Canvas docs.<commit_after>//! I guess these docs will never appear since we re-export the canvas
//! module from graphics...

use gfx::format::Swizzle;
use gfx::handle::RawRenderTargetView;
use gfx::memory::{Bind, Usage};
use gfx::texture::{AaMode, Kind};
use gfx::Factory;

use conf;
use context::DebugId;
use error::*;
use graphics::*;
use Context;

/// A generic canvas independent of graphics backend. This type should probably
/// never be used directly; use `ggez::graphics::Canvas` instead.
#[derive(Debug)]
pub struct CanvasGeneric<Spec>
where
    Spec: BackendSpec,
{
    target: RawRenderTargetView<Spec::Resources>,
    image: Image,
    debug_id: DebugId,
}

/// A canvas that can be rendered to instead of the screen (sometimes referred
/// to as "render target" or "render to texture"). Set the canvas with the
/// `ggez::graphics::set_canvas()` function, and then anything you
/// draw will be drawn to the canvas instead of the screen.
/// Resume drawing to the screen by calling `ggez::graphics::set_canvas(None)`.
///
/// **This is not an optimization tool.**  You may be tempted to say "I'll draw a scene
/// to a `Canvas` and then just draw the single `Canvas` each frame."  This is technically
/// possible but makes life much harder than it needs to be (especially since the current
/// implementation of `Canvas` has a number of [hard-to-squash bugs](https://github.com/ggez/ggez/issues?utf8=%E2%9C%93&q=is%3Aissue+canvas+).)
/// If you want to draw things maximally efficiently, use `SpriteBatch`.
///
/// A `Canvas` allows creating render targets to be used instead of
/// the screen.  This allows graphics to be rendered to images off-screen
/// in order to do things like saving to an image file or creating cool effects
/// by using shaders that render to an image.
/// If you just want to draw multiple things efficiently, look at `SpriteBatch`.
pub type Canvas = CanvasGeneric<GlBackendSpec>;

impl Canvas {
    /// Create a new canvas with the given size and number of samples.
    pub fn new(
        ctx: &mut Context,
        width: u32,
        height: u32,
        samples: conf::NumSamples,
    ) -> GameResult<Canvas> {
        let debug_id = DebugId::get(ctx);
        let (w, h) = (width as u16, height as u16);
        let aa = match samples {
            conf::NumSamples::One => AaMode::Single,
            s => AaMode::Multi(s as u8),
        };
        let kind = Kind::D2(w, h, aa);
        let levels = 1;
        let factory = &mut ctx.gfx_context.factory;
        let texture_create_info = gfx::texture::Info {
            kind: kind,
            levels: levels,
            format: ctx.gfx_context.color_format.0,
            bind: Bind::SHADER_RESOURCE | Bind::RENDER_TARGET | Bind::TRANSFER_SRC,
            usage: Usage::Data,
        };
        let tex = factory.create_texture_raw(
            texture_create_info,
            Some(ctx.gfx_context.color_format.1),
            None,
        )?;
        let resource_desc = gfx::texture::ResourceDesc {
            channel: ctx.gfx_context.color_format.1,
            layer: None,
            min: 0,
            max: levels - 1,
            swizzle: Swizzle::new(),
        };
        let resource = factory.view_texture_as_shader_resource_raw(&tex, resource_desc)?;
        let render_desc = gfx::texture::RenderDesc {
            channel: ctx.gfx_context.color_format.1,
            level: 0,
            layer: None,
        };
        let target = factory.view_texture_as_render_target_raw(&tex, render_desc)?;
        Ok(Canvas {
            target,
            image: Image {
                texture: resource,
                texture_handle: tex,
                sampler_info: ctx.gfx_context.default_sampler_info,
                blend_mode: None,
                width,
                height,
                debug_id,
            },
            debug_id,
        })
    }

    /// Create a new canvas with the current window dimensions.
    pub fn with_window_size(ctx: &mut Context) -> GameResult<Canvas> {
        use graphics;
        let (w, h) = graphics::get_drawable_size(ctx);
        // Default to no multisampling
        Canvas::new(ctx, w, h, conf::NumSamples::One)
    }

    /// Gets the backend `Image` that is being rendered to.
    pub fn get_image(&self) -> &Image {
        &self.image
    }

    /// Destroys the Canvas and returns the `Image` it contains.
    pub fn into_inner(self) -> Image {
        // This texture is created with different settings
        // than the default; does that matter?
        self.image
    }
}

impl Drawable for Canvas {
    fn draw_ex(&self, ctx: &mut Context, param: DrawParam) -> GameResult<()> {
        self.debug_id.assert(ctx);
        // Gotta flip the image on the Y axis here
        // to account for OpenGL's origin being at the bottom-left.
        let mut flipped_param = param;
        flipped_param.scale.y *= -1.0;
        flipped_param.dest.y += self.image.height() as f32 * param.scale.y;
        self.image.draw_ex(ctx, flipped_param)?;
        Ok(())
    }
    fn set_blend_mode(&mut self, mode: Option<BlendMode>) {
        self.image.blend_mode = mode;
    }
    fn get_blend_mode(&self) -> Option<BlendMode> {
        self.image.blend_mode
    }
}

/// Set the canvas to render to. Specifying `Option::None` will cause all
/// rendering to be done directly to the screen.
pub fn set_canvas(ctx: &mut Context, target: Option<&Canvas>) {
    match target {
        Some(surface) => {
            surface.debug_id.assert(ctx);
            ctx.gfx_context.data.out = surface.target.clone();
        }
        None => {
            ctx.gfx_context.data.out = ctx.gfx_context.screen_render_target.clone();
        }
    };
}
<|endoftext|>


<commit_before><commit_msg>Add shorter fn to create Vars<commit_after><|endoftext|>


<commit_before>use databaseinfo::{DatabaseInfo, TableInfo};

use std::fmt;

#[derive(Clone)]
pub enum SExpression<'a, DB: DatabaseInfo>
where <DB as DatabaseInfo>::Table: 'a
{
    Scan {
        table: &'a <DB as DatabaseInfo>::Table,
        source_id: u32,
        yield_fn: Box<SExpression<'a, DB>>
    },
    Map {
        source_id: u32,
        yield_in_fn: Box<SExpression<'a, DB>>,
        yield_out_fn: Box<SExpression<'a, DB>>
    },
    TempGroupBy {
        source_id: u32,
        yield_in_fn: Box<SExpression<'a, DB>>,
        group_by_values: Vec<SExpression<'a, DB>>,
        yield_out_fn: Box<SExpression<'a, DB>>
    },
    Yield {
        fields: Vec<SExpression<'a, DB>>
    },
    ColumnField {
        source_id: u32,
        column_offset: u32
    },
    If {
        predicate: Box<SExpression<'a, DB>>,
        yield_fn: Box<SExpression<'a, DB>>
    },
    BinaryOp {
        op: BinaryOp,
        lhs: Box<SExpression<'a, DB>>,
        rhs: Box<SExpression<'a, DB>>
    },
    AggregateOp {
        op: AggregateOp,
        source_id: u32,
        value: Box<SExpression<'a, DB>>
    },
    CountAll {
        source_id: u32
    },
    Value(<DB as DatabaseInfo>::ColumnValue)
}

impl<'a, DB: DatabaseInfo> fmt::Display for SExpression<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.format(f, 0)
    }
}

impl<'a, DB: DatabaseInfo> SExpression<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    fn format(&self, f: &mut fmt::Formatter, indent: usize) -> Result<(), fmt::Error> {
        macro_rules! write_indent {
            ($i:expr) => (
                for _ in 0..$i {
                    try!(write!(f, "  "));
                }
            )
        }

        write_indent!(indent);

        match self {
            &SExpression::Scan { table, source_id, ref yield_fn } => {
                try!(writeln!(f, "(scan `{}` :source_id {}", table.get_name(), source_id));
                try!(yield_fn.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::Map { source_id, ref yield_in_fn, ref yield_out_fn } => {
                try!(writeln!(f, "(map :source_id {}", source_id));
                try!(yield_in_fn.format(f, indent + 1));
                try!(writeln!(f, ""));
                try!(yield_out_fn.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::TempGroupBy { source_id, ref yield_in_fn, ref group_by_values, ref yield_out_fn } => {
                try!(writeln!(f, "(temp-group-by :source_id {}", source_id));
                try!(yield_in_fn.format(f, indent + 1));
                try!(writeln!(f, ""));
                write_indent!(indent+1);
                try!(writeln!(f, "(group-by-values "));
                for group_by_value in group_by_values {
                    try!(group_by_value.format(f, indent + 2));
                    try!(writeln!(f, ""));
                }
                write_indent!(indent+1);
                try!(writeln!(f, ")"));
                try!(yield_out_fn.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::Yield { ref fields } => {
                try!(writeln!(f, "(yield "));
                for (i, field) in fields.iter().enumerate() {
                    try!(field.format(f, indent + 1));
                    if i != fields.len() - 1 {
                        try!(writeln!(f, ""));
                    }
                }
                write!(f, ")")
            },
            &SExpression::ColumnField { source_id, column_offset } => {
                write!(f, "(column-field :source_id {} :column_offset {})", source_id, column_offset)
            },
            &SExpression::If { ref predicate, ref yield_fn } => {
                try!(writeln!(f, "(if "));
                try!(predicate.format(f, indent + 1));
                try!(writeln!(f, ""));
                try!(yield_fn.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::BinaryOp { ref op, ref lhs, ref rhs } => {
                try!(writeln!(f, "({} ", op.sigil()));
                try!(lhs.format(f, indent + 1));
                try!(writeln!(f, ""));
                try!(rhs.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::AggregateOp { ref op, source_id, ref value } => {
                try!(writeln!(f, "({} :source_id {} ", op.name(), source_id));
                try!(value.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::CountAll { source_id } => {
                write!(f, "(count-all :source_id {})", source_id)
            },
            &SExpression::Value(ref v) => {
                write!(f, "{}", v)
            }
        }
    }
}

#[derive(Copy, Clone)]
pub enum BinaryOp {
    Equal,
    NotEqual,
    LessThan,
    LessThanOrEqual,
    GreaterThan,
    GreaterThanOrEqual,
    And,
    Or,
    Add,
    Subtract,
    Multiply,
    Divide,
    BitAnd,
    BitOr,
    Concatenate,
}

impl BinaryOp {
    fn sigil(&self) -> &'static str {
        use self::BinaryOp::*;

        match self {
            &Equal => "=",
            &NotEqual => "<>",
            &LessThan => "<",
            &LessThanOrEqual => "<=",
            &GreaterThan => ">",
            &GreaterThanOrEqual => ">=",
            &And => "and",
            &Or => "or",
            &Add => "+",
            &Subtract => "-",
            &Multiply => "*",
            &Divide => "/",
            &BitAnd => "&",
            &BitOr => "|",
            &Concatenate => "concat"
        }
    }
}

#[derive(Copy, Clone)]
pub enum AggregateOp {
    Count,
    First,
    Avg,
    Sum,
    Min,
    Max
}

impl AggregateOp {
    fn name(&self) -> &'static str {
        use self::AggregateOp::*;

        match self {
            &Count => "count",
            &First => "first",
            &Avg => "avg",
            &Sum => "sum",
            &Min => "min",
            &Max => "max"
        }
    }
}
<commit_msg>Adjust SExpression output<commit_after>use databaseinfo::{DatabaseInfo, TableInfo};

use std::fmt;

#[derive(Clone)]
pub enum SExpression<'a, DB: DatabaseInfo>
where <DB as DatabaseInfo>::Table: 'a
{
    Scan {
        table: &'a <DB as DatabaseInfo>::Table,
        source_id: u32,
        yield_fn: Box<SExpression<'a, DB>>
    },
    Map {
        source_id: u32,
        yield_in_fn: Box<SExpression<'a, DB>>,
        yield_out_fn: Box<SExpression<'a, DB>>
    },
    TempGroupBy {
        source_id: u32,
        yield_in_fn: Box<SExpression<'a, DB>>,
        group_by_values: Vec<SExpression<'a, DB>>,
        yield_out_fn: Box<SExpression<'a, DB>>
    },
    Yield {
        fields: Vec<SExpression<'a, DB>>
    },
    ColumnField {
        source_id: u32,
        column_offset: u32
    },
    If {
        predicate: Box<SExpression<'a, DB>>,
        yield_fn: Box<SExpression<'a, DB>>
    },
    BinaryOp {
        op: BinaryOp,
        lhs: Box<SExpression<'a, DB>>,
        rhs: Box<SExpression<'a, DB>>
    },
    AggregateOp {
        op: AggregateOp,
        source_id: u32,
        value: Box<SExpression<'a, DB>>
    },
    CountAll {
        source_id: u32
    },
    Value(<DB as DatabaseInfo>::ColumnValue)
}

impl<'a, DB: DatabaseInfo> fmt::Display for SExpression<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        self.format(f, 0)
    }
}

impl<'a, DB: DatabaseInfo> SExpression<'a, DB>
where <DB as DatabaseInfo>::Table: 'a
{
    fn format(&self, f: &mut fmt::Formatter, indent: usize) -> Result<(), fmt::Error> {
        macro_rules! write_indent {
            ($i:expr) => (
                for _ in 0..$i {
                    try!(write!(f, "  "));
                }
            )
        }

        write_indent!(indent);

        match self {
            &SExpression::Scan { table, source_id, ref yield_fn } => {
                try!(writeln!(f, "(scan `{}` :source_id {}", table.get_name(), source_id));
                try!(yield_fn.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::Map { source_id, ref yield_in_fn, ref yield_out_fn } => {
                try!(writeln!(f, "(map :source_id {}", source_id));
                try!(yield_in_fn.format(f, indent + 1));
                try!(writeln!(f, ""));
                try!(yield_out_fn.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::TempGroupBy { source_id, ref yield_in_fn, ref group_by_values, ref yield_out_fn } => {
                try!(writeln!(f, "(temp-group-by :source_id {}", source_id));
                try!(yield_in_fn.format(f, indent + 1));
                try!(writeln!(f, ""));
                write_indent!(indent+1);
                try!(write!(f, "(group-by-values"));
                for group_by_value in group_by_values {
                    try!(writeln!(f, ""));
                    try!(group_by_value.format(f, indent + 2));
                }
                try!(writeln!(f, ")"));
                try!(yield_out_fn.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::Yield { ref fields } => {
                try!(write!(f, "(yield"));
                for field in fields {
                    try!(writeln!(f, ""));
                    try!(field.format(f, indent + 1));
                }
                write!(f, ")")
            },
            &SExpression::ColumnField { source_id, column_offset } => {
                write!(f, "(column-field :source_id {} :column_offset {})", source_id, column_offset)
            },
            &SExpression::If { ref predicate, ref yield_fn } => {
                try!(writeln!(f, "(if "));
                try!(predicate.format(f, indent + 1));
                try!(writeln!(f, ""));
                try!(yield_fn.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::BinaryOp { ref op, ref lhs, ref rhs } => {
                try!(writeln!(f, "({} ", op.sigil()));
                try!(lhs.format(f, indent + 1));
                try!(writeln!(f, ""));
                try!(rhs.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::AggregateOp { ref op, source_id, ref value } => {
                try!(writeln!(f, "({} :source_id {} ", op.name(), source_id));
                try!(value.format(f, indent + 1));
                write!(f, ")")
            },
            &SExpression::CountAll { source_id } => {
                write!(f, "(count-all :source_id {})", source_id)
            },
            &SExpression::Value(ref v) => {
                write!(f, "{}", v)
            }
        }
    }
}

#[derive(Copy, Clone)]
pub enum BinaryOp {
    Equal,
    NotEqual,
    LessThan,
    LessThanOrEqual,
    GreaterThan,
    GreaterThanOrEqual,
    And,
    Or,
    Add,
    Subtract,
    Multiply,
    Divide,
    BitAnd,
    BitOr,
    Concatenate,
}

impl BinaryOp {
    fn sigil(&self) -> &'static str {
        use self::BinaryOp::*;

        match self {
            &Equal => "=",
            &NotEqual => "<>",
            &LessThan => "<",
            &LessThanOrEqual => "<=",
            &GreaterThan => ">",
            &GreaterThanOrEqual => ">=",
            &And => "and",
            &Or => "or",
            &Add => "+",
            &Subtract => "-",
            &Multiply => "*",
            &Divide => "/",
            &BitAnd => "&",
            &BitOr => "|",
            &Concatenate => "concat"
        }
    }
}

#[derive(Copy, Clone)]
pub enum AggregateOp {
    Count,
    First,
    Avg,
    Sum,
    Min,
    Max
}

impl AggregateOp {
    fn name(&self) -> &'static str {
        use self::AggregateOp::*;

        match self {
            &Count => "count",
            &First => "first",
            &Avg => "avg",
            &Sum => "sum",
            &Min => "min",
            &Max => "max"
        }
    }
}
<|endoftext|>


<commit_before>use std::collections::{HashSet, VecDeque};
use plank_syntax::position::Spanned;
use ast::cfg::{Block, BlockEnd, BlockId, BlockLink, Function, Instruction, Program};
use CompileCtx;

fn function_block_chain(f: &Function) -> VecDeque<BlockId> {
    let mut blocks = VecDeque::new();
    let mut current = if let Some(block) = f.start_block {
        block
    } else {
        return blocks;
    };
    loop {
        blocks.push_back(current);
        match f.blocks[&current].link {
            BlockLink::Strong(next) | BlockLink::Weak(next) => current = next,
            BlockLink::None => break,
        }
    }
    blocks
}

fn report_unreachable(block: &Block, ctx: &mut CompileCtx) {
    let mut span = Spanned::span(&block.ops[0]);
    for i in &block.ops {
        match **i {
            Instruction::StartStatement => {
                span = Spanned::span(i);
                break;
            }
            _ => {
                span = span.merge(Spanned::span(i));
            }
        }
    }
    ctx.reporter
        .warning("dead code detected", span)
        .span(span)
        .build();
}

fn analyze_function(f: &mut Function, ctx: &mut CompileCtx) {
    let mut blocks = function_block_chain(f);
    debug_assert_eq!(blocks.len(), f.blocks.len());
    let mut reachable = HashSet::new();
    let mut strong_reachable = None;
    let mut queue = VecDeque::new();
    if let Some(block) = f.start_block {
        queue.push_back(block);
    }
    let mut follow_strong = false;
    while !queue.is_empty() {
        while let Some(block) = queue.pop_front() {
            if !reachable.contains(&block) {
                reachable.insert(block);
                let block = &f.blocks[&block];
                match block.end {
                    BlockEnd::Branch(_, a, b) => {
                        queue.push_back(a);
                        queue.push_back(b);
                    }
                    BlockEnd::Jump(next) => {
                        queue.push_back(next);
                    }
                    BlockEnd::Return(_) | BlockEnd::Error => {}
                }
                if follow_strong {
                    if let BlockLink::Strong(next) = block.link {
                        queue.push_back(next);
                    }
                }
            }
        }
        if strong_reachable.is_none() {
            strong_reachable = Some(reachable.clone());
        }
        follow_strong = true;
        while let Some(block) = blocks.pop_front() {
            if !reachable.contains(&block) && !f.blocks[&block].ops.is_empty() {
                report_unreachable(&f.blocks[&block], ctx);
                queue.push_back(block);
                break;
            }
        }
    }
    let strong_reachable = strong_reachable.unwrap_or_default();
    f.blocks.retain(|k, _| strong_reachable.contains(k));
}

pub(crate) fn remove_dead_code(program: &mut Program, ctx: &mut CompileCtx) {
    for (_, f) in &mut program.functions {
        analyze_function(f, ctx);
    }
}
<commit_msg>don't mark drops as dead code<commit_after>use std::collections::{HashSet, VecDeque};
use plank_syntax::position::Spanned;
use ast::cfg::{Block, BlockEnd, BlockId, BlockLink, Function, Instruction, Program};
use CompileCtx;

fn function_block_chain(f: &Function) -> VecDeque<BlockId> {
    let mut blocks = VecDeque::new();
    let mut current = if let Some(block) = f.start_block {
        block
    } else {
        return blocks;
    };
    loop {
        blocks.push_back(current);
        match f.blocks[&current].link {
            BlockLink::Strong(next) | BlockLink::Weak(next) => current = next,
            BlockLink::None => break,
        }
    }
    blocks
}

fn report_unreachable(block: &Block, ctx: &mut CompileCtx) {
    let mut span = Spanned::span(&block.ops[0]);
    for i in &block.ops {
        match **i {
            Instruction::StartStatement => {
                span = Spanned::span(i);
                break;
            }
            _ => {
                span = span.merge(Spanned::span(i));
            }
        }
    }
    ctx.reporter
        .warning("dead code detected", span)
        .span(span)
        .build();
}

fn can_be_dead(block: &Block) -> bool {
    for op in &block.ops {
        match **op {
            Instruction::Drop(_) => {}
            _ => return true,
        }
    }
    false
}

fn analyze_function(f: &mut Function, ctx: &mut CompileCtx) {
    let mut blocks = function_block_chain(f);
    debug_assert_eq!(blocks.len(), f.blocks.len());
    let mut reachable = HashSet::new();
    let mut strong_reachable = None;
    let mut queue = VecDeque::new();
    if let Some(block) = f.start_block {
        queue.push_back(block);
    }
    let mut follow_strong = false;
    while !queue.is_empty() {
        while let Some(block) = queue.pop_front() {
            if !reachable.contains(&block) {
                reachable.insert(block);
                let block = &f.blocks[&block];
                match block.end {
                    BlockEnd::Branch(_, a, b) => {
                        queue.push_back(a);
                        queue.push_back(b);
                    }
                    BlockEnd::Jump(next) => {
                        queue.push_back(next);
                    }
                    BlockEnd::Return(_) | BlockEnd::Error => {}
                }
                if follow_strong {
                    if let BlockLink::Strong(next) = block.link {
                        queue.push_back(next);
                    }
                }
            }
        }
        if strong_reachable.is_none() {
            strong_reachable = Some(reachable.clone());
        }
        follow_strong = true;
        while let Some(block) = blocks.pop_front() {
            if !reachable.contains(&block) && can_be_dead(&f.blocks[&block]) {
                report_unreachable(&f.blocks[&block], ctx);
                queue.push_back(block);
                break;
            }
        }
    }
    let strong_reachable = strong_reachable.unwrap_or_default();
    f.blocks.retain(|k, _| strong_reachable.contains(k));
}

pub(crate) fn remove_dead_code(program: &mut Program, ctx: &mut CompileCtx) {
    for (_, f) in &mut program.functions {
        analyze_function(f, ctx);
    }
}
<|endoftext|>


<commit_before>use graphics::*;

// Local crate.
use Vector2d = vector2d::Vector2d;

static EPSILON: f64 = 0.0000000001;

pub fn area(contour: &[Vector2d]) -> f64 {
    let n = contour.len();
    let mut A = 0.0_f64;

    for i in range(0, n) {
        let q = i;
        let p = (i + n - 1) % n;
        A += contour.get(p).unwrap().get_x() * contour.get(q).unwrap().get_y()
            - contour.get(q).unwrap().get_x() * contour.get(p).unwrap().get_y();
    }

    A * 0.5_f64
}

/// InsideTriangle decides if a point P is Inside of the triangle
/// defined by A, B, C.
pub fn inside_triangle(
    Ax: f64, Ay: f64,
    Bx: f64, By: f64,
    Cx: f64, Cy: f64,
    Px: f64, Py: f64
) -> bool {

    let ax = Cx - Bx;
    let ay = Cy - By;
    let bx = Ax - Cx;
    let by = Ay - Cy;
    let cx = Bx - Ax;
    let cy = By - Ay;
    let apx = Px - Ax;
    let apy = Py - Ay;
    let bpx = Px - Bx;
    let bpy = Py - By;
    let cpx = Px - Cx;
    let cpy = Py - Cy;

    let aCROSSbp = ax*bpy - ay*bpx;
    let cCROSSap = cx*apy - cy*apx;
    let bCROSScp = bx*cpy - by*cpx;

    (
        (aCROSSbp >= 0.0_f64)
        && (bCROSScp >= 0.0_f64)
        && (cCROSSap >= 0.0_f64)
    )
}

pub fn snip(
    contour: &[Vector2d],
    triangle: [uint, ..3],
    n: uint,
    vertex_indices: &Vec<uint>
) -> bool {
    let u = triangle[0];
    let v = triangle[1];
    let w = triangle[2];

    let A = contour.get(*vertex_indices.get(u)).unwrap();
    let B = contour.get(*vertex_indices.get(v)).unwrap();
    let C = contour.get(*vertex_indices.get(w)).unwrap();

    let (Ax, Ay) = (A.get_x(), A.get_y());
    let (Bx, By) = (B.get_x(), B.get_y());
    let (Cx, Cy) = (C.get_x(), C.get_y());

    if EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) {
        return false;
    }

    for p in range(0, n) {
        if (p == u) || (p == v) || (p == w) { continue; }

        let Px = contour.get(*vertex_indices.get(p)).unwrap().get_x();
        let Py = contour.get(*vertex_indices.get(p)).unwrap().get_y();

        if inside_triangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py) { return false; }
    }

    return true;
}

pub fn process(
    contour: &[Vector2d]
) -> Option<Vec<Vector2d>> {
    /* allocate and initialize list of Vertices in polygon */

    let n = contour.len();
    if n < 3 { return None; }

    let mut result: Vec<Vector2d> = Vec::new();
    let mut vertex_indices: Vec<uint> = Vec::with_capacity(n);

    /* we want a counter-clockwise polygon in V */

    // Computes the area which has opposite signs
    // whether the polygon is clock-wise or counter-clockwise.
    if 0.0_f64 < area(contour) {
        for v in range(0, n) { vertex_indices.push(v); }
    } else {
        // Add indices in reverse order.
        for v in range(0, n) { vertex_indices.push((n-1)-v); }
    }

    // Stores the number of vertices.
    // Used instead of `vertex_indices.len()` to emulate removing of vertices.
    let mut number_of_vertices = n;

    /*  remove nv-2 Vertices, creating 1 triangle every time */

    // Used for error detection.
    let mut count = 2 * number_of_vertices;

    let mut v = number_of_vertices - 1;
    while number_of_vertices > 2 {
        /* if we loop, it is probably a non-simple polygon */
        if count <= 0 {
            //** Triangulate: ERROR - probable bad polygon!
            return None;
        }

        count -= 1;

        /* three consecutive vertices in current polygon, <u,v,w> */
        let triangle = [
            v,
            vecmath::modular_offset_index(number_of_vertices, v, 1),
            vecmath::modular_offset_index(number_of_vertices, v, 2)
        ];
        v = triangle[1];

        if snip(contour, triangle, number_of_vertices, &mut vertex_indices) {
            for &i in triangle.iter() {
                result.push(*contour.get(*vertex_indices.get(i)).unwrap());
            }

            /* remove v from remaining polygon */
            for i in range(0, number_of_vertices - 3) {
                let s = v + i;
                let t = v + i + 1;

                *vertex_indices.get_mut(s) = *vertex_indices.get(t);
            }

            // "Removed" a vertex.
            number_of_vertices -= 1;

            /* resest error detection counter */
            count = 2 * number_of_vertices;
        }
    }

    Some(result)
}

<commit_msg>Added comment<commit_after>use graphics::*;

// Local crate.
use Vector2d = vector2d::Vector2d;

static EPSILON: f64 = 0.0000000001;

pub fn area(contour: &[Vector2d]) -> f64 {
    let n = contour.len();
    let mut A = 0.0_f64;

    for i in range(0, n) {
        let q = i;
        let p = (i + n - 1) % n;
        A += contour.get(p).unwrap().get_x() * contour.get(q).unwrap().get_y()
            - contour.get(q).unwrap().get_x() * contour.get(p).unwrap().get_y();
    }

    A * 0.5_f64
}

/// InsideTriangle decides if a point P is Inside of the triangle
/// defined by A, B, C.
pub fn inside_triangle(
    Ax: f64, Ay: f64,
    Bx: f64, By: f64,
    Cx: f64, Cy: f64,
    Px: f64, Py: f64
) -> bool {

    let ax = Cx - Bx;
    let ay = Cy - By;
    let bx = Ax - Cx;
    let by = Ay - Cy;
    let cx = Bx - Ax;
    let cy = By - Ay;
    let apx = Px - Ax;
    let apy = Py - Ay;
    let bpx = Px - Bx;
    let bpy = Py - By;
    let cpx = Px - Cx;
    let cpy = Py - Cy;

    let aCROSSbp = ax*bpy - ay*bpx;
    let cCROSSap = cx*apy - cy*apx;
    let bCROSScp = bx*cpy - by*cpx;

    (
        (aCROSSbp >= 0.0_f64)
        && (bCROSScp >= 0.0_f64)
        && (cCROSSap >= 0.0_f64)
    )
}

pub fn snip(
    contour: &[Vector2d],
    triangle: [uint, ..3],
    n: uint,
    vertex_indices: &Vec<uint>
) -> bool {
    let (u, v, w) = (triangle[0], triangle[1], triangle[2]);

    let A = contour.get(*vertex_indices.get(u)).unwrap();
    let B = contour.get(*vertex_indices.get(v)).unwrap();
    let C = contour.get(*vertex_indices.get(w)).unwrap();

    let (Ax, Ay) = (A.get_x(), A.get_y());
    let (Bx, By) = (B.get_x(), B.get_y());
    let (Cx, Cy) = (C.get_x(), C.get_y());

    if EPSILON > (((Bx-Ax)*(Cy-Ay)) - ((By-Ay)*(Cx-Ax))) {
        return false;
    }

    for p in range(0, n) {
        // Do not check for any of the vertices in the triangle.
        if (p == u) || (p == v) || (p == w) { continue; }

        let Px = contour.get(*vertex_indices.get(p)).unwrap().get_x();
        let Py = contour.get(*vertex_indices.get(p)).unwrap().get_y();

        if inside_triangle(Ax,Ay,Bx,By,Cx,Cy,Px,Py) { return false; }
    }

    return true;
}

pub fn process(
    contour: &[Vector2d]
) -> Option<Vec<Vector2d>> {
    /* allocate and initialize list of Vertices in polygon */

    let n = contour.len();
    if n < 3 { return None; }

    let mut result: Vec<Vector2d> = Vec::new();
    let mut vertex_indices: Vec<uint> = Vec::with_capacity(n);

    /* we want a counter-clockwise polygon in V */

    // Computes the area which has opposite signs
    // whether the polygon is clock-wise or counter-clockwise.
    if 0.0_f64 < area(contour) {
        for v in range(0, n) { vertex_indices.push(v); }
    } else {
        // Add indices in reverse order.
        for v in range(0, n) { vertex_indices.push((n-1)-v); }
    }

    // Stores the number of vertices.
    // Used instead of `vertex_indices.len()` to emulate removing of vertices.
    let mut number_of_vertices = n;

    /*  remove nv-2 Vertices, creating 1 triangle every time */

    // Used for error detection.
    let mut count = 2 * number_of_vertices;

    let mut v = number_of_vertices - 1;
    while number_of_vertices > 2 {
        /* if we loop, it is probably a non-simple polygon */
        if count <= 0 {
            //** Triangulate: ERROR - probable bad polygon!
            return None;
        }

        count -= 1;

        /* three consecutive vertices in current polygon, <u,v,w> */
        let triangle = [
            v,
            vecmath::modular_offset_index(number_of_vertices, v, 1),
            vecmath::modular_offset_index(number_of_vertices, v, 2)
        ];
        v = triangle[1];

        if snip(contour, triangle, number_of_vertices, &mut vertex_indices) {
            for &i in triangle.iter() {
                result.push(*contour.get(*vertex_indices.get(i)).unwrap());
            }

            /* remove v from remaining polygon */
            for i in range(0, number_of_vertices - 3) {
                let s = v + i;
                let t = v + i + 1;

                *vertex_indices.get_mut(s) = *vertex_indices.get(t);
            }

            // "Removed" a vertex.
            number_of_vertices -= 1;

            /* resest error detection counter */
            count = 2 * number_of_vertices;
        }
    }

    Some(result)
}

<|endoftext|>