<commit_before>use orbclient::Renderer;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
use orbimage;
use orbclient;

use cell::{CheckSet, CloneCell};
use widgets::{Image, Widget};
use draw::draw_box;
use event::Event;
use rect::Rect;
use point::Point;
use theme::{Selector, Theme};
use traits::{Place, Style, Text};

static TOGGLE_ICON: &'static [u8; 703] = include_bytes!("../../res/icon-down-black.png");
static TOGGLE_ICON_ACTIVE: &'static [u8; 706] = include_bytes!("../../res/icon-down-white.png");

struct Entry {
    pub rect: Cell<Rect>,
    pub selector: CloneCell<Selector>,
    pub text: CloneCell<String>,
    pub text_offset: Cell<Point>,
    hover: Cell<bool>,
    pressed: Cell<bool>,
    index: u32,
    active: Cell<bool>,
}

impl Entry {
    fn new(text: &str, index: u32) -> Arc<Self> {
        Arc::new(Entry {
            rect: Cell::new(Rect::default()),
            selector: CloneCell::new(Selector::new(Some("combo-box-entry"))),
            text: CloneCell::new(String::from(text)),
            text_offset: Cell::new(Point::default()),
            hover: Cell::new(false),
            pressed: Cell::new(false),
            index,
            active: Cell::new(false),
        })
    }
}

impl Text for Entry {
    fn text<S: Into<String>>(&self, text: S) -> &Self {
        self.text.set(text.into());
        self
    }

    fn text_offset(&self, x: i32, y: i32) -> &Self {
        self.text_offset.set(Point::new(x, y));
        self
    }
}

impl Style for Entry {
    fn selector(&self) -> &CloneCell<Selector> {
        &self.selector
    }
}

impl Widget for Entry {
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }
    fn draw(&self, renderer: &mut Renderer, _focused: bool, theme: &Theme) {
        let rect = self.rect.get();
        let offset = self.text_offset.get();
        let mut selector = self.selector.get();

        if self.hover.get() || self.active.get() {
            if self.active.get() {
                selector = selector.with_pseudo_class("active");
            } else {
                selector = selector.with_pseudo_class("hover");
            }

            draw_box(
                renderer,
                Rect::new(rect.x, rect.y, rect.width, rect.height),
                theme,
                &selector,
            );
        }

        let mut point = Point::new(rect.x + offset.x, rect.y + rect.height as i32 / 2 - 8);
        for c in self.text.get().chars() {
            if point.x + 8 <= rect.width as i32 - 2 * offset.x {
                renderer.char(point.x, point.y, c, theme.color("color", &selector));
            }
            point.x += 8;
        }
    }
    fn event(&self, event: Event, _focused: bool, redraw: &mut bool) -> bool {
        match event {
            Event::Mouse {
                point, left_button, ..
            } => {
                let mut click = false;

                let rect = self.rect.get();
                if rect.contains(point) {
                    if self.hover.check_set(true) {
                        *redraw = true;
                    }

                    if left_button {
                        if self.pressed.check_set(true) {
                            *redraw = true;
                        }
                    } else {
                        if self.pressed.check_set(false) {
                            click = true;
                            *redraw = true;
                        }
                    }
                } else {
                    if self.hover.check_set(false) {
                        *redraw = true;
                    }

                    if !left_button {
                        if self.pressed.check_set(false) {
                            *redraw = true;
                        }
                    }
                }

                if click {
                    return true;
                }
            }
            _ => (),
        }

        _focused
    }

    fn name(&self) -> &str {
        "ComboBoxEntry"
    }
}

pub struct ComboBox {
    pub rect: Cell<Rect>,
    pub selector: CloneCell<Selector>,
    pressed: Cell<bool>,
    activated: Cell<bool>,
    pub offset: Cell<Point>,
    selected: Cell<Option<u32>>,
    entries: RefCell<Vec<Arc<Entry>>>,
    text: CloneCell<String>,
    flyout_height: Cell<u32>,
    toggle_icon: RefCell<Option<Arc<Image>>>,
    toggle_icon_active: RefCell<Option<Arc<Image>>>,
}

impl ComboBox {
    pub fn new() -> Arc<ComboBox> {
        let toggle_icon = RefCell::new(None);
        if let Ok(icon) = orbimage::parse_png(TOGGLE_ICON) {
            *toggle_icon.borrow_mut() = Some(Image::from_image(icon))
        };

        let toggle_icon_active = RefCell::new(None);
        if let Ok(icon) = orbimage::parse_png(TOGGLE_ICON_ACTIVE) {
            *toggle_icon_active.borrow_mut() = Some(Image::from_image(icon))
        };

        Arc::new(ComboBox {
            rect: Cell::new(Rect::new(0, 0, 332, 28)),
            selector: CloneCell::new(Selector::new(Some("combo-box"))),
            pressed: Cell::new(false),
            activated: Cell::new(false),
            offset: Cell::new(Point::new(4, 4)),
            selected: Cell::new(None),
            entries: RefCell::new(vec![]),
            text: CloneCell::new(String::new()),
            flyout_height: Cell::new(0),
            toggle_icon,
            toggle_icon_active,
        })
    }

    pub fn selected(&self) -> i32 {
        if let Some(selected) = self.selected.get() {
            return selected as i32;
        };

        -1
    }

    pub fn push(&self, text: &str) {
        let rect = self.rect().get();
        let entry = Entry::new(text, self.entries.borrow().len() as u32);
        entry.rect.set(Rect::new(
            rect.x + 1,
            rect.y + rect.height as i32 * (self.entries.borrow().len() as i32 + 1),
            rect.width - 2,
            rect.height,
        ));
        entry.text_offset(self.offset.get().x, self.offset.get().y);
        self.flyout_height
            .set(self.flyout_height.get() + rect.height);

        self.entries.borrow_mut().push(entry);

        if self.entries.borrow().len() == 1 {
            self.change_selection(0);
        }
    }

    pub fn pop(&self) -> String {
        if let Some(entry) = self.entries.borrow_mut().pop() {
            self.change_selection(0);
            return entry.text.get();
        }

        String::new()
    }

    pub fn change_selection(&self, i: u32) {
        if let Some(index) = self.selected.get() {
            if let Some(entry) = self.entries.borrow().get(index as usize) {
                entry.active.set(false)
            }
        }

        self.selected.set(Some(i));

        if let Some(index) = self.selected.get() {
            if let Some(entry) = self.entries.borrow().get(index as usize) {
                entry.active.set(true);
                self.text.set(entry.text.get());
            }
        }
    }

    pub fn text_offset(&self, x: i32, y: i32) -> &Self {
        self.offset.set(Point::new(x, y));
        self
    }
}

impl Style for ComboBox {
    fn selector(&self) -> &CloneCell<Selector> {
        &self.selector
    }
}

impl Widget for ComboBox {
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }

    fn draw(&self, renderer: &mut Renderer, _focused: bool, theme: &Theme) {
        let rect = self.rect.get();
        let activated = self.activated.get();
        let offset = self.offset.get();

        // draw flyout
        if activated {
            //TODO: set this selector as the child of self.selector
            let selector = Selector::new(Some("combo-box-flyout"));

            let flyout_rect = Rect::new(
                rect.x,
                rect.y + rect.height as i32 - 2,
                rect.width,
                self.flyout_height.get() + 2,
            );
            draw_box(renderer, flyout_rect, theme, &selector);

            // draw entries
            for entry in self.entries.borrow().iter() {
                let mut point = Point::new(entry.rect.get().x, entry.rect.get().y);

                if point.y >= rect.y
                    && point.y + rect.height as i32 <= flyout_rect.y + flyout_rect.height as i32
                {
                    entry.draw(renderer, _focused, theme);
                }
            }
        }

        // draw the combobox
        let mut selector = self.selector.get();

        if activated {
            selector = selector.with_pseudo_class("active");
        }

        draw_box(renderer, rect, theme, &selector);

        // draw toggle indicator
        //TODO: set this selector as the child of self.selector
        selector = Selector::new(Some("combo-box-toggle"));

        if activated {
            selector = selector.with_pseudo_class("active");
        }

        let toggle_size = rect.height - 2 * offset.y as u32;

        let toggle_rect = Rect::new(
            rect.x + rect.width as i32 - toggle_size as i32 - offset.y,
            rect.y + offset.y,
            toggle_size,
            toggle_size,
        );

        draw_box(renderer, toggle_rect, theme, &selector);

        // draw the toggle icon
        if activated {
            if let Some(ref icon) = *self.toggle_icon_active.borrow() {
                icon.position(toggle_rect.x, toggle_rect.y);
                icon.draw(renderer, _focused, theme)
            }
        } else {
            if let Some(ref icon) = *self.toggle_icon.borrow() {
                icon.position(toggle_rect.x, toggle_rect.y);
                icon.draw(renderer, _focused, theme)
            }
        }

        // draw selected text
        let mut point = Point::new(rect.x + offset.x - 8, rect.y + rect.height as i32 / 2 - 8);
        for c in self.text.get().chars() {
            if point.x + 8 <= rect.width as i32 - toggle_rect.width as i32 - 2 * offset.x {
                renderer.char(
                    point.x + rect.x,
                    point.y,
                    c,
                    theme.color("color", &"label".into()),
                );
            }
            point.x += 8;
        }
    }

    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
        match event {
            Event::Mouse {
                point, left_button, ..
            } => {
                let mut ignore_event = false;
                if self.activated.get() {
                    for entry in self.entries.borrow().iter() {
                        if entry.event(event, focused, redraw) {
                            ignore_event = true;

                            self.change_selection(entry.index);
                            if self.activated.check_set(false) {
                                *redraw = true;
                            }
                        }
                    }
                }

                let rect = self.rect.get();
                if rect.contains(point) {
                    if left_button {
                        self.pressed.set(!self.pressed.get());

                        if self.activated.check_set(true) {
                            *redraw = true;
                        }
                    } else {
                        if !self.pressed.get() {
                            if self.activated.check_set(false) {
                                *redraw = true;
                            }
                        }
                    }
                } else {
                    if !ignore_event {
                        if left_button {
                            self.pressed.set(false);
                        } else {
                            if !self.pressed.get() {
                                if self.activated.check_set(false) {
                                    *redraw = true;
                                }
                            }
                        }
                    }
                }
            }
            Event::KeyPressed(key_event) => match key_event.scancode {
                orbclient::K_UP => match self.selected.get() {
                    None => {
                        self.change_selection(0);
                        *redraw = true;
                    }
                    Some(i) => if i > 0 {
                        self.change_selection(i - 1);
                        *redraw = true;
                    },
                },
                orbclient::K_DOWN => match self.selected.get() {
                    None => {
                        self.change_selection(0);
                        *redraw = true;
                    }
                    Some(i) => if i < self.entries.borrow().len() as u32 - 1 {
                        self.change_selection(i + 1);
                        *redraw = true;
                    },
                },
                orbclient::K_ENTER => if self.activated.check_set(false) {
                    self.pressed.set(false);
                    *redraw = true;
                },
                _ => {}
            },

            _ => {}
        }

        focused
    }

    fn name(&self) -> &str {
        "ComboBox"
    }
}

