<commit_before>use player;
use player::Player;
use arena::Arena;
use super::enums;
use super::moves::Technique;
//use super::resolve;
use super::pokemon_token::PokemonToken;
use super::movedex::Movedex;
//use super::moves::Technique;
use self::rand::{Rng, thread_rng};

extern crate rand;

pub fn test(){
    println!("Unique");
    for entry in Movedex::new().get_entries() {
         if entry.get_category() == enums::MoveCategory::Unique {
             println!("{:?}: {:?} - {:?}", entry.get_id(), entry.get_name(), entry.get_type());
         }
    }
}

pub fn test2(){
    println!("Unique");
    for entry in Movedex::new().get_entries() {
         if entry.get_category() == enums::MoveCategory::Unique {
             println!("{:?}", entry.get_name());
         }
    }
}

pub fn unique(attack: &Technique, name: &str, move_type: enums::Types, mut user: PokemonToken, mut target: PokemonToken, attacker: &mut Player, defender: &mut Player, arena: &mut Arena) {
    let movedex = Movedex::new();
    let mut rng = thread_rng();

    // target.get_moves(dex.move_by_id());
    // match dex.get_entries() {
    match name {
        "disable" => {
            println!("disable" );
        },
        "teleport" => {
            println!("teleport");
        },
        "mimic" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id()).unwrap();
            attack.resolve(arena, 1);
        },
        "focus-energy" => {
        },
        "metronome" => {
            let random = rng.gen_range(1, 616);
            let attack = movedex.move_by_id(random).unwrap();
            attack.resolve(arena, 1);
        },
        "mirror-move" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id()).unwrap();
            attack.resolve(arena, 1);
        },
        "nature-power" => {
            match arena.get_current_effect().0 {
                enums::Types::Normal => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "tri-attack" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Flying => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "air-slash" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Ground => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "earth_power" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Rock => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "power_gem" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Fire => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "lava_plume" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Water => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "hydro_pump" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Grass => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "energy-ball" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Electric => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "thunderbolt" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                enums::Types::Ice => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "ice_beam" {
                            let attack = movedex.move_by_id(entry.get_id()).unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                },
                _ => {},
            }
        },
        // "transform" => {
        // },
        "splash" => {
            if arena.get_current_effect().0 == enums::Types::Flying{
                println!("The attack can not be used because {:?} is activated.", enums::Types::Flying);
            }else{
                println!("Nothing happens...");
            }
        },
        "rest" => {
            for entry in Movedex::new().get_entries() {
                if entry.get_name() == "rest" {
                    ////Fehler muss noch behofen werden
                    //let mut user_clone = moves::get_user(1, arena).clone();
                    // resolve::ailment("rest",
                    //                  entry.get_type(),
                    //                  entry.get_ailment(),
                    //                  100,
                    //                  user,
                    //                  &mut target,
                    //                  defender);
                }
            }

        },
        "conversion" => {
            user.set_type(0, attack.get_type());
        },
        "spite" => {
            // defender.get_last_move().unwrap().0.get_power_points();
            // target.decrement_ap();
        },
        "sleep-talk" => {
            struct AllMoves {
                one: String,
                two: String,
                three: String,
                four: String,
            }
            // let one: String;;
            let mut moves = AllMoves {one: "".to_string(), two: "".to_string(), three: "".to_string(), four: "".to_string(), };
            if user.is_asleep(){
                if attacker.get_attack(&player::AttackSlot::One).get_name() != "sleep-talk"{
                    // moves.one = attacker.get_attack(&player::AttackSlot::One).get_name();
                    moves.one = attacker.get_attack(&player::AttackSlot::One).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Two).get_name() != "sleep-talk"{
                    moves.two = attacker.get_attack(&player::AttackSlot::Two).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Three).get_name() != "sleep-talk"{
                    moves.three = attacker.get_attack(&player::AttackSlot::Three).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Four).get_name() != "sleep-talk"{
                    moves.four = attacker.get_attack(&player::AttackSlot::Four).get_name().to_string();
                }

                let mut random = rng.gen_range(1, 4);
                loop {
                    match random {
                        1 => {
                            if moves.one == "".to_string(){
                                random = rng.gen_range(2, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::One).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        2 => {
                            if moves.two == "".to_string(){
                                random = rng.gen_range(1, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Two).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        3 => {
                            if moves.three == "".to_string(){
                                random = rng.gen_range(1, 4);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Three).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        4 => {
                            if moves.four == "".to_string(){
                                random = rng.gen_range(1, 3);
                            }else{
                                let attack = movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Four).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break
                            }
                        },
                        _=> { random = rng.gen_range(1, 4); }
                    }
                }
            }
        },
        "celebrate" => {
            println!("{:?} disappears and then rises out of a birthday present that falls into the picture from above.", user.get_name());
        },
        "powder" => {
            if target.get_types().0 == enums::Types::Grass || target.get_types().1 == enums::Types::Grass{
                println!("{:?} has no effect on  Pokemon type plants", name);
            }
        },
        "reflect-type" => {
            user.set_type(0, target.get_types().0);
            user.set_type(1, target.get_types().1);
        },
        "soak" => {
            target.set_type(0, enums::Types::Water);
            target.set_type(1, enums::Types::Water);
        },
        // "conversion-2" => {
        // },
        // "substitute" => {
        // },
        // "sketch" => {
        // },
        // "spider-web" => {
        // },
        // "mind-reader" => {
        // },
        // "curse" => {
        // },
        // "protect" => {
        // },
        // "belly-drum" => {
        // },
        // "destiny-bond" => {
        // },
        // "detect" => {
        // },
        // "lock-on" => {
        // },
        // "endure" => {
        // },
        // "mean-look" => {
        // },
        // "heal-bell" => {
        // },
        // "pain-split" => {
        // },
        // "baton-pass" => {
        // },
        // "encore" => {
        // },
        // "psych-up" => {
        // },
        // "future-sight" => {
        // },
        // "stockpile" => {
        // },
        // "memento" => {
        // },
        // "follow-me" => {
        // },
        // "taunt" => {
        // },
        // "helping-hand" => {
        // },
        // "trick" => {
        // },
        // "role-play" => {
        // },
        // "wish" => {
        // },
        // "assist" => {
        // },
        // "magic-coat" => {
        // },
        // "recycle" => {
        // },
        // "skill-swap" => {
        // },
        // "imprison" => {
        // },
        // "refresh" => {
        // },
        // "grudge" => {
        // },
        // "snatch" => {
        // },
        // "camouflage" => {
        // },
        // "aromatherapy" => {
        // },
        // "block" => {
        // },
        // "doom-desire" => {
        // },
        // "healing-wish" => {
        // },
        // "acupressure" => {
        // },
        // "psycho-shift" => {
        // },
        // "power-trick" => {
        // },
        // "gastro-acid" => {
        // },
        // "copycat" => {
        // },
        // "power-swap" => {
        // },
        // "guard-swap" => {
        // },
        // "worry-seed" => {
        // },
        // "heart-swap" => {
        // },
        // "aqua-ring" => {
        // },
        // "magnet-rise" => {
        // },
        // "switcheroo" => {
        // },
        // "defog" => {
        // },
        // "lunar-dance" => {
        // },
        // "guard-split" => {
        // },
        // "power-split" => {
        // },
        // "rage-powder" => {
        // },
        // "simple-beam" => {
        // },
        // "entrainment" => {
        // },
        // "after-you" => {
        // },
        // "ally-switch" => {
        // },
        // "shell-smash" => {
        // },
        // "quash" => {
        // },
        // "bestow" => {
        // },
        // "trick-or-treat" => {
        // },
        // "forests-curse" => {
        // },
        // "topsy-turvy" => {
        // },
        // "flower-shield" => {
        // },
        // "electrify" => {
        // },
        // "kings-shield" => {
        // },
        // "spiky-shield" => {
        // },
        // "happy-hour" => {
        // },
        // "hold-hands" => {
        // },
        _ => {},
    };
}
<commit_msg>fix unique.rs<commit_after>use player;
use player::Player;
use arena::Arena;
use super::enums;
use super::moves::Technique;
//use super::resolve;
use super::pokemon_token::PokemonToken;
use super::movedex::Movedex;
//use super::moves::Technique;
use self::rand::{Rng, thread_rng};

extern crate rand;

pub fn test() {
    println!("Unique");
    for entry in Movedex::new().get_entries() {
        if entry.get_category() == enums::MoveCategory::Unique {
            println!("{:?}: {:?} - {:?}",
                     entry.get_id(),
                     entry.get_name(),
                     entry.get_type());
        }
    }
}

pub fn test2() {
    println!("Unique");
    for entry in Movedex::new().get_entries() {
        if entry.get_category() == enums::MoveCategory::Unique {
            println!("{:?}", entry.get_name());
        }
    }
}

pub fn unique(attack: &Technique,
              name: &str,
              move_type: enums::Types,
              mut user: PokemonToken,
              mut target: PokemonToken,
              attacker: &mut Player,
              defender: &mut Player,
              arena: &mut Arena) {
    let movedex = Movedex::new();
    let mut rng = thread_rng();

    // target.get_moves(dex.move_by_id());
    // match dex.get_entries() {
    match name {
        "disable" => {
            println!("disable");
        }
        "teleport" => {
            println!("teleport");
        }
        "mimic" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id())
                .unwrap();
            attack.resolve(arena, 1);
        }
        "focus-energy" => {}
        "metronome" => {
            let random = rng.gen_range(1, 616);
            let attack = movedex.move_by_id(random).unwrap();
            attack.resolve(arena, 1);
        }
        "mirror-move" => {
            let attack = movedex.move_by_id(defender.get_last_move().unwrap().0.get_id())
                .unwrap();
            attack.resolve(arena, 1);
        }
        "nature-power" => {
            match arena.get_current_effect().0 {
                enums::Types::Normal => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "tri-attack" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                enums::Types::Flying => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "air-slash" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                enums::Types::Ground => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "earth_power" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                enums::Types::Rock => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "power_gem" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                enums::Types::Fire => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "lava_plume" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                enums::Types::Water => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "hydro_pump" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                enums::Types::Grass => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "energy-ball" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                enums::Types::Electric => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "thunderbolt" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                enums::Types::Ice => {
                    for entry in Movedex::new().get_entries() {
                        if entry.get_name() == "ice_beam" {
                            let attack = movedex.move_by_id(entry.get_id())
                                .unwrap();
                            attack.resolve(arena, 1);
                        }
                    }
                }
                _ => {}
            }
        }
        // "transform" => {
        // },
        "splash" => {
            if arena.get_current_effect().0 == enums::Types::Flying {
                println!("The attack can not be used because {:?} is activated.",
                         enums::Types::Flying);
            } else {
                println!("Nothing happens...");
            }
        }
        "rest" => {
            for entry in Movedex::new().get_entries() {
                if entry.get_name() == "rest" {
                    ////Fehler muss noch behofen werden
                    //let mut user_clone = moves::get_user(1, arena).clone();
                    // resolve::ailment("rest",
                    //                  entry.get_type(),
                    //                  entry.get_ailment(),
                    //                  100,
                    //                  user,
                    //                  &mut target,
                    //                  defender);
                }
            }

        }
        "conversion" => {
            user.set_type(0, attack.get_type());
        }
        "spite" => {
            // defender.get_last_move().unwrap().0.get_power_points();
            // target.decrement_ap();
        }
        "sleep-talk" => {
            struct AllMoves {
                one: String,
                two: String,
                three: String,
                four: String,
            }
            // let one: String;;
            let mut moves = AllMoves {
                one: "".to_string(),
                two: "".to_string(),
                three: "".to_string(),
                four: "".to_string(),
            };
            if user.is_asleep() {
                if attacker.get_attack(&player::AttackSlot::One).get_name() != "sleep-talk" {
                    // moves.one = attacker.get_attack(&player::AttackSlot::One).get_name();
                    moves.one =
                        attacker.get_attack(&player::AttackSlot::One).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Two).get_name() != "sleep-talk" {
                    moves.two =
                        attacker.get_attack(&player::AttackSlot::Two).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Three).get_name() != "sleep-talk" {
                    moves.three =
                        attacker.get_attack(&player::AttackSlot::Three).get_name().to_string();
                }
                if attacker.get_attack(&player::AttackSlot::Four).get_name() != "sleep-talk" {
                    moves.four =
                        attacker.get_attack(&player::AttackSlot::Four).get_name().to_string();
                }

                let mut random = rng.gen_range(1, 4);
                loop {
                    match random {
                        1 => {
                            if moves.one == "".to_string() {
                                random = rng.gen_range(2, 4);
                            } else {
                                let attack =
                                    movedex.move_by_id(attacker.get_attack(&player::AttackSlot::One)
                                            .get_id())
                                        .unwrap();
                                attack.resolve(arena, 1);
                                break;
                            }
                        }
                        2 => {
                            if moves.two == "".to_string() {
                                random = rng.gen_range(1, 4);
                            } else {
                                let attack =
                                    movedex.move_by_id(attacker.get_attack(&player::AttackSlot::Two)
                                            .get_id())
                                        .unwrap();
                                attack.resolve(arena, 1);
                                break;
                            }
                        }
                        3 => {
                            if moves.three == "".to_string() {
                                random = rng.gen_range(1, 4);
                            } else {
                                let attack = movedex.move_by_id(attacker.get_attack(
                                                    &player::AttackSlot::Three).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break;
                            }
                        }
                        4 => {
                            if moves.four == "".to_string() {
                                random = rng.gen_range(1, 3);
                            } else {
                                let attack = movedex.move_by_id(attacker.get_attack(
                                                    &player::AttackSlot::Four).get_id()).unwrap();
                                attack.resolve(arena, 1);
                                break;
                            }
                        }
                        _ => {
                            random = rng.gen_range(1, 4);
                        }
                    }
                }
            }
        }
        "celebrate" => {
            println!("{:?}",
                     user.get_name() + "disappears and then rises out of a birthday" +
                     "present that falls into the picture from above.");
        }
        "powder" => {
            if target.get_types().0 == enums::Types::Grass ||
               target.get_types().1 == enums::Types::Grass {
                println!("{:?} has no effect on  Pokemon type plants", name);
            }
        }
        "reflect-type" => {
            user.set_type(0, target.get_types().0);
            user.set_type(1, target.get_types().1);
        }
        "soak" => {
            target.set_type(0, enums::Types::Water);
            target.set_type(1, enums::Types::Water);
        }
        // "conversion-2" => {
        // },
        // "substitute" => {
        // },
        // "sketch" => {
        // },
        // "spider-web" => {
        // },
        // "mind-reader" => {
        // },
        // "curse" => {
        // },
        // "protect" => {
        // },
        // "belly-drum" => {
        // },
        // "destiny-bond" => {
        // },
        // "detect" => {
        // },
        // "lock-on" => {
        // },
        // "endure" => {
        // },
        // "mean-look" => {
        // },
        // "heal-bell" => {
        // },
        // "pain-split" => {
        // },
        // "baton-pass" => {
        // },
        // "encore" => {
        // },
        // "psych-up" => {
        // },
        // "future-sight" => {
        // },
        // "stockpile" => {
        // },
        // "memento" => {
        // },
        // "follow-me" => {
        // },
        // "taunt" => {
        // },
        // "helping-hand" => {
        // },
        // "trick" => {
        // },
        // "role-play" => {
        // },
        // "wish" => {
        // },
        // "assist" => {
        // },
        // "magic-coat" => {
        // },
        // "recycle" => {
        // },
        // "skill-swap" => {
        // },
        // "imprison" => {
        // },
        // "refresh" => {
        // },
        // "grudge" => {
        // },
        // "snatch" => {
        // },
        // "camouflage" => {
        // },
        // "aromatherapy" => {
        // },
        // "block" => {
        // },
        // "doom-desire" => {
        // },
        // "healing-wish" => {
        // },
        // "acupressure" => {
        // },
        // "psycho-shift" => {
        // },
        // "power-trick" => {
        // },
        // "gastro-acid" => {
        // },
        // "copycat" => {
        // },
        // "power-swap" => {
        // },
        // "guard-swap" => {
        // },
        // "worry-seed" => {
        // },
        // "heart-swap" => {
        // },
        // "aqua-ring" => {
        // },
        // "magnet-rise" => {
        // },
        // "switcheroo" => {
        // },
        // "defog" => {
        // },
        // "lunar-dance" => {
        // },
        // "guard-split" => {
        // },
        // "power-split" => {
        // },
        // "rage-powder" => {
        // },
        // "simple-beam" => {
        // },
        // "entrainment" => {
        // },
        // "after-you" => {
        // },
        // "ally-switch" => {
        // },
        // "shell-smash" => {
        // },
        // "quash" => {
        // },
        // "bestow" => {
        // },
        // "trick-or-treat" => {
        // },
        // "forests-curse" => {
        // },
        // "topsy-turvy" => {
        // },
        // "flower-shield" => {
        // },
        // "electrify" => {
        // },
        // "kings-shield" => {
        // },
        // "spiky-shield" => {
        // },
        // "happy-hour" => {
        // },
        // "hold-hands" => {
        // },
        _ => {}
    };
}
<|endoftext|>


<commit_before>// Copyright 2012-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.

// FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory

//! Operations on unsafe pointers, `*const T`, and `*mut T`.
//!
//! Working with unsafe pointers in Rust is uncommon,
//! typically limited to a few patterns.
//!
//! Use the [`null` function](fn.null.html) to create null pointers,
//! the [`is_null`](trait.RawPtr.html#tymethod.is_null)
//! and [`is_not_null`](trait.RawPtr.html#method.is_not_null)
//! methods of the [`RawPtr` trait](trait.RawPtr.html) to check for null.
//! The `RawPtr` trait is imported by the prelude, so `is_null` etc.
//! work everywhere. The `RawPtr` also defines the `offset` method,
//! for pointer math.
//!
//! # Common ways to create unsafe pointers
//!
//! ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`).
//!
//! ```
//! let my_num: int = 10;
//! let my_num_ptr: *const int = &my_num;
//! let mut my_speed: int = 88;
//! let my_speed_ptr: *mut int = &mut my_speed;
//! ```
//!
//! This does not take ownership of the original allocation
//! and requires no resource management later,
//! but you must not use the pointer after its lifetime.
//!
//! ## 2. Transmute an owned box (`Box<T>`).
//!
//! The `transmute` function takes, by value, whatever it's given
//! and returns it as whatever type is requested, as long as the
//! types are the same size. Because `Box<T>` and `*mut T` have the same
//! representation they can be trivially,
//! though unsafely, transformed from one type to the other.
//!
//! ```
//! use std::mem;
//!
//! unsafe {
//!     let my_num: Box<int> = box 10;
//!     let my_num: *const int = mem::transmute(my_num);
//!     let my_speed: Box<int> = box 88;
//!     let my_speed: *mut int = mem::transmute(my_speed);
//!
//!     // By taking ownership of the original `Box<T>` though
//!     // we are obligated to transmute it back later to be destroyed.
//!     drop(mem::transmute::<_, Box<int>>(my_speed));
//!     drop(mem::transmute::<_, Box<int>>(my_num));
//! }
//! ```
//!
//! Note that here the call to `drop` is for clarity - it indicates
//! that we are done with the given value and it should be destroyed.
//!
//! ## 3. Get it from C.
//!
//! ```
//! extern crate libc;
//!
//! use std::mem;
//!
//! fn main() {
//!     unsafe {
//!         let my_num: *mut int = libc::malloc(mem::size_of::<int>() as libc::size_t) as *mut int;
//!         if my_num.is_null() {
//!             panic!("failed to allocate memory");
//!         }
//!         libc::free(my_num as *mut libc::c_void);
//!     }
//! }
//! ```
//!
//! Usually you wouldn't literally use `malloc` and `free` from Rust,
//! but C APIs hand out a lot of pointers generally, so are a common source
//! of unsafe pointers in Rust.

use mem;
use clone::Clone;
use intrinsics;
use option::Option;
use option::Option::{Some, None};

use cmp::{PartialEq, Eq, PartialOrd, Equiv};
use cmp::Ordering;
use cmp::Ordering::{Less, Equal, Greater};

pub use intrinsics::copy_memory;
pub use intrinsics::copy_nonoverlapping_memory;
pub use intrinsics::set_memory;

/// Create a null pointer.
///
/// # Example
///
/// ```
/// use std::ptr;
///
/// let p: *const int = ptr::null();
/// assert!(p.is_null());
/// ```
#[inline]
#[unstable = "may need a different name after pending changes to pointer types"]
pub fn null<T>() -> *const T { 0 as *const T }

/// Create an unsafe mutable null pointer.
///
/// # Example
///
/// ```
/// use std::ptr;
///
/// let p: *mut int = ptr::null_mut();
/// assert!(p.is_null());
/// ```
#[inline]
#[unstable = "may need a different name after pending changes to pointer types"]
pub fn null_mut<T>() -> *mut T { 0 as *mut T }

/// Zeroes out `count * size_of::<T>` bytes of memory at `dst`
#[inline]
#[experimental = "uncertain about naming and semantics"]
#[allow(experimental)]
pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
    set_memory(dst, 0, count);
}

