<commit_before>//! Main module to handle the layout.
//! This is where the i3-specific code is.

use std::sync::{Mutex, MutexGuard, TryLockError};
use std::ptr;

use super::container::{Container, Handle, ContainerType};
use super::node::{Node};
use super::super::rustwlc::handle::{WlcView, WlcOutput};

pub type TreeResult = Result<(), TryLockError<MutexGuard<'static, Tree>>>;

const ERR_BAD_TREE: &'static str = "Layout tree was in an invalid configuration";

lazy_static! {
    static ref TREE: Mutex<Tree> = {
        Mutex::new(Tree{
            root: Node::new(Container::new_root()),
            active_container: ptr::null(),
        })
    };
}

pub struct Tree {
    root: Node,
    active_container: *const Node,
}

impl Tree {
    fn get_active_container(&self) -> Option<&Node> {
        if self.active_container.is_null() {
            None
        } else {
            unsafe {
                Some(&*self.active_container)
            }
        }
    }

    fn get_active_output(&self) -> Option<&Node> {
        if let Some(node) = self.get_active_container() {
            node.get_ancestor_of_type(ContainerType::Output)
        } else {
            None
        }
    }

    fn get_current_workspace(&self) -> Option<&mut Node> {
        if let Some(container) = self.get_active_container() {
            //if let Some(child) = container.get_ancestor_of_type(ContainerType::Workspace) {
            //return child.get_children()[0].get_parent()

            //}
            // NOTE hack here, remove commented code above to make this work properly
            let parent = container.get_parent().expect(ERR_BAD_TREE);
            for child in parent.get_children_mut() {
                if child == container {
                    return Some(child);
                }
            }
        }
        return None
    }

    fn get_workspace_by_name(&self, name: &str) -> Option<&Node> {
        for child in self.root.get_children()[0].get_children() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn get_workspace_by_name_mut(&mut self, name: &str) -> Option<&mut Node> {
        for child in self.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn add_output(&mut self, wlc_output: WlcOutput) {
        self.root.new_child(Container::new_output(wlc_output));
    }

    fn add_workspace(&mut self, name: String) {
        let workspace = Container::new_workspace(name.to_string());
        let mut index = 0;
        if let Some(output) = self.get_active_output() {
            for (cur_index, child) in self.root.get_children().iter().enumerate() {
                if child == output {
                    index = cur_index;
                    break;
                }
            }
        }
        self.root.get_children_mut()[index].new_child(workspace);
    }

    fn add_view(&self, wlc_view: WlcView) {
        if let Some(current_workspace) = self.get_current_workspace() {
            trace!("Adding view {:?} to {:?}", wlc_view, current_workspace);
            current_workspace.new_child(Container::new_view(wlc_view));
        }
    }

    fn remove_view(&self, wlc_view: &WlcView) {
        if let Some(view) = self.root.find_view_by_handle(&wlc_view) {
            let parent = view.get_parent().expect(ERR_BAD_TREE);
            parent.remove_child(view);
        }
    }
}

unsafe impl Send for Tree {}

pub fn add_output(wlc_output: WlcOutput) -> TreeResult {
    {
        let mut tree = try!(TREE.try_lock());
        tree.add_output(wlc_output);
    }
    try!(add_workspace("1".to_string()));
    try!(switch_workspace(&"1"));
    Ok(())
}

pub fn add_workspace(name: String) -> TreeResult {
    trace!("Adding new workspace to root");
    let mut tree = try!(TREE.lock());
    tree.add_workspace(name);
    Ok(())
}

pub fn add_view(wlc_view: WlcView) -> TreeResult {
    let tree = try!(TREE.lock());
    tree.add_view(wlc_view);
    Ok(())
}

pub fn remove_view(wlc_view: &WlcView) -> TreeResult {
    let tree = try!(TREE.lock());
    tree.remove_view(wlc_view);
    Ok(())
}

pub fn switch_workspace(name: &str) -> TreeResult {
    trace!("Switching to workspace {}", name);
    let mut tree = try!(TREE.lock());
    if let Some(old_workspace) = tree.get_current_workspace() {
        old_workspace.set_visibility(false);
    }
    let current_workspace: *const Node;
    {
        if let Some(_) = tree.get_workspace_by_name(name) {
            trace!("Found workspace {}", name);
        } else {
            trace!("Adding workspace {}", name);
            tree.add_workspace(name.to_string());
        }
        let new_current_workspace = tree.get_workspace_by_name_mut(name).expect(ERR_BAD_TREE);
        new_current_workspace.set_visibility(true);
        // Set the first view to be focused, so that the view is updated to this new workspace
        if new_current_workspace.get_children().len() > 0 {
            trace!("Focusing view");
            match new_current_workspace.get_children_mut()[0]
                .get_val().get_handle().expect(ERR_BAD_TREE) {
                Handle::View(view) => view.focus(),
                _ => {},
            }
        } else {
            WlcView::root().focus();
        }
        current_workspace = new_current_workspace as *const Node;
    }
    tree.active_container = current_workspace;
    Ok(())
}
<commit_msg>Moved unsafe impl block nearer to where it's requirement is<commit_after>//! Main module to handle the layout.
//! This is where the i3-specific code is.

use std::sync::{Mutex, MutexGuard, TryLockError};
use std::ptr;

use super::container::{Container, Handle, ContainerType};
use super::node::{Node};
use super::super::rustwlc::handle::{WlcView, WlcOutput};

pub type TreeResult = Result<(), TryLockError<MutexGuard<'static, Tree>>>;

const ERR_BAD_TREE: &'static str = "Layout tree was in an invalid configuration";

lazy_static! {
    static ref TREE: Mutex<Tree> = {
        Mutex::new(Tree{
            root: Node::new(Container::new_root()),
            active_container: ptr::null(),
        })
    };
}

pub struct Tree {
    root: Node,
    active_container: *const Node,
}

unsafe impl Send for Tree {}

impl Tree {
    fn get_active_container(&self) -> Option<&Node> {
        if self.active_container.is_null() {
            None
        } else {
            unsafe {
                Some(&*self.active_container)
            }
        }
    }

    fn get_active_output(&self) -> Option<&Node> {
        if let Some(node) = self.get_active_container() {
            node.get_ancestor_of_type(ContainerType::Output)
        } else {
            None
        }
    }

    fn get_current_workspace(&self) -> Option<&mut Node> {
        if let Some(container) = self.get_active_container() {
            //if let Some(child) = container.get_ancestor_of_type(ContainerType::Workspace) {
            //return child.get_children()[0].get_parent()

            //}
            // NOTE hack here, remove commented code above to make this work properly
            let parent = container.get_parent().expect(ERR_BAD_TREE);
            for child in parent.get_children_mut() {
                if child == container {
                    return Some(child);
                }
            }
        }
        return None
    }

    fn get_workspace_by_name(&self, name: &str) -> Option<&Node> {
        for child in self.root.get_children()[0].get_children() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn get_workspace_by_name_mut(&mut self, name: &str) -> Option<&mut Node> {
        for child in self.root.get_children_mut()[0].get_children_mut() {
            if child.get_val().get_name().expect(ERR_BAD_TREE) != name {
                continue
            }
            return Some(child);
        }
        return None
    }

    fn add_output(&mut self, wlc_output: WlcOutput) {
        self.root.new_child(Container::new_output(wlc_output));
    }

    fn add_workspace(&mut self, name: String) {
        let workspace = Container::new_workspace(name.to_string());
        let mut index = 0;
        if let Some(output) = self.get_active_output() {
            for (cur_index, child) in self.root.get_children().iter().enumerate() {
                if child == output {
                    index = cur_index;
                    break;
                }
            }
        }
        self.root.get_children_mut()[index].new_child(workspace);
    }

    fn add_view(&self, wlc_view: WlcView) {
        if let Some(current_workspace) = self.get_current_workspace() {
            trace!("Adding view {:?} to {:?}", wlc_view, current_workspace);
            current_workspace.new_child(Container::new_view(wlc_view));
        }
    }

    fn remove_view(&self, wlc_view: &WlcView) {
        if let Some(view) = self.root.find_view_by_handle(&wlc_view) {
            let parent = view.get_parent().expect(ERR_BAD_TREE);
            parent.remove_child(view);
        }
    }
}

pub fn add_output(wlc_output: WlcOutput) -> TreeResult {
    {
        let mut tree = try!(TREE.try_lock());
        tree.add_output(wlc_output);
    }
    try!(add_workspace("1".to_string()));
    try!(switch_workspace(&"1"));
    Ok(())
}

pub fn add_workspace(name: String) -> TreeResult {
    trace!("Adding new workspace to root");
    let mut tree = try!(TREE.lock());
    tree.add_workspace(name);
    Ok(())
}

pub fn add_view(wlc_view: WlcView) -> TreeResult {
    let tree = try!(TREE.lock());
    tree.add_view(wlc_view);
    Ok(())
}

pub fn remove_view(wlc_view: &WlcView) -> TreeResult {
    let tree = try!(TREE.lock());
    tree.remove_view(wlc_view);
    Ok(())
}

pub fn switch_workspace(name: &str) -> TreeResult {
    trace!("Switching to workspace {}", name);
    let mut tree = try!(TREE.lock());
    if let Some(old_workspace) = tree.get_current_workspace() {
        old_workspace.set_visibility(false);
    }
    let current_workspace: *const Node;
    {
        if let Some(_) = tree.get_workspace_by_name(name) {
            trace!("Found workspace {}", name);
        } else {
            trace!("Adding workspace {}", name);
            tree.add_workspace(name.to_string());
        }
        let new_current_workspace = tree.get_workspace_by_name_mut(name).expect(ERR_BAD_TREE);
        new_current_workspace.set_visibility(true);
        // Set the first view to be focused, so that the view is updated to this new workspace
        if new_current_workspace.get_children().len() > 0 {
            trace!("Focusing view");
            match new_current_workspace.get_children_mut()[0]
                .get_val().get_handle().expect(ERR_BAD_TREE) {
                Handle::View(view) => view.focus(),
                _ => {},
            }
        } else {
            WlcView::root().focus();
        }
        current_workspace = new_current_workspace as *const Node;
    }
    tree.active_container = current_workspace;
    Ok(())
}
<|endoftext|>


<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

//! This module contains the `Cleaner` traits and various implementations of it.

use std::borrow::Cow;

/// Custom function because we don't really want to touch \t or \n
fn is_whitespace(c: char) -> bool {
    c == ' ' || c == ' ' || c == ' '
}

/// Trait for cleaning a string.
///
/// This trait must be called for text that is e.g. in a paragraph, a title,
/// NOT for code blocks, hyperlinks and so on!
pub trait Cleaner: Sync {
    /// Cleans a string. The default implementation is to remove multiple consecutive whitespaces
    ///
    /// # Argumets
    ///
    /// * `str`: the string that must be cleaned
    /// * `latex`: a bool specifying whether output is Latex code or not
    fn clean<'a>(&self, str: Cow<'a, str>, _latex: bool) -> Cow<'a, str> {
        str
    }
}

/// Cleaner implementation that does nothing
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::Off;
/// use std::borrow::Cow;
/// let off = Off;
/// let s = off.clean(Cow::Borrowed("  A string   that won't be cleaned "), false);
/// assert_eq!(&s, "  A string   that won't be cleaned ");
/// ```
pub struct Off;
impl Cleaner for Off {}

/// Default implementation of cleaner trait.
///
/// Only removes unnecessary whitespaces.
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::Default;
/// use std::borrow::Cow;
/// let s = Default.clean(Cow::Borrowed("  A  string   with   more   whitespaces  than  needed   "), false);
/// assert_eq!(&s, " A string with more whitespaces than needed ");
/// ```
pub struct Default;
impl Cleaner for Default {
    /// Remove unnecessary whitespaces
    fn clean<'a>(&self, s: Cow<'a, str>, _: bool) -> Cow<'a, str> {
        if s.contains(is_whitespace) { // if not, no need to do anything
            let mut new_s = String::with_capacity(s.len());
            let mut previous_space = false;
            for c in s.chars() {
                if is_whitespace(c) {
                    if previous_space {
                        // previous char already a space, don't copy it
                    } else {
                        new_s.push(c);
                        previous_space = true;
                    }
                } else {
                    previous_space = false;
                    new_s.push(c);
                }
            }

            Cow::Owned(new_s)
        } else {
            s
        }
    }
}