impl Place for ComboBox {}
<commit_msg>Fix bug when x > 200 the entries of Combobox are not drawn.<commit_after>use orbclient::Renderer;
use std::cell::{Cell, RefCell};
use std::sync::Arc;
use orbimage;
use orbclient;

use cell::{CheckSet, CloneCell};
use widgets::{Image, Widget};
use draw::draw_box;
use event::Event;
use rect::Rect;
use point::Point;
use theme::{Selector, Theme};
use traits::{Place, Style, Text};

static TOGGLE_ICON: &'static [u8; 703] = include_bytes!("../../res/icon-down-black.png");
static TOGGLE_ICON_ACTIVE: &'static [u8; 706] = include_bytes!("../../res/icon-down-white.png");

struct Entry {
    pub rect: Cell<Rect>,
    pub selector: CloneCell<Selector>,
    pub text: CloneCell<String>,
    pub text_offset: Cell<Point>,
    hover: Cell<bool>,
    pressed: Cell<bool>,
    index: u32,
    active: Cell<bool>,
}

impl Entry {
    fn new(text: &str, index: u32) -> Arc<Self> {
        Arc::new(Entry {
            rect: Cell::new(Rect::default()),
            selector: CloneCell::new(Selector::new(Some("combo-box-entry"))),
            text: CloneCell::new(String::from(text)),
            text_offset: Cell::new(Point::default()),
            hover: Cell::new(false),
            pressed: Cell::new(false),
            index,
            active: Cell::new(false),
        })
    }
}

impl Text for Entry {
    fn text<S: Into<String>>(&self, text: S) -> &Self {
        self.text.set(text.into());
        self
    }

    fn text_offset(&self, x: i32, y: i32) -> &Self {
        self.text_offset.set(Point::new(x, y));
        self
    }
}

impl Style for Entry {
    fn selector(&self) -> &CloneCell<Selector> {
        &self.selector
    }
}

impl Widget for Entry {
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }
    fn draw(&self, renderer: &mut Renderer, _focused: bool, theme: &Theme) {
        let rect = self.rect.get();
        let offset = self.text_offset.get();
        let mut selector = self.selector.get();

        if self.hover.get() || self.active.get() {
            if self.active.get() {
                selector = selector.with_pseudo_class("active");
            } else {
                selector = selector.with_pseudo_class("hover");
            }

            draw_box(
                renderer,
                Rect::new(rect.x, rect.y, rect.width, rect.height),
                theme,
                &selector,
            );
        }

        let mut point = Point::new(rect.x + offset.x, rect.y + rect.height as i32 / 2 - 8);
        for c in self.text.get().chars() {
            if point.x + 8 <= rect.x +  rect.width as i32 - offset.x {
                renderer.char(point.x, point.y, c, theme.color("color", &selector));
            }
            point.x += 8;
        }
    }
    fn event(&self, event: Event, _focused: bool, redraw: &mut bool) -> bool {
        match event {
            Event::Mouse {
                point, left_button, ..
            } => {
                let mut click = false;

                let rect = self.rect.get();
                if rect.contains(point) {
                    if self.hover.check_set(true) {
                        *redraw = true;
                    }

                    if left_button {
                        if self.pressed.check_set(true) {
                            *redraw = true;
                        }
                    } else {
                        if self.pressed.check_set(false) {
                            click = true;
                            *redraw = true;
                        }
                    }
                } else {
                    if self.hover.check_set(false) {
                        *redraw = true;
                    }

                    if !left_button {
                        if self.pressed.check_set(false) {
                            *redraw = true;
                        }
                    }
                }

                if click {
                    return true;
                }
            }
            _ => (),
        }

        _focused
    }

    fn name(&self) -> &str {
        "ComboBoxEntry"
    }
}

pub struct ComboBox {
    pub rect: Cell<Rect>,
    pub selector: CloneCell<Selector>,
    pressed: Cell<bool>,
    activated: Cell<bool>,
    pub offset: Cell<Point>,
    selected: Cell<Option<u32>>,
    entries: RefCell<Vec<Arc<Entry>>>,
    text: CloneCell<String>,
    flyout_height: Cell<u32>,
    toggle_icon: RefCell<Option<Arc<Image>>>,
    toggle_icon_active: RefCell<Option<Arc<Image>>>,
}

impl ComboBox {
    pub fn new() -> Arc<ComboBox> {
        let toggle_icon = RefCell::new(None);
        if let Ok(icon) = orbimage::parse_png(TOGGLE_ICON) {
            *toggle_icon.borrow_mut() = Some(Image::from_image(icon))
        };

        let toggle_icon_active = RefCell::new(None);
        if let Ok(icon) = orbimage::parse_png(TOGGLE_ICON_ACTIVE) {
            *toggle_icon_active.borrow_mut() = Some(Image::from_image(icon))
        };

        Arc::new(ComboBox {
            rect: Cell::new(Rect::new(0, 0, 332, 28)),
            selector: CloneCell::new(Selector::new(Some("combo-box"))),
            pressed: Cell::new(false),
            activated: Cell::new(false),
            offset: Cell::new(Point::new(4, 4)),
            selected: Cell::new(None),
            entries: RefCell::new(vec![]),
            text: CloneCell::new(String::new()),
            flyout_height: Cell::new(0),
            toggle_icon,
            toggle_icon_active,
        })
    }

    pub fn selected(&self) -> i32 {
        if let Some(selected) = self.selected.get() {
            return selected as i32;
        };

        -1
    }

    pub fn push(&self, text: &str) {
        let rect = self.rect().get();
        let entry = Entry::new(text, self.entries.borrow().len() as u32);
        entry.rect.set(Rect::new(
            rect.x + 1,
            rect.y + rect.height as i32 * (self.entries.borrow().len() as i32 + 1),
            rect.width - 2,
            rect.height,
        ));
        entry.text_offset(self.offset.get().x, self.offset.get().y);
        self.flyout_height
            .set(self.flyout_height.get() + rect.height);

        self.entries.borrow_mut().push(entry);

        if self.entries.borrow().len() == 1 {
            self.change_selection(0);
        }
    }

    pub fn pop(&self) -> String {
        if let Some(entry) = self.entries.borrow_mut().pop() {
            self.change_selection(0);
            return entry.text.get();
        }

        String::new()
    }

    pub fn change_selection(&self, i: u32) {
        if let Some(index) = self.selected.get() {
            if let Some(entry) = self.entries.borrow().get(index as usize) {
                entry.active.set(false)
            }
        }

        self.selected.set(Some(i));

        if let Some(index) = self.selected.get() {
            if let Some(entry) = self.entries.borrow().get(index as usize) {
                entry.active.set(true);
                self.text.set(entry.text.get());
            }
        }
    }

    pub fn text_offset(&self, x: i32, y: i32) -> &Self {
        self.offset.set(Point::new(x, y));
        self
    }
}

impl Style for ComboBox {
    fn selector(&self) -> &CloneCell<Selector> {
        &self.selector
    }
}

impl Widget for ComboBox {
    fn rect(&self) -> &Cell<Rect> {
        &self.rect
    }

    fn draw(&self, renderer: &mut Renderer, _focused: bool, theme: &Theme) {
        let rect = self.rect.get();
        let activated = self.activated.get();
        let offset = self.offset.get();

        // draw flyout
        if activated {
            //TODO: set this selector as the child of self.selector
            let selector = Selector::new(Some("combo-box-flyout"));

            let flyout_rect = Rect::new(
                rect.x,
                rect.y + rect.height as i32 - 2,
                rect.width,
                self.flyout_height.get() + 2,
            );
            draw_box(renderer, flyout_rect, theme, &selector);

            // draw entries
            for entry in self.entries.borrow().iter() {
                let mut point = Point::new(entry.rect.get().x, entry.rect.get().y);

                if point.y >= rect.y
                    && point.y + rect.height as i32 <= flyout_rect.y + flyout_rect.height as i32
                {
                    entry.draw(renderer, _focused, theme);
                }
            }
        }

        // draw the combobox
        let mut selector = self.selector.get();

        if activated {
            selector = selector.with_pseudo_class("active");
        }

        draw_box(renderer, rect, theme, &selector);

        // draw toggle indicator
        //TODO: set this selector as the child of self.selector
        selector = Selector::new(Some("combo-box-toggle"));

        if activated {
            selector = selector.with_pseudo_class("active");
        }

        let toggle_size = rect.height - 2 * offset.y as u32;

        let toggle_rect = Rect::new(
            rect.x + rect.width as i32 - toggle_size as i32 - offset.y,
            rect.y + offset.y,
            toggle_size,
            toggle_size,
        );

        draw_box(renderer, toggle_rect, theme, &selector);

        // draw the toggle icon
        if activated {
            if let Some(ref icon) = *self.toggle_icon_active.borrow() {
                icon.position(toggle_rect.x, toggle_rect.y);
                icon.draw(renderer, _focused, theme)
            }
        } else {
            if let Some(ref icon) = *self.toggle_icon.borrow() {
                icon.position(toggle_rect.x, toggle_rect.y);
                icon.draw(renderer, _focused, theme)
            }
        }

        // draw selected text
        let mut point = Point::new(rect.x + offset.x, rect.y + rect.height as i32 / 2 - 8);
        for c in self.text.get().chars() {
            if point.x + 8 <= rect.x + rect.width as i32 - toggle_rect.width as i32 - 2 * offset.x {
                renderer.char(
                    point.x,
                    point.y,
                    c,
                    theme.color("color", &"label".into()),
                );
            }
            point.x += 8;
        }
    }