/// Swap the values at two mutable locations of the same type, without
/// deinitialising either. They may overlap.
#[inline]
#[unstable]
pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
    // Give ourselves some scratch space to work with
    let mut tmp: T = mem::uninitialized();
    let t: *mut T = &mut tmp;

    // Perform the swap
    copy_nonoverlapping_memory(t, &*x, 1);
    copy_memory(x, &*y, 1); // `x` and `y` may overlap
    copy_nonoverlapping_memory(y, &*t, 1);

    // y and t now point to the same thing, but we need to completely forget `tmp`
    // because it's no longer relevant.
    mem::forget(tmp);
}

/// Replace the value at a mutable location with a new one, returning the old
/// value, without deinitialising either.
#[inline]
#[unstable]
pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
    mem::swap(mem::transmute(dest), &mut src); // cannot overlap
    src
}

/// Reads the value from `*src` and returns it.
#[inline(always)]
#[unstable]
pub unsafe fn read<T>(src: *const T) -> T {
    let mut tmp: T = mem::uninitialized();
    copy_nonoverlapping_memory(&mut tmp, src, 1);
    tmp
}

/// Reads the value from `*src` and nulls it out.
/// This currently prevents destructors from executing.
#[inline(always)]
#[experimental]
#[allow(experimental)]
pub unsafe fn read_and_zero<T>(dest: *mut T) -> T {
    // Copy the data out from `dest`:
    let tmp = read(&*dest);

    // Now zero out `dest`:
    zero_memory(dest, 1);

    tmp
}

