<commit_before>use *;

const API_BASE: &str = "https://api.toornament.com";

#[derive(Debug, Clone)]
pub enum Endpoint {
    OauthToken,
    AllDisciplines,
    DisciplineById(DisciplineId),
    AllTournaments {
        with_streams: bool,
    },
    MyTournaments,
    TournamentByIdGet {
        tournament_id: TournamentId,
        with_streams: bool,
    },
    TournamentByIdUpdate(TournamentId),
    TournamentCreate,
    MatchesByTournament {
        tournament_id: TournamentId,
        with_games: bool,
    },
    MatchesByDiscipline {
        discipline_id: DisciplineId,
        filter: MatchFilter,
    },
    MatchByIdGet {
        tournament_id: TournamentId,
        match_id: MatchId,
        with_games: bool,
    },
    MatchByIdUpdate {
        tournament_id: TournamentId,
        match_id: MatchId,
    },
    MatchResult(TournamentId, MatchId),
    MatchGames {
        tournament_id: TournamentId,
        match_id: MatchId,
        with_stats: bool,
    },
    MatchGameByNumberGet {
        tournament_id: TournamentId,
        match_id: MatchId,
        game_number: GameNumber,
        with_stats: bool,
    },
    MatchGameByNumberUpdate {
        tournament_id: TournamentId,
        match_id: MatchId,
        game_number: GameNumber,
    },
    MatchGameResultGet {
        tournament_id: TournamentId,
        match_id: MatchId,
        game_number: GameNumber,
    },
    MatchGameResultUpdate {
        tournament_id: TournamentId,
        match_id: MatchId,
        game_number: GameNumber,
        update_match: bool,
    },
    Participants {
        tournament_id: TournamentId,
        filter: TournamentParticipantsFilter,
    },
    ParticipantCreate(TournamentId),
    ParticipantsUpdate(TournamentId),
    ParticipantById(TournamentId, ParticipantId),
    Permissions(TournamentId),
    PermissionById(TournamentId, PermissionId),
    Stages(TournamentId),
    Videos {
        tournament_id: TournamentId,
        filter: TournamentVideosFilter,
    },
}

impl ::std::fmt::Display for Endpoint {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let address;
        match *self {
            Endpoint::OauthToken => address = "/oauth/v2/token".to_owned(),
            Endpoint::AllDisciplines => address = "/v1/disciplines".to_owned(),
            Endpoint::DisciplineById(ref id) => address = format!("/v1/disciplines/{}", id.0),
            Endpoint::AllTournaments { with_streams } => {
                address = format!(
                    "/v1/tournaments?with_streams={}",
                    if with_streams { "1" } else { "0" }
                )
            }
            Endpoint::MyTournaments => address = "/v1/me/tournaments".to_owned(),
            Endpoint::TournamentByIdGet {
                ref tournament_id,
                with_streams,
            } => {
                address = format!(
                    "/v1/tournaments/{}?with_streams={}",
                    tournament_id.0,
                    if with_streams { "1" } else { "0" }
                )
            }
            Endpoint::TournamentByIdUpdate(ref tournament_id) => {
                address = format!("/v1/tournaments/{}", tournament_id.0)
            }
            Endpoint::TournamentCreate => address = "/v1/tournaments".to_owned(),
            Endpoint::MatchesByTournament {
                ref tournament_id,
                with_games,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches?with_games={}",
                    tournament_id.0,
                    if with_games { "1" } else { "0" }
                )
            }
            Endpoint::MatchByIdGet {
                ref tournament_id,
                ref match_id,
                with_games,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}?with_games={}",
                    tournament_id.0,
                    match_id.0,
                    if with_games { "1" } else { "0" }
                )
            }
            Endpoint::MatchByIdUpdate {
                ref tournament_id,
                ref match_id,
            } => address = format!("/v1/tournaments/{}/matches/{}", tournament_id.0, match_id.0),
            Endpoint::MatchesByDiscipline {
                ref discipline_id,
                ref filter,
            } => {
                address = format!(
                    "/v1/disciplines/{}/matches?{}",
                    discipline_id.0,
                    match_filter(filter.clone())
                )
            }
            Endpoint::MatchResult(ref tournament_id, ref match_id) => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/result",
                    tournament_id.0, match_id.0
                )
            }
            Endpoint::MatchGames {
                ref tournament_id,
                ref match_id,
                with_stats,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games?with_stats={}",
                    tournament_id.0,
                    match_id.0,
                    if with_stats { "1" } else { "0" }
                )
            }
            Endpoint::MatchGameByNumberGet {
                ref tournament_id,
                ref match_id,
                ref game_number,
                with_stats,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games/{}?with_stats={}",
                    tournament_id.0,
                    match_id.0,
                    game_number.0,
                    if with_stats { "1" } else { "0" }
                )
            }
            Endpoint::MatchGameByNumberUpdate {
                ref tournament_id,
                ref match_id,
                ref game_number,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games/{}",
                    tournament_id.0, match_id.0, game_number.0
                )
            }
            Endpoint::MatchGameResultGet {
                ref tournament_id,
                ref match_id,
                ref game_number,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games/{}/result",
                    tournament_id.0, match_id.0, game_number.0
                )
            }
            Endpoint::MatchGameResultUpdate {
                ref tournament_id,
                ref match_id,
                ref game_number,
                update_match,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games/{}/result?update_match={}",
                    tournament_id.0,
                    match_id.0,
                    game_number.0,
                    if update_match { "1" } else { "0" }
                )
            }
            Endpoint::Participants {
                ref tournament_id,
                ref filter,
            } => {
                address = format!(
                    "/v1/tournaments/{}/participants?{}",
                    tournament_id.0,
                    tournament_participants(filter.clone())
                )
            }
            Endpoint::ParticipantCreate(ref tournament_id) => {
                address = format!("/v1/tournaments/{}/participants", tournament_id.0)
            }
            Endpoint::ParticipantsUpdate(ref tournament_id) => {
                address = format!("/v1/tournaments/{}/participants", tournament_id.0)
            }
            Endpoint::ParticipantById(ref tournament_id, ref participant_id) => {
                address = format!(
                    "/v1/tournaments/{}/participants/{}",
                    tournament_id.0, participant_id.0
                )
            }
            Endpoint::Permissions(ref tournament_id) => {
                address = format!("/v1/tournaments/{}/permissions", tournament_id.0)
            }
            Endpoint::PermissionById(ref tournament_id, ref permission_id) => {
                address = format!(
                    "/v1/tournaments/{}/permissions/{}",
                    tournament_id.0, permission_id.0
                )
            }
            Endpoint::Stages(ref tournament_id) => {
                address = format!("/v1/tournaments/{}/stages", tournament_id.0)
            }
            Endpoint::Videos {
                ref tournament_id,
                ref filter,
            } => {
                address = format!(
                    "/v1/tournaments/{}/videos?{}",
                    tournament_id.0,
                    tournament_videos(filter.clone())
                )
            }
        };

        fmt.write_str(&format!("{}{}", API_BASE, address))
    }
}

fn match_filter(f: MatchFilter) -> String {
    let mut out = Vec::new();
    if let Some(f) = f.featured {
        out.push(format!("featured={}", if f { 1 } else { 0 }));
    }
    if let Some(r) = f.has_result {
        out.push(format!("has_result={}", if r { 1 } else { 0 }));
    }
    if let Some(s) = f.sort {
        out.push(format!("sort={}", s.to_string()));
    }
    if let Some(i) = f.participant_id {
        out.push(format!("participant_id={}", i.0));
    }
    if let Some(ref i) = f.tournament_ids {
        out.push(format!(
            "tournament_ids={}",
            i.iter()
                .map(|i| i.0.as_str())
                .collect::<Vec<&str>>()
                .join(",")
        ));
    }
    out.push(format!("with_games={}", if f.with_games { 1 } else { 0 }));
    if let Some(d) = f.before_date {
        out.push(format!("before_date={}", d));
    }
    if let Some(d) = f.after_date {
        out.push(format!("after_date={}", d));
    }
    if let Some(p) = f.page {
        out.push(format!("page={}", p));
    }
    out.join("&")
}

fn tournament_participants(f: TournamentParticipantsFilter) -> String {
    format!(
        "with_lineup={}&with_custom_fields={}&sort={}&page={}",
        f.with_lineup as u64,
        f.with_custom_fields as u64,
        f.sort.to_string(),
        f.page
    )
}

fn tournament_videos(f: TournamentVideosFilter) -> String {
    let mut out = Vec::new();
    if let Some(c) = f.category {
        out.push(format!("category={}", c.to_string()));
    }
    out.push(format!("sort={}", f.sort.to_string()));
    if let Some(p) = f.page {
        out.push(format!("page={}", p));
    }
    out.join("&")
}

#[cfg(test)]
mod tests {
    use endpoints::match_filter;
    use MatchFilter;

    #[test]
    fn test_match_filter_to_get_string() {
        let f = MatchFilter::default()
            .featured(true)
            .has_result(true)
            .page(2i64);
        assert_eq!(
            match_filter(f),
            "featured=1&has_result=1&sort=date_asc&with_games=0&page=2"
        );
    }

}
<commit_msg>Fix the formatting<commit_after>use *;

const API_BASE: &str = "https://api.toornament.com";