/// Implementation for french 'cleaning'
///
/// This implementation replaces spaces before some characters (e.g. `?` or `;` with non-breaking spaces
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::French;
/// use std::borrow::Cow;
/// let s =  French.clean(Cow::Borrowed("  Bonjour ! Comment allez-vous   ?   "), true);
/// assert_eq!(&s, " Bonjour~! Comment allez-vous~? ");
/// ```
pub struct French;

const THRESHOLD_CURRENCY: usize = 3; // after that, assume it's not a currency
const THRESHOLD_UNIT: usize = 2; // after that, assume it's not a unit
const THRESHOLD_QUOTE: usize = 25; // after that, assume it's a dialogue
const THRESHOLD_REAL_WORD: usize = 3; // after that, can be reasonably sure it is not an abbreviation

impl Cleaner for French {
    /// Puts non breaking spaces before/after `:`, `;`, `?`, `!`, `«`, `»`, `—`
    fn clean<'a>(&self, s: Cow<'a, str>, latex: bool) -> Cow<'a, str> {
        fn is_trouble(c: char) -> bool {
            match c {
                '?'|'!'|';'|':'|'»'|'«'|'—'|'–' | '0'...'9' => true,
                _ => false
            }
        }
        if !s.contains(is_trouble) { // if not, no need to do anything
            return Default.clean(s, latex);
        }
        let nb_char = if latex {
            '~'
        } else {
            ' ' // non breaking space
        };
        let nb_char_narrow = if latex {
            '~'
        } else {
            '\u{202F}' // narrow non breaking space
        };
        let nb_char_em = if latex {
            '~'
        } else {
            '\u{2002}' // demi em space
        };

        // Find first char `c` in slice `v` after index `n`
        fn find_next(v: &[char], c: char, n: usize) -> Option<usize> {
            for i in n..v.len() {
                if v[i] == c  {
                    return Some(i);
                }
            }
            None
        }

        // Return true if next non whitespace char in `v` after index `n` is uppercase
        fn is_next_char_uppercase(v: &[char], n: usize)-> bool {
            for i in n..v.len() {
                if v[i].is_whitespace() {
                    continue;
                }
                if v[i].is_uppercase() {
                    return true;
                }
                if v[i].is_lowercase() {
                    return false;
                }
            }
            false
        }

        // Return true(some) if a closing dash was found before what looks like the end of a sentence, None else
        fn find_closing_dash(v: &[char], n: usize) -> Option<usize> {
            let mut word = String::new();
            for j in n..v.len() {
                match v[j] {

                    '!' | '?' => if is_next_char_uppercase(v, j+1) {
                        return None;
                    },
                    '-' | '–' | '—' => if v[j-1].is_whitespace() {
                        return Some(j-1);
                    },
                    '.' => if !is_next_char_uppercase(v, j+1) {
                        continue;
                    } else {
                        if let Some(c) = word.chars().next() {
                            if !c.is_uppercase() {
                                return None;
                            } else {
                                if word.len() > THRESHOLD_REAL_WORD {
                                    return None;
                                }
                            }
                        }
                    },
                    c if c.is_whitespace() => word = String::new(),
                    c => word.push(c),
                }
            }
            return None;
        }

        /// Returns the next word in `v` starting from index `n`
        fn get_next_word(v: &[char], n: usize) -> &[char] {
            let mut beginning = n;
            let mut end = v.len();

            for i in n..v.len() {
                if v[i].is_alphabetic() {
                    beginning = i;
                    break;
                }
            }

            for i in beginning..v.len() {
                if v[i].is_whitespace() {
                    end = i;
                    break;
                }
            }

            &v[beginning..end]
        }

        /// Return true if the character is a symbol that is used after number and should have a nb_char before
        fn char_is_symbol(v: &[char], i: usize) -> bool {
            let is_next_letter = if i < v.len() - 1 {
                v[i+1].is_alphabetic()
            } else {
                false
            };
            if is_next_letter {
                match v[i] {
                    '°' => true,
                    c if c.is_uppercase() => {
                        let word = get_next_word(v, i);
                        if word.len() > THRESHOLD_CURRENCY {
                            // not a currency
                            false
                        } else {
                            // if all uppercase and less than THRESHOLD, assume it's a currency or a unit
                            word.iter().all(|c| c.is_uppercase())
                        }
                    },
                    c if c.is_alphabetic() => {
                        let word = get_next_word(v, i);
                        // if two letters, assume it is a unit
                        word.len() <= THRESHOLD_UNIT
                    },
                    _ => false
                }
            } else {
                match v[i] {
                    c if (!c.is_alphabetic() && !c.is_whitespace()) => true, // special symbol
                    c if c.is_uppercase() => true, //single uppercase letter
                    _ => false,
                }
            }
        }

        let s = Default.clean(s, latex); // first pass with default impl
        let mut found_opening_quote = false; // we didn't find an opening quote yet
        let mut chars = s.chars().collect::<Vec<_>>();
        let mut is_number_series = false;

        for i in 0..(chars.len()-1) {
            // Handle numbers (that's easy)
            let current = chars[i];
            let next = chars[i+1];

            match current {
                '0'...'9' => if i == 0 {
                    is_number_series = true;
                } else if !chars[i-1].is_alphabetic() {
                    is_number_series = true;
                },
                c if c.is_whitespace() => {
                    if is_number_series && (next.is_digit(10) || char_is_symbol(&chars, i+1)) {
                        // Next char is a number or symbol such as $, and previous was number
                        chars[i] = nb_char_narrow;
                    }
                },
                _ => { is_number_series = false; }
            }
        }

        for i in 0..(chars.len()-1) {
            let current = chars[i];
            let next = chars[i+1];

            // Handle the rest (that's hard)
            if is_whitespace(current) {
                match next {
                    // handle narrow nb space before char
                    '?' | '!' | ';' => chars[i] = nb_char_narrow,
                    ':' => chars[i] = nb_char,
                    '»' => if current == ' ' {
                        // Assumne that if it isn't a normal space it was used here for good reason, don't replace it
                        if found_opening_quote {
                            // not the end of a dialogue
                            chars[i] = nb_char;
                        } else {
                            chars[i] = nb_char;
                        }
                    },
                    _ => (),
                }
            } else {
                match current {
                    // handle nb space after char
                    '—' | '«' | '-' | '–' => {
                        if is_whitespace(next) {
                            let replacing_char = match current {
                                '—' | '-' | '–' => {
                                    if i <= 1 {
                                        nb_char_em
                                    } else {
                                        if chars[i-1] == nb_char {
                                            // non breaking space before, so probably should have a breakable one after
                                            ' '
                                        } else {
                                            if let Some(closing) = find_closing_dash(&chars, i+1) {
                                                chars[closing] = nb_char;
                                            }
                                            nb_char
                                        }
                                    }
                                },
                                '«' => {
                                    found_opening_quote = true;
                                    if i <= 1 {
                                        nb_char
                                    } else {
                                        let j = find_next(&chars, '»', i);
                                        if let Some(j) = j {
                                            if chars[j-1].is_whitespace() {
                                                if j == chars.len() {
                                                    // » is at the end, assume it is a dialogue
                                                    chars[j-1] = nb_char;
                                                    nb_char
                                                } else {
                                                    if j - i > THRESHOLD_QUOTE {
                                                        // It's a quote, so use large space?
                                                        chars[j-1] = nb_char;
                                                        nb_char
                                                    } else {
                                                        // Not long enough to be a quote, use narrow nb char
                                                        chars[j-1] = nb_char_narrow;
                                                        nb_char_narrow
                                                    }
                                                }
                                            } else {
                                                // wtf formatting?
                                                nb_char
                                            }
                                        } else {
                                            // No ending quote found, assume is a dialogue
                                            nb_char
                                        }
                                    }
                                }, // TODO: better heuristic: use narrow nb_char if not at front???
                                _ => unreachable!(),
                            };
                            chars[i+1] = replacing_char;
                        }
                    }
                    _ => (),
                }
            }
        }
        Cow::Owned(chars.into_iter().collect())
    }
}

<commit_msg>Change THRESHOLD_QUOTE<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

//! This module contains the `Cleaner` traits and various implementations of it.

use std::borrow::Cow;

/// Custom function because we don't really want to touch \t or \n
fn is_whitespace(c: char) -> bool {
    c == ' ' || c == ' ' || c == ' '
}

/// Trait for cleaning a string.
///
/// This trait must be called for text that is e.g. in a paragraph, a title,
/// NOT for code blocks, hyperlinks and so on!
pub trait Cleaner: Sync {
    /// Cleans a string. The default implementation is to remove multiple consecutive whitespaces
    ///
    /// # Argumets
    ///
    /// * `str`: the string that must be cleaned
    /// * `latex`: a bool specifying whether output is Latex code or not
    fn clean<'a>(&self, str: Cow<'a, str>, _latex: bool) -> Cow<'a, str> {
        str
    }
}

/// Cleaner implementation that does nothing
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::Off;
/// use std::borrow::Cow;
/// let off = Off;
/// let s = off.clean(Cow::Borrowed("  A string   that won't be cleaned "), false);
/// assert_eq!(&s, "  A string   that won't be cleaned ");
/// ```
pub struct Off;
impl Cleaner for Off {}

