<commit_before>use cgmath::point::{Point, Point2};
use cgmath::vector::{Vec2};
use cgmath::aabb::{Aabb, Aabb2};
use color::rgb::RGB;
use color::rgb::consts::*;
use calx::rectutil::RectUtil;
use area;
use area::{TerrainType, Location, Area};
use fov::Fov;
use glutil::app::{App, SPRITE_INDEX_START};

pub static FLOOR : uint = SPRITE_INDEX_START + 10;
pub static CUBE : uint = SPRITE_INDEX_START + 1;
pub static XWALL : uint = SPRITE_INDEX_START + 20;
pub static YWALL : uint = SPRITE_INDEX_START + 21;
pub static XYWALL : uint = SPRITE_INDEX_START + 22;
pub static OWALL : uint = SPRITE_INDEX_START + 23;
pub static AVATAR : uint = SPRITE_INDEX_START + 26;
pub static WATER : uint = SPRITE_INDEX_START + 12;
pub static MAGMA : uint = SPRITE_INDEX_START + 13;
pub static MAGMA_2 : uint = SPRITE_INDEX_START + 7;
pub static CURSOR_BOTTOM : uint = SPRITE_INDEX_START + 8;
pub static CURSOR_TOP : uint = SPRITE_INDEX_START + 9;
pub static DOWNSTAIRS : uint = SPRITE_INDEX_START + 14;
pub static BLOCK : uint = SPRITE_INDEX_START + 27;
pub static TREE_TRUNK : uint = SPRITE_INDEX_START + 24;
pub static TREE_FOLIAGE : uint = SPRITE_INDEX_START + 32;
pub static GRASS : uint = SPRITE_INDEX_START + 11;

static WALL_COL: &'static RGB<u8> = &LIGHTSLATEGRAY;
static ROCK_COL: &'static RGB<u8> = &DARKGOLDENROD;
static CURSOR_COL: &'static RGB<u8> = &FIREBRICK;

static FLOOR_Z: f32 = 0.500f32;
static BLOCK_Z: f32 = 0.400f32;

/// 3x3 grid of terrain cells. Use this as the input for terrain sprite
/// computation, which will need to consider the immediate vicinity of cells.
pub struct Kernel<C> {
    n: C,
    ne: C,
    e: C,
    nw: C,
    center: C,
    se: C,
    w: C,
    sw: C,
    s: C,
}

impl<C> Kernel<C> {
    pub fn new(get: |Location| -> C, loc: Location) -> Kernel<C> {
        Kernel {
            n: get(loc + Vec2::new(-1, -1)),
            ne: get(loc + Vec2::new(0, -1)),
            e: get(loc + Vec2::new(1, -1)),
            nw: get(loc + Vec2::new(-1, 0)),
            center: get(loc),
            se: get(loc + Vec2::new(1, 0)),
            w: get(loc + Vec2::new(-1, 1)),
            sw: get(loc + Vec2::new(0, 1)),
            s: get(loc + Vec2::new(1, 1)),
        }
    }
}

pub struct Sprite {
    idx: uint,
    pos: Point2<f32>,
    z: f32,
    color: RGB<u8>,
}

impl Sprite {
    pub fn draw(&self, app: &mut App) {
        app.draw_sprite(self.idx, &self.pos, self.z, &self.color);
    }
}