#[derive(Debug, Clone)]
pub enum Endpoint {
    OauthToken,
    AllDisciplines,
    DisciplineById(DisciplineId),
    AllTournaments {
        with_streams: bool,
    },
    MyTournaments,
    TournamentByIdGet {
        tournament_id: TournamentId,
        with_streams: bool,
    },
    TournamentByIdUpdate(TournamentId),
    TournamentCreate,
    MatchesByTournament {
        tournament_id: TournamentId,
        with_games: bool,
    },
    MatchesByDiscipline {
        discipline_id: DisciplineId,
        filter: MatchFilter,
    },
    MatchByIdGet {
        tournament_id: TournamentId,
        match_id: MatchId,
        with_games: bool,
    },
    MatchByIdUpdate {
        tournament_id: TournamentId,
        match_id: MatchId,
    },
    MatchResult(TournamentId, MatchId),
    MatchGames {
        tournament_id: TournamentId,
        match_id: MatchId,
        with_stats: bool,
    },
    MatchGameByNumberGet {
        tournament_id: TournamentId,
        match_id: MatchId,
        game_number: GameNumber,
        with_stats: bool,
    },
    MatchGameByNumberUpdate {
        tournament_id: TournamentId,
        match_id: MatchId,
        game_number: GameNumber,
    },
    MatchGameResultGet {
        tournament_id: TournamentId,
        match_id: MatchId,
        game_number: GameNumber,
    },
    MatchGameResultUpdate {
        tournament_id: TournamentId,
        match_id: MatchId,
        game_number: GameNumber,
        update_match: bool,
    },
    Participants {
        tournament_id: TournamentId,
        filter: TournamentParticipantsFilter,
    },
    ParticipantCreate(TournamentId),
    ParticipantsUpdate(TournamentId),
    ParticipantById(TournamentId, ParticipantId),
    Permissions(TournamentId),
    PermissionById(TournamentId, PermissionId),
    Stages(TournamentId),
    Videos {
        tournament_id: TournamentId,
        filter: TournamentVideosFilter,
    },
}

impl ::std::fmt::Display for Endpoint {
    fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        let address;
        match *self {
            Endpoint::OauthToken => address = "/oauth/v2/token".to_owned(),
            Endpoint::AllDisciplines => address = "/v1/disciplines".to_owned(),
            Endpoint::DisciplineById(ref id) => address = format!("/v1/disciplines/{}", id.0),
            Endpoint::AllTournaments { with_streams } => {
                address = format!(
                    "/v1/tournaments?with_streams={}",
                    if with_streams { "1" } else { "0" }
                )
            }
            Endpoint::MyTournaments => address = "/v1/me/tournaments".to_owned(),
            Endpoint::TournamentByIdGet {
                ref tournament_id,
                with_streams,
            } => {
                address = format!(
                    "/v1/tournaments/{}?with_streams={}",
                    tournament_id.0,
                    if with_streams { "1" } else { "0" }
                )
            }
            Endpoint::TournamentByIdUpdate(ref tournament_id) => {
                address = format!("/v1/tournaments/{}", tournament_id.0)
            }
            Endpoint::TournamentCreate => address = "/v1/tournaments".to_owned(),
            Endpoint::MatchesByTournament {
                ref tournament_id,
                with_games,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches?with_games={}",
                    tournament_id.0,
                    if with_games { "1" } else { "0" }
                )
            }
            Endpoint::MatchByIdGet {
                ref tournament_id,
                ref match_id,
                with_games,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}?with_games={}",
                    tournament_id.0,
                    match_id.0,
                    if with_games { "1" } else { "0" }
                )
            }
            Endpoint::MatchByIdUpdate {
                ref tournament_id,
                ref match_id,
            } => address = format!("/v1/tournaments/{}/matches/{}", tournament_id.0, match_id.0),
            Endpoint::MatchesByDiscipline {
                ref discipline_id,
                ref filter,
            } => {
                address = format!(
                    "/v1/disciplines/{}/matches?{}",
                    discipline_id.0,
                    match_filter(filter.clone())
                )
            }
            Endpoint::MatchResult(ref tournament_id, ref match_id) => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/result",
                    tournament_id.0, match_id.0
                )
            }
            Endpoint::MatchGames {
                ref tournament_id,
                ref match_id,
                with_stats,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games?with_stats={}",
                    tournament_id.0,
                    match_id.0,
                    if with_stats { "1" } else { "0" }
                )
            }
            Endpoint::MatchGameByNumberGet {
                ref tournament_id,
                ref match_id,
                ref game_number,
                with_stats,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games/{}?with_stats={}",
                    tournament_id.0,
                    match_id.0,
                    game_number.0,
                    if with_stats { "1" } else { "0" }
                )
            }
            Endpoint::MatchGameByNumberUpdate {
                ref tournament_id,
                ref match_id,
                ref game_number,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games/{}",
                    tournament_id.0, match_id.0, game_number.0
                )
            }
            Endpoint::MatchGameResultGet {
                ref tournament_id,
                ref match_id,
                ref game_number,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games/{}/result",
                    tournament_id.0, match_id.0, game_number.0
                )
            }
            Endpoint::MatchGameResultUpdate {
                ref tournament_id,
                ref match_id,
                ref game_number,
                update_match,
            } => {
                address = format!(
                    "/v1/tournaments/{}/matches/{}/games/{}/result?update_match={}",
                    tournament_id.0,
                    match_id.0,
                    game_number.0,
                    if update_match { "1" } else { "0" }
                )
            }
            Endpoint::Participants {
                ref tournament_id,
                ref filter,
            } => {
                address = format!(
                    "/v1/tournaments/{}/participants?{}",
                    tournament_id.0,
                    tournament_participants(filter.clone())
                )
            }
            Endpoint::ParticipantCreate(ref tournament_id) => {
                address = format!("/v1/tournaments/{}/participants", tournament_id.0)
            }
            Endpoint::ParticipantsUpdate(ref tournament_id) => {
                address = format!("/v1/tournaments/{}/participants", tournament_id.0)
            }
            Endpoint::ParticipantById(ref tournament_id, ref participant_id) => {
                address = format!(
                    "/v1/tournaments/{}/participants/{}",
                    tournament_id.0, participant_id.0
                )
            }
            Endpoint::Permissions(ref tournament_id) => {
                address = format!("/v1/tournaments/{}/permissions", tournament_id.0)
            }
            Endpoint::PermissionById(ref tournament_id, ref permission_id) => {
                address = format!(
                    "/v1/tournaments/{}/permissions/{}",
                    tournament_id.0, permission_id.0
                )
            }
            Endpoint::Stages(ref tournament_id) => {
                address = format!("/v1/tournaments/{}/stages", tournament_id.0)
            }
            Endpoint::Videos {
                ref tournament_id,
                ref filter,
            } => {
                address = format!(
                    "/v1/tournaments/{}/videos?{}",
                    tournament_id.0,
                    tournament_videos(filter.clone())
                )
            }
        };

        fmt.write_str(&format!("{}{}", API_BASE, address))
    }
}

fn match_filter(f: MatchFilter) -> String {
    let mut out = Vec::new();
    if let Some(f) = f.featured {
        out.push(format!("featured={}", if f { 1 } else { 0 }));
    }
    if let Some(r) = f.has_result {
        out.push(format!("has_result={}", if r { 1 } else { 0 }));
    }
    if let Some(s) = f.sort {
        out.push(format!("sort={}", s.to_string()));
    }
    if let Some(i) = f.participant_id {
        out.push(format!("participant_id={}", i.0));
    }
    if let Some(ref i) = f.tournament_ids {
        out.push(format!(
            "tournament_ids={}",
            i.iter()
                .map(|i| i.0.as_str())
                .collect::<Vec<&str>>()
                .join(",")
        ));
    }
    out.push(format!("with_games={}", if f.with_games { 1 } else { 0 }));
    if let Some(d) = f.before_date {
        out.push(format!("before_date={}", d));
    }
    if let Some(d) = f.after_date {
        out.push(format!("after_date={}", d));
    }
    if let Some(p) = f.page {
        out.push(format!("page={}", p));
    }
    out.join("&")
}

fn tournament_participants(f: TournamentParticipantsFilter) -> String {
    format!(
        "with_lineup={}&with_custom_fields={}&sort={}&page={}",
        f.with_lineup as u64,
        f.with_custom_fields as u64,
        f.sort.to_string(),
        f.page
    )
}

fn tournament_videos(f: TournamentVideosFilter) -> String {
    let mut out = Vec::new();
    if let Some(c) = f.category {
        out.push(format!("category={}", c.to_string()));
    }
    out.push(format!("sort={}", f.sort.to_string()));
    if let Some(p) = f.page {
        out.push(format!("page={}", p));
    }
    out.join("&")
}

#[cfg(test)]
mod tests {
    use endpoints::match_filter;
    use MatchFilter;

    #[test]
    fn test_match_filter_to_get_string() {
        let f = MatchFilter::default()
            .featured(true)
            .has_result(true)
            .page(2i64);
        assert_eq!(
            match_filter(f),
            "featured=1&has_result=1&sort=date_asc&with_games=0&page=2"
        );
    }
}
<|endoftext|>


<commit_before>use std::rand;
use std::rand::Rng;
use cgmath::vector::{Vector2};
use world::system::{World, Entity, EngineLogic};
use world::spatial::{Location, Position, DIRECTIONS6};
use world::area::Area;

#[deriving(Clone, Show)]
pub struct MobComp {
    pub t: MobType,
    pub max_hp: int,
    pub hp: int,
    pub power: int,
    pub armor: int,
}

impl MobComp {
    pub fn new(t: MobType) -> MobComp {
        let hp = if t == Player { 6 } else { 1 };
        MobComp {
            t: t,
            max_hp: hp,
            hp: hp,
            power: if t == Player { 5 } else { 1 },
            armor: 0,
        }
    }

}

pub mod quirk {
#[deriving(Eq, PartialEq, Clone)]
pub enum Quirk {
    /// Moves 1/3 slower than usual
    Slow,
    /// Moves 1/3 faster than usual, stacks with Quick
    Fast,
    /// Moves 1/3 faster than usual, stacks with Fast
    Quick,
}
}

/// Trait for entities that are mobile things.
pub trait Mob {
    fn acts_this_frame(&self) -> bool;
    fn has_quirk(&self, q: quirk::Quirk) -> bool;
    fn mob_type(&self) -> MobType;
    fn power(&self) -> int;
    fn update_ai(&mut self);

