<commit_before>use crate::core::{Info, Method, Options, Query};
use crate::scripts::{
    grouping::{MultiLangScript, ScriptLangGroup},
    raw_detect_script, RawScriptInfo, Script,
};
use crate::Lang;
use crate::{alphabets, combined, trigrams};

/// Detect only a language by a given text.
///
/// # Example
/// ```
/// use whatlang::{detect_lang, Lang};
/// let lang = detect_lang("There is no reason not to learn Esperanto.").unwrap();
/// assert_eq!(lang, Lang::Eng);
/// ```
pub fn detect_lang(text: &str) -> Option<Lang> {
    detect(text).map(|output| output.lang())
}

/// Detect a language and a script by a given text.
///
/// # Example
/// ```
/// use whatlang::{detect_lang, Lang};
/// let lang = detect_lang("There is no reason not to learn Esperanto.").unwrap();
/// assert_eq!(lang, Lang::Eng);
/// ```
pub fn detect(text: &str) -> Option<Info> {
    let opts = Options::default();
    detect_with_options(text, &opts)
}

pub fn detect_with_options(text: &str, options: &Options) -> Option<Info> {
    let query = Query {
        text,
        filter_list: &options.filter_list,
        method: options.method,
    };
    detect_by_query(&query)
}

pub fn detect_by_query(query: &Query) -> Option<Info> {
    let raw_script_info = raw_detect_script(query.text);
    let script = raw_script_info.main_script()?;

    match script.to_lang_group() {
        ScriptLangGroup::One(lang) => Some(Info::new(script, lang, 1.0)),
        ScriptLangGroup::Multi(multi_lang_script) => {
            detect_by_query_based_on_script(query, multi_lang_script)
        }
        ScriptLangGroup::Mandarin => {
            Some(detect_lang_base_on_mandarin_script(query, &raw_script_info))
        }
    }
}

fn detect_by_query_based_on_script(
    query: &Query,
    multi_lang_script: MultiLangScript,
) -> Option<Info> {
    let iquery = query.to_internal(multi_lang_script);
    match query.method {
        Method::Alphabet => alphabets::detect(&iquery),
        Method::Trigram => trigrams::detect(&iquery),
        Method::Combined => combined::detect(&iquery),
    }
}

// Sometimes Mandarin can be Japanese.
// See https://github.com/greyblake/whatlang-rs/pull/45
pub(crate) fn detect_lang_base_on_mandarin_script(
    query: &Query,
    raw_script_info: &RawScriptInfo,
) -> Info {
    let (lang, confidence) = if query.filter_list.is_allowed(Lang::Cmn) {
        let mandrin_count = raw_script_info.count(Script::Mandarin);
        let katakana_count = raw_script_info.count(Script::Katakana);
        let hiragana_count = raw_script_info.count(Script::Hiragana);
        let japanese_count = katakana_count + hiragana_count;
        let total = mandrin_count + hiragana_count;

        let jpn_pct = japanese_count as f64 / total as f64;

        // If at least 5% of characters are Japanese(Katakana or Hiragana) then it's likely to be Japanese language
        // See https://github.com/greyblake/whatlang-rs/issues/88
        if jpn_pct > 0.2 {
            (Lang::Jpn, 1.0)
        } else if jpn_pct > 0.05 {
            (Lang::Jpn, 0.5)
        } else if jpn_pct > 0.02 {
            (Lang::Cmn, 0.5)
        } else {
            (Lang::Cmn, 1.0)
        }
    } else {
        (Lang::Jpn, 1.0)
    };
    Info::new(Script::Mandarin, lang, confidence)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::FilterList;
    use crate::scripts::Script;

    #[test]
    fn test_detect_spanish() {
        let text = "Además de todo lo anteriormente dicho, también encontramos...";
        let output = detect(text);
        assert_eq!(output.is_some(), true);

        let info = output.unwrap();
        assert_eq!(info.lang(), Lang::Spa);
        assert_eq!(info.script(), Script::Latin);
    }

    #[test]
    fn test_detect_lang_ukrainian() {
        let text = "Та нічого, все нормально. А в тебе як?";
        assert_eq!(detect_lang(text), Some(Lang::Ukr));
    }

    #[test]
    fn test_detect_with_options_with_filter_list_except() {
        let text = "I am begging pardon";

        // without filter list
        let output = detect_with_options(text, &Options::default());
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang(), Lang::Jav);

        // with filter list
        let filter_list =
            FilterList::deny(vec![Lang::Jav, Lang::Nld, Lang::Uzb, Lang::Swe, Lang::Nob]);
        let options = Options::new().set_filter_list(filter_list);
        let output = detect_with_options(text, &options);
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang(), Lang::Eng);
    }

    // TODO:  see https://github.com/greyblake/whatlang-rs/issues/78
    #[test]
    fn test_detect_with_options_with_filter_list_except_none() {
        {
            // All languages with Hebrew script are filtered out, so result must be None
            let text = "האקדמיה ללשון העברית";
            let filter_list = FilterList::deny(vec![Lang::Heb, Lang::Yid]);
            let options = Options::new().set_filter_list(filter_list);
            let output = detect_with_options(text, &options);
            assert_eq!(output, None);
        }

        {
            // All Cyrillic languages are filtered out
            let text = "Мы хотим видеть дальше, чем окна дома напротив";
            let filter_list = FilterList::deny(Script::Cyrillic.langs().to_owned());
            let options = Options::new().set_filter_list(filter_list);
            let output = detect_with_options(text, &options);
            assert_eq!(output, None);
        }

        {
            // All Latin languages are filtered out
            let text = "Mit dem Wissen wächst der Zweifel";
            let filter_list = FilterList::deny(Script::Latin.langs().to_owned());
            let options = Options::new().set_filter_list(filter_list);
            let output = detect_with_options(text, &options);
            assert_eq!(output, None);
        }
    }

    #[test]
    fn test_detect_with_options_with_filter_list_only() {
        let filter_list = FilterList::allow(vec![Lang::Epo, Lang::Ukr]);
        let options = Options::new().set_filter_list(filter_list);

        let text = "Mi ne scias!";
        let output = detect_with_options(text, &options);
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang(), Lang::Epo);
    }

    #[test]
    fn test_detect_with_options_with_allowlist_mandarin_japanese() {
        let text = "水";

        let jpn_opts = Options::new().set_filter_list(FilterList::allow(vec![Lang::Jpn]));
        let info = detect_with_options(text, &jpn_opts).unwrap();
        assert_eq!(info.lang(), Lang::Jpn);

        let cmn_opts = Options::new().set_filter_list(FilterList::allow(vec![Lang::Cmn]));
        let info = detect_with_options(text, &cmn_opts).unwrap();
        assert_eq!(info.lang(), Lang::Cmn);
    }

    #[test]
    fn test_detect_with_options_with_blacklist_mandarin_japanese() {
        let text = "水";

        let jpn_opts = Options::new().set_filter_list(FilterList::deny(vec![Lang::Jpn]));
        let info = detect_with_options(text, &jpn_opts).unwrap();
        assert_eq!(info.lang(), Lang::Cmn);

        let cmn_opts = Options::new().set_filter_list(FilterList::deny(vec![Lang::Cmn]));
        let info = detect_with_options(text, &cmn_opts).unwrap();
        assert_eq!(info.lang(), Lang::Jpn);
    }
}
<commit_msg>tweaked test as Tgl is now detected instead of Jav<commit_after>use crate::core::{Info, Method, Options, Query};
use crate::scripts::{
    grouping::{MultiLangScript, ScriptLangGroup},
    raw_detect_script, RawScriptInfo, Script,
};
use crate::Lang;
use crate::{alphabets, combined, trigrams};

/// Detect only a language by a given text.
///
/// # Example
/// ```
/// use whatlang::{detect_lang, Lang};
/// let lang = detect_lang("There is no reason not to learn Esperanto.").unwrap();
/// assert_eq!(lang, Lang::Eng);
/// ```
pub fn detect_lang(text: &str) -> Option<Lang> {
    detect(text).map(|output| output.lang())
}

/// Detect a language and a script by a given text.
///
/// # Example
/// ```
/// use whatlang::{detect_lang, Lang};
/// let lang = detect_lang("There is no reason not to learn Esperanto.").unwrap();
/// assert_eq!(lang, Lang::Eng);
/// ```
pub fn detect(text: &str) -> Option<Info> {
    let opts = Options::default();
    detect_with_options(text, &opts)
}

pub fn detect_with_options(text: &str, options: &Options) -> Option<Info> {
    let query = Query {
        text,
        filter_list: &options.filter_list,
        method: options.method,
    };
    detect_by_query(&query)
}

pub fn detect_by_query(query: &Query) -> Option<Info> {
    let raw_script_info = raw_detect_script(query.text);
    let script = raw_script_info.main_script()?;

    match script.to_lang_group() {
        ScriptLangGroup::One(lang) => Some(Info::new(script, lang, 1.0)),
        ScriptLangGroup::Multi(multi_lang_script) => {
            detect_by_query_based_on_script(query, multi_lang_script)
        }
        ScriptLangGroup::Mandarin => {
            Some(detect_lang_base_on_mandarin_script(query, &raw_script_info))
        }
    }
}

fn detect_by_query_based_on_script(
    query: &Query,
    multi_lang_script: MultiLangScript,
) -> Option<Info> {
    let iquery = query.to_internal(multi_lang_script);
    match query.method {
        Method::Alphabet => alphabets::detect(&iquery),
        Method::Trigram => trigrams::detect(&iquery),
        Method::Combined => combined::detect(&iquery),
    }
}

