<commit_before>extern crate rand;
use rand::Rng;

pub struct Continent {
    pub id: u32,
    pub diseases: DiceHolder,
}

impl Continent {
    pub fn new(id: u32) -> Continent {
        Continent {
            id: id,
            diseases: DiceHolder::new(),
        }
    }
    // adds Disease d to the DiceHolder
    pub fn add(&mut self, d: Disease) {
        self.diseases.add(d);
    }
    pub fn total_count(&self) -> [u32; 4] {
        self.diseases.total_count()
    }
}

pub struct DiceHolder {
    dice: Vec<Disease>,
}

impl DiceHolder {
    pub fn new() -> DiceHolder {
        DiceHolder { dice: Vec::new() }
    }
    // add a Disease to the holder
    pub fn add(&mut self, d: Disease) {
        self.dice.push(d);
    }
    // return number of given color
    pub fn count(&self, color: &str) -> u32 {
        let mut count = 0;
        match color {
            "red" | "Red" => {
                for i in &self.dice {
                    match *i {
                        Disease::Red => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "yellow" | "Yellow" => {
                for i in &self.dice {
                    match *i {
                        Disease::Yellow => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "blue" | "Blue" => {
                for i in &self.dice {
                    match *i {
                        Disease::Blue => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "black" | "Black" => {
                for i in &self.dice {
                    match *i {
                        Disease::Black => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            _ => 0,
        }
    }
    // grab random die, remove and return it
    pub fn grab(&mut self) -> Option<Disease> {
        if self.size() == 0 {
            None
        } else {
            // try randomly until we hit a color that exists
            loop {
                let color = match rand::thread_rng().gen_range(0, 4) {
                    0 => Disease::Red,
                    1 => Disease::Yellow,
                    2 => Disease::Blue,
                    3 => Disease::Black,
                    _ => panic!("Check disease.grab() something's fucked"),
                };
                match self.remove(color) {
                    Some(color) => return Some(color),
                    None => continue,
                }
            }
        }
    }
    // remove and return an Option with the Disease specified - TODO: make this less gross
    // i'm fighting the borrow checker, not working with it
    pub fn remove(&mut self, d: Disease) -> Option<Disease> {
        // grab first die that matches
        let mut found: bool = false;
        let mut index: usize = 0;
        for (i, elem) in self.dice.iter_mut().enumerate() {
            if elem == &d {
                // TODO: cont. i'd like to be able to just return the Option from here
                // but already have a mutable reference to iterate in the first place
                found = true;
                index = i;
                break;
            }
        }
        if found {
            Some(self.dice.remove(index))
        } else {
            None
        }
    }
    // size of holder
    pub fn size(&self) -> usize {
        self.dice.len()
    }
    // returns an array with the counts [red, yellow, blue, black]
    pub fn total_count(&self) -> [u32; 4] {
        [self.count("red"), self.count("yellow"), self.count("blue"), self.count("black")]
    }
}

// partialeq to compare variants
#[derive(Clone, PartialEq)]
pub enum Disease {
    Red,
    Yellow,
    Blue,
    Black,
}

impl Disease {
    // returns result of die roll - die weights from rule book
    // 0 signifies a CDC token
    pub fn roll(&self) -> u32 {
        let roll = rand::thread_rng().gen_range(0, 6);
        match *self {
            Disease::Red => {
                match roll {
                    0 => 0,
                    1 | 2 => 1,
                    3 => 4,
                    4 | 5 => 6,
                    _ => panic!("invalid random roll"),
                }
            }
            Disease::Yellow => {
                match roll {
                    0 => 0,
                    1 | 2 => 2,
                    3 => 4,
                    4 | 5 => 5,
                    _ => panic!("invalid random roll"),
                }
            }
            Disease::Blue => {
                match roll {
                    0 => 0,
                    1 => 1,
                    2 => 2,
                    3 => 3,
                    4 | 5 => 6,
                    _ => panic!("invalid random roll"),
                }
            }
            Disease::Black => {
                match roll {
                    0 => 0,
                    1 | 2 | 3 => 3,
                    4 => 4,
                    5 => 5,
                    _ => panic!("invalid random roll"),
                }
            }
        }
    }
}

pub struct GameModel {
    pub continents: Vec<Continent>,
    pub cdc: DiceHolder,
    pub treatment_center: DiceHolder,
    pub infection_bag: DiceHolder,
}

impl GameModel {
    pub fn new() -> GameModel {
        let mut ret = GameModel {
            continents: Vec::new(),
            cdc: DiceHolder::new(),
            treatment_center: DiceHolder::new(),
            infection_bag: DiceHolder::new(),
        };
        // 6 continents
        for i in 1..7 {
            ret.continents.push(Continent::new(i));
        }
        // 12 of each color in bag
        for _ in 0..12 {
            ret.infection_bag.add(Disease::Red);
            ret.infection_bag.add(Disease::Yellow);
            ret.infection_bag.add(Disease::Blue);
            ret.infection_bag.add(Disease::Black);
        }
        ret
    }
    pub fn initial_infect(&mut self) {
        let mut dice: Vec<Disease> = Vec::new();
        // grab 12 random
        for _ in 0..12 {
            dice.push(self.infection_bag.grab().expect("grab failed during initial_infect"));
        }
        // roll and place
        for i in &dice {
            let mut roll = 0;
            // roll until we don't get a zero
            while roll == 0 {
                roll = i.roll();
            }
            let result = match *i {
                ref i => i.clone(),
            };
            self.continents[roll as usize - 1].add(result);
        }
    }
}
<commit_msg>remove dumb match statement altogether<commit_after>extern crate rand;
use rand::Rng;

pub struct Continent {
    pub id: u32,
    pub diseases: DiceHolder,
}

impl Continent {
    pub fn new(id: u32) -> Continent {
        Continent {
            id: id,
            diseases: DiceHolder::new(),
        }
    }
    // adds Disease d to the DiceHolder
    pub fn add(&mut self, d: Disease) {
        self.diseases.add(d);
    }
    pub fn total_count(&self) -> [u32; 4] {
        self.diseases.total_count()
    }
}

pub struct DiceHolder {
    dice: Vec<Disease>,
}

impl DiceHolder {
    pub fn new() -> DiceHolder {
        DiceHolder { dice: Vec::new() }
    }
    // add a Disease to the holder
    pub fn add(&mut self, d: Disease) {
        self.dice.push(d);
    }
    // return number of given color
    pub fn count(&self, color: &str) -> u32 {
        let mut count = 0;
        match color {
            "red" | "Red" => {
                for i in &self.dice {
                    match *i {
                        Disease::Red => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "yellow" | "Yellow" => {
                for i in &self.dice {
                    match *i {
                        Disease::Yellow => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "blue" | "Blue" => {
                for i in &self.dice {
                    match *i {
                        Disease::Blue => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            "black" | "Black" => {
                for i in &self.dice {
                    match *i {
                        Disease::Black => count += 1,
                        _ => continue,
                    }
                }
                count
            }
            _ => 0,
        }
    }
    // grab random die, remove and return it
    pub fn grab(&mut self) -> Option<Disease> {
        if self.size() == 0 {
            None
        } else {
            // try randomly until we hit a color that exists
            loop {
                let color = match rand::thread_rng().gen_range(0, 4) {
                    0 => Disease::Red,
                    1 => Disease::Yellow,
                    2 => Disease::Blue,
                    3 => Disease::Black,
                    _ => panic!("Check disease.grab() something's fucked"),
                };
                match self.remove(color) {
                    Some(color) => return Some(color),
                    None => continue,
                }
            }
        }
    }
    // remove and return an Option with the Disease specified - TODO: make this less gross
    // i'm fighting the borrow checker, not working with it
    pub fn remove(&mut self, d: Disease) -> Option<Disease> {
        // grab first die that matches
        let mut found: bool = false;
        let mut index: usize = 0;
        for (i, elem) in self.dice.iter_mut().enumerate() {
            if elem == &d {
                // TODO: cont. i'd like to be able to just return the Option from here
                // but already have a mutable reference to iterate in the first place
                found = true;
                index = i;
                break;
            }
        }
        if found {
            Some(self.dice.remove(index))
        } else {
            None
        }
    }
    // size of holder
    pub fn size(&self) -> usize {
        self.dice.len()
    }
    // returns an array with the counts [red, yellow, blue, black]
    pub fn total_count(&self) -> [u32; 4] {
        [self.count("red"), self.count("yellow"), self.count("blue"), self.count("black")]
    }
}

// partialeq to compare variants
#[derive(Clone, PartialEq)]
pub enum Disease {
    Red,
    Yellow,
    Blue,
    Black,
}

impl Disease {
    // returns result of die roll - die weights from rule book
    // 0 signifies a CDC token
    pub fn roll(&self) -> u32 {
        let roll = rand::thread_rng().gen_range(0, 6);
        match *self {
            Disease::Red => {
                match roll {
                    0 => 0,
                    1 | 2 => 1,
                    3 => 4,
                    4 | 5 => 6,
                    _ => panic!("invalid random roll"),
                }
            }
            Disease::Yellow => {
                match roll {
                    0 => 0,
                    1 | 2 => 2,
                    3 => 4,
                    4 | 5 => 5,
                    _ => panic!("invalid random roll"),
                }
            }
            Disease::Blue => {
                match roll {
                    0 => 0,
                    1 => 1,
                    2 => 2,
                    3 => 3,
                    4 | 5 => 6,
                    _ => panic!("invalid random roll"),
                }
            }
            Disease::Black => {
                match roll {
                    0 => 0,
                    1 | 2 | 3 => 3,
                    4 => 4,
                    5 => 5,
                    _ => panic!("invalid random roll"),
                }
            }
        }
    }
}

pub struct GameModel {
    pub continents: Vec<Continent>,
    pub cdc: DiceHolder,
    pub treatment_center: DiceHolder,
    pub infection_bag: DiceHolder,
}

impl GameModel {
    pub fn new() -> GameModel {
        let mut ret = GameModel {
            continents: Vec::new(),
            cdc: DiceHolder::new(),
            treatment_center: DiceHolder::new(),
            infection_bag: DiceHolder::new(),
        };
        // 6 continents
        for i in 1..7 {
            ret.continents.push(Continent::new(i));
        }
        // 12 of each color in bag
        for _ in 0..12 {
            ret.infection_bag.add(Disease::Red);
            ret.infection_bag.add(Disease::Yellow);
            ret.infection_bag.add(Disease::Blue);
            ret.infection_bag.add(Disease::Black);
        }
        ret
    }
    pub fn initial_infect(&mut self) {
        let mut dice: Vec<Disease> = Vec::new();
        // grab 12 random
        for _ in 0..12 {
            dice.push(self.infection_bag.grab().expect("grab failed during initial_infect"));
        }
        // roll and place
        for i in &dice {
            let mut roll = 0;
            // roll until we don't get a zero
            while roll == 0 {
                roll = i.roll();
            }
            self.continents[roll as usize - 1].add(i.clone());
        }
    }
}
<|endoftext|>


<commit_before><commit_msg>Add mix, mix_scalar, mix_vec, lerp, lerp_scalar, lerp_vec.<commit_after><|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An implementation of base index with most common features.
// spell-checker:ignore subprefix

use std::borrow::Cow;
use std::marker::PhantomData;

use super::{StorageKey, StorageValue, Snapshot, Fork, Iter};

/// Basic struct for all indices that implements common features.
///
/// This structure is not intended for direct use, rather it is the basis for building other types
/// of indices.
///
/// `BaseIndex` requires that the keys implement the [`StorageKey`] trait and the values implement
/// [`StorageValue`] trait. However, this structure is not bound to specific types and allows the
/// use of *any* types as keys or values.
/// [`StorageKey`]: ../trait.StorageKey.html
/// [`StorageValue`]: ../trait.StorageValue.html
#[derive(Debug)]
pub struct BaseIndex<T> {
    name: String,
    prefix: Option<Vec<u8>>,
    view: T,
}

/// An iterator over the entries of a `BaseIndex`.
///
/// This struct is created by the [`iter`] or
/// [`iter_from`] methods on [`BaseIndex`]. See its documentation for more.
///
/// [`iter`]: struct.BaseIndex.html#method.iter
/// [`iter_from`]: struct.BaseIndex.html#method.iter_from
/// [`BaseIndex`]: struct.BaseIndex.html
pub struct BaseIndexIter<'a, K, V> {
    base_iter: Iter<'a>,
    base_prefix_len: usize,
    prefix: Vec<u8>,
    ended: bool,
    _k: PhantomData<K>,
    _v: PhantomData<V>,
}

impl<T> BaseIndex<T> {
    /// Creates a new index representation based on the name and storage view.
    ///
    /// Storage view can be specified as [`&Snapshot`] or [`&mut Fork`]. In the first case only
    /// immutable methods are available. In the second case both immutable and mutable methods are
    /// available.
    /// [`&Snapshot`]: ../trait.Snapshot.html
    /// [`&mut Fork`]: ../struct.Fork.html
    pub fn new<S: AsRef<str>>(name: S, view: T) -> Self {
        assert_valid_name(&name);

        BaseIndex {
            name: name.as_ref().to_string(),
            prefix: None,
            view,
        }
    }

    /// Creates a new index representation based on the name, common prefix of its keys
    /// and storage view.
    ///
    /// Storage view can be specified as [`&Snapshot`] or [`&mut Fork`]. In the first case only
    /// immutable methods are available. In the second case both immutable and mutable methods are
    /// available.
    /// [`&Snapshot`]: ../trait.Snapshot.html
    /// [`&mut Fork`]: ../struct.Fork.html
    pub fn with_prefix<S: AsRef<str>>(name: S, prefix: Vec<u8>, view: T) -> Self {
        assert_valid_name(&name);

        BaseIndex {
            name: name.as_ref().to_string(),
            prefix: Some(prefix),
            view,
        }
    }

    fn prefixed_key<K: StorageKey + ?Sized>(&self, key: &K) -> Vec<u8> {
        match self.prefix {
            Some(ref prefix) => {
                let mut v = vec![0; prefix.len() + key.size()];
                v[..prefix.len()].copy_from_slice(prefix);
                key.write(&mut v[prefix.len()..]);
                v
            }
            None => {
                let mut v = vec![0; key.size()];
                key.write(&mut v);
                v
            }
        }
    }
}

impl<T> BaseIndex<T>
where
    T: AsRef<Snapshot>,
{
    /// Returns a value of *any* type corresponding to the key of *any* type.
    pub fn get<K, V>(&self, key: &K) -> Option<V>
    where
        K: StorageKey + ?Sized,
        V: StorageValue,
    {
        self.view
            .as_ref()
            .get(&self.name, &self.prefixed_key(key))
            .map(|v| StorageValue::from_bytes(Cow::Owned(v)))
    }

    /// Returns `true` if the index contains a value of *any* type for the specified key of
    /// *any* type.
    pub fn contains<K>(&self, key: &K) -> bool
    where
        K: StorageKey + ?Sized,
    {
        self.view.as_ref().contains(
            &self.name,
            &self.prefixed_key(key),
        )
    }

    /// Returns an iterator over the entries of the index in ascending order. The iterator element
    /// type is *any* key-value pair. An argument `subprefix` allows to specify a subset of keys
    /// for iteration.
    pub fn iter<P, K, V>(&self, subprefix: &P) -> BaseIndexIter<K, V>
    where
        P: StorageKey,
        K: StorageKey,
        V: StorageValue,
    {
        let iter_prefix = self.prefixed_key(subprefix);
        BaseIndexIter {
            base_iter: self.view.as_ref().iter(&self.name, &iter_prefix),
            base_prefix_len: self.prefix.as_ref().map_or(0, |p| p.len()),
            prefix: iter_prefix,
            ended: false,
            _k: PhantomData,
            _v: PhantomData,
        }
    }

    /// Returns an iterator over the entries of the index in ascending order starting from the
    /// specified key. The iterator element type is *any* key-value pair. An argument `subprefix`
    /// allows to specify a subset of iteration.
    pub fn iter_from<P, F, K, V>(&self, subprefix: &P, from: &F) -> BaseIndexIter<K, V>
    where
        P: StorageKey,
        F: StorageKey + ?Sized,
        K: StorageKey,
        V: StorageValue,
    {
        let iter_prefix = self.prefixed_key(subprefix);
        let iter_from = self.prefixed_key(from);
        BaseIndexIter {
            base_iter: self.view.as_ref().iter(&self.name, &iter_from),
            base_prefix_len: self.prefix.as_ref().map_or(0, |p| p.len()),
            prefix: iter_prefix,
            ended: false,
            _k: PhantomData,
            _v: PhantomData,
        }
    }
}

impl<'a> BaseIndex<&'a mut Fork> {
    /// Inserts the key-value pair into the index. Both key and value may be of *any* types.
    pub fn put<K, V>(&mut self, key: &K, value: V)
    where
        K: StorageKey,
        V: StorageValue,
    {
        let key = self.prefixed_key(key);
        self.view.put(&self.name, key, value.into_bytes());
    }

    /// Removes the key of *any* type from the index.
    pub fn remove<K>(&mut self, key: &K)
    where
        K: StorageKey + ?Sized,
    {
        let key = self.prefixed_key(key);
        self.view.remove(&self.name, key);
    }

    /// Clears the index, removing entries with keys that starts with a prefix or all entries
    /// if `prefix` is `None`.
    ///
    /// # Notes
    ///
    /// Currently this method is not optimized to delete large set of data. During the execution of
    /// this method the amount of allocated memory is linearly dependent on the number of elements
    /// in the index.
    pub fn clear(&mut self) {
        self.view.remove_by_prefix(&self.name, self.prefix.as_ref());
    }
}

impl<'a, K, V> Iterator for BaseIndexIter<'a, K, V>
where
    K: StorageKey,
    V: StorageValue,
{
    type Item = (K::Owned, V);

    fn next(&mut self) -> Option<Self::Item> {
        if self.ended {
            return None;
        }
        if let Some((k, v)) = self.base_iter.next() {
            if k.starts_with(&self.prefix) {
                return Some((
                    K::read(&k[self.base_prefix_len..]),
                    V::from_bytes(Cow::Borrowed(v)),
                ));
            }
        }
        self.ended = true;
        None
    }
}

impl<'a, K, V> ::std::fmt::Debug for BaseIndexIter<'a, K, V> {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "BaseIndexIter(..)")
    }
}

/// A function that validates an index name. Allowable characters in name: ASCII characters, digits
/// and underscores.
fn is_valid_name<S: AsRef<str>>(name: S) -> bool {
    name.as_ref().as_bytes().iter().all(|c| match *c {
        48...57 | 65...90 | 97...122 | 95 | 46 => true,
        _ => false,
    })
}

/// Calls the `is_valid_name` function with the given name and panics if it returns `false`.
fn assert_valid_name<S: AsRef<str>>(name: S) {
    if !is_valid_name(name) {
        panic!("Wrong characters using in name. Use: a-zA-Z0-9 and _");
    }
}

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

    static INDEX_NAME: &str = "test_index_name";

    #[test]
    fn test_index_name_validator() {
        // spell-checker:disable
        assert!(is_valid_name("index_name"));
        assert!(is_valid_name("_index_name"));
        assert!(is_valid_name("AinDex_name_"));
        assert!(is_valid_name("core.index_name1Z"));
        assert!(is_valid_name("configuration.indeX_1namE"));
        assert!(is_valid_name("1index_Namez"));

        assert!(!is_valid_name("index-name"));
        assert!(!is_valid_name("_index-name"));
        assert!(!is_valid_name("индекс_name_"));
        assert!(!is_valid_name("core.index_имя3"));
        assert!(!is_valid_name("indeX_1namE-"));
        assert!(!is_valid_name("1in!dex_Namez"));
    }

    #[test]
    fn check_valid_name() {
        assert_valid_name("valid_name");
    }

    #[test]
    #[should_panic(expected = "Wrong characters using in name. Use: a-zA-Z0-9 and _")]
    fn check_invalid_name() {
        assert_valid_name("invalid-name");
    }
}
<commit_msg>Remove unused test static variable<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! An implementation of base index with most common features.
// spell-checker:ignore subprefix

use std::borrow::Cow;
use std::marker::PhantomData;

use super::{StorageKey, StorageValue, Snapshot, Fork, Iter};

/// Basic struct for all indices that implements common features.
///
/// This structure is not intended for direct use, rather it is the basis for building other types
/// of indices.
///
/// `BaseIndex` requires that the keys implement the [`StorageKey`] trait and the values implement
/// [`StorageValue`] trait. However, this structure is not bound to specific types and allows the
/// use of *any* types as keys or values.
/// [`StorageKey`]: ../trait.StorageKey.html
/// [`StorageValue`]: ../trait.StorageValue.html
#[derive(Debug)]
pub struct BaseIndex<T> {
    name: String,
    prefix: Option<Vec<u8>>,
    view: T,
}

/// An iterator over the entries of a `BaseIndex`.
///
/// This struct is created by the [`iter`] or
/// [`iter_from`] methods on [`BaseIndex`]. See its documentation for more.
///
/// [`iter`]: struct.BaseIndex.html#method.iter
/// [`iter_from`]: struct.BaseIndex.html#method.iter_from
/// [`BaseIndex`]: struct.BaseIndex.html
pub struct BaseIndexIter<'a, K, V> {
    base_iter: Iter<'a>,
    base_prefix_len: usize,
    prefix: Vec<u8>,
    ended: bool,
    _k: PhantomData<K>,
    _v: PhantomData<V>,
}

impl<T> BaseIndex<T> {
    /// Creates a new index representation based on the name and storage view.
    ///
    /// Storage view can be specified as [`&Snapshot`] or [`&mut Fork`]. In the first case only
    /// immutable methods are available. In the second case both immutable and mutable methods are
    /// available.
    /// [`&Snapshot`]: ../trait.Snapshot.html
    /// [`&mut Fork`]: ../struct.Fork.html
    pub fn new<S: AsRef<str>>(name: S, view: T) -> Self {
        assert_valid_name(&name);

        BaseIndex {
            name: name.as_ref().to_string(),
            prefix: None,
            view,
        }
    }

    /// Creates a new index representation based on the name, common prefix of its keys
    /// and storage view.
    ///
    /// Storage view can be specified as [`&Snapshot`] or [`&mut Fork`]. In the first case only
    /// immutable methods are available. In the second case both immutable and mutable methods are
    /// available.
    /// [`&Snapshot`]: ../trait.Snapshot.html
    /// [`&mut Fork`]: ../struct.Fork.html
    pub fn with_prefix<S: AsRef<str>>(name: S, prefix: Vec<u8>, view: T) -> Self {
        assert_valid_name(&name);

        BaseIndex {
            name: name.as_ref().to_string(),
            prefix: Some(prefix),
            view,
        }
    }

    fn prefixed_key<K: StorageKey + ?Sized>(&self, key: &K) -> Vec<u8> {
        match self.prefix {
            Some(ref prefix) => {
                let mut v = vec![0; prefix.len() + key.size()];
                v[..prefix.len()].copy_from_slice(prefix);
                key.write(&mut v[prefix.len()..]);
                v
            }
            None => {
                let mut v = vec![0; key.size()];
                key.write(&mut v);
                v
            }
        }
    }
}

impl<T> BaseIndex<T>
where
    T: AsRef<Snapshot>,
{
    /// Returns a value of *any* type corresponding to the key of *any* type.
    pub fn get<K, V>(&self, key: &K) -> Option<V>
    where
        K: StorageKey + ?Sized,
        V: StorageValue,
    {
        self.view
            .as_ref()
            .get(&self.name, &self.prefixed_key(key))
            .map(|v| StorageValue::from_bytes(Cow::Owned(v)))
    }

    /// Returns `true` if the index contains a value of *any* type for the specified key of
    /// *any* type.
    pub fn contains<K>(&self, key: &K) -> bool
    where
        K: StorageKey + ?Sized,
    {
        self.view.as_ref().contains(
            &self.name,
            &self.prefixed_key(key),
        )
    }

    /// Returns an iterator over the entries of the index in ascending order. The iterator element
    /// type is *any* key-value pair. An argument `subprefix` allows to specify a subset of keys
    /// for iteration.
    pub fn iter<P, K, V>(&self, subprefix: &P) -> BaseIndexIter<K, V>
    where
        P: StorageKey,
        K: StorageKey,
        V: StorageValue,
    {
        let iter_prefix = self.prefixed_key(subprefix);
        BaseIndexIter {
            base_iter: self.view.as_ref().iter(&self.name, &iter_prefix),
            base_prefix_len: self.prefix.as_ref().map_or(0, |p| p.len()),
            prefix: iter_prefix,
            ended: false,
            _k: PhantomData,
            _v: PhantomData,
        }
    }

    /// Returns an iterator over the entries of the index in ascending order starting from the
    /// specified key. The iterator element type is *any* key-value pair. An argument `subprefix`
    /// allows to specify a subset of iteration.
    pub fn iter_from<P, F, K, V>(&self, subprefix: &P, from: &F) -> BaseIndexIter<K, V>
    where
        P: StorageKey,
        F: StorageKey + ?Sized,
        K: StorageKey,
        V: StorageValue,
    {
        let iter_prefix = self.prefixed_key(subprefix);
        let iter_from = self.prefixed_key(from);
        BaseIndexIter {
            base_iter: self.view.as_ref().iter(&self.name, &iter_from),
            base_prefix_len: self.prefix.as_ref().map_or(0, |p| p.len()),
            prefix: iter_prefix,
            ended: false,
            _k: PhantomData,
            _v: PhantomData,
        }
    }
}

impl<'a> BaseIndex<&'a mut Fork> {
    /// Inserts the key-value pair into the index. Both key and value may be of *any* types.
    pub fn put<K, V>(&mut self, key: &K, value: V)
    where
        K: StorageKey,
        V: StorageValue,
    {
        let key = self.prefixed_key(key);
        self.view.put(&self.name, key, value.into_bytes());
    }

    /// Removes the key of *any* type from the index.
    pub fn remove<K>(&mut self, key: &K)
    where
        K: StorageKey + ?Sized,
    {
        let key = self.prefixed_key(key);
        self.view.remove(&self.name, key);
    }

    /// Clears the index, removing entries with keys that starts with a prefix or all entries
    /// if `prefix` is `None`.
    ///
    /// # Notes
    ///
    /// Currently this method is not optimized to delete large set of data. During the execution of
    /// this method the amount of allocated memory is linearly dependent on the number of elements
    /// in the index.
    pub fn clear(&mut self) {
        self.view.remove_by_prefix(&self.name, self.prefix.as_ref());
    }
}

impl<'a, K, V> Iterator for BaseIndexIter<'a, K, V>
where
    K: StorageKey,
    V: StorageValue,
{
    type Item = (K::Owned, V);

    fn next(&mut self) -> Option<Self::Item> {
        if self.ended {
            return None;
        }
        if let Some((k, v)) = self.base_iter.next() {
            if k.starts_with(&self.prefix) {
                return Some((
                    K::read(&k[self.base_prefix_len..]),
                    V::from_bytes(Cow::Borrowed(v)),
                ));
            }
        }
        self.ended = true;
        None
    }
}

impl<'a, K, V> ::std::fmt::Debug for BaseIndexIter<'a, K, V> {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "BaseIndexIter(..)")
    }
}

/// A function that validates an index name. Allowable characters in name: ASCII characters, digits
/// and underscores.
fn is_valid_name<S: AsRef<str>>(name: S) -> bool {
    name.as_ref().as_bytes().iter().all(|c| match *c {
        48...57 | 65...90 | 97...122 | 95 | 46 => true,
        _ => false,
    })
}

/// Calls the `is_valid_name` function with the given name and panics if it returns `false`.
fn assert_valid_name<S: AsRef<str>>(name: S) {
    if !is_valid_name(name) {
        panic!("Wrong characters using in name. Use: a-zA-Z0-9 and _");
    }
}

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

    #[test]
    fn test_index_name_validator() {
        // spell-checker:disable
        assert!(is_valid_name("index_name"));
        assert!(is_valid_name("_index_name"));
        assert!(is_valid_name("AinDex_name_"));
        assert!(is_valid_name("core.index_name1Z"));
        assert!(is_valid_name("configuration.indeX_1namE"));
        assert!(is_valid_name("1index_Namez"));

        assert!(!is_valid_name("index-name"));
        assert!(!is_valid_name("_index-name"));
        assert!(!is_valid_name("индекс_name_"));
        assert!(!is_valid_name("core.index_имя3"));
        assert!(!is_valid_name("indeX_1namE-"));
        assert!(!is_valid_name("1in!dex_Namez"));
    }

    #[test]
    fn check_valid_name() {
        assert_valid_name("valid_name");
    }

    #[test]
    #[should_panic(expected = "Wrong characters using in name. Use: a-zA-Z0-9 and _")]
    fn check_invalid_name() {
        assert_valid_name("invalid-name");
    }
}
<|endoftext|>


<commit_before>use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
use byteorder::{ByteOrder, LittleEndian};

#[derive(Debug)]
pub struct NtrSender {
    tcp_stream: TcpStream,
    current_seq: u32,
    is_heartbeat_sendable: bool,
}
impl NtrSender {
    pub fn new(tcp_stream: TcpStream) -> Self {
        NtrSender {
            tcp_stream: tcp_stream,
            current_seq: 1000,
            is_heartbeat_sendable: true,
        }
    }

    pub fn is_heartbeat_sendable(&self) -> bool {
        self.is_heartbeat_sendable
    }

    pub fn set_is_heartbeat_sendable(&mut self, b: bool) {
        self.is_heartbeat_sendable = b;
    }

    pub fn send_mem_read_packet(&mut self, addr: u32, size: u32, pid: u32) -> io::Result<usize> {
        self.send_empty_packet(9, pid, addr, size)
    }

    pub fn send_mem_write_packet(&mut self,
                                 addr: u32,
                                 pid: u32,
                                 buf: &[u8; 16])
                                 -> io::Result<usize> {
        let args = &mut [0u32; 16];
        args[0] = pid;
        args[1] = addr;
        args[2] = buf.len() as u32;
        try!(self.send_packet(1, 10, args, args[2]));
        self.tcp_stream.write(buf)
    }

    pub fn send_heartbeat_packet(&mut self) -> io::Result<usize> {
        self.send_packet(0, 0, &[0u32; 16], 0)
    }

    pub fn send_list_process_packet(&mut self) -> io::Result<usize> {
        self.send_empty_packet(5, 0, 0, 0)
    }

    fn send_packet(&mut self,
                   packet_type: u32,
                   cmd: u32,
                   args: &[u32; 16],
                   data_len: u32)
                   -> io::Result<usize> {
        let mut buf = [0u8; 84];

        LittleEndian::write_u32(&mut buf[0..4], 0x12345678);
        LittleEndian::write_u32(&mut buf[4..8], self.current_seq);
        LittleEndian::write_u32(&mut buf[8..12], packet_type);
        LittleEndian::write_u32(&mut buf[12..16], cmd);
        for (mut i, val) in args.iter().enumerate() {
            i = 4 * i + 16;
            LittleEndian::write_u32(&mut buf[i..(i + 4)], *val);
        }
        LittleEndian::write_u32(&mut buf[80..84], data_len);

        self.current_seq += 1000;
        self.tcp_stream.write(&buf)
    }

    fn send_empty_packet(&mut self,
                         cmd: u32,
                         arg0: u32,
                         arg1: u32,
                         arg2: u32)
                         -> io::Result<usize> {
        let mut args = [0u32; 16];
        args[0] = arg0;
        args[1] = arg1;
        args[2] = arg2;
        self.send_packet(0, cmd, &args, 0)
    }
}
<commit_msg>fix refactoring mistake<commit_after>use std::io;
use std::io::prelude::*;
use std::net::TcpStream;
use byteorder::{ByteOrder, LittleEndian};

#[derive(Debug)]
pub struct NtrSender {
    tcp_stream: TcpStream,
    current_seq: u32,
    is_heartbeat_sendable: bool,
}
impl NtrSender {
    pub fn new(tcp_stream: TcpStream) -> Self {
        NtrSender {
            tcp_stream: tcp_stream,
            current_seq: 1000,
            is_heartbeat_sendable: true,
        }
    }

    pub fn is_heartbeat_sendable(&self) -> bool {
        self.is_heartbeat_sendable
    }

    pub fn set_is_heartbeat_sendable(&mut self, b: bool) {
        self.is_heartbeat_sendable = b;
    }

    pub fn send_mem_read_packet(&mut self, addr: u32, size: u32, pid: u32) -> io::Result<usize> {
        self.send_empty_packet(9, pid, addr, size)
    }

    pub fn send_mem_write_packet(&mut self,
                                 addr: u32,
                                 pid: u32,
                                 buf: &[u8])
                                 -> io::Result<usize> {
        let args = &mut [0u32; 16];
        args[0] = pid;
        args[1] = addr;
        args[2] = buf.len() as u32;
        try!(self.send_packet(1, 10, args, args[2]));
        self.tcp_stream.write(buf)
    }

    pub fn send_heartbeat_packet(&mut self) -> io::Result<usize> {
        self.send_packet(0, 0, &[0u32; 16], 0)
    }

    pub fn send_list_process_packet(&mut self) -> io::Result<usize> {
        self.send_empty_packet(5, 0, 0, 0)
    }

    fn send_packet(&mut self,
                   packet_type: u32,
                   cmd: u32,
                   args: &[u32; 16],
                   data_len: u32)
                   -> io::Result<usize> {
        let mut buf = [0u8; 84];

        LittleEndian::write_u32(&mut buf[0..4], 0x12345678);
        LittleEndian::write_u32(&mut buf[4..8], self.current_seq);
        LittleEndian::write_u32(&mut buf[8..12], packet_type);
        LittleEndian::write_u32(&mut buf[12..16], cmd);
        for (mut i, val) in args.iter().enumerate() {
            i = 4 * i + 16;
            LittleEndian::write_u32(&mut buf[i..(i + 4)], *val);
        }
        LittleEndian::write_u32(&mut buf[80..84], data_len);

        self.current_seq += 1000;
        self.tcp_stream.write(&buf)
    }

    fn send_empty_packet(&mut self,
                         cmd: u32,
                         arg0: u32,
                         arg1: u32,
                         arg2: u32)
                         -> io::Result<usize> {
        let mut args = [0u32; 16];
        args[0] = arg0;
        args[1] = arg1;
        args[2] = arg2;
        self.send_packet(0, cmd, &args, 0)
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.
use std::fmt::{Display, Formatter};

/// An error type for failures that can occur during a session.
#[derive(Debug)]
pub enum Error {
    /// Action-specific failure.
    Action(Box<dyn std::error::Error>),
    /// Attempted to call an unknown or not implemented action.
    Dispatch(String),
    /// An error occurred when encoding bytes of a proto message.
    Encode(prost::EncodeError),
    /// An error occurred when parsing a proto message.
    Parse(ParseError),
}

impl Error {

    /// Converts an arbitrary action-issued error to a session error.
    ///
    /// This function should be used to construct session errors from action
    /// specific error types and propagate them further in the session pipeline.
    pub fn action<E>(error: E) -> Error
    where
        E: std::error::Error + 'static
    {
        Error::Action(Box::new(error))
    }
}

impl Display for Error {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            Action(ref error) => {
                write!(fmt, "action error: {}", error)
            }
            Dispatch(ref name) if name.is_empty() => {
                write!(fmt, "missing action")
            }
            Dispatch(ref name) => {
                write!(fmt, "unknown action: {}", name)
            }
            Encode(ref error) => {
                write!(fmt, "failure during encoding proto message: {}", error)
            }
            Parse(ref error) => {
                write!(fmt, "malformed proto message: {}", error)
            }
        }
    }
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            Action(ref error) => Some(error.as_ref()),
            Dispatch(_) => None,
            Encode(ref error) => Some(error),
            Parse(ref error) => Some(error),
        }
    }
}

impl From<prost::EncodeError> for Error {

    fn from(error: prost::EncodeError) -> Error {
        Error::Encode(error)
    }
}

impl From<ParseError> for Error {

    fn from(error: ParseError) -> Error {
        Error::Parse(error)
    }
}

/// An error type for failures that can occur when parsing proto messages.
#[derive(Debug)]
pub enum ParseError {
    Malformed(Box<dyn std::error::Error + Send + Sync>),
    /// An error occurred when decoding bytes of a proto message.
    Decode(prost::DecodeError),
}

impl ParseError {

    pub fn malformed<E>(error: E) -> ParseError
    where
        E: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        ParseError::Malformed(error.into())
    }

    pub fn missing_field(name: &'static str) -> ParseError {
        // TODO: A custom error type for missing field errors could be created
        // to avoid allocating a string.
        let error = format!("required field '{}' is missing", name);
        ParseError::malformed(error)
    }
}

impl Display for ParseError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use ParseError::*;

        match *self {
            Malformed(ref error) => {
                write!(fmt, "invalid proto message: {}", error)
            }
            Decode(ref error) => {
                write!(fmt, "failed to decode proto message: {}", error)
            }
        }
    }
}

impl std::error::Error for ParseError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use ParseError::*;

        match *self {
            Malformed(ref error) => Some(error.as_ref()),
            Decode(ref error) => Some(error),
        }
    }
}

impl From<prost::DecodeError> for ParseError {

    fn from(error: prost::DecodeError) -> ParseError {
        ParseError::Decode(error)
    }
}
<commit_msg>Add missing doc comments for parse error items.<commit_after>// Copyright 2020 Google LLC
//
// Use of this source code is governed by an MIT-style license that can be found
// in the LICENSE file or at https://opensource.org/licenses/MIT.
use std::fmt::{Display, Formatter};

/// An error type for failures that can occur during a session.
#[derive(Debug)]
pub enum Error {
    /// Action-specific failure.
    Action(Box<dyn std::error::Error>),
    /// Attempted to call an unknown or not implemented action.
    Dispatch(String),
    /// An error occurred when encoding bytes of a proto message.
    Encode(prost::EncodeError),
    /// An error occurred when parsing a proto message.
    Parse(ParseError),
}

impl Error {

    /// Converts an arbitrary action-issued error to a session error.
    ///
    /// This function should be used to construct session errors from action
    /// specific error types and propagate them further in the session pipeline.
    pub fn action<E>(error: E) -> Error
    where
        E: std::error::Error + 'static
    {
        Error::Action(Box::new(error))
    }
}

impl Display for Error {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use Error::*;

        match *self {
            Action(ref error) => {
                write!(fmt, "action error: {}", error)
            }
            Dispatch(ref name) if name.is_empty() => {
                write!(fmt, "missing action")
            }
            Dispatch(ref name) => {
                write!(fmt, "unknown action: {}", name)
            }
            Encode(ref error) => {
                write!(fmt, "failure during encoding proto message: {}", error)
            }
            Parse(ref error) => {
                write!(fmt, "malformed proto message: {}", error)
            }
        }
    }
}

impl std::error::Error for Error {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use Error::*;

        match *self {
            Action(ref error) => Some(error.as_ref()),
            Dispatch(_) => None,
            Encode(ref error) => Some(error),
            Parse(ref error) => Some(error),
        }
    }
}

impl From<prost::EncodeError> for Error {

    fn from(error: prost::EncodeError) -> Error {
        Error::Encode(error)
    }
}

impl From<ParseError> for Error {

    fn from(error: ParseError) -> Error {
        Error::Parse(error)
    }
}

/// An error type for failures that can occur when parsing proto messages.
#[derive(Debug)]
pub enum ParseError {
    /// An error occurred because the decoded proto message was malformed.
    Malformed(Box<dyn std::error::Error + Send + Sync>),
    /// An error occurred when decoding bytes of a proto message.
    Decode(prost::DecodeError),
}

impl ParseError {

    /// Converts a detailed error indicating a malformed proto to `ParseError`.
    ///
    /// This is just a convenience function for lifting custom error types that
    /// contain more specific information to generic `ParseError`.
    pub fn malformed<E>(error: E) -> ParseError
    where
        E: Into<Box<dyn std::error::Error + Send + Sync>>,
    {
        ParseError::Malformed(error.into())
    }

    /// Creates `ParseError` indicating that required field `name` is missing.
    pub fn missing_field(name: &'static str) -> ParseError {
        // TODO: A custom error type for missing field errors could be created
        // to avoid allocating a string.
        let error = format!("required field '{}' is missing", name);
        ParseError::malformed(error)
    }
}

impl Display for ParseError {

    fn fmt(&self, fmt: &mut Formatter) -> std::fmt::Result {
        use ParseError::*;

        match *self {
            Malformed(ref error) => {
                write!(fmt, "invalid proto message: {}", error)
            }
            Decode(ref error) => {
                write!(fmt, "failed to decode proto message: {}", error)
            }
        }
    }
}

impl std::error::Error for ParseError {

    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        use ParseError::*;

        match *self {
            Malformed(ref error) => Some(error.as_ref()),
            Decode(ref error) => Some(error),
        }
    }
}

impl From<prost::DecodeError> for ParseError {

    fn from(error: prost::DecodeError) -> ParseError {
        ParseError::Decode(error)
    }
}
<|endoftext|>


<commit_before>use {Future, Poll, Async};
use stream::Stream;

/// A combinator used to temporarily convert a stream into a future.
///
/// This future is returned by the `Stream::into_future` method.
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct StreamFuture<S> {
    stream: Option<S>,
}

pub fn new<S: Stream>(s: S) -> StreamFuture<S> {
    StreamFuture { stream: Some(s) }
}

impl<S> StreamFuture<S> {
    /// Acquires a reference to the underlying stream that this combinator is
    /// pulling from.
    ///
    /// This method returns an `Option` to account for the fact that `StreamFuture`'s
    /// implementation of `Future::poll` consumes the underlying stream during polling
    /// in order to return it to the caller of `Future::poll` if the stream yieleded
    /// an element.
    pub fn get_ref(&self) -> Option<&S> {
        self.stream.as_ref()
    }

    /// Acquires a mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    ///
    /// This method returns an `Option` to account for the fact that `StreamFuture`'s
    /// implementation of `Future::poll` consumes the underlying stream during polling
    /// in order to return it to the caller of `Future::poll` if the stream yieleded
    /// an element.
    pub fn get_mut(&mut self) -> Option<&mut S> {
        self.stream.as_mut()
    }

    /// Consumes this combinator, returning the underlying stream.
    ///
    /// Note that this may discard intermediate state of this combinator, so
    /// care should be taken to avoid losing resources when this is called.
    ///
    /// This method returns an `Option` to account for the fact that `StreamFuture`'s
    /// implementation of `Future::poll` consumes the underlying stream during polling
    /// in order to return it to the caller of `Future::poll` if the stream yieleded
    /// an element.
    pub fn into_inner(self) -> Option<S> {
        self.stream
    }
}

impl<S: Stream> Future for StreamFuture<S> {
    type Item = (Option<S::Item>, S);
    type Error = (S::Error, S);

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let item = {
            let s = self.stream.as_mut().expect("polling StreamFuture twice");
            match s.poll() {
                Ok(Async::NotReady) => return Ok(Async::NotReady),
                Ok(Async::Ready(e)) => Ok(e),
                Err(e) => Err(e),
            }
        };
        let stream = self.stream.take().unwrap();
        match item {
            Ok(e) => Ok(Async::Ready((e, stream))),
            Err(e) => Err((e, stream)),
        }
    }
}
<commit_msg>fix typos in comments<commit_after>use {Future, Poll, Async};
use stream::Stream;

/// A combinator used to temporarily convert a stream into a future.
///
/// This future is returned by the `Stream::into_future` method.
#[derive(Debug)]
#[must_use = "futures do nothing unless polled"]
pub struct StreamFuture<S> {
    stream: Option<S>,
}

pub fn new<S: Stream>(s: S) -> StreamFuture<S> {
    StreamFuture { stream: Some(s) }
}

impl<S> StreamFuture<S> {
    /// Acquires a reference to the underlying stream that this combinator is
    /// pulling from.
    ///
    /// This method returns an `Option` to account for the fact that `StreamFuture`'s
    /// implementation of `Future::poll` consumes the underlying stream during polling
    /// in order to return it to the caller of `Future::poll` if the stream yielded
    /// an element.
    pub fn get_ref(&self) -> Option<&S> {
        self.stream.as_ref()
    }

    /// Acquires a mutable reference to the underlying stream that this
    /// combinator is pulling from.
    ///
    /// Note that care must be taken to avoid tampering with the state of the
    /// stream which may otherwise confuse this combinator.
    ///
    /// This method returns an `Option` to account for the fact that `StreamFuture`'s
    /// implementation of `Future::poll` consumes the underlying stream during polling
    /// in order to return it to the caller of `Future::poll` if the stream yielded
    /// an element.
    pub fn get_mut(&mut self) -> Option<&mut S> {
        self.stream.as_mut()
    }

    /// Consumes this combinator, returning the underlying stream.
    ///
    /// Note that this may discard intermediate state of this combinator, so
    /// care should be taken to avoid losing resources when this is called.
    ///
    /// This method returns an `Option` to account for the fact that `StreamFuture`'s
    /// implementation of `Future::poll` consumes the underlying stream during polling
    /// in order to return it to the caller of `Future::poll` if the stream yielded
    /// an element.
    pub fn into_inner(self) -> Option<S> {
        self.stream
    }
}

impl<S: Stream> Future for StreamFuture<S> {
    type Item = (Option<S::Item>, S);
    type Error = (S::Error, S);

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let item = {
            let s = self.stream.as_mut().expect("polling StreamFuture twice");
            match s.poll() {
                Ok(Async::NotReady) => return Ok(Async::NotReady),
                Ok(Async::Ready(e)) => Ok(e),
                Err(e) => Err(e),
            }
        };
        let stream = self.stream.take().unwrap();
        match item {
            Ok(e) => Ok(Async::Ready((e, stream))),
            Err(e) => Err((e, stream)),
        }
    }
}
<|endoftext|>


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

#[macro_use]
extern crate log;

use env_logger;
use simpleservo::{
    self, gl_glue, Coordinates, EventLoopWaker, HostTrait, InitOptions, ServoGlue, SERVO,
};
use std::ffi::{CStr, CString};
use std::mem;
use std::os::raw::{c_char, c_void};

fn call<F>(f: F)
where
    F: Fn(&mut ServoGlue) -> Result<(), &'static str>,
{
    SERVO.with(|s| {
        if let Err(error) = match s.borrow_mut().as_mut() {
            Some(ref mut s) => (f)(s),
            None => Err("Servo not available in this thread"),
        } {
            // FIXME: All C calls should have a have generic Result-like
            // return type. For now, we just panic instead of notifying
            // the embedder.
            panic!(error);
        }
    });
}

/// Callback used by Servo internals
#[repr(C)]
pub struct CHostCallbacks {
    pub flush: extern "C" fn(),
    pub make_current: extern "C" fn(),
    pub on_load_started: extern "C" fn(),
    pub on_load_ended: extern "C" fn(),
    pub on_title_changed: extern "C" fn(title: *const c_char),
    pub on_url_changed: extern "C" fn(url: *const c_char),
    pub on_history_changed: extern "C" fn(can_go_back: bool, can_go_forward: bool),
    pub on_animating_changed: extern "C" fn(animating: bool),
    pub on_shutdown_complete: extern "C" fn(),
    pub on_ime_state_changed: extern "C" fn(show: bool),
}

/// Servo options
#[repr(C)]
pub struct CInitOptions {
    pub args: *const c_char,
    pub url: *const c_char,
    pub width: i32,
    pub height: i32,
    pub density: f32,
    pub vr_pointer: *mut c_void,
    pub enable_subpixel_text_antialiasing: bool,
}

/// The returned string is not freed. This will leak.
#[no_mangle]
pub extern "C" fn servo_version() -> *const c_char {
    let v = simpleservo::servo_version();
    let text = CString::new(v).expect("Can't create string");
    let ptr = text.as_ptr();
    mem::forget(text);
    ptr
}

fn init(
    opts: CInitOptions,
    gl: gl_glue::ServoGl,
    wakeup: extern "C" fn(),
    callbacks: CHostCallbacks,
) {
    crate::env_logger::init();

    let args = unsafe { CStr::from_ptr(opts.args) };
    let args = args
        .to_str()
        .unwrap_or("")
        .split(' ')
        .map(|s| s.to_owned())
        .collect();

    let url = unsafe { CStr::from_ptr(opts.url) };
    let url = url.to_str().map(|s| s.to_string()).ok();

    let coordinates = Coordinates::new(0, 0, opts.width, opts.height, opts.width, opts.height);

    let opts = InitOptions {
        args,
        url,
        coordinates,
        density: opts.density,
        vr_pointer: if opts.vr_pointer.is_null() {
            None
        } else {
            Some(opts.vr_pointer)
        },
        enable_subpixel_text_antialiasing: opts.enable_subpixel_text_antialiasing,
    };

    let wakeup = Box::new(WakeupCallback::new(wakeup));
    let callbacks = Box::new(HostCallbacks::new(callbacks));

    simpleservo::init(opts, gl, wakeup, callbacks).unwrap();
}

#[cfg(target_os = "windows")]
#[no_mangle]
pub extern "C" fn init_with_egl(
    opts: CInitOptions,
    wakeup: extern "C" fn(),
    callbacks: CHostCallbacks,
) {
    let gl = gl_glue::egl::init().unwrap();
    init(opts, gl, wakeup, callbacks)
}

#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
#[no_mangle]
pub extern "C" fn init_with_gl(
    opts: CInitOptions,
    wakeup: extern "C" fn(),
    callbacks: CHostCallbacks,
) {
    let gl = gl_glue::gl::init().unwrap();
    init(opts, gl, wakeup, callbacks)
}

#[no_mangle]
pub extern "C" fn deinit() {
    debug!("deinit");
    simpleservo::deinit();
}

#[no_mangle]
pub extern "C" fn request_shutdown() {
    debug!("request_shutdown");
    call(|s| s.request_shutdown());
}

#[no_mangle]
pub extern "C" fn set_batch_mode(batch: bool) {
    debug!("set_batch_mode");
    call(|s| s.set_batch_mode(batch));
}

#[no_mangle]
pub extern "C" fn resize(width: i32, height: i32) {
    debug!("resize {}/{}", width, height);
    call(|s| {
        let coordinates = Coordinates::new(0, 0, width, height, width, height);
        s.resize(coordinates)
    });
}

#[no_mangle]
pub extern "C" fn perform_updates() {
    debug!("perform_updates");
    call(|s| s.perform_updates());
}

#[no_mangle]
pub extern "C" fn load_uri(url: *const c_char) {
    debug!("load_url");
    let url = unsafe { CStr::from_ptr(url) };
    let url = url.to_str().expect("Can't read string");
    call(|s| s.load_uri(url));
}

#[no_mangle]
pub extern "C" fn reload() {
    debug!("reload");
    call(|s| s.reload());
}

#[no_mangle]
pub extern "C" fn stop() {
    debug!("stop");
    call(|s| s.stop());
}

#[no_mangle]
pub extern "C" fn refresh() {
    debug!("refresh");
    call(|s| s.refresh());
}

#[no_mangle]
pub extern "C" fn go_back() {
    debug!("go_back");
    call(|s| s.go_back());
}

#[no_mangle]
pub extern "C" fn go_forward() {
    debug!("go_forward");
    call(|s| s.go_forward());
}

#[no_mangle]
pub extern "C" fn scroll_start(dx: i32, dy: i32, x: i32, y: i32) {
    debug!("scroll_start");
    call(|s| s.scroll_start(dx as f32, dy as f32, x, y));
}

#[no_mangle]
pub extern "C" fn scroll_end(dx: i32, dy: i32, x: i32, y: i32) {
    debug!("scroll_end");
    call(|s| s.scroll_end(dx as f32, dy as f32, x, y));
}

#[no_mangle]
pub extern "C" fn scroll(dx: i32, dy: i32, x: i32, y: i32) {
    debug!("scroll");
    call(|s| s.scroll(dx as f32, dy as f32, x, y));
}

#[no_mangle]
pub extern "C" fn touch_down(x: f32, y: f32, pointer_id: i32) {
    debug!("touch down");
    call(|s| s.touch_down(x, y, pointer_id));
}

#[no_mangle]
pub extern "C" fn touch_up(x: f32, y: f32, pointer_id: i32) {
    debug!("touch up");
    call(|s| s.touch_up(x, y, pointer_id));
}

#[no_mangle]
pub extern "C" fn touch_move(x: f32, y: f32, pointer_id: i32) {
    debug!("touch move");
    call(|s| s.touch_move(x, y, pointer_id));
}

#[no_mangle]
pub extern "C" fn touch_cancel(x: f32, y: f32, pointer_id: i32) {
    debug!("touch cancel");
    call(|s| s.touch_cancel(x, y, pointer_id));
}

#[no_mangle]
pub extern "C" fn pinchzoom_start(factor: f32, x: i32, y: i32) {
    debug!("pinchzoom_start");
    call(|s| s.pinchzoom_start(factor, x as u32, y as u32));
}

#[no_mangle]
pub extern "C" fn pinchzoom(factor: f32, x: i32, y: i32) {
    debug!("pinchzoom");
    call(|s| s.pinchzoom(factor, x as u32, y as u32));
}

#[no_mangle]
pub extern "C" fn pinchzoom_end(factor: f32, x: i32, y: i32) {
    debug!("pinchzoom_end");
    call(|s| s.pinchzoom_end(factor, x as u32, y as u32));
}

#[no_mangle]
pub extern "C" fn click(x: i32, y: i32) {
    debug!("click");
    call(|s| s.click(x as f32, y as f32));
}

pub struct WakeupCallback(extern "C" fn());

impl WakeupCallback {
    fn new(callback: extern "C" fn()) -> WakeupCallback {
        WakeupCallback(callback)
    }
}

impl EventLoopWaker for WakeupCallback {
    fn clone(&self) -> Box<dyn EventLoopWaker + Send> {
        Box::new(WakeupCallback(self.0))
    }
    fn wake(&self) {
        (self.0)();
    }
}

struct HostCallbacks(CHostCallbacks);

impl HostCallbacks {
    fn new(callback: CHostCallbacks) -> HostCallbacks {
        HostCallbacks(callback)
    }
}

impl HostTrait for HostCallbacks {
    fn flush(&self) {
        debug!("flush");
        (self.0.flush)();
    }

