<commit_before>use hand::BJHand;
use bjaction::BJAction;
use bjaction::HIT;
use bjaction::STAND;
use bjaction::DOUBLE;
use bjaction::SURRENDER;
use bjaction::SPLIT;
use cards::card::Card;
use cards::value::VALUES;
use cards::value::ACE;
use cards::value::KING;
use cards::value::QUEEN;
use cards::value::JACK;
use cards::value::TEN;
use rules::BJRules;
use shoe::shoe::DirectShoe;
use shoe::randomshoe::SuitPicker;

pub trait ActionCalculator {
    fn expected_value(&self, h: &mut BJHand, dealer_up_card: &Card,
                      d: &mut DirectShoe, action: BJAction,
                      rules: &BJRules) -> Option<f64>;
    fn expected_with_dealer(&self, player_hand: &BJHand, dealer_hand: &mut BJHand,
                            d: &mut DirectShoe, rules: &BJRules) -> Option<f64>;
    fn expected_value_best_action(&self, hand: &mut BJHand, dealer_up_card: &Card,
                      d: &mut DirectShoe,
                      rules: &BJRules) -> f64;
}

pub struct ActionCalculatorImpl;

impl ActionCalculator for ActionCalculatorImpl {
    fn expected_value_best_action(&self, hand: &mut BJHand, dealer_up_card: &Card,
                      d: &mut DirectShoe,
                      rules: &BJRules) -> f64 {
        if hand.score() > 21 {
            // Bust... loose bet
            return -1.0;
        }
        let actions = vec![HIT, DOUBLE, SPLIT, SURRENDER];
        let mut best_result = match self.expected_value(
                hand, dealer_up_card, d, STAND, rules) {
            Some(s) => s,
            None => panic!("You should always be able to stand"),
        };
        for &a in actions.iter() {
            match self.expected_value(hand, dealer_up_card, d, a, rules) {
                Some(r) => {
                    if best_result < r {
                        best_result = r;
                    }
                }
                _ => {}
            }
        }
        return best_result;
    }
    fn expected_value(&self, hand: &mut BJHand, dealer_up_card: &Card,
                      d: &mut DirectShoe, action: BJAction,
                      rules: &BJRules) -> Option<f64> {
        return match action {
            HIT => {
                match rules.can_hit(hand) {
                    false => None,
                    true => {
                        let mut final_result = 0.0;
                        for &v in VALUES.iter() {
                            let count_of_val = d.count(&v);
                            if count_of_val > 0 {
                                let odds_of_value = count_of_val as f64 / d.len() as f64;
                                let card_from_deck = match d.remove(&v) {
                                    Some(c) => c,
                                    None => {
                                        panic!("Count positive, but couldn't remove!");
                                    }
                                };
                                hand.add_card(card_from_deck);
                                let ev_with_value = self.expected_value_best_action(
                                    hand, dealer_up_card, d, rules);
                                final_result += odds_of_value * ev_with_value;
                                hand.remove_card(card_from_deck);
                                d.insert(&card_from_deck);
                            }
                        }
                        Some(final_result)
                    }
                }
            }
            STAND => {
                // I guess you can always stand
                let mut dealer_hand = BJHand::new();
                dealer_hand.add_card(*dealer_up_card);
                self.expected_with_dealer(hand, &mut dealer_hand, d, rules)
            }
            DOUBLE => {
                match rules.can_double(hand) {
                    false => None,
                    true => {
                        let mut final_result = 0.0;
                        for &v in VALUES.iter() {
                            let count_of_val = d.count(&v);
                            if count_of_val > 0 {
                                let odds_of_value = count_of_val as f64 / d.len() as f64;
                                let card_from_deck = match d.remove(&v) {
                                    Some(c) => c,
                                    None => {
                                        panic!("Count positive, but couldn't remove!");
                                    }
                                };
                                hand.add_card(card_from_deck);
                                hand.add_double_count();
                                let ev_with_value = 2.0 * self.expected_value_best_action(
                                    hand, dealer_up_card, d, rules);
                                final_result += odds_of_value * ev_with_value;
                                hand.remove_card(card_from_deck);
                                hand.subtract_double_count();
                                d.insert(&card_from_deck);
                            }
                        }
                        Some(final_result)
                    }
                }
            }
            SPLIT => {
                match rules.can_split(hand) {
                    false => None,
                    true => Some(-1.0),
                }
            }
            SURRENDER => {
                match rules.can_surrender(hand) {
                    false => None,
                    true => Some(-0.5),
                }
            }
        }
    }
    fn expected_with_dealer(&self, player_hand: &BJHand, dealer_hand: &mut BJHand,
                            d: &mut DirectShoe, rules: &BJRules) -> Option<f64> {
        if !rules.should_hit_dealer_hand(dealer_hand) {
            let dealer_score = dealer_hand.score();
            let player_score = player_hand.score();
            assert!(player_score <= 21);
            if dealer_score > 21 {
                return Some(1.0);
            } else  if dealer_score > player_score {
                return Some(-1.0);
            } else if dealer_score < player_score {
                return Some(1.0);
            } else {
                return Some(0.0);
            }
        } else {
            // The dealer hits ... takes a random card
            let mut final_result = 0.0;
            let number_of_valid_cards = {
                if rules.dealer_blackjack_after_hand() || dealer_hand.len() != 1 {
                    d.len()
                } else {
                    match dealer_hand.score() {
                        10 => d.len() - d.count(&ACE),
                        11 => d.len() - d.count(&TEN) - d.count(&JACK) - d.count(&QUEEN) -
                           d.count(&KING),
                        _ => d.len()
                    }
                }
            };
            for &v in VALUES.iter() {
                let count_of_val = d.count(&v);
                if count_of_val > 0 {
                    let odds_of_value = count_of_val as f64 / number_of_valid_cards as f64;
                    let card_from_deck = match d.remove(&v) {
                        Some(c) => c,
                        None => {
                            panic!("Count positive, but couldn't remove!");
                        }
                    };
                    assert_eq!(card_from_deck.value().desc(), v.desc());
                    dealer_hand.add_card(card_from_deck);
                    if rules.is_blackjack(dealer_hand) &&
                        !rules.dealer_blackjack_after_hand() {
                            // ignore
                    } else {
                        let ev_with_value = match self.expected_with_dealer(
                            player_hand, dealer_hand, d, rules) {
                                Some(c) => c,
                                None => return None,
                        };
                        final_result += odds_of_value * ev_with_value;
                    }

                    dealer_hand.remove_card(card_from_deck);
                    d.insert(&card_from_deck);
                }
            }
            return Some(final_result);
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use action_calculator::ActionCalculatorImpl;
    use action_calculator::ActionCalculator;
    use self::test::Bencher;
    use cards::value::Value;
    use shoe::shoe::DirectShoe;
    use hand::BJHand;
    use std::num::Float;
    use cards::value;
    use rules::BJRules;

    fn check_value(dealer_cards: &Vec<Value>, player_cards: &Vec<Value>, expected: f64) {
        use shoe::randomshoe::new_infinite_shoe;
        use rules::BJRules;
        let a = ActionCalculatorImpl;
        let rules = BJRules::new();
        let mut shoe = new_infinite_shoe();
        let expansion = 1000000.0f64;
        assert_eq!(
            (a.expected_with_dealer(
                &BJHand::new_from_deck(&mut shoe, player_cards).unwrap(),
                &mut BJHand::new_from_deck(&mut shoe, dealer_cards).unwrap(),
                &mut shoe,
                &rules).unwrap() * expansion).round() as int,
            (expected * expansion) as int);
    }

    fn check_best_value(dealer_up_card: &Value, player_cards: &Vec<Value>, expected: f64) {
        let rules = BJRules::new();
        check_best_value_rules(dealer_up_card, player_cards, expected, &rules);
    }

    fn check_best_value_rules(dealer_up_card: &Value, player_cards: &Vec<Value>, expected: f64,
                             rules: &BJRules) {
        use shoe::randomshoe::new_infinite_shoe;
        let a = ActionCalculatorImpl;
        let mut shoe = new_infinite_shoe();
        let expansion = 1000000.0f64;
        assert_eq!(
            (a.expected_value_best_action(
                &mut BJHand::new_from_deck(&mut shoe, player_cards).unwrap(),
                &shoe.remove(dealer_up_card).unwrap(),
                &mut shoe,
                rules) * expansion).round() as int,
            (expected * expansion) as int);
    }

    #[test]
    fn test_expected_infinite_deck() {
        // Numbers checked against http://wizardofodds.com/games/blackjack/appendix/1/
        check_value(&vec![value::FOUR],  &vec![value::TEN, value::EIGHT]           ,  0.175854);
        check_value(&vec![value::SIX],   &vec![value::TEN, value::SIX]             , -0.153699);
        check_value(&vec![value::SEVEN], &vec![value::TEN, value::TEN]             ,  0.773227);
        check_value(&vec![value::SEVEN], &vec![value::TEN, value::SEVEN]           , -0.106809);
        check_value(&vec![value::NINE],  &vec![value::TEN, value::FIVE]            , -0.543150);
        check_value(&vec![value::TEN],   &vec![value::TEN, value::TEN]             ,  0.554538);
        check_value(&vec![value::TEN],   &vec![value::TEN, value::FIVE, value::SIX],  0.962624);
        check_value(&vec![value::TEN],   &vec![value::TEN, value::SEVEN]           , -0.419721);
        check_value(&vec![value::ACE],   &vec![value::TEN, value::SIX]             , -0.666951);
        check_value(&vec![value::ACE],   &vec![value::TEN, value::EIGHT]           , -0.100199);
    }

    #[test]
    fn test_expected_best_value_surr_16_a() {
        let rules = BJRules::new_complex(true);
        check_best_value_rules(&value::ACE,   &vec![value::TEN, value::SIX], -0.5, &rules);
    }

    #[test]
    fn test_expected_best_value_11_6() {
        check_best_value(&value::SIX,   &vec![value::FIVE, value::SIX], 0.667380);
    }

    #[test]
    fn test_expected_best_value_s18_9() {
        check_best_value(&value::NINE,   &vec![value::ACE, value::SEVEN], -0.100744);
    }

    #[test]
    fn test_expected_best_value_9_2() {
        // HIT
        check_best_value(&value::TWO,   &vec![value::FIVE, value::FOUR], 0.074446);
    }

    #[test]
    fn test_expected_best_value_9_3() {
        // DOUBLE
        check_best_value(&value::THREE,   &vec![value::FIVE, value::FOUR], 0.120816);
    }

    #[test]
    fn test_expected_best_value_18_a() {
        check_best_value(&value::ACE,    &vec![value::TEN, value::EIGHT]           , -0.100199);
    }

    #[test]
    fn test_expected_best_value_21_2() {
        check_value(&vec![value::TWO],   &vec![value::TEN, value::FIVE, value::SIX],  0.882007);
        check_value(&vec![value::TWO],   &vec![value::TEN, value::TEN]             ,  0.639987);
    }

    #[test]
    fn test_expected_best_value_15_9() {
        check_best_value(&value::NINE,  &vec![value::TEN, value::FIVE]             , -0.471578);
    }

    #[test]
    fn test_expected_best_value_16_7() {
        check_best_value(&value::SEVEN,  &vec![value::TEN, value::SIX]             , -0.414779);
    }

    #[test]
    fn test_expected_best_value_20_10() {
        check_value(&vec![value::TEN],   &vec![value::TEN, value::TEN]             ,  0.554538);
    }

    #[bench]
    fn bench_with_calc(b: &mut Bencher) {
        use cards::value;
        b.iter(|| {
            check_best_value(&value::SEVEN,  &vec![value::TEN, value::SIX]             , -0.414779);
        });
    }
}
<commit_msg>Formatting<commit_after>use hand::BJHand;
use bjaction::BJAction;
use bjaction::HIT;
use bjaction::STAND;
use bjaction::DOUBLE;
use bjaction::SURRENDER;
use bjaction::SPLIT;
use cards::card::Card;
use cards::value::VALUES;
use cards::value::ACE;
use cards::value::KING;
use cards::value::QUEEN;
use cards::value::JACK;
use cards::value::TEN;
use rules::BJRules;
use shoe::shoe::DirectShoe;
use shoe::randomshoe::SuitPicker;

pub trait ActionCalculator {
    fn expected_value(&self, h: &mut BJHand, dealer_up_card: &Card,
                      d: &mut DirectShoe, action: BJAction,
                      rules: &BJRules) -> Option<f64>;
    fn expected_with_dealer(&self, player_hand: &BJHand,
                            dealer_hand: &mut BJHand, d: &mut DirectShoe,
                            rules: &BJRules) -> Option<f64>;
    fn expected_value_best_action(&self, hand: &mut BJHand,
                                  dealer_up_card: &Card, d: &mut DirectShoe,
                                  rules: &BJRules) -> f64;
}

pub struct ActionCalculatorImpl;

impl ActionCalculator for ActionCalculatorImpl {
    fn expected_value_best_action(&self, hand: &mut BJHand,
                                  dealer_up_card: &Card, d: &mut DirectShoe,
                                  rules: &BJRules) -> f64 {
        if hand.score() > 21 {
            // Bust... loose bet
            return -1.0;
        }
        let actions = vec![HIT, DOUBLE, SPLIT, SURRENDER];
        let mut best_result = match self.expected_value(
                hand, dealer_up_card, d, STAND, rules) {
            Some(s) => s,
            None => panic!("You should always be able to stand"),
        };
        for &a in actions.iter() {
            match self.expected_value(hand, dealer_up_card, d, a, rules) {
                Some(r) => {
                    if best_result < r {
                        best_result = r;
                    }
                }
                _ => {}
            }
        }
        return best_result;
    }
    fn expected_value(&self, hand: &mut BJHand, dealer_up_card: &Card,
                      d: &mut DirectShoe, action: BJAction,
                      rules: &BJRules) -> Option<f64> {
        return match action {
            HIT => {
                match rules.can_hit(hand) {
                    false => None,
                    true => {
                        let mut final_result = 0.0;
                        for &v in VALUES.iter() {
                            let count_of_val = d.count(&v);
                            if count_of_val > 0 {
                                let odds_of_value = count_of_val as f64 / d.len() as f64;
                                let card_from_deck = match d.remove(&v) {
                                    Some(c) => c,
                                    None => {
                                        panic!("Count positive, but couldn't remove!");
                                    }
                                };
                                hand.add_card(card_from_deck);
                                let ev_with_value = self.expected_value_best_action(
                                    hand, dealer_up_card, d, rules);
                                final_result += odds_of_value * ev_with_value;
                                hand.remove_card(card_from_deck);
                                d.insert(&card_from_deck);
                            }
                        }
                        Some(final_result)
                    }
                }
            }
            STAND => {
                // I guess you can always stand
                let mut dealer_hand = BJHand::new();
                dealer_hand.add_card(*dealer_up_card);
                self.expected_with_dealer(hand, &mut dealer_hand, d, rules)
            }
            DOUBLE => {
                match rules.can_double(hand) {
                    false => None,
                    true => {
                        let mut final_result = 0.0;
                        for &v in VALUES.iter() {
                            let count_of_val = d.count(&v);
                            if count_of_val > 0 {
                                let odds_of_value = count_of_val as f64 / d.len() as f64;
                                let card_from_deck = match d.remove(&v) {
                                    Some(c) => c,
                                    None => {
                                        panic!("Count positive, but couldn't remove!");
                                    }
                                };
                                hand.add_card(card_from_deck);
                                hand.add_double_count();
                                let ev_with_value = 2.0 * self.expected_value_best_action(
                                    hand, dealer_up_card, d, rules);
                                final_result += odds_of_value * ev_with_value;
                                hand.remove_card(card_from_deck);
                                hand.subtract_double_count();
                                d.insert(&card_from_deck);
                            }
                        }
                        Some(final_result)
                    }
                }
            }
            SPLIT => {
                match rules.can_split(hand) {
                    false => None,
                    true => Some(-1.0),
                }
            }
            SURRENDER => {
                match rules.can_surrender(hand) {
                    false => None,
                    true => Some(-0.5),
                }
            }
        }
    }
    fn expected_with_dealer(&self, player_hand: &BJHand,
                            dealer_hand: &mut BJHand, d: &mut DirectShoe,
                            rules: &BJRules) -> Option<f64> {
        if !rules.should_hit_dealer_hand(dealer_hand) {
            let dealer_score = dealer_hand.score();
            let player_score = player_hand.score();
            assert!(player_score <= 21);
            if dealer_score > 21 {
                return Some(1.0);
            } else  if dealer_score > player_score {
                return Some(-1.0);
            } else if dealer_score < player_score {
                return Some(1.0);
            } else {
                return Some(0.0);
            }
        } else {
            // The dealer hits ... takes a random card
            let mut final_result = 0.0;
            let number_of_valid_cards = {
                if rules.dealer_blackjack_after_hand() || dealer_hand.len() != 1 {
                    d.len()
                } else {
                    match dealer_hand.score() {
                        10 => d.len() - d.count(&ACE),
                        11 => d.len() - d.count(&TEN) - d.count(&JACK) - d.count(&QUEEN) -
                           d.count(&KING),
                        _ => d.len()
                    }
                }
            };
            for &v in VALUES.iter() {
                let count_of_val = d.count(&v);
                if count_of_val > 0 {
                    let odds_of_value = count_of_val as f64 / number_of_valid_cards as f64;
                    let card_from_deck = match d.remove(&v) {
                        Some(c) => c,
                        None => {
                            panic!("Count positive, but couldn't remove!");
                        }
                    };
                    assert_eq!(card_from_deck.value().desc(), v.desc());
                    dealer_hand.add_card(card_from_deck);
                    if rules.is_blackjack(dealer_hand) &&
                        !rules.dealer_blackjack_after_hand() {
                            // ignore
                    } else {
                        let ev_with_value = match self.expected_with_dealer(
                            player_hand, dealer_hand, d, rules) {
                                Some(c) => c,
                                None => return None,
                        };
                        final_result += odds_of_value * ev_with_value;
                    }

                    dealer_hand.remove_card(card_from_deck);
                    d.insert(&card_from_deck);
                }
            }
            return Some(final_result);
        }
    }
}

#[cfg(test)]
mod tests {
    extern crate test;
    use action_calculator::ActionCalculatorImpl;
    use action_calculator::ActionCalculator;
    use self::test::Bencher;
    use cards::value::Value;
    use shoe::shoe::DirectShoe;
    use hand::BJHand;
    use std::num::Float;
    use cards::value;
    use rules::BJRules;

    fn check_value(dealer_cards: &Vec<Value>, player_cards: &Vec<Value>, expected: f64) {
        use shoe::randomshoe::new_infinite_shoe;
        use rules::BJRules;
        let a = ActionCalculatorImpl;
        let rules = BJRules::new();
        let mut shoe = new_infinite_shoe();
        let expansion = 1000000.0f64;
        assert_eq!(
            (a.expected_with_dealer(
                &BJHand::new_from_deck(&mut shoe, player_cards).unwrap(),
                &mut BJHand::new_from_deck(&mut shoe, dealer_cards).unwrap(),
                &mut shoe,
                &rules).unwrap() * expansion).round() as int,
            (expected * expansion) as int);
    }

    fn check_best_value(dealer_up_card: &Value, player_cards: &Vec<Value>, expected: f64) {
        let rules = BJRules::new();
        check_best_value_rules(dealer_up_card, player_cards, expected, &rules);
    }

    fn check_best_value_rules(dealer_up_card: &Value, player_cards: &Vec<Value>, expected: f64,
                             rules: &BJRules) {
        use shoe::randomshoe::new_infinite_shoe;
        let a = ActionCalculatorImpl;
        let mut shoe = new_infinite_shoe();
        let expansion = 1000000.0f64;
        assert_eq!(
            (a.expected_value_best_action(
                &mut BJHand::new_from_deck(&mut shoe, player_cards).unwrap(),
                &shoe.remove(dealer_up_card).unwrap(),
                &mut shoe,
                rules) * expansion).round() as int,
            (expected * expansion) as int);
    }

    #[test]
    fn test_expected_infinite_deck() {
        // Numbers checked against http://wizardofodds.com/games/blackjack/appendix/1/
        check_value(&vec![value::FOUR],  &vec![value::TEN, value::EIGHT]           ,  0.175854);
        check_value(&vec![value::SIX],   &vec![value::TEN, value::SIX]             , -0.153699);
        check_value(&vec![value::SEVEN], &vec![value::TEN, value::TEN]             ,  0.773227);
        check_value(&vec![value::SEVEN], &vec![value::TEN, value::SEVEN]           , -0.106809);
        check_value(&vec![value::NINE],  &vec![value::TEN, value::FIVE]            , -0.543150);
        check_value(&vec![value::TEN],   &vec![value::TEN, value::TEN]             ,  0.554538);
        check_value(&vec![value::TEN],   &vec![value::TEN, value::FIVE, value::SIX],  0.962624);
        check_value(&vec![value::TEN],   &vec![value::TEN, value::SEVEN]           , -0.419721);
        check_value(&vec![value::ACE],   &vec![value::TEN, value::SIX]             , -0.666951);
        check_value(&vec![value::ACE],   &vec![value::TEN, value::EIGHT]           , -0.100199);
    }

    #[test]
    fn test_expected_best_value_surr_16_a() {
        let rules = BJRules::new_complex(true);
        check_best_value_rules(&value::ACE,   &vec![value::TEN, value::SIX], -0.5, &rules);
    }

    #[test]
    fn test_expected_best_value_11_6() {
        check_best_value(&value::SIX,   &vec![value::FIVE, value::SIX], 0.667380);
    }

    #[test]
    fn test_expected_best_value_s18_9() {
        check_best_value(&value::NINE,   &vec![value::ACE, value::SEVEN], -0.100744);
    }

    #[test]
    fn test_expected_best_value_9_2() {
        // HIT
        check_best_value(&value::TWO,   &vec![value::FIVE, value::FOUR], 0.074446);
    }

    #[test]
    fn test_expected_best_value_9_3() {
        // DOUBLE
        check_best_value(&value::THREE,   &vec![value::FIVE, value::FOUR], 0.120816);
    }

    #[test]
    fn test_expected_best_value_18_a() {
        check_best_value(&value::ACE,    &vec![value::TEN, value::EIGHT]           , -0.100199);
    }

    #[test]
    fn test_expected_best_value_21_2() {
        check_value(&vec![value::TWO],   &vec![value::TEN, value::FIVE, value::SIX],  0.882007);
        check_value(&vec![value::TWO],   &vec![value::TEN, value::TEN]             ,  0.639987);
    }

    #[test]
    fn test_expected_best_value_15_9() {
        check_best_value(&value::NINE,  &vec![value::TEN, value::FIVE]             , -0.471578);
    }

    #[test]
    fn test_expected_best_value_16_7() {
        check_best_value(&value::SEVEN,  &vec![value::TEN, value::SIX]             , -0.414779);
    }

    #[test]
    fn test_expected_best_value_20_10() {
        check_value(&vec![value::TEN],   &vec![value::TEN, value::TEN]             ,  0.554538);
    }

    #[bench]
    fn bench_with_calc(b: &mut Bencher) {
        use cards::value;
        b.iter(|| {
            check_best_value(&value::SEVEN,  &vec![value::TEN, value::SIX]             , -0.414779);
        });
    }
}
<|endoftext|>


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

use WriteMode;
use visitor::FmtVisitor;
use syntax::codemap::{self, BytePos, Span, Pos};
use comment::{CodeCharKind, CommentCodeSlices, rewrite_comment};

impl<'a> FmtVisitor<'a> {
    // TODO these format_missing methods are ugly. Refactor and add unit tests
    // for the central whitespace stripping loop.
    pub fn format_missing(&mut self, end: BytePos) {
        self.format_missing_inner(end,
                                  |this, last_snippet, _| this.buffer.push_str(last_snippet))
    }

    pub fn format_missing_with_indent(&mut self, end: BytePos) {
        let config = self.config;
        self.format_missing_inner(end, |this, last_snippet, snippet| {
            this.buffer.push_str(last_snippet.trim_right());
            if last_snippet == snippet {
                // No new lines in the snippet.
                this.buffer.push_str("\n");
            }
            let indent = this.block_indent.to_string(config);
            this.buffer.push_str(&indent);
        })
    }

    fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self,
                                                                end: BytePos,
                                                                process_last_snippet: F) {
        let start = self.last_pos;

        if start == end {
            // Do nothing if this is the beginning of the file.
            if start != self.codemap.lookup_char_pos(start).file.start_pos {
                process_last_snippet(self, "", "");
            }
            return;
        }

        // assert!(start < end,
        //         "Request to format inverted span: {:?} to {:?}",
        //         self.codemap.lookup_char_pos(start),
        //         self.codemap.lookup_char_pos(end));

        self.last_pos = end;
        let span = codemap::mk_sp(start, end);

        self.write_snippet(span, &process_last_snippet);
    }

    fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F)
        where F: Fn(&mut FmtVisitor, &str, &str)
    {
        // Get a snippet from the file start to the span's hi without allocating.
        // We need it to determine what precedes the current comment. If the comment
        // follows code on the same line, we won't touch it.
        let big_span_lo = self.codemap.lookup_char_pos(span.lo).file.start_pos;
        let local_begin = self.codemap.lookup_byte_offset(big_span_lo);
        let local_end = self.codemap.lookup_byte_offset(span.hi);
        let start_index = local_begin.pos.to_usize();
        let end_index = local_end.pos.to_usize();
        let big_snippet = &local_begin.fm.src.as_ref().unwrap()[start_index..end_index];

        let big_diff = (span.lo - big_span_lo).to_usize();
        let snippet = self.snippet(span);

        self.write_snippet_inner(big_snippet, big_diff, &snippet, process_last_snippet);
    }