// Sometimes Mandarin can be Japanese.
// See https://github.com/greyblake/whatlang-rs/pull/45
pub(crate) fn detect_lang_base_on_mandarin_script(
    query: &Query,
    raw_script_info: &RawScriptInfo,
) -> Info {
    let (lang, confidence) = if query.filter_list.is_allowed(Lang::Cmn) {
        let mandrin_count = raw_script_info.count(Script::Mandarin);
        let katakana_count = raw_script_info.count(Script::Katakana);
        let hiragana_count = raw_script_info.count(Script::Hiragana);
        let japanese_count = katakana_count + hiragana_count;
        let total = mandrin_count + hiragana_count;

        let jpn_pct = japanese_count as f64 / total as f64;

        // If at least 5% of characters are Japanese(Katakana or Hiragana) then it's likely to be Japanese language
        // See https://github.com/greyblake/whatlang-rs/issues/88
        if jpn_pct > 0.2 {
            (Lang::Jpn, 1.0)
        } else if jpn_pct > 0.05 {
            (Lang::Jpn, 0.5)
        } else if jpn_pct > 0.02 {
            (Lang::Cmn, 0.5)
        } else {
            (Lang::Cmn, 1.0)
        }
    } else {
        (Lang::Jpn, 1.0)
    };
    Info::new(Script::Mandarin, lang, confidence)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::FilterList;
    use crate::scripts::Script;

    #[test]
    fn test_detect_spanish() {
        let text = "Además de todo lo anteriormente dicho, también encontramos...";
        let output = detect(text);
        assert_eq!(output.is_some(), true);

        let info = output.unwrap();
        assert_eq!(info.lang(), Lang::Spa);
        assert_eq!(info.script(), Script::Latin);
    }

    #[test]
    fn test_detect_lang_ukrainian() {
        let text = "Та нічого, все нормально. А в тебе як?";
        assert_eq!(detect_lang(text), Some(Lang::Ukr));
    }

    #[test]
    fn test_detect_with_options_with_filter_list_except() {
        let text = "I am begging pardon";

        // without filter list
        let output = detect_with_options(text, &Options::default());
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang(), Lang::Tgl);

        // with filter list
        let filter_list = FilterList::deny(vec![
            Lang::Jav,
            Lang::Nld,
            Lang::Uzb,
            Lang::Swe,
            Lang::Nob,
            Lang::Tgl,
        ]);
        let options = Options::new().set_filter_list(filter_list);
        let output = detect_with_options(text, &options);
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang(), Lang::Eng);
    }

    // TODO:  see https://github.com/greyblake/whatlang-rs/issues/78
    #[test]
    fn test_detect_with_options_with_filter_list_except_none() {
        {
            // All languages with Hebrew script are filtered out, so result must be None
            let text = "האקדמיה ללשון העברית";
            let filter_list = FilterList::deny(vec![Lang::Heb, Lang::Yid]);
            let options = Options::new().set_filter_list(filter_list);
            let output = detect_with_options(text, &options);
            assert_eq!(output, None);
        }

        {
            // All Cyrillic languages are filtered out
            let text = "Мы хотим видеть дальше, чем окна дома напротив";
            let filter_list = FilterList::deny(Script::Cyrillic.langs().to_owned());
            let options = Options::new().set_filter_list(filter_list);
            let output = detect_with_options(text, &options);
            assert_eq!(output, None);
        }

        {
            // All Latin languages are filtered out
            let text = "Mit dem Wissen wächst der Zweifel";
            let filter_list = FilterList::deny(Script::Latin.langs().to_owned());
            let options = Options::new().set_filter_list(filter_list);
            let output = detect_with_options(text, &options);
            assert_eq!(output, None);
        }
    }

    #[test]
    fn test_detect_with_options_with_filter_list_only() {
        let filter_list = FilterList::allow(vec![Lang::Epo, Lang::Ukr]);
        let options = Options::new().set_filter_list(filter_list);

        let text = "Mi ne scias!";
        let output = detect_with_options(text, &options);
        assert_eq!(output.is_some(), true);
        let info = output.unwrap();
        assert_eq!(info.lang(), Lang::Epo);
    }

    #[test]
    fn test_detect_with_options_with_allowlist_mandarin_japanese() {
        let text = "水";

        let jpn_opts = Options::new().set_filter_list(FilterList::allow(vec![Lang::Jpn]));
        let info = detect_with_options(text, &jpn_opts).unwrap();
        assert_eq!(info.lang(), Lang::Jpn);

        let cmn_opts = Options::new().set_filter_list(FilterList::allow(vec![Lang::Cmn]));
        let info = detect_with_options(text, &cmn_opts).unwrap();
        assert_eq!(info.lang(), Lang::Cmn);
    }

    #[test]
    fn test_detect_with_options_with_blacklist_mandarin_japanese() {
        let text = "水";

        let jpn_opts = Options::new().set_filter_list(FilterList::deny(vec![Lang::Jpn]));
        let info = detect_with_options(text, &jpn_opts).unwrap();
        assert_eq!(info.lang(), Lang::Cmn);

        let cmn_opts = Options::new().set_filter_list(FilterList::deny(vec![Lang::Cmn]));
        let info = detect_with_options(text, &cmn_opts).unwrap();
        assert_eq!(info.lang(), Lang::Jpn);
    }
}
<|endoftext|>


<commit_before>// MIT License
//
// Copyright (c) 2020 Ben
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// © 2020 GitHub, Inc.
// Terms
// https://github.com/tempor1s/bktree-rs
use std::char;
use std::cmp::min;
use std::collections::{HashMap, HashSet};

/// BKTree structure that is used to store word like structures
/// and perform "fuzzy" search on them to implement "do you mean"
/// functionality on them. Can perform said search on any term that implements
/// the distance trait. The default implementation is Osa distance.
#[derive(Default)]
pub struct BKTree<K, V>
where
    K: Distance,
{
    root: Option<BKTreeNode<K, V>>,
}

impl<K, V> BKTree<K, V>
where
    K: Distance,
{
    /// Create a new BK Tree with an empty root.
    pub fn new() -> BKTree<K, V> {
        BKTree { root: None }
    }

    /// Create a new tree from the items in a Vector.
    /// Useful for inserting a lot of items from a file etc.
    /// Vector requires a Vec of tuples of K, V pairs where K implements Distance trait
    pub fn new_from_vec(items: Vec<(K, V)>) -> BKTree<K, V> {
        let mut tree = BKTree { root: None };

        for item in items {
            tree.insert(item.0, item.1);
        }

        return tree;
    }

    /// Add a new (key, value) pair into the BKTree.
    pub fn insert(&mut self, key: K, value: V) {
        // If the root exists, insert from there.
        if let Some(root) = &mut self.root {
            root.insert(key, value);
        } else {
            // otherwise, set the root to be a new BKTreeNode
            self.root = Some(BKTreeNode::new(key, value));
        }
    }

    /// Search for the closest Item to the key with a given tolerence. (Steps to get there)
    /// The return value is a tuple of 2 Vecs, where the first one has exact matches and the second
    /// are matches within the given tolerence.
    ///
    /// A match is approximate if the distance between key1 and key2 are less than the given tolerence.
    pub fn find(&self, key: &K, tolerence: usize) -> (Vec<&V>, Vec<&K>) {
        // if our root exists, search from the root
        return if let Some(root) = &self.root {
            root.find(&key, tolerence)
        } else {
            // if we can not find anything, return a tuple of empty vectors
            (vec![], vec![])
        };
    }
}

#[derive(Debug)]
struct BKTreeNode<K, V>
where
    K: Distance,
{
    key: K,
    value: V,
    children: HashMap<usize, BKTreeNode<K, V>>,
}

impl<K, V> BKTreeNode<K, V>
where
    K: Distance,
{
    /// Create a new BK Tree Node with the given (K, V) pair and empty HashMap of children
    fn new(key: K, value: V) -> Self {
        BKTreeNode {
            key,
            value,
            children: HashMap::new(),
        }
    }

    /// Insert a new (key, value) pair into this nodes children
    fn insert(&mut self, key: K, value: V) {
        // Get the distance between the current nodes key and the given key
        let distance = self.key.distance(&key);
        // If the child exists, traverse and insert from there.
        if let Some(child) = self.children.get_mut(&distance) {
            child.insert(key, value);
        } else {
            // otherwise, insert the current node into the children and with the given distance
            self.children.insert(distance, BKTreeNode::new(key, value));
        }
    }

    /// Find a key in the given childrens nodes
    fn find(&self, key: &K, leniency: usize) -> (Vec<&V>, Vec<&K>) {
        // Create a new tuple of empty vectors for exact and close matches
        let (mut exact, mut close) = (vec![], vec![]);
        // Get the distance between the current nodes key and then passed in key.
        let current_distance = self.key.distance(&key);
        // If the current distance is 0, it means its an exact match so push it to our "exact" matches
        if current_distance == 0 {
            exact.push(&self.value);
        // Otherwise, if the value is less than our leniency then add it to the close matches
        } else if current_distance <= leniency {
            close.push(&self.key);
        }

        // Saturing just means that the values will not overflow
        for i in
            current_distance.saturating_sub(leniency)..=current_distance.saturating_add(leniency)
        {
            // Because of how the tree works, we can traverse based off the leniency
            if let Some(child) = self.children.get(&i) {
                let mut result = child.find(key, leniency);
                exact.append(&mut result.0);
                close.append(&mut result.1);
            }
        }
        // return our vector of close and exact values
        return (exact, close);
    }
}

/// This trait is used by the BKTree to determine the distance between 2 objects
/// when fuzzy searching. An example of this for strings is the Levenshtein distance,
/// Damerau-Levenshtein distance, Optimal string alignment distance, or a custom implementation.
pub trait Distance {
    /// Used to determine the "distance" between two objects.
    fn distance(&self, other: &Self) -> usize;
}

// We want to implement distance for String, and OSA is a good way to do so.
// This allows us to create a BKTree using Strings
impl Distance for String {
    fn distance(&self, other: &Self) -> usize {
        osa_distance(self, other)
    }
}

impl Distance for &str {
    fn distance(&self, other: &Self) -> usize {
        osa_distance(self, other)
    }
}

// Manual implementation of this function. Did not want to include a seperate library.
// https://docs.rs/strsim/0.9.2/src/strsim/lib.rs.html#263-307
fn osa_distance(a: &str, b: &str) -> usize {
    let a_len = a.chars().count();
    let b_len = b.chars().count();

    if a == b {
        return 0;
    } else if a_len == 0 {
        return b_len;
    } else if b_len == 0 {
        return a_len;
    }

    let mut prev_two_distances = Vec::with_capacity(b_len + 1);
    let mut prev_distances = Vec::with_capacity(b_len + 1);
    let mut current_distances = Vec::with_capacity(b_len + 1);

    let mut prev_a_char = char::MAX;
    let mut prev_b_char = char::MAX;

    for i in 0..(b_len + 1) {
        prev_two_distances.push(i);
        prev_distances.push(i);
        current_distances.push(0);
    }

    for (i, a_char) in a.chars().enumerate() {
        current_distances[0] = i + 1;

        for (j, b_char) in b.chars().enumerate() {
            let cost = if a_char == b_char { 0 } else { 1 };
            current_distances[j + 1] = min(
                current_distances[j] + 1,
                min(prev_distances[j + 1] + 1, prev_distances[j] + cost),
            );

            if i > 0 && j > 0 && a_char != b_char && a_char == prev_b_char && b_char == prev_a_char
            {
                current_distances[j + 1] =
                    min(current_distances[j + 1], prev_two_distances[j - 1] + 1);
            }

            prev_b_char = b_char;
        }

        prev_two_distances.clone_from(&prev_distances);
        prev_distances.clone_from(&current_distances);
        prev_a_char = a_char;
    }

    current_distances[b_len]
}

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

    static TEST_DATA: [(&'static str, &'static str); 7] = [
        ("AMERICAN SCRAP PROCESSING INC", "SCRAP PROCESSING INC"), // 0
        ("ACP ACQUISITION CORP", "CP ACQUISITION CORP"),           // 1
        ("ADAMANT TECHNOLOGIES", "NT TECHNOLOGIES, INC."),         // 2
        ("zehn", "fünfzehn"),                                     // 3
        (
            // 4
            "Genesis - The Carpet Crawlers",
            "Genesys - The carpett craulers",
        ),
        (
            // 5
            "Genesis - (The Lamb Lies Down on Broadway) The Carpet Crawlers",
            "Genesys - (The Lamb Lies Down on Broadway) The Chamber of 32 Doors",
        ),
        (
            // 6
            "Genesis - (The Lamb Lies Down on Broadway) The Lamia",
            "Genesis - The Lamia",
        ),
    ];

    #[test]
    fn osa_1() {
        assert_eq!(0, osa_distance(TEST_DATA[0].0, TEST_DATA[0].0));
        assert_eq!(9, osa_distance(TEST_DATA[0].0, TEST_DATA[0].1));
        assert_eq!(1, osa_distance(TEST_DATA[1].0, TEST_DATA[1].1));
        assert_eq!(11, osa_distance(TEST_DATA[2].0, TEST_DATA[2].1));
        assert_eq!(4, osa_distance(TEST_DATA[3].0, TEST_DATA[3].1));
        assert_eq!(5, osa_distance(TEST_DATA[4].0, TEST_DATA[4].1));
        assert_eq!(14, osa_distance(TEST_DATA[5].0, TEST_DATA[5].1));
        assert_eq!(33, osa_distance(TEST_DATA[6].0, TEST_DATA[6].1));
    }
}
<commit_msg>[collection] after try this was not corrected<commit_after>// MIT License
//
// Copyright (c) 2020 Ben
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// © 2020 GitHub, Inc.
// Terms
// https://github.com/tempor1s/bktree-rs
use std::char;
use std::cmp::min;
use std::collections::HashMap;