/// Unsafely overwrite a memory location with the given value without destroying
/// the old value.
///
/// This operation is unsafe because it does not destroy the previous value
/// contained at the location `dst`. This could leak allocations or resources,
/// so care must be taken to previously deallocate the value at `dst`.
#[inline]
#[unstable]
pub unsafe fn write<T>(dst: *mut T, src: T) {
    intrinsics::move_val_init(&mut *dst, src)
}

/// Methods on raw pointers
pub trait RawPtr<T> {
    /// Returns the null pointer.
    fn null() -> Self;

    /// Returns true if the pointer is equal to the null pointer.
    fn is_null(&self) -> bool;

    /// Returns true if the pointer is not equal to the null pointer.
    fn is_not_null(&self) -> bool { !self.is_null() }

    /// Returns the value of this pointer (ie, the address it points to)
    fn to_uint(&self) -> uint;

    /// Returns `None` if the pointer is null, or else returns a reference to the
    /// value wrapped in `Some`.
    ///
    /// # Safety Notes
    ///
    /// While this method and its mutable counterpart are useful for null-safety,
    /// it is important to note that this is still an unsafe operation because
    /// the returned value could be pointing to invalid memory.
    unsafe fn as_ref<'a>(&self) -> Option<&'a T>;

    /// Calculates the offset from a pointer. The offset *must* be in-bounds of
    /// the object, or one-byte-past-the-end.  `count` is in units of T; e.g. a
    /// `count` of 3 represents a pointer offset of `3 * sizeof::<T>()` bytes.
    unsafe fn offset(self, count: int) -> Self;
}

/// Methods on mutable raw pointers
pub trait RawMutPtr<T>{
    /// Returns `None` if the pointer is null, or else returns a mutable reference
    /// to the value wrapped in `Some`. As with `as_ref`, this is unsafe because
    /// it cannot verify the validity of the returned pointer.
    unsafe fn as_mut<'a>(&self) -> Option<&'a mut T>;
}

impl<T> RawPtr<T> for *const T {
    #[inline]
    fn null() -> *const T { null() }

    #[inline]
    fn is_null(&self) -> bool { *self == RawPtr::null() }

    #[inline]
    fn to_uint(&self) -> uint { *self as uint }

    #[inline]
    unsafe fn offset(self, count: int) -> *const T {
        intrinsics::offset(self, count)
    }

    #[inline]
    unsafe fn as_ref<'a>(&self) -> Option<&'a T> {
        if self.is_null() {
            None
        } else {
            Some(&**self)
        }
    }
}

impl<T> RawPtr<T> for *mut T {
    #[inline]
    fn null() -> *mut T { null_mut() }

    #[inline]
    fn is_null(&self) -> bool { *self == RawPtr::null() }

    #[inline]
    fn to_uint(&self) -> uint { *self as uint }

    #[inline]
    unsafe fn offset(self, count: int) -> *mut T {
        intrinsics::offset(self as *const T, count) as *mut T
    }

    #[inline]
    unsafe fn as_ref<'a>(&self) -> Option<&'a T> {
        if self.is_null() {
            None
        } else {
            Some(&**self)
        }
    }
}

impl<T> RawMutPtr<T> for *mut T {
    #[inline]
    unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> {
        if self.is_null() {
            None
        } else {
            Some(&mut **self)
        }
    }
}

// Equality for pointers
impl<T> PartialEq for *const T {
    #[inline]
    fn eq(&self, other: &*const T) -> bool {
        *self == *other
    }
    #[inline]
    fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
}

impl<T> Eq for *const T {}

impl<T> PartialEq for *mut T {
    #[inline]
    fn eq(&self, other: &*mut T) -> bool {
        *self == *other
    }
    #[inline]
    fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
}

impl<T> Eq for *mut T {}

// Equivalence for pointers
#[allow(deprecated)]
#[deprecated = "Use overloaded `core::cmp::PartialEq`"]
impl<T> Equiv<*mut T> for *const T {
    fn equiv(&self, other: &*mut T) -> bool {
        self.to_uint() == other.to_uint()
    }
}

#[allow(deprecated)]
#[deprecated = "Use overloaded `core::cmp::PartialEq`"]
impl<T> Equiv<*const T> for *mut T {
    fn equiv(&self, other: &*const T) -> bool {
        self.to_uint() == other.to_uint()
    }
}

impl<T> Clone for *const T {
    #[inline]
    fn clone(&self) -> *const T {
        *self
    }
}

impl<T> Clone for *mut T {
    #[inline]
    fn clone(&self) -> *mut T {
        *self
    }
}

// Equality for extern "C" fn pointers
mod externfnpointers {
    use mem;
    use cmp::PartialEq;

    impl<_R> PartialEq for extern "C" fn() -> _R {
        #[inline]
        fn eq(&self, other: &extern "C" fn() -> _R) -> bool {
            let self_: *const () = unsafe { mem::transmute(*self) };
            let other_: *const () = unsafe { mem::transmute(*other) };
            self_ == other_
        }
    }
    macro_rules! fnptreq(
        ($($p:ident),*) => {
            impl<_R,$($p),*> PartialEq for extern "C" fn($($p),*) -> _R {
                #[inline]
                fn eq(&self, other: &extern "C" fn($($p),*) -> _R) -> bool {
                    let self_: *const () = unsafe { mem::transmute(*self) };

                    let other_: *const () = unsafe { mem::transmute(*other) };
                    self_ == other_
                }
            }
        }
    )
    fnptreq!(A)
    fnptreq!(A,B)
    fnptreq!(A,B,C)
    fnptreq!(A,B,C,D)
    fnptreq!(A,B,C,D,E)
}

// Comparison for pointers
impl<T> PartialOrd for *const T {
    #[inline]
    fn partial_cmp(&self, other: &*const T) -> Option<Ordering> {
        if self < other {
            Some(Less)
        } else if self == other {
            Some(Equal)
        } else {
            Some(Greater)
        }
    }

    #[inline]
    fn lt(&self, other: &*const T) -> bool { *self < *other }

    #[inline]
    fn le(&self, other: &*const T) -> bool { *self <= *other }

    #[inline]
    fn gt(&self, other: &*const T) -> bool { *self > *other }