    fn event(&self, event: Event, focused: bool, redraw: &mut bool) -> bool {
        match event {
            Event::Mouse {
                point, left_button, ..
            } => {
                let mut ignore_event = false;
                if self.activated.get() {
                    for entry in self.entries.borrow().iter() {
                        if entry.event(event, focused, redraw) {
                            ignore_event = true;

                            self.change_selection(entry.index);
                            if self.activated.check_set(false) {
                                *redraw = true;
                            }
                        }
                    }
                }

                let rect = self.rect.get();
                if rect.contains(point) {
                    if left_button {
                        self.pressed.set(!self.pressed.get());

                        if self.activated.check_set(true) {
                            *redraw = true;
                        }
                    } else {
                        if !self.pressed.get() {
                            if self.activated.check_set(false) {
                                *redraw = true;
                            }
                        }
                    }
                } else {
                    if !ignore_event {
                        if left_button {
                            self.pressed.set(false);
                        } else {
                            if !self.pressed.get() {
                                if self.activated.check_set(false) {
                                    *redraw = true;
                                }
                            }
                        }
                    }
                }
            }
            Event::KeyPressed(key_event) => match key_event.scancode {
                orbclient::K_UP => match self.selected.get() {
                    None => {
                        self.change_selection(0);
                        *redraw = true;
                    }
                    Some(i) => if i > 0 {
                        self.change_selection(i - 1);
                        *redraw = true;
                    },
                },
                orbclient::K_DOWN => match self.selected.get() {
                    None => {
                        self.change_selection(0);
                        *redraw = true;
                    }
                    Some(i) => if i < self.entries.borrow().len() as u32 - 1 {
                        self.change_selection(i + 1);
                        *redraw = true;
                    },
                },
                orbclient::K_ENTER => if self.activated.check_set(false) {
                    self.pressed.set(false);
                    *redraw = true;
                },
                _ => {}
            },

            _ => {}
        }

        focused
    }

    fn name(&self) -> &str {
        "ComboBox"
    }
}

impl Place for ComboBox {}
<|endoftext|>


<commit_before>//! `ReservoirSampling` implementation.
use rand::Rng;
use std::fmt;

/// Simple implementation of [Reservoir Sampling](https://en.wikipedia.org/wiki/Reservoir_sampling)
/// with [fast approximation](https://erikerlandson.github.io/blog/2015/11/20/very-fast-reservoir-sampling/)
#[derive(Clone)]
pub struct ReservoirSampling<T, R>
where
    R: Rng,
{
    k: usize,
    rng: R,
    reservoir: Vec<T>,
    i: usize,
    skip_until: usize,
}

impl<T, R> ReservoirSampling<T, R>
where
    R: Rng,
{
    /// Create new reservoir sampler that keeps `k` samples and uses `rng` for its random
    /// decisions.
    pub fn new(k: usize, rng: R) -> Self {
        assert!(k > 0, "k must be greater than 0");

        Self {
            k,
            rng,
            reservoir: vec![],
            i: 0,
            skip_until: 0,
        }
    }

    /// Number of samples that should be kept.
    pub fn k(&self) -> usize {
        self.k
    }

    /// Read-only copy of the reservoir. Contains at most `k` entries.
    pub fn reservoir(&self) -> &Vec<T> {
        &self.reservoir
    }

    /// Number of data points seen.
    pub fn i(&self) -> usize {
        self.i
    }

    /// Observe new data point.
    pub fn add(&mut self, obj: T) {
        let t = self.k * 4; // TODO: make this a parameter

        if self.i < self.k {
            // initial fill-up
            self.reservoir.push(obj)
        } else if self.i < t {
            // normal reservoir sampling
            let j = self.rng.gen_range::<usize>(0, self.i);
            if j < self.k {
                self.reservoir[j] = obj;
            }
        } else if self.i >= self.skip_until {
            // fast skipping approximation
            let j = self.rng.gen_range::<usize>(0, self.k);
            self.reservoir[j] = obj;

            // calculate next skip
            let p = (self.k as f64) / ((self.i + 1) as f64);
            let u = 1. - self.rng.gen_range::<f64>(0., 1.); // (0.0, 1.0]
            let g = (u.ln() / (1. - p).ln()).floor() as usize;
            self.skip_until = self.i + g;
        }

        self.i += 1;
    }

    /// Checks if reservoir is empty (i.e. no data points where observed)
    pub fn is_empty(&self) -> bool {
        self.i == 0
    }

    /// Clear sampler state. It now behaves like a fresh one (i.e. no data points seen so far).
    pub fn clear(&mut self) {
        self.i = 0;
        self.skip_until = 0;
        self.reservoir.clear();
    }
}

impl<T, R> fmt::Debug for ReservoirSampling<T, R>
where
    R: Rng,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ReservoirSampling {{ k: {} }}", self.k)
    }
}

impl<T, R> Extend<T> for ReservoirSampling<T, R>
where
    R: Rng,
{
    fn extend<S: IntoIterator<Item = T>>(&mut self, iter: S) {
        for elem in iter {
            self.add(elem);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::ReservoirSampling;
    use rand::{ChaChaRng, SeedableRng};

    #[test]
    #[should_panic(expected = "k must be greater than 0")]
    fn new_panics_k0() {
        ReservoirSampling::<u64, ChaChaRng>::new(0, ChaChaRng::from_seed([0; 32]));
    }

    #[test]
    fn getter() {
        let rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        assert_eq!(rs.k(), 10);
        assert_eq!(rs.i(), 0);
        assert_eq!(rs.reservoir(), &vec![]);
    }

    #[test]
    fn empty() {
        let rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        assert!(rs.is_empty());
        assert!(rs.reservoir().is_empty());
    }

    #[test]
    fn add_k() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        for i in 0..10 {
            rs.add(i);
        }
        assert_eq!(rs.i(), 10);
        assert_eq!(rs.reservoir(), &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn add_parts() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(100, ChaChaRng::from_seed([0; 32]));
        for _ in 0..1500 {
            rs.add(0);
        }
        for _ in 0..7500 {
            rs.add(1);
        }
        for _ in 0..1000 {
            rs.add(0);
        }
        assert!((rs.reservoir().iter().sum::<u64>() as i64 - 75).abs() < 5);
    }

    #[test]
    fn debug() {
        let rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        assert_eq!(format!("{:?}", rs), "ReservoirSampling { k: 10 }");
    }

    #[test]
    fn clear() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        for i in 0..10 {
            rs.add(i);
        }
        rs.clear();
        for i in 10..20 {
            rs.add(i);
        }
        assert_eq!(rs.i(), 10);
        assert_eq!(
            rs.reservoir(),
            &vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
        );
    }

    #[test]
    fn extend() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        rs.extend(0..10);
        assert_eq!(rs.i(), 10);
        assert_eq!(rs.reservoir(), &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn clone() {
        let mut rs1 = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        for i in 0..10 {
            rs1.add(i);
        }
        let mut rs2 = rs1.clone();
        for _ in 0..1000 {
            rs2.add(99);
        }
        assert_eq!(rs1.i(), 10);
        assert_eq!(rs2.i(), 1010);
        assert_eq!(rs1.reservoir(), &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
        assert_eq!(
            rs2.reservoir(),
            &vec![99, 99, 99, 99, 99, 99, 99, 99, 99, 99]
        );
    }

    #[test]
    fn k1() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(1, ChaChaRng::from_seed([0; 32]));
        for _ in 0..10 {
            rs.add(1);
        }
        assert_eq!(rs.reservoir(), &vec![1]);
    }
}
<commit_msg>reservoirsampling: improve docs<commit_after>//! ReservoirSampling implementation.
use rand::Rng;
use std::fmt;

/// A ReservoirSampling is a data-structure that samples a fixed number of elements from a data
/// stream, without the need to memorize any additional elements.
///
/// # Examples
/// ```
/// use pdatastructs::reservoirsampling::ReservoirSampling;
/// use pdatastructs::rand::{ChaChaRng, SeedableRng};
///
/// // set up sampler for 10 elements
/// let rng = ChaChaRng::from_seed([0; 32]);
/// let mut sampler = ReservoirSampling::new(10, rng);
///
/// // add some data
/// for i in 0..1000 {
///     let x = i % 2;
///     sampler.add(x);
/// }
///
/// // later
/// assert_eq!(sampler.reservoir().iter().sum::<i64>(), 5);
/// ```
///
/// # Applications
/// - Getting a set of representative samples of a large data set.
/// - Collecting distribution information of a stream of data, which can then recover approximative
///   histograms or CDFs (Cumulative Distribution Function).
///
/// # How It Works
///
/// ## Setup
/// The sampler is initialized with an empty reservoir vector and a potential capacity `k`.
///
/// ## Insertion
/// If the sampler did see less than `k` elements, the element is appended to the reservoir vector,
/// so no sampling takes place (full take).
///
/// After the reservoir is filled up with `k` elements, the "normal reservoir sampling" phase
/// starts until `t = k * 4` elements were processed. In this phase, every incoming element
/// replaces may replace a random, existing element in the reservoir, iff a random number `x in [1,
/// i]` (i being the number of seen elements) is smaller or equal to `k`.
///
/// In the final phase, not every new incoming element may processed. Instead, some elements are
/// skipped. The number of skipped elements is chosen randomly but with respect to the number of
/// seen elements. Every non-skipped element replaces a random, existing element of the reservoir.
///
/// ## Read-Out
/// The reservoir vector is just returned, no further calculation is required.
///
/// # See Also
/// - `std::vec::Vec`: can be used to get an exact sampling but needs to store all elements of the
///   incoming data stream
///
/// # References
/// - ["Very Fast Reservoir Sampling", Erik Erlandson, 2015](https://erikerlandson.github.io/blog/2015/11/20/very-fast-reservoir-sampling/)
/// - [Wikipedia: Reservoir Sampling](https://en.wikipedia.org/wiki/Reservoir_sampling)
#[derive(Clone)]
pub struct ReservoirSampling<T, R>
where
    R: Rng,
{
    k: usize,
    rng: R,
    reservoir: Vec<T>,
    i: usize,
    skip_until: usize,
}

impl<T, R> ReservoirSampling<T, R>
where
    R: Rng,
{
    /// Create new reservoir sampler that keeps `k` samples and uses `rng` for its random
    /// decisions.
    pub fn new(k: usize, rng: R) -> Self {
        assert!(k > 0, "k must be greater than 0");

        Self {
            k,
            rng,
            reservoir: vec![],
            i: 0,
            skip_until: 0,
        }
    }

    /// Number of samples that should be kept.
    pub fn k(&self) -> usize {
        self.k
    }

    /// Read-only copy of the reservoir. Contains at most `k` entries.
    pub fn reservoir(&self) -> &Vec<T> {
        &self.reservoir
    }

    /// Number of data points seen.
    pub fn i(&self) -> usize {
        self.i
    }

    /// Observe new data point.
    pub fn add(&mut self, obj: T) {
        let t = self.k * 4; // TODO: make this a parameter

        if self.i < self.k {
            // initial fill-up
            self.reservoir.push(obj)
        } else if self.i < t {
            // normal reservoir sampling
            let j = self.rng.gen_range::<usize>(0, self.i);
            if j < self.k {
                self.reservoir[j] = obj;
            }
        } else if self.i >= self.skip_until {
            // fast skipping approximation
            let j = self.rng.gen_range::<usize>(0, self.k);
            self.reservoir[j] = obj;

            // calculate next skip
            let p = (self.k as f64) / ((self.i + 1) as f64);
            let u = 1. - self.rng.gen_range::<f64>(0., 1.); // (0.0, 1.0]
            let g = (u.ln() / (1. - p).ln()).floor() as usize;
            self.skip_until = self.i + g;
        }

        self.i += 1;
    }

    /// Checks if reservoir is empty (i.e. no data points where observed)
    pub fn is_empty(&self) -> bool {
        self.i == 0
    }

    /// Clear sampler state. It now behaves like a fresh one (i.e. no data points seen so far).
    pub fn clear(&mut self) {
        self.i = 0;
        self.skip_until = 0;
        self.reservoir.clear();
    }
}

impl<T, R> fmt::Debug for ReservoirSampling<T, R>
where
    R: Rng,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ReservoirSampling {{ k: {} }}", self.k)
    }
}