/// BKTree structure that is used to store word like structures
/// and perform "fuzzy" search on them to implement "do you mean"
/// functionality on them. Can perform said search on any term that implements
/// the distance trait. The default implementation is Osa distance.
#[derive(Default)]
pub struct BKTree<K, V>
where
    K: Distance,
{
    root: Option<BKTreeNode<K, V>>,
}

impl<K, V> BKTree<K, V>
where
    K: Distance,
{
    /// Create a new BK Tree with an empty root.
    pub fn new() -> BKTree<K, V> {
        BKTree { root: None }
    }

    /// Create a new tree from the items in a Vector.
    /// Useful for inserting a lot of items from a file etc.
    /// Vector requires a Vec of tuples of K, V pairs where K implements Distance trait
    pub fn new_from_vec(items: Vec<(K, V)>) -> BKTree<K, V> {
        let mut tree = BKTree { root: None };

        for item in items {
            tree.insert(item.0, item.1);
        }

        return tree;
    }

    /// Add a new (key, value) pair into the BKTree.
    pub fn insert(&mut self, key: K, value: V) {
        // If the root exists, insert from there.
        if let Some(root) = &mut self.root {
            root.insert(key, value);
        } else {
            // otherwise, set the root to be a new BKTreeNode
            self.root = Some(BKTreeNode::new(key, value));
        }
    }

    /// Search for the closest Item to the key with a given tolerence. (Steps to get there)
    /// The return value is a tuple of 2 Vecs, where the first one has exact matches and the second
    /// are matches within the given tolerence.
    ///
    /// A match is approximate if the distance between key1 and key2 are less than the given tolerence.
    pub fn find(&self, key: &K, tolerence: usize) -> (Vec<&V>, Vec<&K>) {
        // if our root exists, search from the root
        return if let Some(root) = &self.root {
            root.find(&key, tolerence)
        } else {
            // if we can not find anything, return a tuple of empty vectors
            (vec![], vec![])
        };
    }
}

#[derive(Debug)]
struct BKTreeNode<K, V>
where
    K: Distance,
{
    key: K,
    value: V,
    children: HashMap<usize, BKTreeNode<K, V>>,
}

impl<K, V> BKTreeNode<K, V>
where
    K: Distance,
{
    /// Create a new BK Tree Node with the given (K, V) pair and empty HashMap of children
    fn new(key: K, value: V) -> Self {
        BKTreeNode {
            key,
            value,
            children: HashMap::new(),
        }
    }

    /// Insert a new (key, value) pair into this nodes children
    fn insert(&mut self, key: K, value: V) {
        // Get the distance between the current nodes key and the given key
        let distance = self.key.distance(&key);
        // If the child exists, traverse and insert from there.
        if let Some(child) = self.children.get_mut(&distance) {
            child.insert(key, value);
        } else {
            // otherwise, insert the current node into the children and with the given distance
            self.children.insert(distance, BKTreeNode::new(key, value));
        }
    }

    /// Find a key in the given childrens nodes
    fn find(&self, key: &K, leniency: usize) -> (Vec<&V>, Vec<&K>) {
        // Create a new tuple of empty vectors for exact and close matches
        let (mut exact, mut close) = (vec![], vec![]);
        // Get the distance between the current nodes key and then passed in key.
        let current_distance = self.key.distance(&key);
        // If the current distance is 0, it means its an exact match so push it to our "exact" matches
        if current_distance == 0 {
            exact.push(&self.value);
        // Otherwise, if the value is less than our leniency then add it to the close matches
        } else if current_distance <= leniency {
            close.push(&self.key);
        }

        // Saturing just means that the values will not overflow
        for i in
            current_distance.saturating_sub(leniency)..=current_distance.saturating_add(leniency)
        {
            // Because of how the tree works, we can traverse based off the leniency
            if let Some(child) = self.children.get(&i) {
                let mut result = child.find(key, leniency);
                exact.append(&mut result.0);
                close.append(&mut result.1);
            }
        }
        // return our vector of close and exact values
        return (exact, close);
    }
}

/// This trait is used by the BKTree to determine the distance between 2 objects
/// when fuzzy searching. An example of this for strings is the Levenshtein distance,
/// Damerau-Levenshtein distance, Optimal string alignment distance, or a custom implementation.
pub trait Distance {
    /// Used to determine the "distance" between two objects.
    fn distance(&self, other: &Self) -> usize;
}

// We want to implement distance for String, and OSA is a good way to do so.
// This allows us to create a BKTree using Strings
impl Distance for String {
    fn distance(&self, other: &Self) -> usize {
        osa_distance(self, other)
    }
}

impl Distance for &str {
    fn distance(&self, other: &Self) -> usize {
        osa_distance(self, other)
    }
}

// Manual implementation of this function. Did not want to include a seperate library.
// https://docs.rs/strsim/0.9.2/src/strsim/lib.rs.html#263-307
fn osa_distance(a: &str, b: &str) -> usize {
    let a_len = a.chars().count();
    let b_len = b.chars().count();

    if a == b {
        return 0;
    } else if a_len == 0 {
        return b_len;
    } else if b_len == 0 {
        return a_len;
    }

    let mut prev_two_distances = Vec::with_capacity(b_len + 1);
    let mut prev_distances = Vec::with_capacity(b_len + 1);
    let mut current_distances = Vec::with_capacity(b_len + 1);

    let mut prev_a_char = char::MAX;
    let mut prev_b_char = char::MAX;

    for i in 0..(b_len + 1) {
        prev_two_distances.push(i);
        prev_distances.push(i);
        current_distances.push(0);
    }

    for (i, a_char) in a.chars().enumerate() {
        current_distances[0] = i + 1;

        for (j, b_char) in b.chars().enumerate() {
            let cost = if a_char == b_char { 0 } else { 1 };
            current_distances[j + 1] = min(
                current_distances[j] + 1,
                min(prev_distances[j + 1] + 1, prev_distances[j] + cost),
            );

            if i > 0 && j > 0 && a_char != b_char && a_char == prev_b_char && b_char == prev_a_char
            {
                current_distances[j + 1] =
                    min(current_distances[j + 1], prev_two_distances[j - 1] + 1);
            }

            prev_b_char = b_char;
        }

        prev_two_distances.clone_from(&prev_distances);
        prev_distances.clone_from(&current_distances);
        prev_a_char = a_char;
    }

    current_distances[b_len]
}

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

    static TEST_DATA: [(&'static str, &'static str); 7] = [
        ("AMERICAN SCRAP PROCESSING INC", "SCRAP PROCESSING INC"), // 0
        ("ACP ACQUISITION CORP", "CP ACQUISITION CORP"),           // 1
        ("ADAMANT TECHNOLOGIES", "NT TECHNOLOGIES, INC."),         // 2
        ("zehn", "fünfzehn"),                                     // 3
        (
            // 4
            "Genesis - The Carpet Crawlers",
            "Genesys - The carpett craulers",
        ),
        (
            // 5
            "Genesis - (The Lamb Lies Down on Broadway) The Carpet Crawlers",
            "Genesys - (The Lamb Lies Down on Broadway) The Chamber of 32 Doors",
        ),
        (
            // 6
            "Genesis - (The Lamb Lies Down on Broadway) The Lamia",
            "Genesis - The Lamia",
        ),
    ];

    #[test]
    fn osa_1() {
        assert_eq!(0, osa_distance(TEST_DATA[0].0, TEST_DATA[0].0));
        assert_eq!(9, osa_distance(TEST_DATA[0].0, TEST_DATA[0].1));
        assert_eq!(1, osa_distance(TEST_DATA[1].0, TEST_DATA[1].1));
        assert_eq!(11, osa_distance(TEST_DATA[2].0, TEST_DATA[2].1));
        assert_eq!(4, osa_distance(TEST_DATA[3].0, TEST_DATA[3].1));
        assert_eq!(5, osa_distance(TEST_DATA[4].0, TEST_DATA[4].1));
        assert_eq!(14, osa_distance(TEST_DATA[5].0, TEST_DATA[5].1));
        assert_eq!(33, osa_distance(TEST_DATA[6].0, TEST_DATA[6].1));
    }
}
<|endoftext|>


<commit_before>#![no_main]

use arbitrary::Arbitrary;
use libfuzzer_sys::fuzz_target;

#[derive(Arbitrary, Debug)]
enum FloatInput {
    F32(f32),
    F64(f64),
}

#[derive(Arbitrary, Debug)]
struct Inputs {
    inputs: Vec<(FloatInput, bool)>,
}

fuzz_target!(|input: Inputs| {
    let mut buffer = ryu::Buffer::new();
    for input_step in input.inputs {
        match input_step {
            (FloatInput::F32(val), false) => buffer.format(val),
            (FloatInput::F32(val), true) => buffer.format_finite(val),
            (FloatInput::F64(val), false) => buffer.format(val),
            (FloatInput::F64(val), true) => buffer.format_finite(val),
        };
    }
});
<commit_msg>Format a single float per fuzz call<commit_after>#![no_main]

use arbitrary::Arbitrary;
use libfuzzer_sys::fuzz_target;

#[derive(Arbitrary, Debug)]
enum FloatInput {
    F32(f32),
    F64(f64),
}

fuzz_target!(|inputs: (FloatInput, bool)| {
    let (input, finite) = inputs;
    let mut buffer = ryu::Buffer::new();
    match (input, finite) {
        (FloatInput::F32(val), false) => buffer.format(val),
        (FloatInput::F32(val), true) => buffer.format_finite(val),
        (FloatInput::F64(val), false) => buffer.format(val),
        (FloatInput::F64(val), true) => buffer.format_finite(val),
    };
});
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    cluster::Cluster,
    effects::{self, network_delay},
    experiments::{Context, Experiment, ExperimentParam},
    tx_emitter::EmitJobRequest,
};
use anyhow::Result;
use async_trait::async_trait;
use libra_logger::info;
use std::{
    fmt::{Display, Error, Formatter},
    time::Duration,
};
use structopt::StructOpt;