    fn write_snippet_inner<F>(&mut self,
                              big_snippet: &str,
                              big_diff: usize,
                              old_snippet: &str,
                              process_last_snippet: F)
        where F: Fn(&mut FmtVisitor, &str, &str)
    {
        // Trim whitespace from the right hand side of each line.
        // Annoyingly, the library functions for splitting by lines etc. are not
        // quite right, so we must do it ourselves.
        let mut line_start = 0;
        let mut last_wspace = None;
        let mut rewrite_next_comment = true;

        fn replace_chars(string: &str) -> String {
            string.chars()
                  .map(|ch| {
                      if ch.is_whitespace() {
                          ch
                      } else {
                          'X'
                      }
                  })
                  .collect()
        }

        let replaced = match self.write_mode {
            Some(mode) => {
                match mode {
                    WriteMode::Coverage => replace_chars(old_snippet),
                    _ => old_snippet.to_owned(),
                }
            }
            None => old_snippet.to_owned(),
        };
        let snippet = &*replaced;

        for (kind, offset, subslice) in CommentCodeSlices::new(snippet) {
            if let CodeCharKind::Comment = kind {
                let last_char = big_snippet[..(offset + big_diff)]
                                    .chars()
                                    .rev()
                                    .skip_while(|rev_c| [' ', '\t'].contains(&rev_c))
                                    .next();

                let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c));

                if rewrite_next_comment && fix_indent {
                    if let Some('{') = last_char {
                        self.buffer.push_str("\n");
                    }

                    let comment_width = ::std::cmp::min(self.config.ideal_width,
                                                        self.config.max_width -
                                                        self.block_indent.width());

                    self.buffer.push_str(&self.block_indent.to_string(self.config));
                    self.buffer.push_str(&rewrite_comment(subslice,
                                                          false,
                                                          comment_width,
                                                          self.block_indent,
                                                          self.config)
                                              .unwrap());

                    last_wspace = None;
                    line_start = offset + subslice.len();

                    if let Some('/') = subslice.chars().skip(1).next() {
                        // Add a newline after line comments
                        self.buffer.push_str("\n");
                    } else if line_start < snippet.len() {
                        // For other comments add a newline if there isn't one at the end already
                        let c = snippet[line_start..].chars().next().unwrap();
                        if c != '\n' && c != '\r' {
                            self.buffer.push_str("\n");
                        }
                    }

                    continue;
                } else {
                    rewrite_next_comment = false;
                }
            }