pub fn terrain_sprites(k: &Kernel<TerrainType>, pos: &Point2<f32>) -> ~[Sprite] {
    let mut ret = ~[];

    // TODO: Make this thing more data-driven once the data schema needed by
    // different types of terrain becomes clearer.
    match k.center {
        area::Water => {
            ret.push(Sprite { idx: WATER, pos: *pos, z: FLOOR_Z, color: ROYALBLUE });
        },
        area::Magma => {
            // A two-tone tile, made using two sprites.
            ret.push(Sprite { idx: MAGMA, pos: *pos, z: FLOOR_Z, color: CRIMSON });
            ret.push(Sprite { idx: MAGMA_2, pos: *pos, z: FLOOR_Z, color: YELLOW });
        },
        area::Tree => {
            // A two-toner, with floor, using two z-layers
            ret.push(Sprite { idx: FLOOR, pos: *pos, z: FLOOR_Z, color: SLATEGRAY });
            ret.push(Sprite { idx: TREE_TRUNK, pos: *pos, z: BLOCK_Z, color: SADDLEBROWN });
            ret.push(Sprite { idx: TREE_FOLIAGE, pos: *pos, z: BLOCK_Z, color: DARKGREEN });
        },
        area::Floor => {
            ret.push(Sprite { idx: FLOOR, pos: *pos, z: FLOOR_Z, color: SLATEGRAY });
        },
        area::Grass => {
            ret.push(Sprite { idx: GRASS, pos: *pos, z: FLOOR_Z, color: DARKGREEN });
        },
        area::Downstairs => {
            ret.push(Sprite { idx: DOWNSTAIRS, pos: *pos, z: FLOOR_Z, color: SLATEGRAY });
        },
        area::Rock => {
            ret.push(Sprite { idx: BLOCK, pos: *pos, z: BLOCK_Z, color: *ROCK_COL });
            // Back lines for blocks with open floor behind them.
            if !k.nw.is_wall() {
                ret.push(Sprite { idx: BLOCK + 1, pos: *pos, z: BLOCK_Z, color: *ROCK_COL });
            }
            if !k.n.is_wall() {
                ret.push(Sprite { idx: BLOCK + 2, pos: *pos, z: BLOCK_Z, color: *ROCK_COL });
            }
            if !k.ne.is_wall() {
                ret.push(Sprite { idx: BLOCK + 3, pos: *pos, z: BLOCK_Z, color: *ROCK_COL });
            }
        }
        area::Wall => {
            ret.push(Sprite { idx: FLOOR, pos: *pos, z: FLOOR_Z, color: SLATEGRAY });
            let (left_wall, right_wall, block) = wall_flags_lrb(k);
            if block {
                ret.push(Sprite { idx: CUBE, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            }
            if left_wall && right_wall {
                ret.push(Sprite { idx: XYWALL, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            } else if left_wall {
                ret.push(Sprite { idx: XWALL, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            } else if right_wall {
                ret.push(Sprite { idx: YWALL, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            } else if !block || !k.s.is_wall() {
                // NB: This branch has some actual local kernel logic not
                // handled by wall_flags_lrb.
                ret.push(Sprite { idx: OWALL, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            }
        },
    }

    // Return code:
    // (there is a wall piece to the left front of the tile,
    //  there is a wall piece to the right front of the tile,
    //  there is a solid block in the tile)
    fn wall_flags_lrb(k: &Kernel<TerrainType>) -> (bool, bool, bool) {
        if k.nw.is_wall() && k.n.is_wall() && k.ne.is_wall() {
            // If there is open space to east or west, even if this block
            // has adjacent walls to the southeast or the southwest, those
            // will be using thin wall sprites, so this block needs to have
            // the corresponding wall bit to make the wall line not have
            // gaps.
            (!k.w.is_wall() || !k.sw.is_wall(), !k.e.is_wall() || !k.se.is_wall(), true)
        } else {
            (k.nw.is_wall(), k.ne.is_wall(), false)
        }
    }

    ret
}

pub fn draw_area(
    area: &Area, app: &mut App, center: &Location,
    seen: &Fov, remembered: &Fov) {
    // XXX: Horrible prototype code, figure out cleaning.

    let origin = Vec2::new(320.0f32, 180.0f32);

    // Mouse cursoring
    let mouse = app.get_mouse();
    let cursor_chart_pos = screen_to_chart(&mouse.pos.add_v(&origin.neg()).add_v(&Vec2::new(8.0f32, 0.0f32)));

    let mut rect = Aabb2::new(
        screen_to_chart(&Point2::new(0f32, 0f32).add_v(&origin.neg())),
        screen_to_chart(&Point2::new(640f32, 392f32).add_v(&origin.neg())));
    rect = rect.grow(&screen_to_chart(&Point2::new(640f32, 0f32).add_v(&origin.neg())));
    rect = rect.grow(&screen_to_chart(&Point2::new(0f32, 392f32).add_v(&origin.neg())));

    let &Location(ref offset) = center;
    let pos_offset = Vec2::new(offset.x as int, offset.y as int);

    for pt in rect.points() {
        let p = Location(pt) + pos_offset;
        let offset = chart_to_screen(&pt).add_v(&origin);

        let seen = seen.contains(&p) || remembered.contains(&p);
        let kernel = Kernel::new(|p| area.get(p), p);
        let mut sprites = terrain_sprites(&kernel, &offset);
        for s in sprites.mut_iter() {
            if !seen { s.color = DARKSLATEGRAY; }
            s.draw(app);
        }

        if &p == center {
            app.draw_sprite(AVATAR, &offset, BLOCK_Z, &AZURE);
        }
    }

    app.draw_sprite(CURSOR_BOTTOM, &chart_to_screen(&cursor_chart_pos).add_v(&origin), FLOOR_Z, CURSOR_COL);
    app.draw_sprite(CURSOR_TOP, &chart_to_screen(&cursor_chart_pos).add_v(&origin), BLOCK_Z, CURSOR_COL);

}

pub fn chart_to_screen(map_pos: &Point2<i8>) -> Point2<f32> {
    Point2::new(
        16.0 * (map_pos.x as f32) - 16.0 * (map_pos.y as f32),
        8.0 * (map_pos.x as f32) + 8.0 * (map_pos.y as f32))
}

pub fn screen_to_chart(screen_pos: &Point2<f32>) -> Point2<i8> {
    let column = (screen_pos.x / 16.0).floor();
    let row = ((screen_pos.y - column * 8.0) / 16.0).floor();
    Point2::new((column + row) as i8, row as i8)
}
<commit_msg>Tweak magma terrain view<commit_after>use cgmath::point::{Point, Point2};
use cgmath::vector::{Vec2};
use cgmath::aabb::{Aabb, Aabb2};
use color::rgb::RGB;
use color::rgb::consts::*;
use calx::rectutil::RectUtil;
use area;
use area::{TerrainType, Location, Area};
use fov::Fov;
use glutil::app::{App, SPRITE_INDEX_START};

pub static FLOOR : uint = SPRITE_INDEX_START + 10;
pub static CUBE : uint = SPRITE_INDEX_START + 1;
pub static XWALL : uint = SPRITE_INDEX_START + 20;
pub static YWALL : uint = SPRITE_INDEX_START + 21;
pub static XYWALL : uint = SPRITE_INDEX_START + 22;
pub static OWALL : uint = SPRITE_INDEX_START + 23;
pub static AVATAR : uint = SPRITE_INDEX_START + 26;
pub static WATER : uint = SPRITE_INDEX_START + 12;
pub static MAGMA : uint = SPRITE_INDEX_START + 13;
pub static MAGMA_2 : uint = SPRITE_INDEX_START + 7;
pub static CURSOR_BOTTOM : uint = SPRITE_INDEX_START + 8;
pub static CURSOR_TOP : uint = SPRITE_INDEX_START + 9;
pub static DOWNSTAIRS : uint = SPRITE_INDEX_START + 14;
pub static BLOCK : uint = SPRITE_INDEX_START + 27;
pub static TREE_TRUNK : uint = SPRITE_INDEX_START + 24;
pub static TREE_FOLIAGE : uint = SPRITE_INDEX_START + 32;
pub static GRASS : uint = SPRITE_INDEX_START + 11;

static WALL_COL: &'static RGB<u8> = &LIGHTSLATEGRAY;
static ROCK_COL: &'static RGB<u8> = &DARKGOLDENROD;
static CURSOR_COL: &'static RGB<u8> = &FIREBRICK;

static FLOOR_Z: f32 = 0.500f32;
static BLOCK_Z: f32 = 0.400f32;

/// 3x3 grid of terrain cells. Use this as the input for terrain sprite
/// computation, which will need to consider the immediate vicinity of cells.
pub struct Kernel<C> {
    n: C,
    ne: C,
    e: C,
    nw: C,
    center: C,
    se: C,
    w: C,
    sw: C,
    s: C,
}

impl<C> Kernel<C> {
    pub fn new(get: |Location| -> C, loc: Location) -> Kernel<C> {
        Kernel {
            n: get(loc + Vec2::new(-1, -1)),
            ne: get(loc + Vec2::new(0, -1)),
            e: get(loc + Vec2::new(1, -1)),
            nw: get(loc + Vec2::new(-1, 0)),
            center: get(loc),
            se: get(loc + Vec2::new(1, 0)),
            w: get(loc + Vec2::new(-1, 1)),
            sw: get(loc + Vec2::new(0, 1)),
            s: get(loc + Vec2::new(1, 1)),
        }
    }
}

pub struct Sprite {
    idx: uint,
    pos: Point2<f32>,
    z: f32,
    color: RGB<u8>,
}

impl Sprite {
    pub fn draw(&self, app: &mut App) {
        app.draw_sprite(self.idx, &self.pos, self.z, &self.color);
    }
}

pub fn terrain_sprites(k: &Kernel<TerrainType>, pos: &Point2<f32>) -> ~[Sprite] {
    let mut ret = ~[];

    // TODO: Make this thing more data-driven once the data schema needed by
    // different types of terrain becomes clearer.
    match k.center {
        area::Water => {
            ret.push(Sprite { idx: WATER, pos: *pos, z: FLOOR_Z, color: ROYALBLUE });
        },
        area::Magma => {
            ret.push(Sprite { idx: MAGMA, pos: *pos, z: FLOOR_Z, color: DARKRED });
        },
        area::Tree => {
            // A two-toner, with floor, using two z-layers
            ret.push(Sprite { idx: FLOOR, pos: *pos, z: FLOOR_Z, color: SLATEGRAY });
            ret.push(Sprite { idx: TREE_TRUNK, pos: *pos, z: BLOCK_Z, color: SADDLEBROWN });
            ret.push(Sprite { idx: TREE_FOLIAGE, pos: *pos, z: BLOCK_Z, color: DARKGREEN });
        },
        area::Floor => {
            ret.push(Sprite { idx: FLOOR, pos: *pos, z: FLOOR_Z, color: SLATEGRAY });
        },
        area::Grass => {
            ret.push(Sprite { idx: GRASS, pos: *pos, z: FLOOR_Z, color: DARKGREEN });
        },
        area::Downstairs => {
            ret.push(Sprite { idx: DOWNSTAIRS, pos: *pos, z: FLOOR_Z, color: SLATEGRAY });
        },
        area::Rock => {
            ret.push(Sprite { idx: BLOCK, pos: *pos, z: BLOCK_Z, color: *ROCK_COL });
            // Back lines for blocks with open floor behind them.
            if !k.nw.is_wall() {
                ret.push(Sprite { idx: BLOCK + 1, pos: *pos, z: BLOCK_Z, color: *ROCK_COL });
            }
            if !k.n.is_wall() {
                ret.push(Sprite { idx: BLOCK + 2, pos: *pos, z: BLOCK_Z, color: *ROCK_COL });
            }
            if !k.ne.is_wall() {
                ret.push(Sprite { idx: BLOCK + 3, pos: *pos, z: BLOCK_Z, color: *ROCK_COL });
            }
        }
        area::Wall => {
            ret.push(Sprite { idx: FLOOR, pos: *pos, z: FLOOR_Z, color: SLATEGRAY });
            let (left_wall, right_wall, block) = wall_flags_lrb(k);
            if block {
                ret.push(Sprite { idx: CUBE, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            }
            if left_wall && right_wall {
                ret.push(Sprite { idx: XYWALL, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            } else if left_wall {
                ret.push(Sprite { idx: XWALL, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            } else if right_wall {
                ret.push(Sprite { idx: YWALL, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            } else if !block || !k.s.is_wall() {
                // NB: This branch has some actual local kernel logic not
                // handled by wall_flags_lrb.
                ret.push(Sprite { idx: OWALL, pos: *pos, z: BLOCK_Z, color: *WALL_COL });
            }
        },
    }

    // Return code:
    // (there is a wall piece to the left front of the tile,
    //  there is a wall piece to the right front of the tile,
    //  there is a solid block in the tile)
    fn wall_flags_lrb(k: &Kernel<TerrainType>) -> (bool, bool, bool) {
        if k.nw.is_wall() && k.n.is_wall() && k.ne.is_wall() {
            // If there is open space to east or west, even if this block
            // has adjacent walls to the southeast or the southwest, those
            // will be using thin wall sprites, so this block needs to have
            // the corresponding wall bit to make the wall line not have
            // gaps.
            (!k.w.is_wall() || !k.sw.is_wall(), !k.e.is_wall() || !k.se.is_wall(), true)
        } else {
            (k.nw.is_wall(), k.ne.is_wall(), false)
        }
    }

    ret
}

pub fn draw_area(
    area: &Area, app: &mut App, center: &Location,
    seen: &Fov, remembered: &Fov) {
    // XXX: Horrible prototype code, figure out cleaning.

    let origin = Vec2::new(320.0f32, 180.0f32);

    // Mouse cursoring
    let mouse = app.get_mouse();
    let cursor_chart_pos = screen_to_chart(&mouse.pos.add_v(&origin.neg()).add_v(&Vec2::new(8.0f32, 0.0f32)));

    let mut rect = Aabb2::new(
        screen_to_chart(&Point2::new(0f32, 0f32).add_v(&origin.neg())),
        screen_to_chart(&Point2::new(640f32, 392f32).add_v(&origin.neg())));
    rect = rect.grow(&screen_to_chart(&Point2::new(640f32, 0f32).add_v(&origin.neg())));
    rect = rect.grow(&screen_to_chart(&Point2::new(0f32, 392f32).add_v(&origin.neg())));

    let &Location(ref offset) = center;
    let pos_offset = Vec2::new(offset.x as int, offset.y as int);

    for pt in rect.points() {
        let p = Location(pt) + pos_offset;
        let offset = chart_to_screen(&pt).add_v(&origin);

        let seen = seen.contains(&p) || remembered.contains(&p);
        let kernel = Kernel::new(|p| area.get(p), p);
        let mut sprites = terrain_sprites(&kernel, &offset);
        for s in sprites.mut_iter() {
            if !seen { s.color = DARKSLATEGRAY; }
            s.draw(app);
        }

        if &p == center {
            app.draw_sprite(AVATAR, &offset, BLOCK_Z, &AZURE);
        }
    }

    app.draw_sprite(CURSOR_BOTTOM, &chart_to_screen(&cursor_chart_pos).add_v(&origin), FLOOR_Z, CURSOR_COL);
    app.draw_sprite(CURSOR_TOP, &chart_to_screen(&cursor_chart_pos).add_v(&origin), BLOCK_Z, CURSOR_COL);

}

pub fn chart_to_screen(map_pos: &Point2<i8>) -> Point2<f32> {
    Point2::new(
        16.0 * (map_pos.x as f32) - 16.0 * (map_pos.y as f32),
        8.0 * (map_pos.x as f32) + 8.0 * (map_pos.y as f32))
}

pub fn screen_to_chart(screen_pos: &Point2<f32>) -> Point2<i8> {
    let column = (screen_pos.x / 16.0).floor();
    let row = ((screen_pos.y - column * 8.0) / 16.0).floor();
    Point2::new((column + row) as i8, row as i8)
}
<|endoftext|>


<commit_before>extern crate rand;

use std::convert::From;
use std::default::Default;
use std::iter::FromIterator;

use std::iter::repeat;
use std::collections::VecDeque;
// use std::collections::vec_deque::{ IntoIter, Iter, IterMut };
use self::rand::Rng;

/// a little implementation of a random-wheel.
pub struct RouletteWheel<T> {
    /// the sum of all probabilities in this wheel.
    proba_sum: f32,
    /// all the (probability, data) in a linked-list to pop easily.
    cards: VecDeque<(f32, T)>
}

impl<T: Clone> Clone for RouletteWheel<T> {
    fn clone(&self) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: self.proba_sum,
            cards: self.cards.clone()
        }
    }
}

impl<T> Default for RouletteWheel<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'a, T: Clone> From<&'a [T]> for RouletteWheel<T> {
    fn from(s: &'a [T]) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: s.len() as f32,
            cards: VecDeque::from_iter(repeat(1.0).zip(s.iter().cloned()))
        }
    }
}

// impl<T> IntoIterator for RouletteWheel<T> {

//     type Item = (f32, T);
//     type IntoIter = IntoIter<(f32, T)>;

//     /// Creates a consuming iterator, that is, one that moves each value out of
//     /// the rouletteWheel (from start to end).
//     #[inline]
//     fn into_iter(self) -> IntoIter<(f32, T)> {
//         self.cards.into_iter()
//     }
// }

// pub struct ProbaModifier<T> {
//     container: RouletteWheel<T>, // need &'a mut !!!
//     position: usize
// }

// impl<T> ProbaModifier<T> {

//     pub fn read(&self) -> &(f32, T) {
//         &self.container.cards[self.position]
//     }

//     pub fn update(&mut self, new_proba: f32) {

//         let card = &mut self.container.cards[self.position];
//         self.container.proba_sum += card.0 - new_proba;
//         card.0 = new_proba;
//     }
// }

// impl<T> IntoIterator for RouletteWheel<T> {

//     type Item = ProbaModifier<T>;
//     type IntoIter = IntoIter<T>;

//     fn into_iter(self) -> IntoIter<T> {
//         IntoIter(ProbaModifier{
//             container: self,
//             position: 0
//         })
//     }
// }

// pub struct IntoIter<T>(ProbaModifier<T>);

// impl<T> Iterator for IntoIter<T> {

//     type Item = ProbaModifier<T>;

//     fn next(&mut self) -> Option<ProbaModifier<T>> {
//         // Some(self.0)
//         None
//     }
// }

impl<T> RouletteWheel<T> {
    // /// create a new random-wheel from vector.
    // /// # Example
    // ///
    // /// ```
    // /// use roulette_wheel::RouletteWheel;
    // ///
    // /// let numbers: Vec<_> = (0..20).collect();
    // ///
    // /// // default probability is set to 1.0 for each element
    // /// let rw: RouletteWheel<u8> = RouletteWheel::from_vec(numbers);
    // /// ```
    // pub fn from_vec(vector: Vec<T>) -> RouletteWheel<T> {
    //     RouletteWheel {
    //         proba_sum: vector.len() as f32,
    //         cards: repeat(1.0).into_iter().zip(vector).collect()
    //     }
    // }

    /// create a new empty random-wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    /// ```
    pub fn new() -> RouletteWheel<T> {

        RouletteWheel {

            proba_sum: 0.0,
            cards: VecDeque::new()
        }
    }

    /// Creates an empty RouletteWheel with space for at least n elements.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let numbers: Vec<_> = (0..20).collect();
    /// let mut rw: RouletteWheel<u8> = RouletteWheel::with_capacity(numbers.len());
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn with_capacity(n: usize) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: 0.0,
            cards: VecDeque::with_capacity(n)
        }
    }

    /// Reserves capacity for at least `additional` more elements to be inserted
    /// in the given `Ringbuf`.
    /// The collection may reserve more space to avoid frequent reallocations.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw: RouletteWheel<u8> = RouletteWheel::new();
    /// rw.reserve(20);
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn reserve(&mut self, additional: usize) {
        self.cards.reserve(additional);
    }

    /// Returns the number of elements the RouletteWheel can hold without
    /// reallocating.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    ///
    /// println!("actual capacity: {}", rw.capacity());
    /// ```
    pub fn capacity(&self) -> usize {
        self.cards.capacity()
    }

    /// returns the number of elements in the wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// assert_eq!(rw.len(), 0);
    ///
    /// rw.push(1., 'r');
    /// rw.push(1., 'c');
    /// rw.push(1., 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.cards.len()
    }

    /// remove all elements in this wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1., 'r');
    /// rw.push(1., 'c');
    /// rw.push(1., 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    ///
    /// rw.clear();
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn clear(&mut self) {
        self.cards.clear()
    }

    /// returns `true` if this wheel is empty else return `false`.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// assert_eq!(rw.is_empty(), true);
    ///
    /// rw.push(1., 'r');
    /// rw.push(1., 'c');
    /// rw.push(1., 'a');
    ///
    /// assert_eq!(rw.is_empty(), false);
    /// ```
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    // /// Returns an iterator over the slice.
    // /// # Example
    // ///
    // /// ```
    // /// use roulette_wheel::RouletteWheel;
    // ///
    // /// let mut rw = RouletteWheel::new();
    // ///
    // /// rw.push(1., 'r');
    // /// rw.push(1., 'c');
    // /// rw.push(1., 'a');
    // ///
    // /// let mut iter = rw.iter();
    // ///
    // /// assert_eq!(iter.next(), Some(&(1.0, 'r')));
    // /// assert_eq!(iter.next(), Some(&(1.0, 'c')));
    // /// assert_eq!(iter.next(), Some(&(1.0, 'a')));
    // /// assert_eq!(iter.next(), None);
    // /// ```
    // pub fn iter(&self) -> Iter<(f32, T)> {
    //     self.cards.iter()
    // }

    // /// Returns an iterator that allows modifying each value.
    // /// # Example
    // ///
    // /// ```
    // /// use roulette_wheel::RouletteWheel;
    // ///
    // /// let mut rw = RouletteWheel::new();
    // ///
    // /// rw.push(1., 'r');
    // /// rw.push(1., 'c');
    // /// rw.push(1., 'a');
    // ///
    // /// for a in &mut rw.iter_mut() {
    // ///     a.1 = 'm';
    // /// }
    // ///
    // /// assert_eq!(rw.peek(), Some((1., &'m')));
    // /// ```
    // pub fn iter_mut(&mut self) -> IterMut<(f32, T)> {
    //     self.cards.iter_mut()
    // }

    /// add an element associated with a probability.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1., 'r');
    /// rw.push(1., 'c');
    /// rw.push(1., 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn push(&mut self, proba: f32, data: T) {
        assert!(proba > 0.0, "proba {} is lower or equal to zero!", proba);
        self.cards.push_back((proba, data));
        self.proba_sum += proba;
        if self.proba_sum.is_infinite() {
            panic!("Probability sum reached an Inf value!");
        }
    }

    /// Will recompute the probabilities sum
    /// use it when you iterate through this vector and change proba values
    pub fn compute_proba_sum(&mut self) {
        self.proba_sum = 0.0;
        for &(proba, _) in self.cards.iter() {
            assert!(proba > 0.0, "proba '{}' is lower or equal to zero!", proba);
            self.proba_sum += proba;
        }
        if self.proba_sum.is_infinite() {
            panic!("Probability sum reached an Inf value!");
        }
    }

    /// returns total of luck you pushed.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.5, 'r');
    /// rw.push(2., 'c');
    /// rw.push(3., 'a');
    ///
    /// assert_eq!(rw.proba_sum(), 6.5);
    /// ```
    pub fn proba_sum(&self) -> f32 {
        self.proba_sum
    }

    /// returns a random distance to browser between 0 and the probabilities sum.
    fn gen_random_dist(&self) -> f32 {
        match self.proba_sum {
            sum if sum > 0. => rand::thread_rng().gen_range(0., sum),
            _               => 0.
        }
    }

    /// returns a random index in self.cards.
    fn get_random_index(&self) -> Option<usize> {
        if self.is_empty() == false {
            let mut dist = self.gen_random_dist();
            for (id, &(ref proba, _)) in self.cards.iter().enumerate() {
                dist -= *proba;
                if dist <= 0. {
                    return Some(id);
                }
            }
            None
        }
        else { None }
    }

    /// returns a ref to the randomly peeked element with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1., 'r');
    ///
    /// assert_eq!(rw.peek(), Some((1.0, &'r')));
    /// assert_eq!(rw.peek(), Some((1.0, &'r')));
    /// ```
    pub fn peek(&self) -> Option<(f32, &T)> {
        if let Some(index) = self.get_random_index() {
            if let Some(&(proba, ref data)) = self.cards.get(index) {
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }

    /// returns a mutable ref to the randomly peeked element with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1., 'r');
    ///
    /// match rw.peek_mut() {
    ///     Some((_, val)) => *val = 'b',
    ///     None => {}
    /// }
    ///
    /// assert_eq!(rw.peek(), Some((1.0, &'b')));
    /// ```
    pub fn peek_mut(&mut self) -> Option<(f32, &mut T)> {
        if let Some(index) = self.get_random_index() {
            if let Some(&mut (proba, ref mut data)) = self.cards.get_mut(index) {
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }

    /// removes a randomly peeked element and return it with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1., 'r');
    ///
    /// assert_eq!(rw.pop(), Some((1.0, 'r')));
    ///
    /// // once you pop the value, it doesn't exist anymore
    /// assert_eq!(rw.peek(), None);
    /// assert_eq!(rw.pop(), None);
    /// ```
    pub fn pop(&mut self) -> Option<(f32, T)> {
        if let Some(index) = self.get_random_index() {
            if let Some((proba, data)) = self.cards.remove(index) {
                self.proba_sum -= proba;
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }
}
<commit_msg>trying to maeke it works<commit_after>extern crate rand;

use std::convert::From;
use std::default::Default;
use std::iter::{FromIterator, Iterator, repeat};
use std::collections::VecDeque;
use std::collections::vec_deque::{Iter, IterMut};
use self::rand::Rng;

/// a little implementation of a random-wheel.
pub struct RouletteWheel<T> {
    /// the sum of all probabilities in this wheel.
    proba_sum: f32,
    /// all the (probability, data) in a linked-list to pop easily.
    cards: VecDeque<(f32, T)>
}

impl<T: Clone> Clone for RouletteWheel<T> {
    fn clone(&self) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: self.proba_sum,
            cards: self.cards.clone()
        }
    }
}

impl<T> Default for RouletteWheel<T> {
    fn default() -> Self {
        Self::new()
    }
}

impl<'a, T: Clone> From<&'a [T]> for RouletteWheel<T> {
    fn from(s: &'a [T]) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: s.len() as f32,
            cards: VecDeque::from_iter(repeat(1.0).zip(s.iter().cloned()))
        }
    }
}

/// This struct is given by the `iter_mut()` method and is here to help you modifing
/// each element fitness: when you `set_fitness()` the `RouletteWheel::proba_sum`
/// is updated automatically.
pub struct FitnessModifier<'a, T: 'a> {
    wheel: &'a mut RouletteWheel<T>,
    value: &'a mut (f32, T)
}

impl<'a, T> FitnessModifier<'a, T> {
    /// read (proba, data) of each element
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// // fm for FitnessModifier
    /// for fm in rw.iter_mut() {
    ///     let &mut (proba, _) = fm.read();
    ///     println!("({}, _)", proba);
    /// }
    /// ```
    pub fn read(&'a self) -> &'a (f32, T) {
        self.value
    }

    /// update the probability of each element to be catch
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    /// assert!(rw.proba_sum(), 3.0);
    ///
    /// // fm for FitnessModifier
    /// for fm in rw.iter_mut() {
    ///     fm.set_proba(2.0);
    /// }
    /// assert!(rw.proba_sum(), 6.0);
    /// ```
    pub fn set_proba(&'a self, new: f32) {
        let &mut (ref mut proba, _) = self.value;
        self.wheel.proba_sum -= *proba;
        self.wheel.proba_sum += new;
        *proba = new;
    }
}

pub struct FitnessIterMut<'a, T: 'a> {
    wheel: &'a mut RouletteWheel<T>,
    iterator: &'a mut IterMut<'a, (f32, T)>
}

impl<'a, T> Iterator for FitnessIterMut<'a, T> {
    type Item = FitnessModifier<'a, T>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(value) = self.iterator.next() {
            Some(FitnessModifier { wheel: self.wheel, value: value })
        }
        else {
            None
        }
    }
}

impl<T> RouletteWheel<T> {
    /// create a new empty random-wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    /// ```
    pub fn new() -> RouletteWheel<T> {

        RouletteWheel {

            proba_sum: 0.0,
            cards: VecDeque::new()
        }
    }

    /// Creates an empty RouletteWheel with space for at least n elements.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let numbers: Vec<_> = (0..20).collect();
    /// let rw: RouletteWheel<u8> = RouletteWheel::with_capacity(numbers.len());
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn with_capacity(n: usize) -> RouletteWheel<T> {
        RouletteWheel {
            proba_sum: 0.0,
            cards: VecDeque::with_capacity(n)
        }
    }

    /// Reserves capacity for at least `additional` more elements to be inserted
    /// in the given `Ringbuf`.
    /// The collection may reserve more space to avoid frequent reallocations.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    /// rw.reserve(20);
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn reserve(&mut self, additional: usize) {
        self.cards.reserve(additional);
    }

    /// Returns the number of elements the RouletteWheel can hold without
    /// reallocating.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let rw: RouletteWheel<u8> = RouletteWheel::new();
    ///
    /// println!("actual capacity: {}", rw.capacity());
    /// ```
    pub fn capacity(&self) -> usize {
        self.cards.capacity()
    }

    /// returns the number of elements in the wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// assert_eq!(rw.len(), 0);
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn len(&self) -> usize {
        self.cards.len()
    }

    /// returns `true` if empty else return `false`.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// assert_eq!(rw.is_empty(), true);
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.is_empty(), false);
    /// ```
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// remove all elements in this wheel.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    ///
    /// rw.clear();
    ///
    /// assert_eq!(rw.len(), 0);
    /// ```
    pub fn clear(&mut self) {
        self.cards.clear()
    }

    /// add an element associated with a probability.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// assert_eq!(rw.len(), 3);
    /// ```
    pub fn push(&mut self, proba: f32, data: T) {
        assert!(proba > 0.0, "proba {} is lower or equal to zero!", proba);
        self.cards.push_back((proba, data));
        self.proba_sum += proba;
        if self.proba_sum.is_infinite() {
            panic!("Probability sum reached an Inf value!");
        }
    }

    /// Will recompute the probabilities sum
    /// use it when you iterate through this vector and change proba values
    pub fn compute_proba_sum(&mut self) {
        self.proba_sum = 0.0;
        for &(proba, _) in self.cards.iter() {
            assert!(proba > 0.0, "proba '{}' is lower or equal to zero!", proba);
            self.proba_sum += proba;
        }
        if self.proba_sum.is_infinite() {
            panic!("Probability sum reached an Inf value!");
        }
    }

    /// returns total of luck you pushed.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.5, 'r');
    /// rw.push(2., 'c');
    /// rw.push(3., 'a');
    ///
    /// assert_eq!(rw.proba_sum(), 6.5);
    /// ```
    pub fn proba_sum(&self) -> f32 {
        self.proba_sum
    }

    /// returns a random distance to browser between 0 and the probabilities sum.
    fn gen_random_dist(&self) -> f32 {
        match self.proba_sum {
            sum if sum > 0. => rand::thread_rng().gen_range(0., sum),
            _               => 0.
        }
    }

    /// returns a random index in self.cards.
    fn get_random_index(&self) -> Option<usize> {
        if self.is_empty() == false {
            let mut dist = self.gen_random_dist();
            for (id, &(ref proba, _)) in self.cards.iter().enumerate() {
                dist -= *proba;
                if dist <= 0. {
                    return Some(id);
                }
            }
            None
        }
        else { None }
    }

    /// returns a ref to the randomly peeked element with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    ///
    /// assert_eq!(rw.peek(), Some((1.0, &'r')));
    /// assert_eq!(rw.peek(), Some((1.0, &'r')));
    /// ```
    pub fn peek(&self) -> Option<(f32, &T)> {
        if let Some(index) = self.get_random_index() {
            if let Some(&(proba, ref data)) = self.cards.get(index) {
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }

    /// returns a mutable ref to the randomly peeked element with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    ///
    /// match rw.peek_mut() {
    ///     Some((_, val)) => *val = 'b',
    ///     None => {}
    /// }
    ///
    /// assert_eq!(rw.peek(), Some((1.0, &'b')));
    /// ```
    pub fn peek_mut(&mut self) -> Option<(f32, &mut T)> {
        if let Some(index) = self.get_random_index() {
            if let Some(&mut (proba, ref mut data)) = self.cards.get_mut(index) {
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }

    /// removes a randomly peeked element and return it with
    /// it's probality to be peeked.
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    ///
    /// assert_eq!(rw.pop(), Some((1.0, 'r')));
    ///
    /// // once you pop the value, it doesn't exist anymore
    /// assert_eq!(rw.peek(), None);
    /// assert_eq!(rw.pop(), None);
    /// ```
    pub fn pop(&mut self) -> Option<(f32, T)> {
        if let Some(index) = self.get_random_index() {
            if let Some((proba, data)) = self.cards.remove(index) {
                self.proba_sum -= proba;
                Some((proba, data))
            }
            else { None }
        }
        else { None }
    }

    /// Returns an iterator over the slice, giving &(proba, elem).
    /// # Example
    ///
    /// ```
    /// use roulette_wheel::RouletteWheel;
    ///
    /// let mut rw = RouletteWheel::new();
    ///
    /// rw.push(1.0, 'r');
    /// rw.push(1.0, 'c');
    /// rw.push(1.0, 'a');
    ///
    /// let mut iter = rw.iter();
    ///
    /// assert_eq!(iter.next(), Some(&(1.0, 'r')));
    /// assert_eq!(iter.next(), Some(&(1.0, 'c')));
    /// assert_eq!(iter.next(), Some(&(1.0, 'a')));
    /// assert_eq!(iter.next(), None);
    /// ```
    pub fn iter(&self) -> Iter<(f32, T)> {
        self.cards.iter()
    }
}
<|endoftext|>


<commit_before>
// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
// https://serde.rs/codegen-hybrid.html

// FIXME: Make sure that all structs above Issue are not using `String`s instead of `Enum`s.
// FIXME: Harmonize the different state enums (e.g. IssueState, MergeRequestState, Authors)
// FIXME: Use a type for sha1
// FIXME: Use chrono crate for dates

#[derive(Debug, Serialize, Deserialize)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Group {
    pub id: i64,
    pub name: String,
    pub path: String,
    pub description: String,
    pub visibility_level: i64,
    pub lfs_enabled: bool,
    pub avatar_url: Option<String>,
    pub web_url: String,
    pub request_access_enabled: bool,
}

pub type Groups = Vec<Group>;

#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectOwner {
    pub name: String,
    pub username: String,
    pub id: i64,
    pub state: String,
    pub avatar_url: String,
    pub web_url: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespaceAvatar {
    url: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespace {
    id: i64,
    name: String,
    path: String,
    owner_id: Option<i64>,  // FIXME: Why would a project not have this?
    created_at: String,  // FIXME: Date instead?
    updated_at: String,  // FIXME: Date instead?
    description: String,
    avatar: Option<ProjectNamespaceAvatar>,
    membership_lock: Option<bool>,
    share_with_group_lock: bool,
    visibility_level: i64,
    request_access_enabled: bool,
    ldap_sync_status: Option<String>,
    ldap_sync_error: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_successful_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_sync_at: Option<String>,  // FIXME: Is String the proper type?
    deleted_at: Option<String>,  // FIXME: Is String the proper type?
    lfs_enabled: Option<String>,  // FIXME: Is String the proper type?
    repository_size_limit: Option<String>  // FIXME: Is String the proper type?
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectForkedFrom {
    id: i64,
    http_url_to_repo: String,
    web_url: String,
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectAccess {
    access_level: i64,
    notification_level: i64,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectPermissions {
    project_access: Option<ProjectAccess>,
    group_access: Option<ProjectAccess>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectSharedWithGroup {
    group_id: i64,
    group_name: String,
    group_access_level: i64,
}

// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
#[derive(Debug, Serialize, Deserialize)]
pub struct Project {
    id: i64,
    description: String,
    default_branch: Option<String>,
    tag_list: Vec<String>,
    public: bool,
    archived: bool,
    visibility_level: i64,
    ssh_url_to_repo: String,
    http_url_to_repo: String,
    web_url: String,
    // owner: Option<ProjectOwner>,  // FIXME: Why would a project not have an owner?
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
    container_registry_enabled: Option<bool>,
    issues_enabled: bool,
    merge_requests_enabled: bool,
    wiki_enabled: bool,
    builds_enabled: bool,
    snippets_enabled: bool,
    created_at: String,  // FIXME: Date instead?
    last_activity_at: String,  // FIXME: Date instead?
    shared_runners_enabled: bool,
    lfs_enabled: bool,
    creator_id: i64,
    namespace: ProjectNamespace,
    forked_from_project: Option<ProjectForkedFrom>,
    avatar_url: Option<String>,
    star_count: i64,
    forks_count: i64,
    open_issues_count: i64,
    runners_token: Option<String>,
    public_builds: bool,
    shared_with_groups: Vec<ProjectSharedWithGroup>,
    only_allow_merge_if_build_succeeds: bool,
    request_access_enabled: bool,
    only_allow_merge_if_all_discussions_are_resolved: Option<bool>,  // FIXME: Is bool the proper type?
    approvals_before_merge: Option<i64>,
    permissions: ProjectPermissions,
}

pub type Projects = Vec<Project>;

#[derive(Debug, Serialize, Deserialize)]
enum IssueState {
    #[serde(rename = "opened")]
    Opened,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
enum UserState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "blocked")]
    Blocked,
}

#[derive(Debug, Serialize, Deserialize)]
enum MilestoneState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
struct Milestone {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MilestoneState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    due_date: Option<String>  // FIXME: Use date type?
}

#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    username: String,
    id: i64,
    state: UserState,
    avatar_url: Option<String>,
    web_url: Option<String>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Issue {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: IssueState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    labels: Vec<String>,
    milestone: Option<Milestone>,
    assignee: Option<User>,
    author: User,
    subscribed: bool,
    user_notes_count: i64,
    upvotes: i64,
    downvotes: i64,
    due_date: Option<String>,  // FIXME: Use date type?
    confidential: bool,
    web_url: Option<String>
}

pub type Issues = Vec<Issue>;

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum MergeRequestState {
    #[serde(rename = "merged")]
    Merged,
    #[serde(rename = "opened")]
    Opened,
    #[serde(rename = "closed")]
    Closed,
    #[serde(rename = "all")]
    All,
}

#[derive(Debug, Serialize, Deserialize)]
enum MergeRequestStatus {
    #[serde(rename = "can_be_merged")]
    CanBeMerged,
    #[serde(rename = "cannot_be_merged")]
    CannotBeMerged,
    #[serde(rename = "unchecked")]
    Unchecked,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct MergeRequest {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MergeRequestState,
    created_at: String,  // FIXME: Use chrono crate
    updated_at: String,  // FIXME: Use chrono crate
    target_branch: String,
    source_branch: String,
    upvotes: i64,
    downvotes: i64,
    author: User,
    assignee: Option<User>,
    source_project_id: i64,
    target_project_id: i64,
    labels: Vec<String>,
    work_in_progress: bool,
    milestone: Option<Milestone>,
    merge_when_build_succeeds: bool,
    merge_status: MergeRequestStatus,
    sha: String,
    merge_commit_sha: Option<String>,
    subscribed: bool,
    user_notes_count: i64,
    should_remove_source_branch: Option<bool>,
    force_remove_source_branch: bool,
    web_url: String
}

pub type MergeRequests = Vec<MergeRequest>;
<commit_msg>Add FIXMEs<commit_after>
// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
// https://serde.rs/codegen-hybrid.html

// FIXME: Make sure that all structs above Issue are not using `String`s instead of `Enum`s.
// FIXME: Harmonize the different state enums (e.g. IssueState, MergeRequestState, Authors)
// FIXME: Move all enums here (ListingOrderBy, ListingSort, etc.)
// FIXME: Use a type for sha1
// FIXME: Use chrono crate for dates
// FIXME: Use unsigned integers where it makes sense (id, iid, etc.)
// FIXME: Verify all `match` in push_str() in build_query(): They should contain all members.
// FIXME: Get rid of build_query(), use serde's Serialize instead.

#[derive(Debug, Serialize, Deserialize)]
pub struct Version {
    pub version: String,
    pub revision: String,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Group {
    pub id: i64,
    pub name: String,
    pub path: String,
    pub description: String,
    pub visibility_level: i64,
    pub lfs_enabled: bool,
    pub avatar_url: Option<String>,
    pub web_url: String,
    pub request_access_enabled: bool,
}

pub type Groups = Vec<Group>;

#[derive(Debug, Serialize, Deserialize)]
pub struct ProjectOwner {
    pub name: String,
    pub username: String,
    pub id: i64,
    pub state: String,
    pub avatar_url: String,
    pub web_url: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespaceAvatar {
    url: Option<String>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectNamespace {
    id: i64,
    name: String,
    path: String,
    owner_id: Option<i64>,  // FIXME: Why would a project not have this?
    created_at: String,  // FIXME: Date instead?
    updated_at: String,  // FIXME: Date instead?
    description: String,
    avatar: Option<ProjectNamespaceAvatar>,
    membership_lock: Option<bool>,
    share_with_group_lock: bool,
    visibility_level: i64,
    request_access_enabled: bool,
    ldap_sync_status: Option<String>,
    ldap_sync_error: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_successful_update_at: Option<String>,  // FIXME: Is String the proper type?
    ldap_sync_last_sync_at: Option<String>,  // FIXME: Is String the proper type?
    deleted_at: Option<String>,  // FIXME: Is String the proper type?
    lfs_enabled: Option<String>,  // FIXME: Is String the proper type?
    repository_size_limit: Option<String>  // FIXME: Is String the proper type?
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectForkedFrom {
    id: i64,
    http_url_to_repo: String,
    web_url: String,
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectAccess {
    access_level: i64,
    notification_level: i64,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectPermissions {
    project_access: Option<ProjectAccess>,
    group_access: Option<ProjectAccess>,
}

#[derive(Debug, Serialize, Deserialize)]
struct ProjectSharedWithGroup {
    group_id: i64,
    group_name: String,
    group_access_level: i64,
}

// https://users.rust-lang.org/t/what-am-i-doing-wrong-go-program-is-12x-faster-than-rust/5692/13
// https://doc.rust-lang.org/rustc-serialize/rustc_serialize/json/index.html
#[derive(Debug, Serialize, Deserialize)]
pub struct Project {
    id: i64,
    description: String,
    default_branch: Option<String>,
    tag_list: Vec<String>,
    public: bool,
    archived: bool,
    visibility_level: i64,
    ssh_url_to_repo: String,
    http_url_to_repo: String,
    web_url: String,
    // owner: Option<ProjectOwner>,  // FIXME: Why would a project not have an owner?
    name: String,
    name_with_namespace: String,
    path: String,
    path_with_namespace: String,
    container_registry_enabled: Option<bool>,
    issues_enabled: bool,
    merge_requests_enabled: bool,
    wiki_enabled: bool,
    builds_enabled: bool,
    snippets_enabled: bool,
    created_at: String,  // FIXME: Date instead?
    last_activity_at: String,  // FIXME: Date instead?
    shared_runners_enabled: bool,
    lfs_enabled: bool,
    creator_id: i64,
    namespace: ProjectNamespace,
    forked_from_project: Option<ProjectForkedFrom>,
    avatar_url: Option<String>,
    star_count: i64,
    forks_count: i64,
    open_issues_count: i64,
    runners_token: Option<String>,
    public_builds: bool,
    shared_with_groups: Vec<ProjectSharedWithGroup>,
    only_allow_merge_if_build_succeeds: bool,
    request_access_enabled: bool,
    only_allow_merge_if_all_discussions_are_resolved: Option<bool>,  // FIXME: Is bool the proper type?
    approvals_before_merge: Option<i64>,
    permissions: ProjectPermissions,
}

pub type Projects = Vec<Project>;

#[derive(Debug, Serialize, Deserialize)]
enum IssueState {
    #[serde(rename = "opened")]
    Opened,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
enum UserState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "blocked")]
    Blocked,
}

#[derive(Debug, Serialize, Deserialize)]
enum MilestoneState {
    #[serde(rename = "active")]
    Active,

    #[serde(rename = "closed")]
    Closed,
}

#[derive(Debug, Serialize, Deserialize)]
struct Milestone {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MilestoneState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    due_date: Option<String>  // FIXME: Use date type?
}

#[derive(Debug, Serialize, Deserialize)]
struct User {
    name: String,
    username: String,
    id: i64,
    state: UserState,
    avatar_url: Option<String>,
    web_url: Option<String>
}

#[derive(Debug, Serialize, Deserialize)]
pub struct Issue {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: IssueState,
    created_at: String,  // FIXME: Use date type?
    updated_at: String,  // FIXME: Use date type?
    labels: Vec<String>,
    milestone: Option<Milestone>,
    assignee: Option<User>,
    author: User,
    subscribed: bool,
    user_notes_count: i64,
    upvotes: i64,
    downvotes: i64,
    due_date: Option<String>,  // FIXME: Use date type?
    confidential: bool,
    web_url: Option<String>
}

pub type Issues = Vec<Issue>;

#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
pub enum MergeRequestState {
    #[serde(rename = "merged")]
    Merged,
    #[serde(rename = "opened")]
    Opened,
    #[serde(rename = "closed")]
    Closed,
    #[serde(rename = "all")]
    All,
}

#[derive(Debug, Serialize, Deserialize)]
enum MergeRequestStatus {
    #[serde(rename = "can_be_merged")]
    CanBeMerged,
    #[serde(rename = "cannot_be_merged")]
    CannotBeMerged,
    #[serde(rename = "unchecked")]
    Unchecked,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct MergeRequest {
    id: i64,
    iid: i64,
    project_id: i64,
    title: String,
    description: String,
    state: MergeRequestState,
    created_at: String,  // FIXME: Use chrono crate
    updated_at: String,  // FIXME: Use chrono crate
    target_branch: String,
    source_branch: String,
    upvotes: i64,
    downvotes: i64,
    author: User,
    assignee: Option<User>,
    source_project_id: i64,
    target_project_id: i64,
    labels: Vec<String>,
    work_in_progress: bool,
    milestone: Option<Milestone>,
    merge_when_build_succeeds: bool,
    merge_status: MergeRequestStatus,
    sha: String,
    merge_commit_sha: Option<String>,
    subscribed: bool,
    user_notes_count: i64,
    should_remove_source_branch: Option<bool>,
    force_remove_source_branch: bool,
    web_url: String
}

pub type MergeRequests = Vec<MergeRequest>;
<|endoftext|>


<commit_before>use serde::ser::Serialize;
use serde::ser::Serializer;
use linked_hash_map::LinkedHashMap;

trait EntryType: Serialize {
    fn type_name() -> &'static str;
    fn remote_ip(&self) -> &str;
    fn timestamp(&self) -> f64;
    fn request_method(&self) -> &str;
    fn request_url(&self) -> &str;
    fn request_protocol(&self) -> &str;
    fn response_status(&self) -> Option<u32>;
    fn response_bytes(&self) -> Option<u64>;
}

#[derive(Serialize, Debug)]
struct ClientAccessLogEntry<'a> {
    record_type: &'a str,
    vxid: u32,
    request_type: &'a str,
    remote_address: AddressLogEntry<'a>,
    session_timestamp: f64,
    start_timestamp: f64,
    end_timestamp: f64,
    handing: &'a str,
    request: HttpRequestLogEntry<'a>,
    response: HttpResponseLogEntry<'a>,
    process_duration: Option<f64>,
    fetch_duration: Option<f64>,
    ttfb_duration: f64,
    serve_duration: f64,
    recv_header_bytes: u64,
    recv_body_bytes: u64,
    recv_total_bytes: u64,
    sent_header_bytes: u64,
    sent_body_bytes: u64,
    sent_total_bytes: u64,
    esi_count: usize,
    restart_count: usize,
    restart_log: Option<LogBook<'a>>,
    log: LogBook<'a>,
}

impl<'a> EntryType for ClientAccessLogEntry<'a> {
    fn type_name() -> &'static str {
        "client_access"
    }
    fn remote_ip(&self) -> &str {
        self.remote_address.ip
    }
    fn timestamp(&self) -> f64 {
        self.end_timestamp
    }
    fn request_method(&self) -> &str {
        self.request.method
    }
    fn request_url(&self) -> &str {
        self.request.url
    }
    fn request_protocol(&self) -> &str {
        self.request.protocol
    }
    fn response_status(&self) -> Option<u32> {
        Some(self.response.status)
    }
    fn response_bytes(&self) -> Option<u64> {
        Some(self.sent_body_bytes)
    }
}

#[derive(Serialize, Debug)]
struct BackendAccessLogEntry<'a> {
    record_type: &'a str,
    vxid: u32,
    remote_address: AddressLogEntry<'a>,
    session_timestamp: f64,
    start_timestamp: f64,
    end_timestamp: f64,
    handing: &'a str,
    request: HttpRequestLogEntry<'a>,
    response: Option<HttpResponseLogEntry<'a>>,
    send_duration: f64,
    wait_duration: Option<f64>,
    ttfb_duration: Option<f64>,
    fetch_duration: Option<f64>,
    sent_header_bytes: Option<u64>,
    sent_body_bytes: Option<u64>,
    sent_total_bytes: Option<u64>,
    recv_header_bytes: Option<u64>,
    recv_body_bytes: Option<u64>,
    recv_total_bytes: Option<u64>,
    retry: usize,
    backend_connection: Option<BackendConnectionLogEntry<'a>>,
    cache_object: Option<CacheObjectLogEntry<'a>>,
    log: LogBook<'a>,
}

impl<'a> EntryType for BackendAccessLogEntry<'a> {
    fn type_name() -> &'static str {
        "backend_access"
    }
    fn remote_ip(&self) -> &str {
        self.remote_address.ip
    }
    fn timestamp(&self) -> f64 {
        self.end_timestamp
    }
    fn request_method(&self) -> &str {
        self.request.method
    }
    fn request_url(&self) -> &str {
        self.request.url
    }
    fn request_protocol(&self) -> &str {
        self.request.protocol
    }
    fn response_status(&self) -> Option<u32> {
        self.response.as_ref().map(|r| r.status).or(Some(503)) // no response
    }
    fn response_bytes(&self) -> Option<u64> {
        self.recv_body_bytes
    }
}

#[derive(Serialize, Debug)]
struct PipeSessionLogEntry<'a> {
    record_type: &'a str,
    vxid: u32,
    remote_address: AddressLogEntry<'a>,
    session_timestamp: f64,
    start_timestamp: f64,
    end_timestamp: f64,
    backend_connection: BackendConnectionLogEntry<'a>,
    request: HttpRequestLogEntry<'a>,
    backend_request: HttpRequestLogEntry<'a>,
    process_duration: Option<f64>,
    ttfb_duration: f64,
    recv_total_bytes: u64,
    sent_total_bytes: u64,
    log: LogBook<'a>,
}

impl<'a> EntryType for PipeSessionLogEntry<'a> {
    fn type_name() -> &'static str {
        "pipe_session"
    }
    fn remote_ip(&self) -> &str {
        self.remote_address.ip
    }
    fn timestamp(&self) -> f64 {
        self.end_timestamp
    }
    fn request_method(&self) -> &str {
        self.request.method
    }
    fn request_url(&self) -> &str {
        self.request.url
    }
    fn request_protocol(&self) -> &str {
        self.request.protocol
    }
    fn response_status(&self) -> Option<u32> {
        None
    }
    fn response_bytes(&self) -> Option<u64> {
        Some(self.sent_total_bytes)
    }
}

#[derive(Serialize, Debug)]
struct AddressLogEntry<'a> {
    ip: &'a str,
    port: u16,
}

#[derive(Debug)]
struct HeadersLogEntry<'a> {
    headers: &'a LinkedHashMap<String, Vec<String>>,
}

impl<'a> Serialize for HeadersLogEntry<'a> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let mut state = try!(serializer.serialize_seq(Some(self.headers.len())));
        for (ref name, ref values) in self.headers {
            try!(serializer.serialize_seq_elt(&mut state, (name, values)));
        }
        try!(serializer.serialize_seq_end(state));
        Ok(())
    }
}

#[derive(Serialize, Debug)]
struct HttpRequestLogEntry<'a> {
    protocol: &'a str,
    method: &'a str,
    url: &'a str,
    headers: HeadersLogEntry<'a>,
}

#[derive(Serialize, Debug)]
struct HttpResponseLogEntry<'a> {
    status: u32,
    reason: &'a str,
    protocol: &'a str,
    headers: HeadersLogEntry<'a>,
}

#[derive(Debug)]
struct LogBook<'a> {
    entries: &'a [LogEntry],
}

#[derive(Serialize, Debug)]
struct LogBookEntry<'a> {
    entry_type: &'a str,
    message: &'a str,
    #[serde(skip_serializing_if="Option::is_none")]
    detail: Option<&'a str>,
}

impl<'a> Serialize for LogBook<'a> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let mut state = try!(serializer.serialize_seq(Some(self.entries.len())));
        for log_entry in self.entries {
            let (entry_type, message, detail) = match log_entry {
                &LogEntry::Vcl(ref msg) => ("VCL", msg.as_str(), None),
                &LogEntry::Debug(ref msg) => ("Debug", msg.as_str(), None),
                &LogEntry::Error(ref msg) => ("Error", msg.as_str(), None),
                &LogEntry::FetchError(ref msg) => ("Fetch Error", msg.as_str(), None),
                &LogEntry::Warning(ref msg) => ("Warning", msg.as_str(), None),
                &LogEntry::Acl(ref result, ref name, ref addr) => match result.as_str() {
                    "MATCH" => ("ACL Match", name.as_str(), addr.as_ref().map(String::as_str)),
                    "NO_MATCH" => ("ACL No Match", name.as_str(), addr.as_ref().map(String::as_str)),
                    _ => ("ACL Other", result.as_str(), Some(name.as_str())),
                },
            };

            try!(serializer.serialize_seq_elt(&mut state, &LogBookEntry {
                entry_type: entry_type,
                message: message,
                detail: detail,
            }));
        }
        try!(serializer.serialize_seq_end(state));
        Ok(())
    }
}

#[derive(Serialize, Debug)]
struct CacheObjectLogEntry<'a> {
    storage_type: &'a str,
    storage_name: &'a str,
    ttl_duration: Option<f64>,
    grace_duration: Option<f64>,
    keep_duration: Option<f64>,
    since_timestamp: f64,
    origin_timestamp: f64,
    fetch_mode: &'a str,
    fetch_streamed: bool,
    response: HttpResponseLogEntry<'a>,
}

#[derive(Serialize, Debug)]
struct BackendConnectionLogEntry<'a> {
    fd: isize,
    name: &'a str,
    remote_address: AddressLogEntry<'a>,
    local_address: AddressLogEntry<'a>,
}
<commit_msg>Revert "serialize headers as Vec<(String, Vec<String>)> since names are not normalized"<commit_after>use serde::ser::Serialize;
use serde::ser::Serializer;
use linked_hash_map::LinkedHashMap;

trait EntryType: Serialize {
    fn type_name() -> &'static str;
    fn remote_ip(&self) -> &str;
    fn timestamp(&self) -> f64;
    fn request_method(&self) -> &str;
    fn request_url(&self) -> &str;
    fn request_protocol(&self) -> &str;
    fn response_status(&self) -> Option<u32>;
    fn response_bytes(&self) -> Option<u64>;
}

#[derive(Serialize, Debug)]
struct ClientAccessLogEntry<'a> {
    record_type: &'a str,
    vxid: u32,
    request_type: &'a str,
    remote_address: AddressLogEntry<'a>,
    session_timestamp: f64,
    start_timestamp: f64,
    end_timestamp: f64,
    handing: &'a str,
    request: HttpRequestLogEntry<'a>,
    response: HttpResponseLogEntry<'a>,
    process_duration: Option<f64>,
    fetch_duration: Option<f64>,
    ttfb_duration: f64,
    serve_duration: f64,
    recv_header_bytes: u64,
    recv_body_bytes: u64,
    recv_total_bytes: u64,
    sent_header_bytes: u64,
    sent_body_bytes: u64,
    sent_total_bytes: u64,
    esi_count: usize,
    restart_count: usize,
    restart_log: Option<LogBook<'a>>,
    log: LogBook<'a>,
}

impl<'a> EntryType for ClientAccessLogEntry<'a> {
    fn type_name() -> &'static str {
        "client_access"
    }
    fn remote_ip(&self) -> &str {
        self.remote_address.ip
    }
    fn timestamp(&self) -> f64 {
        self.end_timestamp
    }
    fn request_method(&self) -> &str {
        self.request.method
    }
    fn request_url(&self) -> &str {
        self.request.url
    }
    fn request_protocol(&self) -> &str {
        self.request.protocol
    }
    fn response_status(&self) -> Option<u32> {
        Some(self.response.status)
    }
    fn response_bytes(&self) -> Option<u64> {
        Some(self.sent_total_bytes)
    }
}

#[derive(Serialize, Debug)]
struct BackendAccessLogEntry<'a> {
    record_type: &'a str,
    vxid: u32,
    remote_address: AddressLogEntry<'a>,
    session_timestamp: f64,
    start_timestamp: f64,
    end_timestamp: f64,
    handing: &'a str,
    request: HttpRequestLogEntry<'a>,
    response: Option<HttpResponseLogEntry<'a>>,
    send_duration: f64,
    wait_duration: Option<f64>,
    ttfb_duration: Option<f64>,
    fetch_duration: Option<f64>,
    sent_header_bytes: Option<u64>,
    sent_body_bytes: Option<u64>,
    sent_total_bytes: Option<u64>,
    recv_header_bytes: Option<u64>,
    recv_body_bytes: Option<u64>,
    recv_total_bytes: Option<u64>,
    retry: usize,
    backend_connection: Option<BackendConnectionLogEntry<'a>>,
    cache_object: Option<CacheObjectLogEntry<'a>>,
    log: LogBook<'a>,
}

impl<'a> EntryType for BackendAccessLogEntry<'a> {
    fn type_name() -> &'static str {
        "backend_access"
    }
    fn remote_ip(&self) -> &str {
        self.remote_address.ip
    }
    fn timestamp(&self) -> f64 {
        self.end_timestamp
    }
    fn request_method(&self) -> &str {
        self.request.method
    }
    fn request_url(&self) -> &str {
        self.request.url
    }
    fn request_protocol(&self) -> &str {
        self.request.protocol
    }
    fn response_status(&self) -> Option<u32> {
        self.response.as_ref().map(|r| r.status).or(Some(503)) // no response
    }
    fn response_bytes(&self) -> Option<u64> {
        self.recv_total_bytes
    }
}

#[derive(Serialize, Debug)]
struct PipeSessionLogEntry<'a> {
    record_type: &'a str,
    vxid: u32,
    remote_address: AddressLogEntry<'a>,
    session_timestamp: f64,
    start_timestamp: f64,
    end_timestamp: f64,
    backend_connection: BackendConnectionLogEntry<'a>,
    request: HttpRequestLogEntry<'a>,
    backend_request: HttpRequestLogEntry<'a>,
    process_duration: Option<f64>,
    ttfb_duration: f64,
    recv_total_bytes: u64,
    sent_total_bytes: u64,
    log: LogBook<'a>,
}

impl<'a> EntryType for PipeSessionLogEntry<'a> {
    fn type_name() -> &'static str {
        "pipe_session"
    }
    fn remote_ip(&self) -> &str {
        self.remote_address.ip
    }
    fn timestamp(&self) -> f64 {
        self.end_timestamp
    }
    fn request_method(&self) -> &str {
        self.request.method
    }
    fn request_url(&self) -> &str {
        self.request.url
    }
    fn request_protocol(&self) -> &str {
        self.request.protocol
    }
    fn response_status(&self) -> Option<u32> {
        None
    }
    fn response_bytes(&self) -> Option<u64> {
        Some(self.sent_total_bytes)
    }
}

