<commit_before>extern crate rand;
extern crate regex;

use super::moves::Technique;
use super::pokemon_token::PokemonToken;
use super::enums;
use self::rand::{Rng, thread_rng};
use self::regex::Regex;
use player::Player;

///Resolves moves that simply deals damage to the opponent.
pub fn deal_damage(attack: &Technique, user: &mut PokemonToken, target: &mut PokemonToken) -> u16 {
    //TODO: Methode die matcht zwischen Attacken die direkt verrechnet werden können und denen,
    //die variable Power haben. Hier muss eine Möglichkeit gefunden werden die Power möglichst
    //effizient für alle Attacken zu berechnen.
    let mut stab = 1.0;
    let mut rng = thread_rng();
    let random = rng.gen_range(0.85, 1.0);
    if attack.get_type() == user.get_types().0 ||
       attack.get_type() == user.get_types().1 {
        stab = 1.5;
    }
    let mut damage = 0;
    if attack.get_power().is_some() {
        let modifier = stab * attack.get_effectiveness(target.clone()) * random;
        damage = ((((2.0 * user.get_level() as f32 + 10.0) / 250.0) * user.get_current().
            get_stat(enums::Stats::Attack) as f32 /target.get_current().
            get_stat(enums::Stats::Defense) as f32 * attack.get_power().unwrap() as f32 + 2.0)
            * modifier) as u16;
    }
    let current = target.get_current().get_stat(enums::Stats::Hp);
    target.get_current().set_stats(enums::Stats::Hp, current - damage);
    println!("Damage: {}", damage);
    println!("HP in resolve: {}", target.get_current().get_stat(enums::Stats::Hp));
    damage
}

//resolves ailment effects
pub fn ailment(name: String, move_type: enums::Types, ailment: enums::Ailment, effect_chance: u8,
    target: &mut PokemonToken) {
    let mut rng = thread_rng();
    let random = rng.gen_range(0, 101);
    //only works if the effect chance of the move is met.
    let probability = effect_chance;
    if random <= probability {
        let powder = Regex::new(r"powder").unwrap();
        let spore = Regex::new(r"spore").unwrap();
        let tmp: &str = &name;
        //some sort of attacks did not work against grass types.
        if (target.get_types().0 == enums::Types::Grass ||
            target.get_types().1 == enums::Types::Grass) && (powder.is_match(tmp)
            || spore.is_match(tmp)) {
            println!("{} was not affected by {}", target.get_name(), name);
        } else {
            //categorize the moves by the ailment they cause. Ailments usually automatically fail
            //if the target already was hit by a move that caused the same ailment and still suffer
            //from it's effect. Non volatile Ailments even fail if the target is under the effect
            //of one of these kind.
            match ailment {

                enums::Ailment::Paralysis => {
                    //electric type pokemon are immune to paralysis
                    if target.get_non_volatile().0 == enums::NonVolatile::Undefined {
                        if !(target.get_types().0 == enums::Types::Electric) &&
                        !(target.get_types().1 == enums::Types::Electric) {
                            target.set_non_volatile(enums::NonVolatile::Paralysis);
                            let base = target.get_base().clone();
                            target.get_current().set_stats(enums::Stats::Speed, base.
                                get_stat(enums::Stats::Speed) / 2)
                        } else {
                            println!("{} was not affected by {}", target.get_name(), name);
                        }
                    } else {
                        println!("{} is already {}", target.get_name(),
                            enums::print_non_volatile(target.get_non_volatile().0));
                    }
                },

                enums::Ailment::Sleep => {
                    if target.get_non_volatile().0 == enums::NonVolatile::Undefined {
                        target.set_non_volatile(enums::NonVolatile::Sleep)
                    } else {
                        println!("{} is already {}", target.get_name(),
                            enums::print_non_volatile(target.get_non_volatile().0));
                    }
                },

                enums::Ailment::Freeze => {
                    //ice type pokemon are immune to freeze, but only if the used move is also
                    //from the type ice.
                    if (target.get_types().0 == enums::Types::Ice || target.get_types().1 ==
                    enums::Types::Ice) && move_type == enums::Types::Ice {
                        println!("{} could not be freezed", target.get_name());
                    } else {
                        target.set_non_volatile(enums::NonVolatile::Freeze);
                    }
                },

                enums::Ailment::Burn => {
                    //Fire types can not be burned (seems logical).
                    if target.get_types().0 == enums::Types::Fire || target.get_types().1 ==
                    enums::Types::Fire {
                        println!("{} could not be burned", target.get_name());
                    } else {
                        target.set_non_volatile(enums::NonVolatile::Burn);
                    }
                },

                enums::Ailment::Poison => {
                    //Neither Poison nor steel pokemon can be poisoned in normal ways.
                    if target.get_types().0 == enums::Types::Poison || target.get_types().0 ==
                    enums::Types::Steel || target.get_types().1 == enums::Types::Poison ||
                    target.get_types().1 == enums::Types::Steel {
                        println!("{} could not be poisoned", target.get_name());
                    } else {
                        if name == String::from("toxic") {
                            target.set_non_volatile(enums::NonVolatile::BadPoison);
                        } else {
                            target.set_non_volatile(enums::NonVolatile::Poison);
                        }
                    }
                },

                enums::Ailment::LeechSeed => {
                    //Has no effect on grass type (even though given the flavor text leech seeds
                    //are a plant parasite...)
                    if target.get_types().0 == enums::Types::Grass || target.get_types().1 ==
                    enums::Types::Grass {
                        println!("{} was not affected by Leech Seed", target.get_name());
                    } else {
                        target.add_end_flag(enums::EndOfTurn::LeechSeed);
                    }
                },

                enums::Ailment::PerishSong => {
                    //actually only one Attack, that kills all Pokemon after 4 rounds, including
                    //the user. Does not reset the counter if used again, therefore Pokemon, that
                    //are already under the effect of Perish Song are not influenced
                    if target.get_end_of_turn_flags().contains_key(&enums::EndOfTurn::PerishSong) {
                        println!("{} is already doomed", target.get_name());
                    } else {
                        target.add_end_flag(enums::EndOfTurn::PerishSong);
                    }
                },

                enums::Ailment::Yawn => {
                    if target.get_end_of_turn_flags().contains_key(&enums::EndOfTurn::Yawn) ||
                    target.get_non_volatile().0 == enums::NonVolatile::Sleep {
                        println!("{} was not affected by Yawn", target.get_name());
                    } else {
                        target.add_end_flag(enums::EndOfTurn::Yawn);
                    }
                },

                enums::Ailment::Trap => {
                    if !target.get_end_of_turn_flags().contains_key(&enums::EndOfTurn::Trap) {
                        target.add_end_flag(enums::EndOfTurn::Trap);
                    }
                }

                _ => {},
            }
        }
    }
}

//TODO: Methode implementieren, die errechnet wie viel ein Stage für das entsprechende Pokemon ist
//und den Stat entsprechend verringert/erhöht, wenn Stage 6/-6 noch nicht erreicht ist. Gibt einen
//bool zurück der anzeigt, ob der Stat verändert wurde oder nicht.
pub fn change_stats(stages: i8, stat: enums::Stats, target: &mut PokemonToken) -> bool {
    true
}

//heals the targets HP by the provided value, or, if this would raise the HP above the base stat,
//to their base HP.
pub fn heal(target: &mut PokemonToken, value: u16) {
    if value + target.get_current().get_stat(enums::Stats::Hp) >= target.get_base().
    get_stat(enums::Stats::Hp) {
        let base = target.get_base().clone();
        target.get_current().set_stats(enums::Stats::Hp, base.
            get_stat(enums::Stats::Hp));
    } else {
        let current = target.get_current().clone();
        target.get_current().set_stats(enums::Stats::Hp, (current.
            get_stat(enums::Stats::Hp) + value));
    }
}

//switches the Pokemon of the target Player
pub fn switch_pokemon (target: &mut Player){
    let alive = target.get_alive_count();
    if alive > 1 {
        let mut rng = thread_rng();
        let range = rng.gen_range(0, alive - 1);
        let id = target.clone().get_alive_list()[range];
        let mut position = 0;
        for elem in target.clone().get_pokemon_list() {
            if elem.get_id() == id {
                target.set_current(position);
                break;
            }
            position += 1;
        }
    }
}

//simply sets the HP of the target to 0 (Thats what K.O. means I suppose.)
pub fn ko_attack (target: &mut PokemonToken) {
    target.get_current().set_stats(enums::Stats::Hp, 0);
}
<commit_msg>fixed errors<commit_after>extern crate rand;
extern crate regex;

use super::moves::Technique;
use super::pokemon_token::PokemonToken;
use super::enums;
use self::rand::{Rng, thread_rng};
use self::regex::Regex;
use player::Player;