            for (mut i, c) in subslice.char_indices() {
                i += offset;

                if c == '\n' {
                    if let Some(lw) = last_wspace {
                        self.buffer.push_str(&snippet[line_start..lw]);
                        self.buffer.push_str("\n");
                    } else {
                        self.buffer.push_str(&snippet[line_start..i + 1]);
                    }

                    line_start = i + 1;
                    last_wspace = None;
                    rewrite_next_comment = rewrite_next_comment || kind == CodeCharKind::Normal;
                } else {
                    if c.is_whitespace() {
                        if last_wspace.is_none() {
                            last_wspace = Some(i);
                        }
                    } else {
                        rewrite_next_comment = rewrite_next_comment || kind == CodeCharKind::Normal;
                        last_wspace = None;
                    }
                }
            }
        }

        process_last_snippet(self, &snippet[line_start..], &snippet);
    }
}
<commit_msg>Uncommented missed spans check<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use WriteMode;
use visitor::FmtVisitor;
use syntax::codemap::{self, BytePos, Span, Pos};
use comment::{CodeCharKind, CommentCodeSlices, rewrite_comment};

impl<'a> FmtVisitor<'a> {
    // TODO these format_missing methods are ugly. Refactor and add unit tests
    // for the central whitespace stripping loop.
    pub fn format_missing(&mut self, end: BytePos) {
        self.format_missing_inner(end,
                                  |this, last_snippet, _| this.buffer.push_str(last_snippet))
    }

    pub fn format_missing_with_indent(&mut self, end: BytePos) {
        let config = self.config;
        self.format_missing_inner(end, |this, last_snippet, snippet| {
            this.buffer.push_str(last_snippet.trim_right());
            if last_snippet == snippet {
                // No new lines in the snippet.
                this.buffer.push_str("\n");
            }
            let indent = this.block_indent.to_string(config);
            this.buffer.push_str(&indent);
        })
    }

    fn format_missing_inner<F: Fn(&mut FmtVisitor, &str, &str)>(&mut self,
                                                                end: BytePos,
                                                                process_last_snippet: F) {
        let start = self.last_pos;

        if start == end {
            // Do nothing if this is the beginning of the file.
            if start != self.codemap.lookup_char_pos(start).file.start_pos {
                process_last_snippet(self, "", "");
            }
            return;
        }

        assert!(start < end,
                "Request to format inverted span: {:?} to {:?}",
                self.codemap.lookup_char_pos(start),
                self.codemap.lookup_char_pos(end));

        self.last_pos = end;
        let span = codemap::mk_sp(start, end);

        self.write_snippet(span, &process_last_snippet);
    }

    fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F)
        where F: Fn(&mut FmtVisitor, &str, &str)
    {
        // Get a snippet from the file start to the span's hi without allocating.
        // We need it to determine what precedes the current comment. If the comment
        // follows code on the same line, we won't touch it.
        let big_span_lo = self.codemap.lookup_char_pos(span.lo).file.start_pos;
        let local_begin = self.codemap.lookup_byte_offset(big_span_lo);
        let local_end = self.codemap.lookup_byte_offset(span.hi);
        let start_index = local_begin.pos.to_usize();
        let end_index = local_end.pos.to_usize();
        let big_snippet = &local_begin.fm.src.as_ref().unwrap()[start_index..end_index];

        let big_diff = (span.lo - big_span_lo).to_usize();
        let snippet = self.snippet(span);

        self.write_snippet_inner(big_snippet, big_diff, &snippet, process_last_snippet);
    }

    fn write_snippet_inner<F>(&mut self,
                              big_snippet: &str,
                              big_diff: usize,
                              old_snippet: &str,
                              process_last_snippet: F)
        where F: Fn(&mut FmtVisitor, &str, &str)
    {
        // Trim whitespace from the right hand side of each line.
        // Annoyingly, the library functions for splitting by lines etc. are not
        // quite right, so we must do it ourselves.
        let mut line_start = 0;
        let mut last_wspace = None;
        let mut rewrite_next_comment = true;

        fn replace_chars(string: &str) -> String {
            string.chars()
                  .map(|ch| {
                      if ch.is_whitespace() {
                          ch
                      } else {
                          'X'
                      }
                  })
                  .collect()
        }

        let replaced = match self.write_mode {
            Some(mode) => {
                match mode {
                    WriteMode::Coverage => replace_chars(old_snippet),
                    _ => old_snippet.to_owned(),
                }
            }
            None => old_snippet.to_owned(),
        };
        let snippet = &*replaced;

        for (kind, offset, subslice) in CommentCodeSlices::new(snippet) {
            if let CodeCharKind::Comment = kind {
                let last_char = big_snippet[..(offset + big_diff)]
                                    .chars()
                                    .rev()
                                    .skip_while(|rev_c| [' ', '\t'].contains(&rev_c))
                                    .next();

                let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c));

                if rewrite_next_comment && fix_indent {
                    if let Some('{') = last_char {
                        self.buffer.push_str("\n");
                    }

                    let comment_width = ::std::cmp::min(self.config.ideal_width,
                                                        self.config.max_width -
                                                        self.block_indent.width());

                    self.buffer.push_str(&self.block_indent.to_string(self.config));
                    self.buffer.push_str(&rewrite_comment(subslice,
                                                          false,
                                                          comment_width,
                                                          self.block_indent,
                                                          self.config)
                                              .unwrap());

                    last_wspace = None;
                    line_start = offset + subslice.len();

                    if let Some('/') = subslice.chars().skip(1).next() {
                        // Add a newline after line comments
                        self.buffer.push_str("\n");
                    } else if line_start < snippet.len() {
                        // For other comments add a newline if there isn't one at the end already
                        let c = snippet[line_start..].chars().next().unwrap();
                        if c != '\n' && c != '\r' {
                            self.buffer.push_str("\n");
                        }
                    }

                    continue;
                } else {
                    rewrite_next_comment = false;
                }
            }

            for (mut i, c) in subslice.char_indices() {
                i += offset;

                if c == '\n' {
                    if let Some(lw) = last_wspace {
                        self.buffer.push_str(&snippet[line_start..lw]);
                        self.buffer.push_str("\n");
                    } else {
                        self.buffer.push_str(&snippet[line_start..i + 1]);
                    }

                    line_start = i + 1;
                    last_wspace = None;
                    rewrite_next_comment = rewrite_next_comment || kind == CodeCharKind::Normal;
                } else {
                    if c.is_whitespace() {
                        if last_wspace.is_none() {
                            last_wspace = Some(i);
                        }
                    } else {
                        rewrite_next_comment = rewrite_next_comment || kind == CodeCharKind::Normal;
                        last_wspace = None;
                    }
                }
            }
        }

        process_last_snippet(self, &snippet[line_start..], &snippet);
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 by SiegeLord
//
// All rights reserved. Distributed under ZLib. For full terms see the file LICENSE.

use ffi::*;
use allegro::ffi::*;
use allegro::{Core, Color, Bitmap, BitmapLike};
use std::kinds::marker::NoSend;

use libc::*;
use std::option::Some;
use std::mem;

pub enum FontAlignment
{
	AlignLeft,
	AlignCentre,
	AlignRight
}

impl FontAlignment
{
	fn get_allegro_flags(&self) -> c_int
	{
		match *self
		{
			AlignLeft => ALLEGRO_ALIGN_LEFT,
			AlignRight => ALLEGRO_ALIGN_RIGHT,
			AlignCentre => ALLEGRO_ALIGN_CENTRE,
		}
	}
}

pub trait FontDrawing
{
	fn draw_text(&self, font: &Font, color: Color, x: f32, y: f32, align: FontAlignment, text: &str);
	fn draw_justified_text(&self, font: &Font, color: Color, x1: f32, x2: f32, y: f32, diff: f32, align: FontAlignment, text: &str);
}

impl FontDrawing for Core
{
	fn draw_justified_text(&self, font: &Font, color: Color, x1: f32, x2: f32, y: f32, diff: f32, align: FontAlignment, text: &str)
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninitialized();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);

			al_draw_justified_ustr(mem::transmute(font.get_font()), *color, x1 as c_float,
			                       x2 as c_float, y as c_float, diff as c_float, align.get_allegro_flags(), ustr);
		}
	}

	fn draw_text(&self, font: &Font, color: Color, x: f32, y: f32, align: FontAlignment, text: &str)
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninitialized();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);

			al_draw_ustr(mem::transmute(font.get_font()), *color, x as c_float, y as c_float, align.get_allegro_flags(), ustr);
		}
	}
}

pub struct Font
{
	allegro_font: *mut ALLEGRO_FONT,
	no_send_marker: NoSend,
}

impl Font
{
	pub unsafe fn wrap_allegro_font(font: *mut ALLEGRO_FONT) -> Option
	{
		Font::new(font)
	}

	fn new(font: *mut ALLEGRO_FONT) -> Option
	{
		if font.is_null()
		{
			None
		}
		else
		{
			Some(Font{ allegro_font: font, no_send_marker: NoSend })
		}
	}

	pub fn get_font(&self) -> *mut ALLEGRO_FONT
	{
		self.allegro_font
	}

	pub fn get_text_width(&self, text: &str) -> i32
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninitialized();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);
			al_get_ustr_width(self.get_font() as *_, ustr) as i32
		}
	}

	pub fn get_line_height(&self) -> i32
	{
		unsafe
		{
			al_get_font_line_height(self.get_font() as *_) as i32
		}
	}

	pub fn get_ascent(&self) -> i32
	{
		unsafe
		{
			al_get_font_ascent(self.get_font() as *_) as i32
		}
	}

	pub fn get_descent(&self) -> i32
	{
		unsafe
		{
			al_get_font_descent(self.get_font() as *_) as i32
		}
	}

	pub fn get_text_dimensions(&self, text: &str) -> (i32, i32, i32, i32)
	{
		unsafe
		{
			let (mut x, mut y, mut w, mut h): (c_int, c_int, c_int, c_int) = mem::uninitialized();
			let mut info: ALLEGRO_USTR_INFO = mem::uninitialized();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);
			al_get_ustr_dimensions(self.get_font() as *_, ustr, &mut x, &mut y, &mut w, &mut h);
			(x as i32, y as i32, w as i32, h as i32)
		}
	}
}

// Not Send just because of the marker
#[unsafe_destructor]
impl Drop for Font
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_font(self.allegro_font);
		}
	}
}

impl ::addon::FontAddon
{
	pub fn create_builtin_font(&self) -> Option
	{
		Font::new(unsafe
		{
			al_create_builtin_font()
		})
	}

	pub fn load_bitmap_font(&self, filename: &str) -> Option
	{
		Font::new(unsafe
		{
			filename.with_c_str(|s|
			{
				al_load_bitmap_font(s)
			})
		})
	}

	pub fn grab_font_from_bitmap(&self, bmp: &Bitmap, ranges: &[(c_int, c_int)]) -> Option
	{
		Font::new(unsafe
		{
			al_grab_font_from_bitmap(bmp.get_bitmap(), (ranges.len() * 2) as c_int, ranges.as_ptr() as *c_int)
		})
	}
}
<commit_msg>Don't draw empty text. This can sometimes cause a crash in Allegro (as the ptr is NULL)<commit_after>// Copyright (c) 2014 by SiegeLord
//
// All rights reserved. Distributed under ZLib. For full terms see the file LICENSE.

use ffi::*;
use allegro::ffi::*;
use allegro::{Core, Color, Bitmap, BitmapLike};
use std::kinds::marker::NoSend;

use libc::*;
use std::option::Some;
use std::mem;

pub enum FontAlignment
{
	AlignLeft,
	AlignCentre,
	AlignRight
}

impl FontAlignment
{
	fn get_allegro_flags(&self) -> c_int
	{
		match *self
		{
			AlignLeft => ALLEGRO_ALIGN_LEFT,
			AlignRight => ALLEGRO_ALIGN_RIGHT,
			AlignCentre => ALLEGRO_ALIGN_CENTRE,
		}
	}
}

pub trait FontDrawing
{
	fn draw_text(&self, font: &Font, color: Color, x: f32, y: f32, align: FontAlignment, text: &str);
	fn draw_justified_text(&self, font: &Font, color: Color, x1: f32, x2: f32, y: f32, diff: f32, align: FontAlignment, text: &str);
}

impl FontDrawing for Core
{
	fn draw_justified_text(&self, font: &Font, color: Color, x1: f32, x2: f32, y: f32, diff: f32, align: FontAlignment, text: &str)
	{
		if text.len() == 0
		{
			return;
		}
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninitialized();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);

			al_draw_justified_ustr(mem::transmute(font.get_font()), *color, x1 as c_float,
			                       x2 as c_float, y as c_float, diff as c_float, align.get_allegro_flags(), ustr);
		}
	}

	fn draw_text(&self, font: &Font, color: Color, x: f32, y: f32, align: FontAlignment, text: &str)
	{
		if text.len() == 0
		{
			return;
		}
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninitialized();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);

			al_draw_ustr(mem::transmute(font.get_font()), *color, x as c_float, y as c_float, align.get_allegro_flags(), ustr);
		}
	}
}

pub struct Font
{
	allegro_font: *mut ALLEGRO_FONT,
	no_send_marker: NoSend,
}

impl Font
{
	pub unsafe fn wrap_allegro_font(font: *mut ALLEGRO_FONT) -> Option
	{
		Font::new(font)
	}

	fn new(font: *mut ALLEGRO_FONT) -> Option
	{
		if font.is_null()
		{
			None
		}
		else
		{
			Some(Font{ allegro_font: font, no_send_marker: NoSend })
		}
	}

	pub fn get_font(&self) -> *mut ALLEGRO_FONT
	{
		self.allegro_font
	}

	pub fn get_text_width(&self, text: &str) -> i32
	{
		unsafe
		{
			let mut info: ALLEGRO_USTR_INFO = mem::uninitialized();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);
			al_get_ustr_width(self.get_font() as *_, ustr) as i32
		}
	}

	pub fn get_line_height(&self) -> i32
	{
		unsafe
		{
			al_get_font_line_height(self.get_font() as *_) as i32
		}
	}

	pub fn get_ascent(&self) -> i32
	{
		unsafe
		{
			al_get_font_ascent(self.get_font() as *_) as i32
		}
	}

	pub fn get_descent(&self) -> i32
	{
		unsafe
		{
			al_get_font_descent(self.get_font() as *_) as i32
		}
	}

	pub fn get_text_dimensions(&self, text: &str) -> (i32, i32, i32, i32)
	{
		unsafe
		{
			let (mut x, mut y, mut w, mut h): (c_int, c_int, c_int, c_int) = mem::uninitialized();
			let mut info: ALLEGRO_USTR_INFO = mem::uninitialized();
			let ustr = al_ref_buffer(&mut info, text.as_ptr() as *i8, text.len() as size_t);
			al_get_ustr_dimensions(self.get_font() as *_, ustr, &mut x, &mut y, &mut w, &mut h);
			(x as i32, y as i32, w as i32, h as i32)
		}
	}
}

// Not Send just because of the marker
#[unsafe_destructor]
impl Drop for Font
{
	fn drop(&mut self)
	{
		unsafe
		{
			al_destroy_font(self.allegro_font);
		}
	}
}

impl ::addon::FontAddon
{
	pub fn create_builtin_font(&self) -> Option
	{
		Font::new(unsafe
		{
			al_create_builtin_font()
		})
	}