    fn make_current(&self) {
        debug!("make_current");
        (self.0.make_current)();
    }

    fn on_load_started(&self) {
        debug!("on_load_ended");
        (self.0.on_load_started)();
    }

    fn on_load_ended(&self) {
        debug!("on_load_ended");
        (self.0.on_load_ended)();
    }

    fn on_title_changed(&self, title: String) {
        debug!("on_title_changed");
        let title = CString::new(title).expect("Can't create string");
        let title_ptr = title.as_ptr();
        mem::forget(title);
        (self.0.on_title_changed)(title_ptr);
    }

    fn on_url_changed(&self, url: String) {
        debug!("on_url_changed");
        let url = CString::new(url).expect("Can't create string");
        let url_ptr = url.as_ptr();
        mem::forget(url);
        (self.0.on_url_changed)(url_ptr);
    }

    fn on_history_changed(&self, can_go_back: bool, can_go_forward: bool) {
        debug!("on_history_changed");
        (self.0.on_history_changed)(can_go_back, can_go_forward);
    }

    fn on_animating_changed(&self, animating: bool) {
        debug!("on_animating_changed");
        (self.0.on_animating_changed)(animating);
    }

    fn on_shutdown_complete(&self) {
        debug!("on_shutdown_complete");
        (self.0.on_shutdown_complete)();
    }