/// Default implementation of cleaner trait.
///
/// Only removes unnecessary whitespaces.
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::Default;
/// use std::borrow::Cow;
/// let s = Default.clean(Cow::Borrowed("  A  string   with   more   whitespaces  than  needed   "), false);
/// assert_eq!(&s, " A string with more whitespaces than needed ");
/// ```
pub struct Default;
impl Cleaner for Default {
    /// Remove unnecessary whitespaces
    fn clean<'a>(&self, s: Cow<'a, str>, _: bool) -> Cow<'a, str> {
        if s.contains(is_whitespace) { // if not, no need to do anything
            let mut new_s = String::with_capacity(s.len());
            let mut previous_space = false;
            for c in s.chars() {
                if is_whitespace(c) {
                    if previous_space {
                        // previous char already a space, don't copy it
                    } else {
                        new_s.push(c);
                        previous_space = true;
                    }
                } else {
                    previous_space = false;
                    new_s.push(c);
                }
            }

            Cow::Owned(new_s)
        } else {
            s
        }
    }
}

/// Implementation for french 'cleaning'
///
/// This implementation replaces spaces before some characters (e.g. `?` or `;` with non-breaking spaces
///
/// # Examples
///
/// ```
/// use crowbook::cleaner::Cleaner;
/// use crowbook::cleaner::French;
/// use std::borrow::Cow;
/// let s =  French.clean(Cow::Borrowed("  Bonjour ! Comment allez-vous   ?   "), true);
/// assert_eq!(&s, " Bonjour~! Comment allez-vous~? ");
/// ```
pub struct French;

const THRESHOLD_CURRENCY: usize = 3; // after that, assume it's not a currency
const THRESHOLD_UNIT: usize = 2; // after that, assume it's not a unit
const THRESHOLD_QUOTE: usize = 27; // after that, assume it's a dialogue
const THRESHOLD_REAL_WORD: usize = 3; // after that, can be reasonably sure it is not an abbreviation

impl Cleaner for French {
    /// Puts non breaking spaces before/after `:`, `;`, `?`, `!`, `«`, `»`, `—`
    fn clean<'a>(&self, s: Cow<'a, str>, latex: bool) -> Cow<'a, str> {
        fn is_trouble(c: char) -> bool {
            match c {
                '?'|'!'|';'|':'|'»'|'«'|'—'|'–' | '0'...'9' => true,
                _ => false
            }
        }
        if !s.contains(is_trouble) { // if not, no need to do anything
            return Default.clean(s, latex);
        }
        let nb_char = if latex {
            '~'
        } else {
            ' ' // non breaking space
        };
        let nb_char_narrow = if latex {
            '~'
        } else {
            '\u{202F}' // narrow non breaking space
        };
        let nb_char_em = if latex {
            '~'
        } else {
            '\u{2002}' // demi em space
        };

        // Find first char `c` in slice `v` after index `n`
        fn find_next(v: &[char], c: char, n: usize) -> Option<usize> {
            for i in n..v.len() {
                if v[i] == c  {
                    return Some(i);
                }
            }
            None
        }

        // Return true if next non whitespace char in `v` after index `n` is uppercase
        fn is_next_char_uppercase(v: &[char], n: usize)-> bool {
            for i in n..v.len() {
                if v[i].is_whitespace() {
                    continue;
                }
                if v[i].is_uppercase() {
                    return true;
                }
                if v[i].is_lowercase() {
                    return false;
                }
            }
            false
        }

        // Return true(some) if a closing dash was found before what looks like the end of a sentence, None else
        fn find_closing_dash(v: &[char], n: usize) -> Option<usize> {
            let mut word = String::new();
            for j in n..v.len() {
                match v[j] {

                    '!' | '?' => if is_next_char_uppercase(v, j+1) {
                        return None;
                    },
                    '-' | '–' | '—' => if v[j-1].is_whitespace() {
                        return Some(j-1);
                    },
                    '.' => if !is_next_char_uppercase(v, j+1) {
                        continue;
                    } else {
                        if let Some(c) = word.chars().next() {
                            if !c.is_uppercase() {
                                return None;
                            } else {
                                if word.len() > THRESHOLD_REAL_WORD {
                                    return None;
                                }
                            }
                        }
                    },
                    c if c.is_whitespace() => word = String::new(),
                    c => word.push(c),
                }
            }
            return None;
        }

        /// Returns the next word in `v` starting from index `n`
        fn get_next_word(v: &[char], n: usize) -> &[char] {
            let mut beginning = n;
            let mut end = v.len();

            for i in n..v.len() {
                if v[i].is_alphabetic() {
                    beginning = i;
                    break;
                }
            }

            for i in beginning..v.len() {
                if v[i].is_whitespace() {
                    end = i;
                    break;
                }
            }

            &v[beginning..end]
        }

        /// Return true if the character is a symbol that is used after number and should have a nb_char before
        fn char_is_symbol(v: &[char], i: usize) -> bool {
            let is_next_letter = if i < v.len() - 1 {
                v[i+1].is_alphabetic()
            } else {
                false
            };
            if is_next_letter {
                match v[i] {
                    '°' => true,
                    c if c.is_uppercase() => {
                        let word = get_next_word(v, i);
                        if word.len() > THRESHOLD_CURRENCY {
                            // not a currency
                            false
                        } else {
                            // if all uppercase and less than THRESHOLD, assume it's a currency or a unit
                            word.iter().all(|c| c.is_uppercase())
                        }
                    },
                    c if c.is_alphabetic() => {
                        let word = get_next_word(v, i);
                        // if two letters, assume it is a unit
                        word.len() <= THRESHOLD_UNIT
                    },
                    _ => false
                }
            } else {
                match v[i] {
                    c if (!c.is_alphabetic() && !c.is_whitespace()) => true, // special symbol
                    c if c.is_uppercase() => true, //single uppercase letter
                    _ => false,
                }
            }
        }

        let s = Default.clean(s, latex); // first pass with default impl
        let mut found_opening_quote = false; // we didn't find an opening quote yet
        let mut chars = s.chars().collect::<Vec<_>>();
        let mut is_number_series = false;

        for i in 0..(chars.len()-1) {
            // Handle numbers (that's easy)
            let current = chars[i];
            let next = chars[i+1];

            match current {
                '0'...'9' => if i == 0 {
                    is_number_series = true;
                } else if !chars[i-1].is_alphabetic() {
                    is_number_series = true;
                },
                c if c.is_whitespace() => {
                    if is_number_series && (next.is_digit(10) || char_is_symbol(&chars, i+1)) {
                        // Next char is a number or symbol such as $, and previous was number
                        chars[i] = nb_char_narrow;
                    }
                },
                _ => { is_number_series = false; }
            }
        }

        for i in 0..(chars.len()-1) {
            let current = chars[i];
            let next = chars[i+1];

            // Handle the rest (that's hard)
            if is_whitespace(current) {
                match next {
                    // handle narrow nb space before char
                    '?' | '!' | ';' => chars[i] = nb_char_narrow,
                    ':' => chars[i] = nb_char,
                    '»' => if current == ' ' {
                        // Assumne that if it isn't a normal space it was used here for good reason, don't replace it
                        if found_opening_quote {
                            // not the end of a dialogue
                            chars[i] = nb_char;
                        } else {
                            chars[i] = nb_char;
                        }
                    },
                    _ => (),
                }
            } else {
                match current {
                    // handle nb space after char
                    '—' | '«' | '-' | '–' => {
                        if is_whitespace(next) {
                            let replacing_char = match current {
                                '—' | '-' | '–' => {
                                    if i <= 1 {
                                        nb_char_em
                                    } else {
                                        if chars[i-1] == nb_char {
                                            // non breaking space before, so probably should have a breakable one after
                                            ' '
                                        } else {
                                            if let Some(closing) = find_closing_dash(&chars, i+1) {
                                                chars[closing] = nb_char;
                                            }
                                            nb_char
                                        }
                                    }
                                },
                                '«' => {
                                    found_opening_quote = true;
                                    if i <= 1 {
                                        nb_char
                                    } else {
                                        let j = find_next(&chars, '»', i);
                                        if let Some(j) = j {
                                            if chars[j-1].is_whitespace() {
                                                if j == chars.len() {
                                                    // » is at the end, assume it is a dialogue
                                                    chars[j-1] = nb_char;
                                                    nb_char
                                                } else {
                                                    if j - i > THRESHOLD_QUOTE {
                                                        // It's a quote, so use large space?
                                                        chars[j-1] = nb_char;
                                                        nb_char
                                                    } else {
                                                        // Not long enough to be a quote, use narrow nb char
                                                        chars[j-1] = nb_char_narrow;
                                                        nb_char_narrow
                                                    }
                                                }
                                            } else {
                                                // wtf formatting?
                                                nb_char
                                            }
                                        } else {
                                            // No ending quote found, assume is a dialogue
                                            nb_char
                                        }
                                    }
                                }, // TODO: better heuristic: use narrow nb_char if not at front???
                                _ => unreachable!(),
                            };
                            chars[i+1] = replacing_char;
                        }
                    }
                    _ => (),
                }
            }
        }
        Cow::Owned(chars.into_iter().collect())
    }
}

<|endoftext|>


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

use hir::def_id::DefId;
use util::nodemap::NodeMap;
use syntax::ast;
use syntax::ext::base::MacroKind;
use syntax_pos::Span;
use hir;

#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum CtorKind {
    /// Constructor function automatically created by a tuple struct/variant.
    Fn,
    /// Constructor constant automatically created by a unit struct/variant.
    Const,
    /// Unusable name in value namespace created by a struct variant.
    Fictive,
}

#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Def {
    // Type namespace
    Mod(DefId),
    Struct(DefId), // DefId refers to NodeId of the struct itself
    Union(DefId),
    Enum(DefId),
    Variant(DefId),
    Trait(DefId),
    TyAlias(DefId),
    AssociatedTy(DefId),
    PrimTy(hir::PrimTy),
    TyParam(DefId),
    SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),

    // Value namespace
    Fn(DefId),
    Const(DefId),
    Static(DefId, bool /* is_mutbl */),
    StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor
    VariantCtor(DefId, CtorKind),
    Method(DefId),
    AssociatedConst(DefId),
    Local(DefId),
    Upvar(DefId,        // def id of closed over local
          usize,        // index in the freevars list of the closure
          ast::NodeId), // expr node that creates the closure
    Label(ast::NodeId),

    // Macro namespace
    Macro(DefId, MacroKind),

    GlobalAsm(DefId),

    // Both namespaces
    Err,
}

/// The result of resolving a path before lowering to HIR.
/// `base_def` is definition of resolved part of the
/// path, `unresolved_segments` is the number of unresolved
/// segments.
///     module::Type::AssocX::AssocY::MethodOrAssocType
///     ^~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
///     base_def      unresolved_segments = 3
///
///     <T as Trait>::AssocX::AssocY::MethodOrAssocType
///           ^~~~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~
///           base_def        unresolved_segments = 2
#[derive(Copy, Clone, Debug)]
pub struct PathResolution {
    base_def: Def,
    unresolved_segments: usize,
}