#[derive(Serialize, Debug)]
struct AddressLogEntry<'a> {
    ip: &'a str,
    port: u16,
}

#[derive(Debug)]
struct HeadersLogEntry<'a> {
    headers: &'a LinkedHashMap<String, Vec<String>>,
}

impl<'a> Serialize for HeadersLogEntry<'a> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let mut state = try!(serializer.serialize_map(Some(self.headers.len())));
        for (ref name, ref values) in self.headers {
            try!(serializer.serialize_map_key(&mut state, name));
            try!(serializer.serialize_map_value(&mut state, values));
        }
        try!(serializer.serialize_map_end(state));
        Ok(())
    }
}

#[derive(Serialize, Debug)]
struct HttpRequestLogEntry<'a> {
    protocol: &'a str,
    method: &'a str,
    url: &'a str,
    headers: HeadersLogEntry<'a>,
}

#[derive(Serialize, Debug)]
struct HttpResponseLogEntry<'a> {
    status: u32,
    reason: &'a str,
    protocol: &'a str,
    headers: HeadersLogEntry<'a>,
}

#[derive(Debug)]
struct LogBook<'a> {
    entries: &'a [LogEntry],
}

#[derive(Serialize, Debug)]
struct LogBookEntry<'a> {
    entry_type: &'a str,
    message: &'a str,
    #[serde(skip_serializing_if="Option::is_none")]
    detail: Option<&'a str>,
}