pub struct PerformanceBenchmarkThreeRegionSimulation {
    cluster: Cluster,
}

#[derive(StructOpt, Debug)]
pub struct PerformanceBenchmarkThreeRegionSimulationParams {}

impl ExperimentParam for PerformanceBenchmarkThreeRegionSimulationParams {
    type E = PerformanceBenchmarkThreeRegionSimulation;
    fn build(self, cluster: &Cluster) -> Self::E {
        Self::E {
            cluster: cluster.clone(),
        }
    }
}

#[async_trait]
impl Experiment for PerformanceBenchmarkThreeRegionSimulation {
    async fn run(&mut self, context: &mut Context<'_>) -> anyhow::Result<()> {
        let num_nodes = self.cluster.validator_instances().len();
        let split_country_num = ((num_nodes as f64) * 0.8) as usize;
        let split_region_num = split_country_num / 2;
        let (us, euro) = self.cluster.split_n_validators_random(split_country_num);
        let (us_west, us_east) = us.split_n_validators_random(split_region_num);
        let mut effects = network_delay::three_region_simulation_effects(
            (
                us_west.validator_instances().to_vec(),
                us_east.validator_instances().to_vec(),
                euro.validator_instances().to_vec(),
            ),
            (
                Duration::from_millis(60), // us_east<->eu one way delay
                Duration::from_millis(95), // us_west<->eu one way delay
                Duration::from_millis(40), // us_west<->us_east one way delay
            ),
        );

        effects::activate_all(&mut effects).await?;

        let window = Duration::from_secs(240);
        let emit_job_request = if context.emit_to_validator {
            EmitJobRequest::for_instances(
                context.cluster.validator_instances().to_vec(),
                context.global_emit_job_request,
            )
        } else {
            EmitJobRequest::for_instances(
                context.cluster.fullnode_instances().to_vec(),
                context.global_emit_job_request,
            )
        };
        let stats = context
            .tx_emitter
            .emit_txn_for(window, emit_job_request)
            .await?;
        let avg_tps = stats.committed / window.as_secs();
        let avg_latency_client = stats.latency / stats.committed;
        let p99_latency = stats.latency_buckets.percentile(99, 100);
        info!(
            "Tx status from client side: txn {}, avg latency {}",
            stats.committed as u64, avg_latency_client
        );

        effects::deactivate_all(&mut effects).await?;

        context
            .report
            .report_metric(&self, "avg_tps", avg_tps as f64);
        context
            .report
            .report_metric(&self, "avg_latency", avg_latency_client as f64);
        context
            .report
            .report_metric(&self, "p99_latency", p99_latency as f64);
        context.report.report_text(format!(
            "{} : {:.0} TPS, {:.1} ms latency, {:.1} ms p99 latency",
            self, avg_tps, avg_latency_client, p99_latency
        ));
        Ok(())
    }

    fn deadline(&self) -> Duration {
        Duration::from_secs(600)
    }
}

impl Display for PerformanceBenchmarkThreeRegionSimulation {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        write!(f, "3 Region Simulation")
    }
}
<commit_msg>[cluster-test] Track and report expired transactions in 3-region simulation test<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    cluster::Cluster,
    effects::{self, network_delay},
    experiments::{Context, Experiment, ExperimentParam},
    tx_emitter::EmitJobRequest,
};
use anyhow::Result;
use async_trait::async_trait;
use libra_logger::info;
use std::{
    fmt::{Display, Error, Formatter},
    time::Duration,
};
use structopt::StructOpt;

pub struct PerformanceBenchmarkThreeRegionSimulation {
    cluster: Cluster,
}

#[derive(StructOpt, Debug)]
pub struct PerformanceBenchmarkThreeRegionSimulationParams {}

impl ExperimentParam for PerformanceBenchmarkThreeRegionSimulationParams {
    type E = PerformanceBenchmarkThreeRegionSimulation;
    fn build(self, cluster: &Cluster) -> Self::E {
        Self::E {
            cluster: cluster.clone(),
        }
    }
}

#[async_trait]
impl Experiment for PerformanceBenchmarkThreeRegionSimulation {
    async fn run(&mut self, context: &mut Context<'_>) -> anyhow::Result<()> {
        let num_nodes = self.cluster.validator_instances().len();
        let split_country_num = ((num_nodes as f64) * 0.8) as usize;
        let split_region_num = split_country_num / 2;
        let (us, euro) = self.cluster.split_n_validators_random(split_country_num);
        let (us_west, us_east) = us.split_n_validators_random(split_region_num);
        let mut effects = network_delay::three_region_simulation_effects(
            (
                us_west.validator_instances().to_vec(),
                us_east.validator_instances().to_vec(),
                euro.validator_instances().to_vec(),
            ),
            (
                Duration::from_millis(60), // us_east<->eu one way delay
                Duration::from_millis(95), // us_west<->eu one way delay
                Duration::from_millis(40), // us_west<->us_east one way delay
            ),
        );

        effects::activate_all(&mut effects).await?;

        let window = Duration::from_secs(240);
        let emit_job_request = if context.emit_to_validator {
            EmitJobRequest::for_instances(
                context.cluster.validator_instances().to_vec(),
                context.global_emit_job_request,
            )
        } else {
            EmitJobRequest::for_instances(
                context.cluster.fullnode_instances().to_vec(),
                context.global_emit_job_request,
            )
        };
        let stats = context
            .tx_emitter
            .emit_txn_for(window, emit_job_request)
            .await?;
        let avg_tps = stats.committed / window.as_secs();
        let avg_latency_client = stats.latency / stats.committed;
        let p99_latency = stats.latency_buckets.percentile(99, 100);
        let submitted_txn = stats.submitted;
        let expired_txn = stats.expired;
        info!(
            "Tx status from client side: txn {}, avg latency {}",
            stats.committed as u64, avg_latency_client
        );

        effects::deactivate_all(&mut effects).await?;
        context
            .report
            .report_metric(&self, "submitted_txn", submitted_txn as f64);
        context
            .report
            .report_metric(&self, "expired_txn", expired_txn as f64);
        context
            .report
            .report_metric(&self, "avg_tps", avg_tps as f64);
        context
            .report
            .report_metric(&self, "avg_latency", avg_latency_client as f64);
        context
            .report
            .report_metric(&self, "p99_latency", p99_latency as f64);
        let expired_text = if expired_txn == 0 {
            "no expired txns".to_string()
        } else {
            format!("(!) expired {} out of {} txns", expired_txn, submitted_txn)
        };
        context.report.report_text(format!(
            "{} : {:.0} TPS, {:.1} ms latency, {:.1} ms p99 latency, {}",
            self, avg_tps, avg_latency_client, p99_latency, expired_text
        ));
        Ok(())
    }

    fn deadline(&self) -> Duration {
        Duration::from_secs(600)
    }
}

impl Display for PerformanceBenchmarkThreeRegionSimulation {
    fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
        write!(f, "3 Region Simulation")
    }
}
<|endoftext|>


<commit_before>use tool::*;

///
/// Represents a tooling environment, which enables tools to be retrieved by name.
///
/// Environments make it possible to use tools without needing to know where the
/// precise implementation is located. Environments also provide a way to perform
/// dependency injection in other tools.
///
pub trait Environment {
    ///
    /// Retrieves a tool using a JSON interface by name
    ///
    fn get_json_tool(&self, name: &str) -> Result<Box<Tool>, RetrieveToolError>;
}

///
/// The reason an environment retrieve failed
///
#[derive(Copy, Clone, Debug)]
pub enum RetrieveFailReason {
    /// Reason not listed in this enum
    Generic,

    /// A tool could not be found
    NotFound,
}

///
/// Represents an error that occurred during a request to retrieve a tool
///
#[derive(Debug)]
pub struct RetrieveToolError {
    /// The reason the failure occurred
    reason: RetrieveFailReason,

    /// A human-readable message associated with this error
    msg: String
}

impl RetrieveToolError {
    ///
    /// Creates a new error
    ///
    pub fn new(message: &str) -> RetrieveToolError {
        RetrieveToolError { reason: RetrieveFailReason::Generic, msg: String::from(message) }
    }

    ///
    /// Creates a 'tool not found' error
    ///
    pub fn not_found() -> RetrieveToolError {
        RetrieveToolError { reason: RetrieveFailReason::NotFound, msg: String::from("Tool not found") }
    }

    ///
    /// Retrieves the message for an error
    ///
    pub fn message<'a>(&'a self) -> &'a str {
        &self.msg
    }

    ///
    /// Retrieves the reason attached to this failure
    ///
    pub fn reason(&self) -> RetrieveFailReason {
        self.reason
    }
}
<commit_msg>Mark Environment as Send (needed for creating things like combined_environment)<commit_after>use tool::*;

///
/// Represents a tooling environment, which enables tools to be retrieved by name.
///
/// Environments make it possible to use tools without needing to know where the
/// precise implementation is located. Environments also provide a way to perform
/// dependency injection in other tools.
///
pub trait Environment : Send {
    ///
    /// Retrieves a tool using a JSON interface by name
    ///
    fn get_json_tool(&self, name: &str) -> Result<Box<Tool>, RetrieveToolError>;
}

///
/// The reason an environment retrieve failed
///
#[derive(Copy, Clone, Debug)]
pub enum RetrieveFailReason {
    /// Reason not listed in this enum
    Generic,

    /// A tool could not be found
    NotFound,
}

///
/// Represents an error that occurred during a request to retrieve a tool
///
#[derive(Debug)]
pub struct RetrieveToolError {
    /// The reason the failure occurred
    reason: RetrieveFailReason,

    /// A human-readable message associated with this error
    msg: String
}

impl RetrieveToolError {
    ///
    /// Creates a new error
    ///
    pub fn new(message: &str) -> RetrieveToolError {
        RetrieveToolError { reason: RetrieveFailReason::Generic, msg: String::from(message) }
    }

    ///
    /// Creates a 'tool not found' error
    ///
    pub fn not_found() -> RetrieveToolError {
        RetrieveToolError { reason: RetrieveFailReason::NotFound, msg: String::from("Tool not found") }
    }

    ///
    /// Retrieves the message for an error
    ///
    pub fn message<'a>(&'a self) -> &'a str {
        &self.msg
    }

    ///
    /// Retrieves the reason attached to this failure
    ///
    pub fn reason(&self) -> RetrieveFailReason {
        self.reason
    }
}
<|endoftext|>


<commit_before>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{ensure, Error, Result};
use bech32::{Bech32, FromBase32, ToBase32};
use bytes::Bytes;
use hex;
use libra_crypto::{
    hash::{CryptoHash, CryptoHasher},
    HashValue, VerifyingKey,
};
use libra_crypto_derive::CryptoHasher;
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use rand::{rngs::OsRng, Rng};
use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
use std::{convert::TryFrom, fmt, str::FromStr};

pub const ADDRESS_LENGTH: usize = 32;

const SHORT_STRING_LENGTH: usize = 4;