	pub fn load_bitmap_font(&self, filename: &str) -> Option
	{
		Font::new(unsafe
		{
			filename.with_c_str(|s|
			{
				al_load_bitmap_font(s)
			})
		})
	}

	pub fn grab_font_from_bitmap(&self, bmp: &Bitmap, ranges: &[(c_int, c_int)]) -> Option
	{
		Font::new(unsafe
		{
			al_grab_font_from_bitmap(bmp.get_bitmap(), (ranges.len() * 2) as c_int, ranges.as_ptr() as *c_int)
		})
	}
}
<|endoftext|>


<commit_before>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("../demo-cxx/demo.cc")
//!         .flag("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=../demo-cxx/demo.h");
//!     println!("cargo:rerun-if-changed=../demo-cxx/demo.cc");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the
//! *demo-rs* and *demo-cxx* directories of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

mod error;
mod gen;
mod paths;
mod syntax;

use crate::error::Result;
use crate::gen::Opt;
use anyhow::anyhow;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::process;

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> cc::Build {
    match try_generate_bridge(rust_source_file.as_ref()) {
        Ok(build) => build,
        Err(err) => {
            let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {:?}\n\n", anyhow!(err));
            process::exit(1);
        }
    }
}

fn try_generate_bridge(rust_source_file: &Path) -> Result<cc::Build> {
    let header = gen::do_generate_header(rust_source_file, Opt::default());
    let header_path = paths::out_with_extension(rust_source_file, ".h")?;
    fs::create_dir_all(header_path.parent().unwrap())?;
    fs::write(&header_path, header)?;
    paths::symlink_header(&header_path, rust_source_file);

    let bridge = gen::do_generate_bridge(rust_source_file, Opt::default());
    let bridge_path = paths::out_with_extension(rust_source_file, ".cc")?;
    fs::write(&bridge_path, bridge)?;
    let mut build = paths::cc_build();
    build.file(&bridge_path);

    let ref cxx_h = paths::include_dir()?.join("rust").join("cxx.h");
    let _ = fs::create_dir_all(cxx_h.parent().unwrap());
    let _ = fs::remove_file(cxx_h);
    let _ = fs::write(cxx_h, gen::include::HEADER);

    Ok(build)
}
<commit_msg>Suppress some lints in cxx-build<commit_after>//! The CXX code generator for constructing and compiling C++ code.
//!
//! This is intended to be used from Cargo build scripts to execute CXX's
//! C++ code generator, set up any additional compiler flags depending on
//! the use case, and make the C++ compiler invocation.
//!
//!

//!
//! # Example
//!
//! Example of a canonical Cargo build script that builds a CXX bridge:
//!
//! ```no_run
//! // build.rs
//!
//! fn main() {
//!     cxx_build::bridge("src/main.rs")
//!         .file("../demo-cxx/demo.cc")
//!         .flag("-std=c++11")
//!         .compile("cxxbridge-demo");
//!
//!     println!("cargo:rerun-if-changed=src/main.rs");
//!     println!("cargo:rerun-if-changed=../demo-cxx/demo.h");
//!     println!("cargo:rerun-if-changed=../demo-cxx/demo.cc");
//! }
//! ```
//!
//! A runnable working setup with this build script is shown in the
//! *demo-rs* and *demo-cxx* directories of [https://github.com/dtolnay/cxx].
//!
//! [https://github.com/dtolnay/cxx]: https://github.com/dtolnay/cxx
//!
//!

//!
//! # Alternatives
//!
//! For use in non-Cargo builds like Bazel or Buck, CXX provides an
//! alternate way of invoking the C++ code generator as a standalone command
//! line tool. The tool is packaged as the `cxxbridge-cmd` crate.
//!
//! ```bash
//! $ cargo install cxxbridge-cmd  # or build it from the repo
//!
//! $ cxxbridge src/main.rs --header > path/to/mybridge.h
//! $ cxxbridge src/main.rs > path/to/mybridge.cc
//! ```

#![allow(
    clippy::inherent_to_string,
    clippy::needless_doctest_main,
    clippy::new_without_default,
    clippy::toplevel_ref_arg
)]

mod error;
mod gen;
mod paths;
mod syntax;

use crate::error::Result;
use crate::gen::Opt;
use anyhow::anyhow;
use std::fs;
use std::io::{self, Write};
use std::path::Path;
use std::process;

/// This returns a [`cc::Build`] on which you should continue to set up any
/// additional source files or compiler flags, and lastly call its [`compile`]
/// method to execute the C++ build.
///
/// [`compile`]: https://docs.rs/cc/1.0.49/cc/struct.Build.html#method.compile
#[must_use]
pub fn bridge(rust_source_file: impl AsRef<Path>) -> cc::Build {
    match try_generate_bridge(rust_source_file.as_ref()) {
        Ok(build) => build,
        Err(err) => {
            let _ = writeln!(io::stderr(), "\n\ncxxbridge error: {:?}\n\n", anyhow!(err));
            process::exit(1);
        }
    }
}

fn try_generate_bridge(rust_source_file: &Path) -> Result<cc::Build> {
    let header = gen::do_generate_header(rust_source_file, Opt::default());
    let header_path = paths::out_with_extension(rust_source_file, ".h")?;
    fs::create_dir_all(header_path.parent().unwrap())?;
    fs::write(&header_path, header)?;
    paths::symlink_header(&header_path, rust_source_file);

    let bridge = gen::do_generate_bridge(rust_source_file, Opt::default());
    let bridge_path = paths::out_with_extension(rust_source_file, ".cc")?;
    fs::write(&bridge_path, bridge)?;
    let mut build = paths::cc_build();
    build.file(&bridge_path);

    let ref cxx_h = paths::include_dir()?.join("rust").join("cxx.h");
    let _ = fs::create_dir_all(cxx_h.parent().unwrap());
    let _ = fs::remove_file(cxx_h);
    let _ = fs::write(cxx_h, gen::include::HEADER);

    Ok(build)
}
<|endoftext|>


<commit_before>//! Models for server and channel invites.

#[cfg(feature = "http")]
use crate::http::CacheHttp;
use chrono::{DateTime, FixedOffset};
use super::prelude::*;

#[cfg(feature = "model")]
use crate::builder::CreateInvite;
#[cfg(feature = "model")]
use crate::internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use super::{Permissions, utils as model_utils};
#[cfg(feature = "model")]
use crate::utils;
#[cfg(feature = "cache")]
use crate::cache::CacheRwLock;
#[cfg(feature = "http")]
use crate::http::Http;

/// Information about an invite code.
///
/// Information can not be accessed for guilds the current user is banned from.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Invite {
    /// The approximate number of [`Member`]s in the related [`Guild`].
    ///
    /// [`Guild`]: ../guild/struct.Guild.html
    /// [`Member`]: ../guild/struct.Member.html
    pub approximate_member_count: Option<u64>,
    /// The approximate number of [`Member`]s with an active session in the
    /// related [`Guild`].
    ///
    /// An active session is defined as an open, heartbeating WebSocket connection.
    /// These include [invisible][`OnlineStatus::Invisible`] members.
    ///
    /// [`OnlineStatus::Invisible`]: ../user/enum.OnlineStatus.html#variant.Invisible
    /// [`Guild`]: ../guild/struct.Guild.html
    /// [`Member`]: ../guild/struct.Member.html
    pub approximate_presence_count: Option<u64>,
    /// The unique code for the invite.
    pub code: String,
    /// A representation of the minimal amount of information needed about the
    /// [`GuildChannel`] being invited to.
    ///
    /// [`GuildChannel`]: ../channel/struct.GuildChannel.html
    pub channel: InviteChannel,
    /// A representation of the minimal amount of information needed about the
    /// [`Guild`] being invited to.
    ///
    /// This can be `None` if the invite is to a [`Group`] and not to a
    /// Guild.
    ///
    /// [`Guild`]: ../guild/struct.Guild.html
    /// [`Group`]: ../channel/struct.Group.html
    pub guild: Option<InviteGuild>,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

#[cfg(feature = "model")]
impl Invite {
    /// Creates an invite for a [`GuildChannel`], providing a builder so that
    /// fields may optionally be set.
    ///
    /// See the documentation for the [`CreateInvite`] builder for information
    /// on how to use this and the default values that it provides.
    ///
    /// Requires the [Create Invite] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have the required [permission].
    ///
    /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions
    /// [`CreateInvite`]: ../../builder/struct.CreateInvite.html
    /// [`GuildChannel`]: ../channel/struct.GuildChannel.html
    /// [Create Invite]: ../permissions/struct.Permissions.html#associatedconstant.CREATE_INVITE
    /// [permission]: ../permissions/index.html
    #[cfg(feature = "client")]
    pub fn create<C, F>(cache_http: impl CacheHttp, channel_id: C, f: F) -> Result<RichInvite>
        where C: Into<ChannelId>, F: FnOnce(CreateInvite) -> CreateInvite {
        Self::_create(cache_http, channel_id.into(), f)
    }

    #[cfg(feature = "client")]
    fn _create<F>(cache_http: impl CacheHttp, channel_id: ChannelId, f: F) -> Result<RichInvite>
        where F: FnOnce(CreateInvite) -> CreateInvite {
        #[cfg(feature = "cache")]
        {
            if let Some(cache) = cache_http.cache() {
                let req = Permissions::CREATE_INVITE;

                if !model_utils::user_has_perms(cache, channel_id, None, req)? {
                    return Err(Error::Model(ModelError::InvalidPermissions(req)));
                }
            }
        }

        let map = utils::hashmap_to_json_map(f(CreateInvite::default()).0);

        cache_http.http().create_invite(channel_id.0, &map)
    }

    /// Deletes the invite.
    ///
    /// **Note**: Requires the [Manage Guild] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have the required [permission].
    ///
    /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions
    /// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD
    /// [permission]: ../permissions/index.html
    #[cfg(feature = "http")]
    pub fn delete(&self, cache_http: impl CacheHttp) -> Result<Invite> {
        #[cfg(feature = "cache")]
        {
            if let Some(cache) = cache_http.cache() {
                let req = Permissions::MANAGE_GUILD;

                let guild_id = self.guild.as_ref().map(|g| g.id);
                if !model_utils::user_has_perms(cache, self.channel.id, guild_id, req)? {
                    return Err(Error::Model(ModelError::InvalidPermissions(req)));
                }
            }
        }

        cache_http.http().as_ref().delete_invite(&self.code)
    }

    /// Gets the information about an invite.
    #[cfg(feature = "http")]
    pub fn get(http: impl AsRef<Http>, code: &str, stats: bool) -> Result<Invite> {
        let mut invite = code;

        #[cfg(feature = "utils")]
        {
            invite = crate::utils::parse_invite(invite);
        }

        http.as_ref().get_invite(invite, stats)
    }