    fn on_ime_state_changed(&self, show: bool) {
        debug!("on_ime_state_changed");
        (self.0.on_ime_state_changed)(show);
    }
}
<commit_msg>handle null args<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

#[macro_use]
extern crate log;

use env_logger;
use simpleservo::{
    self, gl_glue, Coordinates, EventLoopWaker, HostTrait, InitOptions, ServoGlue, SERVO,
};
use std::ffi::{CStr, CString};
use std::mem;
use std::os::raw::{c_char, c_void};

fn call<F>(f: F)
where
    F: Fn(&mut ServoGlue) -> Result<(), &'static str>,
{
    SERVO.with(|s| {
        if let Err(error) = match s.borrow_mut().as_mut() {
            Some(ref mut s) => (f)(s),
            None => Err("Servo not available in this thread"),
        } {
            // FIXME: All C calls should have a have generic Result-like
            // return type. For now, we just panic instead of notifying
            // the embedder.
            panic!(error);
        }
    });
}

/// Callback used by Servo internals
#[repr(C)]
pub struct CHostCallbacks {
    pub flush: extern "C" fn(),
    pub make_current: extern "C" fn(),
    pub on_load_started: extern "C" fn(),
    pub on_load_ended: extern "C" fn(),
    pub on_title_changed: extern "C" fn(title: *const c_char),
    pub on_url_changed: extern "C" fn(url: *const c_char),
    pub on_history_changed: extern "C" fn(can_go_back: bool, can_go_forward: bool),
    pub on_animating_changed: extern "C" fn(animating: bool),
    pub on_shutdown_complete: extern "C" fn(),
    pub on_ime_state_changed: extern "C" fn(show: bool),
}

/// Servo options
#[repr(C)]
pub struct CInitOptions {
    pub args: *const c_char,
    pub url: *const c_char,
    pub width: i32,
    pub height: i32,
    pub density: f32,
    pub vr_pointer: *mut c_void,
    pub enable_subpixel_text_antialiasing: bool,
}

/// The returned string is not freed. This will leak.
#[no_mangle]
pub extern "C" fn servo_version() -> *const c_char {
    let v = simpleservo::servo_version();
    let text = CString::new(v).expect("Can't create string");
    let ptr = text.as_ptr();
    mem::forget(text);
    ptr
}

fn init(
    opts: CInitOptions,
    gl: gl_glue::ServoGl,
    wakeup: extern "C" fn(),
    callbacks: CHostCallbacks,
) {
    crate::env_logger::init();

    let args = if !opts.args.is_null() {
        let args = unsafe { CStr::from_ptr(opts.args) };
        args.to_str()
            .unwrap_or("")
            .split(' ')
            .map(|s| s.to_owned())
            .collect()
    } else {
        vec![]
    };

    let url = unsafe { CStr::from_ptr(opts.url) };
    let url = url.to_str().map(|s| s.to_string()).ok();

    let coordinates = Coordinates::new(0, 0, opts.width, opts.height, opts.width, opts.height);

    let opts = InitOptions {
        args,
        url,
        coordinates,
        density: opts.density,
        vr_pointer: if opts.vr_pointer.is_null() {
            None
        } else {
            Some(opts.vr_pointer)
        },
        enable_subpixel_text_antialiasing: opts.enable_subpixel_text_antialiasing,
    };

    let wakeup = Box::new(WakeupCallback::new(wakeup));
    let callbacks = Box::new(HostCallbacks::new(callbacks));

    simpleservo::init(opts, gl, wakeup, callbacks).unwrap();
}

#[cfg(target_os = "windows")]
#[no_mangle]
pub extern "C" fn init_with_egl(
    opts: CInitOptions,
    wakeup: extern "C" fn(),
    callbacks: CHostCallbacks,
) {
    let gl = gl_glue::egl::init().unwrap();
    init(opts, gl, wakeup, callbacks)
}

#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
#[no_mangle]
pub extern "C" fn init_with_gl(
    opts: CInitOptions,
    wakeup: extern "C" fn(),
    callbacks: CHostCallbacks,
) {
    let gl = gl_glue::gl::init().unwrap();
    init(opts, gl, wakeup, callbacks)
}

#[no_mangle]
pub extern "C" fn deinit() {
    debug!("deinit");
    simpleservo::deinit();
}

#[no_mangle]
pub extern "C" fn request_shutdown() {
    debug!("request_shutdown");
    call(|s| s.request_shutdown());
}

#[no_mangle]
pub extern "C" fn set_batch_mode(batch: bool) {
    debug!("set_batch_mode");
    call(|s| s.set_batch_mode(batch));
}

#[no_mangle]
pub extern "C" fn resize(width: i32, height: i32) {
    debug!("resize {}/{}", width, height);
    call(|s| {
        let coordinates = Coordinates::new(0, 0, width, height, width, height);
        s.resize(coordinates)
    });
}

#[no_mangle]
pub extern "C" fn perform_updates() {
    debug!("perform_updates");
    call(|s| s.perform_updates());
}

#[no_mangle]
pub extern "C" fn load_uri(url: *const c_char) {
    debug!("load_url");
    let url = unsafe { CStr::from_ptr(url) };
    let url = url.to_str().expect("Can't read string");
    call(|s| s.load_uri(url));
}

#[no_mangle]
pub extern "C" fn reload() {
    debug!("reload");
    call(|s| s.reload());
}

#[no_mangle]
pub extern "C" fn stop() {
    debug!("stop");
    call(|s| s.stop());
}

#[no_mangle]
pub extern "C" fn refresh() {
    debug!("refresh");
    call(|s| s.refresh());
}

#[no_mangle]
pub extern "C" fn go_back() {
    debug!("go_back");
    call(|s| s.go_back());
}

#[no_mangle]
pub extern "C" fn go_forward() {
    debug!("go_forward");
    call(|s| s.go_forward());
}

#[no_mangle]
pub extern "C" fn scroll_start(dx: i32, dy: i32, x: i32, y: i32) {
    debug!("scroll_start");
    call(|s| s.scroll_start(dx as f32, dy as f32, x, y));
}

#[no_mangle]
pub extern "C" fn scroll_end(dx: i32, dy: i32, x: i32, y: i32) {
    debug!("scroll_end");
    call(|s| s.scroll_end(dx as f32, dy as f32, x, y));
}

#[no_mangle]
pub extern "C" fn scroll(dx: i32, dy: i32, x: i32, y: i32) {
    debug!("scroll");
    call(|s| s.scroll(dx as f32, dy as f32, x, y));
}

#[no_mangle]
pub extern "C" fn touch_down(x: f32, y: f32, pointer_id: i32) {
    debug!("touch down");
    call(|s| s.touch_down(x, y, pointer_id));
}

#[no_mangle]
pub extern "C" fn touch_up(x: f32, y: f32, pointer_id: i32) {
    debug!("touch up");
    call(|s| s.touch_up(x, y, pointer_id));
}

#[no_mangle]
pub extern "C" fn touch_move(x: f32, y: f32, pointer_id: i32) {
    debug!("touch move");
    call(|s| s.touch_move(x, y, pointer_id));
}

#[no_mangle]
pub extern "C" fn touch_cancel(x: f32, y: f32, pointer_id: i32) {
    debug!("touch cancel");
    call(|s| s.touch_cancel(x, y, pointer_id));
}

#[no_mangle]
pub extern "C" fn pinchzoom_start(factor: f32, x: i32, y: i32) {
    debug!("pinchzoom_start");
    call(|s| s.pinchzoom_start(factor, x as u32, y as u32));
}

#[no_mangle]
pub extern "C" fn pinchzoom(factor: f32, x: i32, y: i32) {
    debug!("pinchzoom");
    call(|s| s.pinchzoom(factor, x as u32, y as u32));
}

#[no_mangle]
pub extern "C" fn pinchzoom_end(factor: f32, x: i32, y: i32) {
    debug!("pinchzoom_end");
    call(|s| s.pinchzoom_end(factor, x as u32, y as u32));
}

#[no_mangle]
pub extern "C" fn click(x: i32, y: i32) {
    debug!("click");
    call(|s| s.click(x as f32, y as f32));
}

pub struct WakeupCallback(extern "C" fn());

impl WakeupCallback {
    fn new(callback: extern "C" fn()) -> WakeupCallback {
        WakeupCallback(callback)
    }
}

impl EventLoopWaker for WakeupCallback {
    fn clone(&self) -> Box<dyn EventLoopWaker + Send> {
        Box::new(WakeupCallback(self.0))
    }
    fn wake(&self) {
        (self.0)();
    }
}

struct HostCallbacks(CHostCallbacks);

impl HostCallbacks {
    fn new(callback: CHostCallbacks) -> HostCallbacks {
        HostCallbacks(callback)
    }
}

impl HostTrait for HostCallbacks {
    fn flush(&self) {
        debug!("flush");
        (self.0.flush)();
    }