impl<T, R> Extend<T> for ReservoirSampling<T, R>
where
    R: Rng,
{
    fn extend<S: IntoIterator<Item = T>>(&mut self, iter: S) {
        for elem in iter {
            self.add(elem);
        }
    }
}

#[cfg(test)]
mod tests {
    use super::ReservoirSampling;
    use rand::{ChaChaRng, SeedableRng};

    #[test]
    #[should_panic(expected = "k must be greater than 0")]
    fn new_panics_k0() {
        ReservoirSampling::<u64, ChaChaRng>::new(0, ChaChaRng::from_seed([0; 32]));
    }

    #[test]
    fn getter() {
        let rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        assert_eq!(rs.k(), 10);
        assert_eq!(rs.i(), 0);
        assert_eq!(rs.reservoir(), &vec![]);
    }

    #[test]
    fn empty() {
        let rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        assert!(rs.is_empty());
        assert!(rs.reservoir().is_empty());
    }

    #[test]
    fn add_k() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        for i in 0..10 {
            rs.add(i);
        }
        assert_eq!(rs.i(), 10);
        assert_eq!(rs.reservoir(), &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn add_parts() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(100, ChaChaRng::from_seed([0; 32]));
        for _ in 0..1500 {
            rs.add(0);
        }
        for _ in 0..7500 {
            rs.add(1);
        }
        for _ in 0..1000 {
            rs.add(0);
        }
        assert!((rs.reservoir().iter().sum::<u64>() as i64 - 75).abs() < 5);
    }

    #[test]
    fn debug() {
        let rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        assert_eq!(format!("{:?}", rs), "ReservoirSampling { k: 10 }");
    }

    #[test]
    fn clear() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        for i in 0..10 {
            rs.add(i);
        }
        rs.clear();
        for i in 10..20 {
            rs.add(i);
        }
        assert_eq!(rs.i(), 10);
        assert_eq!(
            rs.reservoir(),
            &vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
        );
    }

    #[test]
    fn extend() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        rs.extend(0..10);
        assert_eq!(rs.i(), 10);
        assert_eq!(rs.reservoir(), &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
    }

    #[test]
    fn clone() {
        let mut rs1 = ReservoirSampling::<u64, ChaChaRng>::new(10, ChaChaRng::from_seed([0; 32]));
        for i in 0..10 {
            rs1.add(i);
        }
        let mut rs2 = rs1.clone();
        for _ in 0..1000 {
            rs2.add(99);
        }
        assert_eq!(rs1.i(), 10);
        assert_eq!(rs2.i(), 1010);
        assert_eq!(rs1.reservoir(), &vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
        assert_eq!(
            rs2.reservoir(),
            &vec![99, 99, 99, 99, 99, 99, 99, 99, 99, 99]
        );
    }

    #[test]
    fn k1() {
        let mut rs = ReservoirSampling::<u64, ChaChaRng>::new(1, ChaChaRng::from_seed([0; 32]));
        for _ in 0..10 {
            rs.add(1);
        }
        assert_eq!(rs.reservoir(), &vec![1]);
    }
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate lazy_static;
extern crate network as client_network;

mod beacon;
mod config;
mod error;
mod helpers;
mod metrics;
mod network;
mod node;
mod response_builder;
mod spec;
mod url_query;
mod validator;

use error::{ApiError, ApiResult};
use beacon_chain::{BeaconChain, BeaconChainTypes};
use client_network::NetworkMessage;
use client_network::Service as NetworkService;
use eth2_config::Eth2Config;
use hyper::rt::Future;
use hyper::service::{Service, MakeService};
use hyper::{Body, Method, Request, Response, Server, StatusCode};
use parking_lot::RwLock;
use response_builder::ResponseBuilder;
use slog::{info, o, warn};
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::runtime::TaskExecutor;
use tokio::sync::mpsc;
use url_query::UrlQuery;
use hyper::server::conn::AddrStream;

pub use beacon::{BlockResponse, HeadResponse, StateResponse};
pub use config::Config as ApiConfig;
use eth2_libp2p::rpc::RequestId;
use serde::export::PhantomData;

type BoxFut = Box<dyn Future<Item = Response<Body>, Error = ApiError> + Send>;

pub struct ApiMaker<T: BeaconChainTypes + 'static> {
    log: slog::Logger,
    beacon_chain: Arc<BeaconChain<T>>,
    db_path: DBPath,
    network_service: Arc<NetworkService<T>>,
    network_channel: Arc<RwLock<mpsc::UnboundedSender<NetworkMessage>>>,
    eth2_config: Arc<Eth2Config>,
}

impl<T: BeaconChainTypes> MakeService<AddrStream> for ApiMaker<T> {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = ApiError;
    type Service = ApiService<T>;
    type Future = futures::future::FutureResult<Self::Service, Self::MakeError>;
    type MakeError = String;

    fn make_service(&mut self, _ctx: AddrStream) -> Self::Future {
        futures::future::ok(ApiService {
            log: self.log.clone(),
            beacon_chain: self.beacon_chain.clone(),
            db_path: self.db_path.clone(),
            network_service: self.network_service.clone(),
            network_channel: self.network_channel.clone(),
            eth2_config: self.eth2_config.clone(),
        })
    }
}

pub struct ApiService<T: BeaconChainTypes + 'static> {
    log: slog::Logger,
    beacon_chain: Arc<BeaconChain<T>>,
    db_path: DBPath,
    network_service: Arc<NetworkService<T>>,
    network_channel: Arc<RwLock<mpsc::UnboundedSender<NetworkMessage>>>,
    eth2_config: Arc<Eth2Config>,
}

impl<T: BeaconChainTypes> Service for ApiService<T> {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = ApiError;
    type Future = BoxFut;

    fn call(&mut self, mut req: Request<Body>) -> Self::Future {
        metrics::inc_counter(&metrics::REQUEST_COUNT);
        let timer = metrics::start_timer(&metrics::REQUEST_RESPONSE_TIME);

        req.extensions_mut()
            .insert::<slog::Logger>(self.log.clone());
        req.extensions_mut()
            .insert::<Arc<BeaconChain<T>>>(self.beacon_chain.clone());
        req.extensions_mut().insert::<DBPath>(self.db_path.clone());
        req.extensions_mut()
            .insert::<Arc<NetworkService<T>>>(self.network_service.clone());
        req.extensions_mut()
            .insert::<Arc<RwLock<mpsc::UnboundedSender<NetworkMessage>>>>(
                self.network_channel.clone(),
            );
        req.extensions_mut()
            .insert::<Arc<Eth2Config>>(self.eth2_config.clone());

        let path = req.uri().path().to_string();

        // Route the request to the correct handler.
        let result = match (req.method(), path.as_ref()) {
            // Methods for Client
            (&Method::GET, "/node/version") => node::get_version(req),
            /*
            (&Method::GET, "/node/genesis_time") => node::get_genesis_time::<T>(req),
            (&Method::GET, "/node/syncing") => helpers::implementation_pending_response(req),

            // Methods for Network
            (&Method::GET, "/network/enr") => network::get_enr::<T>(req),
            (&Method::GET, "/network/peer_count") => network::get_peer_count::<T>(req),
            (&Method::GET, "/network/peer_id") => network::get_peer_id::<T>(req),
            (&Method::GET, "/network/peers") => network::get_peer_list::<T>(req),
            (&Method::GET, "/network/listen_port") => network::get_listen_port::<T>(req),
            (&Method::GET, "/network/listen_addresses") => {
                network::get_listen_addresses::<T>(req)
            }

            // Methods for Beacon Node
            (&Method::GET, "/beacon/head") => beacon::get_head::<T>(req),
            (&Method::GET, "/beacon/block") => beacon::get_block::<T>(req),
            (&Method::GET, "/beacon/block_root") => beacon::get_block_root::<T>(req),
            (&Method::GET, "/beacon/blocks") => helpers::implementation_pending_response(req),
            (&Method::GET, "/beacon/fork") => beacon::get_fork::<T>(req),
            (&Method::GET, "/beacon/attestations") => {
                helpers::implementation_pending_response(req)
            }
            (&Method::GET, "/beacon/attestations/pending") => {
                helpers::implementation_pending_response(req)
            }

            (&Method::GET, "/beacon/validators") => beacon::get_validators::<T>(req),
            (&Method::GET, "/beacon/validators/indicies") => {
                helpers::implementation_pending_response(req)
            }
            (&Method::GET, "/beacon/validators/pubkeys") => {
                helpers::implementation_pending_response(req)
            }

            // Methods for Validator
            (&Method::GET, "/beacon/validator/duties") => {
                validator::get_validator_duties::<T>(req)
            }
            (&Method::GET, "/beacon/validator/block") => {
                validator::get_new_beacon_block::<T>(req)
            }
            (&Method::POST, "/beacon/validator/block") => {
                validator::publish_beacon_block::<T>(req)
            }
            (&Method::GET, "/beacon/validator/attestation") => {
                validator::get_new_attestation::<T>(req)
            }
            (&Method::POST, "/beacon/validator/attestation") => {
                helpers::implementation_pending_response(req)
            }

            (&Method::GET, "/beacon/state") => beacon::get_state::<T>(req),
            (&Method::GET, "/beacon/state_root") => beacon::get_state_root::<T>(req),
            (&Method::GET, "/beacon/state/current_finalized_checkpoint") => {
                beacon::get_current_finalized_checkpoint::<T>(req)
            }
            (&Method::GET, "/beacon/state/genesis") => beacon::get_genesis_state::<T>(req),
            //TODO: Add aggreggate/filtered state lookups here, e.g. /beacon/validators/balances

            // Methods for bootstrap and checking configuration
            (&Method::GET, "/spec") => spec::get_spec::<T>(req),
            (&Method::GET, "/spec/slots_per_epoch") => spec::get_slots_per_epoch::<T>(req),
            (&Method::GET, "/spec/deposit_contract") => {
                helpers::implementation_pending_response(req)
            }
            (&Method::GET, "/spec/eth2_config") => spec::get_eth2_config::<T>(req),

            (&Method::GET, "/metrics") => metrics::get_prometheus::<T>(req),

            */
            _ => Err(ApiError::NotFound(
                "Request path and/or method not found.".to_owned(),
            )),
        };

        let response = match result {
            // Return the `hyper::Response`.
            Ok(response) => {
                metrics::inc_counter(&metrics::SUCCESS_COUNT);
                slog::debug!(self.log, "Request successful: {:?}", path);
                response
            }
            // Map the `ApiError` into `hyper::Response`.
            Err(e) => {
                slog::debug!(self.log, "Request failure: {:?}", path);
                e.into()
            }
        };

        metrics::stop_timer(timer);

        Box::new(futures::future::ok(response))

    }
}