impl PathResolution {
    pub fn new(def: Def) -> Self {
        PathResolution { base_def: def, unresolved_segments: 0 }
    }

    pub fn with_unresolved_segments(def: Def, mut unresolved_segments: usize) -> Self {
        if def == Def::Err { unresolved_segments = 0 }
        PathResolution { base_def: def, unresolved_segments: unresolved_segments }
    }

    #[inline]
    pub fn base_def(&self) -> Def {
        self.base_def
    }

    #[inline]
    pub fn unresolved_segments(&self) -> usize {
        self.unresolved_segments
    }

    pub fn kind_name(&self) -> &'static str {
        if self.unresolved_segments != 0 {
            "associated item"
        } else {
            self.base_def.kind_name()
        }
    }
}

/// Definition mapping
pub type DefMap = NodeMap<PathResolution>;

/// This is the replacement export map. It maps a module to all of the exports
/// within.
pub type ExportMap = NodeMap<Vec<Export>>;

#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Export {
    /// The name of the target.
    pub ident: ast::Ident,
    /// The definition of the target.
    pub def: Def,
    /// The span of the target definition.
    pub span: Span,
}

impl CtorKind {
    pub fn from_ast(vdata: &ast::VariantData) -> CtorKind {
        match *vdata {
            ast::VariantData::Tuple(..) => CtorKind::Fn,
            ast::VariantData::Unit(..) => CtorKind::Const,
            ast::VariantData::Struct(..) => CtorKind::Fictive,
        }
    }
    pub fn from_hir(vdata: &hir::VariantData) -> CtorKind {
        match *vdata {
            hir::VariantData::Tuple(..) => CtorKind::Fn,
            hir::VariantData::Unit(..) => CtorKind::Const,
            hir::VariantData::Struct(..) => CtorKind::Fictive,
        }
    }
}

impl Def {
    pub fn def_id(&self) -> DefId {
        match *self {
            Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
            Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
            Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
            Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
            Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) |
            Def::GlobalAsm(id) => {
                id
            }

            Def::Label(..)  |
            Def::PrimTy(..) |
            Def::SelfTy(..) |
            Def::Err => {
                bug!("attempted .def_id() on invalid def: {:?}", self)
            }
        }
    }

    /// A human readable kind name
    pub fn kind_name(&self) -> &'static str {
        match *self {
            Def::Fn(..) => "function",
            Def::Mod(..) => "module",
            Def::Static(..) => "static",
            Def::Variant(..) => "variant",
            Def::VariantCtor(.., CtorKind::Fn) => "tuple variant",
            Def::VariantCtor(.., CtorKind::Const) => "unit variant",
            Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
            Def::Enum(..) => "enum",
            Def::TyAlias(..) => "type alias",
            Def::AssociatedTy(..) => "associated type",
            Def::Struct(..) => "struct",
            Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
            Def::StructCtor(.., CtorKind::Const) => "unit struct",
            Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"),
            Def::Union(..) => "union",
            Def::Trait(..) => "trait",
            Def::Method(..) => "method",
            Def::Const(..) => "constant",
            Def::AssociatedConst(..) => "associated constant",
            Def::TyParam(..) => "type parameter",
            Def::PrimTy(..) => "builtin type",
            Def::Local(..) => "local variable",
            Def::Upvar(..) => "closure capture",
            Def::Label(..) => "label",
            Def::SelfTy(..) => "self type",
            Def::Macro(..) => "macro",
            Def::GlobalAsm(..) => "global asm",
            Def::Err => "unresolved item",
        }
    }
}
<commit_msg>Update def.rs<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use hir::def_id::DefId;
use util::nodemap::NodeMap;
use syntax::ast;
use syntax::ext::base::MacroKind;
use syntax_pos::Span;
use hir;

#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum CtorKind {
    /// Constructor function automatically created by a tuple struct/variant.
    Fn,
    /// Constructor constant automatically created by a unit struct/variant.
    Const,
    /// Unusable name in value namespace created by a struct variant.
    Fictive,
}

#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Def {
    // Type namespace
    Mod(DefId),
    Struct(DefId), // DefId refers to NodeId of the struct itself
    Union(DefId),
    Enum(DefId),
    Variant(DefId),
    Trait(DefId),
    TyAlias(DefId),
    AssociatedTy(DefId),
    PrimTy(hir::PrimTy),
    TyParam(DefId),
    SelfTy(Option<DefId> /* trait */, Option<DefId> /* impl */),

    // Value namespace
    Fn(DefId),
    Const(DefId),
    Static(DefId, bool /* is_mutbl */),
    StructCtor(DefId, CtorKind), // DefId refers to NodeId of the struct's constructor
    VariantCtor(DefId, CtorKind),
    Method(DefId),
    AssociatedConst(DefId),
    Local(DefId),
    Upvar(DefId,        // def id of closed over local
          usize,        // index in the freevars list of the closure
          ast::NodeId), // expr node that creates the closure
    Label(ast::NodeId),

    // Macro namespace
    Macro(DefId, MacroKind),

    GlobalAsm(DefId),

    // Both namespaces
    Err,
}

/// The result of resolving a path before lowering to HIR.
/// `base_def` is definition of resolved part of the
/// path, `unresolved_segments` is the number of unresolved
/// segments.
///     module::Type::AssocX::AssocY::MethodOrAssocType
///     ^~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
///     base_def      unresolved_segments = 3
///
///     <T as Trait>::AssocX::AssocY::MethodOrAssocType
///           ^~~~~~~~~~~~~~  ^~~~~~~~~~~~~~~~~~~~~~~~~
///           base_def        unresolved_segments = 2
#[derive(Copy, Clone, Debug)]
pub struct PathResolution {
    base_def: Def,
    unresolved_segments: usize,
}

impl PathResolution {
    pub fn new(def: Def) -> Self {
        PathResolution { base_def: def, unresolved_segments: 0 }
    }

    pub fn with_unresolved_segments(def: Def, mut unresolved_segments: usize) -> Self {
        if def == Def::Err { unresolved_segments = 0 }
        PathResolution { base_def: def, unresolved_segments: unresolved_segments }
    }

    #[inline]
    pub fn base_def(&self) -> Def {
        self.base_def
    }

    #[inline]
    pub fn unresolved_segments(&self) -> usize {
        self.unresolved_segments
    }

    pub fn kind_name(&self) -> &'static str {
        if self.unresolved_segments != 0 {
            "associated item"
        } else {
            self.base_def.kind_name()
        }
    }
}

/// Definition mapping
pub type DefMap = NodeMap<PathResolution>;

/// This is the replacement export map. It maps a module to all of the exports
/// within.
pub type ExportMap = NodeMap<Vec<Export>>;

#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct Export {
    /// The name of the target.
    pub ident: ast::Ident,
    /// The definition of the target.
    pub def: Def,
    /// The span of the target definition.
    pub span: Span,
}

impl CtorKind {
    pub fn from_ast(vdata: &ast::VariantData) -> CtorKind {
        match *vdata {
            ast::VariantData::Tuple(..) => CtorKind::Fn,
            ast::VariantData::Unit(..) => CtorKind::Const,
            ast::VariantData::Struct(..) => CtorKind::Fictive,
        }
    }
    pub fn from_hir(vdata: &hir::VariantData) -> CtorKind {
        match *vdata {
            hir::VariantData::Tuple(..) => CtorKind::Fn,
            hir::VariantData::Unit(..) => CtorKind::Const,
            hir::VariantData::Struct(..) => CtorKind::Fictive,
        }
    }
}

impl Def {
    pub fn def_id(&self) -> DefId {
        match *self {
            Def::Fn(id) | Def::Mod(id) | Def::Static(id, _) |
            Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
            Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
            Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
            Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) |
            Def::GlobalAsm(id) => {
                id
            }

            Def::Label(..)  |
            Def::PrimTy(..) |
            Def::SelfTy(..) |
            Def::Err => {
                bug!("attempted .def_id() on invalid def: {:?}", self)
            }
        }
    }

    /// A human readable kind name
    pub fn kind_name(&self) -> &'static str {
        match *self {
            Def::Fn(..) => "function",
            Def::Mod(..) => "module",
            Def::Static(..) => "static",
            Def::Variant(..) => "variant",
            Def::VariantCtor(.., CtorKind::Fn) => "tuple variant",
            Def::VariantCtor(.., CtorKind::Const) => "unit variant",
            Def::VariantCtor(.., CtorKind::Fictive) => "struct variant",
            Def::Enum(..) => "enum",
            Def::TyAlias(..) => "type alias",
            Def::AssociatedTy(..) => "associated type",
            Def::Struct(..) => "struct",
            Def::StructCtor(.., CtorKind::Fn) => "tuple struct",
            Def::StructCtor(.., CtorKind::Const) => "unit struct",
            Def::StructCtor(.., CtorKind::Fictive) => bug!("impossible struct constructor"),
            Def::Union(..) => "union",
            Def::Trait(..) => "trait",
            Def::Method(..) => "method",
            Def::Const(..) => "constant",
            Def::AssociatedConst(..) => "associated constant",
            Def::TyParam(..) => "type parameter",
            Def::PrimTy(..) => "builtin type",
            Def::Local(..) => "local variable",
            Def::Upvar(..) => "closure capture",
            Def::Label(..) => "label",
            Def::SelfTy(..) => "self type",
            Def::Macro(..) => "macro",
            Def::GlobalAsm(..) => "global asm",
            Def::Err => "unresolved item",
        }
    }
}
<|endoftext|>


<commit_before>#[doc = "An atomically reference counted wrapper that can be used to
share immutable data between tasks."]

import comm::{port, chan, methods};
import sys::methods;

export arc, get, clone, shared_arc, get_arc;

export exclusive, methods;

#[abi = "cdecl"]
native mod rustrt {
    #[rust_stack]
    fn rust_atomic_increment(p: &mut libc::intptr_t)
        -> libc::intptr_t;

    #[rust_stack]
    fn rust_atomic_decrement(p: &mut libc::intptr_t)
        -> libc::intptr_t;
}

type arc_data<T> = {
    mut count: libc::intptr_t,
    data: T
};

resource arc_destruct<T>(data: *libc::c_void) {
    unsafe {
        let data: ~arc_data<T> = unsafe::reinterpret_cast(data);
        let new_count = rustrt::rust_atomic_decrement(&mut data.count);
        assert new_count >= 0;
        if new_count == 0 {
            // drop glue takes over.
        } else {
            unsafe::forget(data);
        }
    }
}

type arc<T: const> = arc_destruct<T>;

#[doc="Create an atomically reference counted wrapper."]
fn arc<T: const>(-data: T) -> arc<T> {
    let data = ~{mut count: 1, data: data};
    unsafe {
        let ptr = unsafe::transmute(data);
        arc_destruct(ptr)
    }
}

#[doc="Access the underlying data in an atomically reference counted
 wrapper."]