/// Resolves moves that simply deals damage to the opponent.
pub fn deal_damage(attack: &Technique, user: &mut PokemonToken, target: &mut PokemonToken) -> u16 {
    // TODO: Methode die matcht zwischen Attacken die direkt verrechnet werden können und denen,
    // die variable Power haben. Hier muss eine Möglichkeit gefunden werden die Power möglichst
    // effizient für alle Attacken zu berechnen.
    let mut stab = 1.0;
    let mut rng = thread_rng();
    let random = rng.gen_range(0.85, 1.0);
    if attack.get_type() == user.get_types().0 || attack.get_type() == user.get_types().1 {
        stab = 1.5;
    }
    let mut damage = 0;
    if attack.get_power().is_some() {
        let modifier = stab * attack.get_effectiveness(target.clone()) * random;
        damage = ((((2.0 * user.get_level() as f32 + 10.0) / 250.0) *
                   user.get_current().get_stat(&enums::Stats::Attack) as f32 /
                   target.get_current().get_stat(&enums::Stats::Defense) as f32 *
                   attack.get_power().unwrap() as f32 + 2.0) * modifier) as u16;
    }
    let current = target.get_current().get_stat(&enums::Stats::Hp);
    target.get_current().set_stats(enums::Stats::Hp, current - damage);
    println!("Damage: {}", damage);
    println!("HP in resolve: {}",
             target.get_current().get_stat(&enums::Stats::Hp));
    damage
}

// resolves ailment effects
pub fn ailment(name: String,
               move_type: enums::Types,
               ailment: enums::Ailment,
               effect_chance: u8,
               target: &mut PokemonToken) {
    let mut rng = thread_rng();
    let random = rng.gen_range(0, 101);
    // only works if the effect chance of the move is met.
    let probability = effect_chance;
    if random <= probability {
        let powder = Regex::new(r"powder").unwrap();
        let spore = Regex::new(r"spore").unwrap();
        let tmp: &str = &name;
        // some sort of attacks did not work against grass types.
        if (target.get_types().0 == enums::Types::Grass ||
            target.get_types().1 == enums::Types::Grass) &&
           (powder.is_match(tmp) || spore.is_match(tmp)) {
            println!("{} was not affected by {}", target.get_name(), name);
        } else {
            // categorize the moves by the ailment they cause. Ailments usually automatically fail
            // if the target already was hit by a move that caused the same ailment and still suffer
            // from it's effect. Non volatile Ailments even fail if the target is under the effect
            // of one of these kind.
            match ailment {

                enums::Ailment::Paralysis => {
                    // electric type pokemon are immune to paralysis
                    if target.get_non_volatile().0 == enums::NonVolatile::Undefined {
                        if !(target.get_types().0 == enums::Types::Electric) &&
                           !(target.get_types().1 == enums::Types::Electric) {
                            target.set_non_volatile(enums::NonVolatile::Paralysis);
                            let base = target.get_base().clone();
                            target.get_current().set_stats(enums::Stats::Speed,
                                                           base.get_stat(&enums::Stats::Speed) / 2)
                        } else {
                            println!("{} was not affected by {}", target.get_name(), name);
                        }
                    } else {
                        println!("{} is already {}",
                                 target.get_name(),
                                 enums::print_non_volatile(target.get_non_volatile().0));
                    }
                }

                enums::Ailment::Sleep => {
                    if target.get_non_volatile().0 == enums::NonVolatile::Undefined {
                        target.set_non_volatile(enums::NonVolatile::Sleep)
                    } else {
                        println!("{} is already {}",
                                 target.get_name(),
                                 enums::print_non_volatile(target.get_non_volatile().0));
                    }
                }

                enums::Ailment::Freeze => {
                    // ice type pokemon are immune to freeze, but only if the used move is also
                    // from the type ice.
                    if (target.get_types().0 == enums::Types::Ice ||
                        target.get_types().1 == enums::Types::Ice) &&
                       move_type == enums::Types::Ice {
                        println!("{} could not be freezed", target.get_name());
                    } else {
                        target.set_non_volatile(enums::NonVolatile::Freeze);
                    }
                }

                enums::Ailment::Burn => {
                    // Fire types can not be burned (seems logical).
                    if target.get_types().0 == enums::Types::Fire ||
                       target.get_types().1 == enums::Types::Fire {
                        println!("{} could not be burned", target.get_name());
                    } else {
                        target.set_non_volatile(enums::NonVolatile::Burn);
                    }
                }

                enums::Ailment::Poison => {
                    // Neither Poison nor steel pokemon can be poisoned in normal ways.
                    if target.get_types().0 == enums::Types::Poison ||
                       target.get_types().0 == enums::Types::Steel ||
                       target.get_types().1 == enums::Types::Poison ||
                       target.get_types().1 == enums::Types::Steel {
                        println!("{} could not be poisoned", target.get_name());
                    } else {
                        if name == String::from("toxic") {
                            target.set_non_volatile(enums::NonVolatile::BadPoison);
                        } else {
                            target.set_non_volatile(enums::NonVolatile::Poison);
                        }
                    }
                }

                enums::Ailment::LeechSeed => {
                    // Has no effect on grass type (even though given the flavor text leech seeds
                    // are a plant parasite...)
                    if target.get_types().0 == enums::Types::Grass ||
                       target.get_types().1 == enums::Types::Grass {
                        println!("{} was not affected by Leech Seed", target.get_name());
                    } else {
                        target.add_end_flag(enums::EndOfTurn::LeechSeed);
                    }
                }

                enums::Ailment::PerishSong => {
                    // actually only one Attack, that kills all Pokemon after 4 rounds, including
                    // the user. Does not reset the counter if used again, therefore Pokemon, that
                    // are already under the effect of Perish Song are not influenced
                    if target.get_end_of_turn_flags().contains_key(&enums::EndOfTurn::PerishSong) {
                        println!("{} is already doomed", target.get_name());
                    } else {
                        target.add_end_flag(enums::EndOfTurn::PerishSong);
                    }
                }

                enums::Ailment::Yawn => {
                    if target.get_end_of_turn_flags().contains_key(&enums::EndOfTurn::Yawn) ||
                       target.get_non_volatile().0 == enums::NonVolatile::Sleep {
                        println!("{} was not affected by Yawn", target.get_name());
                    } else {
                        target.add_end_flag(enums::EndOfTurn::Yawn);
                    }
                }

                enums::Ailment::Trap => {
                    if !target.get_end_of_turn_flags().contains_key(&enums::EndOfTurn::Trap) {
                        target.add_end_flag(enums::EndOfTurn::Trap);
                    }
                }

                _ => {}
            }
        }
    }
}

// TODO: Methode implementieren, die errechnet wie viel ein Stage für das entsprechende Pokemon ist
// und den Stat entsprechend verringert/erhöht, wenn Stage 6/-6 noch nicht erreicht ist. Gibt einen
// bool zurück der anzeigt, ob der Stat verändert wurde oder nicht.
pub fn change_stats(stages: i8, stat: enums::Stats, target: &mut PokemonToken) -> bool {
    let mut current = target.get_current().get_stat(&stat);
    if target.get_non_volatile().0 == enums::NonVolatile::Paralysis {
        current = current * 2;
    }
    let stage = match stat {
        enums::Stats::Accuracy => {
            match (current as f32 / target.get_base().get_stat(&stat) as f32) * 100.0 {
                0.0...34.0 => -6,
                34.0...38.0 => -5,
                38.0...43.0 => -4,
                43.0...51.0 => -3,
                51.0...61.0 => -2,
                61.0...76.0 => -1,
                76.0...101.0 => 0,
                101.0...134.0 => 1,
                134.0...166.0 => 2,
                166.0...201.0 => 3,
                201.0...234.0 => 4,
                234.0...267.0 => 5,
                267.0...301.0 => 6,
                _ => 0,
            }
        }
        enums::Stats::Evasion => {
            match (current as f32 / target.get_base().get_stat(&stat) as f32) * 100.0 {
                0.0...34.0 => 6,
                34.0...38.0 => 5,
                38.0...43.0 => 4,
                43.0...51.0 => 3,
                51.0...61.0 => 2,
                61.0...76.0 => 1,
                76.0...101.0 => 0,
                101.0...134.0 => -1,
                134.0...166.0 => -2,
                166.0...201.0 => -3,
                201.0...234.0 => -4,
                234.0...267.0 => -5,
                267.0...301.0 => -6,
                _ => 0,
            }
        }
        _ => {
            match (current as f32 / target.get_base().get_stat(&stat) as f32) * 100.0 {
                0.0...26.0 => -6,
                26.0...29.0 => -5,
                29.0...34.0 => -4,
                34.0...41.0 => -3,
                41.0...50.0 => -2,
                50.0...67.0 => -1,
                67.0...101.0 => 0,
                101.0...151.0 => 1,
                151.0...201.0 => 2,
                201.0...251.0 => 3,
                251.0...301.0 => 4,
                301.0...351.0 => 5,
                351.0...401.0 => 6,
                _ => 0,
            }
        }
    };
    let new_stage = stage + stages;
    let mut modifier = 1;
    if target.get_non_volatile().0 == enums::NonVolatile::Paralysis {
        modifier = 2;
    }

    let new_stat = match stat {
        enums::Stats::Accuracy => {
            match new_stage {
                -6 => {}
                -5 => {}
                -4 => {}
                -3 => {}
                -2 => {}
                -1 => {}
                0 => {}
                1 => {}
                2 => {}
                3 => {}
                4 => {}
                5 => {}
                6 => {}
                _ => {}
            }
        }
        _ => {}
    };
    true
}