pub fn start_server<T: BeaconChainTypes>(
    config: &ApiConfig,
    executor: &TaskExecutor,
    beacon_chain: Arc<BeaconChain<T>>,
    network_service: Arc<NetworkService<T>>,
    network_chan: mpsc::UnboundedSender<NetworkMessage>,
    db_path: PathBuf,
    eth2_config: Eth2Config,
    log: &slog::Logger,
) -> Result<exit_future::Signal, hyper::Error> {
    let log = log.new(o!("Service" => "Api"));

    // build a channel to kill the HTTP server
    let (exit_signal, exit) = exit_future::signal();

    let exit_log = log.clone();
    let server_exit = exit.and_then(move |_| {
        info!(exit_log, "API service shutdown");
        Ok(())
    });

    let db_path = DBPath(db_path);

    // Get the address to bind to
    let bind_addr = (config.listen_address, config.port).into();

    // Clone our stateful objects, for use in service closure.
    let server_log = log.clone();
    let server_bc = beacon_chain.clone();
    let eth2_config = Arc::new(eth2_config);

    let service = move || ApiMaker {
        log: log.clone(),
        beacon_chain: beacon_chain.clone(),
        db_path: db_path.clone(),
        network_service: network_service.clone(),
        network_channel: Arc::new(RwLock::new(network_chan.clone())),
        eth2_config: eth2_config.clone(),
    };

    let log_clone = log.clone();
    let server = Server::bind(&bind_addr)
        .serve(service)
        .with_graceful_shutdown(server_exit)
        .map_err(move |e| {
            warn!(
            log_clone,
            "API failed to start, Unable to bind"; "address" => format!("{:?}", e)
            )
        });

    info!(
    log,
    "REST API started";
    "address" => format!("{}", config.listen_address),
    "port" => config.port,
    );

    executor.spawn(server);

    Ok(exit_signal)
}

fn success_response(body: Body) -> Response<Body> {
    Response::builder()
        .status(StatusCode::OK)
        .header("content-type", "application/json")
        .body(body)
        .expect("We should always be able to make response from the success body.")
}

#[derive(Clone)]
pub struct DBPath(PathBuf);

impl Deref for DBPath {
    type Target = PathBuf;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<commit_msg>Fix ApiService woes (hopefully)<commit_after>#[macro_use]
extern crate lazy_static;
extern crate network as client_network;

mod beacon;
mod config;
mod error;
mod helpers;
mod metrics;
mod network;
mod node;
mod response_builder;
mod spec;
mod url_query;
mod validator;

use beacon_chain::{BeaconChain, BeaconChainTypes};
use client_network::NetworkMessage;
use client_network::Service as NetworkService;
use error::{ApiError, ApiResult};
use eth2_config::Eth2Config;
use hyper::rt::Future;
use hyper::server::conn::AddrStream;
use hyper::service::{MakeService, Service};
use hyper::{Body, Method, Request, Response, Server, StatusCode};
use parking_lot::RwLock;
use response_builder::ResponseBuilder;
use slog::{info, o, warn};
use std::ops::Deref;
use std::path::PathBuf;
use std::sync::Arc;
use tokio::runtime::TaskExecutor;
use tokio::sync::mpsc;
use url_query::UrlQuery;

pub use beacon::{BlockResponse, HeadResponse, StateResponse};
pub use config::Config as ApiConfig;
use eth2_libp2p::rpc::RequestId;
use serde::export::PhantomData;

type BoxFut = Box<dyn Future<Item = Response<Body>, Error = ApiError> + Send>;

pub struct ApiService<T: BeaconChainTypes + 'static> {
    log: slog::Logger,
    beacon_chain: Arc<BeaconChain<T>>,
    db_path: DBPath,
    network_service: Arc<NetworkService<T>>,
    network_channel: Arc<RwLock<mpsc::UnboundedSender<NetworkMessage>>>,
    eth2_config: Arc<Eth2Config>,
}

impl<T: BeaconChainTypes> Service for ApiService<T> {
    type ReqBody = Body;
    type ResBody = Body;
    type Error = ApiError;
    type Future = BoxFut;

    fn call(&mut self, mut req: Request<Body>) -> Self::Future {
        metrics::inc_counter(&metrics::REQUEST_COUNT);
        let timer = metrics::start_timer(&metrics::REQUEST_RESPONSE_TIME);

        req.extensions_mut()
            .insert::<slog::Logger>(self.log.clone());
        req.extensions_mut()
            .insert::<Arc<BeaconChain<T>>>(self.beacon_chain.clone());
        req.extensions_mut().insert::<DBPath>(self.db_path.clone());
        req.extensions_mut()
            .insert::<Arc<NetworkService<T>>>(self.network_service.clone());
        req.extensions_mut()
            .insert::<Arc<RwLock<mpsc::UnboundedSender<NetworkMessage>>>>(
                self.network_channel.clone(),
            );
        req.extensions_mut()
            .insert::<Arc<Eth2Config>>(self.eth2_config.clone());

        let path = req.uri().path().to_string();

        // Route the request to the correct handler.
        let result = match (req.method(), path.as_ref()) {
            // Methods for Client
            (&Method::GET, "/node/version") => node::get_version(req),
            /*
            (&Method::GET, "/node/genesis_time") => node::get_genesis_time::<T>(req),
            (&Method::GET, "/node/syncing") => helpers::implementation_pending_response(req),

            // Methods for Network
            (&Method::GET, "/network/enr") => network::get_enr::<T>(req),
            (&Method::GET, "/network/peer_count") => network::get_peer_count::<T>(req),
            (&Method::GET, "/network/peer_id") => network::get_peer_id::<T>(req),
            (&Method::GET, "/network/peers") => network::get_peer_list::<T>(req),
            (&Method::GET, "/network/listen_port") => network::get_listen_port::<T>(req),
            (&Method::GET, "/network/listen_addresses") => {
                network::get_listen_addresses::<T>(req)
            }

            // Methods for Beacon Node
            (&Method::GET, "/beacon/head") => beacon::get_head::<T>(req),
            (&Method::GET, "/beacon/block") => beacon::get_block::<T>(req),
            (&Method::GET, "/beacon/block_root") => beacon::get_block_root::<T>(req),
            (&Method::GET, "/beacon/blocks") => helpers::implementation_pending_response(req),
            (&Method::GET, "/beacon/fork") => beacon::get_fork::<T>(req),
            (&Method::GET, "/beacon/attestations") => {
                helpers::implementation_pending_response(req)
            }
            (&Method::GET, "/beacon/attestations/pending") => {
                helpers::implementation_pending_response(req)
            }

            (&Method::GET, "/beacon/validators") => beacon::get_validators::<T>(req),
            (&Method::GET, "/beacon/validators/indicies") => {
                helpers::implementation_pending_response(req)
            }
            (&Method::GET, "/beacon/validators/pubkeys") => {
                helpers::implementation_pending_response(req)
            }

            // Methods for Validator
            (&Method::GET, "/beacon/validator/duties") => {
                validator::get_validator_duties::<T>(req)
            }
            (&Method::GET, "/beacon/validator/block") => {
                validator::get_new_beacon_block::<T>(req)
            }
            (&Method::POST, "/beacon/validator/block") => {
                validator::publish_beacon_block::<T>(req)
            }
            (&Method::GET, "/beacon/validator/attestation") => {
                validator::get_new_attestation::<T>(req)
            }
            (&Method::POST, "/beacon/validator/attestation") => {
                helpers::implementation_pending_response(req)
            }

            (&Method::GET, "/beacon/state") => beacon::get_state::<T>(req),
            (&Method::GET, "/beacon/state_root") => beacon::get_state_root::<T>(req),
            (&Method::GET, "/beacon/state/current_finalized_checkpoint") => {
                beacon::get_current_finalized_checkpoint::<T>(req)
            }
            (&Method::GET, "/beacon/state/genesis") => beacon::get_genesis_state::<T>(req),
            //TODO: Add aggreggate/filtered state lookups here, e.g. /beacon/validators/balances

            // Methods for bootstrap and checking configuration
            (&Method::GET, "/spec") => spec::get_spec::<T>(req),
            (&Method::GET, "/spec/slots_per_epoch") => spec::get_slots_per_epoch::<T>(req),
            (&Method::GET, "/spec/deposit_contract") => {
                helpers::implementation_pending_response(req)
            }
            (&Method::GET, "/spec/eth2_config") => spec::get_eth2_config::<T>(req),

            (&Method::GET, "/metrics") => metrics::get_prometheus::<T>(req),

            */
            _ => Err(ApiError::NotFound(
                "Request path and/or method not found.".to_owned(),
            )),
        };

        let response = match result {
            // Return the `hyper::Response`.
            Ok(response) => {
                metrics::inc_counter(&metrics::SUCCESS_COUNT);
                slog::debug!(self.log, "Request successful: {:?}", path);
                response
            }
            // Map the `ApiError` into `hyper::Response`.
            Err(e) => {
                slog::debug!(self.log, "Request failure: {:?}", path);
                e.into()
            }
        };

        metrics::stop_timer(timer);

        Box::new(futures::future::ok(response))
    }
}