    fn make_current(&self) {
        debug!("make_current");
        (self.0.make_current)();
    }

    fn on_load_started(&self) {
        debug!("on_load_ended");
        (self.0.on_load_started)();
    }

    fn on_load_ended(&self) {
        debug!("on_load_ended");
        (self.0.on_load_ended)();
    }

    fn on_title_changed(&self, title: String) {
        debug!("on_title_changed");
        let title = CString::new(title).expect("Can't create string");
        let title_ptr = title.as_ptr();
        mem::forget(title);
        (self.0.on_title_changed)(title_ptr);
    }

    fn on_url_changed(&self, url: String) {
        debug!("on_url_changed");
        let url = CString::new(url).expect("Can't create string");
        let url_ptr = url.as_ptr();
        mem::forget(url);
        (self.0.on_url_changed)(url_ptr);
    }

    fn on_history_changed(&self, can_go_back: bool, can_go_forward: bool) {
        debug!("on_history_changed");
        (self.0.on_history_changed)(can_go_back, can_go_forward);
    }

    fn on_animating_changed(&self, animating: bool) {
        debug!("on_animating_changed");
        (self.0.on_animating_changed)(animating);
    }

    fn on_shutdown_complete(&self) {
        debug!("on_shutdown_complete");
        (self.0.on_shutdown_complete)();
    }