impl<'a> Serialize for LogBook<'a> {
    fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer {
        let mut state = try!(serializer.serialize_seq(Some(self.entries.len())));
        for log_entry in self.entries {
            let (entry_type, message, detail) = match log_entry {
                &LogEntry::Vcl(ref msg) => ("VCL", msg.as_str(), None),
                &LogEntry::Debug(ref msg) => ("Debug", msg.as_str(), None),
                &LogEntry::Error(ref msg) => ("Error", msg.as_str(), None),
                &LogEntry::FetchError(ref msg) => ("Fetch Error", msg.as_str(), None),
                &LogEntry::Warning(ref msg) => ("Warning", msg.as_str(), None),
                &LogEntry::Acl(ref result, ref name, ref addr) => match result.as_str() {
                    "MATCH" => ("ACL Match", name.as_str(), addr.as_ref().map(String::as_str)),
                    "NO_MATCH" => ("ACL No Match", name.as_str(), addr.as_ref().map(String::as_str)),
                    _ => ("ACL Other", result.as_str(), Some(name.as_str())),
                },
            };

            try!(serializer.serialize_seq_elt(&mut state, &LogBookEntry {
                entry_type: entry_type,
                message: message,
                detail: detail,
            }));
        }
        try!(serializer.serialize_seq_end(state));
        Ok(())
    }
}