    /// Returns a URL to use for the invite.
    ///
    /// # Examples
    ///
    /// Retrieve the URL for an invite with the code `WxZumR`:
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// # extern crate serenity;
    /// #
    /// # use serde_json::json;
    /// # use serenity::model::prelude::*;
    /// #
    /// # fn main() {
    /// # let invite = serde_json::from_value::<Invite>(json!({
    /// #     "approximate_member_count": Some(1812),
    /// #     "approximate_presence_count": Some(717),
    /// #     "code": "WxZumR",
    /// #     "channel": {
    /// #         "id": ChannelId(1),
    /// #         "name": "foo",
    /// #         "type": ChannelType::Text,
    /// #     },
    /// #     "guild": {
    /// #         "id": GuildId(2),
    /// #         "icon": None::<String>,
    /// #         "name": "bar",
    /// #         "splash_hash": None::<String>,
    /// #         "text_channel_count": 7,
    /// #         "voice_channel_count": 3,
    /// #     },
    /// # })).unwrap();
    /// #
    /// assert_eq!(invite.url(), "https://discord.gg/WxZumR");
    /// # }
    /// ```
    pub fn url(&self) -> String { format!("https://discord.gg/{}", self.code) }
}

/// A minimal information about the channel an invite points to.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InviteChannel {
    pub id: ChannelId,
    pub name: String,
    #[serde(rename = "type")] pub kind: ChannelType,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// A minimal amount of information about the guild an invite points to.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InviteGuild {
    pub id: GuildId,
    pub icon: Option<String>,
    pub name: String,
    pub splash_hash: Option<String>,
    pub text_channel_count: Option<u64>,
    pub voice_channel_count: Option<u64>,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

#[cfg(feature = "model")]
impl InviteGuild {
    /// Returns the Id of the shard associated with the guild.
    ///
    /// When the cache is enabled this will automatically retrieve the total
    /// number of shards.
    ///
    /// **Note**: When the cache is enabled, this function unlocks the cache to
    /// retrieve the total number of shards in use. If you already have the
    /// total, consider using [`utils::shard_id`].
    ///
    /// [`utils::shard_id`]: ../../utils/fn.shard_id.html
    #[cfg(all(feature = "cache", feature = "utils"))]
    #[inline]
    pub fn shard_id(&self, cache: impl AsRef<CacheRwLock>) -> u64 { self.id.shard_id(&cache) }

    /// Returns the Id of the shard associated with the guild.
    ///
    /// When the cache is enabled this will automatically retrieve the total
    /// number of shards.
    ///
    /// When the cache is not enabled, the total number of shards being used
    /// will need to be passed.
    ///
    /// # Examples
    ///
    /// Retrieve the Id of the shard for a guild with Id `81384788765712384`,
    /// using 17 shards:
    ///
    /// ```rust,ignore
    /// use serenity::utils;
    ///
    /// // assumes a `guild` has already been bound
    ///
    /// assert_eq!(guild.shard_id(17), 7);
    /// ```
    #[cfg(all(feature = "utils", not(feature = "cache")))]
    #[inline]
    pub fn shard_id(&self, shard_count: u64) -> u64 { self.id.shard_id(shard_count) }
}

/// Detailed information about an invite.
/// This information can only be retrieved by anyone with the [Manage Guild]
/// permission. Otherwise, a minimal amount of information can be retrieved via
/// the [`Invite`] struct.
///
/// [`Invite`]: struct.Invite.html
/// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RichInvite {
    /// A representation of the minimal amount of information needed about the
    /// channel being invited to.
    pub channel: InviteChannel,
    /// The unique code for the invite.
    pub code: String,
    /// When the invite was created.
    pub created_at: DateTime<FixedOffset>,
    /// A representation of the minimal amount of information needed about the
    /// [`Guild`] being invited to.
    ///
    /// This can be `None` if the invite is to a [`Group`] and not to a
    /// Guild.
    ///
    /// [`Guild`]: ../guild/struct.Guild.html
    /// [`Group`]: ../channel/struct.Group.html
    pub guild: Option<InviteGuild>,
    /// The user that created the invite.
    pub inviter: User,
    /// The maximum age of the invite in seconds, from when it was created.
    pub max_age: u64,
    /// The maximum number of times that an invite may be used before it expires.

    /// Note that this does not supersede the [`max_age`] value, if the value of
    /// [`temporary`] is `true`. If the value of `temporary` is `false`, then the
    /// invite _will_ self-expire after the given number of max uses.

    /// If the value is `0`, then the invite is permanent.
    ///
    /// [`max_age`]: #structfield.max_age
    /// [`temporary`]: #structfield.temporary
    pub max_uses: u64,
    /// Indicator of whether the invite self-expires after a certain amount of
    /// time or uses.
    pub temporary: bool,
    /// The amount of times that an invite has been used.
    pub uses: u64,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

#[cfg(feature = "model")]
impl RichInvite {
    /// Deletes the invite.
    ///
    /// Refer to [`http::delete_invite`] for more information.
    ///
    /// **Note**: Requires the [Manage Guild] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` feature is enabled, then this returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permission].
    ///
    /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions
    /// [`Invite::delete`]: struct.Invite.html#method.delete
    /// [`http::delete_invite`]: ../../http/fn.delete_invite.html
    /// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD.html
    /// [permission]: ../permissions/index.html
    #[cfg(feature = "http")]
    pub fn delete(&self, cache_http: impl CacheHttp) -> Result<Invite> {
        #[cfg(feature = "cache")]
        {
            if let Some(cache) = cache_http.cache() {
                let req = Permissions::MANAGE_GUILD;

                let guild_id = self.guild.as_ref().map(|g| g.id);
                if !model_utils::user_has_perms(cache, self.channel.id, guild_id, req)? {
                    return Err(Error::Model(ModelError::InvalidPermissions(req)));
                }
            }
        }

        cache_http.http().as_ref().delete_invite(&self.code)
    }