const LIBRA_NETWORK_ID_SHORT: &str = "lb";

/// A struct that represents an account address.
/// Currently Public Key is used.
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Default, Clone, Copy, CryptoHasher)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct AccountAddress([u8; ADDRESS_LENGTH]);

impl AccountAddress {
    pub const fn new(address: [u8; ADDRESS_LENGTH]) -> Self {
        AccountAddress(address)
    }

    pub fn random() -> Self {
        let mut rng = OsRng::new().expect("can't access OsRng");
        let buf: [u8; 32] = rng.gen();
        AccountAddress::new(buf)
    }

    // Helpful in log messages
    pub fn short_str(&self) -> String {
        hex::encode(&self.0[0..SHORT_STRING_LENGTH])
    }

    pub fn to_vec(&self) -> Vec<u8> {
        self.0.to_vec()
    }

    pub fn from_public_key<PublicKey: VerifyingKey>(public_key: &PublicKey) -> Self {
        let hash = *HashValue::from_sha3_256(&public_key.to_bytes()).as_ref();
        AccountAddress::new(hash)
    }

    pub fn from_hex_literal(literal: &str) -> Result<Self> {
        let mut hex_string = String::from(&literal[2..]);
        if hex_string.len() % 2 != 0 {
            hex_string.insert(0, '0');
        }

        let mut result = hex::decode(hex_string.as_str())?;
        let len = result.len();
        if len < 32 {
            result.reverse();
            for _ in len..32 {
                result.push(0);
            }
            result.reverse();
        }

        assert!(result.len() >= 32);
        AccountAddress::try_from(result)
    }
}

impl CryptoHash for AccountAddress {
    type Hasher = AccountAddressHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&self.0);
        state.finish()
    }
}

impl AsRef<[u8]> for AccountAddress {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl fmt::Display for AccountAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
        // Forward to the LowerHex impl with a "0x" prepended (the # flag).
        write!(f, "{:#x}", self)
    }
}

impl fmt::Debug for AccountAddress {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Forward to the LowerHex impl with a "0x" prepended (the # flag).
        write!(f, "{:#x}", self)
    }
}

impl fmt::LowerHex for AccountAddress {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", hex::encode(&self.0))
    }
}

impl TryFrom<&[u8]> for AccountAddress {
    type Error = Error;

    /// Tries to convert the provided byte array into Address.
    fn try_from(bytes: &[u8]) -> Result<AccountAddress> {
        ensure!(
            bytes.len() == ADDRESS_LENGTH,
            "The Address {:?} is of invalid length",
            bytes
        );
        let mut addr = [0u8; ADDRESS_LENGTH];
        addr.copy_from_slice(bytes);
        Ok(AccountAddress(addr))
    }
}

impl TryFrom<&[u8; 32]> for AccountAddress {
    type Error = Error;

    /// Tries to convert the provided byte array into Address.
    fn try_from(bytes: &[u8; 32]) -> Result<AccountAddress> {
        AccountAddress::try_from(&bytes[..])
    }
}

impl TryFrom<Vec<u8>> for AccountAddress {
    type Error = Error;

    /// Tries to convert the provided byte buffer into Address.
    fn try_from(bytes: Vec<u8>) -> Result<AccountAddress> {
        AccountAddress::try_from(&bytes[..])
    }
}

impl From<AccountAddress> for Vec<u8> {
    fn from(addr: AccountAddress) -> Vec<u8> {
        addr.0.to_vec()
    }
}

impl From<&AccountAddress> for Vec<u8> {
    fn from(addr: &AccountAddress) -> Vec<u8> {
        addr.0.to_vec()
    }
}

impl TryFrom<Bytes> for AccountAddress {
    type Error = Error;

    fn try_from(bytes: Bytes) -> Result<AccountAddress> {
        AccountAddress::try_from(bytes.as_ref())
    }
}

impl From<AccountAddress> for Bytes {
    fn from(addr: AccountAddress) -> Bytes {
        Bytes::copy_from_slice(addr.0.as_ref())
    }
}

impl From<&AccountAddress> for String {
    fn from(addr: &AccountAddress) -> String {
        ::hex::encode(addr.as_ref())
    }
}

impl TryFrom<String> for AccountAddress {
    type Error = Error;

    fn try_from(s: String) -> Result<AccountAddress> {
        assert!(!s.is_empty());
        let bytes_out = ::hex::decode(s)?;
        AccountAddress::try_from(bytes_out.as_slice())
    }
}

impl TryFrom<Bech32> for AccountAddress {
    type Error = Error;

    fn try_from(encoded_input: Bech32) -> Result<AccountAddress> {
        let base32_hash = encoded_input.data();
        let hash = Vec::from_base32(&base32_hash)?;
        AccountAddress::try_from(&hash[..])
    }
}

impl FromStr for AccountAddress {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        assert!(!s.is_empty());
        let bytes_out = ::hex::decode(s)?;
        AccountAddress::try_from(bytes_out.as_slice())
    }
}

impl TryFrom<AccountAddress> for Bech32 {
    type Error = Error;

    fn try_from(addr: AccountAddress) -> Result<Bech32> {
        let base32_hash = addr.0.to_base32();
        bech32::Bech32::new(LIBRA_NETWORK_ID_SHORT.into(), base32_hash).map_err(Into::into)
    }
}

impl<'de> Deserialize<'de> for AccountAddress {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        if deserializer.is_human_readable() {
            let s = <&str>::deserialize(deserializer)?;
            AccountAddress::from_str(s).map_err(D::Error::custom)
        } else {
            let b = <[u8; ADDRESS_LENGTH]>::deserialize(deserializer)?;
            Ok(AccountAddress::new(b))
        }
    }
}

impl Serialize for AccountAddress {
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        if serializer.is_human_readable() {
            self.to_string().serialize(serializer)
        } else {
            self.0.serialize(serializer)
        }
    }
}
<commit_msg>[Types] Improve AccountAddress::from_hex_literal<commit_after>// Copyright (c) The Libra Core Contributors
// SPDX-License-Identifier: Apache-2.0

use anyhow::{ensure, Error, Result};
use bech32::{Bech32, FromBase32, ToBase32};
use bytes::Bytes;
use hex;
use libra_crypto::{
    hash::{CryptoHash, CryptoHasher},
    HashValue, VerifyingKey,
};
use libra_crypto_derive::CryptoHasher;
#[cfg(any(test, feature = "fuzzing"))]
use proptest_derive::Arbitrary;
use rand::{rngs::OsRng, Rng};
use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
use std::{convert::TryFrom, fmt, str::FromStr};

pub const ADDRESS_LENGTH: usize = 32;

const SHORT_STRING_LENGTH: usize = 4;

const LIBRA_NETWORK_ID_SHORT: &str = "lb";

/// A struct that represents an account address.
/// Currently Public Key is used.
#[derive(Ord, PartialOrd, Eq, PartialEq, Hash, Default, Clone, Copy, CryptoHasher)]
#[cfg_attr(any(test, feature = "fuzzing"), derive(Arbitrary))]
pub struct AccountAddress([u8; ADDRESS_LENGTH]);

impl AccountAddress {
    pub const fn new(address: [u8; ADDRESS_LENGTH]) -> Self {
        AccountAddress(address)
    }

    pub fn random() -> Self {
        let mut rng = OsRng::new().expect("can't access OsRng");
        let buf: [u8; 32] = rng.gen();
        AccountAddress::new(buf)
    }

    // Helpful in log messages
    pub fn short_str(&self) -> String {
        hex::encode(&self.0[0..SHORT_STRING_LENGTH])
    }

    pub fn to_vec(&self) -> Vec<u8> {
        self.0.to_vec()
    }

    pub fn from_public_key<PublicKey: VerifyingKey>(public_key: &PublicKey) -> Self {
        let hash = *HashValue::from_sha3_256(&public_key.to_bytes()).as_ref();
        AccountAddress::new(hash)
    }

    pub fn from_hex_literal(literal: &str) -> Result<Self> {
        ensure!(literal.starts_with("0x"), "literal must start with 0x.");

        let mut hex_string = String::from(&literal[2..]);
        if hex_string.len() % 2 != 0 {
            hex_string.insert(0, '0');
        }

        let mut result = hex::decode(&hex_string)?;
        let len = result.len();
        if len < ADDRESS_LENGTH {
            result.reverse();
            for _ in len..ADDRESS_LENGTH {
                result.push(0);
            }
            result.reverse();
        }

        AccountAddress::try_from(result)
    }
}

impl CryptoHash for AccountAddress {
    type Hasher = AccountAddressHasher;

    fn hash(&self) -> HashValue {
        let mut state = Self::Hasher::default();
        state.write(&self.0);
        state.finish()
    }
}

impl AsRef<[u8]> for AccountAddress {
    fn as_ref(&self) -> &[u8] {
        &self.0
    }
}

impl fmt::Display for AccountAddress {
    fn fmt(&self, f: &mut fmt::Formatter) -> std::fmt::Result {
        // Forward to the LowerHex impl with a "0x" prepended (the # flag).
        write!(f, "{:#x}", self)
    }
}

impl fmt::Debug for AccountAddress {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        // Forward to the LowerHex impl with a "0x" prepended (the # flag).
        write!(f, "{:#x}", self)
    }
}

impl fmt::LowerHex for AccountAddress {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{}", hex::encode(&self.0))
    }
}

impl TryFrom<&[u8]> for AccountAddress {
    type Error = Error;

    /// Tries to convert the provided byte array into Address.
    fn try_from(bytes: &[u8]) -> Result<AccountAddress> {
        ensure!(
            bytes.len() == ADDRESS_LENGTH,
            "The Address {:?} is of invalid length",
            bytes
        );
        let mut addr = [0u8; ADDRESS_LENGTH];
        addr.copy_from_slice(bytes);
        Ok(AccountAddress(addr))
    }
}

impl TryFrom<&[u8; 32]> for AccountAddress {
    type Error = Error;

    /// Tries to convert the provided byte array into Address.
    fn try_from(bytes: &[u8; 32]) -> Result<AccountAddress> {
        AccountAddress::try_from(&bytes[..])
    }
}

impl TryFrom<Vec<u8>> for AccountAddress {
    type Error = Error;

    /// Tries to convert the provided byte buffer into Address.
    fn try_from(bytes: Vec<u8>) -> Result<AccountAddress> {
        AccountAddress::try_from(&bytes[..])
    }
}

impl From<AccountAddress> for Vec<u8> {
    fn from(addr: AccountAddress) -> Vec<u8> {
        addr.0.to_vec()
    }
}

impl From<&AccountAddress> for Vec<u8> {
    fn from(addr: &AccountAddress) -> Vec<u8> {
        addr.0.to_vec()
    }
}

impl TryFrom<Bytes> for AccountAddress {
    type Error = Error;

    fn try_from(bytes: Bytes) -> Result<AccountAddress> {
        AccountAddress::try_from(bytes.as_ref())
    }
}

impl From<AccountAddress> for Bytes {
    fn from(addr: AccountAddress) -> Bytes {
        Bytes::copy_from_slice(addr.0.as_ref())
    }
}