#[derive(Serialize, Debug)]
struct CacheObjectLogEntry<'a> {
    storage_type: &'a str,
    storage_name: &'a str,
    ttl_duration: Option<f64>,
    grace_duration: Option<f64>,
    keep_duration: Option<f64>,
    since_timestamp: f64,
    origin_timestamp: f64,
    fetch_mode: &'a str,
    fetch_streamed: bool,
    response: HttpResponseLogEntry<'a>,
}

#[derive(Serialize, Debug)]
struct BackendConnectionLogEntry<'a> {
    fd: isize,
    name: &'a str,
    remote_address: AddressLogEntry<'a>,
    local_address: AddressLogEntry<'a>,
}
<|endoftext|>


<commit_before>extern crate tui;
extern crate termion;

use std::io;

use termion::event;
use termion::input::TermRead;

use tui::Terminal;
use tui::backend::MouseBackend;
use tui::widgets::{Widget, Block, border, Table};
use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color, Modifier};

struct App<'a> {
    size: Rect,
    items: Vec<Vec<&'a str>>,
    selected: usize,
}

impl<'a> App<'a> {
    fn new() -> App<'a> {
        App {
            size: Rect::default(),
            items: vec![vec!["Row12", "Row12", "Row13"],
                        vec!["Row21", "Row22", "Row23"],
                        vec!["Row31", "Row32", "Row33"],
                        vec!["Row41", "Row42", "Row43"],
                        vec!["Row41", "Row42", "Row43"],
                        vec!["Row41", "Row42", "Row43"]],
            selected: 0,
        }
    }
}