    /// Returns a URL to use for the invite.
    ///
    /// # Examples
    ///
    /// Retrieve the URL for an invite with the code `WxZumR`:
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// # extern crate serenity;
    /// #
    /// # use serde_json::json;
    /// # use serenity::model::prelude::*;
    /// #
    /// # fn main() {
    /// # let invite = serde_json::from_value::<RichInvite>(json!({
    /// #     "code": "WxZumR",
    /// #     "channel": {
    /// #         "id": ChannelId(1),
    /// #         "name": "foo",
    /// #         "type": ChannelType::Text,
    /// #     },
    /// #     "created_at": "2017-01-29T15:35:17.136000+00:00",
    /// #     "guild": {
    /// #         "id": GuildId(2),
    /// #         "icon": None::<String>,
    /// #         "name": "baz",
    /// #         "splash_hash": None::<String>,
    /// #         "text_channel_count": None::<u64>,
    /// #         "voice_channel_count": None::<u64>,
    /// #     },
    /// #     "inviter": {
    /// #         "avatar": None::<String>,
    /// #         "bot": false,
    /// #         "discriminator": 3,
    /// #         "id": UserId(4),
    /// #         "username": "qux",
    /// #     },
    /// #     "max_age": 5,
    /// #     "max_uses": 6,
    /// #     "temporary": true,
    /// #     "uses": 7,
    /// # })).unwrap();
    /// #
    /// assert_eq!(invite.url(), "https://discord.gg/WxZumR");
    /// # }
    /// ```
    pub fn url(&self) -> String { format!("https://discord.gg/{}", self.code) }
}
<commit_msg>Add optional inviter field to Invite (#715)<commit_after>//! Models for server and channel invites.

#[cfg(feature = "http")]
use crate::http::CacheHttp;
use chrono::{DateTime, FixedOffset};
use super::prelude::*;

#[cfg(feature = "model")]
use crate::builder::CreateInvite;
#[cfg(feature = "model")]
use crate::internal::prelude::*;
#[cfg(all(feature = "cache", feature = "model"))]
use super::{Permissions, utils as model_utils};
#[cfg(feature = "model")]
use crate::utils;
#[cfg(feature = "cache")]
use crate::cache::CacheRwLock;
#[cfg(feature = "http")]
use crate::http::Http;
use std::ops::Deref;

/// Information about an invite code.
///
/// Information can not be accessed for guilds the current user is banned from.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Invite {
    /// The approximate number of [`Member`]s in the related [`Guild`].
    ///
    /// [`Guild`]: ../guild/struct.Guild.html
    /// [`Member`]: ../guild/struct.Member.html
    pub approximate_member_count: Option<u64>,
    /// The approximate number of [`Member`]s with an active session in the
    /// related [`Guild`].
    ///
    /// An active session is defined as an open, heartbeating WebSocket connection.
    /// These include [invisible][`OnlineStatus::Invisible`] members.
    ///
    /// [`OnlineStatus::Invisible`]: ../user/enum.OnlineStatus.html#variant.Invisible
    /// [`Guild`]: ../guild/struct.Guild.html
    /// [`Member`]: ../guild/struct.Member.html
    pub approximate_presence_count: Option<u64>,
    /// The unique code for the invite.
    pub code: String,
    /// A representation of the minimal amount of information needed about the
    /// [`GuildChannel`] being invited to.
    ///
    /// [`GuildChannel`]: ../channel/struct.GuildChannel.html
    pub channel: InviteChannel,
    /// A representation of the minimal amount of information needed about the
    /// [`Guild`] being invited to.
    ///
    /// This can be `None` if the invite is to a [`Group`] and not to a
    /// Guild.
    ///
    /// [`Guild`]: ../guild/struct.Guild.html
    /// [`Group`]: ../channel/struct.Group.html
    pub guild: Option<InviteGuild>,
    /// A representation of the minimal amount of information needed about the
    /// [`User`] that created the invite.
    ///
    /// This can be `None` for invites created by Discord such as invite-widgets
    /// or vanity invite links.
    ///
    /// [`User`]: ../user/struct.User.html
    pub inviter: Option<InviteUser>,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

#[cfg(feature = "model")]
impl Invite {
    /// Creates an invite for a [`GuildChannel`], providing a builder so that
    /// fields may optionally be set.
    ///
    /// See the documentation for the [`CreateInvite`] builder for information
    /// on how to use this and the default values that it provides.
    ///
    /// Requires the [Create Invite] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have the required [permission].
    ///
    /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions
    /// [`CreateInvite`]: ../../builder/struct.CreateInvite.html
    /// [`GuildChannel`]: ../channel/struct.GuildChannel.html
    /// [Create Invite]: ../permissions/struct.Permissions.html#associatedconstant.CREATE_INVITE
    /// [permission]: ../permissions/index.html
    #[cfg(feature = "client")]
    pub fn create<C, F>(cache_http: impl CacheHttp, channel_id: C, f: F) -> Result<RichInvite>
        where C: Into<ChannelId>, F: FnOnce(CreateInvite) -> CreateInvite {
        Self::_create(cache_http, channel_id.into(), f)
    }

    #[cfg(feature = "client")]
    fn _create<F>(cache_http: impl CacheHttp, channel_id: ChannelId, f: F) -> Result<RichInvite>
        where F: FnOnce(CreateInvite) -> CreateInvite {
        #[cfg(feature = "cache")]
        {
            if let Some(cache) = cache_http.cache() {
                let req = Permissions::CREATE_INVITE;

                if !model_utils::user_has_perms(cache, channel_id, None, req)? {
                    return Err(Error::Model(ModelError::InvalidPermissions(req)));
                }
            }
        }

        let map = utils::hashmap_to_json_map(f(CreateInvite::default()).0);

        cache_http.http().create_invite(channel_id.0, &map)
    }

    /// Deletes the invite.
    ///
    /// **Note**: Requires the [Manage Guild] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` is enabled, returns a [`ModelError::InvalidPermissions`]
    /// if the current user does not have the required [permission].
    ///
    /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions
    /// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD
    /// [permission]: ../permissions/index.html
    #[cfg(feature = "http")]
    pub fn delete(&self, cache_http: impl CacheHttp) -> Result<Invite> {
        #[cfg(feature = "cache")]
        {
            if let Some(cache) = cache_http.cache() {
                let req = Permissions::MANAGE_GUILD;

                let guild_id = self.guild.as_ref().map(|g| g.id);
                if !model_utils::user_has_perms(cache, self.channel.id, guild_id, req)? {
                    return Err(Error::Model(ModelError::InvalidPermissions(req)));
                }
            }
        }

        cache_http.http().as_ref().delete_invite(&self.code)
    }

    /// Gets the information about an invite.
    #[cfg(feature = "http")]
    pub fn get(http: impl AsRef<Http>, code: &str, stats: bool) -> Result<Invite> {
        let mut invite = code;

        #[cfg(feature = "utils")]
        {
            invite = crate::utils::parse_invite(invite);
        }

        http.as_ref().get_invite(invite, stats)
    }

    /// Returns a URL to use for the invite.
    ///
    /// # Examples
    ///
    /// Retrieve the URL for an invite with the code `WxZumR`:
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// # extern crate serenity;
    /// #
    /// # use serde_json::json;
    /// # use serenity::model::prelude::*;
    /// #
    /// # fn main() {
    /// # let invite = serde_json::from_value::<Invite>(json!({
    /// #     "approximate_member_count": Some(1812),
    /// #     "approximate_presence_count": Some(717),
    /// #     "code": "WxZumR",
    /// #     "channel": {
    /// #         "id": ChannelId(1),
    /// #         "name": "foo",
    /// #         "type": ChannelType::Text,
    /// #     },
    /// #     "guild": {
    /// #         "id": GuildId(2),
    /// #         "icon": None::<String>,
    /// #         "name": "bar",
    /// #         "splash_hash": None::<String>,
    /// #         "text_channel_count": 7,
    /// #         "voice_channel_count": 3,
    /// #     },
    /// #     "inviter": {
    /// #         "id": UserId(3),
    /// #         "username": "foo",
    /// #         "discriminator": "1234",
    /// #         "avatar": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    /// #     },
    /// # })).unwrap();
    /// #
    /// assert_eq!(invite.url(), "https://discord.gg/WxZumR");
    /// # }
    /// ```
    pub fn url(&self) -> String { format!("https://discord.gg/{}", self.code) }
}

/// A minimal amount of information about the inviter (person who created the invite).
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InviteUser {
    pub id: UserId,
    #[serde(rename = "username")] pub name: String,
    #[serde(deserialize_with = "deserialize_u16")] pub discriminator: u16,
    pub avatar: Option<String>,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// InviteUser implements a Deref to UserId so it gains the convenience methods
/// for converting it into a [`User`] instance.
///
/// [`User`]: ../user/struct.User.html
impl Deref for InviteUser {
    type Target = UserId;

    fn deref(&self) -> &Self::Target {
        &self.id
    }
}

/// A minimal amount of information about the channel an invite points to.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InviteChannel {
    pub id: ChannelId,
    pub name: String,
    #[serde(rename = "type")] pub kind: ChannelType,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

/// A minimal amount of information about the guild an invite points to.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct InviteGuild {
    pub id: GuildId,
    pub icon: Option<String>,
    pub name: String,
    pub splash_hash: Option<String>,
    pub text_channel_count: Option<u64>,
    pub voice_channel_count: Option<u64>,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

#[cfg(feature = "model")]
impl InviteGuild {
    /// Returns the Id of the shard associated with the guild.
    ///
    /// When the cache is enabled this will automatically retrieve the total
    /// number of shards.
    ///
    /// **Note**: When the cache is enabled, this function unlocks the cache to
    /// retrieve the total number of shards in use. If you already have the
    /// total, consider using [`utils::shard_id`].
    ///
    /// [`utils::shard_id`]: ../../utils/fn.shard_id.html
    #[cfg(all(feature = "cache", feature = "utils"))]
    #[inline]
    pub fn shard_id(&self, cache: impl AsRef<CacheRwLock>) -> u64 { self.id.shard_id(&cache) }

    /// Returns the Id of the shard associated with the guild.
    ///
    /// When the cache is enabled this will automatically retrieve the total
    /// number of shards.
    ///
    /// When the cache is not enabled, the total number of shards being used
    /// will need to be passed.
    ///
    /// # Examples
    ///
    /// Retrieve the Id of the shard for a guild with Id `81384788765712384`,
    /// using 17 shards:
    ///
    /// ```rust,ignore
    /// use serenity::utils;
    ///
    /// // assumes a `guild` has already been bound
    ///
    /// assert_eq!(guild.shard_id(17), 7);
    /// ```
    #[cfg(all(feature = "utils", not(feature = "cache")))]
    #[inline]
    pub fn shard_id(&self, shard_count: u64) -> u64 { self.id.shard_id(shard_count) }
}

/// Detailed information about an invite.
/// This information can only be retrieved by anyone with the [Manage Guild]
/// permission. Otherwise, a minimal amount of information can be retrieved via
/// the [`Invite`] struct.
///
/// [`Invite`]: struct.Invite.html
/// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct RichInvite {
    /// A representation of the minimal amount of information needed about the
    /// channel being invited to.
    pub channel: InviteChannel,
    /// The unique code for the invite.
    pub code: String,
    /// When the invite was created.
    pub created_at: DateTime<FixedOffset>,
    /// A representation of the minimal amount of information needed about the
    /// [`Guild`] being invited to.
    ///
    /// This can be `None` if the invite is to a [`Group`] and not to a
    /// Guild.
    ///
    /// [`Guild`]: ../guild/struct.Guild.html
    /// [`Group`]: ../channel/struct.Group.html
    pub guild: Option<InviteGuild>,
    /// The user that created the invite.
    pub inviter: User,
    /// The maximum age of the invite in seconds, from when it was created.
    pub max_age: u64,
    /// The maximum number of times that an invite may be used before it expires.

    /// Note that this does not supersede the [`max_age`] value, if the value of
    /// [`temporary`] is `true`. If the value of `temporary` is `false`, then the
    /// invite _will_ self-expire after the given number of max uses.

    /// If the value is `0`, then the invite is permanent.
    ///
    /// [`max_age`]: #structfield.max_age
    /// [`temporary`]: #structfield.temporary
    pub max_uses: u64,
    /// Indicator of whether the invite self-expires after a certain amount of
    /// time or uses.
    pub temporary: bool,
    /// The amount of times that an invite has been used.
    pub uses: u64,
    #[serde(skip)]
    pub(crate) _nonexhaustive: (),
}

#[cfg(feature = "model")]
impl RichInvite {
    /// Deletes the invite.
    ///
    /// Refer to [`http::delete_invite`] for more information.
    ///
    /// **Note**: Requires the [Manage Guild] permission.
    ///
    /// # Errors
    ///
    /// If the `cache` feature is enabled, then this returns a
    /// [`ModelError::InvalidPermissions`] if the current user does not have
    /// the required [permission].
    ///
    /// [`ModelError::InvalidPermissions`]: ../error/enum.Error.html#variant.InvalidPermissions
    /// [`Invite::delete`]: struct.Invite.html#method.delete
    /// [`http::delete_invite`]: ../../http/fn.delete_invite.html
    /// [Manage Guild]: ../permissions/struct.Permissions.html#associatedconstant.MANAGE_GUILD.html
    /// [permission]: ../permissions/index.html
    #[cfg(feature = "http")]
    pub fn delete(&self, cache_http: impl CacheHttp) -> Result<Invite> {
        #[cfg(feature = "cache")]
        {
            if let Some(cache) = cache_http.cache() {
                let req = Permissions::MANAGE_GUILD;

                let guild_id = self.guild.as_ref().map(|g| g.id);
                if !model_utils::user_has_perms(cache, self.channel.id, guild_id, req)? {
                    return Err(Error::Model(ModelError::InvalidPermissions(req)));
                }
            }
        }

        cache_http.http().as_ref().delete_invite(&self.code)
    }

    /// Returns a URL to use for the invite.
    ///
    /// # Examples
    ///
    /// Retrieve the URL for an invite with the code `WxZumR`:
    ///
    /// ```rust
    /// # extern crate serde_json;
    /// # extern crate serenity;
    /// #
    /// # use serde_json::json;
    /// # use serenity::model::prelude::*;
    /// #
    /// # fn main() {
    /// # let invite = serde_json::from_value::<RichInvite>(json!({
    /// #     "code": "WxZumR",
    /// #     "channel": {
    /// #         "id": ChannelId(1),
    /// #         "name": "foo",
    /// #         "type": ChannelType::Text,
    /// #     },
    /// #     "created_at": "2017-01-29T15:35:17.136000+00:00",
    /// #     "guild": {
    /// #         "id": GuildId(2),
    /// #         "icon": None::<String>,
    /// #         "name": "baz",
    /// #         "splash_hash": None::<String>,
    /// #         "text_channel_count": None::<u64>,
    /// #         "voice_channel_count": None::<u64>,
    /// #     },
    /// #     "inviter": {
    /// #         "avatar": None::<String>,
    /// #         "bot": false,
    /// #         "discriminator": 3,
    /// #         "id": UserId(4),
    /// #         "username": "qux",
    /// #     },
    /// #     "max_age": 5,
    /// #     "max_uses": 6,
    /// #     "temporary": true,
    /// #     "uses": 7,
    /// # })).unwrap();
    /// #
    /// assert_eq!(invite.url(), "https://discord.gg/WxZumR");
    /// # }
    /// ```
    pub fn url(&self) -> String { format!("https://discord.gg/{}", self.code) }
}
<|endoftext|>


<commit_before>use bitstream::byteread::*;

pub trait BitRead {
    fn consumed(&self) -> usize;
    fn available(&self) -> usize;
    fn can_refill(&self) -> bool;
    fn refill64(&mut self) -> ();
    fn get_val(&mut self, n:usize) -> u64;
    fn get_bit(&mut self) -> bool;
    fn peek_val(&mut self, n:usize) -> u64;
    fn get_bits_64(&mut self, n: usize) -> u64;
    fn refill32(&mut self) -> ();
    fn get_bits_32(&mut self, n: usize) -> u32;

    fn peek_bits_64(&mut self, n: usize) -> u64;

    fn peek_bits_32(&mut self, n: usize) -> u32;

    fn skip_rem(&mut self, n:usize) -> ();
    fn skip_bits(&mut self, size : usize) -> ();
}

#[derive(Debug, Clone, Copy)]
pub struct BitReadLE <'a> {
    buffer : &'a[u8], /// read buffer, 8-bytes padded
    index : usize,
    cache : u64,
    left : usize,
}