    fn on_ime_state_changed(&self, show: bool) {
        debug!("on_ime_state_changed");
        (self.0.on_ime_state_changed)(show);
    }
}
<|endoftext|>


<commit_before>use crate::discord_client::{CommandHandler, DiscordClient};
use serenity::{
    client,
    model::{channel::Message, gateway::Ready},
    prelude::*,
};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;

pub struct SerenityDiscordClient {
    serenity_client: Arc<Mutex<Client>>,
    command_callbacks: Arc<Mutex<HashMap<String, Box<CommandHandler + Send>>>>,
}

struct SerenityDiscordHandler {
    command_callbacks: Arc<Mutex<HashMap<String, Box<CommandHandler + Send>>>>,
    command_prefix: &'static str,
}

impl DiscordClient for SerenityDiscordClient {
    fn new(token: &str) -> Self {
        println!("valid token: {}", client::validate_token(token).is_ok());

        let command_callbacks = Arc::new(Mutex::new(HashMap::new()));
        let serenity_handler = SerenityDiscordHandler {
            command_callbacks: command_callbacks.clone(),
            command_prefix: "!", //TODO: make this configurable in case of clashes with other bots
        };

        let serenity_client =
            Arc::new(Mutex::new(Client::new(token, serenity_handler).expect("Error creating serenity client")));
        println!("created client");

        let thread_serenity_client = serenity_client.clone();
        thread::spawn( move || {
            if let Err(why) = thread_serenity_client.lock().unwrap().start() {
                println!("An error occurred while running the client: {:?}", why);
            }
        });
        println!("started connection");

        SerenityDiscordClient {
            serenity_client: serenity_client.clone(),
            command_callbacks: command_callbacks.clone(),
        }
    }