impl From<&AccountAddress> for String {
    fn from(addr: &AccountAddress) -> String {
        ::hex::encode(addr.as_ref())
    }
}

impl TryFrom<String> for AccountAddress {
    type Error = Error;

    fn try_from(s: String) -> Result<AccountAddress> {
        assert!(!s.is_empty());
        let bytes_out = ::hex::decode(s)?;
        AccountAddress::try_from(bytes_out.as_slice())
    }
}

impl TryFrom<Bech32> for AccountAddress {
    type Error = Error;

    fn try_from(encoded_input: Bech32) -> Result<AccountAddress> {
        let base32_hash = encoded_input.data();
        let hash = Vec::from_base32(&base32_hash)?;
        AccountAddress::try_from(&hash[..])
    }
}

impl FromStr for AccountAddress {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        assert!(!s.is_empty());
        let bytes_out = ::hex::decode(s)?;
        AccountAddress::try_from(bytes_out.as_slice())
    }
}

impl TryFrom<AccountAddress> for Bech32 {
    type Error = Error;

    fn try_from(addr: AccountAddress) -> Result<Bech32> {
        let base32_hash = addr.0.to_base32();
        bech32::Bech32::new(LIBRA_NETWORK_ID_SHORT.into(), base32_hash).map_err(Into::into)
    }
}

impl<'de> Deserialize<'de> for AccountAddress {
    fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
    where
        D: Deserializer<'de>,
    {
        if deserializer.is_human_readable() {
            let s = <&str>::deserialize(deserializer)?;
            AccountAddress::from_str(s).map_err(D::Error::custom)
        } else {
            let b = <[u8; ADDRESS_LENGTH]>::deserialize(deserializer)?;
            Ok(AccountAddress::new(b))
        }
    }
}

impl Serialize for AccountAddress {
    fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        if serializer.is_human_readable() {
            self.to_string().serialize(serializer)
        } else {
            self.0.serialize(serializer)
        }
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// corresponds to lauxlib.h
use libc::{c_int, c_long, c_char, c_void, size_t};
use ffi::lua;
use ffi::lua::{lua_State, lua_CFunction, lua_Integer, lua_Number};
use ffi::luaconf::LUAL_BUFFERSIZE;
use std::ptr;

pub use super::glue::LUAL_NUMSIZES;

// extra error code for 'luaL_load'
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;

#[repr(C)]
pub struct luaL_Reg {
  name: *const c_char,
  func: lua_CFunction,
}

#[inline(always)]
pub unsafe fn luaL_checkversion(L: *mut lua_State) {
  luaL_checkversion_(L, lua::LUA_VERSION_NUM as lua_Number, LUAL_NUMSIZES as size_t)
}

extern {
  pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: size_t);

  pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
  pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
  pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut size_t) -> *const c_char;
  pub fn luaL_argerror(L: *mut lua_State, arg: c_int, l: *const c_char) -> c_int;
  pub fn luaL_checklstring(L: *mut lua_State, arg: c_int, l: *mut size_t) -> *const c_char;
  pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut size_t) -> *const c_char;
  pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number;
  pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number;
  pub fn luaL_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
  pub fn luaL_optinteger(L: *mut lua_State, arg: c_int, def: lua_Integer) -> lua_Integer;

  pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char);
  pub fn luaL_checktype(L: *mut lua_State, arg: c_int, t: c_int);
  pub fn luaL_checkany(L: *mut lua_State, arg: c_int);

  pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
  pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
  pub fn luaL_testudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
  pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;

  pub fn luaL_where(L: *mut lua_State, lvl: c_int) -> c_int;
  pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> c_int;

  // TODO: test this
  pub fn luaL_checkoption(L: *mut lua_State, arg: c_int, def: *const c_char, lst: [*const c_char]) -> c_int;

  pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
  pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
}

// pre-defined references
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;

extern {
  pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
  pub fn luaL_unref(L: *mut lua_State, t: c_int, r: c_int);

  pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char) -> c_int;
}

#[inline(always)]
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
  luaL_loadfilex(L, f, ptr::null())
}

extern {
  pub fn luaL_loadbufferx(L: *mut lua_State, buff: *const c_char, sz: size_t, name: *const c_char, mode: *const c_char) -> c_int;
  pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;

  pub fn luaL_newstate() -> *mut lua_State;

  pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;

  pub fn luaL_gsub(L: *mut lua_State, s: *const c_char, p: *const c_char, r: *const c_char) -> *const c_char;

  pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);

  pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;

  pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);

  pub fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int);
}

#[inline(always)]
#[allow(unused_variable)]
pub unsafe fn luaL_newlibtable(L: *mut lua_State, l: *const luaL_Reg) {
  // TODO: figure out how to pass an appropriate hint for the second param
  // this involves correcting the second parameter's type; in C this is
  // sizeof(l)/sizeof(l[0])
  lua::lua_createtable(L, 0, 0)
}

#[inline(always)]
pub unsafe fn luaL_newlib(L: *mut lua_State, l: *const luaL_Reg) {
  luaL_checkversion(L);
  luaL_newlibtable(L, l);
  luaL_setfuncs(L, l, 0)
}

#[inline(always)]
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
  if cond == 0 {
    luaL_argerror(L, arg, extramsg);
  }
}

#[inline(always)]
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
  luaL_checklstring(L, n, ptr::null_mut())
}

#[inline(always)]
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
  luaL_optlstring(L, n, d, ptr::null_mut())
}

// From 5.3 user manual:
// Macros to project non-default integer types (luaL_checkint, luaL_optint,
// luaL_checklong, luaL_optlong) were deprecated. Use their equivalent over
// lua_Integer with a type cast (or, when possible, use lua_Integer in your
// code).
#[inline(always)]
#[deprecated]
pub unsafe fn luaL_checkint(L: *mut lua_State, n: c_int) -> c_int {
  luaL_checkinteger(L, n) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_optint(L: *mut lua_State, n: c_int, d: c_int) -> c_int {
  luaL_optinteger(L, n, d as lua_Integer) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_checklong(L: *mut lua_State, n: c_int) -> c_long {
  luaL_checkinteger(L, n) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_optlong(L: *mut lua_State, n: c_int, d: c_long) -> c_long {
  luaL_optinteger(L, n, d as lua_Integer) as c_int
}

#[inline(always)]
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
  lua::lua_typename(L, lua::lua_type(L, i))
}

#[inline(always)]
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
  let status = luaL_loadfile(L, filename);
  if status == 0 {
    lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
  } else {
    status
  }
}

#[inline(always)]
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
  let status = luaL_loadstring(L, s);
  if status == 0 {
    lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
  } else {
    status
  }
}

#[inline(always)]
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
  lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n);
}

// luaL_opt would be implemented here but it is undocumented, so it's omitted

#[inline(always)]
pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: size_t, n: *const c_char) -> c_int {
  luaL_loadbufferx(L, s, sz, n, ptr::null())
}

#[repr(C)]
pub struct luaL_Buffer {
  b: *mut c_char,
  size: size_t,
  n: size_t,
  L: *mut lua_State,
  initb: [c_char, ..LUAL_BUFFERSIZE as uint]
}

// TODO: Test this thoroughly
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
  // (B)->n < (B) -> size || luaL_prepbuffsize((B), 1)
  if (*B).n < (*B).size {
    luaL_prepbuffsize(B, 1);
  }
  // (B)->b[(B)->n++] = (c)
  let offset = (*B).b.offset((*B).n as int);
  ptr::write(offset, c);
  (*B).n += 1;
}

#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, s: size_t) {
  (*B).n += s;
}

extern {
  pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
  pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: size_t) -> *mut c_char;
  pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: size_t);
  pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
  pub fn luaL_addvalue(B: *mut luaL_Buffer);
  pub fn luaL_pushresult(B: *mut luaL_Buffer);
  pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: size_t);
  pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: size_t) -> *mut c_char;
}

pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
  luaL_prepbuffsize(B, LUAL_BUFFERSIZE as size_t)
}

// omitted: LUA_FILEHANDLE

#[repr(C)]
pub struct luaL_Stream {
  f: *mut c_void,
  closef: lua_CFunction
}

// omitted: old module system compatibility
<commit_msg>Change unused_variable to unused_variables<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2014 J.C. Moyer
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// corresponds to lauxlib.h
use libc::{c_int, c_long, c_char, c_void, size_t};
use ffi::lua;
use ffi::lua::{lua_State, lua_CFunction, lua_Integer, lua_Number};
use ffi::luaconf::LUAL_BUFFERSIZE;
use std::ptr;

pub use super::glue::LUAL_NUMSIZES;

// extra error code for 'luaL_load'
pub const LUA_ERRFILE: c_int = lua::LUA_ERRERR + 1;

#[repr(C)]
pub struct luaL_Reg {
  name: *const c_char,
  func: lua_CFunction,
}

#[inline(always)]
pub unsafe fn luaL_checkversion(L: *mut lua_State) {
  luaL_checkversion_(L, lua::LUA_VERSION_NUM as lua_Number, LUAL_NUMSIZES as size_t)
}