impl <'a> BitRead for BitReadLE<'a> {
    #[inline]
    fn consumed(&self) -> usize {
        self.index * 8 - self.left
    }

    #[inline]
    fn available(&self) -> usize {
        (self.buffer.len() - self.index) * 8 + self.left
    }

    #[inline]
    fn can_refill(&self) -> bool {
        self.index < self.buffer.len() - 8
    }

    #[inline]
    fn refill64(&mut self) -> () {
        if !self.can_refill() {
            return;
        }

        self.cache  = get_u64l(&self.buffer[self.index..]);
        self.index += 8;
        self.left   = 64;
    }

    #[inline]
    fn get_val(&mut self, n:usize) -> u64 {
        let ret = self.peek_val(n);

        self.cache = self.cache >> n;
        self.left -= n;

        return ret;
    }

    #[inline]
    fn peek_val(&mut self, n:usize) -> u64 {
        self.cache & ((1u64 << n) - 1)
    }

    #[inline]
    fn get_bit(&mut self) -> bool {
        if self.left <= 0 {
            self.refill64();
        }

        self.get_val(1) != 0
    }

    #[inline]
    fn get_bits_64(&mut self, n:usize) -> u64 {
        let mut left = 0;
        let mut ret = 0;

        if n == 0 {
            return 0;
        }

        if self.left < n {
            left = self.left;
            ret  = self.get_val(left);
            self.refill64();
        }

        self.get_val(n - left) << left | ret
    }

    #[inline]
    fn peek_bits_64(&mut self, n:usize) -> u64 {
        let mut tmp = self.clone();

        tmp.get_bits_64(n)
    }

    #[inline]
    fn refill32(&mut self) -> () {
        if !self.can_refill() {
            return;
        }
        let val = get_u32l(&self.buffer[self.index..]) as u64;

        self.cache  = val << self.left | self.cache;
        self.index += 4;
        self.left  += 32;
    }

    #[inline]
    fn get_bits_32(&mut self, n:usize) -> u32 {
        if n == 0 {
            return 0;
        }

        if self.left <= n {
            self.refill32();
        }

        return self.get_val(n) as u32;
    }

    #[inline]
    fn peek_bits_32(&mut self, n:usize) -> u32 {
        if n == 0 {
            return 0;
        }

        if self.left <= n {
            self.refill32();
        }

        return self.peek_val(n) as u32;
    }

    fn skip_rem(&mut self, n:usize) -> () {
        self.cache = self.cache >> n;
        self.left -= n;
    }

    #[inline]
    fn skip_bits(&mut self, mut n:usize) -> () {
        if self.left < n {
            n -= self.left;
            self.skip_rem(n);
            if n > 64 {
                let skip = n / 8;

                n -= skip * 8;
                self.index += skip;
            }
            self.refill64();
        }

        self.skip_rem(n);
    }
}

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

    const CHECKBOARD: [u8; 128] = [0b01010101; 128];

#[test]
    fn get_bit() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.get_bit());
        assert!(!reader.get_bit());
    }

#[test]
    fn get_bits_64() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.get_bits_64(1) == 1);
        assert!(reader.get_bits_64(2) == 2);
        assert!(reader.get_bits_64(4) == 10);
        assert!(reader.get_bits_64(1) == 0);
        assert!(reader.get_bits_64(8) == 85);
    }

#[test]
    fn peek_bits_64() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.peek_bits_64(1) == 1);
        assert!(reader.peek_bits_64(1) == 1);
        assert!(reader.peek_bits_64(2) == 1);
        assert!(reader.peek_bits_64(2) == 1);
    }
#[test]
    fn get_bits_32() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.get_bits_64(1) == 1);
        assert!(reader.get_bits_64(2) == 2);
        assert!(reader.get_bits_64(4) == 10);
        assert!(reader.get_bits_64(1) == 0);
        assert!(reader.get_bits_64(8) == 85);
    }

#[test]
    fn peek_bits_32() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.peek_bits_32(1) == 1);
        assert!(reader.peek_bits_32(1) == 1);
        assert!(reader.peek_bits_32(2) == 1);
        assert!(reader.peek_bits_32(2) == 1);
    }
#[test]
    fn skip_bits() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD,
            index: 0,
            cache: 0,
            left: 0
        };

        reader.skip_bits(0);
        assert!(reader.peek_bits_32(1) == 1);
        reader.skip_bits(2);
        assert!(reader.peek_bits_32(1) == 1);
        reader.skip_bits(2);
        assert!(reader.peek_bits_32(1) == 1);
    }
}
<commit_msg>bitread: Add align_bits and update tests<commit_after>use bitstream::byteread::*;

pub trait BitRead {
    fn consumed(&self) -> usize;
    fn available(&self) -> usize;
    fn can_refill(&self) -> bool;
    fn refill64(&mut self) -> ();
    fn get_val(&mut self, n:usize) -> u64;
    fn get_bit(&mut self) -> bool;
    fn peek_val(&mut self, n:usize) -> u64;
    fn get_bits_64(&mut self, n: usize) -> u64;
    fn refill32(&mut self) -> ();
    fn get_bits_32(&mut self, n: usize) -> u32;

    fn peek_bits_64(&mut self, n: usize) -> u64;

    fn peek_bits_32(&mut self, n: usize) -> u32;

    fn skip_rem(&mut self, n:usize) -> ();
    fn skip_bits(&mut self, size : usize) -> ();
    fn align_bits(&mut self) -> ();
}

#[derive(Debug, Clone, Copy)]
pub struct BitReadLE <'a> {
    buffer : &'a[u8], /// read buffer, 8-bytes padded
    index : usize,
    cache : u64,
    left : usize,
}

impl <'a> BitRead for BitReadLE<'a> {
    #[inline]
    fn consumed(&self) -> usize {
        self.index * 8 - self.left
    }

    #[inline]
    fn available(&self) -> usize {
        (self.buffer.len() - self.index) * 8 + self.left
    }

    #[inline]
    fn can_refill(&self) -> bool {
        self.index < self.buffer.len() - 8
    }

    #[inline]
    fn refill64(&mut self) -> () {
        if !self.can_refill() {
            return;
        }

        self.cache  = get_u64l(&self.buffer[self.index..]);
        self.index += 8;
        self.left   = 64;
    }

    #[inline]
    fn get_val(&mut self, n:usize) -> u64 {
        let ret = self.peek_val(n);

        self.cache = self.cache >> n;
        self.left -= n;

        return ret;
    }

    #[inline]
    fn peek_val(&mut self, n:usize) -> u64 {
        self.cache & ((1u64 << n) - 1)
    }

    #[inline]
    fn get_bit(&mut self) -> bool {
        if self.left <= 0 {
            self.refill64();
        }

        self.get_val(1) != 0
    }

    #[inline]
    fn get_bits_64(&mut self, n:usize) -> u64 {
        let mut left = 0;
        let mut ret = 0;

        if n == 0 {
            return 0;
        }

        if self.left < n {
            left = self.left;
            ret  = self.get_val(left);
            self.refill64();
        }

        self.get_val(n - left) << left | ret
    }

    #[inline]
    fn peek_bits_64(&mut self, n:usize) -> u64 {
        let mut tmp = self.clone();

        tmp.get_bits_64(n)
    }

    #[inline]
    fn refill32(&mut self) -> () {
        if !self.can_refill() {
            return;
        }
        let val = get_u32l(&self.buffer[self.index..]) as u64;

        self.cache  = val << self.left | self.cache;
        self.index += 4;
        self.left  += 32;
    }

    #[inline]
    fn get_bits_32(&mut self, n:usize) -> u32 {
        if n == 0 {
            return 0;
        }

        if self.left <= n {
            self.refill32();
        }

        return self.get_val(n) as u32;
    }

    #[inline]
    fn peek_bits_32(&mut self, n:usize) -> u32 {
        if n == 0 {
            return 0;
        }

        if self.left <= n {
            self.refill32();
        }

        return self.peek_val(n) as u32;
    }

    fn skip_rem(&mut self, n:usize) -> () {
        self.cache = self.cache >> n;
        self.left -= n;
    }

    #[inline]
    fn skip_bits(&mut self, mut n:usize) -> () {
        if self.left < n {
            n -= self.left;
            self.skip_rem(n);
            if n > 64 {
                let skip = n / 8;

                n -= skip * 8;
                self.index += skip;
            }
            self.refill64();
        }

        self.skip_rem(n);
    }

    #[inline]
    fn align_bits(&mut self) -> () {
        let left = self.left;

        self.skip_bits(left);
    }
}

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

    const CHECKBOARD0101: [u8; 128] = [0b01010101; 128];
    const CHECKBOARD0011: [u8; 128] = [0b00110011; 128];

#[test]
    fn get_bit() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD0101,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.get_bit());
        assert!(!reader.get_bit());
    }

#[test]
    fn get_bits_64() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD0101,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.get_bits_64(1) == 1);
        assert!(reader.get_bits_64(2) == 2);
        assert!(reader.get_bits_64(4) == 10);
        assert!(reader.get_bits_64(1) == 0);
        assert!(reader.get_bits_64(8) == 85);
    }

#[test]
    fn peek_bits_64() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD0101,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.peek_bits_64(1) == 1);
        assert!(reader.peek_bits_64(1) == 1);
        assert!(reader.peek_bits_64(2) == 1);
        assert!(reader.peek_bits_64(2) == 1);
    }
#[test]
    fn get_bits_32() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD0101,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.get_bits_64(1) == 1);
        assert!(reader.get_bits_64(2) == 2);
        assert!(reader.get_bits_64(4) == 10);
        assert!(reader.get_bits_64(1) == 0);
        assert!(reader.get_bits_64(8) == 85);
    }

#[test]
    fn peek_bits_32() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD0101,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.peek_bits_32(1) == 1);
        assert!(reader.peek_bits_32(1) == 1);
        assert!(reader.peek_bits_32(2) == 1);
        assert!(reader.peek_bits_32(2) == 1);
    }
#[test]
    fn skip_bits() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD0101,
            index: 0,
            cache: 0,
            left: 0
        };

        reader.skip_bits(0);
        assert!(reader.peek_bits_32(1) == 1);
        reader.skip_bits(2);
        assert!(reader.peek_bits_32(1) == 1);
        reader.skip_bits(2);
        assert!(reader.peek_bits_32(1) == 1);
    }
#[test]
    fn align_bits() {
        let mut reader = BitReadLE {
            buffer: &CHECKBOARD0011,
            index: 0,
            cache: 0,
            left: 0
        };

        assert!(reader.get_bits_64(3) == 3);
        reader.align_bits();
        assert!(reader.get_bits_64(4) == 3);
        reader.skip_bits(1);
        reader.align_bits();
        assert!(reader.get_bits_64(4) == 3);
    }
}
<|endoftext|>