    fn register_command<T>(&self, command: &str, command_handler: T) -> Result<(), Box<std::error::Error>>
    where
        T: CommandHandler + Send + 'static,
    {
        if self
            .command_callbacks
            .lock()
            .unwrap()
            .insert(command.to_string(), Box::new(command_handler))
            .is_some()
        {
            panic!("command was entered twice for {}", command);
        }
        Ok(())
    }
}

impl EventHandler for SerenityDiscordHandler {
    fn message(&self, ctx: Context, msg: Message) {
        //TODO: clean this up and split it out into more functions?
        if msg.content.starts_with(self.command_prefix) {
            if let Some(command) = msg.content.split_whitespace().nth(0) {
                if let Some(command) = command.chars().next().map(|c| &command[c.len_utf8()..]) {
                    if let Some(command_handler) =
                        self.command_callbacks.lock().unwrap().get(command)
                    {
                        if let Err(err) = command_handler.process_command(command, &|output| {
                            if let Err(err) = msg.channel_id.say(&ctx.http, output) {
                                println!("Error sending message: {:?}", err);
                            }
                        }) {
                            println!("Error processing command: {:?}", err);
                        }
                    };
                };
            };
        }
    }

    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}
<commit_msg>Fixes bug in pic command where query params were not parsed<commit_after>use crate::discord_client::{CommandHandler, DiscordClient};
use serenity::{
    client,
    model::{channel::Message, gateway::Ready},
    prelude::*,
};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::thread;

pub struct SerenityDiscordClient {
    serenity_client: Arc<Mutex<Client>>,
    command_callbacks: Arc<Mutex<HashMap<String, Box<CommandHandler + Send>>>>,
}

struct SerenityDiscordHandler {
    command_callbacks: Arc<Mutex<HashMap<String, Box<CommandHandler + Send>>>>,
    command_prefix: &'static str,
}

impl DiscordClient for SerenityDiscordClient {
    fn new(token: &str) -> Self {
        println!("valid token: {}", client::validate_token(token).is_ok());

        let command_callbacks = Arc::new(Mutex::new(HashMap::new()));
        let serenity_handler = SerenityDiscordHandler {
            command_callbacks: command_callbacks.clone(),
            command_prefix: "!", //TODO: make this configurable in case of clashes with other bots
        };

        let serenity_client =
            Arc::new(Mutex::new(Client::new(token, serenity_handler).expect("Error creating serenity client")));
        println!("created client");

        let thread_serenity_client = serenity_client.clone();
        thread::spawn( move || {
            if let Err(why) = thread_serenity_client.lock().unwrap().start() {
                println!("An error occurred while running the client: {:?}", why);
            }
        });
        println!("started connection");

        SerenityDiscordClient {
            serenity_client: serenity_client.clone(),
            command_callbacks: command_callbacks.clone(),
        }
    }