    /// Try to move the mob in a direction, then try to roll around obstacles
    /// if the direction is blocked.
    fn smart_move(&mut self, dir8: uint) -> Option<Vector2<int>>;

    fn enemy_at(&self, loc: Location) -> Option<Entity>;
    fn attack(&mut self, loc: Location);
}

impl Mob for Entity {
    fn acts_this_frame(&self) -> bool {
        if !self.has::<MobComp>() { return false; }

        // Go through a cycle of 5 phases to get 4 possible speeds.
        // System idea from Jeff Lait.
        let phase = self.world().get_tick() % 5;
        match phase {
            0 => return true,
            1 => return self.has_quirk(quirk::Fast),
            2 => return true,
            3 => return self.has_quirk(quirk::Quick),
            4 => return !self.has_quirk(quirk::Slow),
            _ => fail!("Invalid action phase"),
        }
    }

    fn has_quirk(&self, q: quirk::Quirk) -> bool {
        if q == quirk::Fast && self.mob_type() == GridBug { return true; }

        false
    }

    fn mob_type(&self) -> MobType { self.into::<MobComp>().unwrap().t }

    fn power(&self) -> int { self.into::<MobComp>().unwrap().power }

    fn update_ai(&mut self) {
        if self.mob_type() == GridBug {
            // Grid bugs move only non-diagonally. Even though horizontal
            // non-diagonal movement actually involves teleporting through
            // walls...
            let delta = *rand::task_rng()
                .choose(&[
                        Vector2::new(-1, -1),
                        Vector2::new( 1, -1),
                        Vector2::new( 1,  1),
                        Vector2::new(-1,  1),
                        ])
                .unwrap();
            self.move(&delta);
            return;
        }

        self.move(rand::task_rng().choose(DIRECTIONS6.as_slice()).unwrap());
    }

    fn smart_move(&mut self, dir8: uint) -> Option<Vector2<int>> {
        static SMART_MOVE: &'static [&'static [Vector2<int>]] = &[
            &[DIRECTIONS6[0], DIRECTIONS6[5], DIRECTIONS6[1]],
            &[DIRECTIONS6[1], DIRECTIONS6[0], DIRECTIONS6[2]],
            &[DIRECTIONS6[2], DIRECTIONS6[1], DIRECTIONS6[3]],
            &[DIRECTIONS6[3], DIRECTIONS6[2], DIRECTIONS6[4]],
            &[DIRECTIONS6[4], DIRECTIONS6[3], DIRECTIONS6[5]],
            &[DIRECTIONS6[5], DIRECTIONS6[4], DIRECTIONS6[0]],

            // Right sideways move zigzag.
            &[DIRECTIONS6[1], DIRECTIONS6[2]],
            &[DIRECTIONS6[2], DIRECTIONS6[1]],

            // Left sideways move zigzag.
            &[DIRECTIONS6[5], DIRECTIONS6[4]],
            &[DIRECTIONS6[4], DIRECTIONS6[5]],
            ];
        // "horizontal" movement is a zig-zag since there's no natural hex axis
        // in that direction. Find out the grid column the mob is on and
        // determine whether to zig or zag based on that.
        let loc = self.location();
        let zag = ((loc.x - loc.y) % 2) as uint;

        let deltas = SMART_MOVE[match dir8 {
                0 => 0,
                1 => 1,
                2 => 6 + zag,
                3 => 2,
                4 => 3,
                5 => 4,
                6 => 8 + zag,
                7 => 5,
                _ => fail!("Invalid dir8"),
            }];

        for delta in deltas.iter() {
            let new_loc = loc + *delta;
            match self.enemy_at(new_loc) {
                Some(_) => {
                    self.attack(new_loc);
                    return None;
                }
                _ => ()
            }
            if self.move(delta) { return Some(*delta); }
        }

        None
    }

    fn enemy_at(&self, loc: Location) -> Option<Entity> {
        let targs = self.world().mobs_at(loc);
        // Nothing to fight.
        if targs.len() == 0 { return None; }
        // TODO: Alignment check
        Some(targs[0].clone())
    }

    fn attack(&mut self, loc: Location) {
        let p = self.power();
        // No power, can't fight.
        if p == 0 { return; }

        let target = match self.enemy_at(loc) {
            None => return,
            Some(t) => t,
        };

        // Every five points of power is one certain hit.
        let full = p / 5;
        let partial = (p % 5) as f64 / 5.0;

        // TODO: Make some rng utility functions.
        let r = rand::random::<f64>() % 1.0;

        let damage = full + if r < partial { 1 } else { 0 };

        // TODO: A deal_damage method.
        let mut tm = target.into::<MobComp>().unwrap();
        tm.hp -= damage;

        if tm.hp <= 0 {
            if target.mob_type() == Player {
                println!("TODO handle player death");
                tm.hp = tm.max_hp;
            }
            // TODO: Whatever extra stuff we want to do when killing a mob.
            // It's probably a special occasion if it's the player avatar.
            self.world().delete_entity(&target);
        }
    }
}

#[deriving(Eq, PartialEq, Clone, Show)]
pub enum MobType {
    Player,
    Dreg,
    GridBug,
    Serpent,
}

pub trait Mobs {
    fn mobs_at(&self, loc: Location) -> Vec<Entity>;
    fn mobs(&self) -> Vec<Entity>;
    fn player(&self) -> Option<Entity>;
    fn player_has_turn(&self) -> bool;
    fn clear_npcs(&mut self);
    fn update_mobs(&mut self);
}

impl Mobs for World {
    fn mobs_at(&self, loc: Location) -> Vec<Entity> {
        self.entities_at(loc).iter().filter(|e| e.has::<MobComp>())
            .map(|e| e.clone()).collect()
    }

    fn mobs(&self) -> Vec<Entity> {
        self.entities().filter(|e| e.has::<MobComp>())
            .map(|e| e.clone()).collect()
    }

    fn player(&self) -> Option<Entity> {
        for e in self.mobs().iter() {
            if e.mob_type() == Player {
                return Some(e.clone());
            }
        }
        None
    }

    fn player_has_turn(&self) -> bool {
        match self.player() {
            Some(p) => p.acts_this_frame(),
            _ => false
        }
    }

    fn clear_npcs(&mut self) {
        for e in self.mobs().mut_iter() {
            if e.mob_type() != Player {
                e.delete();
            }
        }
    }

    fn update_mobs(&mut self) {
        for mob in self.mobs().mut_iter() {
            if !mob.acts_this_frame() { continue; }
            if mob.mob_type() == Player { continue; }
            mob.update_ai();
        }

        self.advance_frame();
    }
}
<commit_msg>Rename quirk -> intrinsic<commit_after>use std::rand;
use std::rand::Rng;
use cgmath::vector::{Vector2};
use world::system::{World, Entity, EngineLogic};
use world::spatial::{Location, Position, DIRECTIONS6};
use world::area::Area;

#[deriving(Clone, Show)]
pub struct MobComp {
    pub t: MobType,
    pub max_hp: int,
    pub hp: int,
    pub power: int,
    pub armor: int,
}

impl MobComp {
    pub fn new(t: MobType) -> MobComp {
        let hp = if t == Player { 6 } else { 1 };
        MobComp {
            t: t,
            max_hp: hp,
            hp: hp,
            power: if t == Player { 5 } else { 1 },
            armor: 0,
        }
    }

}

pub mod intrinsic {
#[deriving(Eq, PartialEq, Clone)]
pub enum Intrinsic {
    /// Moves 1/3 slower than usual
    Slow,
    /// Moves 1/3 faster than usual, stacks with Quick
    Fast,
    /// Moves 1/3 faster than usual, stacks with Fast
    Quick,
}
}

/// Trait for entities that are mobile things.
pub trait Mob {
    fn acts_this_frame(&self) -> bool;
    fn has_intrinsic(&self, q: intrinsic::Intrinsic) -> bool;
    fn mob_type(&self) -> MobType;
    fn power(&self) -> int;
    fn update_ai(&mut self);

    /// Try to move the mob in a direction, then try to roll around obstacles
    /// if the direction is blocked.
    fn smart_move(&mut self, dir8: uint) -> Option<Vector2<int>>;

    fn enemy_at(&self, loc: Location) -> Option<Entity>;
    fn attack(&mut self, loc: Location);
}

impl Mob for Entity {
    fn acts_this_frame(&self) -> bool {
        if !self.has::<MobComp>() { return false; }

        // Go through a cycle of 5 phases to get 4 possible speeds.
        // System idea from Jeff Lait.
        let phase = self.world().get_tick() % 5;
        match phase {
            0 => return true,
            1 => return self.has_intrinsic(intrinsic::Fast),
            2 => return true,
            3 => return self.has_intrinsic(intrinsic::Quick),
            4 => return !self.has_intrinsic(intrinsic::Slow),
            _ => fail!("Invalid action phase"),
        }
    }

    fn has_intrinsic(&self, q: intrinsic::Intrinsic) -> bool {
        if q == intrinsic::Fast && self.mob_type() == GridBug { return true; }

        false
    }

    fn mob_type(&self) -> MobType { self.into::<MobComp>().unwrap().t }

    fn power(&self) -> int { self.into::<MobComp>().unwrap().power }

    fn update_ai(&mut self) {
        if self.mob_type() == GridBug {
            // Grid bugs move only non-diagonally. Even though horizontal
            // non-diagonal movement actually involves teleporting through
            // walls...
            let delta = *rand::task_rng()
                .choose(&[
                        Vector2::new(-1, -1),
                        Vector2::new( 1, -1),
                        Vector2::new( 1,  1),
                        Vector2::new(-1,  1),
                        ])
                .unwrap();
            self.move(&delta);
            return;
        }

        self.move(rand::task_rng().choose(DIRECTIONS6.as_slice()).unwrap());
    }