    #[inline]
    fn ge(&self, other: &*const T) -> bool { *self >= *other }
}

impl<T> PartialOrd for *mut T {
    #[inline]
    fn partial_cmp(&self, other: &*mut T) -> Option<Ordering> {
        if self < other {
            Some(Less)
        } else if self == other {
            Some(Equal)
        } else {
            Some(Greater)
        }
    }

    #[inline]
    fn lt(&self, other: &*mut T) -> bool { *self < *other }

    #[inline]
    fn le(&self, other: &*mut T) -> bool { *self <= *other }

    #[inline]
    fn gt(&self, other: &*mut T) -> bool { *self > *other }

    #[inline]
    fn ge(&self, other: &*mut T) -> bool { *self >= *other }
}

<commit_msg>rollup merge of #19779: Noctune/master<commit_after>// Copyright 2012-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.

// FIXME: talk about offset, copy_memory, copy_nonoverlapping_memory

//! Operations on unsafe pointers, `*const T`, and `*mut T`.
//!
//! Working with unsafe pointers in Rust is uncommon,
//! typically limited to a few patterns.
//!
//! Use the [`null` function](fn.null.html) to create null pointers,
//! the [`is_null`](trait.RawPtr.html#tymethod.is_null)
//! and [`is_not_null`](trait.RawPtr.html#method.is_not_null)
//! methods of the [`RawPtr` trait](trait.RawPtr.html) to check for null.
//! The `RawPtr` trait is imported by the prelude, so `is_null` etc.
//! work everywhere. The `RawPtr` also defines the `offset` method,
//! for pointer math.
//!
//! # Common ways to create unsafe pointers
//!
//! ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`).
//!
//! ```
//! let my_num: int = 10;
//! let my_num_ptr: *const int = &my_num;
//! let mut my_speed: int = 88;
//! let my_speed_ptr: *mut int = &mut my_speed;
//! ```
//!
//! This does not take ownership of the original allocation
//! and requires no resource management later,
//! but you must not use the pointer after its lifetime.
//!
//! ## 2. Transmute an owned box (`Box<T>`).
//!
//! The `transmute` function takes, by value, whatever it's given
//! and returns it as whatever type is requested, as long as the
//! types are the same size. Because `Box<T>` and `*mut T` have the same
//! representation they can be trivially,
//! though unsafely, transformed from one type to the other.
//!
//! ```
//! use std::mem;
//!
//! unsafe {
//!     let my_num: Box<int> = box 10;
//!     let my_num: *const int = mem::transmute(my_num);
//!     let my_speed: Box<int> = box 88;
//!     let my_speed: *mut int = mem::transmute(my_speed);
//!
//!     // By taking ownership of the original `Box<T>` though
//!     // we are obligated to transmute it back later to be destroyed.
//!     drop(mem::transmute::<_, Box<int>>(my_speed));
//!     drop(mem::transmute::<_, Box<int>>(my_num));
//! }
//! ```
//!
//! Note that here the call to `drop` is for clarity - it indicates
//! that we are done with the given value and it should be destroyed.
//!
//! ## 3. Get it from C.
//!
//! ```
//! extern crate libc;
//!
//! use std::mem;
//!
//! fn main() {
//!     unsafe {
//!         let my_num: *mut int = libc::malloc(mem::size_of::<int>() as libc::size_t) as *mut int;
//!         if my_num.is_null() {
//!             panic!("failed to allocate memory");
//!         }
//!         libc::free(my_num as *mut libc::c_void);
//!     }
//! }
//! ```
//!
//! Usually you wouldn't literally use `malloc` and `free` from Rust,
//! but C APIs hand out a lot of pointers generally, so are a common source
//! of unsafe pointers in Rust.

use mem;
use clone::Clone;
use intrinsics;
use option::Option;
use option::Option::{Some, None};

use cmp::{PartialEq, Eq, Ord, PartialOrd, Equiv};
use cmp::Ordering;
use cmp::Ordering::{Less, Equal, Greater};

pub use intrinsics::copy_memory;
pub use intrinsics::copy_nonoverlapping_memory;
pub use intrinsics::set_memory;

/// Create a null pointer.
///
/// # Example
///
/// ```
/// use std::ptr;
///
/// let p: *const int = ptr::null();
/// assert!(p.is_null());
/// ```
#[inline]
#[unstable = "may need a different name after pending changes to pointer types"]
pub fn null<T>() -> *const T { 0 as *const T }

/// Create an unsafe mutable null pointer.
///
/// # Example
///
/// ```
/// use std::ptr;
///
/// let p: *mut int = ptr::null_mut();
/// assert!(p.is_null());
/// ```
#[inline]
#[unstable = "may need a different name after pending changes to pointer types"]
pub fn null_mut<T>() -> *mut T { 0 as *mut T }

/// Zeroes out `count * size_of::<T>` bytes of memory at `dst`
#[inline]
#[experimental = "uncertain about naming and semantics"]
#[allow(experimental)]
pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
    set_memory(dst, 0, count);
}

/// Swap the values at two mutable locations of the same type, without
/// deinitialising either. They may overlap.
#[inline]
#[unstable]
pub unsafe fn swap<T>(x: *mut T, y: *mut T) {
    // Give ourselves some scratch space to work with
    let mut tmp: T = mem::uninitialized();
    let t: *mut T = &mut tmp;

    // Perform the swap
    copy_nonoverlapping_memory(t, &*x, 1);
    copy_memory(x, &*y, 1); // `x` and `y` may overlap
    copy_nonoverlapping_memory(y, &*t, 1);

    // y and t now point to the same thing, but we need to completely forget `tmp`
    // because it's no longer relevant.
    mem::forget(tmp);
}

/// Replace the value at a mutable location with a new one, returning the old
/// value, without deinitialising either.
#[inline]
#[unstable]
pub unsafe fn replace<T>(dest: *mut T, mut src: T) -> T {
    mem::swap(mem::transmute(dest), &mut src); // cannot overlap
    src
}

/// Reads the value from `*src` and returns it.
#[inline(always)]
#[unstable]
pub unsafe fn read<T>(src: *const T) -> T {
    let mut tmp: T = mem::uninitialized();
    copy_nonoverlapping_memory(&mut tmp, src, 1);
    tmp
}

/// Reads the value from `*src` and nulls it out.
/// This currently prevents destructors from executing.
#[inline(always)]
#[experimental]
#[allow(experimental)]
pub unsafe fn read_and_zero<T>(dest: *mut T) -> T {
    // Copy the data out from `dest`:
    let tmp = read(&*dest);

    // Now zero out `dest`:
    zero_memory(dest, 1);

    tmp
}

/// Unsafely overwrite a memory location with the given value without destroying
/// the old value.
///
/// This operation is unsafe because it does not destroy the previous value
/// contained at the location `dst`. This could leak allocations or resources,
/// so care must be taken to previously deallocate the value at `dst`.
#[inline]
#[unstable]
pub unsafe fn write<T>(dst: *mut T, src: T) {
    intrinsics::move_val_init(&mut *dst, src)
}

/// Methods on raw pointers
pub trait RawPtr<T> {
    /// Returns the null pointer.
    fn null() -> Self;

    /// Returns true if the pointer is equal to the null pointer.
    fn is_null(&self) -> bool;

    /// Returns true if the pointer is not equal to the null pointer.
    fn is_not_null(&self) -> bool { !self.is_null() }

    /// Returns the value of this pointer (ie, the address it points to)
    fn to_uint(&self) -> uint;

    /// Returns `None` if the pointer is null, or else returns a reference to the
    /// value wrapped in `Some`.
    ///
    /// # Safety Notes
    ///
    /// While this method and its mutable counterpart are useful for null-safety,
    /// it is important to note that this is still an unsafe operation because
    /// the returned value could be pointing to invalid memory.
    unsafe fn as_ref<'a>(&self) -> Option<&'a T>;

    /// Calculates the offset from a pointer. The offset *must* be in-bounds of
    /// the object, or one-byte-past-the-end.  `count` is in units of T; e.g. a
    /// `count` of 3 represents a pointer offset of `3 * sizeof::<T>()` bytes.
    unsafe fn offset(self, count: int) -> Self;
}

/// Methods on mutable raw pointers
pub trait RawMutPtr<T>{
    /// Returns `None` if the pointer is null, or else returns a mutable reference
    /// to the value wrapped in `Some`. As with `as_ref`, this is unsafe because
    /// it cannot verify the validity of the returned pointer.
    unsafe fn as_mut<'a>(&self) -> Option<&'a mut T>;
}

impl<T> RawPtr<T> for *const T {
    #[inline]
    fn null() -> *const T { null() }

    #[inline]
    fn is_null(&self) -> bool { *self == RawPtr::null() }

    #[inline]
    fn to_uint(&self) -> uint { *self as uint }

    #[inline]
    unsafe fn offset(self, count: int) -> *const T {
        intrinsics::offset(self, count)
    }

    #[inline]
    unsafe fn as_ref<'a>(&self) -> Option<&'a T> {
        if self.is_null() {
            None
        } else {
            Some(&**self)
        }
    }
}

impl<T> RawPtr<T> for *mut T {
    #[inline]
    fn null() -> *mut T { null_mut() }

    #[inline]
    fn is_null(&self) -> bool { *self == RawPtr::null() }

    #[inline]
    fn to_uint(&self) -> uint { *self as uint }

    #[inline]
    unsafe fn offset(self, count: int) -> *mut T {
        intrinsics::offset(self as *const T, count) as *mut T
    }

    #[inline]
    unsafe fn as_ref<'a>(&self) -> Option<&'a T> {
        if self.is_null() {
            None
        } else {
            Some(&**self)
        }
    }
}