extern {
  pub fn luaL_checkversion_(L: *mut lua_State, ver: lua_Number, sz: size_t);

  pub fn luaL_getmetafield(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
  pub fn luaL_callmeta(L: *mut lua_State, obj: c_int, e: *const c_char) -> c_int;
  pub fn luaL_tolstring(L: *mut lua_State, idx: c_int, len: *mut size_t) -> *const c_char;
  pub fn luaL_argerror(L: *mut lua_State, arg: c_int, l: *const c_char) -> c_int;
  pub fn luaL_checklstring(L: *mut lua_State, arg: c_int, l: *mut size_t) -> *const c_char;
  pub fn luaL_optlstring(L: *mut lua_State, arg: c_int, def: *const c_char, l: *mut size_t) -> *const c_char;
  pub fn luaL_checknumber(L: *mut lua_State, arg: c_int) -> lua_Number;
  pub fn luaL_optnumber(L: *mut lua_State, arg: c_int, def: lua_Number) -> lua_Number;
  pub fn luaL_checkinteger(L: *mut lua_State, arg: c_int) -> lua_Integer;
  pub fn luaL_optinteger(L: *mut lua_State, arg: c_int, def: lua_Integer) -> lua_Integer;

  pub fn luaL_checkstack(L: *mut lua_State, sz: c_int, msg: *const c_char);
  pub fn luaL_checktype(L: *mut lua_State, arg: c_int, t: c_int);
  pub fn luaL_checkany(L: *mut lua_State, arg: c_int);

  pub fn luaL_newmetatable(L: *mut lua_State, tname: *const c_char) -> c_int;
  pub fn luaL_setmetatable(L: *mut lua_State, tname: *const c_char);
  pub fn luaL_testudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;
  pub fn luaL_checkudata(L: *mut lua_State, ud: c_int, tname: *const c_char) -> *mut c_void;

  pub fn luaL_where(L: *mut lua_State, lvl: c_int) -> c_int;
  pub fn luaL_error(L: *mut lua_State, fmt: *const c_char, ...) -> c_int;

  // TODO: test this
  pub fn luaL_checkoption(L: *mut lua_State, arg: c_int, def: *const c_char, lst: [*const c_char]) -> c_int;

  pub fn luaL_fileresult(L: *mut lua_State, stat: c_int, fname: *const c_char) -> c_int;
  pub fn luaL_execresult(L: *mut lua_State, stat: c_int) -> c_int;
}

// pre-defined references
pub const LUA_NOREF: c_int = -2;
pub const LUA_REFNIL: c_int = -1;

extern {
  pub fn luaL_ref(L: *mut lua_State, t: c_int) -> c_int;
  pub fn luaL_unref(L: *mut lua_State, t: c_int, r: c_int);

  pub fn luaL_loadfilex(L: *mut lua_State, filename: *const c_char, mode: *const c_char) -> c_int;
}

#[inline(always)]
pub unsafe fn luaL_loadfile(L: *mut lua_State, f: *const c_char) -> c_int {
  luaL_loadfilex(L, f, ptr::null())
}

extern {
  pub fn luaL_loadbufferx(L: *mut lua_State, buff: *const c_char, sz: size_t, name: *const c_char, mode: *const c_char) -> c_int;
  pub fn luaL_loadstring(L: *mut lua_State, s: *const c_char) -> c_int;

  pub fn luaL_newstate() -> *mut lua_State;

  pub fn luaL_len(L: *mut lua_State, idx: c_int) -> lua_Integer;

  pub fn luaL_gsub(L: *mut lua_State, s: *const c_char, p: *const c_char, r: *const c_char) -> *const c_char;

  pub fn luaL_setfuncs(L: *mut lua_State, l: *const luaL_Reg, nup: c_int);

  pub fn luaL_getsubtable(L: *mut lua_State, idx: c_int, fname: *const c_char) -> c_int;

  pub fn luaL_traceback(L: *mut lua_State, L1: *mut lua_State, msg: *const c_char, level: c_int);

  pub fn luaL_requiref(L: *mut lua_State, modname: *const c_char, openf: lua_CFunction, glb: c_int);
}

#[inline(always)]
#[allow(unused_variables)]
pub unsafe fn luaL_newlibtable(L: *mut lua_State, l: *const luaL_Reg) {
  // TODO: figure out how to pass an appropriate hint for the second param
  // this involves correcting the second parameter's type; in C this is
  // sizeof(l)/sizeof(l[0])
  lua::lua_createtable(L, 0, 0)
}

#[inline(always)]
pub unsafe fn luaL_newlib(L: *mut lua_State, l: *const luaL_Reg) {
  luaL_checkversion(L);
  luaL_newlibtable(L, l);
  luaL_setfuncs(L, l, 0)
}

#[inline(always)]
pub unsafe fn luaL_argcheck(L: *mut lua_State, cond: c_int, arg: c_int, extramsg: *const c_char) {
  if cond == 0 {
    luaL_argerror(L, arg, extramsg);
  }
}

#[inline(always)]
pub unsafe fn luaL_checkstring(L: *mut lua_State, n: c_int) -> *const c_char {
  luaL_checklstring(L, n, ptr::null_mut())
}

#[inline(always)]
pub unsafe fn luaL_optstring(L: *mut lua_State, n: c_int, d: *const c_char) -> *const c_char {
  luaL_optlstring(L, n, d, ptr::null_mut())
}

// From 5.3 user manual:
// Macros to project non-default integer types (luaL_checkint, luaL_optint,
// luaL_checklong, luaL_optlong) were deprecated. Use their equivalent over
// lua_Integer with a type cast (or, when possible, use lua_Integer in your
// code).
#[inline(always)]
#[deprecated]
pub unsafe fn luaL_checkint(L: *mut lua_State, n: c_int) -> c_int {
  luaL_checkinteger(L, n) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_optint(L: *mut lua_State, n: c_int, d: c_int) -> c_int {
  luaL_optinteger(L, n, d as lua_Integer) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_checklong(L: *mut lua_State, n: c_int) -> c_long {
  luaL_checkinteger(L, n) as c_int
}

#[inline(always)]
#[deprecated]
pub unsafe fn luaL_optlong(L: *mut lua_State, n: c_int, d: c_long) -> c_long {
  luaL_optinteger(L, n, d as lua_Integer) as c_int
}

#[inline(always)]
pub unsafe fn luaL_typename(L: *mut lua_State, i: c_int) -> *const c_char {
  lua::lua_typename(L, lua::lua_type(L, i))
}

#[inline(always)]
pub unsafe fn luaL_dofile(L: *mut lua_State, filename: *const c_char) -> c_int {
  let status = luaL_loadfile(L, filename);
  if status == 0 {
    lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
  } else {
    status
  }
}

#[inline(always)]
pub unsafe fn luaL_dostring(L: *mut lua_State, s: *const c_char) -> c_int {
  let status = luaL_loadstring(L, s);
  if status == 0 {
    lua::lua_pcall(L, 0, lua::LUA_MULTRET, 0)
  } else {
    status
  }
}

#[inline(always)]
pub unsafe fn luaL_getmetatable(L: *mut lua_State, n: *const c_char) {
  lua::lua_getfield(L, lua::LUA_REGISTRYINDEX, n);
}

// luaL_opt would be implemented here but it is undocumented, so it's omitted

#[inline(always)]
pub unsafe fn luaL_loadbuffer(L: *mut lua_State, s: *const c_char, sz: size_t, n: *const c_char) -> c_int {
  luaL_loadbufferx(L, s, sz, n, ptr::null())
}

#[repr(C)]
pub struct luaL_Buffer {
  b: *mut c_char,
  size: size_t,
  n: size_t,
  L: *mut lua_State,
  initb: [c_char, ..LUAL_BUFFERSIZE as uint]
}

// TODO: Test this thoroughly
#[inline(always)]
pub unsafe fn luaL_addchar(B: *mut luaL_Buffer, c: c_char) {
  // (B)->n < (B) -> size || luaL_prepbuffsize((B), 1)
  if (*B).n < (*B).size {
    luaL_prepbuffsize(B, 1);
  }
  // (B)->b[(B)->n++] = (c)
  let offset = (*B).b.offset((*B).n as int);
  ptr::write(offset, c);
  (*B).n += 1;
}

#[inline(always)]
pub unsafe fn luaL_addsize(B: *mut luaL_Buffer, s: size_t) {
  (*B).n += s;
}

extern {
  pub fn luaL_buffinit(L: *mut lua_State, B: *mut luaL_Buffer);
  pub fn luaL_prepbuffsize(B: *mut luaL_Buffer, sz: size_t) -> *mut c_char;
  pub fn luaL_addlstring(B: *mut luaL_Buffer, s: *const c_char, l: size_t);
  pub fn luaL_addstring(B: *mut luaL_Buffer, s: *const c_char);
  pub fn luaL_addvalue(B: *mut luaL_Buffer);
  pub fn luaL_pushresult(B: *mut luaL_Buffer);
  pub fn luaL_pushresultsize(B: *mut luaL_Buffer, sz: size_t);
  pub fn luaL_buffinitsize(L: *mut lua_State, B: *mut luaL_Buffer, sz: size_t) -> *mut c_char;
}

pub unsafe fn luaL_prepbuffer(B: *mut luaL_Buffer) -> *mut c_char {
  luaL_prepbuffsize(B, LUAL_BUFFERSIZE as size_t)
}

// omitted: LUA_FILEHANDLE

#[repr(C)]
pub struct luaL_Stream {
  f: *mut c_void,
  closef: lua_CFunction
}

// omitted: old module system compatibility
<|endoftext|>


<commit_before>extern crate glob;
extern crate zip;

//use glob::Pattern;
use std::fs;
use zip_info::WriteZipInfo;

pub struct ZipInfoFlatWriter {
    archive: zip::ZipArchive<fs::File>,
    path_name: String,
}

impl ZipInfoFlatWriter {
    /// Open a zip archive for this writer:
    pub fn new(file_path: String) -> ZipInfoFlatWriter {
        let file = fs::File::open(&file_path).unwrap();

        let whole_archive = zip::ZipArchive::new(file).unwrap();

        ZipInfoFlatWriter { archive: whole_archive, path_name: file_path }
    }
}

impl WriteZipInfo for ZipInfoFlatWriter {
    /// Concatenate Zip file name with indented stats:
    fn write_zip_info(&mut self, exclude: &str) -> String {
        let mut info = format!("{}", self.path_name);

        let exclude_pattern = glob::Pattern::new(exclude).unwrap();

        for i in 0..self.archive.len() {
            let archive_item = self.archive.by_index(i).unwrap();

            if !exclude_pattern.matches(archive_item.name()) {
                info = format!("{}{}", info, info_for_archive_item(archive_item));
            }
        }

        info
    }
}

fn info_for_archive_item(archive_item: zip::read::ZipFile) -> String {
    let mut info = String::new();
    let item_path = archive_item.name();
    info = format!("{}\n\t{}", info, item_path);

    let compression_type = archive_item.compression();
    info = format!("{}\n\t\tCompression type: {}", info, compression_type);

    let original_size = archive_item.size();
    info = format!("{}\n\t\tOriginal size: {}", info, original_size);

    let compressed_size = archive_item.compressed_size();
    info = format!("{}\n\t\tCompressed size: {}", info, compressed_size);

    if original_size > 0 {
        let compression_rate =
            (original_size as f64 - compressed_size as f64)
            / original_size as f64;
        let compression_perc = format!("{:.*}%", 2, compression_rate * 100.0);
        info = format!("{}\n\t\tCompression_rate: {}", info, compression_perc);
    }

    let comment = archive_item.comment();
    if comment.len() > 0 {
        info = format!("{}\n\t\tComment: {}", info, comment);
    }

    info
}
<commit_msg>Remove comment cruft<commit_after>extern crate glob;
extern crate zip;

use std::fs;
use zip_info::WriteZipInfo;

pub struct ZipInfoFlatWriter {
    archive: zip::ZipArchive<fs::File>,
    path_name: String,
}

impl ZipInfoFlatWriter {
    /// Open a zip archive for this writer:
    pub fn new(file_path: String) -> ZipInfoFlatWriter {
        let file = fs::File::open(&file_path).unwrap();

        let whole_archive = zip::ZipArchive::new(file).unwrap();

        ZipInfoFlatWriter { archive: whole_archive, path_name: file_path }
    }
}

impl WriteZipInfo for ZipInfoFlatWriter {
    /// Concatenate Zip file name with indented stats:
    fn write_zip_info(&mut self, exclude: &str) -> String {
        let mut info = format!("{}", self.path_name);

        let exclude_pattern = glob::Pattern::new(exclude).unwrap();

        for i in 0..self.archive.len() {
            let archive_item = self.archive.by_index(i).unwrap();

            if !exclude_pattern.matches(archive_item.name()) {
                info = format!("{}{}", info, info_for_archive_item(archive_item));
            }
        }

        info
    }
}

fn info_for_archive_item(archive_item: zip::read::ZipFile) -> String {
    let mut info = String::new();
    let item_path = archive_item.name();
    info = format!("{}\n\t{}", info, item_path);

    let compression_type = archive_item.compression();
    info = format!("{}\n\t\tCompression type: {}", info, compression_type);

    let original_size = archive_item.size();
    info = format!("{}\n\t\tOriginal size: {}", info, original_size);

    let compressed_size = archive_item.compressed_size();
    info = format!("{}\n\t\tCompressed size: {}", info, compressed_size);

    if original_size > 0 {
        let compression_rate =
            (original_size as f64 - compressed_size as f64)
            / original_size as f64;
        let compression_perc = format!("{:.*}%", 2, compression_rate * 100.0);
        info = format!("{}\n\t\tCompression_rate: {}", info, compression_perc);
    }

    let comment = archive_item.comment();
    if comment.len() > 0 {
        info = format!("{}\n\t\tComment: {}", info, comment);
    }

    info
}
<|endoftext|>


<commit_before>use ::game::component::Component;
use std::collections::HashMap;
use cgmath::Vector3;

<<<<<<< HEAD
//it is this large for two reasons, one I want to make sure that we never run out to space, and second so that we can have negative uids for flag varibles
//type UID = i64;

pub struct Entity<'a>{
    name: String,
    components: HashMap<String, &'a Component>,
=======
pub struct Entity {
    name: String,
    components: HashMap<String, Box<Component>>,
>>>>>>> adb54650e7336494cd9d626caa517be110f8a56f
    position: Vector3<f32>,
    scale: Vector3<f32>,
    rotation: Vector3<f32>
}

impl<'a> Entity<'a> {

    pub fn add_component(&mut self, component: &'a Component) -> bool {
        if !self.components.contains_key(&component.get_name()) {

            self.components.insert(component.get_name(), component);
            return true;
        }
        return false;
    }

    pub fn remove_component(&mut self, name: String) {
        self.components.remove(&name);
    }

    pub fn get_position(&self) -> Vector3<f32> {
        self.position.clone()
    }

    pub fn get_rotation(&self) -> Vector3<f32> {
        self.rotation.clone()
    }

    pub fn get_scale(&self) -> Vector3<f32> {
        self.scale.clone()
    }
}<commit_msg>Fixing entity from pull<commit_after>use ::game::component::Component;
use std::collections::HashMap;
use cgmath::Vector3;

//it is this large for two reasons, one I want to make sure that we never run out to space, and second so that we can have negative uids for flag varibles
//type UID = i64;

pub struct Entity<'a>{
    name: String,
    components: HashMap<String, &'a Component>,
    position: Vector3<f32>,
    scale: Vector3<f32>,
    rotation: Vector3<f32>
}

impl<'a> Entity<'a> {

    pub fn add_component(&mut self, component: &'a Component) -> bool {
        if !self.components.contains_key(&component.get_name()) {

            self.components.insert(component.get_name(), component);
            return true;
        }
        return false;
    }

    pub fn remove_component(&mut self, name: String) {
        self.components.remove(&name);
    }

    pub fn get_position(&self) -> Vector3<f32> {
        self.position.clone()
    }

    pub fn get_rotation(&self) -> Vector3<f32> {
        self.rotation.clone()
    }

    pub fn get_scale(&self) -> Vector3<f32> {
        self.scale.clone()
    }
}<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::sync::Arc;

use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use device::Device;
use pipeline::ComputePipelineRef;
use pipeline::GraphicsPipelineRef;
use VulkanObject;
use VulkanPointers;
use vk;

/// Command that binds a pipeline to a command buffer.
pub struct CmdBindPipeline
 {
    // The raw pipeline object to bind.
    raw_pipeline: vk::Pipeline,
    // The raw Vulkan enum representing the kind of pipeline.
    pipeline_ty: vk::PipelineBindPoint,
    // The device of the pipeline object, so that we can compare it with the command buffer's
    // device.
    device: Arc<Device>,
    // The pipeline object to bind. Unused, but we need to keep it alive.
    pipeline: P,
}

impl
 CmdBindPipeline
 {
    /// Builds a command that binds a compute pipeline to the compute pipeline bind point.
    ///
    /// Use this command right before a compute dispatch.
    #[inline]
    pub fn bind_compute_pipeline(pipeline: P) -> CmdBindPipeline
 where P: ComputePipelineRef {
        let raw_pipeline = pipeline.inner().internal_object();
        let device = pipeline.device().clone();

        CmdBindPipeline {
            raw_pipeline: raw_pipeline,
            pipeline_ty: vk::PIPELINE_BIND_POINT_COMPUTE,
            device: device,
            pipeline: pipeline,
        }
    }
}

impl CmdBindPipeline<()> {
    /// Builds a command that binds a graphics pipeline to the graphics pipeline bind point.
    ///
    /// Use this command right before a draw command.
    #[inline]
    pub fn bind_graphics_pipeline
(pipeline: P) -> CmdBindPipeline

        where P: GraphicsPipelineRef
    {
        let raw_pipeline = pipeline.inner().internal_object();
        let device = pipeline.device().clone();

        CmdBindPipeline {
            raw_pipeline: raw_pipeline,
            pipeline_ty: vk::PIPELINE_BIND_POINT_GRAPHICS,
            device: device,
            pipeline: pipeline,
        }
    }
}

impl
 CmdBindPipeline
 {
    /// This disables the command but keeps it alive. All getters still return the same value, but
    /// executing the command will not do anything.
    #[inline]
    pub fn disabled(mut self) -> CmdBindPipeline
 {
        self.raw_pipeline = 0;
        self
    }

    /// Returns the device the pipeline is assocated with.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }

    /// True if this is the graphics pipeline. False if the compute pipeline.
    // TODO: should be an enum?
    #[inline]
    pub fn is_graphics(&self) -> bool {
        self.pipeline_ty == vk::PIPELINE_BIND_POINT_GRAPHICS
    }

    /// Returns an object giving access to the pipeline object that will be bound.
    #[inline]
    pub fn sys(&self) -> CmdBindPipelineSys {
        CmdBindPipelineSys(self.raw_pipeline, PhantomData)
    }
}

unsafe impl<'a, P, Pl> AddCommand<&'a CmdBindPipeline<Pl>> for UnsafeCommandBufferBuilder

    where P: CommandPool
{
    type Out = UnsafeCommandBufferBuilder
;

    #[inline]
    fn add(self, command: &'a CmdBindPipeline<Pl>) -> Self::Out {
        if command.raw_pipeline != 0 {
            unsafe {
                let vk = self.device().pointers();
                let cmd = self.internal_object();
                vk.CmdBindPipeline(cmd, command.pipeline_ty, command.raw_pipeline);
            }
        }

        self
    }
}

/// Object that represents the internals of the bind pipeline command.
#[derive(Debug, Copy, Clone)]
pub struct CmdBindPipelineSys<'a>(vk::Pipeline, PhantomData<&'a ()>);

unsafe impl<'a> VulkanObject for CmdBindPipelineSys<'a> {
    type Object = vk::Pipeline;

    #[inline]
    fn internal_object(&self) -> vk::Pipeline {
        self.0
    }
}
<commit_msg>Simplify CmdBindPipeline<commit_after>// Copyright (c) 2016 The vulkano developers
// 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. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

use std::marker::PhantomData;
use std::sync::Arc;

use command_buffer::cb::AddCommand;
use command_buffer::cb::UnsafeCommandBufferBuilder;
use command_buffer::pool::CommandPool;
use device::Device;
use pipeline::ComputePipelineRef;
use pipeline::GraphicsPipelineRef;
use VulkanObject;
use VulkanPointers;
use vk;

/// Command that binds a pipeline to a command buffer.
pub struct CmdBindPipeline
 {
    // The raw pipeline object to bind.
    raw_pipeline: vk::Pipeline,
    // The raw Vulkan enum representing the kind of pipeline.
    pipeline_ty: vk::PipelineBindPoint,
    // The device of the pipeline object, so that we can compare it with the command buffer's
    // device.
    device: Arc<Device>,
    // The pipeline object to bind. Unused, but we need to keep it alive.
    pipeline: P,
}

impl
 CmdBindPipeline
 {
    /// Builds a command that binds a compute pipeline to the compute pipeline bind point.
    ///
    /// Use this command right before a compute dispatch.
    #[inline]
    pub fn bind_compute_pipeline(pipeline: P) -> CmdBindPipeline
 where P: ComputePipelineRef {
        let raw_pipeline = pipeline.inner().internal_object();
        let device = pipeline.device().clone();

        CmdBindPipeline {
            raw_pipeline: raw_pipeline,
            pipeline_ty: vk::PIPELINE_BIND_POINT_COMPUTE,
            device: device,
            pipeline: pipeline,
        }
    }

    /// Builds a command that binds a graphics pipeline to the graphics pipeline bind point.
    ///
    /// Use this command right before a draw command.
    #[inline]
    pub fn bind_graphics_pipeline(pipeline: P) -> CmdBindPipeline

        where P: GraphicsPipelineRef
    {
        let raw_pipeline = pipeline.inner().internal_object();
        let device = pipeline.device().clone();

        CmdBindPipeline {
            raw_pipeline: raw_pipeline,
            pipeline_ty: vk::PIPELINE_BIND_POINT_GRAPHICS,
            device: device,
            pipeline: pipeline,
        }
    }

    /// This disables the command but keeps it alive. All getters still return the same value, but
    /// executing the command will not do anything.
    #[inline]
    pub fn disabled(mut self) -> CmdBindPipeline
 {
        self.raw_pipeline = 0;
        self
    }

    /// Returns the device the pipeline is assocated with.
    #[inline]
    pub fn device(&self) -> &Arc<Device> {
        &self.device
    }

    /// True if this is the graphics pipeline. False if the compute pipeline.
    // TODO: should be an enum?
    #[inline]
    pub fn is_graphics(&self) -> bool {
        self.pipeline_ty == vk::PIPELINE_BIND_POINT_GRAPHICS
    }

    /// Returns an object giving access to the pipeline object that will be bound.
    #[inline]
    pub fn sys(&self) -> CmdBindPipelineSys {
        CmdBindPipelineSys(self.raw_pipeline, PhantomData)
    }
}

unsafe impl<'a, P, Pl> AddCommand<&'a CmdBindPipeline<Pl>> for UnsafeCommandBufferBuilder

    where P: CommandPool
{
    type Out = UnsafeCommandBufferBuilder
;

    #[inline]
    fn add(self, command: &'a CmdBindPipeline<Pl>) -> Self::Out {
        if command.raw_pipeline != 0 {
            unsafe {
                let vk = self.device().pointers();
                let cmd = self.internal_object();
                vk.CmdBindPipeline(cmd, command.pipeline_ty, command.raw_pipeline);
            }
        }

        self
    }
}

/// Object that represents the internals of the bind pipeline command.
#[derive(Debug, Copy, Clone)]
pub struct CmdBindPipelineSys<'a>(vk::Pipeline, PhantomData<&'a ()>);

unsafe impl<'a> VulkanObject for CmdBindPipelineSys<'a> {
    type Object = vk::Pipeline;

    #[inline]
    fn internal_object(&self) -> vk::Pipeline {
        self.0
    }
}
<|endoftext|>