    fn smart_move(&mut self, dir8: uint) -> Option<Vector2<int>> {
        static SMART_MOVE: &'static [&'static [Vector2<int>]] = &[
            &[DIRECTIONS6[0], DIRECTIONS6[5], DIRECTIONS6[1]],
            &[DIRECTIONS6[1], DIRECTIONS6[0], DIRECTIONS6[2]],
            &[DIRECTIONS6[2], DIRECTIONS6[1], DIRECTIONS6[3]],
            &[DIRECTIONS6[3], DIRECTIONS6[2], DIRECTIONS6[4]],
            &[DIRECTIONS6[4], DIRECTIONS6[3], DIRECTIONS6[5]],
            &[DIRECTIONS6[5], DIRECTIONS6[4], DIRECTIONS6[0]],

            // Right sideways move zigzag.
            &[DIRECTIONS6[1], DIRECTIONS6[2]],
            &[DIRECTIONS6[2], DIRECTIONS6[1]],

            // Left sideways move zigzag.
            &[DIRECTIONS6[5], DIRECTIONS6[4]],
            &[DIRECTIONS6[4], DIRECTIONS6[5]],
            ];
        // "horizontal" movement is a zig-zag since there's no natural hex axis
        // in that direction. Find out the grid column the mob is on and
        // determine whether to zig or zag based on that.
        let loc = self.location();
        let zag = ((loc.x - loc.y) % 2) as uint;

        let deltas = SMART_MOVE[match dir8 {
                0 => 0,
                1 => 1,
                2 => 6 + zag,
                3 => 2,
                4 => 3,
                5 => 4,
                6 => 8 + zag,
                7 => 5,
                _ => fail!("Invalid dir8"),
            }];

        for delta in deltas.iter() {
            let new_loc = loc + *delta;
            match self.enemy_at(new_loc) {
                Some(_) => {
                    self.attack(new_loc);
                    return None;
                }
                _ => ()
            }
            if self.move(delta) { return Some(*delta); }
        }

        None
    }

    fn enemy_at(&self, loc: Location) -> Option<Entity> {
        let targs = self.world().mobs_at(loc);
        // Nothing to fight.
        if targs.len() == 0 { return None; }
        // TODO: Alignment check
        Some(targs[0].clone())
    }

    fn attack(&mut self, loc: Location) {
        let p = self.power();
        // No power, can't fight.
        if p == 0 { return; }

        let target = match self.enemy_at(loc) {
            None => return,
            Some(t) => t,
        };

        // Every five points of power is one certain hit.
        let full = p / 5;
        let partial = (p % 5) as f64 / 5.0;

        // TODO: Make some rng utility functions.
        let r = rand::random::<f64>() % 1.0;

        let damage = full + if r < partial { 1 } else { 0 };

        // TODO: A deal_damage method.
        let mut tm = target.into::<MobComp>().unwrap();
        tm.hp -= damage;

        if tm.hp <= 0 {
            if target.mob_type() == Player {
                println!("TODO handle player death");
                tm.hp = tm.max_hp;
            }
            // TODO: Whatever extra stuff we want to do when killing a mob.
            // It's probably a special occasion if it's the player avatar.
            self.world().delete_entity(&target);
        }
    }
}

#[deriving(Eq, PartialEq, Clone, Show)]
pub enum MobType {
    Player,
    Dreg,
    GridBug,
    Serpent,
}

pub trait Mobs {
    fn mobs_at(&self, loc: Location) -> Vec<Entity>;
    fn mobs(&self) -> Vec<Entity>;
    fn player(&self) -> Option<Entity>;
    fn player_has_turn(&self) -> bool;
    fn clear_npcs(&mut self);
    fn update_mobs(&mut self);
}

impl Mobs for World {
    fn mobs_at(&self, loc: Location) -> Vec<Entity> {
        self.entities_at(loc).iter().filter(|e| e.has::<MobComp>())
            .map(|e| e.clone()).collect()
    }

    fn mobs(&self) -> Vec<Entity> {
        self.entities().filter(|e| e.has::<MobComp>())
            .map(|e| e.clone()).collect()
    }

    fn player(&self) -> Option<Entity> {
        for e in self.mobs().iter() {
            if e.mob_type() == Player {
                return Some(e.clone());
            }
        }
        None
    }

    fn player_has_turn(&self) -> bool {
        match self.player() {
            Some(p) => p.acts_this_frame(),
            _ => false
        }
    }

    fn clear_npcs(&mut self) {
        for e in self.mobs().mut_iter() {
            if e.mob_type() != Player {
                e.delete();
            }
        }
    }

    fn update_mobs(&mut self) {
        for mob in self.mobs().mut_iter() {
            if !mob.acts_this_frame() { continue; }
            if mob.mob_type() == Player { continue; }
            mob.update_ai();
        }

        self.advance_frame();
    }
}
<|endoftext|>


<commit_before>//! The `EventLog` lets us cheaply record and query behavior
//! in a concurrent system. It lets us reconstruct stories about
//! what happened to our data. It lets us write tests like:
//! 1. no keys are lost through tree structural modifications
//! 2. no nodes are made inaccessible through structural modifications
//! 3. no segments are zeroed and reused before all resident
//!    pages have been relocated and stabilized.
//! 4. recovery does not skip active segments
//! 5. no page is double-allocated or double-freed
//! 6. pages before restart match pages after restart
//!
//! What does it mean for data to be accessible?
//! 1. key -> page
//! 2. page -> lid
//! 3. lid ranges get stabiized over time
//! 4. lid ranges get zeroed over time
//! 5. segment trailers get written over time
//! 6. if a page's old location is zeroed before
//!    `io_bufs` segment trailers have been written,
//!    we are vulnerable to data loss
//! 3. segments have lifespans from fsync to zero
//! 4.
#![allow(missing_docs)]

use crate::pagecache::DiskPtr;
use crate::*;

use crate::stack::{Iter as StackIter, Stack};

/// A thing that happens at a certain time.
#[derive(Debug, Clone)]
enum Event {
    PagesOnShutdown { pages: Map<PageId, Vec<DiskPtr>> },
    PagesOnRecovery { pages: Map<PageId, Vec<DiskPtr>> },
    MetaOnShutdown { meta: Meta },
    MetaOnRecovery { meta: Meta },
    RecoveredLsn(Lsn),
    Stabilized(Lsn),
}

/// A lock-free queue of Events.
#[derive(Default, Debug)]
pub struct EventLog {
    inner: Stack<Event>,
}

impl EventLog {
    pub(crate) fn reset(&self) {
        self.verify();
        let guard = pin();
        while self.inner.pop(&guard).is_some() {}
    }

    fn iter<'a>(&self, guard: &'a Guard) -> StackIter<'a, Event> {
        let head = self.inner.head(guard);
        StackIter::from_ptr(head, guard)
    }

    pub(crate) fn verify(&self) {
        let guard = pin();
        let iter = self.iter(&guard);

        // if we encounter a `PagesOnRecovery`, then we should
        // compare it to any subsequent `PagesOnShutdown`

        let mut recovered_pages = None;
        let mut recovered_meta = None;
        let mut minimum_lsn = None;

        for event in iter {
            match event {
                Event::Stabilized(lsn) | Event::RecoveredLsn(lsn) => {
                    if let Some(later_lsn) = minimum_lsn {
                        assert!(
                            later_lsn >= lsn,
                            "lsn must never go down between recoveries \
                            or stabilizations. It was {} but later became {}. history: {:?}",
                            lsn,
                            later_lsn,
                            self.iter(&guard)
                                .filter(|e| matches!(e, Event::Stabilized(_))
                                    || matches!(e, Event::RecoveredLsn(_)))
                                .collect::<Vec<_>>(),
                        );
                    }
                    minimum_lsn = Some(lsn);
                }
                Event::PagesOnRecovery { pages } => {
                    recovered_pages = Some(pages.clone());
                }
                Event::PagesOnShutdown { pages } => {
                    if let Some(ref par) = recovered_pages {
                        let pids = par
                            .iter()
                            .map(|(pid, _frag_locations)| *pid)
                            .chain(
                                pages.iter().map(|(pid, _frag_locations)| *pid),
                            )
                            .collect::<Set<_>>()
                            .into_iter();

                        for pid in pids {
                            // we filter out the blob pointer in the log
                            // because it is expected that upon recovery,
                            // any blob pointers will be forgotten from
                            // the log now that they are present in the
                            // snapshot.
                            let locations_before_restart: Vec<_> = pages
                                .get(&pid)
                                .unwrap()
                                .iter()
                                .map(|ptr| {
                                    let mut ptr = *ptr;
                                    ptr.forget_heap_log_coordinates();
                                    ptr
                                })
                                .collect();
                            let locations_after_restart: Vec<_> = par
                                .get(&pid)
                                .unwrap()
                                .iter()
                                .copied()
                                .collect();
                            assert_eq!(
                                locations_before_restart,
                                locations_after_restart,
                                "page {} had frag locations {:?} before \
                                 restart, but {:?} after restart",
                                pid,
                                locations_before_restart,
                                locations_after_restart
                            );
                        }
                    }
                }
                Event::MetaOnRecovery { meta } => {
                    recovered_meta = Some(meta);
                }
                Event::MetaOnShutdown { meta } => {
                    if let Some(rec_meta) = recovered_meta {
                        assert_eq!(meta, rec_meta);
                    }
                }
            }
        }

        debug!("event log verified \u{2713}");
    }

    pub(crate) fn stabilized_lsn(&self, lsn: Lsn) {
        let guard = pin();
        self.inner.push(Event::Stabilized(lsn), &guard);
    }

    pub(crate) fn recovered_lsn(&self, lsn: Lsn) {
        let guard = pin();
        self.inner.push(Event::RecoveredLsn(lsn), &guard);
    }

    pub(crate) fn pages_before_restart(
        &self,
        pages: Map<PageId, Vec<DiskPtr>>,
    ) {
        let guard = pin();
        self.inner.push(Event::PagesOnShutdown { pages }, &guard);
    }

    pub(crate) fn pages_after_restart(&self, pages: Map<PageId, Vec<DiskPtr>>) {
        let guard = pin();
        self.inner.push(Event::PagesOnRecovery { pages }, &guard);
    }

    pub fn meta_before_restart(&self, meta: Meta) {
        let guard = pin();
        self.inner.push(Event::MetaOnShutdown { meta }, &guard);
    }

    pub fn meta_after_restart(&self, meta: Meta) {
        let guard = pin();
        self.inner.push(Event::MetaOnRecovery { meta }, &guard);
    }
}
<commit_msg>Be more explicit about non-present pid errors upon verification<commit_after>//! The `EventLog` lets us cheaply record and query behavior
//! in a concurrent system. It lets us reconstruct stories about
//! what happened to our data. It lets us write tests like:
//! 1. no keys are lost through tree structural modifications
//! 2. no nodes are made inaccessible through structural modifications
//! 3. no segments are zeroed and reused before all resident
//!    pages have been relocated and stabilized.
//! 4. recovery does not skip active segments
//! 5. no page is double-allocated or double-freed
//! 6. pages before restart match pages after restart
//!
//! What does it mean for data to be accessible?
//! 1. key -> page
//! 2. page -> lid
//! 3. lid ranges get stabiized over time
//! 4. lid ranges get zeroed over time
//! 5. segment trailers get written over time
//! 6. if a page's old location is zeroed before
//!    `io_bufs` segment trailers have been written,
//!    we are vulnerable to data loss
//! 3. segments have lifespans from fsync to zero
//! 4.
#![allow(missing_docs)]