impl<T> RawMutPtr<T> for *mut T {
    #[inline]
    unsafe fn as_mut<'a>(&self) -> Option<&'a mut T> {
        if self.is_null() {
            None
        } else {
            Some(&mut **self)
        }
    }
}

// Equality for pointers
impl<T> PartialEq for *const T {
    #[inline]
    fn eq(&self, other: &*const T) -> bool {
        *self == *other
    }
    #[inline]
    fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
}

impl<T> Eq for *const T {}

impl<T> PartialEq for *mut T {
    #[inline]
    fn eq(&self, other: &*mut T) -> bool {
        *self == *other
    }
    #[inline]
    fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
}

impl<T> Eq for *mut T {}

// Equivalence for pointers
#[allow(deprecated)]
#[deprecated = "Use overloaded `core::cmp::PartialEq`"]
impl<T> Equiv<*mut T> for *const T {
    fn equiv(&self, other: &*mut T) -> bool {
        self.to_uint() == other.to_uint()
    }
}

#[allow(deprecated)]
#[deprecated = "Use overloaded `core::cmp::PartialEq`"]
impl<T> Equiv<*const T> for *mut T {
    fn equiv(&self, other: &*const T) -> bool {
        self.to_uint() == other.to_uint()
    }
}

impl<T> Clone for *const T {
    #[inline]
    fn clone(&self) -> *const T {
        *self
    }
}

impl<T> Clone for *mut T {
    #[inline]
    fn clone(&self) -> *mut T {
        *self
    }
}

// Equality for extern "C" fn pointers
mod externfnpointers {
    use mem;
    use cmp::PartialEq;

    impl<_R> PartialEq for extern "C" fn() -> _R {
        #[inline]
        fn eq(&self, other: &extern "C" fn() -> _R) -> bool {
            let self_: *const () = unsafe { mem::transmute(*self) };
            let other_: *const () = unsafe { mem::transmute(*other) };
            self_ == other_
        }
    }
    macro_rules! fnptreq(
        ($($p:ident),*) => {
            impl<_R,$($p),*> PartialEq for extern "C" fn($($p),*) -> _R {
                #[inline]
                fn eq(&self, other: &extern "C" fn($($p),*) -> _R) -> bool {
                    let self_: *const () = unsafe { mem::transmute(*self) };

                    let other_: *const () = unsafe { mem::transmute(*other) };
                    self_ == other_
                }
            }
        }
    )
    fnptreq!(A)
    fnptreq!(A,B)
    fnptreq!(A,B,C)
    fnptreq!(A,B,C,D)
    fnptreq!(A,B,C,D,E)
}

// Comparison for pointers
impl<T> Ord for *const T {
    #[inline]
    fn cmp(&self, other: &*const T) -> Ordering {
        if self < other {
            Less
        } else if self == other {
            Equal
        } else {
            Greater
        }
    }
}

impl<T> PartialOrd for *const T {
    #[inline]
    fn partial_cmp(&self, other: &*const T) -> Option<Ordering> {
        Some(self.cmp(other))
    }

    #[inline]
    fn lt(&self, other: &*const T) -> bool { *self < *other }

    #[inline]
    fn le(&self, other: &*const T) -> bool { *self <= *other }

    #[inline]
    fn gt(&self, other: &*const T) -> bool { *self > *other }

    #[inline]
    fn ge(&self, other: &*const T) -> bool { *self >= *other }
}

impl<T> Ord for *mut T {
    #[inline]
    fn cmp(&self, other: &*mut T) -> Ordering {
        if self < other {
            Less
        } else if self == other {
            Equal
        } else {
            Greater
        }
    }
}

impl<T> PartialOrd for *mut T {
    #[inline]
    fn partial_cmp(&self, other: &*mut T) -> Option<Ordering> {
        Some(self.cmp(other))
    }

    #[inline]
    fn lt(&self, other: &*mut T) -> bool { *self < *other }

    #[inline]
    fn le(&self, other: &*mut T) -> bool { *self <= *other }

    #[inline]
    fn gt(&self, other: &*mut T) -> bool { *self > *other }

    #[inline]
    fn ge(&self, other: &*mut T) -> bool { *self >= *other }
}

<|endoftext|>


<commit_before>use chrono::NaiveDate;
use failure::{Error, SyncFailure};
use get_xml_child_text;
use MAL;
use minidom::Element;
use request;
use RequestURL;
use SeriesInfo;
use std::fmt::Debug;

/// Used to perform operations on a user's anime list.
///
/// Note that since the `AnimeList` struct stores a reference to a [MAL] instance,
/// the [MAL] instance must live as long as the `AnimeList`.
///
/// [MAL]: ../struct.MAL.html
pub struct AnimeList<'a> {
    mal: &'a MAL,
}

impl<'a> AnimeList<'a> {
    /// Creates a new instance of the `AnimeList` struct and stores the provided [MAL] reference
    /// so authorization can be handled automatically.
    ///
    /// [MAL]: ../struct.MAL.html
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::MAL;
    /// use mal::list::AnimeList;
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// // Create a new AnimeList instance.
    /// // Keep in mind that the MAL instance must now live for as long as the AnimeList
    /// let anime_list = AnimeList::new(&mal);
    /// ```
    #[inline]
    pub fn new(mal: &'a MAL) -> AnimeList<'a> {
        AnimeList {
            mal
        }
    }

    /// Requests and parses all entries on the user's anime list.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::MAL;
    /// use mal::list::AnimeList;
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// // Create a new AnimeList instance
    /// let anime_list = AnimeList::new(&mal);
    ///
    /// // Read all list entries from the user's list
    /// let entries = anime_list.read_entries().unwrap();
    ///
    /// assert!(entries.len() > 0);
    /// ```
    pub fn read_entries(&self) -> Result<Vec<ListEntry>, Error> {
        let resp = request::get_verify(self.mal, RequestURL::AnimeList(&self.mal.username))?.text()?;
        let root: Element = resp.parse().map_err(SyncFailure::new)?;

        let mut entries = Vec::new();

        for child in root.children().skip(1) {
            let get_child = |name| get_xml_child_text(child, name);

            let info = SeriesInfo {
                id: get_child("series_animedb_id")?.parse()?,
                title: get_child("series_title")?,
                episodes: get_child("series_episodes")?.parse()?,
            };

            let entry = ListEntry {
                series_info: info.into(),
                watched_episodes: get_child("my_watched_episodes")?.parse::<u32>()?.into(),
                start_date: parse_str_date(&get_child("my_start_date")?).into(),
                finish_date: parse_str_date(&get_child("my_finish_date")?).into(),
                status: Status::from_i32(get_child("my_status")?.parse()?)?.into(),
                score: get_child("my_score")?.parse::<u8>()?.into(),
                rewatching: (get_child("my_rewatching")?.parse::<u8>()? == 1).into(),
            };

            entries.push(entry);
        }

        Ok(entries)
    }

    /// Adds an anime to the user's list.
    ///
    /// If the anime is already on the user's list, nothing will happen.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::{MAL, SeriesInfo};
    /// use mal::list::{AnimeList, ListEntry, Status};
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// /// // Search for "Toradora" on MyAnimeList
    /// let mut search_results = mal.search("Toradora").unwrap();
    ///
    /// // Use the first result's info
    /// let toradora_info = search_results.swap_remove(0);
    ///
    /// // Create a new AnimeList instance
    /// let anime_list = AnimeList::new(&mal);
    ///
    /// // Create a new anime list entry with Toradora's info
    /// let mut entry = ListEntry::new(toradora_info);
    ///
    /// // Set the entry's watched episodes to 5 and status to watching
    /// entry.set_watched_episodes(5).set_status(Status::Watching);
    ///
    /// // Add the entry to the user's anime list
    /// anime_list.add(&entry).unwrap();
    /// ```
    #[inline]
    pub fn add(&self, entry: &ListEntry) -> Result<(), Error> {
        let body = entry.generate_xml()?;

        request::auth_post_verify(self.mal,
            RequestURL::Add(entry.series_info.id),
            body)?;

        Ok(())
    }

    /// Updates the specified anime on the user's list.
    ///
    /// If the anime is already on the user's list, nothing will happen.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::{MAL, SeriesInfo};
    /// use mal::list::{AnimeList, ListEntry, Status};
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// // Create a new AnimeList instance
    /// let anime_list = AnimeList::new(&mal);
    ///
    /// // Get and parse all of the list entries
    /// let entries = anime_list.read_entries().unwrap();
    ///
    /// // Find Toradora in the list entries
    /// let mut toradora_entry = entries.into_iter().find(|e| e.series_info.id == 4224).unwrap();
    ///
    /// // Set new values for the list entry
    /// // In this case, the episode count will be updated to 25, the score will be set to 10, and the status will be set to completed
    /// toradora_entry.set_watched_episodes(25)
    ///               .set_score(10)
    ///               .set_status(Status::Completed);
    ///
    /// // Update the anime on the user's list and clear the modified changeset
    /// anime_list.update(&mut toradora_entry).unwrap();
    ///
    /// assert_eq!(toradora_entry.watched_episodes(), 25);
    /// assert_eq!(toradora_entry.status(), Status::Completed);
    /// assert_eq!(toradora_entry.score(), 10);
    /// ```
    #[inline]
    pub fn update(&self, entry: &mut ListEntry) -> Result<(), Error> {
        let body = entry.generate_xml()?;

        request::auth_post_verify(self.mal,
            RequestURL::Update(entry.series_info.id),
            body)?;

        entry.reset_changed_status();
        Ok(())
    }
}

fn parse_str_date(date: &str) -> Option<NaiveDate> {
    if date != "0000-00-00" {
        NaiveDate::parse_from_str(date, "%Y-%m-%d").ok()
    } else {
        None
    }
}

#[derive(Debug, Clone)]
struct ChangeTracker<T: Debug + Clone> {
    value: T,
    changed: bool,
}

impl<T: Debug + Clone> ChangeTracker<T> {
    fn new(value: T) -> ChangeTracker<T> {
        ChangeTracker {
            value,
            changed: false,
        }
    }