fn get<T: const>(rc: &a.arc<T>) -> &a.T {
    unsafe {
        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
        // Cast us back into the correct region
        let r = unsafe::reinterpret_cast(&ptr.data);
        unsafe::forget(ptr);
        ret r;
    }
}

#[doc="Duplicate an atomically reference counted wrapper.

The resulting two `arc` objects will point to the same underlying data
object. However, one of the `arc` objects can be sent to another task,
allowing them to share the underlying data."]
fn clone<T: const>(rc: &arc<T>) -> arc<T> {
    unsafe {
        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
        rustrt::rust_atomic_increment(&mut ptr.count);
        unsafe::forget(ptr);
    }
    arc_destruct(**rc)
}

// An arc over mutable data that is protected by a lock.
type ex_data<T> = {lock: sys::lock_and_signal, data: T};
type exclusive<T> = arc_destruct<ex_data<T>>;

fn exclusive<T>(-data: T) -> exclusive<T> {
    let data = ~{mut count: 1, data: {lock: sys::create_lock(),
                                      data: data}};
    unsafe {
        let ptr = unsafe::reinterpret_cast(data);
        unsafe::forget(data);
        arc_destruct(ptr)
    }
}

impl methods<T> for exclusive<T> {
    fn clone() -> exclusive<T> {
        unsafe {
            // this makes me nervous...
            let ptr: ~arc_data<ex_data<T>> = unsafe::reinterpret_cast(*self);
            rustrt::rust_atomic_increment(&mut ptr.count);
            unsafe::forget(ptr);
        }
        arc_destruct(*self)
    }

    fn with<U>(f: fn(sys::condition, x: &T) -> U) -> U {
        unsafe {
            let ptr: ~arc_data<ex_data<T>> = unsafe::reinterpret_cast(*self);
            let rec: &ex_data<T> = &(*ptr).data;
            unsafe::forget(ptr);
            rec.lock.lock_cond() {|c|
                f(c, &rec.data)
            }
        }
    }
}

// Convenience code for sharing arcs between tasks

type get_chan<T: const send> = chan<chan<arc<T>>>;

// (terminate, get)
type shared_arc<T: const send> = (shared_arc_res, get_chan<T>);

resource shared_arc_res(c: comm::chan<()>) {
    c.send(());
}

fn shared_arc<T: send const>(-data: T) -> shared_arc<T> {
    let a = arc::arc(data);
    let p = port();
    let c = chan(p);
    task::spawn() {|move a|
        let mut live = true;
        let terminate = port();
        let get = port();

        c.send((chan(terminate), chan(get)));

        while live {
            alt comm::select2(terminate, get) {
              either::left(()) { live = false; }
              either::right(cc) {
                comm::send(cc, arc::clone(&a));
              }
            }
        }
    };
    let (terminate, get) = p.recv();
    (shared_arc_res(terminate), get)
}

fn get_arc<T: send const>(c: get_chan<T>) -> arc::arc<T> {
    let p = port();
    c.send(chan(p));
    p.recv()
}

#[cfg(test)]
mod tests {
    import comm::*;
    import future::future;

    #[test]
    fn manually_share_arc() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let arc_v = arc::arc(v);

        let p = port();
        let c = chan(p);

        task::spawn() {||
            let p = port();
            c.send(chan(p));

            let arc_v = p.recv();

            let v = *arc::get::<[int]>(&arc_v);
            assert v[3] == 4;
        };

        let c = p.recv();
        c.send(arc::clone(&arc_v));

        assert (*arc::get(&arc_v))[2] == 3;

        log(info, arc_v);
    }

    #[test]
    fn auto_share_arc() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let (_res, arc_c) = shared_arc(v);

        let p = port();
        let c = chan(p);

        task::spawn() {||
            let arc_v = get_arc(arc_c);
            let v = *get(&arc_v);
            assert v[2] == 3;

            c.send(());
        };

        assert p.recv() == ();
    }

    #[test]
    fn exclusive_arc() {
        let mut futures = [];

        let num_tasks = 10u;
        let count = 1000u;

        let total = exclusive(~mut 0u);

        for uint::range(0u, num_tasks) {|_i|
            let total = total.clone();
            futures += [future::spawn({||
                for uint::range(0u, count) {|_i|
                    total.with {|_cond, count|
                        **count += 1u;
                    }
                }
            })];
        };

        for futures.each {|f| f.get() };

        total.with {|_cond, total|
            assert **total == num_tasks * count
        };
    }
}
<commit_msg>Reference fixes.<commit_after>#[doc = "An atomically reference counted wrapper that can be used to
share immutable data between tasks."]

import comm::{port, chan, methods};
import sys::methods;

export arc, get, clone, shared_arc, get_arc;

export exclusive, methods;

#[abi = "cdecl"]
native mod rustrt {
    #[rust_stack]
    fn rust_atomic_increment(p: &mut libc::intptr_t)
        -> libc::intptr_t;

    #[rust_stack]
    fn rust_atomic_decrement(p: &mut libc::intptr_t)
        -> libc::intptr_t;
}

type arc_data<T> = {
    mut count: libc::intptr_t,
    data: T
};

resource arc_destruct<T>(data: *libc::c_void) {
    unsafe {
        let data: ~arc_data<T> = unsafe::reinterpret_cast(data);
        let new_count = rustrt::rust_atomic_decrement(&mut data.count);
        assert new_count >= 0;
        if new_count == 0 {
            // drop glue takes over.
        } else {
            unsafe::forget(data);
        }
    }
}

type arc<T: const> = arc_destruct<T>;

#[doc="Create an atomically reference counted wrapper."]
fn arc<T: const>(-data: T) -> arc<T> {
    let data = ~{mut count: 1, data: data};
    unsafe {
        let ptr = unsafe::transmute(data);
        arc_destruct(ptr)
    }
}

#[doc="Access the underlying data in an atomically reference counted
 wrapper."]
fn get<T: const>(rc: &a.arc<T>) -> &a.T {
    unsafe {
        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
        // Cast us back into the correct region
        let r = unsafe::reinterpret_cast(&ptr.data);
        unsafe::forget(ptr);
        ret r;
    }
}

#[doc="Duplicate an atomically reference counted wrapper.

The resulting two `arc` objects will point to the same underlying data
object. However, one of the `arc` objects can be sent to another task,
allowing them to share the underlying data."]
fn clone<T: const>(rc: &arc<T>) -> arc<T> {
    unsafe {
        let ptr: ~arc_data<T> = unsafe::reinterpret_cast(**rc);
        rustrt::rust_atomic_increment(&mut ptr.count);
        unsafe::forget(ptr);
    }
    arc_destruct(**rc)
}

// An arc over mutable data that is protected by a lock.
type ex_data<T> = {lock: sys::lock_and_signal, data: T};
type exclusive<T> = arc_destruct<ex_data<T>>;

fn exclusive<T>(-data: T) -> exclusive<T> {
    let data = ~{mut count: 1, data: {lock: sys::create_lock(),
                                      data: data}};
    unsafe {
        let ptr = unsafe::reinterpret_cast(data);
        unsafe::forget(data);
        arc_destruct(ptr)
    }
}

impl methods<T> for exclusive<T> {
    fn clone() -> exclusive<T> {
        unsafe {
            // this makes me nervous...
            let ptr: ~arc_data<ex_data<T>> = unsafe::reinterpret_cast(*self);
            rustrt::rust_atomic_increment(&mut ptr.count);
            unsafe::forget(ptr);
        }
        arc_destruct(*self)
    }

    fn with<U>(f: fn(sys::condition, x: &T) -> U) -> U {
        unsafe {
            let ptr: ~arc_data<ex_data<T>> = unsafe::reinterpret_cast(*self);
            let r = {
                let rec: &ex_data<T> = &(*ptr).data;
                rec.lock.lock_cond() {|c|
                    f(c, &rec.data)
                }
            };
            unsafe::forget(ptr);
            r
        }
    }
}

// Convenience code for sharing arcs between tasks

type get_chan<T: const send> = chan<chan<arc<T>>>;

// (terminate, get)
type shared_arc<T: const send> = (shared_arc_res, get_chan<T>);

resource shared_arc_res(c: comm::chan<()>) {
    c.send(());
}

fn shared_arc<T: send const>(-data: T) -> shared_arc<T> {
    let a = arc::arc(data);
    let p = port();
    let c = chan(p);
    task::spawn() {|move a|
        let mut live = true;
        let terminate = port();
        let get = port();

        c.send((chan(terminate), chan(get)));

        while live {
            alt comm::select2(terminate, get) {
              either::left(()) { live = false; }
              either::right(cc) {
                comm::send(cc, arc::clone(&a));
              }
            }
        }
    };
    let (terminate, get) = p.recv();
    (shared_arc_res(terminate), get)
}

fn get_arc<T: send const>(c: get_chan<T>) -> arc::arc<T> {
    let p = port();
    c.send(chan(p));
    p.recv()
}

#[cfg(test)]
mod tests {
    import comm::*;
    import future::future;

    #[test]
    fn manually_share_arc() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let arc_v = arc::arc(v);

        let p = port();
        let c = chan(p);

        task::spawn() {||
            let p = port();
            c.send(chan(p));

            let arc_v = p.recv();

            let v = *arc::get::<[int]>(&arc_v);
            assert v[3] == 4;
        };

        let c = p.recv();
        c.send(arc::clone(&arc_v));

        assert (*arc::get(&arc_v))[2] == 3;

        log(info, arc_v);
    }

    #[test]
    fn auto_share_arc() {
        let v = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
        let (_res, arc_c) = shared_arc(v);

        let p = port();
        let c = chan(p);

        task::spawn() {||
            let arc_v = get_arc(arc_c);
            let v = *get(&arc_v);
            assert v[2] == 3;

            c.send(());
        };

        assert p.recv() == ();
    }

    #[test]
    fn exclusive_arc() {
        let mut futures = [];

        let num_tasks = 10u;
        let count = 1000u;

        let total = exclusive(~mut 0u);

        for uint::range(0u, num_tasks) {|_i|
            let total = total.clone();
            futures += [future::spawn({||
                for uint::range(0u, count) {|_i|
                    total.with {|_cond, count|
                        **count += 1u;
                    }
                }
            })];
        };

        for futures.each {|f| f.get() };

        total.with {|_cond, total|
            assert **total == num_tasks * count
        };
    }
}
<|endoftext|>


<commit_before>//! Infers how each function uses every register

use analysis::inst_combine;
use frontend::radeco_containers::{RadecoFunction, RadecoModule};
use middle::dce;
use middle::ir;
use middle::regfile::*;
use middle::ssa::cfg_traits::*;
use middle::ssa::ssa_traits::*;
use middle::ssa::ssastorage::SSAStorage;
use middle::ssa::utils;

use petgraph::visit::{DfsPostOrder, Walker};

use std::collections::{BTreeMap, HashSet};