use crate::pagecache::DiskPtr;
use crate::*;

use crate::stack::{Iter as StackIter, Stack};

/// A thing that happens at a certain time.
#[derive(Debug, Clone)]
enum Event {
    PagesOnShutdown { pages: Map<PageId, Vec<DiskPtr>> },
    PagesOnRecovery { pages: Map<PageId, Vec<DiskPtr>> },
    MetaOnShutdown { meta: Meta },
    MetaOnRecovery { meta: Meta },
    RecoveredLsn(Lsn),
    Stabilized(Lsn),
}

/// A lock-free queue of Events.
#[derive(Default, Debug)]
pub struct EventLog {
    inner: Stack<Event>,
}

impl EventLog {
    pub(crate) fn reset(&self) {
        self.verify();
        let guard = pin();
        while self.inner.pop(&guard).is_some() {}
    }

    fn iter<'a>(&self, guard: &'a Guard) -> StackIter<'a, Event> {
        let head = self.inner.head(guard);
        StackIter::from_ptr(head, guard)
    }

    pub(crate) fn verify(&self) {
        let guard = pin();
        let iter = self.iter(&guard);

        // if we encounter a `PagesOnRecovery`, then we should
        // compare it to any subsequent `PagesOnShutdown`

        let mut recovered_pages = None;
        let mut recovered_meta = None;
        let mut minimum_lsn = None;

        for event in iter {
            match event {
                Event::Stabilized(lsn) | Event::RecoveredLsn(lsn) => {
                    if let Some(later_lsn) = minimum_lsn {
                        assert!(
                            later_lsn >= lsn,
                            "lsn must never go down between recoveries \
                            or stabilizations. It was {} but later became {}. history: {:?}",
                            lsn,
                            later_lsn,
                            self.iter(&guard)
                                .filter(|e| matches!(e, Event::Stabilized(_))
                                    || matches!(e, Event::RecoveredLsn(_)))
                                .collect::<Vec<_>>(),
                        );
                    }
                    minimum_lsn = Some(lsn);
                }
                Event::PagesOnRecovery { pages } => {
                    recovered_pages = Some(pages.clone());
                }
                Event::PagesOnShutdown { pages } => {
                    if let Some(ref par) = recovered_pages {
                        let pids = par
                            .iter()
                            .map(|(pid, _frag_locations)| *pid)
                            .chain(
                                pages.iter().map(|(pid, _frag_locations)| *pid),
                            )
                            .collect::<Set<_>>()
                            .into_iter();

                        for pid in pids {
                            // we filter out the blob pointer in the log
                            // because it is expected that upon recovery,
                            // any blob pointers will be forgotten from
                            // the log now that they are present in the
                            // snapshot.
                            let locations_before_restart: Vec<_> = pages
                                .get(&pid)
                                .unwrap()
                                .iter()
                                .map(|ptr| {
                                    let mut ptr = *ptr;
                                    ptr.forget_heap_log_coordinates();
                                    ptr
                                })
                                .collect();
                            let locations_after_restart: Vec<_> = par
                                .get(&pid)
                                .unwrap_or_else(|| panic!("pid {} no longer present after restart", pid))
                                .iter()
                                .copied()
                                .collect();
                            assert_eq!(
                                locations_before_restart,
                                locations_after_restart,
                                "page {} had frag locations {:?} before \
                                 restart, but {:?} after restart",
                                pid,
                                locations_before_restart,
                                locations_after_restart
                            );
                        }
                    }
                }
                Event::MetaOnRecovery { meta } => {
                    recovered_meta = Some(meta);
                }
                Event::MetaOnShutdown { meta } => {
                    if let Some(rec_meta) = recovered_meta {
                        assert_eq!(meta, rec_meta);
                    }
                }
            }
        }

        debug!("event log verified \u{2713}");
    }

    pub(crate) fn stabilized_lsn(&self, lsn: Lsn) {
        let guard = pin();
        self.inner.push(Event::Stabilized(lsn), &guard);
    }

    pub(crate) fn recovered_lsn(&self, lsn: Lsn) {
        let guard = pin();
        self.inner.push(Event::RecoveredLsn(lsn), &guard);
    }

    pub(crate) fn pages_before_restart(
        &self,
        pages: Map<PageId, Vec<DiskPtr>>,
    ) {
        let guard = pin();
        self.inner.push(Event::PagesOnShutdown { pages }, &guard);
    }

    pub(crate) fn pages_after_restart(&self, pages: Map<PageId, Vec<DiskPtr>>) {
        let guard = pin();
        self.inner.push(Event::PagesOnRecovery { pages }, &guard);
    }

    pub fn meta_before_restart(&self, meta: Meta) {
        let guard = pin();
        self.inner.push(Event::MetaOnShutdown { meta }, &guard);
    }

    pub fn meta_after_restart(&self, meta: Meta) {
        let guard = pin();
        self.inner.push(Event::MetaOnRecovery { meta }, &guard);
    }
}
<|endoftext|>


<commit_before>use lexer::Token;

pub enum Expr {
    Plus(Box<Expr>, Box<Expr>),
    Minus(Box<Expr>, Box<Expr>),
    Times(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
    Mod(Box<Expr>, Box<Expr>),
    Ident(String),
    Integer(i32),
}

impl Expr {
    fn boxed(self) -> Box<Self> {
        Box::new(self)
    }

    fn plus(left: Expr, right: Expr) -> Expr {
        Expr::Plus(left.boxed(), right.boxed())
    }

    fn minus(left: Expr, right: Expr) -> Expr {
        Expr::Minus(left.boxed(), right.boxed())
    }

    fn times(left: Expr, right: Expr) -> Expr {
        Expr::Times(left.boxed(), right.boxed())
    }
}

pub fn parse(input: &Vec<Token>) -> Expr {
    Expr::plus(Expr::Integer(100), Expr::Integer(50))
}
<commit_msg>added div function<commit_after>use lexer::Token;

pub enum Expr {
    Plus(Box<Expr>, Box<Expr>),
    Minus(Box<Expr>, Box<Expr>),
    Times(Box<Expr>, Box<Expr>),
    Div(Box<Expr>, Box<Expr>),
    Mod(Box<Expr>, Box<Expr>),
    Ident(String),
    Integer(i32),
}

impl Expr {
    fn boxed(self) -> Box<Self> {
        Box::new(self)
    }

    fn plus(left: Expr, right: Expr) -> Expr {
        Expr::Plus(left.boxed(), right.boxed())
    }

    fn minus(left: Expr, right: Expr) -> Expr {
        Expr::Minus(left.boxed(), right.boxed())
    }

    fn times(left: Expr, right: Expr) -> Expr {
        Expr::Times(left.boxed(), right.boxed())
    }

    fn div(left: Expr, right: Expr) -> Expr {
        Expr::Div(left.boxed(), right.boxed())
    }
}

pub fn parse(input: &Vec<Token>) -> Expr {
    Expr::plus(Expr::Integer(100), Expr::Integer(50))
}
<|endoftext|>


<commit_before>// Rust on bare metal - Tested with Rust 1.0.0
// Uses Pure64 to get into a 64-bit SMP state
// rustc -O --crate-type lib -o kernel64.o --emit obj kernel64.rs
// ld -T app.ld -o kernel64.sys kernel64.o

const BUF_VIDEO: *mut u16 = 0xb8000 as *mut u16;

#[no_mangle]
pub fn main() {
    clear_screen(Color::LightBlue);
    loop {
        // Loop forever
    }
}

#[derive(Copy,Clone)]
enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yello       = 14,
    White       = 15,
}

fn clear_screen(background: Color) {
    for x in 0 .. 80*25 {
        unsafe {
            std::ptr::write(BUF_VIDEO.offset(x),(background as u16) << 12);
        }
    }
}
<commit_msg>silence unused enum warning<commit_after>// Rust on bare metal - Tested with Rust 1.0.0
// Uses Pure64 to get into a 64-bit SMP state
// rustc -O --crate-type lib -o kernel64.o --emit obj kernel64.rs
// ld -T app.ld -o kernel64.sys kernel64.o

// declare the address of the text buffer
const BUF_TEXT: *mut u16 = 0xb8000 as *mut u16;