    fn get(&self) -> &T {
        &self.value
    }

    fn set(&mut self, value: T) {
        self.value = value;
        self.changed = true;
    }
}

impl<T: Debug + Clone> From<T> for ChangeTracker<T> {
    fn from(value: T) -> Self {
        ChangeTracker::new(value)
    }
}

/// Represents information about an anime series on a user's list.
#[derive(Debug, Clone)]
pub struct ListEntry {
    /// The general series information.
    pub series_info: SeriesInfo,
    watched_episodes: ChangeTracker<u32>,
    /// The date the user started watching the series.
    start_date: ChangeTracker<Option<NaiveDate>>,
    /// The date the user finished watching the series.
    finish_date: ChangeTracker<Option<NaiveDate>>,
    /// The current watch status of the series.
    status: ChangeTracker<Status>,
    /// The current rating given by the user.
    score: ChangeTracker<u8>,
    /// Indicates whether or not the anime is currently being rewatched.
    rewatching: ChangeTracker<bool>,
}

impl ListEntry {
    /// Creates a new `ListEntry` instance with [SeriesInfo] obtained from [MAL].
    ///
    /// [MAL]: ../struct.MAL.html
    /// [SeriesInfo]: ../struct.SeriesInfo.html
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::MAL;
    /// use mal::list::ListEntry;
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// // Search for Toradora on MAL
    /// let mut results = mal.search("Toradora").unwrap();
    ///
    /// // Select the first result
    /// let toradora_info = results.swap_remove(0);
    ///
    /// // Create a new ListEntry that represents Toradora with default values
    /// let entry = ListEntry::new(toradora_info);
    /// ```
    #[inline]
    pub fn new(info: SeriesInfo) -> ListEntry {
        ListEntry {
            series_info: info,
            watched_episodes: 0.into(),
            start_date: None.into(),
            finish_date: None.into(),
            status: Status::default().into(),
            score: 0.into(),
            rewatching: false.into(),
        }
    }

    fn generate_xml(&self) -> Result<String, Error> {
        macro_rules! gen_xml {
            ($entry:ident, $xml_elem:ident, $($field:ident($val_name:ident): $xml_name:expr => $xml_val:expr),+) => {
                $(if $entry.$field.changed {
                    let $val_name = $entry.$field.get();

                    let mut elem = Element::bare($xml_name);
                    elem.append_text_node($xml_val);
                    $xml_elem.append_child(elem);
                })+
            };
        }

        let mut entry = Element::bare("entry");

        gen_xml!(self, entry,
            watched_episodes(num): "episode" => num.to_string(),
            status(status): "status" => (*status as i32).to_string(),
            start_date(date): "date_start" => date_to_str(*date),
            finish_date(date): "date_finish" => date_to_str(*date),
            score(score): "score" => score.to_string(),
            rewatching(v): "enable_rewatching" => (*v as u8).to_string()
        );

        let mut buffer = Vec::new();
        entry.write_to(&mut buffer).map_err(SyncFailure::new)?;

        Ok(String::from_utf8(buffer)?)
    }

    fn reset_changed_status(&mut self) {
        macro_rules! reset {
            ($($name:ident),+) => ($(self.$name.changed = false;)+);
        }

        reset! {
            watched_episodes,
            start_date,
            finish_date,
            status,
            score,
            rewatching
        }
    }

    /// Returns the number of episodes watched.
    #[inline]
    pub fn watched_episodes(&self) -> u32 {
        *self.watched_episodes.get()
    }

    /// Sets the watched episode count.
    #[inline]
    pub fn set_watched_episodes<'a>(&'a mut self, watched: u32) -> &'a mut ListEntry {
        self.watched_episodes.set(watched);
        self
    }

    /// Returns the date the anime started being watched.
    #[inline]
    pub fn start_date(&self) -> &Option<NaiveDate> {
        &self.start_date.get()
    }

    /// Sets the date the user started watching the anime.
    #[inline]
    pub fn set_start_date<'a>(&'a mut self, date: Option<NaiveDate>) -> &'a mut ListEntry {
        self.start_date.set(date);
        self
    }

    /// Returns the date the anime finished being watched.
    #[inline]
    pub fn finish_date(&self) -> &Option<NaiveDate> {
        &self.finish_date.get()
    }

    /// Sets the date the user finished watching the anime.
    #[inline]
    pub fn set_finish_date<'a>(&'a mut self, date: Option<NaiveDate>) -> &'a mut ListEntry {
        self.finish_date.set(date);
        self
    }

    /// Returns the current watch status of the anime.
    #[inline]
    pub fn status(&self) -> Status {
        *self.status.get()
    }

    /// Sets the current watch status for the anime.
    #[inline]
    pub fn set_status<'a>(&'a mut self, status: Status) -> &'a mut ListEntry {
        self.status.set(status);
        self
    }

    /// Returns the user's score of the anime.
    #[inline]
    pub fn score(&self) -> u8 {
        *self.score.get()
    }

    /// Sets the user's score for the anime.
    #[inline]
    pub fn set_score<'a>(&'a mut self, score: u8) -> &'a mut ListEntry {
        self.score.set(score);
        self
    }

    /// Returns true if the anime is currently being rewatched.
    #[inline]
    pub fn rewatching(&self) -> bool {
        *self.rewatching.get()
    }

    /// Sets whether or not the user is currently rewatching the anime.
    #[inline]
    pub fn set_rewatching<'a>(&'a mut self, rewatching: bool) -> &'a mut ListEntry {
        self.rewatching.set(rewatching);
        self
    }
}

impl PartialEq for ListEntry {
    #[inline]
    fn eq(&self, other: &ListEntry) -> bool {
        self.series_info == other.series_info
    }
}

fn date_to_str(date: Option<NaiveDate>) -> String {
    match date {
        Some(date) => date.format("%m%d%Y").to_string(),
        None => {
            // MAL uses an all-zero date to represent a non-set one
            "00000000".into()
        }
    }
}

#[derive(Fail, Debug)]
#[fail(display = "{} does not map to any Status enum variants", _0)]
pub struct InvalidStatus(pub i32);

/// Represents the watch status of an anime on a user's list.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Status {
    Watching = 1,
    Completed,
    OnHold,
    Dropped,
    PlanToWatch = 6,
}

impl Status {
    /// Attempts to convert an i32 to a `Status`.
    ///
    /// Note that the i32 value of each `Status` variant is mapped
    /// to the one provided by the MyAnimeList API, so they do not increment naturally.
    ///
    /// # Example
    ///
    /// ```
    /// use mal::list::Status;
    ///
    /// let status = Status::from_i32(1).unwrap();
    /// assert_eq!(status, Status::Watching);
    /// ```
    #[inline]
    pub fn from_i32(value: i32) -> Result<Status, InvalidStatus> {
        match value {
            1 => Ok(Status::Watching),
            2 => Ok(Status::Completed),
            3 => Ok(Status::OnHold),
            4 => Ok(Status::Dropped),
            6 => Ok(Status::PlanToWatch),
            i => Err(InvalidStatus(i)),
        }
    }
}

impl Default for Status {
    #[inline]
    fn default() -> Self {
        Status::PlanToWatch
    }
}
<commit_msg>Remove unnecessary documentation<commit_after>use chrono::NaiveDate;
use failure::{Error, SyncFailure};
use get_xml_child_text;
use MAL;
use minidom::Element;
use request;
use RequestURL;
use SeriesInfo;
use std::fmt::Debug;

/// Used to perform operations on a user's anime list.
///
/// Note that since the `AnimeList` struct stores a reference to a [MAL] instance,
/// the [MAL] instance must live as long as the `AnimeList`.
///
/// [MAL]: ../struct.MAL.html
pub struct AnimeList<'a> {
    mal: &'a MAL,
}