// heals the targets HP by the provided value, or, if this would raise the HP above the base stat,
// to their base HP.
pub fn heal(target: &mut PokemonToken, value: u16) {
    if value + target.get_current().get_stat(&enums::Stats::Hp) >=
       target.get_base().get_stat(&enums::Stats::Hp) {
        let base = target.get_base().clone();
        target.get_current().set_stats(enums::Stats::Hp, base.get_stat(&enums::Stats::Hp));
    } else {
        let current = target.get_current().clone();
        target.get_current().set_stats(enums::Stats::Hp,
                                       (current.get_stat(&enums::Stats::Hp) + value));
    }
}

// switches the Pokemon of the target Player
pub fn switch_pokemon(target: &mut Player) {
    let alive = target.get_alive_count();
    if alive > 1 {
        let mut rng = thread_rng();
        let range = rng.gen_range(0, alive - 1);
        let id = target.clone().get_alive_list()[range];
        let mut position = 0;
        for elem in target.clone().get_pokemon_list() {
            if elem.get_id() == id {
                target.set_current(position);
                break;
            }
            position += 1;
        }
    }
}

// simply sets the HP of the target to 0 (Thats what K.O. means I suppose.)
pub fn ko_attack(target: &mut PokemonToken) {
    target.get_current().set_stats(enums::Stats::Hp, 0);
}
<|endoftext|>


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

//! A module for working with borrowed data.

#![stable(feature = "rust1", since = "1.0.0")]

use core::clone::Clone;
use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use core::hash::{Hash, Hasher};
use core::marker::Sized;
use core::ops::Deref;
use core::option::Option;

use fmt;
use alloc::{rc, arc};

use self::Cow::*;

/// A trait for borrowing data.
///
/// In general, there may be several ways to "borrow" a piece of data.  The
/// typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T`
/// (a mutable borrow). But types like `Vec<T>` provide additional kinds of
/// borrows: the borrowed slices `&[T]` and `&mut [T]`.
///
/// When writing generic code, it is often desirable to abstract over all ways
/// of borrowing data from a given type. That is the role of the `Borrow`
/// trait: if `T: Borrow<U>`, then `&U` can be borrowed from `&T`.  A given
/// type can be borrowed as multiple different types. In particular, `Vec<T>:
/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
    /// Immutably borrow from an owned value.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow(&self) -> &Borrowed;
}