pub fn start_server<T: BeaconChainTypes>(
    config: &ApiConfig,
    executor: &TaskExecutor,
    beacon_chain: Arc<BeaconChain<T>>,
    network_service: Arc<NetworkService<T>>,
    network_chan: mpsc::UnboundedSender<NetworkMessage>,
    db_path: PathBuf,
    eth2_config: Eth2Config,
    log: &slog::Logger,
) -> Result<exit_future::Signal, hyper::Error> {
    let log = log.new(o!("Service" => "Api"));

    // build a channel to kill the HTTP server
    let (exit_signal, exit) = exit_future::signal();

    let exit_log = log.clone();
    let server_exit = exit.and_then(move |_| {
        info!(exit_log, "API service shutdown");
        Ok(())
    });

    let db_path = DBPath(db_path);

    // Get the address to bind to
    let bind_addr = (config.listen_address, config.port).into();

    // Clone our stateful objects, for use in service closure.
    let server_log = log.clone();
    let server_bc = beacon_chain.clone();
    let eth2_config = Arc::new(eth2_config);

    let service = move || -> futures::future::FutureResult<ApiService<T>, String> {
        futures::future::ok(ApiService {
            log: log.clone(),
            beacon_chain: beacon_chain.clone(),
            db_path: db_path.clone(),
            network_service: network_service.clone(),
            network_channel: Arc::new(RwLock::new(network_chan.clone())),
            eth2_config: eth2_config.clone(),
        })
    };

    let log_clone = log.clone();
    let server = Server::bind(&bind_addr)
        .serve(service)
        .with_graceful_shutdown(server_exit)
        .map_err(move |e| {
            warn!(
            log_clone,
            "API failed to start, Unable to bind"; "address" => format!("{:?}", e)
            )
        });

    info!(
    log,
    "REST API started";
    "address" => format!("{}", config.listen_address),
    "port" => config.port,
    );

    executor.spawn(server);

    Ok(exit_signal)
}

fn success_response(body: Body) -> Response<Body> {
    Response::builder()
        .status(StatusCode::OK)
        .header("content-type", "application/json")
        .body(body)
        .expect("We should always be able to make response from the success body.")
}

#[derive(Clone)]
pub struct DBPath(PathBuf);

impl Deref for DBPath {
    type Target = PathBuf;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}
<|endoftext|>


<commit_before>use jsonpath_lib::select;
use lazy_static::lazy_static;
use regex::{Regex, RegexBuilder};
use serde_json::Value;
use std::{env, fmt, fs};

mod cache;
mod config;
mod error;

use cache::Cache;
use config::parse_config;
use error::CkError;

fn main() -> Result<(), String> {
    let config = parse_config(env::args().collect());

    let mut failed = Vec::new();
    let mut cache = Cache::new(&config.doc_dir);
    let commands = get_commands(&config.template)
        .map_err(|_| format!("Jsondocck failed for {}", &config.template))?;

    for command in commands {
        if let Err(e) = check_command(command, &mut cache) {
            failed.push(e);
        }
    }

    if failed.is_empty() {
        Ok(())
    } else {
        for i in failed {
            eprintln!("{}", i);
        }
        Err(format!("Jsondocck failed for {}", &config.template))
    }
}

#[derive(Debug)]
pub struct Command {
    negated: bool,
    kind: CommandKind,
    args: Vec<String>,
    lineno: usize,
}

#[derive(Debug)]
pub enum CommandKind {
    Has,
    Count,
    Is,
    Set,
}

impl CommandKind {
    fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
        let count = match self {
            CommandKind::Has => (1..=3).contains(&args.len()),
            CommandKind::Count | CommandKind::Is => 3 == args.len(),
            CommandKind::Set => 4 == args.len(),
        };

        if !count {
            print_err(&format!("Incorrect number of arguments to `@{}`", self), lineno);
            return false;
        }

        if args[0] == "-" && command_num == 0 {
            print_err(&format!("Tried to use the previous path in the first command"), lineno);
            return false;
        }

        if let CommandKind::Count = self {
            if args[2].parse::<usize>().is_err() {
                print_err(&format!("Third argument to @count must be a valid usize"), lineno);
                return false;
            }
        }

        true
    }
}

impl fmt::Display for CommandKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let text = match self {
            CommandKind::Has => "has",
            CommandKind::Count => "count",
            CommandKind::Is => "is",
            CommandKind::Set => "set",
        };
        write!(f, "{}", text)
    }
}