impl<'a> AnimeList<'a> {
    /// Creates a new instance of the `AnimeList` struct and stores the provided [MAL] reference
    /// so authorization can be handled automatically.
    ///
    /// [MAL]: ../struct.MAL.html
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::MAL;
    /// use mal::list::AnimeList;
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// // Create a new AnimeList instance.
    /// // Keep in mind that the MAL instance must now live for as long as the AnimeList
    /// let anime_list = AnimeList::new(&mal);
    /// ```
    #[inline]
    pub fn new(mal: &'a MAL) -> AnimeList<'a> {
        AnimeList {
            mal
        }
    }

    /// Requests and parses all entries on the user's anime list.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::MAL;
    /// use mal::list::AnimeList;
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// // Create a new AnimeList instance
    /// let anime_list = AnimeList::new(&mal);
    ///
    /// // Read all list entries from the user's list
    /// let entries = anime_list.read_entries().unwrap();
    ///
    /// assert!(entries.len() > 0);
    /// ```
    pub fn read_entries(&self) -> Result<Vec<ListEntry>, Error> {
        let resp = request::get_verify(self.mal, RequestURL::AnimeList(&self.mal.username))?.text()?;
        let root: Element = resp.parse().map_err(SyncFailure::new)?;

        let mut entries = Vec::new();

        for child in root.children().skip(1) {
            let get_child = |name| get_xml_child_text(child, name);

            let info = SeriesInfo {
                id: get_child("series_animedb_id")?.parse()?,
                title: get_child("series_title")?,
                episodes: get_child("series_episodes")?.parse()?,
            };

            let entry = ListEntry {
                series_info: info.into(),
                watched_episodes: get_child("my_watched_episodes")?.parse::<u32>()?.into(),
                start_date: parse_str_date(&get_child("my_start_date")?).into(),
                finish_date: parse_str_date(&get_child("my_finish_date")?).into(),
                status: Status::from_i32(get_child("my_status")?.parse()?)?.into(),
                score: get_child("my_score")?.parse::<u8>()?.into(),
                rewatching: (get_child("my_rewatching")?.parse::<u8>()? == 1).into(),
            };

            entries.push(entry);
        }

        Ok(entries)
    }

    /// Adds an anime to the user's list.
    ///
    /// If the anime is already on the user's list, nothing will happen.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::{MAL, SeriesInfo};
    /// use mal::list::{AnimeList, ListEntry, Status};
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// /// // Search for "Toradora" on MyAnimeList
    /// let mut search_results = mal.search("Toradora").unwrap();
    ///
    /// // Use the first result's info
    /// let toradora_info = search_results.swap_remove(0);
    ///
    /// // Create a new AnimeList instance
    /// let anime_list = AnimeList::new(&mal);
    ///
    /// // Create a new anime list entry with Toradora's info
    /// let mut entry = ListEntry::new(toradora_info);
    ///
    /// // Set the entry's watched episodes to 5 and status to watching
    /// entry.set_watched_episodes(5).set_status(Status::Watching);
    ///
    /// // Add the entry to the user's anime list
    /// anime_list.add(&entry).unwrap();
    /// ```
    #[inline]
    pub fn add(&self, entry: &ListEntry) -> Result<(), Error> {
        let body = entry.generate_xml()?;

        request::auth_post_verify(self.mal,
            RequestURL::Add(entry.series_info.id),
            body)?;

        Ok(())
    }

    /// Updates the specified anime on the user's list.
    ///
    /// If the anime is already on the user's list, nothing will happen.
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::{MAL, SeriesInfo};
    /// use mal::list::{AnimeList, ListEntry, Status};
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// // Create a new AnimeList instance
    /// let anime_list = AnimeList::new(&mal);
    ///
    /// // Get and parse all of the list entries
    /// let entries = anime_list.read_entries().unwrap();
    ///
    /// // Find Toradora in the list entries
    /// let mut toradora_entry = entries.into_iter().find(|e| e.series_info.id == 4224).unwrap();
    ///
    /// // Set new values for the list entry
    /// // In this case, the episode count will be updated to 25, the score will be set to 10, and the status will be set to completed
    /// toradora_entry.set_watched_episodes(25)
    ///               .set_score(10)
    ///               .set_status(Status::Completed);
    ///
    /// // Update the anime on the user's list and clear the modified changeset
    /// anime_list.update(&mut toradora_entry).unwrap();
    ///
    /// assert_eq!(toradora_entry.watched_episodes(), 25);
    /// assert_eq!(toradora_entry.status(), Status::Completed);
    /// assert_eq!(toradora_entry.score(), 10);
    /// ```
    #[inline]
    pub fn update(&self, entry: &mut ListEntry) -> Result<(), Error> {
        let body = entry.generate_xml()?;

        request::auth_post_verify(self.mal,
            RequestURL::Update(entry.series_info.id),
            body)?;

        entry.reset_changed_status();
        Ok(())
    }
}

fn parse_str_date(date: &str) -> Option<NaiveDate> {
    if date != "0000-00-00" {
        NaiveDate::parse_from_str(date, "%Y-%m-%d").ok()
    } else {
        None
    }
}

#[derive(Debug, Clone)]
struct ChangeTracker<T: Debug + Clone> {
    value: T,
    changed: bool,
}

impl<T: Debug + Clone> ChangeTracker<T> {
    fn new(value: T) -> ChangeTracker<T> {
        ChangeTracker {
            value,
            changed: false,
        }
    }

    fn get(&self) -> &T {
        &self.value
    }

    fn set(&mut self, value: T) {
        self.value = value;
        self.changed = true;
    }
}

impl<T: Debug + Clone> From<T> for ChangeTracker<T> {
    fn from(value: T) -> Self {
        ChangeTracker::new(value)
    }
}

/// Represents information about an anime series on a user's list.
#[derive(Debug, Clone)]
pub struct ListEntry {
    /// The general series information.
    pub series_info: SeriesInfo,
    watched_episodes: ChangeTracker<u32>,
    start_date: ChangeTracker<Option<NaiveDate>>,
    finish_date: ChangeTracker<Option<NaiveDate>>,
    status: ChangeTracker<Status>,
    score: ChangeTracker<u8>,
    rewatching: ChangeTracker<bool>,
}

impl ListEntry {
    /// Creates a new `ListEntry` instance with [SeriesInfo] obtained from [MAL].
    ///
    /// [MAL]: ../struct.MAL.html
    /// [SeriesInfo]: ../struct.SeriesInfo.html
    ///
    /// # Examples
    ///
    /// ```no_run
    /// use mal::MAL;
    /// use mal::list::ListEntry;
    ///
    /// // Create a new MAL instance
    /// let mal = MAL::new("username", "password");
    ///
    /// // Search for Toradora on MAL
    /// let mut results = mal.search("Toradora").unwrap();
    ///
    /// // Select the first result
    /// let toradora_info = results.swap_remove(0);
    ///
    /// // Create a new ListEntry that represents Toradora with default values
    /// let entry = ListEntry::new(toradora_info);
    /// ```
    #[inline]
    pub fn new(info: SeriesInfo) -> ListEntry {
        ListEntry {
            series_info: info,
            watched_episodes: 0.into(),
            start_date: None.into(),
            finish_date: None.into(),
            status: Status::default().into(),
            score: 0.into(),
            rewatching: false.into(),
        }
    }

    fn generate_xml(&self) -> Result<String, Error> {
        macro_rules! gen_xml {
            ($entry:ident, $xml_elem:ident, $($field:ident($val_name:ident): $xml_name:expr => $xml_val:expr),+) => {
                $(if $entry.$field.changed {
                    let $val_name = $entry.$field.get();

                    let mut elem = Element::bare($xml_name);
                    elem.append_text_node($xml_val);
                    $xml_elem.append_child(elem);
                })+
            };
        }

        let mut entry = Element::bare("entry");

        gen_xml!(self, entry,
            watched_episodes(num): "episode" => num.to_string(),
            status(status): "status" => (*status as i32).to_string(),
            start_date(date): "date_start" => date_to_str(*date),
            finish_date(date): "date_finish" => date_to_str(*date),
            score(score): "score" => score.to_string(),
            rewatching(v): "enable_rewatching" => (*v as u8).to_string()
        );

        let mut buffer = Vec::new();
        entry.write_to(&mut buffer).map_err(SyncFailure::new)?;

        Ok(String::from_utf8(buffer)?)
    }

    fn reset_changed_status(&mut self) {
        macro_rules! reset {
            ($($name:ident),+) => ($(self.$name.changed = false;)+);
        }

        reset! {
            watched_episodes,
            start_date,
            finish_date,
            status,
            score,
            rewatching
        }
    }

    /// Returns the number of episodes watched.
    #[inline]
    pub fn watched_episodes(&self) -> u32 {
        *self.watched_episodes.get()
    }

    /// Sets the watched episode count.
    #[inline]
    pub fn set_watched_episodes<'a>(&'a mut self, watched: u32) -> &'a mut ListEntry {
        self.watched_episodes.set(watched);
        self
    }

    /// Returns the date the anime started being watched.
    #[inline]
    pub fn start_date(&self) -> &Option<NaiveDate> {
        &self.start_date.get()
    }

    /// Sets the date the user started watching the anime.
    #[inline]
    pub fn set_start_date<'a>(&'a mut self, date: Option<NaiveDate>) -> &'a mut ListEntry {
        self.start_date.set(date);
        self
    }

    /// Returns the date the anime finished being watched.
    #[inline]
    pub fn finish_date(&self) -> &Option<NaiveDate> {
        &self.finish_date.get()
    }

    /// Sets the date the user finished watching the anime.
    #[inline]
    pub fn set_finish_date<'a>(&'a mut self, date: Option<NaiveDate>) -> &'a mut ListEntry {
        self.finish_date.set(date);
        self
    }

    /// Returns the current watch status of the anime.
    #[inline]
    pub fn status(&self) -> Status {
        *self.status.get()
    }

    /// Sets the current watch status for the anime.
    #[inline]
    pub fn set_status<'a>(&'a mut self, status: Status) -> &'a mut ListEntry {
        self.status.set(status);
        self
    }

    /// Returns the user's score of the anime.
    #[inline]
    pub fn score(&self) -> u8 {
        *self.score.get()
    }

    /// Sets the user's score for the anime.
    #[inline]
    pub fn set_score<'a>(&'a mut self, score: u8) -> &'a mut ListEntry {
        self.score.set(score);
        self
    }

    /// Returns true if the anime is currently being rewatched.
    #[inline]
    pub fn rewatching(&self) -> bool {
        *self.rewatching.get()
    }

    /// Sets whether or not the user is currently rewatching the anime.
    #[inline]
    pub fn set_rewatching<'a>(&'a mut self, rewatching: bool) -> &'a mut ListEntry {
        self.rewatching.set(rewatching);
        self
    }
}

impl PartialEq for ListEntry {
    #[inline]
    fn eq(&self, other: &ListEntry) -> bool {
        self.series_info == other.series_info
    }
}

fn date_to_str(date: Option<NaiveDate>) -> String {
    match date {
        Some(date) => date.format("%m%d%Y").to_string(),
        None => {
            // MAL uses an all-zero date to represent a non-set one
            "00000000".into()
        }
    }
}

#[derive(Fail, Debug)]
#[fail(display = "{} does not map to any Status enum variants", _0)]
pub struct InvalidStatus(pub i32);