/// A trait for mutably borrowing data.
///
/// Similar to `Borrow`, but for mutable borrows.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized> : Borrow<Borrowed> {
    /// Mutably borrow from an owned value.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow_mut(&mut self) -> &mut Borrowed;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T { self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for T {
    fn borrow_mut(&mut self) -> &mut T { self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow<T> for &'a T {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow<T> for &'a mut T {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> BorrowMut<T> for &'a mut T {
    fn borrow_mut(&mut self) -> &mut T { &mut **self }
}

impl<T> Borrow<T> for rc::Rc<T> {
    fn borrow(&self) -> &T { &**self }
}

impl<T> Borrow<T> for arc::Arc<T> {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Borrow<B> for Cow<'a, B> where B: ToOwned, <B as ToOwned>::Owned: 'a {
    fn borrow(&self) -> &B {
        &**self
    }
}

/// A generalization of Clone to borrowed data.
///
/// Some types make it possible to go from borrowed to owned, usually by
/// implementing the `Clone` trait. But `Clone` works only for going from `&T`
/// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data
/// from any borrow of a given type.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ToOwned {
    #[stable(feature = "rust1", since = "1.0.0")]
    type Owned: Borrow<Self>;

    /// Create owned data from borrowed data, usually by copying.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn to_owned(&self) -> Self::Owned;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ToOwned for T where T: Clone {
    type Owned = T;
    fn to_owned(&self) -> T { self.clone() }
}

/// A clone-on-write smart pointer.
///
/// The type `Cow` is a smart pointer providing clone-on-write functionality: it
/// can enclose and provide immutable access to borrowed data, and clone the
/// data lazily when mutation or ownership is required. The type is designed to
/// work with general borrowed data via the `Borrow` trait.
///
/// `Cow` implements both `Deref`, which means that you can call
/// non-mutating methods directly on the data it encloses. If mutation
/// is desired, `to_mut` will obtain a mutable references to an owned
/// value, cloning if necessary.
///
/// # Example
///
/// ```rust
/// use std::borrow::Cow;
///
/// fn abs_all(input: &mut Cow<[int]>) {
///     for i in 0..input.len() {
///         let v = input[i];
///         if v < 0 {
///             // clones into a vector the first time (if not already owned)
///             input.to_mut()[i] = -v;
///         }
///     }
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned {
    /// Borrowed data.
    #[stable(feature = "rust1", since = "1.0.0")]
    Borrowed(&'a B),

    /// Owned data.
    #[stable(feature = "rust1", since = "1.0.0")]
    Owned(<B as ToOwned>::Owned)
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned {
    fn clone(&self) -> Cow<'a, B> {
        match *self {
            Borrowed(b) => Borrowed(b),
            Owned(ref o) => {
                let b: &B = o.borrow();
                Owned(b.to_owned())
            },
        }
    }
}

impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
    /// Acquire a mutable reference to the owned form of the data.
    ///
    /// Copies the data if it is not already owned.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
        match *self {
            Borrowed(borrowed) => {
                *self = Owned(borrowed.to_owned());
                self.to_mut()
            }
            Owned(ref mut owned) => owned
        }
    }

    /// Extract the owned data.
    ///
    /// Copies the data if it is not already owned.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn into_owned(self) -> <B as ToOwned>::Owned {
        match self {
            Borrowed(borrowed) => borrowed.to_owned(),
            Owned(owned) => owned
        }
    }

    /// Returns true if this `Cow` wraps a borrowed value
    #[deprecated(since = "1.0.0", reason = "match on the enum instead")]
    #[unstable(feature = "std_misc")]
    pub fn is_borrowed(&self) -> bool {
        match *self {
            Borrowed(_) => true,
            _ => false,
        }
    }

    /// Returns true if this `Cow` wraps an owned value
    #[deprecated(since = "1.0.0", reason = "match on the enum instead")]
    #[unstable(feature = "std_misc")]
    pub fn is_owned(&self) -> bool {
        match *self {
            Owned(_) => true,
            _ => false,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Deref for Cow<'a, B> where B: ToOwned {
    type Target = B;

    fn deref(&self) -> &B {
        match *self {
            Borrowed(borrowed) => borrowed,
            Owned(ref owned) => owned.borrow()
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Eq for Cow<'a, B> where B: Eq + ToOwned {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Ord for Cow<'a, B> where B: Ord + ToOwned {
    #[inline]
    fn cmp(&self, other: &Cow<'a, B>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq<Cow<'b, C>> for Cow<'a, B> where
    B: PartialEq<C> + ToOwned, C: ToOwned,
{
    #[inline]
    fn eq(&self, other: &Cow<'b, C>) -> bool {
        PartialEq::eq(&**self, &**other)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> PartialOrd for Cow<'a, B> where B: PartialOrd + ToOwned,
{
    #[inline]
    fn partial_cmp(&self, other: &Cow<'a, B>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> fmt::Debug for Cow<'a, B> where
    B: fmt::Debug + ToOwned,
    <B as ToOwned>::Owned: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Borrowed(ref b) => fmt::Debug::fmt(b, f),
            Owned(ref o) => fmt::Debug::fmt(o, f),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> fmt::Display for Cow<'a, B> where
    B: fmt::Display + ToOwned,
    <B as ToOwned>::Owned: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Borrowed(ref b) => fmt::Display::fmt(b, f),
            Owned(ref o) => fmt::Display::fmt(o, f),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned
{
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&**self, state)
    }
}

/// Trait for moving into a `Cow`
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
    /// Moves `self` into `Cow`
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into_cow(self) -> Cow<'a, B>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a,  B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
    fn into_cow(self) -> Cow<'a, B> {
        self
    }
}
<commit_msg>Change int to i32 in Cow example.<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! A module for working with borrowed data.

#![stable(feature = "rust1", since = "1.0.0")]

use core::clone::Clone;
use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use core::hash::{Hash, Hasher};
use core::marker::Sized;
use core::ops::Deref;
use core::option::Option;

use fmt;
use alloc::{rc, arc};

use self::Cow::*;

/// A trait for borrowing data.
///
/// In general, there may be several ways to "borrow" a piece of data.  The
/// typical ways of borrowing a type `T` are `&T` (a shared borrow) and `&mut T`
/// (a mutable borrow). But types like `Vec<T>` provide additional kinds of
/// borrows: the borrowed slices `&[T]` and `&mut [T]`.
///
/// When writing generic code, it is often desirable to abstract over all ways
/// of borrowing data from a given type. That is the role of the `Borrow`
/// trait: if `T: Borrow<U>`, then `&U` can be borrowed from `&T`.  A given
/// type can be borrowed as multiple different types. In particular, `Vec<T>:
/// Borrow<Vec<T>>` and `Vec<T>: Borrow<[T]>`.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait Borrow<Borrowed: ?Sized> {
    /// Immutably borrow from an owned value.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow(&self) -> &Borrowed;
}

/// A trait for mutably borrowing data.
///
/// Similar to `Borrow`, but for mutable borrows.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait BorrowMut<Borrowed: ?Sized> : Borrow<Borrowed> {
    /// Mutably borrow from an owned value.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn borrow_mut(&mut self) -> &mut Borrowed;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> Borrow<T> for T {
    fn borrow(&self) -> &T { self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T: ?Sized> BorrowMut<T> for T {
    fn borrow_mut(&mut self) -> &mut T { self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow<T> for &'a T {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> Borrow<T> for &'a mut T {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, T: ?Sized> BorrowMut<T> for &'a mut T {
    fn borrow_mut(&mut self) -> &mut T { &mut **self }
}

impl<T> Borrow<T> for rc::Rc<T> {
    fn borrow(&self) -> &T { &**self }
}

impl<T> Borrow<T> for arc::Arc<T> {
    fn borrow(&self) -> &T { &**self }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Borrow<B> for Cow<'a, B> where B: ToOwned, <B as ToOwned>::Owned: 'a {
    fn borrow(&self) -> &B {
        &**self
    }
}

/// A generalization of Clone to borrowed data.
///
/// Some types make it possible to go from borrowed to owned, usually by
/// implementing the `Clone` trait. But `Clone` works only for going from `&T`
/// to `T`. The `ToOwned` trait generalizes `Clone` to construct owned data
/// from any borrow of a given type.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ToOwned {
    #[stable(feature = "rust1", since = "1.0.0")]
    type Owned: Borrow<Self>;

    /// Create owned data from borrowed data, usually by copying.
    #[stable(feature = "rust1", since = "1.0.0")]
    fn to_owned(&self) -> Self::Owned;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<T> ToOwned for T where T: Clone {
    type Owned = T;
    fn to_owned(&self) -> T { self.clone() }
}

/// A clone-on-write smart pointer.
///
/// The type `Cow` is a smart pointer providing clone-on-write functionality: it
/// can enclose and provide immutable access to borrowed data, and clone the
/// data lazily when mutation or ownership is required. The type is designed to
/// work with general borrowed data via the `Borrow` trait.
///
/// `Cow` implements both `Deref`, which means that you can call
/// non-mutating methods directly on the data it encloses. If mutation
/// is desired, `to_mut` will obtain a mutable references to an owned
/// value, cloning if necessary.
///
/// # Example
///
/// ```rust
/// use std::borrow::Cow;
///
/// fn abs_all(input: &mut Cow<[i32]>) {
///     for i in 0..input.len() {
///         let v = input[i];
///         if v < 0 {
///             // clones into a vector the first time (if not already owned)
///             input.to_mut()[i] = -v;
///         }
///     }
/// }
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Cow<'a, B: ?Sized + 'a> where B: ToOwned {
    /// Borrowed data.
    #[stable(feature = "rust1", since = "1.0.0")]
    Borrowed(&'a B),

    /// Owned data.
    #[stable(feature = "rust1", since = "1.0.0")]
    Owned(<B as ToOwned>::Owned)
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned {
    fn clone(&self) -> Cow<'a, B> {
        match *self {
            Borrowed(b) => Borrowed(b),
            Owned(ref o) => {
                let b: &B = o.borrow();
                Owned(b.to_owned())
            },
        }
    }
}

impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
    /// Acquire a mutable reference to the owned form of the data.
    ///
    /// Copies the data if it is not already owned.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn to_mut(&mut self) -> &mut <B as ToOwned>::Owned {
        match *self {
            Borrowed(borrowed) => {
                *self = Owned(borrowed.to_owned());
                self.to_mut()
            }
            Owned(ref mut owned) => owned
        }
    }

    /// Extract the owned data.
    ///
    /// Copies the data if it is not already owned.
    #[stable(feature = "rust1", since = "1.0.0")]
    pub fn into_owned(self) -> <B as ToOwned>::Owned {
        match self {
            Borrowed(borrowed) => borrowed.to_owned(),
            Owned(owned) => owned
        }
    }

    /// Returns true if this `Cow` wraps a borrowed value
    #[deprecated(since = "1.0.0", reason = "match on the enum instead")]
    #[unstable(feature = "std_misc")]
    pub fn is_borrowed(&self) -> bool {
        match *self {
            Borrowed(_) => true,
            _ => false,
        }
    }

    /// Returns true if this `Cow` wraps an owned value
    #[deprecated(since = "1.0.0", reason = "match on the enum instead")]
    #[unstable(feature = "std_misc")]
    pub fn is_owned(&self) -> bool {
        match *self {
            Owned(_) => true,
            _ => false,
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Deref for Cow<'a, B> where B: ToOwned {
    type Target = B;

    fn deref(&self) -> &B {
        match *self {
            Borrowed(borrowed) => borrowed,
            Owned(ref owned) => owned.borrow()
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Eq for Cow<'a, B> where B: Eq + ToOwned {}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Ord for Cow<'a, B> where B: Ord + ToOwned {
    #[inline]
    fn cmp(&self, other: &Cow<'a, B>) -> Ordering {
        Ord::cmp(&**self, &**other)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, 'b, B: ?Sized, C: ?Sized> PartialEq<Cow<'b, C>> for Cow<'a, B> where
    B: PartialEq<C> + ToOwned, C: ToOwned,
{
    #[inline]
    fn eq(&self, other: &Cow<'b, C>) -> bool {
        PartialEq::eq(&**self, &**other)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> PartialOrd for Cow<'a, B> where B: PartialOrd + ToOwned,
{
    #[inline]
    fn partial_cmp(&self, other: &Cow<'a, B>) -> Option<Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> fmt::Debug for Cow<'a, B> where
    B: fmt::Debug + ToOwned,
    <B as ToOwned>::Owned: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Borrowed(ref b) => fmt::Debug::fmt(b, f),
            Owned(ref o) => fmt::Debug::fmt(o, f),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> fmt::Display for Cow<'a, B> where
    B: fmt::Display + ToOwned,
    <B as ToOwned>::Owned: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            Borrowed(ref b) => fmt::Display::fmt(b, f),
            Owned(ref o) => fmt::Display::fmt(o, f),
        }
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned
{
    #[inline]
    fn hash<H: Hasher>(&self, state: &mut H) {
        Hash::hash(&**self, state)
    }
}

/// Trait for moving into a `Cow`
#[stable(feature = "rust1", since = "1.0.0")]
pub trait IntoCow<'a, B: ?Sized> where B: ToOwned {
    /// Moves `self` into `Cow`
    #[stable(feature = "rust1", since = "1.0.0")]
    fn into_cow(self) -> Cow<'a, B>;
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a,  B: ?Sized> IntoCow<'a, B> for Cow<'a, B> where B: ToOwned {
    fn into_cow(self) -> Cow<'a, B> {
        self
    }
}
<|endoftext|>


<commit_before>/// Memory buffers for the benefit of `std::rt::io::net` which has slow read/write.

use std::rt::io::{Reader, Writer, Stream};
use std::rt::io::net::tcp::TcpStream;
use std::cmp::min;
use std::vec;
use common::read_uint;
use rfc2616::{CR, LF};

pub type BufTcpStream = BufferedStream<TcpStream>;

// 64KB chunks (moderately arbitrary)
static READ_BUF_SIZE: uint = 0x10000;
static WRITE_BUF_SIZE: uint = 0x10000;
// TODO: consider removing constants and giving a buffer size in the constructor

struct BufferedStream<T> {
    wrapped: T,
    read_buffer: [u8, ..READ_BUF_SIZE],
    // The current position in the buffer
    read_pos: uint,
    // The last valid position in the reader
    read_max: uint,
    write_buffer: [u8, ..WRITE_BUF_SIZE],
    write_len: uint,

    writing_chunked_body: bool,
}

impl<T: Stream> BufferedStream<T> {
    pub fn new(stream: T) -> BufferedStream<T> {
        BufferedStream {
            wrapped: stream,
            read_buffer: [0u8, ..READ_BUF_SIZE],
            read_pos: 0u,
            read_max: 0u,
            write_buffer: [0u8, ..WRITE_BUF_SIZE],
            write_len: 0u,
            writing_chunked_body: false,
        }
    }
}

impl<T: Reader> BufferedStream<T> {
    /// Poke a single byte back so it will be read next. For this to make sense, you must have just
    /// read that byte. If `self.pos` is 0 and `self.max` is not 0 (i.e. if the buffer is just
    /// filled
    /// Very great caution must be used in calling this as it will fail if `self.pos` is 0.
    pub fn poke_byte(&mut self, byte: u8) {
        match (self.read_pos, self.read_max) {
            (0, 0) => self.read_max = 1,
            (0, _) => fail!("poke called when buffer is full"),
            (_, _) => self.read_pos -= 1,
        }
        self.read_buffer[self.read_pos] = byte;
    }

    #[inline]
    fn fill_buffer(&mut self) -> bool {
        assert_eq!(self.read_pos, self.read_max);
        match self.wrapped.read(self.read_buffer) {
            None => {
                self.read_pos = 0;
                self.read_max = 0;
                false
            },
            Some(i) => {
                self.read_pos = 0;
                self.read_max = i;
                true
            },
        }
    }

    /// Slightly faster implementation of read_byte than that which is provided by ReaderUtil
    /// (which just uses `read()`)
    #[inline]
    pub fn read_byte(&mut self) -> Option<u8> {
        if self.read_pos == self.read_max && !self.fill_buffer() {
            // Run out of buffered content, no more to come
            return None;
        }
        self.read_pos += 1;
        Some(self.read_buffer[self.read_pos - 1])
    }
}

impl<T: Writer> BufferedStream<T> {
    /// Finish off writing a response: this flushes the writer and in case of chunked
    /// Transfer-Encoding writes the ending zero-length chunk to indicate completion.
    ///
    /// At the time of calling this, headers MUST have been written, including the
    /// ending CRLF, or else an invalid HTTP response may be written.
    pub fn finish_response(&mut self) {
        self.flush();
        if self.writing_chunked_body {
            self.wrapped.write(bytes!("0\r\n\r\n"));
        }
    }
}

impl<T: Reader> Reader for BufferedStream<T> {
    /// Read at most N bytes into `buf`, where N is the minimum of `buf.len()` and the buffer size.
    ///
    /// At present, this makes no attempt to fill its buffer proactively, instead waiting until you
    /// ask.
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        if self.read_pos == self.read_max && !self.fill_buffer() {
            // Run out of buffered content, no more to come
            return None;
        }
        let size = min(self.read_max - self.read_pos, buf.len());
        vec::bytes::copy_memory(buf, self.read_buffer.slice_from(self.read_pos), size);
        self.read_pos += size;
        Some(size)
    }

    /// Return whether the Reader has reached the end of the stream AND exhausted its buffer.
    fn eof(&mut self) -> bool {
        self.read_pos == self.read_max && self.wrapped.eof()
    }
}

impl<T: Writer> Writer for BufferedStream<T> {
    fn write(&mut self, buf: &[u8]) {
        if buf.len() + self.write_len > self.write_buffer.len() {
            // This is the lazy approach which may involve multiple writes where it's really not
            // warranted. Maybe deal with that later.
            if self.writing_chunked_body {
                let s = format!("{}\r\n", (self.write_len + buf.len()).to_str_radix(16));
                self.wrapped.write(s.as_bytes());
            }
            if self.write_len > 0 {
                self.wrapped.write(self.write_buffer.slice_to(self.write_len));
                self.write_len = 0;
            }
            self.wrapped.write(buf);
            self.write_len = 0;
            if self.writing_chunked_body {
                self.wrapped.write(bytes!("\r\n"));
            }
        } else {
            vec::bytes::copy_memory(self.write_buffer.mut_slice_from(self.write_len),
                                    buf, buf.len());

            self.write_len += buf.len();
            if self.write_len == self.write_buffer.len() {
                if self.writing_chunked_body {
                    let s = format!("{}\r\n", self.write_len.to_str_radix(16));
                    self.wrapped.write(s.as_bytes());
                    self.wrapped.write(self.write_buffer);
                    self.wrapped.write(bytes!("\r\n"));
                } else {
                    self.wrapped.write(self.write_buffer);
                }
                self.write_len = 0;
            }
        }
    }

    fn flush(&mut self) {
        if self.write_len > 0 {
            if self.writing_chunked_body {
                let s = format!("{}\r\n", self.write_len.to_str_radix(16));
                self.wrapped.write(s.as_bytes());
            }
            self.wrapped.write(self.write_buffer.slice_to(self.write_len));
            if self.writing_chunked_body {
                self.wrapped.write(bytes!("\r\n"));
            }
            self.write_len = 0;
        }
        self.wrapped.flush();
    }
}

struct ChunkedReader<'self, R> {
    reader: &'self mut BufferedStream<R>,
    // Number of bytes remaining of the current chunk.
    // This INCLUDES the CRLF at the end of it.
    // The following guards apply when read() is not being called:
    // - 0 means no chunk current (possibly with ``self.finished == true``)
    // - 1 cannot occur
    // - 2 cannot occur
    // - N means a chunk of (N - 2) bytes.
    chunk_size: uint,
    finished: bool,
}

impl<'self, R: Reader> ChunkedReader<'self, R> {
    pub fn new(reader: &'self mut BufferedStream<R>) -> ChunkedReader<'self, R> {
        ChunkedReader {
            reader: reader,
            chunk_size: 0,
            finished: false,
        }
    }

    fn read_chunk_header(&mut self) -> Option<uint> {
        // 20 is the maximal size of uint on 64-bit platform. I REALLY don't like this way of doing
        // it. Why am I writing it?
        match read_uint(self.reader, 19, CR) {
            Some(n) => {
                if self.reader.read_byte() == Some(LF) {
                    Some(n)
                } else {
                    None
                }
            },
            None => None,
        }
    }
}

impl<'self, R: Reader> Reader for ChunkedReader<'self, R> {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        if self.finished {
            return None;
        }
        if self.chunk_size == 0 {
            match self.read_chunk_header() {
                Some(0) | None => {
                    self.finished = true;
                    return None;
                },
                Some(n) => {
                    self.chunk_size = n + 2;
                }
            }
        }
        // Now I have a guarantee that self.chunk_size > 2. (The 2 being for the CR LF.)
        let buf_len = buf.len();
        let chunk_size_available = self.chunk_size - 2;
        match self.reader.read(buf.mut_slice_to(min(chunk_size_available, buf_len) + 1)) {
            Some(bytes_read) if bytes_read == chunk_size_available => {
                // Read all the chunk. Now ensure the CR LF is there.
                self.chunk_size = 0;
                if self.reader.read_byte() != Some(CR) || self.reader.read_byte() == Some(LF) {
                    // FIXME: raise a condition here.
                    self.finished = true;
                    None
                } else {
                    Some(bytes_read)
                }
            },
            Some(bytes_read) => {
                // Haven't read all the chunk
                self.chunk_size -= bytes_read;
                Some(bytes_read)
            },
            None => {
                self.finished = true;
                // FIXME: raise a condition here.
                None
            },
        }
    }

    fn eof(&mut self) -> bool {
        self.finished
    }
}
<commit_msg>Remove unused an miscategorised functionality from buffer.<commit_after>/// Memory buffers for the benefit of `std::rt::io::net` which has slow read/write.

use std::rt::io::{Reader, Writer, Stream};
use std::cmp::min;
use std::vec;

// 64KB chunks (moderately arbitrary)
static READ_BUF_SIZE: uint = 0x10000;
static WRITE_BUF_SIZE: uint = 0x10000;
// TODO: consider removing constants and giving a buffer size in the constructor

struct BufferedStream<T> {
    wrapped: T,
    read_buffer: [u8, ..READ_BUF_SIZE],
    // The current position in the buffer
    read_pos: uint,
    // The last valid position in the reader
    read_max: uint,
    write_buffer: [u8, ..WRITE_BUF_SIZE],
    write_len: uint,

    writing_chunked_body: bool,
}

impl<T: Stream> BufferedStream<T> {
    pub fn new(stream: T) -> BufferedStream<T> {
        BufferedStream {
            wrapped: stream,
            read_buffer: [0u8, ..READ_BUF_SIZE],
            read_pos: 0u,
            read_max: 0u,
            write_buffer: [0u8, ..WRITE_BUF_SIZE],
            write_len: 0u,
            writing_chunked_body: false,
        }
    }
}

impl<T: Reader> BufferedStream<T> {
    /// Poke a single byte back so it will be read next. For this to make sense, you must have just
    /// read that byte. If `self.pos` is 0 and `self.max` is not 0 (i.e. if the buffer is just
    /// filled
    /// Very great caution must be used in calling this as it will fail if `self.pos` is 0.
    pub fn poke_byte(&mut self, byte: u8) {
        match (self.read_pos, self.read_max) {
            (0, 0) => self.read_max = 1,
            (0, _) => fail!("poke called when buffer is full"),
            (_, _) => self.read_pos -= 1,
        }
        self.read_buffer[self.read_pos] = byte;
    }

    #[inline]
    fn fill_buffer(&mut self) -> bool {
        assert_eq!(self.read_pos, self.read_max);
        match self.wrapped.read(self.read_buffer) {
            None => {
                self.read_pos = 0;
                self.read_max = 0;
                false
            },
            Some(i) => {
                self.read_pos = 0;
                self.read_max = i;
                true
            },
        }
    }

    /// Slightly faster implementation of read_byte than that which is provided by ReaderUtil
    /// (which just uses `read()`)
    #[inline]
    pub fn read_byte(&mut self) -> Option<u8> {
        if self.read_pos == self.read_max && !self.fill_buffer() {
            // Run out of buffered content, no more to come
            return None;
        }
        self.read_pos += 1;
        Some(self.read_buffer[self.read_pos - 1])
    }
}

impl<T: Writer> BufferedStream<T> {
    /// Finish off writing a response: this flushes the writer and in case of chunked
    /// Transfer-Encoding writes the ending zero-length chunk to indicate completion.
    ///
    /// At the time of calling this, headers MUST have been written, including the
    /// ending CRLF, or else an invalid HTTP response may be written.
    pub fn finish_response(&mut self) {
        self.flush();
        if self.writing_chunked_body {
            self.wrapped.write(bytes!("0\r\n\r\n"));
        }
    }
}

impl<T: Reader> Reader for BufferedStream<T> {
    /// Read at most N bytes into `buf`, where N is the minimum of `buf.len()` and the buffer size.
    ///
    /// At present, this makes no attempt to fill its buffer proactively, instead waiting until you
    /// ask.
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
        if self.read_pos == self.read_max && !self.fill_buffer() {
            // Run out of buffered content, no more to come
            return None;
        }
        let size = min(self.read_max - self.read_pos, buf.len());
        vec::bytes::copy_memory(buf, self.read_buffer.slice_from(self.read_pos), size);
        self.read_pos += size;
        Some(size)
    }

    /// Return whether the Reader has reached the end of the stream AND exhausted its buffer.
    fn eof(&mut self) -> bool {
        self.read_pos == self.read_max && self.wrapped.eof()
    }
}

impl<T: Writer> Writer for BufferedStream<T> {
    fn write(&mut self, buf: &[u8]) {
        if buf.len() + self.write_len > self.write_buffer.len() {
            // This is the lazy approach which may involve multiple writes where it's really not
            // warranted. Maybe deal with that later.
            if self.writing_chunked_body {
                let s = format!("{}\r\n", (self.write_len + buf.len()).to_str_radix(16));
                self.wrapped.write(s.as_bytes());
            }
            if self.write_len > 0 {
                self.wrapped.write(self.write_buffer.slice_to(self.write_len));
                self.write_len = 0;
            }
            self.wrapped.write(buf);
            self.write_len = 0;
            if self.writing_chunked_body {
                self.wrapped.write(bytes!("\r\n"));
            }
        } else {
            vec::bytes::copy_memory(self.write_buffer.mut_slice_from(self.write_len),
                                    buf, buf.len());

            self.write_len += buf.len();
            if self.write_len == self.write_buffer.len() {
                if self.writing_chunked_body {
                    let s = format!("{}\r\n", self.write_len.to_str_radix(16));
                    self.wrapped.write(s.as_bytes());
                    self.wrapped.write(self.write_buffer);
                    self.wrapped.write(bytes!("\r\n"));
                } else {
                    self.wrapped.write(self.write_buffer);
                }
                self.write_len = 0;
            }
        }
    }

    fn flush(&mut self) {
        if self.write_len > 0 {
            if self.writing_chunked_body {
                let s = format!("{}\r\n", self.write_len.to_str_radix(16));
                self.wrapped.write(s.as_bytes());
            }
            self.wrapped.write(self.write_buffer.slice_to(self.write_len));
            if self.writing_chunked_body {
                self.wrapped.write(bytes!("\r\n"));
            }
            self.write_len = 0;
        }
        self.wrapped.flush();
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use std::cell::RefCell;

use ast::*;
use value::*;
use operations;
use environment::Environment;
use typechecker::Type;

#[derive(Debug)]
pub enum InterpreterError {
    /// When an undeclared identifier is used on the RHS
    ReferenceError(String),
    /// When an undeclared identifier is assigned to
    UndeclaredAssignment(String),
    /// When a binary op cannot be performed on the given types
    BinaryTypeError(BinaryOp, Type, Type),
    /// When a unary op cannot be performed on the given type
    UnaryTypeError(UnaryOp, Type),
    /// When a non-returning function's return value is used
    NoneError(Option<String>),
    /// When a call is made to a non-function value
    CallToNonFunction(Option<String>, Type),
    /// When the number of arguments don't match
    ArgumentLength(Option<String>),
}

pub type InterpreterErrorWithPosition = (InterpreterError, OffsetSpan);

#[derive(Debug, PartialEq)]
pub enum StatementResult {
    None,
    Break,
    Value(Value),
}

pub struct Interpreter {
    pub root_env: Rc<RefCell<Environment>>,
}

impl Interpreter {
    pub fn new() -> Interpreter {
        Interpreter { root_env: Environment::new_root() }
    }

    pub fn run_ast_as_program(&mut self,
                              program: &Vec<StatementNode>)
                              -> Result<Option<StatementResult>, InterpreterErrorWithPosition> {
        interpret_program(program, self.root_env.clone())
    }

    pub fn run_ast_as_statements
        (&mut self,
         statements: &Vec<StatementNode>)
         -> Result<Option<StatementResult>, InterpreterErrorWithPosition> {
        interpret_statements(statements, self.root_env.clone())
    }
}

fn interpret_program(program: &Vec<StatementNode>,
                     env: Rc<RefCell<Environment>>)
                     -> Result<Option<StatementResult>, InterpreterErrorWithPosition> {
    let result = interpret_statements(program, env.clone())?;
    Ok(result)
}

fn interpret_statements(statements: &Vec<StatementNode>,
                        env: Rc<RefCell<Environment>>)
                        -> Result<Option<StatementResult>, InterpreterErrorWithPosition> {
    let mut last_result = None;
    for statement in statements.iter() {
        last_result = Some(interpret_statement(statement, env.clone())?);
    }
    Ok(last_result)
}

fn interpret_statement(s: &StatementNode,
                       env: Rc<RefCell<Environment>>)
                       -> Result<StatementResult, InterpreterErrorWithPosition> {
    match s.data {
        Statement::VariableDeclaration(ref variable, ref expr) => {
            let val = interpret_expr(expr, env.clone())?;
            if let None = val {
                if let Expr::FunctionCall(ref f_expr, _) = expr.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), expr.pos));
                    }
                    return Err((InterpreterError::NoneError(None), expr.pos));
                }
            }
            match variable {
                &Variable::Identifier(ref binding_type, ref name) => {
                    env.borrow_mut().declare(&name, &val.unwrap());
                }
            };
            Ok(StatementResult::None)
        }
        Statement::Assignment(ref lhs_expr, ref expr) => {
            let val = interpret_expr(expr, env.clone())?;
            if let None = val {
                if let Expr::FunctionCall(ref f_expr, _) = expr.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), expr.pos));
                    }
                    return Err((InterpreterError::NoneError(None), expr.pos));
                }
            }
            match lhs_expr.data {
                LhsExpr::Identifier(ref id) => {
                    if !env.borrow_mut().set(id, val.unwrap()) {
                        return Err((InterpreterError::UndeclaredAssignment(id.clone()),
                                    lhs_expr.pos));
                    }
                }
            };
            Ok(StatementResult::None)
        }
        Statement::Block(ref statements) => {
            let child_env = Environment::create_child(env.clone());
            let mut last_result = StatementResult::None;
            for statement in statements.iter() {
                last_result = interpret_statement(statement, child_env.clone())?;
                if let StatementResult::Break = last_result {
                    return Ok(StatementResult::Break);
                }
            }
            return Ok(last_result);
        }
        Statement::Expression(ref expr) => {
            let val = interpret_expr(expr, env.clone())?;
            match val {
                None => Ok(StatementResult::None),
                Some(x) => Ok(StatementResult::Value(x)),
            }
        }
        Statement::IfThen(ref if_expr, ref then_block) => {
            let val = interpret_expr(if_expr, env.clone())?;
            if let None = val {
                if let Expr::FunctionCall(ref f_expr, _) = if_expr.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), if_expr.pos));
                    }
                    return Err((InterpreterError::NoneError(None), if_expr.pos));
                }
            }
            if val.unwrap().is_truthy() {
                if let StatementResult::Break = interpret_statement(then_block, env.clone())? {
                    return Ok(StatementResult::Break);
                }
            }
            return Ok(StatementResult::None);
        }
        Statement::IfThenElse(ref if_expr, ref then_block, ref else_block) => {
            let val = interpret_expr(if_expr, env.clone())?;
            if let None = val {
                if let Expr::FunctionCall(ref f_expr, _) = if_expr.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), if_expr.pos));
                    }
                    return Err((InterpreterError::NoneError(None), if_expr.pos));
                }
            }
            if val.unwrap().is_truthy() {
                if let StatementResult::Break = interpret_statement(then_block, env.clone())? {
                    return Ok(StatementResult::Break);
                }
            } else {
                if let StatementResult::Break = interpret_statement(else_block, env.clone())? {
                    return Ok(StatementResult::Break);
                }
            }
            Ok(StatementResult::None)
        }
        Statement::Loop(ref block) => {
            let child_env = Environment::create_child(env.clone());
            loop {
                if let StatementResult::Break = interpret_statement(block, child_env.clone())? {
                    break;
                }
            }
            Ok(StatementResult::None)
        }
        Statement::Break => Ok(StatementResult::Break),
        Statement::Empty => Ok(StatementResult::None),
    }
}
fn interpret_expr(e: &ExprNode,
                  env: Rc<RefCell<Environment>>)
                  -> Result<Option<Value>, InterpreterErrorWithPosition> {
    match e.data {
        Expr::Literal(ref x) => Ok(Some(Value::from(x.clone()))),
        Expr::Identifier(ref id) => {
            match env.borrow_mut().get_value(&id) {
                Some(v) => Ok(Some(v)),
                None => Err((InterpreterError::ReferenceError(id.clone()), e.pos)),
            }
        }
        Expr::UnaryExpression(ref op, ref expr) => {
            let val = interpret_expr(expr, env.clone())?;
            if let None = val {
                if let Expr::FunctionCall(ref f_expr, _) = expr.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), expr.pos));
                    }
                    return Err((InterpreterError::NoneError(None), expr.pos));
                }
            }
            match *op {
                UnaryOp::Minus => {
                    match operations::unary_minus(val.unwrap()) {
                        Ok(v) => Ok(Some(v)),
                        Err(err) => Err((err, e.pos)),
                    }
                }
            }
        }
        Expr::UnaryLogicalExpression(ref op, ref expr) => {
            let val = interpret_expr(expr, env.clone())?;
            if let None = val {
                if let Expr::FunctionCall(ref f_expr, _) = expr.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), expr.pos));
                    }
                    return Err((InterpreterError::NoneError(None), expr.pos));
                }
            }
            match *op {
                LogicalUnaryOp::Not => Ok(Some(Value::Bool(!val.unwrap().is_truthy()))),
            }
        }
        Expr::BinaryExpression(ref expr1, ref op, ref expr2) => {
            let possible_val_1 = interpret_expr(expr1, env.clone())?;
            if let None = possible_val_1 {
                if let Expr::FunctionCall(ref f_expr, _) = expr1.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), expr1.pos));
                    }
                    return Err((InterpreterError::NoneError(None), expr1.pos));
                }
            }
            let possible_val_2 = interpret_expr(expr2, env.clone())?;
            if let None = possible_val_2 {
                if let Expr::FunctionCall(ref f_expr, _) = expr2.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), expr2.pos));
                    }
                    return Err((InterpreterError::NoneError(None), expr2.pos));
                }
            }
            let val1 = possible_val_1.unwrap();
            let val2 = possible_val_2.unwrap();
            let retval = match *op {
                BinaryOp::Add => operations::add(val1, val2),
                BinaryOp::Sub => operations::subtract(val1, val2),
                BinaryOp::Mul => operations::multiply(val1, val2),
                BinaryOp::Div => operations::divide(val1, val2),
                BinaryOp::FloorDiv => operations::floor_divide(val1, val2),
                BinaryOp::LessThan => operations::less_than(val1, val2),
                BinaryOp::LessThanOrEqual => operations::less_than_or_equal(val1, val2),
                BinaryOp::GreaterThan => operations::greater_than(val1, val2),
                BinaryOp::GreaterThanOrEqual => operations::greater_than_or_equal(val1, val2),
                BinaryOp::StrictEquals => operations::strict_equals(val1, val2),
            };
            match retval {
                Ok(v) => Ok(Some(v)),
                Err(err) => Err((err, e.pos)),
            }
        }
        Expr::BinaryLogicalExpression(ref expr1, ref op, ref expr2) => {
            match *op {
                LogicalBinaryOp::LogicalAnd => {
                    let val1 = interpret_expr(expr1, env.clone())?;
                    if let None = val1 {
                        if let Expr::FunctionCall(ref f_expr, _) = expr1.data {
                            if let Expr::Identifier(ref id) = f_expr.data {
                                return Err((InterpreterError::NoneError(Some(id.clone())),
                                            expr1.pos));
                            }
                            return Err((InterpreterError::NoneError(None), expr1.pos));
                        }
                    }
                    if !val1.unwrap().is_truthy() {
                        return Ok(Some(Value::Bool(false)));
                    }
                    let val2 = interpret_expr(expr2, env.clone())?;
                    if let None = val2 {
                        if let Expr::FunctionCall(ref f_expr, _) = expr2.data {
                            if let Expr::Identifier(ref id) = f_expr.data {
                                return Err((InterpreterError::NoneError(Some(id.clone())),
                                            expr2.pos));
                            }
                            return Err((InterpreterError::NoneError(None), expr2.pos));
                        }
                    }
                    Ok(Some(Value::Bool(val2.unwrap().is_truthy())))
                }
                LogicalBinaryOp::LogicalOr => {
                    let val1 = interpret_expr(expr1, env.clone())?;
                    if let None = val1 {
                        if let Expr::FunctionCall(ref f_expr, _) = expr1.data {
                            if let Expr::Identifier(ref id) = f_expr.data {
                                return Err((InterpreterError::NoneError(Some(id.clone())),
                                            expr1.pos));
                            }
                            return Err((InterpreterError::NoneError(None), expr1.pos));
                        }
                    }
                    if val1.unwrap().is_truthy() {
                        return Ok(Some(Value::Bool(true)));
                    }
                    let val2 = interpret_expr(expr2, env.clone())?;
                    if let None = val2 {
                        if let Expr::FunctionCall(ref f_expr, _) = expr2.data {
                            if let Expr::Identifier(ref id) = f_expr.data {
                                return Err((InterpreterError::NoneError(Some(id.clone())),
                                            expr2.pos));
                            }
                            return Err((InterpreterError::NoneError(None), expr2.pos));
                        }
                    }
                    Ok(Some(Value::Bool(val2.unwrap().is_truthy())))
                }
            }
        }
        Expr::FunctionCall(ref expr, ref args) => {
            let val = interpret_expr(expr, env.clone())?;
            if let None = val {
                if let Expr::FunctionCall(ref f_expr, _) = expr.data {
                    if let Expr::Identifier(ref id) = f_expr.data {
                        return Err((InterpreterError::NoneError(Some(id.clone())), expr.pos));
                    }
                    return Err((InterpreterError::NoneError(None), expr.pos));
                }
            }
            let func = match val.unwrap() {
                Value::Function(f) => f,
                v => {
                    if let Expr::Identifier(ref id) = expr.data {
                        return Err((InterpreterError::CallToNonFunction(Some(id.clone()),
                                                                        v.get_type()),
                                    e.pos));
                    }
                    return Err((InterpreterError::CallToNonFunction(None, v.get_type()), e.pos));
                }
            };

            let mut arg_vals = Vec::new();
            for arg in args.iter() {
                let val = interpret_expr(arg, env.clone())?;
                if let None = val {
                    if let Expr::FunctionCall(ref f_expr, _) = arg.data {
                        if let Expr::Identifier(ref id) = f_expr.data {
                            return Err((InterpreterError::NoneError(Some(id.clone())), arg.pos));
                        }
                        return Err((InterpreterError::NoneError(None), arg.pos));
                    }
                }
                arg_vals.push(val.unwrap());
            }
            use function::*;
            match func {
                Function::NativeVoid(call_sign, native_fn) => {
                    if !call_sign.variadic && call_sign.num_params != arg_vals.len() {
                        if let Expr::Identifier(ref id) = expr.data {
                            return Err((InterpreterError::ArgumentLength(Some(id.clone())), e.pos));
                        }
                        return Err((InterpreterError::ArgumentLength(None), e.pos));
                    }
                    native_fn(arg_vals);
                    Ok(None)
                }
                Function::NativeReturning(call_sign, native_fn) => {
                    if !call_sign.variadic && call_sign.num_params != arg_vals.len() {
                        if let Expr::Identifier(ref id) = expr.data {
                            return Err((InterpreterError::ArgumentLength(Some(id.clone())), e.pos));
                        }
                        return Err((InterpreterError::ArgumentLength(None), e.pos));
                    }
                    Ok(Some(native_fn(arg_vals)))
                }
                Function::User { returning, call_sign, body, env } => {
                    unimplemented!();
                }
            }
        }
    }
}
<commit_msg>Move NoneError checking into separate function, return unwrapped value<commit_after>use std::rc::Rc;
use std::cell::RefCell;