lazy_static! {
    static ref LINE_PATTERN: Regex = RegexBuilder::new(
        r#"
        \s(?P<invalid>!?)@(?P<negated>!?)
        (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
        (?P<args>.*)$
    "#
    )
    .ignore_whitespace(true)
    .unicode(true)
    .build()
    .unwrap();
}

fn print_err(msg: &str, lineno: usize) {
    eprintln!("Invalid command: {} on line {}", msg, lineno)
}

/// Get a list of commands from a file. Does the work of ensuring the commands
/// are syntactically valid.
fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
    let mut commands = Vec::new();
    let mut errors = false;
    let file = fs::read_to_string(template).unwrap();

    for (lineno, line) in file.split('\n').enumerate() {
        let lineno = lineno + 1;

        let cap = match LINE_PATTERN.captures(line) {
            Some(c) => c,
            None => continue,
        };

        let negated = cap.name("negated").unwrap().as_str() == "!";
        let cmd = cap.name("cmd").unwrap().as_str();

        let cmd = match cmd {
            "has" => CommandKind::Has,
            "count" => CommandKind::Count,
            "is" => CommandKind::Is,
            "set" => CommandKind::Set,
            _ => {
                print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
                errors = true;
                continue;
            }
        };

        if let Some(m) = cap.name("invalid") {
            if m.as_str() == "!" {
                print_err(
                    &format!(
                        "`!@{0}{1}`, (help: try with `@!{1}`)",
                        if negated { "!" } else { "" },
                        cmd,
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        }

        let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str()));

        let args = match args {
            Some(args) => args,
            None => {
                print_err(
                    &format!(
                        "Invalid arguments to shlex::split: `{}`",
                        cap.name("args").unwrap().as_str()
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        };

        if !cmd.validate(&args, commands.len(), lineno) {
            errors = true;
            continue;
        }

        commands.push(Command { negated, kind: cmd, args, lineno })
    }

    if !errors { Ok(commands) } else { Err(()) }
}

/// Performs the actual work of ensuring a command passes. Generally assumes the command
/// is syntactically valid.
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
    // FIXME: Be more granular about why, (eg syntax error, count not equal)
    let result = match command.kind {
        CommandKind::Has => {
            match command.args.len() {
                // @has <path> = file existence
                1 => cache.get_file(&command.args[0]).is_ok(),
                // @has <path> <jsonpath> = check path exists
                2 => {
                    let val = cache.get_value(&command.args[0])?;

                    match select(&val, &command.args[1]) {
                        Ok(results) => !results.is_empty(),
                        Err(_) => false,
                    }
                }
                // @has <path> <jsonpath> <value> = check *any* item matched by path equals value
                3 => {
                    let val = cache.get_value(&command.args[0])?;
                    match select(&val, &command.args[1]) {
                        Ok(results) => {
                            // FIXME: Share the pat getting code with the `Is` branch.
                            let v_holder;
                            let pat: &Value = if command.args[2].starts_with("$") {
                                &cache.variables[&command.args[2][1..]]
                            } else {
                                v_holder = serde_json::from_str(&command.args[2]).unwrap();
                                &v_holder
                            };
                            !results.is_empty() && results.into_iter().any(|val| val == pat)
                        }
                        Err(_) => false,
                    }
                }
                _ => unreachable!(),
            }
        }
        CommandKind::Count => {
            // @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
            assert_eq!(command.args.len(), 3);
            let expected: usize = command.args[2].parse().unwrap();

            let val = cache.get_value(&command.args[0])?;
            match select(&val, &command.args[1]) {
                Ok(results) => results.len() == expected,
                Err(_) => false,
            }
        }
        CommandKind::Is => {
            // @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
            assert_eq!(command.args.len(), 3);
            let val = cache.get_value(&command.args[0])?;
            match select(&val, &command.args[1]) {
                Ok(results) => {
                    let v_holder;
                    let pat: &Value = if command.args[2].starts_with("$") {
                        &cache.variables[&command.args[2][1..]]
                    } else {
                        v_holder = serde_json::from_str(&command.args[2]).unwrap();
                        &v_holder
                    };
                    results.len() == 1 && results[0] == pat
                }
                Err(_) => false,
            }
        }
        // FIXME, Figure out semantics for @!set
        CommandKind::Set => {
            // @set <name> = <path> <jsonpath>
            assert_eq!(command.args.len(), 4);
            assert_eq!(command.args[1], "=", "Expected an `=`");
            let val = cache.get_value(&command.args[2])?;

            match select(&val, &command.args[3]) {
                Ok(results) => {
                    assert_eq!(results.len(), 1);
                    let r = cache.variables.insert(command.args[0].clone(), results[0].clone());
                    assert!(r.is_none(), "Name collision");
                    true
                }
                Err(_) => false,
            }
        }
    };

    if result == command.negated {
        if command.negated {
            Err(CkError::FailedCheck(
                format!(
                    "`@!{} {}` matched when it shouldn't",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        } else {
            // FIXME: In the future, try 'peeling back' each step, and see at what level the match failed
            Err(CkError::FailedCheck(
                format!(
                    "`@{} {}` didn't match when it should",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        }
    } else {
        Ok(())
    }
}
<commit_msg>Apply suggestions from code review<commit_after>use jsonpath_lib::select;
use lazy_static::lazy_static;
use regex::{Regex, RegexBuilder};
use serde_json::Value;
use std::{env, fmt, fs};

mod cache;
mod config;
mod error;

use cache::Cache;
use config::parse_config;
use error::CkError;

fn main() -> Result<(), String> {
    let config = parse_config(env::args().collect());

    let mut failed = Vec::new();
    let mut cache = Cache::new(&config.doc_dir);
    let commands = get_commands(&config.template)
        .map_err(|_| format!("Jsondocck failed for {}", &config.template))?;

    for command in commands {
        if let Err(e) = check_command(command, &mut cache) {
            failed.push(e);
        }
    }

    if failed.is_empty() {
        Ok(())
    } else {
        for i in failed {
            eprintln!("{}", i);
        }
        Err(format!("Jsondocck failed for {}", &config.template))
    }
}

#[derive(Debug)]
pub struct Command {
    negated: bool,
    kind: CommandKind,
    args: Vec<String>,
    lineno: usize,
}

#[derive(Debug)]
pub enum CommandKind {
    Has,
    Count,
    Is,
    Set,
}

impl CommandKind {
    fn validate(&self, args: &[String], command_num: usize, lineno: usize) -> bool {
        let count = match self {
            CommandKind::Has => (1..=3).contains(&args.len()),
            CommandKind::Count | CommandKind::Is => 3 == args.len(),
            CommandKind::Set => 4 == args.len(),
        };

        if !count {
            print_err(&format!("Incorrect number of arguments to `@{}`", self), lineno);
            return false;
        }

        if args[0] == "-" && command_num == 0 {
            print_err(&format!("Tried to use the previous path in the first command"), lineno);
            return false;
        }

        if let CommandKind::Count = self {
            if args[2].parse::<usize>().is_err() {
                print_err(&format!("Third argument to @count must be a valid usize"), lineno);
                return false;
            }
        }

        true
    }
}

impl fmt::Display for CommandKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let text = match self {
            CommandKind::Has => "has",
            CommandKind::Count => "count",
            CommandKind::Is => "is",
            CommandKind::Set => "set",
        };
        write!(f, "{}", text)
    }
}

lazy_static! {
    static ref LINE_PATTERN: Regex = RegexBuilder::new(
        r#"
        \s(?P<invalid>!?)@(?P<negated>!?)
        (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*)
        (?P<args>.*)$
    "#
    )
    .ignore_whitespace(true)
    .unicode(true)
    .build()
    .unwrap();
}

fn print_err(msg: &str, lineno: usize) {
    eprintln!("Invalid command: {} on line {}", msg, lineno)
}

/// Get a list of commands from a file. Does the work of ensuring the commands
/// are syntactically valid.
fn get_commands(template: &str) -> Result<Vec<Command>, ()> {
    let mut commands = Vec::new();
    let mut errors = false;
    let file = fs::read_to_string(template).unwrap();

    for (lineno, line) in file.split('\n').enumerate() {
        let lineno = lineno + 1;

        let cap = match LINE_PATTERN.captures(line) {
            Some(c) => c,
            None => continue,
        };

        let negated = cap.name("negated").unwrap().as_str() == "!";
        let cmd = cap.name("cmd").unwrap().as_str();

        let cmd = match cmd {
            "has" => CommandKind::Has,
            "count" => CommandKind::Count,
            "is" => CommandKind::Is,
            "set" => CommandKind::Set,
            _ => {
                print_err(&format!("Unrecognized command name `@{}`", cmd), lineno);
                errors = true;
                continue;
            }
        };

        if let Some(m) = cap.name("invalid") {
            if m.as_str() == "!" {
                print_err(
                    &format!(
                        "`!@{0}{1}`, (help: try with `@!{1}`)",
                        if negated { "!" } else { "" },
                        cmd,
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        }

        let args = cap.name("args").map_or(Some(vec![]), |m| shlex::split(m.as_str()));

        let args = match args {
            Some(args) => args,
            None => {
                print_err(
                    &format!(
                        "Invalid arguments to shlex::split: `{}`",
                        cap.name("args").unwrap().as_str()
                    ),
                    lineno,
                );
                errors = true;
                continue;
            }
        };

        if !cmd.validate(&args, commands.len(), lineno) {
            errors = true;
            continue;
        }

        commands.push(Command { negated, kind: cmd, args, lineno })
    }

    if !errors { Ok(commands) } else { Err(()) }
}

/// Performs the actual work of ensuring a command passes. Generally assumes the command
/// is syntactically valid.
fn check_command(command: Command, cache: &mut Cache) -> Result<(), CkError> {
    // FIXME: Be more granular about why, (e.g. syntax error, count not equal)
    let result = match command.kind {
        CommandKind::Has => {
            match command.args.len() {
                // @has <path> = file existence
                1 => cache.get_file(&command.args[0]).is_ok(),
                // @has <path> <jsonpath> = check path exists
                2 => {
                    let val = cache.get_value(&command.args[0])?;

                    match select(&val, &command.args[1]) {
                        Ok(results) => !results.is_empty(),
                        Err(_) => false,
                    }
                }
                // @has <path> <jsonpath> <value> = check *any* item matched by path equals value
                3 => {
                    let val = cache.get_value(&command.args[0])?;
                    match select(&val, &command.args[1]) {
                        Ok(results) => {
                            // FIXME: Share the pat getting code with the `Is` branch.
                            let v_holder;
                            let pat: &Value = if command.args[2].starts_with("$") {
                                &cache.variables[&command.args[2][1..]]
                            } else {
                                v_holder = serde_json::from_str(&command.args[2]).unwrap();
                                &v_holder
                            };
                            results.contains(pat)
                        }
                        Err(_) => false,
                    }
                }
                _ => unreachable!(),
            }
        }
        CommandKind::Count => {
            // @count <path> <jsonpath> <count> = Check that the jsonpath matches exactly [count] times
            assert_eq!(command.args.len(), 3);
            let expected: usize = command.args[2].parse().unwrap();

            let val = cache.get_value(&command.args[0])?;
            match select(&val, &command.args[1]) {
                Ok(results) => results.len() == expected,
                Err(_) => false,
            }
        }
        CommandKind::Is => {
            // @has <path> <jsonpath> <value> = check *exactly one* item matched by path, and it equals value
            assert_eq!(command.args.len(), 3);
            let val = cache.get_value(&command.args[0])?;
            match select(&val, &command.args[1]) {
                Ok(results) => {
                    let v_holder;
                    let pat: &Value = if command.args[2].starts_with("$") {
                        &cache.variables[&command.args[2][1..]]
                    } else {
                        v_holder = serde_json::from_str(&command.args[2]).unwrap();
                        &v_holder
                    };
                    results.len() == 1 && results[0] == pat
                }
                Err(_) => false,
            }
        }
        // FIXME, Figure out semantics for @!set
        CommandKind::Set => {
            // @set <name> = <path> <jsonpath>
            assert_eq!(command.args.len(), 4);
            assert_eq!(command.args[1], "=", "Expected an `=`");
            let val = cache.get_value(&command.args[2])?;

            match select(&val, &command.args[3]) {
                Ok(results) => {
                    assert_eq!(results.len(), 1);
                    let r = cache.variables.insert(command.args[0].clone(), results[0].clone());
                    assert!(r.is_none(), "Name collision: {} is duplicated", command.args[0]);
                    true
                }
                Err(_) => false,
            }
        }
    };

    if result == command.negated {
        if command.negated {
            Err(CkError::FailedCheck(
                format!(
                    "`@!{} {}` matched when it shouldn't",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        } else {
            // FIXME: In the future, try 'peeling back' each step, and see at what level the match failed
            Err(CkError::FailedCheck(
                format!(
                    "`@{} {}` didn't match when it should",
                    command.kind,
                    command.args.join(" ")
                ),
                command,
            ))
        }
    } else {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use std::borrow::Cow;
use std::ops::Deref;

use serde::de::{Deserialize, Deserializer, Error};
use serde::ser::{Serialize, Serializer};

use types::*;

/// Unique identifier for the target chat or username of the
/// target channel (in the format @channelusername)
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ChatRef<'a> {
    Id(ChatId),
    #[doc(hidden)]
    ChannelUsername(Cow<'a, str>,),
}

impl<'a> ChatRef<'a> {
    pub fn from_chat_id(chat_id: ChatId) -> ChatRef<'a> {
        ChatRef::Id(chat_id)
    }
}

pub trait ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a>;
}

impl<'a, S> ToChatRef<'a> for S where S: Deref, S::Target: ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.deref().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for Chat {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.id().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ChatMember {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.user.to_chat_ref()
    }
}

impl<'a> Serialize for ChatRef<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        match *self {
            ChatRef::Id(id) => serializer.serialize_i64(id.into()),
            ChatRef::ChannelUsername(ref username) => serializer.serialize_str(&username),
        }
    }
}

macro_rules! chat_id_impls {
    ($id: ident) => {
        integer_id_impls!($id);

        impl<'a> ToChatRef<'a> for $id {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                ChatRef::from_chat_id((*self).into())
            }
        }
    };
}

macro_rules! concrete_chat_id_impls {
    ($id: ident, $typ: ident) => {
        chat_id_impls!($id);

        impl From<$id> for ChatId {
            fn from(c: $id) -> Self {
                ChatId::new(c.into())
            }
        }

        impl<'a> ToChatRef<'a> for $typ {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                self.id.to_chat_ref()
            }
        }
    };
}

pub trait ToUserId {
    fn to_user_id(&self) -> UserId;
}

impl<S> ToUserId for S where S: Deref, S::Target: ToUserId {
    fn to_user_id(&self) -> UserId {
        self.deref().to_user_id()
    }
}

impl ToUserId for UserId {
    fn to_user_id(&self) -> UserId {
        *self
    }
}

impl ToUserId for ChatMember {
    fn to_user_id(&self) -> UserId {
        self.user.id
    }
}

impl ToUserId for User {
    fn to_user_id(&self) -> UserId {
        self.id
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UserId(Integer);
concrete_chat_id_impls!(UserId, User);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GroupId(Integer);
concrete_chat_id_impls!(GroupId, Group);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SupergroupId(Integer);
concrete_chat_id_impls!(SupergroupId, Supergroup);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChannelId(Integer);
concrete_chat_id_impls!(ChannelId, Channel);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChatId(Integer);
chat_id_impls!(ChatId);

/// This object represents a Telegram user or bot.
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
pub struct User {
    /// Unique identifier for this user or bot.
    pub id: UserId,
    /// User‘s or bot’s first name.
    pub first_name: String,
    /// User‘s or bot’s last name.
    pub last_name: Option<String>,
    /// User‘s or bot’s username.
    pub username: Option<String>,
}

/// This object represents a group.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Group {
    /// Unique identifier for this chat.
    pub id: GroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: bool,
}

/// This object represents a supergroup.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Supergroup {
    /// Unique identifier for this chat.
    pub id: SupergroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for supergroup.
    pub username: Option<String>,
}

/// This object represents a channel.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Channel {
    /// Unique identifier for this chat.
    pub id: ChannelId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for channel.
    pub username: Option<String>,
}

/// This object represents a chat.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Chat {
    Private(User),
    Group(Group),
    Supergroup(Supergroup),
    Channel(Channel),
    #[doc(hidden)]
    Unknown(RawChat),
}

impl Chat {
    pub fn id(&self) -> ChatId {
        match *self {
            Chat::Private(ref x) => x.id.into(),
            Chat::Group(ref x) => x.id.into(),
            Chat::Supergroup(ref x) => x.id.into(),
            Chat::Channel(ref x) => x.id.into(),
            Chat::Unknown(ref x) => x.id.into(),
        }
    }
}

impl<'de> Deserialize<'de> for Chat {
    fn deserialize<D>(deserializer: D) -> Result<Chat, D::Error>
        where D: Deserializer<'de>
    {
        let raw: RawChat = Deserialize::deserialize(deserializer)?;

        macro_rules! required_field {
            ($name:ident) => {{
                match raw.$name {
                    Some(val) => val,
                    None => return Err(D::Error::missing_field(stringify!($name)))
                }
            }}
        }

        Ok(match raw.type_.as_ref() {
            "private" => {
                Chat::Private(User {
                    id: raw.id.into(),
                    username: raw.username,
                    first_name: required_field!(first_name),
                    last_name: raw.last_name,
                })
            }
            "group" => {
                Chat::Group(Group {
                    id: raw.id.into(),
                    title: required_field!(title),
                    all_members_are_administrators: required_field!(all_members_are_administrators),
                })
            }
            "supergroup" => {
                Chat::Supergroup(Supergroup {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            "channel" => {
                Chat::Channel(Channel {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            _ => Chat::Unknown(raw),
        })
    }
}

/// This object represents a chat, directly mapped.
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
pub struct RawChat {
    /// Unique identifier for this chat.
    pub id: Integer,
    /// Type of chat, can be either “private”, “group”, “supergroup” or “channel”
    #[serde(rename="type")]
    pub type_: String,
    /// Title, for supergroups, channels and group chats
    pub title: Option<String>,
    /// Username, for private chats, supergroups and channels if available
    pub username: Option<String>,
    /// First name of the other party in a private chat
    pub first_name: Option<String>,
    /// Last name of the other party in a private chat
    pub last_name: Option<String>,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: Option<bool>,
}
<commit_msg>refactor: rename macro<commit_after>use std::borrow::Cow;
use std::ops::Deref;

use serde::de::{Deserialize, Deserializer, Error};
use serde::ser::{Serialize, Serializer};

use types::*;

/// Unique identifier for the target chat or username of the
/// target channel (in the format @channelusername)
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum ChatRef<'a> {
    Id(ChatId),
    #[doc(hidden)]
    ChannelUsername(Cow<'a, str>,),
}

impl<'a> ChatRef<'a> {
    pub fn from_chat_id(chat_id: ChatId) -> ChatRef<'a> {
        ChatRef::Id(chat_id)
    }
}

pub trait ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a>;
}

impl<'a, S> ToChatRef<'a> for S where S: Deref, S::Target: ToChatRef<'a> {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.deref().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for Chat {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.id().to_chat_ref()
    }
}

impl<'a> ToChatRef<'a> for ChatMember {
    fn to_chat_ref(&self) -> ChatRef<'a> {
        self.user.to_chat_ref()
    }
}

impl<'a> Serialize for ChatRef<'a> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer
    {
        match *self {
            ChatRef::Id(id) => serializer.serialize_i64(id.into()),
            ChatRef::ChannelUsername(ref username) => serializer.serialize_str(&username),
        }
    }
}

macro_rules! chat_id_impls {
    ($id: ident) => {
        integer_id_impls!($id);

        impl<'a> ToChatRef<'a> for $id {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                ChatRef::from_chat_id((*self).into())
            }
        }
    };
}

macro_rules! specific_chat_id_impls {
    ($id: ident, $typ: ident) => {
        chat_id_impls!($id);

        impl From<$id> for ChatId {
            fn from(c: $id) -> Self {
                ChatId::new(c.into())
            }
        }

        impl<'a> ToChatRef<'a> for $typ {
            fn to_chat_ref(&self) -> ChatRef<'a> {
                self.id.to_chat_ref()
            }
        }
    };
}

pub trait ToUserId {
    fn to_user_id(&self) -> UserId;
}

impl<S> ToUserId for S where S: Deref, S::Target: ToUserId {
    fn to_user_id(&self) -> UserId {
        self.deref().to_user_id()
    }
}

impl ToUserId for UserId {
    fn to_user_id(&self) -> UserId {
        *self
    }
}

impl ToUserId for ChatMember {
    fn to_user_id(&self) -> UserId {
        self.user.id
    }
}

impl ToUserId for User {
    fn to_user_id(&self) -> UserId {
        self.id
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct UserId(Integer);
specific_chat_id_impls!(UserId, User);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct GroupId(Integer);
specific_chat_id_impls!(GroupId, Group);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SupergroupId(Integer);
specific_chat_id_impls!(SupergroupId, Supergroup);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChannelId(Integer);
specific_chat_id_impls!(ChannelId, Channel);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ChatId(Integer);
chat_id_impls!(ChatId);

/// This object represents a Telegram user or bot.
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
pub struct User {
    /// Unique identifier for this user or bot.
    pub id: UserId,
    /// User‘s or bot’s first name.
    pub first_name: String,
    /// User‘s or bot’s last name.
    pub last_name: Option<String>,
    /// User‘s or bot’s username.
    pub username: Option<String>,
}

/// This object represents a group.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Group {
    /// Unique identifier for this chat.
    pub id: GroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: bool,
}

/// This object represents a supergroup.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Supergroup {
    /// Unique identifier for this chat.
    pub id: SupergroupId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for supergroup.
    pub username: Option<String>,
}

/// This object represents a channel.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct Channel {
    /// Unique identifier for this chat.
    pub id: ChannelId,
    /// Title, for supergroups, channels and group chats.
    pub title: String,
    /// Username for channel.
    pub username: Option<String>,
}

/// This object represents a chat.
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub enum Chat {
    Private(User),
    Group(Group),
    Supergroup(Supergroup),
    Channel(Channel),
    #[doc(hidden)]
    Unknown(RawChat),
}

impl Chat {
    pub fn id(&self) -> ChatId {
        match *self {
            Chat::Private(ref x) => x.id.into(),
            Chat::Group(ref x) => x.id.into(),
            Chat::Supergroup(ref x) => x.id.into(),
            Chat::Channel(ref x) => x.id.into(),
            Chat::Unknown(ref x) => x.id.into(),
        }
    }
}

impl<'de> Deserialize<'de> for Chat {
    fn deserialize<D>(deserializer: D) -> Result<Chat, D::Error>
        where D: Deserializer<'de>
    {
        let raw: RawChat = Deserialize::deserialize(deserializer)?;

        macro_rules! required_field {
            ($name:ident) => {{
                match raw.$name {
                    Some(val) => val,
                    None => return Err(D::Error::missing_field(stringify!($name)))
                }
            }}
        }

        Ok(match raw.type_.as_ref() {
            "private" => {
                Chat::Private(User {
                    id: raw.id.into(),
                    username: raw.username,
                    first_name: required_field!(first_name),
                    last_name: raw.last_name,
                })
            }
            "group" => {
                Chat::Group(Group {
                    id: raw.id.into(),
                    title: required_field!(title),
                    all_members_are_administrators: required_field!(all_members_are_administrators),
                })
            }
            "supergroup" => {
                Chat::Supergroup(Supergroup {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            "channel" => {
                Chat::Channel(Channel {
                    id: raw.id.into(),
                    title: required_field!(title),
                    username: raw.username,
                })
            }
            _ => Chat::Unknown(raw),
        })
    }
}

/// This object represents a chat, directly mapped.
#[derive(Debug, Clone, PartialEq, PartialOrd, Deserialize)]
pub struct RawChat {
    /// Unique identifier for this chat.
    pub id: Integer,
    /// Type of chat, can be either “private”, “group”, “supergroup” or “channel”
    #[serde(rename="type")]
    pub type_: String,
    /// Title, for supergroups, channels and group chats
    pub title: Option<String>,
    /// Username, for private chats, supergroups and channels if available
    pub username: Option<String>,
    /// First name of the other party in a private chat
    pub first_name: Option<String>,
    /// Last name of the other party in a private chat
    pub last_name: Option<String>,
    /// True if a group has ‘All Members Are Admins’ enabled.
    pub all_members_are_administrators: Option<bool>,
}
<|endoftext|>


<commit_before>use std::io::{Cursor, Read};
use std::error::Error;
use utils::extensions::{PeekingExt, FilteringScanExt};

// TODO: do not remove if in passage name, monospace etc.

struct ScanState {
    comment: bool,
    skip_next: bool,
}

pub fn screen<R: Read>(input: &mut R) -> Cursor<Vec<u8>> {

    let mut content = String::new();
    match input.read_to_string(&mut content) {
        Err(why) => panic!("could not read from input: {}", Error::description(&why)),
        Ok(_) => debug!("read input to buffer"),
    };

    Cursor::new(content.chars().peeking().scan_filter(
        ScanState {
            comment: false,
            skip_next: false,
        },
        |state, elem| {
            match (state.comment, state.skip_next, elem) {
                (_, true, _) => { //skipping
                    state.skip_next = false;
                    None
                },
                (false, _, ('/', Some('%'))) => { //comment_start
                    state.comment = true;
                    state.skip_next = true;
                    None
                },
                (true, _, ('%', Some('/'))) => { //comment_end
                    state.comment = false;
                    state.skip_next = true;
                    None
                },
                (true, _, _) => None, //comment
                (false, _, (x, _)) => Some(x as u8), //char
            }
        }
    ).collect())
}
<commit_msg>solve utfs8-bug (crashing compiler) if the twee file contains unicode-characters<commit_after>use std::io::{Cursor, Read};
use std::error::Error;
use utils::extensions::{PeekingExt, FilteringScanExt};

// TODO: do not remove if in passage name, monospace etc.

struct ScanState {
    comment: bool,
    skip_next: bool,
}

pub fn screen<R: Read>(input: &mut R) -> Cursor<Vec<u8>> {

    let mut content = String::new();
    match input.read_to_string(&mut content) {
        Err(why) => panic!("could not read from input: {}", Error::description(&why)),
        Ok(_) => debug!("read input to buffer"),
    };

    Cursor::new(content.bytes().peeking().scan_filter(
        ScanState {
            comment: false,
            skip_next: false,
        },
        |state, elem| {
            const SLASH: u8 = '/' as u8;
            const PERCENT: u8 = '%' as u8;
            match (state.comment, state.skip_next, elem) {
                (_, true, _) => { //skipping
                    state.skip_next = false;
                    None
                },
                (false, _, (SLASH, Some(PERCENT))) => { //comment_start
                    state.comment = true;
                    state.skip_next = true;
                    None
                },
                (true, _, (PERCENT, Some(SLASH))) => { //comment_end
                    state.comment = false;
                    state.skip_next = true;
                    None
                },
                (true, _, _) => None, //comment
                (false, _, (x, _)) => Some(x as u8), //char
            }
        }
    ).collect())
}
<|endoftext|>