#[no_mangle]
pub fn main() {
    clear_screen(Color::LightBlue);
    loop {
        // Loop forever
    }
}

#[derive(Copy,Clone)]
pub enum Color {
    Black       = 0,
    Blue        = 1,
    Green       = 2,
    Cyan        = 3,
    Red         = 4,
    Pink        = 5,
    Brown       = 6,
    LightGray   = 7,
    DarkGray    = 8,
    LightBlue   = 9,
    LightGreen  = 10,
    LightCyan   = 11,
    LightRed    = 12,
    LightPink   = 13,
    Yello       = 14,
    White       = 15,
}

fn clear_screen(background: Color) {
    for x in 0 .. 80*25 {
        unsafe {
            // one should probably use the `core` feature (which is only
            // available outside the stable release channel)
            std::ptr::write(BUF_TEXT.offset(x),(background as u16) << 12);
        }
    }
}
<|endoftext|>


<commit_before>/*

  This struct essentially encapsulates the "instance variables"

*/
#[derive(Debug)]
pub struct SimpleHdrHistogram {
    pub leading_zeros_count_base: usize,
    pub sub_bucket_mask: u64,
    pub unit_magnitude: u32,
    pub sub_bucket_count: usize,
    pub sub_bucket_half_count: usize,
    pub sub_bucket_half_count_magnitude: u32,
    pub counts: Vec<u64>,
    pub counts_array_length: usize,
    pub normalizing_index_offset: usize,
    pub max_value: u64,
    pub min_non_zero_value: u64,
    pub unit_magnitude_mask: u64,
    pub total_count: u64,
}

/*

  Implementing this trait (Default) for our struct gives us a nice way to
  initialize an instance using default args instead of having to provide all of them

 */
impl Default for SimpleHdrHistogram {
    fn default () -> SimpleHdrHistogram {
        SimpleHdrHistogram {
            leading_zeros_count_base: 0,
            sub_bucket_mask: 0,
            unit_magnitude: 0,
            sub_bucket_count: 0,
            sub_bucket_half_count: 0,
            sub_bucket_half_count_magnitude: 0,
            counts: Vec::new(),
            counts_array_length: 0,
            normalizing_index_offset: 0,
            max_value: 0,
            min_non_zero_value: u64::max_value(),
            unit_magnitude_mask: 0,
            total_count: 0,
        }
    }
}

pub trait HistogramBase {

    //FIXME this stuff could be mostly unsigned

    //TODO this block should be default impl of this trait
    fn record_single_value(&mut self, value: u64) -> Result<(), String>;
    fn counts_array_index(&self, value: u64) -> Result<usize, String>;
    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize;
    fn get_bucket_index(&self, value: u64) -> usize;
    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize;
    fn update_min_and_max(&mut self, value: u64);
    fn update_max_value(&mut self, value: u64);
    fn update_min_non_zero_value(&mut self, value: u64);
    // end TODO

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String>;
    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
        Result<usize, String>;
    fn increment_total_count(&mut self);

}

impl HistogramBase for SimpleHdrHistogram {

    fn increment_total_count(&mut self) {
        self.total_count += 1;
    }

    fn update_max_value(&mut self, value: u64) {
        let mut internal_value = value | self.unit_magnitude_mask;
        self.max_value = internal_value;
    }

    fn update_min_non_zero_value(&mut self, value: u64) {
        if value <= self.unit_magnitude_mask {
            return
        }
        let internal_value = value & !self.unit_magnitude_mask;
        self.min_non_zero_value = internal_value;
    }

    fn update_min_and_max(&mut self, value: u64) {
        if value > self.max_value {
            self.update_max_value(value);
        }
        if ((value < self.min_non_zero_value) && (value != 0)) {
            self.update_min_non_zero_value(value);
        }
    }

    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
Result<usize, String> {
        match normalizing_index_offset {
            0 => Ok(index),
            _ =>
                if ((index > array_length) || (index < 0)) {
                    Err(String::from("index out of covered range"))
                } else {
                    let mut normalized_index: usize = index - normalizing_index_offset;
                    if (normalized_index < 0) {
                        normalized_index += array_length;
                    } else if (normalized_index >= array_length) {
                        normalized_index -=array_length;
                    }
                    Ok(normalized_index)
                }
        }
    }

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String> {
        let normalized_index =
            self.normalize_index(index, self.normalizing_index_offset, self.counts_array_length);
        match normalized_index {
            Ok(the_index) => {
                self.counts[the_index] += 1;
                Ok(())
            }
            Err(err) =>
                Err(err)
        }
    }

    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize {
        let sum = bucket_index + self.unit_magnitude as usize;
        value.rotate_right(sum as u32) as usize
    }

    fn get_bucket_index(&self, value: u64) -> usize {
        let valueOrred = value | self.sub_bucket_mask;
        self.leading_zeros_count_base - (valueOrred.leading_zeros() as usize)
    }

    fn record_single_value(&mut self, value: u64) -> Result<(), String> {
        match self.counts_array_index(value) {
            Ok(counts_index) => {
                match self.increment_count_at_index(counts_index) {
                    Ok(_) => {
                        self.update_min_and_max(value);
                        self.increment_total_count();
                        Ok(())
                    }
                    Err(err) => {
                        Err(String::from(format!("Could not increment count at index due to: {}", err))) }
                }}
            Err(err) => Err(String::from(format!("Could not get index due to: {}", err)))
        }
    }

    fn counts_array_index(&self, value: u64) -> Result<usize, String> {
        if value < 0 {
            Err(String::from("Histogram recorded values cannot be negative."))
        } else {
            let bucket_index = self.get_bucket_index(value);
            let sub_bucket_index = self.get_sub_bucket_index(value, bucket_index);
            let result = self.counts_array_index_sub(bucket_index, sub_bucket_index);
            Ok(result)
        }
    }

    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize {
        assert!(sub_bucket_index < self.sub_bucket_count);
        assert!(bucket_index == 0 || (sub_bucket_index >= self.sub_bucket_half_count));

        let bucket_base_index = (bucket_index + 1) << self.sub_bucket_half_count_magnitude;
        let offset_in_bucket = sub_bucket_index - self.sub_bucket_half_count;

        bucket_base_index + offset_in_bucket
    }
}

#[test]
fn can_record_single_value() {
    let mut the_hist = SimpleHdrHistogram { ..Default::default() };
    let result = the_hist.record_single_value(99);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }
}

#[test]
fn can_compute_counts_array_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.counts_array_index(99);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not compute counts array index because error: {}", err))
    }
}

#[test]
fn can_get_bucket_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.get_bucket_index(99);
    assert_eq!(result, 0)
}