/// For every function, patch all of its call sites to ignore registers that the
/// callee doesn't read and to preserve register values that the callee
/// preserves. Then, record which registers it reads and which registers it
/// preserves.
///
/// After this, all functions should have mutable [`regusage`][RadecoFunction::regusage]s.
///
/// This analysis is super conservative; for example, if a function preserves a
/// register by pushing it onto the stack and popping it back right before
/// returning, it is considered to be read and not preserved because we can't
/// guarantee that that stack location is never subsequently read or modified.
/// See #147 for further discussion
pub fn run(rmod: &mut RadecoModule, reginfo: &SubRegisterFile) -> () {
    Inferer::new().run(rmod, reginfo);
}

struct Inferer {
    /// Addresses of the functions we've already analyzed
    analyzed: HashSet<u64>,
}

impl Inferer {
    fn new() -> Inferer {
        Inferer {
            analyzed: HashSet::new(),
        }
    }

    /// Calls `patch_fn`, `dce::collect`, and `analyze_fn` on every function,
    /// callees first
    fn run(&mut self, rmod: &mut RadecoModule, reginfo: &SubRegisterFile) -> () {
        // for imports, *ASSUME* that the callconv that r2 says is correct
        {
            let imp_ru_iter = rmod.imports.iter().filter_map(|(&imp_addr, imp_info)| {
                let imp_rfn = imp_info.rfn.borrow();
                let regusage = reginfo.r2callconv_to_register_usage(
                    imp_rfn.callconv.as_ref()?, // ignore imports without callconvs
                    &*imp_rfn.callconv_name,
                )?;
                Some((imp_addr, regusage))
            });
            for (imp_addr, imp_ru) in imp_ru_iter {
                rmod.functions.get_mut(&imp_addr).unwrap().regusage = imp_ru;
                self.analyzed.insert(imp_addr);
            }
        }

        let mut dfs_wi = DfsPostOrder::empty(&rmod.callgraph).iter(&rmod.callgraph);
        // pick a function ...
        for fn_ni in rmod.callgraph.node_indices() {
            // ... and start a dfs on it
            dfs_wi.inner_mut().move_to(fn_ni);
            while let Some(fn_to_anal) = dfs_wi.next() {
                let fn_addr = rmod.callgraph[fn_to_anal];

                // ignore functions already in `call_convs` (probably because its an import)
                if !self.analyzed.contains(&fn_addr) {
                    self.patch_fn(fn_addr, &mut rmod.functions);

                    let rfn = &mut rmod.functions.get_mut(&fn_addr).unwrap();
                    dce::collect(rfn.ssa_mut());
                    inst_combine::run(rfn.ssa_mut());

                    let ru = self.analyze_fn(rfn, reginfo).unwrap_or_else(|| {
                        radeco_err!("Failed to analyze fn: {:?} (@ {:#X})", rfn.name, fn_addr);
                        // if analysis failed, default to "reads and clobbers everything"
                        reginfo.new_register_usage()
                    });

                    rfn.regusage = ru;
                    self.analyzed.insert(fn_addr);
                }
            }
        }
    }

    /// Using the callconv info we've gathered so far, patch-up call sites to
    /// to remove arguments that the callee doesn't read and make values in
    /// callee-saved registers be preserved across the call.
    fn patch_fn(&self, fn_addr: u64, fn_map: &mut BTreeMap<u64, RadecoFunction>) -> () {
        radeco_trace!("patching calls in fn: {}", fn_map[&fn_addr].name);
        for node in fn_map[&fn_addr].ssa().inorder_walk() {
            if let Ok(NodeType::Op(ir::MOpcode::OpCall)) =
                fn_map[&fn_addr].ssa().node_data(node).map(|nd| nd.nt)
            {
                self.patch_call_node(node, fn_addr, fn_map)
                    .unwrap_or_else(|| {
                        radeco_warn!(
                            "failed to remove unused args for call at {:#X}",
                            fn_map[&fn_addr].ssa().address(node).unwrap()
                        );
                    });
            }
        }
    }

    fn patch_call_node(
        &self,
        call_node: <SSAStorage as SSA>::ValueRef,
        fn_addr: u64,
        fn_map: &mut BTreeMap<u64, RadecoFunction>,
    ) -> Option<()> {
        // bail on indirect or weird call
        let (call_tgt_addr, call_reg_map) = direct_call_info(fn_map[&fn_addr].ssa(), call_node)?;

        // remove unread args
        for (regid, &op_node) in &call_reg_map {
            if fn_map[&call_tgt_addr].regusage.is_ignored(regid) {
                fn_map
                    .get_mut(&fn_addr)
                    .unwrap()
                    .ssa_mut()
                    .op_unuse(call_node, op_node);
            }
        }

        // bridge preserved registers
        for (regid, (use_node, _)) in utils::call_rets(call_node, fn_map[&fn_addr].ssa()) {
            if fn_map[&call_tgt_addr].regusage.is_preserved(regid) {
                fn_map
                    .get_mut(&fn_addr)
                    .unwrap()
                    .ssa_mut()
                    .replace_value(use_node, call_reg_map[regid]);
            }
        }

        Some(())
    }

    fn analyze_fn(&self, rfn: &RadecoFunction, reginfo: &SubRegisterFile) -> Option<RegisterUsage> {
        radeco_trace!("analyzing fn: {}", rfn.name);
        let ssa = rfn.ssa();
        let entry_regstate_node = ssa.registers_in(ssa.entry_node()?)?;
        let exit_regstate_node = ssa.registers_in(ssa.exit_node()?)?;
        // some registers may not be present in the entry node;
        // this means that the function neither reads nor preserves that register
        let entry_regstate = utils::register_state_info(entry_regstate_node, ssa);
        let exit_regstate = utils::register_state_info(exit_regstate_node, ssa);

        let mut ret = reginfo.new_register_usage();
        ret.set_all_ignored();

        for regid in ssa.regfile.iter_register_ids() {
            // ignore registers not in entry regstate
            if let Some(&(reg_val_entry, _)) = entry_regstate.get(regid) {
                // bail if a register isn't present in exit regstate
                let &(reg_val_exit, _) = exit_regstate.get(regid)?;

                if reg_val_exit == reg_val_entry {
                    ret.set_preserved(regid);
                }

                // find all uses, ignoring entry/exit register state
                let mut uses_iter = ssa
                    .uses_of(reg_val_entry)
                    .into_iter()
                    .filter(|&n| n != entry_regstate_node && n != exit_regstate_node);
                if uses_iter.next().is_some() {
                    ret.set_read(regid);
                }
            }
        }

        Some(ret)
    }
}

fn direct_call_info(
    ssa: &SSAStorage,
    call_node: <SSAStorage as SSA>::ValueRef,
) -> Option<(u64, RegisterMap<<SSAStorage as SSA>::ValueRef>)> {
    let callinfo = utils::call_info(call_node, ssa)?;
    Some((ssa.constant(callinfo.target)?, callinfo.register_args))
}
<commit_msg>Comment `inst_combine::run` out<commit_after>//! Infers how each function uses every register

use analysis::inst_combine;
use frontend::radeco_containers::{RadecoFunction, RadecoModule};
use middle::dce;
use middle::ir;
use middle::regfile::*;
use middle::ssa::cfg_traits::*;
use middle::ssa::ssa_traits::*;
use middle::ssa::ssastorage::SSAStorage;
use middle::ssa::utils;

use petgraph::visit::{DfsPostOrder, Walker};

use std::collections::{BTreeMap, HashSet};

/// For every function, patch all of its call sites to ignore registers that the
/// callee doesn't read and to preserve register values that the callee
/// preserves. Then, record which registers it reads and which registers it
/// preserves.
///
/// After this, all functions should have mutable [`regusage`][RadecoFunction::regusage]s.
///
/// This analysis is super conservative; for example, if a function preserves a
/// register by pushing it onto the stack and popping it back right before
/// returning, it is considered to be read and not preserved because we can't
/// guarantee that that stack location is never subsequently read or modified.
/// See #147 for further discussion
pub fn run(rmod: &mut RadecoModule, reginfo: &SubRegisterFile) -> () {
    Inferer::new().run(rmod, reginfo);
}

struct Inferer {
    /// Addresses of the functions we've already analyzed
    analyzed: HashSet<u64>,
}

impl Inferer {
    fn new() -> Inferer {
        Inferer {
            analyzed: HashSet::new(),
        }
    }

    /// Calls `patch_fn`, `dce::collect`, and `analyze_fn` on every function,
    /// callees first
    fn run(&mut self, rmod: &mut RadecoModule, reginfo: &SubRegisterFile) -> () {
        // for imports, *ASSUME* that the callconv that r2 says is correct
        {
            let imp_ru_iter = rmod.imports.iter().filter_map(|(&imp_addr, imp_info)| {
                let imp_rfn = imp_info.rfn.borrow();
                let regusage = reginfo.r2callconv_to_register_usage(
                    imp_rfn.callconv.as_ref()?, // ignore imports without callconvs
                    &*imp_rfn.callconv_name,
                )?;
                Some((imp_addr, regusage))
            });
            for (imp_addr, imp_ru) in imp_ru_iter {
                rmod.functions.get_mut(&imp_addr).unwrap().regusage = imp_ru;
                self.analyzed.insert(imp_addr);
            }
        }

        let mut dfs_wi = DfsPostOrder::empty(&rmod.callgraph).iter(&rmod.callgraph);
        // pick a function ...
        for fn_ni in rmod.callgraph.node_indices() {
            // ... and start a dfs on it
            dfs_wi.inner_mut().move_to(fn_ni);
            while let Some(fn_to_anal) = dfs_wi.next() {
                let fn_addr = rmod.callgraph[fn_to_anal];

                // ignore functions already in `call_convs` (probably because its an import)
                if !self.analyzed.contains(&fn_addr) {
                    self.patch_fn(fn_addr, &mut rmod.functions);

                    let rfn = &mut rmod.functions.get_mut(&fn_addr).unwrap();
                    dce::collect(rfn.ssa_mut());
                    // TODO preserve NodeIndex for recovering local variables
                    // inst_combine::run(rfn.ssa_mut());

                    let ru = self.analyze_fn(rfn, reginfo).unwrap_or_else(|| {
                        radeco_err!("Failed to analyze fn: {:?} (@ {:#X})", rfn.name, fn_addr);
                        // if analysis failed, default to "reads and clobbers everything"
                        reginfo.new_register_usage()
                    });

                    rfn.regusage = ru;
                    self.analyzed.insert(fn_addr);
                }
            }
        }
    }

    /// Using the callconv info we've gathered so far, patch-up call sites to
    /// to remove arguments that the callee doesn't read and make values in
    /// callee-saved registers be preserved across the call.
    fn patch_fn(&self, fn_addr: u64, fn_map: &mut BTreeMap<u64, RadecoFunction>) -> () {
        radeco_trace!("patching calls in fn: {}", fn_map[&fn_addr].name);
        for node in fn_map[&fn_addr].ssa().inorder_walk() {
            if let Ok(NodeType::Op(ir::MOpcode::OpCall)) =
                fn_map[&fn_addr].ssa().node_data(node).map(|nd| nd.nt)
            {
                self.patch_call_node(node, fn_addr, fn_map)
                    .unwrap_or_else(|| {
                        radeco_warn!(
                            "failed to remove unused args for call at {:#X}",
                            fn_map[&fn_addr].ssa().address(node).unwrap()
                        );
                    });
            }
        }
    }