fn main() {
    // Terminal initialization
    let backend = MouseBackend::new().unwrap();
    let mut terminal = Terminal::new(backend).unwrap();

    // App
    let mut app = App::new();

    // First draw call
    terminal.clear().unwrap();
    terminal.hide_cursor().unwrap();
    app.size = terminal.size().unwrap();
    draw(&mut terminal, &app);

    // Input
    let stdin = io::stdin();
    for c in stdin.keys() {
        let size = terminal.size().unwrap();
        if size != app.size {
            terminal.resize(size).unwrap();
            app.size = size;
        }

        let evt = c.unwrap();
        match evt {
            event::Key::Char('q') => {
                break;
            }
            event::Key::Down => {
                app.selected += 1;
                if app.selected > app.items.len() - 1 {
                    app.selected = 0;
                }
            }
            event::Key::Up => {
                if app.selected > 0 {
                    app.selected -= 1;
                } else {
                    app.selected = app.items.len() - 1;
                }
            }
            _ => {}
        };
        draw(&mut terminal, &app);
    }

    terminal.show_cursor().unwrap();
}

fn draw(t: &mut Terminal<MouseBackend>, app: &App) {

    Group::default()
        .direction(Direction::Horizontal)
        .sizes(&[Size::Percent(100)])
        .margin(5)
        .render(t, &app.size, |t, chunks| {
            let selected_style = Style::default().fg(Color::Yellow).modifier(Modifier::Bold);
            let normal_style = Style::default().fg(Color::White);
            Table::default()
                .block(Block::default().borders(border::ALL).title("Table"))
                .header(&["Header1", "Header2", "Header3"])
                .widths(&[10, 10, 10])
                .rows(&app.items
                           .iter()
                           .enumerate()
                           .map(|(i, item)| {
                                    (item,
                                     if i == app.selected {
                                         &selected_style
                                     } else {
                                         &normal_style
                                     })
                                })
                           .collect::<Vec<(&Vec<&str>, &Style)>>())
                .render(t, &chunks[0]);
        });

    t.draw().unwrap();
}
<commit_msg>[examples] Fix Table example<commit_after>extern crate tui;
extern crate termion;