#[test]
fn can_get_sub_bucket_index() {
    let mut the_hist = init_histo(1, 1000, 5);
    let result = the_hist.get_sub_bucket_index(99, 1);
    assert_eq!(result, 0)
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let mut hist =  SimpleHdrHistogram { ..Default::default() };

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = 1_u64.rotate_left(unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
        ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = (sub_bucket_count - 1).rotate_left(unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    hist.leading_zeros_count_base = leading_zero_count_base;
    hist.sub_bucket_mask = sub_bucket_mask;
    hist.unit_magnitude = unit_magnitude;
    hist.sub_bucket_count = sub_bucket_count;
    hist.sub_bucket_half_count = sub_bucket_half_count;
    hist.sub_bucket_half_count_magnitude = sub_bucket_half_count_magnitude;
    hist.counts = Vec::with_capacity(counts_arr_len);
    hist.counts_array_length = counts_arr_len;
    hist.normalizing_index_offset = 0_usize; // 0 for normal Histogram ctor in Java impl

    println!("hist: {:?}", hist);

    hist
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // is this cast ok?
    let mut smallest_untrackable_value: u64 = sub_bucket_count.rotate_left(unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if (smallest_untrackable_value > u64::max_value() / 2) {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value.rotate_left(1);
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<commit_msg>code cleanup to fix some warnings. yay unsigned!<commit_after>/*

  This struct essentially encapsulates the "instance variables"

*/
#[derive(Debug)]
pub struct SimpleHdrHistogram {
    pub leading_zeros_count_base: usize,
    pub sub_bucket_mask: u64,
    pub unit_magnitude: u32,
    pub sub_bucket_count: usize,
    pub sub_bucket_half_count: usize,
    pub sub_bucket_half_count_magnitude: u32,
    pub counts: Vec<u64>,
    pub counts_array_length: usize,
    pub normalizing_index_offset: usize,
    pub max_value: u64,
    pub min_non_zero_value: u64,
    pub unit_magnitude_mask: u64,
    pub total_count: u64,
}

/*

  Implementing this trait (Default) for our struct gives us a nice way to
  initialize an instance using default args instead of having to provide all of them

 */
impl Default for SimpleHdrHistogram {
    fn default () -> SimpleHdrHistogram {
        SimpleHdrHistogram {
            leading_zeros_count_base: 0,
            sub_bucket_mask: 0,
            unit_magnitude: 0,
            sub_bucket_count: 0,
            sub_bucket_half_count: 0,
            sub_bucket_half_count_magnitude: 0,
            counts: Vec::new(),
            counts_array_length: 0,
            normalizing_index_offset: 0,
            max_value: 0,
            min_non_zero_value: u64::max_value(),
            unit_magnitude_mask: 0,
            total_count: 0,
        }
    }
}

pub trait HistogramBase {

    //FIXME this stuff could be mostly unsigned

    //TODO this block should be default impl of this trait
    fn record_single_value(&mut self, value: u64) -> Result<(), String>;
    fn counts_array_index(&self, value: u64) -> Result<usize, String>;
    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize;
    fn get_bucket_index(&self, value: u64) -> usize;
    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize;
    fn update_min_and_max(&mut self, value: u64);
    fn update_max_value(&mut self, value: u64);
    fn update_min_non_zero_value(&mut self, value: u64);
    // end TODO

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String>;
    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
        Result<usize, String>;
    fn increment_total_count(&mut self);

}

impl HistogramBase for SimpleHdrHistogram {

    fn increment_total_count(&mut self) {
        self.total_count += 1;
    }

    fn update_max_value(&mut self, value: u64) {
        let internal_value = value | self.unit_magnitude_mask;
        self.max_value = internal_value;
    }

    fn update_min_non_zero_value(&mut self, value: u64) {
        if value <= self.unit_magnitude_mask {
            return
        }
        let internal_value = value & !self.unit_magnitude_mask;
        self.min_non_zero_value = internal_value;
    }

    fn update_min_and_max(&mut self, value: u64) {
        if value > self.max_value {
            self.update_max_value(value);
        }
        if value < self.min_non_zero_value && value != 0 {
            self.update_min_non_zero_value(value);
        }
    }

    fn normalize_index(&self, index: usize, normalizing_index_offset: usize, array_length: usize) ->
Result<usize, String> {
        match normalizing_index_offset {
            0 => Ok(index),
            _ =>
                if index > array_length {
                    Err(String::from("index out of covered range"))
                } else {
                    let mut normalized_index: usize = index - normalizing_index_offset;
                    if normalized_index >= array_length {
                        normalized_index -=array_length;
                    }
                    Ok(normalized_index)
                }
        }
    }

    fn increment_count_at_index(&mut self, index: usize) -> Result<(), String> {
        let normalized_index =
            self.normalize_index(index, self.normalizing_index_offset, self.counts_array_length);
        match normalized_index {
            Ok(the_index) => {
                self.counts[the_index] += 1;
                Ok(())
            }
            Err(err) =>
                Err(err)
        }
    }

    fn get_sub_bucket_index(&self, value: u64, bucket_index: usize) -> usize {
        let sum = bucket_index + self.unit_magnitude as usize;
        value.rotate_right(sum as u32) as usize
    }

    fn get_bucket_index(&self, value: u64) -> usize {
        let value_orred = value | self.sub_bucket_mask;
        self.leading_zeros_count_base - (value_orred.leading_zeros() as usize)
    }

    fn record_single_value(&mut self, value: u64) -> Result<(), String> {
        match self.counts_array_index(value) {
            Ok(counts_index) => {
                match self.increment_count_at_index(counts_index) {
                    Ok(_) => {
                        self.update_min_and_max(value);
                        self.increment_total_count();
                        Ok(())
                    }
                    Err(err) => {
                        Err(String::from(format!("Could not increment count at index due to: {}", err))) }
                }}
            Err(err) => Err(String::from(format!("Could not get index due to: {}", err)))
        }
    }

    fn counts_array_index(&self, value: u64) -> Result<usize, String> {
        let bucket_index = self.get_bucket_index(value);
        let sub_bucket_index = self.get_sub_bucket_index(value, bucket_index);
        let result = self.counts_array_index_sub(bucket_index, sub_bucket_index);
        Ok(result)
    }

    fn counts_array_index_sub(&self, bucket_index: usize, sub_bucket_index: usize) -> usize {
        assert!(sub_bucket_index < self.sub_bucket_count);
        assert!(bucket_index == 0 || (sub_bucket_index >= self.sub_bucket_half_count));

        let bucket_base_index = (bucket_index + 1) << self.sub_bucket_half_count_magnitude;
        let offset_in_bucket = sub_bucket_index - self.sub_bucket_half_count;

        bucket_base_index + offset_in_bucket
    }
}

#[test]
fn can_record_single_value() {
    let mut the_hist = SimpleHdrHistogram { ..Default::default() };
    let result = the_hist.record_single_value(99);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not add single record to histogram because error: {}", err))
    }
}

#[test]
fn can_compute_counts_array_index() {
    let the_hist = init_histo(1, 1000, 5);
    let result = the_hist.counts_array_index(99);

    match result {
        Ok(_) => (),
        Err(err) => panic!(format!("could not compute counts array index because error: {}", err))
    }
}

#[test]
fn can_get_bucket_index() {
    let the_hist = init_histo(1, 1000, 5);
    let result = the_hist.get_bucket_index(99);
    assert_eq!(result, 0)
}

#[test]
fn can_get_sub_bucket_index() {
    let the_hist = init_histo(1, 1000, 5);
    let result = the_hist.get_sub_bucket_index(99, 1);
    assert_eq!(result, 0)
}

/// lowest_discernible_value: must be >= 1
/// highest_trackable_value: must be >= 2 * lowest_discernible_value
/// num_significant_digits: must be <= 5
fn init_histo(lowest_discernible_value: u64, highest_trackable_value: u64, num_significant_digits: u32) -> SimpleHdrHistogram {

    assert!(lowest_discernible_value >= 1);
    assert!(highest_trackable_value >= 2 * lowest_discernible_value);
    assert!(num_significant_digits <= 5);

    let mut hist =  SimpleHdrHistogram { ..Default::default() };

    let largest_value_with_single_unit_resolution = 2_u64 * 10_u64.pow(num_significant_digits);

    let unit_magnitude = ((lowest_discernible_value as f64).ln() / 2_f64.ln()) as u32;
    let unit_magnitude_mask: u64  = 1_u64.rotate_left(unit_magnitude) - 1;

    // find nearest power of 2 to largest_value_with_single_unit_resolution
    let sub_bucket_count_magnitude: u32 =
        ((largest_value_with_single_unit_resolution as f64).ln() / 2_f64.ln()).ceil() as u32;

    // ugly looking... how should ternaries be done?
    let sub_bucket_half_count_magnitude: u32 = (if sub_bucket_count_magnitude > 1 { sub_bucket_count_magnitude } else { 1 }) - 1;
    let sub_bucket_count: usize = 2_usize.pow(sub_bucket_half_count_magnitude + 1);
    let sub_bucket_half_count: usize = sub_bucket_count / 2;
    // TODO is this cast OK?
    let sub_bucket_mask = (sub_bucket_count - 1).rotate_left(unit_magnitude) as u64;

    let counts_arr_len = counts_arr_len(highest_trackable_value, sub_bucket_count, unit_magnitude);
    let bucket_count = buckets_needed_for_value(highest_trackable_value, sub_bucket_count, unit_magnitude);

    let leading_zero_count_base: usize = (64_u32 - unit_magnitude - sub_bucket_half_count_magnitude - 1) as usize;

    hist.leading_zeros_count_base = leading_zero_count_base;
    hist.sub_bucket_mask = sub_bucket_mask;
    hist.unit_magnitude = unit_magnitude;
    hist.sub_bucket_count = sub_bucket_count;
    hist.sub_bucket_half_count = sub_bucket_half_count;
    hist.sub_bucket_half_count_magnitude = sub_bucket_half_count_magnitude;
    hist.counts = Vec::with_capacity(counts_arr_len);
    hist.counts_array_length = counts_arr_len;
    hist.normalizing_index_offset = 0_usize; // 0 for normal Histogram ctor in Java impl

    println!("hist: {:?}", hist);

    hist
}

fn buckets_needed_for_value(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {

    // is this cast ok?
    let mut smallest_untrackable_value: u64 = sub_bucket_count.rotate_left(unit_magnitude) as u64;
    let mut buckets_needed: usize = 1;

    while smallest_untrackable_value <= value {
        if smallest_untrackable_value > u64::max_value() / 2 {
            return buckets_needed + 1;
        }

        smallest_untrackable_value = smallest_untrackable_value.rotate_left(1);
        buckets_needed += 1;
    }

    return buckets_needed;
}

fn counts_arr_len_for_buckets(buckets: usize, sub_bucket_count: usize) -> usize {
    (buckets + 1) * (sub_bucket_count / 2)
}

fn counts_arr_len(value: u64, sub_bucket_count: usize, unit_magnitude: u32) -> usize {
    counts_arr_len_for_buckets(buckets_needed_for_value(value, sub_bucket_count, unit_magnitude), sub_bucket_count)
}<|endoftext|>


<commit_before>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_name = "geoip"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_ulong, c_float};
use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

type GeoIP_ = *const c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup_ {
    netmask: c_int
}

impl GeoIPLookup_ {
    fn new() -> GeoIPLookup_ {
        GeoIPLookup_ {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *const c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_record_by_ipnum(db: GeoIP_, ipnum: c_ulong) -> *const GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: GeoIP_, ipnum: In6Addr) -> *const GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *const GeoIPRecord_);
    fn GeoIP_set_charset(db: GeoIP_, charset: c_int) -> c_int;
}

enum Charset {
    UTF8 = 1
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct GeoIPRecord_ {
    country_code: *const c_char,
    country_code3: *const c_char,
    country_name: *const c_char,
    region: *const c_char,
    city: *const c_char,
    postal_code: *const c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *const c_char,
    netmask: c_int
}

pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: uint,
    pub area_code: uint,
    pub charset: uint,
    pub continent_code: Option<String>,
    pub netmask: uint
}

impl CityInfo {
    fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        let country_code = unsafe { if res.country_code.is_null() {
            None
        } else {
            CString::new(res.country_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            CString::new(res.country_code3, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            CString::new(res.country_name, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            CString::new(res.region, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            CString::new(res.city, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            CString::new(res.postal_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            CString::new(res.continent_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        CityInfo {
            country_code: country_code,
            country_code3: country_code3,
            country_name: country_name,
            region: region,
            city: city,
            postal_code: postal_code,
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as uint,
            area_code: res.area_code as uint,
            charset: res.charset as uint,
            continent_code: continent_code,
            netmask: res.netmask as uint
        }
    }
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { GeoIP_set_charset(db, UTF8 as c_int) } != 0 {
            return Err("Can't set charset to UTF8".to_string());
        }
        Ok(GeoIP { db: db })
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_record_by_ipnum(self.db, ipnum)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_record_by_ipnum_v6(self.db, in6_addr)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let city_info = CityInfo::from_geoiprecord(&unsafe { *cres });
        unsafe { GeoIPRecord_delete(cres) };
        unsafe { std::mem::forget(cres) };
        Some(city_info)
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup_::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(' ', 1);
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as uint
        };
        Some(as_info)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoLiteCity.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<commit_msg>splitn() argument change<commit_after>// (C)opyleft 2013,2014 Frank Denis

/*!
 * Bindings for the GeoIP library
 */
#![desc = "Bindings for the GeoIP library."]
#![license = "BSD"]
#![crate_name = "geoip"]
#![crate_type = "rlib"]

#![warn(non_camel_case_types,
        non_uppercase_statics,
        unnecessary_qualification,
        managed_heap_memory)]

extern crate libc;

use libc::{c_void, c_char, c_int, c_ulong, c_float};
use std::c_str::CString;
use std::fmt;
use std::io::net::ip::{IpAddr,Ipv4Addr,Ipv6Addr};

type GeoIP_ = *const c_void;
type In6Addr = [u8, ..16];

struct GeoIPLookup_ {
    netmask: c_int
}

impl GeoIPLookup_ {
    fn new() -> GeoIPLookup_ {
        GeoIPLookup_ {
            netmask: 0
        }
    }
}

#[link(name = "GeoIP")]
extern {
    fn GeoIP_open(dbtype: *const c_char, flags: c_int) -> GeoIP_;
    fn GeoIP_delete(db: GeoIP_);
    fn GeoIP_name_by_ipnum_gl(db: GeoIP_, ipnum: c_ulong, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_name_by_ipnum_v6_gl(db: GeoIP_, ipnum: In6Addr, gl: &GeoIPLookup_) -> *const c_char;
    fn GeoIP_record_by_ipnum(db: GeoIP_, ipnum: c_ulong) -> *const GeoIPRecord_;
    fn GeoIP_record_by_ipnum_v6(db: GeoIP_, ipnum: In6Addr) -> *const GeoIPRecord_;
    fn GeoIPRecord_delete(gir: *const GeoIPRecord_);
    fn GeoIP_set_charset(db: GeoIP_, charset: c_int) -> c_int;
}

enum Charset {
    UTF8 = 1
}

pub enum Options {
    Standard = 0,
    MemoryCache = 1,
    CheckCache = 2,
    IndexCache = 4,
    MmapCache = 8
}

pub enum DBType {
    CountryEdition = 1,
    RegionEditionRev0 = 7,
    CityEditionRev0 = 6,
    ORGEdition = 5,
    ISPEdition = 4,
    CityEditionRev1 = 2,
    RegionEditionRev1 = 3,
    ProxyEdition = 8,
    ASNUMEdition = 9,
    NetSpeedEdition = 10,
    DomainEdition = 11,
    CountryEditionV6 = 12,
    LocationAEdition = 13,
    AccuracyRadiusEdition = 14,
    LargeCountryEdition = 17,
    LargeCountryEditionV6 = 18,
    ASNumEditionV6 = 21,
    ISPEditionV6 = 22,
    ORGEditionV6 = 23,
    DomainEditionV6 = 24,
    LoctionAEditionV6 = 25,
    RegistrarEdition = 26,
    RegistrarEditionV6 = 27,
    UserTypeEdition = 28,
    UserTypeEditionV6 = 29,
    CityEditionRev1V6 = 30,
    CityEditionRev0V6 = 31,
    NetSpeedEditionRev1 = 32,
    NetSpeedEditionRev1V6 = 33,
    CountryConfEdition = 34,
    CityConfEdition = 35,
    RegionConfEdition = 36,
    PostalConfEdition = 37,
    AccuracyRadiusEditionV6 = 38
}

pub struct GeoIP {
    db: GeoIP_
}

pub struct GeoIPRecord_ {
    country_code: *const c_char,
    country_code3: *const c_char,
    country_name: *const c_char,
    region: *const c_char,
    city: *const c_char,
    postal_code: *const c_char,
    latitude: c_float,
    longitude: c_float,
    dma_code: c_int,
    area_code: c_int,
    charset: c_int,
    continent_code: *const c_char,
    netmask: c_int
}

pub struct ASInfo {
    pub asn: uint,
    pub name: String,
    pub netmask: uint
}

pub struct CityInfo {
    pub country_code: Option<String>,
    pub country_code3: Option<String>,
    pub country_name: Option<String>,
    pub region: Option<String>,
    pub city: Option<String>,
    pub postal_code: Option<String>,
    pub latitude: f32,
    pub longitude: f32,
    pub dma_code: uint,
    pub area_code: uint,
    pub charset: uint,
    pub continent_code: Option<String>,
    pub netmask: uint
}

impl CityInfo {
    fn from_geoiprecord(res: &GeoIPRecord_) -> CityInfo {
        let country_code = unsafe { if res.country_code.is_null() {
            None
        } else {
            CString::new(res.country_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_code3 = unsafe { if res.country_code3.is_null() {
            None
        } else {
            CString::new(res.country_code3, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let country_name = unsafe { if res.country_name.is_null() {
            None
        } else {
            CString::new(res.country_name, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let region = unsafe { if res.region.is_null() {
            None
        } else {
            CString::new(res.region, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let city = unsafe { if res.city.is_null() {
            None
        } else {
            CString::new(res.city, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let postal_code = unsafe { if res.postal_code.is_null() {
            None
        } else {
            CString::new(res.postal_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        let continent_code = unsafe { if res.continent_code.is_null() {
            None
        } else {
            CString::new(res.continent_code, false).as_str().
                and_then(|str| Some(String::from_str(str)))
        }};
        CityInfo {
            country_code: country_code,
            country_code3: country_code3,
            country_name: country_name,
            region: region,
            city: city,
            postal_code: postal_code,
            latitude: res.latitude as f32,
            longitude: res.longitude as f32,
            dma_code: res.dma_code as uint,
            area_code: res.area_code as uint,
            charset: res.charset as uint,
            continent_code: continent_code,
            netmask: res.netmask as uint
        }
    }
}

impl fmt::Show for ASInfo {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}\t{}", self.asn, self.name)
    }
}

impl GeoIP {
    pub fn open(path: &Path, options: Options) -> Result<GeoIP, String> {
        let file = match path.as_str() {
            None => return Err(format!("Invalid path {}", path.display())),
            Some(file) => file
        };
        let db = unsafe {
            GeoIP_open(file.to_c_str().unwrap(), options as c_int)
        };
        if db.is_null() {
            return Err(format!("Can't open {}", file));
        }
        if unsafe { GeoIP_set_charset(db, UTF8 as c_int) } != 0 {
            return Err("Can't set charset to UTF8".to_string());
        }
        Ok(GeoIP { db: db })
    }

    pub fn city_info_by_ip(&self, ip: IpAddr) -> Option<CityInfo> {
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_record_by_ipnum(self.db, ipnum)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_record_by_ipnum_v6(self.db, in6_addr)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let city_info = CityInfo::from_geoiprecord(&unsafe { *cres });
        unsafe { GeoIPRecord_delete(cres) };
        unsafe { std::mem::forget(cres) };
        Some(city_info)
    }

    pub fn as_info_by_ip(&self, ip: IpAddr) -> Option<ASInfo> {
        let gl = GeoIPLookup_::new();
        let cres = match ip {
            Ipv4Addr(a, b, c, d) => {
                let ipnum: c_ulong =
                    (a as c_ulong << 24) | (b as c_ulong << 16) |
                    (c as c_ulong << 8)  | (d as c_ulong);
                unsafe {
                    GeoIP_name_by_ipnum_gl(self.db, ipnum, &gl)
                }
            },
            Ipv6Addr(a, b, c, d, e, f, g, h) => {
                let in6_addr: In6Addr = [(a >> 8) as u8, a as u8,
                                         (b >> 8) as u8, b as u8,
                                         (c >> 8) as u8, c as u8,
                                         (d >> 8) as u8, d as u8,
                                         (e >> 8) as u8, e as u8,
                                         (f >> 8) as u8, f as u8,
                                         (g >> 8) as u8, g as u8,
                                         (h >> 8) as u8, h as u8];
                unsafe {
                    GeoIP_name_by_ipnum_v6_gl(self.db, in6_addr, &gl)
                }
            }
        };
        if cres.is_null() {
            return None;
        }
        let description_cstr = unsafe { CString::new(cres, true) };
        let description = match description_cstr.as_str() {
            None => return None,
            Some(description) => description
        };
        let mut di = description.splitn(1, ' ');
        let asn = match di.next() {
            None => return None,
            Some(asn) => {
                if ! asn.starts_with("AS") {
                    return None
                } else {
                    from_str::<uint>(asn.slice_from(2)).unwrap()
                }
            }
        };
        let name = di.next().unwrap_or("(none)");
        let as_info = ASInfo {
            asn: asn,
            name: name.to_string(),
            netmask: gl.netmask as uint
        };
        Some(as_info)
    }
}

impl Drop for GeoIP {
    fn drop(&mut self) {
        unsafe {
            GeoIP_delete(self.db);
        }
    }
}

#[test]
fn geoip_test_basic() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoIPASNum.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("91.203.184.192").unwrap();
    let res = geoip.as_info_by_ip(ip).unwrap();
    assert!(res.asn == 41064);
    assert!(res.name.as_slice().contains("Telefun"));
    assert!(res.netmask == 22);
}

#[test]
fn geoip_test_city() {
    let geoip = match GeoIP::open(&from_str("/opt/geoip/GeoLiteCity.dat").unwrap(), MemoryCache) {
        Err(err) => fail!(err),
        Ok(geoip) => geoip
    };
    let ip = from_str("8.8.8.8").unwrap();
    let res = geoip.city_info_by_ip(ip).unwrap();
    assert!(res.city.unwrap().as_slice() == "Mountain View");
}
<|endoftext|>