    fn register_command<T>(&self, command: &str, command_handler: T) -> Result<(), Box<std::error::Error>>
    where
        T: CommandHandler + Send + 'static,
    {
        if self
            .command_callbacks
            .lock()
            .unwrap()
            .insert(command.to_string(), Box::new(command_handler))
            .is_some()
        {
            panic!("command was entered twice for {}", command);
        }
        Ok(())
    }
}

impl EventHandler for SerenityDiscordHandler {
    fn message(&self, ctx: Context, msg: Message) {
        //TODO: clean this up and split it out into more functions?
        if msg.content.starts_with(self.command_prefix) {
            if let Some(command) = msg.content.split_whitespace().nth(0) {
                if let Some(command) = command.chars().next().map(|c| &command[c.len_utf8()..]) {
                    if let Some(command_handler) =
                        self.command_callbacks.lock().unwrap().get(command)
                    {
                        if let Err(err) = command_handler.process_command(&msg.content, &|output| {
                            if let Err(err) = msg.channel_id.say(&ctx.http, output) {
                                println!("Error sending message: {:?}", err);
                            }
                        }) {
                            println!("Error processing command: {:?}", err);
                        }
                    };
                };
            };
        }
    }

    fn ready(&self, _: Context, ready: Ready) {
        println!("{} is connected!", ready.user.name);
    }
}
<|endoftext|>


<commit_before>use clap::{App, AppSettings, Arg, Shell, SubCommand};

pub fn build_cli() -> App<'static, 'static> {
    let database_arg = Arg::with_name("DATABASE_URL")
        .long("database-url")
        .help(
            "Specifies the database URL to connect to. Falls back to \
             the DATABASE_URL environment variable if unspecified.",
        )
        .global(true)
        .takes_value(true);

    let migration_subcommand = SubCommand::with_name("migration")
        .about(
            "A group of commands for generating, running, and reverting \
             migrations.",
        )
        .setting(AppSettings::VersionlessSubcommands)
        .arg(migration_dir_arg())
        .subcommand(SubCommand::with_name("run").about("Runs all pending migrations"))
        .subcommand(SubCommand::with_name("revert").about("Reverts the latest run migration"))
        .subcommand(SubCommand::with_name("redo").about(
            "Reverts and re-runs the latest migration. Useful \
             for testing that a migration can in fact be reverted.",
        ))
        .subcommand(
            SubCommand::with_name("list")
                .about("Lists all available migrations, marking those that have been applied."),
        )
        .subcommand(
            SubCommand::with_name("pending")
                .about("Returns true if there are any pending migrations."),
        )
        .subcommand(
            SubCommand::with_name("generate")
                .about(
                    "Generate a new migration with the given name, and \
                     the current timestamp as the version",
                )
                .arg(
                    Arg::with_name("MIGRATION_NAME")
                        .help("The name of the migration to create")
                        .required(true),
                )
                .arg(
                    Arg::with_name("MIGRATION_VERSION")
                        .long("version")
                        .help(
                            "The version number to use when generating the migration. \
                             Defaults to the current timestamp, which should suffice \
                             for most use cases.",
                        )
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("MIGRATION_FORMAT")
                        .long("format")
                        .possible_values(&["sql", "barrel"])
                        .default_value("sql")
                        .takes_value(true)
                        .help("The format of the migration to be generated."),
                ),
        )
        .setting(AppSettings::SubcommandRequiredElseHelp);

    let setup_subcommand = SubCommand::with_name("setup")
        .arg(migration_dir_arg())
        .about(
            "Creates the migrations directory, creates the database \
             specified in your DATABASE_URL, and runs existing migrations.",
        );

    let database_subcommand = SubCommand::with_name("database")
        .alias("db")
        .arg(migration_dir_arg())
        .about("A group of commands for setting up and resetting your database.")
        .setting(AppSettings::VersionlessSubcommands)
        .subcommand(SubCommand::with_name("setup").about(
            "Creates the database specified in your DATABASE_URL, \
             and then runs any existing migrations.",
        ))
        .subcommand(SubCommand::with_name("reset").about(
            "Resets your database by dropping the database specified \
             in your DATABASE_URL and then running `diesel database setup`.",
        ))
        .subcommand(
            SubCommand::with_name("drop")
                .about("Drops the database specified in your DATABASE_URL.")
                .setting(AppSettings::Hidden),
        )
        .setting(AppSettings::SubcommandRequiredElseHelp);

    let generate_bash_completion_subcommand = SubCommand::with_name("bash-completion")
        .about("DEPRECATED: Generate bash completion script for the diesel command.");

    let generate_completions_subcommand = SubCommand::with_name("completions")
        .about("Generate shell completion scripts for the diesel command.")
        .arg(
            Arg::with_name("SHELL")
                .index(1)
                .required(true)
                .possible_values(&Shell::variants()),
        );

    let infer_schema_subcommand = SubCommand::with_name("print-schema")
        .setting(AppSettings::VersionlessSubcommands)
        .about("Print table definitions for database schema.")
        .arg(
            Arg::with_name("schema")
                .long("schema")
                .short("s")
                .takes_value(true)
                .help("The name of the schema."),
        )
        .arg(
            Arg::with_name("table-name")
                .index(1)
                .takes_value(true)
                .multiple(true)
                .help("Table names to filter (default only-tables if not empty)"),
        )
        .arg(
            Arg::with_name("only-tables")
                .short("o")
                .long("only-tables")
                .help("Only include tables from table-name")
                .conflicts_with("only-table-regexes")
                .conflicts_with("except-tables")
                .conflicts_with("except-table-regexes")
                .conflicts_with("blacklist"),
        )
        .arg(
            Arg::with_name("only-table-regexes")
                .long("only-table-regexes")
                .help("Only include tables from table-name that matches regexp")
                .conflicts_with("only-tables")
                .conflicts_with("whitelist")
                .conflicts_with("except-tables")
                .conflicts_with("except-table-regexes")
                .conflicts_with("blacklist"),
        )
        .arg(
            Arg::with_name("whitelist")
                .short("w")
                .long("whitelist")
                .hidden(true)
                .conflicts_with("only-table-regexes")
                .conflicts_with("blacklist")
                .conflicts_with("except-tables")
                .conflicts_with("except-table-regexes"),
        )
        .arg(
            Arg::with_name("except-tables")
                .short("e")
                .long("except-tables")
                .help("Exclude tables from table-name")
                .conflicts_with("only-tables")
                .conflicts_with("only-table-regexes")
                .conflicts_with("whitelist")
                .conflicts_with("except-table-regexes"),
        )
        .arg(
            Arg::with_name("except-tables-regexes")
                .long("except-tables-regexes")
                .help("Exclude tables from table-name that matches regex")
                .conflicts_with("only-tables")
                .conflicts_with("whitelist")
                .conflicts_with("only-table-regexes")
                .conflicts_with("except-tables")
                .conflicts_with("blacklist"),
        )
        .arg(
            Arg::with_name("blacklist")
                .short("b")
                .long("blacklist")
                .hidden(true)
                .conflicts_with("whitelist")
                .conflicts_with("only-tables")
                .conflicts_with("only-table-regexes")
                .conflicts_with("except-table-regexes"),
        )
        .arg(
            Arg::with_name("with-docs")
                .long("with-docs")
                .help("Render documentation comments for tables and columns"),
        )
        .arg(
            Arg::with_name("patch-file")
                .long("patch-file")
                .takes_value(true)
                .help("A unified diff file to be applied to the final schema"),
        )
        .arg(
            Arg::with_name("import-types")
                .long("import-types")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .help("A list of types to import for every table, separated by commas"),
        );

    let config_arg = Arg::with_name("CONFIG_FILE")
        .long("config-file")
        .help(
            "The location of the configuration file to use. Falls back to the \
             `DIESEL_CONFIG_FILE` environment variable if unspecified. Defaults \
             to `diesel.toml` in your project root. See \
             diesel.rs/guides/configuring-diesel-cli for documentation on this file.",
        )
        .global(true)
        .takes_value(true);

    let locked_schema_arg = Arg::with_name("LOCKED_SCHEMA")
        .long("locked-schema")
        .help("Require that the schema file is up to date")
        .long_help(
            "When `print_schema.file` is specified in your config file, this \
             flag will cause Diesel CLI to error if any command would result in \
             changes to that file. It is recommended that you use this flag when \
             running migrations in CI or production.",
        )
        .global(true);

    App::new("diesel")
        .version(env!("CARGO_PKG_VERSION"))
        .setting(AppSettings::VersionlessSubcommands)
        .after_help(
            "You can also run `diesel SUBCOMMAND -h` to get more information about that subcommand.",
        )
        .arg(database_arg)
        .arg(config_arg)
        .arg(locked_schema_arg)
        .subcommand(migration_subcommand)
        .subcommand(setup_subcommand)
        .subcommand(database_subcommand)
        .subcommand(generate_bash_completion_subcommand)
        .subcommand(generate_completions_subcommand)
        .subcommand(infer_schema_subcommand)
        .setting(AppSettings::SubcommandRequiredElseHelp)
}

fn migration_dir_arg<'a, 'b>() -> Arg<'a, 'b> {
    Arg::with_name("MIGRATION_DIRECTORY")
        .long("migration-dir")
        .help(
            "The location of your migration directory. By default this \
             will look for a directory called `migrations` in the \
             current directory and its parents.",
        )
        .takes_value(true)
        .global(true)
}
<commit_msg>fix typo<commit_after>use clap::{App, AppSettings, Arg, Shell, SubCommand};

pub fn build_cli() -> App<'static, 'static> {
    let database_arg = Arg::with_name("DATABASE_URL")
        .long("database-url")
        .help(
            "Specifies the database URL to connect to. Falls back to \
             the DATABASE_URL environment variable if unspecified.",
        )
        .global(true)
        .takes_value(true);

    let migration_subcommand = SubCommand::with_name("migration")
        .about(
            "A group of commands for generating, running, and reverting \
             migrations.",
        )
        .setting(AppSettings::VersionlessSubcommands)
        .arg(migration_dir_arg())
        .subcommand(SubCommand::with_name("run").about("Runs all pending migrations"))
        .subcommand(SubCommand::with_name("revert").about("Reverts the latest run migration"))
        .subcommand(SubCommand::with_name("redo").about(
            "Reverts and re-runs the latest migration. Useful \
             for testing that a migration can in fact be reverted.",
        ))
        .subcommand(
            SubCommand::with_name("list")
                .about("Lists all available migrations, marking those that have been applied."),
        )
        .subcommand(
            SubCommand::with_name("pending")
                .about("Returns true if there are any pending migrations."),
        )
        .subcommand(
            SubCommand::with_name("generate")
                .about(
                    "Generate a new migration with the given name, and \
                     the current timestamp as the version",
                )
                .arg(
                    Arg::with_name("MIGRATION_NAME")
                        .help("The name of the migration to create")
                        .required(true),
                )
                .arg(
                    Arg::with_name("MIGRATION_VERSION")
                        .long("version")
                        .help(
                            "The version number to use when generating the migration. \
                             Defaults to the current timestamp, which should suffice \
                             for most use cases.",
                        )
                        .takes_value(true),
                )
                .arg(
                    Arg::with_name("MIGRATION_FORMAT")
                        .long("format")
                        .possible_values(&["sql", "barrel"])
                        .default_value("sql")
                        .takes_value(true)
                        .help("The format of the migration to be generated."),
                ),
        )
        .setting(AppSettings::SubcommandRequiredElseHelp);

    let setup_subcommand = SubCommand::with_name("setup")
        .arg(migration_dir_arg())
        .about(
            "Creates the migrations directory, creates the database \
             specified in your DATABASE_URL, and runs existing migrations.",
        );

    let database_subcommand = SubCommand::with_name("database")
        .alias("db")
        .arg(migration_dir_arg())
        .about("A group of commands for setting up and resetting your database.")
        .setting(AppSettings::VersionlessSubcommands)
        .subcommand(SubCommand::with_name("setup").about(
            "Creates the database specified in your DATABASE_URL, \
             and then runs any existing migrations.",
        ))
        .subcommand(SubCommand::with_name("reset").about(
            "Resets your database by dropping the database specified \
             in your DATABASE_URL and then running `diesel database setup`.",
        ))
        .subcommand(
            SubCommand::with_name("drop")
                .about("Drops the database specified in your DATABASE_URL.")
                .setting(AppSettings::Hidden),
        )
        .setting(AppSettings::SubcommandRequiredElseHelp);

    let generate_bash_completion_subcommand = SubCommand::with_name("bash-completion")
        .about("DEPRECATED: Generate bash completion script for the diesel command.");

    let generate_completions_subcommand = SubCommand::with_name("completions")
        .about("Generate shell completion scripts for the diesel command.")
        .arg(
            Arg::with_name("SHELL")
                .index(1)
                .required(true)
                .possible_values(&Shell::variants()),
        );

    let infer_schema_subcommand = SubCommand::with_name("print-schema")
        .setting(AppSettings::VersionlessSubcommands)
        .about("Print table definitions for database schema.")
        .arg(
            Arg::with_name("schema")
                .long("schema")
                .short("s")
                .takes_value(true)
                .help("The name of the schema."),
        )
        .arg(
            Arg::with_name("table-name")
                .index(1)
                .takes_value(true)
                .multiple(true)
                .help("Table names to filter (default only-tables if not empty)"),
        )
        .arg(
            Arg::with_name("only-tables")
                .short("o")
                .long("only-tables")
                .help("Only include tables from table-name")
                .conflicts_with("only-table-regexes")
                .conflicts_with("except-tables")
                .conflicts_with("except-table-regexes")
                .conflicts_with("blacklist"),
        )
        .arg(
            Arg::with_name("only-table-regexes")
                .long("only-table-regexes")
                .help("Only include tables from table-name that matches regexp")
                .conflicts_with("only-tables")
                .conflicts_with("whitelist")
                .conflicts_with("except-tables")
                .conflicts_with("except-table-regexes")
                .conflicts_with("blacklist"),
        )
        .arg(
            Arg::with_name("whitelist")
                .short("w")
                .long("whitelist")
                .hidden(true)
                .conflicts_with("only-table-regexes")
                .conflicts_with("blacklist")
                .conflicts_with("except-tables")
                .conflicts_with("except-table-regexes"),
        )
        .arg(
            Arg::with_name("except-tables")
                .short("e")
                .long("except-tables")
                .help("Exclude tables from table-name")
                .conflicts_with("only-tables")
                .conflicts_with("only-table-regexes")
                .conflicts_with("whitelist")
                .conflicts_with("except-table-regexes"),
        )
        .arg(
            Arg::with_name("except-table-regexes")
                .long("except-table-regexes")
                .help("Exclude tables from table-name that matches regex")
                .conflicts_with("only-tables")
                .conflicts_with("whitelist")
                .conflicts_with("only-table-regexes")
                .conflicts_with("except-tables")
                .conflicts_with("blacklist"),
        )
        .arg(
            Arg::with_name("blacklist")
                .short("b")
                .long("blacklist")
                .hidden(true)
                .conflicts_with("whitelist")
                .conflicts_with("only-tables")
                .conflicts_with("only-table-regexes")
                .conflicts_with("except-table-regexes"),
        )
        .arg(
            Arg::with_name("with-docs")
                .long("with-docs")
                .help("Render documentation comments for tables and columns"),
        )
        .arg(
            Arg::with_name("patch-file")
                .long("patch-file")
                .takes_value(true)
                .help("A unified diff file to be applied to the final schema"),
        )
        .arg(
            Arg::with_name("import-types")
                .long("import-types")
                .takes_value(true)
                .multiple(true)
                .number_of_values(1)
                .help("A list of types to import for every table, separated by commas"),
        );

    let config_arg = Arg::with_name("CONFIG_FILE")
        .long("config-file")
        .help(
            "The location of the configuration file to use. Falls back to the \
             `DIESEL_CONFIG_FILE` environment variable if unspecified. Defaults \
             to `diesel.toml` in your project root. See \
             diesel.rs/guides/configuring-diesel-cli for documentation on this file.",
        )
        .global(true)
        .takes_value(true);

    let locked_schema_arg = Arg::with_name("LOCKED_SCHEMA")
        .long("locked-schema")
        .help("Require that the schema file is up to date")
        .long_help(
            "When `print_schema.file` is specified in your config file, this \
             flag will cause Diesel CLI to error if any command would result in \
             changes to that file. It is recommended that you use this flag when \
             running migrations in CI or production.",
        )
        .global(true);

    App::new("diesel")
        .version(env!("CARGO_PKG_VERSION"))
        .setting(AppSettings::VersionlessSubcommands)
        .after_help(
            "You can also run `diesel SUBCOMMAND -h` to get more information about that subcommand.",
        )
        .arg(database_arg)
        .arg(config_arg)
        .arg(locked_schema_arg)
        .subcommand(migration_subcommand)
        .subcommand(setup_subcommand)
        .subcommand(database_subcommand)
        .subcommand(generate_bash_completion_subcommand)
        .subcommand(generate_completions_subcommand)
        .subcommand(infer_schema_subcommand)
        .setting(AppSettings::SubcommandRequiredElseHelp)
}

fn migration_dir_arg<'a, 'b>() -> Arg<'a, 'b> {
    Arg::with_name("MIGRATION_DIRECTORY")
        .long("migration-dir")
        .help(
            "The location of your migration directory. By default this \
             will look for a directory called `migrations` in the \
             current directory and its parents.",
        )
        .takes_value(true)
        .global(true)
}
<|endoftext|>