use std::io;

use termion::event;
use termion::input::TermRead;

use tui::Terminal;
use tui::backend::MouseBackend;
use tui::widgets::{Widget, Block, border, Table, Row};
use tui::layout::{Group, Direction, Size, Rect};
use tui::style::{Style, Color, Modifier};

struct App<'a> {
    size: Rect,
    items: Vec<Vec<&'a str>>,
    selected: usize,
}

impl<'a> App<'a> {
    fn new() -> App<'a> {
        App {
            size: Rect::default(),
            items: vec![
                vec!["Row12", "Row12", "Row13"],
                vec!["Row21", "Row22", "Row23"],
                vec!["Row31", "Row32", "Row33"],
                vec!["Row41", "Row42", "Row43"],
                vec!["Row51", "Row52", "Row53"],
                vec!["Row61", "Row62", "Row63"],
            ],
            selected: 0,
        }
    }
}

fn main() {
    // Terminal initialization
    let backend = MouseBackend::new().unwrap();
    let mut terminal = Terminal::new(backend).unwrap();

    // App
    let mut app = App::new();

    // First draw call
    terminal.clear().unwrap();
    terminal.hide_cursor().unwrap();
    app.size = terminal.size().unwrap();
    draw(&mut terminal, &app);

    // Input
    let stdin = io::stdin();
    for c in stdin.keys() {
        let size = terminal.size().unwrap();
        if size != app.size {
            terminal.resize(size).unwrap();
            app.size = size;
        }

        let evt = c.unwrap();
        match evt {
            event::Key::Char('q') => {
                break;
            }
            event::Key::Down => {
                app.selected += 1;
                if app.selected > app.items.len() - 1 {
                    app.selected = 0;
                }
            }
            event::Key::Up => {
                if app.selected > 0 {
                    app.selected -= 1;
                } else {
                    app.selected = app.items.len() - 1;
                }
            }
            _ => {}
        };
        draw(&mut terminal, &app);
    }

    terminal.show_cursor().unwrap();
    terminal.clear().unwrap();
}