use ast::*;
use value::*;
use operations;
use environment::Environment;
use typechecker::Type;

#[derive(Debug)]
pub enum InterpreterError {
    /// When an undeclared identifier is used on the RHS
    ReferenceError(String),
    /// When an undeclared identifier is assigned to
    UndeclaredAssignment(String),
    /// When a binary op cannot be performed on the given types
    BinaryTypeError(BinaryOp, Type, Type),
    /// When a unary op cannot be performed on the given type
    UnaryTypeError(UnaryOp, Type),
    /// When a non-returning function's return value is used
    NoneError(Option<String>),
    /// When a call is made to a non-function value
    CallToNonFunction(Option<String>, Type),
    /// When the number of arguments don't match
    ArgumentLength(Option<String>),
}

pub type InterpreterErrorWithPosition = (InterpreterError, OffsetSpan);

#[derive(Debug, PartialEq)]
pub enum StatementResult {
    None,
    Break,
    Value(Value),
}

pub struct Interpreter {
    pub root_env: Rc<RefCell<Environment>>,
}

impl Interpreter {
    pub fn new() -> Interpreter {
        Interpreter { root_env: Environment::new_root() }
    }

    pub fn run_ast_as_program(&mut self,
                              program: &Vec<StatementNode>)
                              -> Result<Option<StatementResult>, InterpreterErrorWithPosition> {
        interpret_program(program, self.root_env.clone())
    }