    fn patch_call_node(
        &self,
        call_node: <SSAStorage as SSA>::ValueRef,
        fn_addr: u64,
        fn_map: &mut BTreeMap<u64, RadecoFunction>,
    ) -> Option<()> {
        // bail on indirect or weird call
        let (call_tgt_addr, call_reg_map) = direct_call_info(fn_map[&fn_addr].ssa(), call_node)?;

        // remove unread args
        for (regid, &op_node) in &call_reg_map {
            if fn_map[&call_tgt_addr].regusage.is_ignored(regid) {
                fn_map
                    .get_mut(&fn_addr)
                    .unwrap()
                    .ssa_mut()
                    .op_unuse(call_node, op_node);
            }
        }

        // bridge preserved registers
        for (regid, (use_node, _)) in utils::call_rets(call_node, fn_map[&fn_addr].ssa()) {
            if fn_map[&call_tgt_addr].regusage.is_preserved(regid) {
                fn_map
                    .get_mut(&fn_addr)
                    .unwrap()
                    .ssa_mut()
                    .replace_value(use_node, call_reg_map[regid]);
            }
        }

        Some(())
    }

    fn analyze_fn(&self, rfn: &RadecoFunction, reginfo: &SubRegisterFile) -> Option<RegisterUsage> {
        radeco_trace!("analyzing fn: {}", rfn.name);
        let ssa = rfn.ssa();
        let entry_regstate_node = ssa.registers_in(ssa.entry_node()?)?;
        let exit_regstate_node = ssa.registers_in(ssa.exit_node()?)?;
        // some registers may not be present in the entry node;
        // this means that the function neither reads nor preserves that register
        let entry_regstate = utils::register_state_info(entry_regstate_node, ssa);
        let exit_regstate = utils::register_state_info(exit_regstate_node, ssa);

        let mut ret = reginfo.new_register_usage();
        ret.set_all_ignored();

        for regid in ssa.regfile.iter_register_ids() {
            // ignore registers not in entry regstate
            if let Some(&(reg_val_entry, _)) = entry_regstate.get(regid) {
                // bail if a register isn't present in exit regstate
                let &(reg_val_exit, _) = exit_regstate.get(regid)?;

                if reg_val_exit == reg_val_entry {
                    ret.set_preserved(regid);
                }

                // find all uses, ignoring entry/exit register state
                let mut uses_iter = ssa
                    .uses_of(reg_val_entry)
                    .into_iter()
                    .filter(|&n| n != entry_regstate_node && n != exit_regstate_node);
                if uses_iter.next().is_some() {
                    ret.set_read(regid);
                }
            }
        }

        Some(ret)
    }
}

fn direct_call_info(
    ssa: &SSAStorage,
    call_node: <SSAStorage as SSA>::ValueRef,
) -> Option<(u64, RegisterMap<<SSAStorage as SSA>::ValueRef>)> {
    let callinfo = utils::call_info(call_node, ssa)?;
    Some((ssa.constant(callinfo.target)?, callinfo.register_args))
}
<|endoftext|>


<commit_before>use std::sync::Arc;
use super::{Args, Configuration};
use client::Context;
use model::{Message, Permissions};
use std::collections::HashMap;
use std::fmt;

pub type Check = Fn(&mut Context, &Message, &mut Args, &Arc<Command>) -> bool
                     + Send
                     + Sync
                     + 'static;
pub type Exec = Fn(&mut Context, &Message, Args) -> Result<(), Error> + Send + Sync + 'static;
pub type Help = Fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Args)
                   -> Result<(), Error>
                    + Send
                    + Sync
                    + 'static;
pub type BeforeHook = Fn(&mut Context, &Message, &str) -> bool + Send + Sync + 'static;
pub type AfterHook = Fn(&mut Context, &Message, &str, Result<(), Error>) + Send + Sync + 'static;
pub(crate) type InternalCommand = Arc<Command>;
pub type PrefixCheck = Fn(&mut Context, &Message) -> Option<String> + Send + Sync + 'static;

pub enum CommandOrAlias {
    Alias(String),
    Command(InternalCommand),
}

/// An error from a command.
#[derive(Clone, Debug)]
pub struct Error(pub String);

impl<D: fmt::Display> From<D> for Error {
    fn from(d: D) -> Self {
        Error(format!("{}", d))
    }
}

/// Command function type. Allows to access internal framework things inside
/// your commands.
pub enum CommandType {
    StringResponse(String),
    Basic(Box<Exec>),
    WithCommands(Box<Help>),
}

pub struct CommandGroup {
    pub prefix: Option<String>,
    pub commands: HashMap<String, CommandOrAlias>,
    /// Some fields taken from Command
    pub bucket: Option<String>,
    pub required_permissions: Permissions,
    pub allowed_roles: Vec<String>,
    pub help_available: bool,
    pub dm_only: bool,
    pub guild_only: bool,
    pub owners_only: bool,
}

/// Command struct used to store commands internally.
pub struct Command {
    /// A set of checks to be called prior to executing the command. The checks
    /// will short-circuit on the first check that returns `false`.
    pub checks: Vec<Box<Check>>,
    /// Function called when the command is called.
    pub exec: CommandType,
    /// Ratelimit bucket.
    pub bucket: Option<String>,
    /// Command description, used by other commands.
    pub desc: Option<String>,
    /// Example arguments, used by other commands.
    pub example: Option<String>,
    /// Command usage schema, used by other commands.
    pub usage: Option<String>,
    /// Minumum amount of arguments that should be passed.
    pub min_args: Option<i32>,
    /// Maximum amount of arguments that can be passed.
    pub max_args: Option<i32>,
    /// Permissions required to use this command.
    pub required_permissions: Permissions,
    /// Roles allowed to use this command.
    pub allowed_roles: Vec<String>,
    /// Whether command should be displayed in help list or not, used by other commands.
    pub help_available: bool,
    /// Whether command can be used only privately or not.
    pub dm_only: bool,
    /// Whether command can be used only in guilds or not.
    pub guild_only: bool,
    /// Whether command can only be used by owners or not.
    pub owners_only: bool,
    pub(crate) aliases: Vec<String>,
}

impl Command {
    pub fn new<F>(f: F) -> Self
        where F: Fn(&mut Context, &Message, Args) -> Result<(), Error> + Send + Sync + 'static {
        Command {
            exec: CommandType::Basic(Box::new(f)),
            ..Command::default()
        }
    }
}

impl Default for Command {
    fn default() -> Command {
        Command {
            aliases: Vec::new(),
            checks: Vec::default(),
            exec: CommandType::Basic(Box::new(|_, _, _| Ok(()))),
            desc: None,
            usage: None,
            example: None,
            min_args: None,
            bucket: None,
            max_args: None,
            required_permissions: Permissions::empty(),
            dm_only: false,
            guild_only: false,
            help_available: true,
            owners_only: false,
            allowed_roles: Vec::new(),
        }
    }
}

pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Option<Vec<usize>> {
    if !conf.prefixes.is_empty() || conf.dynamic_prefix.is_some() {
        // Find out if they were mentioned. If not, determine if the prefix
        // was used. If not, return None.
        let mut positions: Vec<usize> = vec![];

        if let Some(mention_end) = find_mention_end(&msg.content, conf) {
            positions.push(mention_end);
        } else if let Some(ref func) = conf.dynamic_prefix {
            if let Some(x) = func(ctx, msg) {
                if msg.content.starts_with(&x) {
                    positions.push(x.len());
                }
            } else {
                for n in &conf.prefixes {
                    if msg.content.starts_with(n) {
                        positions.push(n.len());
                    }
                }
            }
        } else {
            for n in &conf.prefixes {
                if msg.content.starts_with(n) {
                    positions.push(n.len());
                }
            }
        };

        if positions.is_empty() {
            return None;
        }

        if conf.allow_whitespace {
            let pos = *unsafe { positions.get_unchecked(0) };

            positions.insert(0, pos + 1);
        }

        Some(positions)
    } else if conf.on_mention.is_some() {
        find_mention_end(&msg.content, conf).map(|mention_end| {
            let mut positions = vec![mention_end];

            if conf.allow_whitespace {
                positions.insert(0, mention_end + 1);
            }

            positions
        })
    } else {
        None
    }
}

fn find_mention_end(content: &str, conf: &Configuration) -> Option<usize> {
    conf.on_mention.as_ref().and_then(|mentions| {
        mentions
            .iter()
            .find(|mention| content.starts_with(&mention[..]))
            .map(|m| m.len())
    })
}
<commit_msg>Add a todo<commit_after>use std::sync::Arc;
use super::{Args, Configuration};
use client::Context;
use model::{Message, Permissions};
use std::collections::HashMap;
use std::fmt;

pub type Check = Fn(&mut Context, &Message, &mut Args, &Arc<Command>) -> bool
                     + Send
                     + Sync
                     + 'static;
pub type Exec = Fn(&mut Context, &Message, Args) -> Result<(), Error> + Send + Sync + 'static;
pub type Help = Fn(&mut Context, &Message, HashMap<String, Arc<CommandGroup>>, Args)
                   -> Result<(), Error>
                    + Send
                    + Sync
                    + 'static;
pub type BeforeHook = Fn(&mut Context, &Message, &str) -> bool + Send + Sync + 'static;
pub type AfterHook = Fn(&mut Context, &Message, &str, Result<(), Error>) + Send + Sync + 'static;
pub(crate) type InternalCommand = Arc<Command>;
pub type PrefixCheck = Fn(&mut Context, &Message) -> Option<String> + Send + Sync + 'static;

pub enum CommandOrAlias {
    Alias(String),
    Command(InternalCommand),
}

/// An error from a command.
#[derive(Clone, Debug)]
pub struct Error(pub String);

// TODO: Have seperate `From<(&)String>` and `From<&str>` impls via specialization
impl<D: fmt::Display> From<D> for Error {
    fn from(d: D) -> Self {
        Error(format!("{}", d))
    }
}

/// Command function type. Allows to access internal framework things inside
/// your commands.
pub enum CommandType {
    StringResponse(String),
    Basic(Box<Exec>),
    WithCommands(Box<Help>),
}

pub struct CommandGroup {
    pub prefix: Option<String>,
    pub commands: HashMap<String, CommandOrAlias>,
    /// Some fields taken from Command
    pub bucket: Option<String>,
    pub required_permissions: Permissions,
    pub allowed_roles: Vec<String>,
    pub help_available: bool,
    pub dm_only: bool,
    pub guild_only: bool,
    pub owners_only: bool,
}