fn draw(t: &mut Terminal<MouseBackend>, app: &App) {

    Group::default()
        .direction(Direction::Horizontal)
        .sizes(&[Size::Percent(100)])
        .margin(5)
        .render(t, &app.size, |t, chunks| {
            let selected_style = Style::default().fg(Color::Yellow).modifier(Modifier::Bold);
            let normal_style = Style::default().fg(Color::White);
            Table::new(
                ["Header1", "Header2", "Header3"].into_iter(),
                app.items.iter().enumerate().map(|(i, item)| if i ==
                    app.selected
                {
                    Row::StyledData(item.into_iter(), &selected_style)
                } else {
                    Row::StyledData(item.into_iter(), &normal_style)
                }),
            ).block(Block::default().borders(border::ALL).title("Table"))
                .widths(&[10, 10, 10])
                .render(t, &chunks[0]);
        });

    t.draw().unwrap();
}
<|endoftext|>


<commit_before>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

extern crate twitter_api as twitter;
extern crate rustc_serialize as rustc_serialize;
extern crate oauth_client as oauth;

use std::io;
use std::io::prelude::*;
use std::env;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::path::PathBuf;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const PATH: &'static str = "./tweet.conf";

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read() -> Option<Config> {
        let path = Path::new(PATH);
        let mut file = match File::open(&path) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self) {
        let path = Path::new(PATH);
        let mut file = match OpenOptions::new().write(true).open(&path) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = write!(&mut file, "{}\n", &json::encode(self).unwrap());
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let mut line = String::new();
    let _ = io::stdin().read_line(&mut line).unwrap();
    line.trim().to_string()
}

fn main() {
    let conf = match Config::read() {
        Some(c) => c,
        None => {
            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, &pin);

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };
            c.write();
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::tweet(&consumer, &access, &status);
}

<commit_msg>examples/tweet.rs : rename PATH -> TWITTER_CONF_FILENAME<commit_after>#![warn(bad_style,
        unused, unused_extern_crates, unused_import_braces,
        unused_qualifications, unused_results)]

extern crate twitter_api as twitter;
extern crate rustc_serialize as rustc_serialize;
extern crate oauth_client as oauth;

use std::io;
use std::io::prelude::*;
use std::env;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::path::PathBuf;
use rustc_serialize::Decodable;
use rustc_serialize::json::{self, Json};
use oauth::Token;

const TWITTER_CONF_FILENAME: &'static str = ".twitter.conf";

#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct Config {
    pub consumer_key: String,
    pub consumer_secret: String,
    pub access_key: String,
    pub access_secret: String
}

impl Config {
    pub fn read() -> Option<Config> {
        let path = Path::new(PATH);
        let mut file = match File::open(&path) {
            Ok(f) => f,
            Err(_) => return None
        };
        let conf = Json::from_reader(&mut file).unwrap();
        Decodable::decode(&mut json::Decoder::new(conf)).ok()
    }

    pub fn write(&self) {
        let path = Path::new(PATH);
        let mut file = match OpenOptions::new().write(true).open(&path) {
            Ok(f) => f,
            Err(e) => panic!("{}", e)
        };
        let _ = write!(&mut file, "{}\n", &json::encode(self).unwrap());
    }
}

fn console_input(prompt: &str) -> String {
    print!("{}\n\t", prompt);
    let mut line = String::new();
    let _ = io::stdin().read_line(&mut line).unwrap();
    line.trim().to_string()
}

fn main() {
    let conf = match Config::read() {
        Some(c) => c,
        None => {
            let consumer_key    = console_input("input your consumer key:");
            let consumer_secret = console_input("input your consumer secret:");
            let consumer = Token::new(consumer_key, consumer_secret);

            let request = twitter::get_request_token(&consumer);
            println!("open the following url:");
            println!("\t{}", twitter::get_authorize_url(&request));
            let pin = console_input("input pin:");
            let access = twitter::get_access_token(&consumer, &request, &pin);

            let c = Config {
                consumer_key: consumer.key.to_string(),
                consumer_secret: consumer.secret.to_string(),
                access_key: access.key.to_string(),
                access_secret: access.secret.to_string()
            };
            c.write();
            c
        }
    };

    let consumer = Token::new(conf.consumer_key, conf.consumer_secret);
    let access = Token::new(conf.access_key, conf.access_secret);

    let status = console_input("What's happening?");
    twitter::tweet(&consumer, &access, &status);
}

<|endoftext|>


<commit_before>extern crate antidote;
#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate tokio_core;
extern crate telegram_bot_raw;

#[cfg(feature = "curl_connector")]
extern crate curl;
#[cfg(feature = "curl_connector")]
extern crate tokio_curl;

#[cfg(feature = "hyper_connector")]
extern crate hyper;
#[cfg(feature = "hyper_connector")]
extern crate hyper_tls;

mod api;
mod errors;
mod future;
mod macros;
mod stream;

pub mod connector;
pub mod prelude;
pub mod types;

pub use self::api::{Api, Config};
pub use connector::*;
pub use self::errors::{Error, ErrorKind};
pub use self::future::TelegramFuture;
pub use stream::UpdatesStream;
pub use prelude::*;
pub use types::*;
<commit_msg>docs: add link to the repository<commit_after>//! This crate helps writing bots for the messenger Telegram.
//! See [readme](https://github.com/telegram-rs/telegram-bot) for details.

extern crate antidote;
#[macro_use]
extern crate error_chain;
extern crate futures;
extern crate tokio_core;
extern crate telegram_bot_raw;

#[cfg(feature = "curl_connector")]
extern crate curl;
#[cfg(feature = "curl_connector")]
extern crate tokio_curl;

#[cfg(feature = "hyper_connector")]
extern crate hyper;
#[cfg(feature = "hyper_connector")]
extern crate hyper_tls;

mod api;
mod errors;
mod future;
mod macros;
mod stream;

pub mod connector;
pub mod prelude;
pub mod types;

pub use self::api::{Api, Config};
pub use connector::*;
pub use self::errors::{Error, ErrorKind};
pub use self::future::TelegramFuture;
pub use stream::UpdatesStream;
pub use prelude::*;
pub use types::*;
<|endoftext|>