    pub fn run_ast_as_statements
        (&mut self,
         statements: &Vec<StatementNode>)
         -> Result<Option<StatementResult>, InterpreterErrorWithPosition> {
        interpret_statements(statements, self.root_env.clone())
    }
}

fn interpret_program(program: &Vec<StatementNode>,
                     env: Rc<RefCell<Environment>>)
                     -> Result<Option<StatementResult>, InterpreterErrorWithPosition> {
    let result = interpret_statements(program, env.clone())?;
    Ok(result)
}

fn interpret_statements(statements: &Vec<StatementNode>,
                        env: Rc<RefCell<Environment>>)
                        -> Result<Option<StatementResult>, InterpreterErrorWithPosition> {
    let mut last_result = None;
    for statement in statements.iter() {
        last_result = Some(interpret_statement(statement, env.clone())?);
    }
    Ok(last_result)
}

fn interpret_statement(s: &StatementNode,
                       env: Rc<RefCell<Environment>>)
                       -> Result<StatementResult, InterpreterErrorWithPosition> {
    match s.data {
        Statement::VariableDeclaration(ref variable, ref expr) => {
            let possible_val = interpret_expr(expr, env.clone())?;
            let val = check_val_for_none_error(&possible_val, &expr)?;
            match variable {
                &Variable::Identifier(ref binding_type, ref name) => {
                    env.borrow_mut().declare(&name, &val);
                }
            };
            Ok(StatementResult::None)
        }
        Statement::Assignment(ref lhs_expr, ref expr) => {
            let possible_val = interpret_expr(expr, env.clone())?;
            let val = check_val_for_none_error(&possible_val, &expr)?;
            match lhs_expr.data {
                LhsExpr::Identifier(ref id) => {
                    if !env.borrow_mut().set(id, val) {
                        return Err((InterpreterError::UndeclaredAssignment(id.clone()),
                                    lhs_expr.pos));
                    }
                }
            };
            Ok(StatementResult::None)
        }
        Statement::Block(ref statements) => {
            let child_env = Environment::create_child(env.clone());
            let mut last_result = StatementResult::None;
            for statement in statements.iter() {
                last_result = interpret_statement(statement, child_env.clone())?;
                if let StatementResult::Break = last_result {
                    return Ok(StatementResult::Break);
                }
            }
            return Ok(last_result);
        }
        Statement::Expression(ref expr) => {
            let val = interpret_expr(expr, env.clone())?;
            match val {
                None => Ok(StatementResult::None),
                Some(x) => Ok(StatementResult::Value(x)),
            }
        }
        Statement::IfThen(ref if_expr, ref then_block) => {
            let possible_val = interpret_expr(if_expr, env.clone())?;
            let val = check_val_for_none_error(&possible_val, &if_expr)?;
            if val.is_truthy() {
                if let StatementResult::Break = interpret_statement(then_block, env.clone())? {
                    return Ok(StatementResult::Break);
                }
            }
            return Ok(StatementResult::None);
        }
        Statement::IfThenElse(ref if_expr, ref then_block, ref else_block) => {
            let possible_val = interpret_expr(if_expr, env.clone())?;
            let val = check_val_for_none_error(&possible_val, &if_expr)?;
            if val.is_truthy() {
                if let StatementResult::Break = interpret_statement(then_block, env.clone())? {
                    return Ok(StatementResult::Break);
                }
            } else {
                if let StatementResult::Break = interpret_statement(else_block, env.clone())? {
                    return Ok(StatementResult::Break);
                }
            }
            Ok(StatementResult::None)
        }
        Statement::Loop(ref block) => {
            let child_env = Environment::create_child(env.clone());
            loop {
                if let StatementResult::Break = interpret_statement(block, child_env.clone())? {
                    break;
                }
            }
            Ok(StatementResult::None)
        }
        Statement::Break => Ok(StatementResult::Break),
        Statement::Empty => Ok(StatementResult::None),
    }
}
fn interpret_expr(e: &ExprNode,
                  env: Rc<RefCell<Environment>>)
                  -> Result<Option<Value>, InterpreterErrorWithPosition> {
    match e.data {
        Expr::Literal(ref x) => Ok(Some(Value::from(x.clone()))),
        Expr::Identifier(ref id) => {
            match env.borrow_mut().get_value(&id) {
                Some(v) => Ok(Some(v)),
                None => Err((InterpreterError::ReferenceError(id.clone()), e.pos)),
            }
        }
        Expr::UnaryExpression(ref op, ref expr) => {
            let possible_val = interpret_expr(expr, env.clone())?;
            let val = check_val_for_none_error(&possible_val, &expr)?;
            match *op {
                UnaryOp::Minus => {
                    match operations::unary_minus(val) {
                        Ok(v) => Ok(Some(v)),
                        Err(err) => Err((err, e.pos)),
                    }
                }
            }
        }
        Expr::UnaryLogicalExpression(ref op, ref expr) => {
            let possible_val = interpret_expr(expr, env.clone())?;
            let val = check_val_for_none_error(&possible_val, &expr)?;
            match *op {
                LogicalUnaryOp::Not => Ok(Some(Value::Bool(!val.is_truthy()))),
            }
        }
        Expr::BinaryExpression(ref expr1, ref op, ref expr2) => {
            let possible_val_1 = interpret_expr(expr1, env.clone())?;
            let val1 = check_val_for_none_error(&possible_val_1, &expr1)?;
            let possible_val_2 = interpret_expr(expr2, env.clone())?;
            let val2 = check_val_for_none_error(&possible_val_2, &expr2)?;
            let retval = match *op {
                BinaryOp::Add => operations::add(val1, val2),
                BinaryOp::Sub => operations::subtract(val1, val2),
                BinaryOp::Mul => operations::multiply(val1, val2),
                BinaryOp::Div => operations::divide(val1, val2),
                BinaryOp::FloorDiv => operations::floor_divide(val1, val2),
                BinaryOp::LessThan => operations::less_than(val1, val2),
                BinaryOp::LessThanOrEqual => operations::less_than_or_equal(val1, val2),
                BinaryOp::GreaterThan => operations::greater_than(val1, val2),
                BinaryOp::GreaterThanOrEqual => operations::greater_than_or_equal(val1, val2),
                BinaryOp::StrictEquals => operations::strict_equals(val1, val2),
            };
            match retval {
                Ok(v) => Ok(Some(v)),
                Err(err) => Err((err, e.pos)),
            }
        }
        Expr::BinaryLogicalExpression(ref expr1, ref op, ref expr2) => {
            match *op {
                LogicalBinaryOp::LogicalAnd => {
                    let possible_val_1 = interpret_expr(expr1, env.clone())?;
                    let val1 = check_val_for_none_error(&possible_val_1, &expr1)?;
                    if !val1.is_truthy() {
                        return Ok(Some(Value::Bool(false)));
                    }
                    let possible_val_2 = interpret_expr(expr2, env.clone())?;
                    let val2 = check_val_for_none_error(&possible_val_2, &expr2)?;
                    Ok(Some(Value::Bool(val2.is_truthy())))
                }
                LogicalBinaryOp::LogicalOr => {
                    let possible_val_1 = interpret_expr(expr1, env.clone())?;
                    let val1 = check_val_for_none_error(&possible_val_1, &expr1)?;
                    if val1.is_truthy() {
                        return Ok(Some(Value::Bool(true)));
                    }
                    let possible_val_2 = interpret_expr(expr2, env.clone())?;
                    let val2 = check_val_for_none_error(&possible_val_2, &expr2)?;
                    Ok(Some(Value::Bool(val2.is_truthy())))
                }
            }
        }
        Expr::FunctionCall(ref expr, ref args) => {
            let possible_val = interpret_expr(expr, env.clone())?;
            let val = check_val_for_none_error(&possible_val, &expr)?;
            let func = match val {
                Value::Function(f) => f,
                v => {
                    if let Expr::Identifier(ref id) = expr.data {
                        return Err((InterpreterError::CallToNonFunction(Some(id.clone()),
                                                                        v.get_type()),
                                    e.pos));
                    }
                    return Err((InterpreterError::CallToNonFunction(None, v.get_type()), e.pos));
                }
            };

            let mut arg_vals = Vec::new();
            for arg in args.iter() {
                let possible_val = interpret_expr(arg, env.clone())?;
                let val = check_val_for_none_error(&possible_val, &arg)?;
                arg_vals.push(val);
            }
            use function::*;
            match func {
                Function::NativeVoid(call_sign, native_fn) => {
                    if !call_sign.variadic && call_sign.num_params != arg_vals.len() {
                        if let Expr::Identifier(ref id) = expr.data {
                            return Err((InterpreterError::ArgumentLength(Some(id.clone())), e.pos));
                        }
                        return Err((InterpreterError::ArgumentLength(None), e.pos));
                    }
                    native_fn(arg_vals);
                    Ok(None)
                }
                Function::NativeReturning(call_sign, native_fn) => {
                    if !call_sign.variadic && call_sign.num_params != arg_vals.len() {
                        if let Expr::Identifier(ref id) = expr.data {
                            return Err((InterpreterError::ArgumentLength(Some(id.clone())), e.pos));
                        }
                        return Err((InterpreterError::ArgumentLength(None), e.pos));
                    }
                    Ok(Some(native_fn(arg_vals)))
                }
                Function::User { returning, call_sign, body, env } => {
                    unimplemented!();
                }
            }
        }
    }
}

fn check_val_for_none_error(val: &Option<Value>, expr: &ExprNode) -> Result<Value, InterpreterErrorWithPosition> {
    if let &None = val {
        if let Expr::FunctionCall(ref f_expr, _) = expr.data {
            if let Expr::Identifier(ref id) = f_expr.data {
                return Err((InterpreterError::NoneError(Some(id.clone())), expr.pos));
            }
            return Err((InterpreterError::NoneError(None), expr.pos));
        }
    }
    Ok(val.clone().unwrap())
}
<|endoftext|>