/// Represents the watch status of an anime on a user's list.
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Status {
    Watching = 1,
    Completed,
    OnHold,
    Dropped,
    PlanToWatch = 6,
}

impl Status {
    /// Attempts to convert an i32 to a `Status`.
    ///
    /// Note that the i32 value of each `Status` variant is mapped
    /// to the one provided by the MyAnimeList API, so they do not increment naturally.
    ///
    /// # Example
    ///
    /// ```
    /// use mal::list::Status;
    ///
    /// let status = Status::from_i32(1).unwrap();
    /// assert_eq!(status, Status::Watching);
    /// ```
    #[inline]
    pub fn from_i32(value: i32) -> Result<Status, InvalidStatus> {
        match value {
            1 => Ok(Status::Watching),
            2 => Ok(Status::Completed),
            3 => Ok(Status::OnHold),
            4 => Ok(Status::Dropped),
            6 => Ok(Status::PlanToWatch),
            i => Err(InvalidStatus(i)),
        }
    }
}

impl Default for Status {
    #[inline]
    fn default() -> Self {
        Status::PlanToWatch
    }
}
<|endoftext|>


<commit_before>use serde_json::builder::ObjectBuilder;
use serde_json::Value;
use std::net::Shutdown;
use std::sync::mpsc::{
    TryRecvError,
    Receiver as MpscReceiver,
    Sender as MpscSender
};
use std::time::Duration as StdDuration;
use std::{env, thread};
use super::super::ClientError;
use super::{GatewayError, GatewayStatus};
use time::{self, Duration};
use websocket::client::request::Url as RequestUrl;
use websocket::client::{Receiver, Sender};
use websocket::stream::WebSocketStream;
use ::constants::{self, OpCode};
use ::error::{Error, Result};
use ::internal::ws_impl::{ReceiverExt, SenderExt};
use ::model::event::{Event, GatewayEvent, ReadyEvent};

#[inline]
pub fn parse_ready(event: GatewayEvent,
                   tx: &MpscSender<GatewayStatus>,
                   receiver: &mut Receiver<WebSocketStream>,
                   identification: Value)
                   -> Result<(ReadyEvent, u64)> {
    match event {
        GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
            Ok((event, seq))
        },
        GatewayEvent::InvalidateSession => {
            debug!("Session invalidation");

            let _ = tx.send(GatewayStatus::SendMessage(identification));

            match receiver.recv_json(GatewayEvent::decode)? {
                GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
                    Ok((event, seq))
                },
                other => {
                    debug!("Unexpected event: {:?}", other);

                    Err(Error::Gateway(GatewayError::InvalidHandshake))
                },
            }
        },
        other => {
            debug!("Unexpected event: {:?}", other);

            Err(Error::Gateway(GatewayError::InvalidHandshake))
        },
    }
}

pub fn identify(token: &str, shard_info: Option<[u64; 2]>) -> Value {
    ObjectBuilder::new()
        .insert("op", OpCode::Identify.num())
        .insert_object("d", |mut object| {
            object = identify_compression(object)
                .insert("large_threshold", 250) // max value
                .insert_object("properties", |object| object
                    .insert("$browser", "Ergonomic and high-level Rust library")
                    .insert("$device", "serenity")
                    .insert("$os", env::consts::OS))
                .insert("token", token)
                .insert("v", constants::GATEWAY_VERSION);

            if let Some(shard_info) = shard_info {
                object = object.insert_array("shard", |a| a
                    .push(shard_info[0])
                    .push(shard_info[1]));
            }

            object
        })
        .build()
}

#[inline(always)]
pub fn identify_compression(object: ObjectBuilder) -> ObjectBuilder {
    object.insert("compression", !cfg!(feature="debug"))
}

pub fn build_gateway_url(base: &str) -> Result<RequestUrl> {
    RequestUrl::parse(&format!("{}?v={}", base, constants::GATEWAY_VERSION))
        .map_err(|_| Error::Client(ClientError::Gateway))
}

pub fn keepalive(interval: u64,
                 mut sender: Sender<WebSocketStream>,
                 channel: MpscReceiver<GatewayStatus>) {
    let mut base_interval = Duration::milliseconds(interval as i64);
    let mut next_tick = time::get_time() + base_interval;

    let mut last_sequence = 0;

    'outer: loop {
        thread::sleep(StdDuration::from_millis(100));

        loop {
            match channel.try_recv() {
                Ok(GatewayStatus::Interval(interval)) => {
                    base_interval = Duration::milliseconds(interval as i64);
                },
                Ok(GatewayStatus::Sender(new_sender)) => {
                    sender = new_sender;
                },
                Ok(GatewayStatus::SendMessage(val)) => {
                    if let Err(why) = sender.send_json(&val) {
                        warn!("Error sending message: {:?}", why);
                    }
                },
                Ok(GatewayStatus::Sequence(seq)) => {
                    last_sequence = seq;
                },
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => break 'outer,
            }
        }

        if time::get_time() >= next_tick {
            next_tick = next_tick + base_interval;

            let map = ObjectBuilder::new()
                .insert("d", last_sequence)
                .insert("op", OpCode::Heartbeat.num())
                .build();

            if let Err(why) = sender.send_json(&map) {
                warn!("Error sending keepalive: {:?}", why);
            }
        }
    }

    let _ = sender.get_mut().shutdown(Shutdown::Both);
}
<commit_msg>A bit more logging<commit_after>use serde_json::builder::ObjectBuilder;
use serde_json::Value;
use std::net::Shutdown;
use std::sync::mpsc::{
    TryRecvError,
    Receiver as MpscReceiver,
    Sender as MpscSender
};
use std::time::Duration as StdDuration;
use std::{env, thread};
use super::super::ClientError;
use super::{GatewayError, GatewayStatus};
use time::{self, Duration};
use websocket::client::request::Url as RequestUrl;
use websocket::client::{Receiver, Sender};
use websocket::stream::WebSocketStream;
use ::constants::{self, OpCode};
use ::error::{Error, Result};
use ::internal::ws_impl::{ReceiverExt, SenderExt};
use ::model::event::{Event, GatewayEvent, ReadyEvent};

#[inline]
pub fn parse_ready(event: GatewayEvent,
                   tx: &MpscSender<GatewayStatus>,
                   receiver: &mut Receiver<WebSocketStream>,
                   identification: Value)
                   -> Result<(ReadyEvent, u64)> {
    match event {
        GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
            Ok((event, seq))
        },
        GatewayEvent::InvalidateSession => {
            debug!("Session invalidation");

            let _ = tx.send(GatewayStatus::SendMessage(identification));

            match receiver.recv_json(GatewayEvent::decode)? {
                GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
                    Ok((event, seq))
                },
                other => {
                    debug!("Unexpected event: {:?}", other);

                    Err(Error::Gateway(GatewayError::InvalidHandshake))
                },
            }
        },
        other => {
            debug!("Unexpected event: {:?}", other);

            Err(Error::Gateway(GatewayError::InvalidHandshake))
        },
    }
}

pub fn identify(token: &str, shard_info: Option<[u64; 2]>) -> Value {
    ObjectBuilder::new()
        .insert("op", OpCode::Identify.num())
        .insert_object("d", |mut object| {
            object = identify_compression(object)
                .insert("large_threshold", 250) // max value
                .insert_object("properties", |object| object
                    .insert("$browser", "Ergonomic and high-level Rust library")
                    .insert("$device", "serenity")
                    .insert("$os", env::consts::OS))
                .insert("token", token)
                .insert("v", constants::GATEWAY_VERSION);

            if let Some(shard_info) = shard_info {
                object = object.insert_array("shard", |a| a
                    .push(shard_info[0])
                    .push(shard_info[1]));
            }

            object
        })
        .build()
}

#[inline(always)]
pub fn identify_compression(object: ObjectBuilder) -> ObjectBuilder {
    object.insert("compression", !cfg!(feature="debug"))
}

pub fn build_gateway_url(base: &str) -> Result<RequestUrl> {
    RequestUrl::parse(&format!("{}?v={}", base, constants::GATEWAY_VERSION))
        .map_err(|_| Error::Client(ClientError::Gateway))
}

pub fn keepalive(interval: u64,
                 mut sender: Sender<WebSocketStream>,
                 channel: MpscReceiver<GatewayStatus>) {
    let mut base_interval = Duration::milliseconds(interval as i64);
    let mut next_tick = time::get_time() + base_interval;

    let mut last_sequence = 0;

    'outer: loop {
        thread::sleep(StdDuration::from_millis(100));

        loop {
            match channel.try_recv() {
                Ok(GatewayStatus::Interval(interval)) => {
                    base_interval = Duration::milliseconds(interval as i64);
                },
                Ok(GatewayStatus::Sender(new_sender)) => {
                    sender = new_sender;
                },
                Ok(GatewayStatus::SendMessage(val)) => {
                    if let Err(why) = sender.send_json(&val) {
                        warn!("Error sending message: {:?}", why);
                    }
                },
                Ok(GatewayStatus::Sequence(seq)) => {
                    last_sequence = seq;
                },
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => break 'outer,
            }
        }

        if time::get_time() >= next_tick {
            next_tick = next_tick + base_interval;

            let map = ObjectBuilder::new()
                .insert("d", last_sequence)
                .insert("op", OpCode::Heartbeat.num())
                .build();

            debug!("Sending heartbeat d: {}", last_sequence);

            if let Err(why) = sender.send_json(&map) {
                warn!("Error sending keepalive: {:?}", why);
            }
        }
    }

    debug!("Closing keepalive");

    let _ = sender.get_mut().shutdown(Shutdown::Both);
}
<|endoftext|>