/// Command struct used to store commands internally.
pub struct Command {
    /// A set of checks to be called prior to executing the command. The checks
    /// will short-circuit on the first check that returns `false`.
    pub checks: Vec<Box<Check>>,
    /// Function called when the command is called.
    pub exec: CommandType,
    /// Ratelimit bucket.
    pub bucket: Option<String>,
    /// Command description, used by other commands.
    pub desc: Option<String>,
    /// Example arguments, used by other commands.
    pub example: Option<String>,
    /// Command usage schema, used by other commands.
    pub usage: Option<String>,
    /// Minumum amount of arguments that should be passed.
    pub min_args: Option<i32>,
    /// Maximum amount of arguments that can be passed.
    pub max_args: Option<i32>,
    /// Permissions required to use this command.
    pub required_permissions: Permissions,
    /// Roles allowed to use this command.
    pub allowed_roles: Vec<String>,
    /// Whether command should be displayed in help list or not, used by other commands.
    pub help_available: bool,
    /// Whether command can be used only privately or not.
    pub dm_only: bool,
    /// Whether command can be used only in guilds or not.
    pub guild_only: bool,
    /// Whether command can only be used by owners or not.
    pub owners_only: bool,
    pub(crate) aliases: Vec<String>,
}

impl Command {
    pub fn new<F>(f: F) -> Self
        where F: Fn(&mut Context, &Message, Args) -> Result<(), Error> + Send + Sync + 'static {
        Command {
            exec: CommandType::Basic(Box::new(f)),
            ..Command::default()
        }
    }
}

impl Default for Command {
    fn default() -> Command {
        Command {
            aliases: Vec::new(),
            checks: Vec::default(),
            exec: CommandType::Basic(Box::new(|_, _, _| Ok(()))),
            desc: None,
            usage: None,
            example: None,
            min_args: None,
            bucket: None,
            max_args: None,
            required_permissions: Permissions::empty(),
            dm_only: false,
            guild_only: false,
            help_available: true,
            owners_only: false,
            allowed_roles: Vec::new(),
        }
    }
}

pub fn positions(ctx: &mut Context, msg: &Message, conf: &Configuration) -> Option<Vec<usize>> {
    if !conf.prefixes.is_empty() || conf.dynamic_prefix.is_some() {
        // Find out if they were mentioned. If not, determine if the prefix
        // was used. If not, return None.
        let mut positions: Vec<usize> = vec![];

        if let Some(mention_end) = find_mention_end(&msg.content, conf) {
            positions.push(mention_end);
        } else if let Some(ref func) = conf.dynamic_prefix {
            if let Some(x) = func(ctx, msg) {
                if msg.content.starts_with(&x) {
                    positions.push(x.len());
                }
            } else {
                for n in &conf.prefixes {
                    if msg.content.starts_with(n) {
                        positions.push(n.len());
                    }
                }
            }
        } else {
            for n in &conf.prefixes {
                if msg.content.starts_with(n) {
                    positions.push(n.len());
                }
            }
        };

        if positions.is_empty() {
            return None;
        }

        if conf.allow_whitespace {
            let pos = *unsafe { positions.get_unchecked(0) };

            positions.insert(0, pos + 1);
        }

        Some(positions)
    } else if conf.on_mention.is_some() {
        find_mention_end(&msg.content, conf).map(|mention_end| {
            let mut positions = vec![mention_end];

            if conf.allow_whitespace {
                positions.insert(0, mention_end + 1);
            }

            positions
        })
    } else {
        None
    }
}

fn find_mention_end(content: &str, conf: &Configuration) -> Option<usize> {
    conf.on_mention.as_ref().and_then(|mentions| {
        mentions
            .iter()
            .find(|mention| content.starts_with(&mention[..]))
            .map(|m| m.len())
    })
}
<|endoftext|>


<commit_before>extern crate random;
extern crate tensorflow;

use std::error::Error;
use std::result::Result;
use std::process::exit;
use tensorflow::Code;
// Workaround for https://github.com/rust-lang/cargo/issues/1570
#[cfg(feature = "tensorflow_unstable")]
use tensorflow::expr::{Compiler, Placeholder};
use tensorflow::Graph;
use tensorflow::Session;
use tensorflow::SessionOptions;
use tensorflow::Status;
use tensorflow::StepWithGraph;
use tensorflow::Tensor;

fn main() {
    // Putting the main code in another function serves two purposes:
    // 1. We can use the try! macro.
    // 2. We can call exit safely, which does not run any destructors.
    exit(match run() {
        Ok(_) => 0,
        Err(e) => {
            println!("{}", e);
            1
        }
    })
}

struct Checker {
    success: bool,
    epsilon: f32,
}

impl Checker {
    fn new(epsilon: f32) -> Self {
        Checker {
            success: true,
            epsilon: epsilon,
        }
    }

    fn check(&mut self, name: &str, expected: f32, actual: f32) {
        let success = (expected - actual).abs() < self.epsilon;
        println!("Checking {}: expected {}, got {}. {}",
                 name,
                 expected,
                 actual,
                 if success { "Success!" } else { "FAIL" });
        self.success &= success;
    }

    fn result(&self) -> Result<(), Box<Error>> {
        if self.success {
            Ok(())
        } else {
            Err(Box::new(try!(Status::new_set(Code::Internal, "At least one check failed"))))
        }
    }
}

// Workaround for https://github.com/rust-lang/cargo/issues/1570
#[cfg(not(feature = "tensorflow_unstable"))]
fn run() -> Result<(), Box<Error>> {
    println!("examples/expressions.rs is disabled because the `tensorflow_unstable feature is \
              not enabled!`");
    Ok(())
}

// Workaround for https://github.com/rust-lang/cargo/issues/1570
#[cfg(feature = "tensorflow_unstable")]
fn run() -> Result<(), Box<Error>> {
    // Build the graph
    let mut g = Graph::new();
    let y_node = {
        let mut compiler = Compiler::new(&mut g);
        let x_expr = <Placeholder<f32>>::new_expr(&vec![2], "x");
        try!(compiler.compile(x_expr * 2.0f32 + 1.0f32))
    };
    let x_node = try!(g.operation_by_name_required("x"));
    // This is another valid way to get x_node and y_node:
    // let (x_node, y_node) = {
    //   let mut compiler = Compiler::new(&mut g);
    //   let x_expr = <Placeholder<f32>>::new_expr(&vec![2], "x");
    //   let x_node = try!(compiler.compile(x_expr.clone()));
    //   let y_node = try!(compiler.compile(x_expr * 2.0f32 + 1.0f32));
    //   (x_node, y_node)
    // };
    let options = SessionOptions::new();
    let mut session = try!(Session::new(&options, &g));

    // Evaluate the graph.
    let mut x = <Tensor<f32>>::new(&[2]);
    x[0] = 2.0;
    x[1] = 3.0;
    let mut step = StepWithGraph::new();
    step.add_input(&x_node, 0, &x);
    let output_token = step.request_output(&y_node, 0);
    session.run(&mut step).unwrap();

    // Check our results.
    let output_tensor = try!(step.take_output::<f32>(output_token));
    let data = output_tensor.data();
    let mut checker = Checker::new(1e-3);
    checker.check("data[0]", 5.0, data[0]);
    checker.check("data[1]", 7.0, data[1]);
    checker.result()
}
<commit_msg>Fix backtick placement in examples/expressions.rs<commit_after>extern crate random;
extern crate tensorflow;

use std::error::Error;
use std::result::Result;
use std::process::exit;
use tensorflow::Code;
// Workaround for https://github.com/rust-lang/cargo/issues/1570
#[cfg(feature = "tensorflow_unstable")]
use tensorflow::expr::{Compiler, Placeholder};
use tensorflow::Graph;
use tensorflow::Session;
use tensorflow::SessionOptions;
use tensorflow::Status;
use tensorflow::StepWithGraph;
use tensorflow::Tensor;

fn main() {
    // Putting the main code in another function serves two purposes:
    // 1. We can use the try! macro.
    // 2. We can call exit safely, which does not run any destructors.
    exit(match run() {
        Ok(_) => 0,
        Err(e) => {
            println!("{}", e);
            1
        }
    })
}

struct Checker {
    success: bool,
    epsilon: f32,
}

impl Checker {
    fn new(epsilon: f32) -> Self {
        Checker {
            success: true,
            epsilon: epsilon,
        }
    }

    fn check(&mut self, name: &str, expected: f32, actual: f32) {
        let success = (expected - actual).abs() < self.epsilon;
        println!("Checking {}: expected {}, got {}. {}",
                 name,
                 expected,
                 actual,
                 if success { "Success!" } else { "FAIL" });
        self.success &= success;
    }

    fn result(&self) -> Result<(), Box<Error>> {
        if self.success {
            Ok(())
        } else {
            Err(Box::new(try!(Status::new_set(Code::Internal, "At least one check failed"))))
        }
    }
}

// Workaround for https://github.com/rust-lang/cargo/issues/1570
#[cfg(not(feature = "tensorflow_unstable"))]
fn run() -> Result<(), Box<Error>> {
    println!("examples/expressions.rs is disabled because the `tensorflow_unstable` feature is \
              not enabled!");
    Ok(())
}

// Workaround for https://github.com/rust-lang/cargo/issues/1570
#[cfg(feature = "tensorflow_unstable")]
fn run() -> Result<(), Box<Error>> {
    // Build the graph
    let mut g = Graph::new();
    let y_node = {
        let mut compiler = Compiler::new(&mut g);
        let x_expr = <Placeholder<f32>>::new_expr(&vec![2], "x");
        try!(compiler.compile(x_expr * 2.0f32 + 1.0f32))
    };
    let x_node = try!(g.operation_by_name_required("x"));
    // This is another valid way to get x_node and y_node:
    // let (x_node, y_node) = {
    //   let mut compiler = Compiler::new(&mut g);
    //   let x_expr = <Placeholder<f32>>::new_expr(&vec![2], "x");
    //   let x_node = try!(compiler.compile(x_expr.clone()));
    //   let y_node = try!(compiler.compile(x_expr * 2.0f32 + 1.0f32));
    //   (x_node, y_node)
    // };
    let options = SessionOptions::new();
    let mut session = try!(Session::new(&options, &g));

    // Evaluate the graph.
    let mut x = <Tensor<f32>>::new(&[2]);
    x[0] = 2.0;
    x[1] = 3.0;
    let mut step = StepWithGraph::new();
    step.add_input(&x_node, 0, &x);
    let output_token = step.request_output(&y_node, 0);
    session.run(&mut step).unwrap();

    // Check our results.
    let output_tensor = try!(step.take_output::<f32>(output_token));
    let data = output_tensor.data();
    let mut checker = Checker::new(1e-3);
    checker.check("data[0]", 5.0, data[0]);
    checker.check("data[1]", 7.0, data[1]);
    checker.result()
}
<|endoftext|>