<commit_before>use memchr::memchr;

use super::{
    FAIL_STATE, ROOT_STATE,
    StateIdx, PatIdx,
    AcAutomaton, Transitions, Match,
};
use super::autiter::Automaton;

/// A complete Aho-Corasick automaton.
///
/// This uses a single transition matrix that permits each input character
/// to move to the next state with a single lookup in the matrix.
///
/// This is as fast as it gets, but it is guaranteed to use a lot of memory.
/// Namely, it will use at least `4 * 256 * #states`, where the number of
/// states is capped at length of all patterns concatenated.
#[derive(Clone, Debug)]
pub struct FullAcAutomaton {
    pats: Vec<String>,
    trans: Vec<StateIdx>,  // row-major, where states are rows
    out: Vec<Vec<PatIdx>>, // indexed by StateIdx
    start_bytes: Vec<u8>,
}

impl FullAcAutomaton {
    /// Build a new expanded Aho-Corasick automaton from an existing
    /// Aho-Corasick automaton.
    pub fn new<T: Transitions>(ac: AcAutomaton<T>) -> FullAcAutomaton {
        let mut fac = FullAcAutomaton {
            pats: vec![],
            trans: vec![FAIL_STATE; 256 * ac.states.len()],
            out: vec![vec![]; ac.states.len()],
            start_bytes: vec![],
        };
        fac.build_matrix(&ac);
        fac.pats = ac.pats;
        fac.start_bytes = ac.start_bytes;
        fac
    }

    fn set(&mut self, si: StateIdx, i: u8, goto: StateIdx) {
        let ns = self.num_states();
        self.trans[i as usize * ns + si as usize] = goto;
    }

    #[inline]
    fn num_states(&self) -> usize {
        self.out.len()
    }
}

impl Automaton for FullAcAutomaton {
    #[inline]
    fn next_state(&self, si: StateIdx, i: u8) -> StateIdx {
        self.trans[i as usize * self.num_states() + si as usize]
    }

    #[inline]
    fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
        let pati = self.out[si as usize][outi];
        let patlen = self.pats[pati].len();
        let start = texti + 1 - patlen;
        Match {
            pati: pati,
            start: start,
            end: start + patlen,
        }
    }

    #[inline]
    fn has_match(&self, si: StateIdx, outi: usize) -> bool {
        outi < self.out[si as usize].len()
    }

    #[inline]
    fn skip_to(&self, si: StateIdx, text: &[u8], at: usize) -> usize {
        if si != ROOT_STATE || !self.is_skippable() {
            return at;
        }
        let b = self.start_bytes[0];
        match memchr(b, &text[at..]) {
            None => text.len(),
            Some(i) => at + i,
        }
    }

    #[inline]
    fn is_skippable(&self) -> bool {
        self.start_bytes.len() == 1
    }

    #[inline]
    fn patterns(&self) -> &[String] {
        &self.pats
    }

    #[inline]
    fn pattern(&self, i: usize) -> &str {
        &self.pats[i]
    }
}

impl FullAcAutomaton {
    fn build_matrix<T: Transitions>(&mut self, ac: &AcAutomaton<T>) {
        for (si, s) in ac.states.iter().enumerate().skip(1) {
            for b in (0..256).map(|b| b as u8) {
                self.set(si as StateIdx, b, ac.next_state(si as StateIdx, b));
            }
            for &pati in &s.out {
                self.out[si].push(pati);
            }
        }
    }
}
<commit_msg>Add a more concise Debug impl for `FullAcAutomaton`.<commit_after>use std::fmt;

use memchr::memchr;

use super::{
    FAIL_STATE, ROOT_STATE,
    StateIdx, PatIdx,
    AcAutomaton, Transitions, Match,
};
use super::autiter::Automaton;

/// A complete Aho-Corasick automaton.
///
/// This uses a single transition matrix that permits each input character
/// to move to the next state with a single lookup in the matrix.
///
/// This is as fast as it gets, but it is guaranteed to use a lot of memory.
/// Namely, it will use at least `4 * 256 * #states`, where the number of
/// states is capped at length of all patterns concatenated.
#[derive(Clone)]
pub struct FullAcAutomaton {
    pats: Vec<String>,
    trans: Vec<StateIdx>,  // row-major, where states are rows
    out: Vec<Vec<PatIdx>>, // indexed by StateIdx
    start_bytes: Vec<u8>,
}

impl FullAcAutomaton {
    /// Build a new expanded Aho-Corasick automaton from an existing
    /// Aho-Corasick automaton.
    pub fn new<T: Transitions>(ac: AcAutomaton<T>) -> FullAcAutomaton {
        let mut fac = FullAcAutomaton {
            pats: vec![],
            trans: vec![FAIL_STATE; 256 * ac.states.len()],
            out: vec![vec![]; ac.states.len()],
            start_bytes: vec![],
        };
        fac.build_matrix(&ac);
        fac.pats = ac.pats;
        fac.start_bytes = ac.start_bytes;
        fac
    }

    fn set(&mut self, si: StateIdx, i: u8, goto: StateIdx) {
        let ns = self.num_states();
        self.trans[i as usize * ns + si as usize] = goto;
    }

    #[inline]
    fn num_states(&self) -> usize {
        self.out.len()
    }
}

impl Automaton for FullAcAutomaton {
    #[inline]
    fn next_state(&self, si: StateIdx, i: u8) -> StateIdx {
        self.trans[i as usize * self.num_states() + si as usize]
    }

    #[inline]
    fn get_match(&self, si: StateIdx, outi: usize, texti: usize) -> Match {
        let pati = self.out[si as usize][outi];
        let patlen = self.pats[pati].len();
        let start = texti + 1 - patlen;
        Match {
            pati: pati,
            start: start,
            end: start + patlen,
        }
    }

    #[inline]
    fn has_match(&self, si: StateIdx, outi: usize) -> bool {
        outi < self.out[si as usize].len()
    }

    #[inline]
    fn skip_to(&self, si: StateIdx, text: &[u8], at: usize) -> usize {
        if si != ROOT_STATE || !self.is_skippable() {
            return at;
        }
        let b = self.start_bytes[0];
        match memchr(b, &text[at..]) {
            None => text.len(),
            Some(i) => at + i,
        }
    }

    #[inline]
    fn is_skippable(&self) -> bool {
        self.start_bytes.len() == 1
    }

    #[inline]
    fn patterns(&self) -> &[String] {
        &self.pats
    }

    #[inline]
    fn pattern(&self, i: usize) -> &str {
        &self.pats[i]
    }
}

impl FullAcAutomaton {
    fn build_matrix<T: Transitions>(&mut self, ac: &AcAutomaton<T>) {
        for (si, s) in ac.states.iter().enumerate().skip(1) {
            for b in (0..256).map(|b| b as u8) {
                self.set(si as StateIdx, b, ac.next_state(si as StateIdx, b));
            }
            for &pati in &s.out {
                self.out[si].push(pati);
            }
        }
    }
}

impl fmt::Debug for FullAcAutomaton {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "FullAcAutomaton({:?})", self.pats)
    }
}
<|endoftext|>


<commit_before>extern crate rustbox;

use std::error::Error;
use std::time::Duration;
use std::thread;

use self::rustbox::RustBox;
use self::rustbox::Key;

use super::ui::Ui;
use super::board::Board;
use super::srs::Direction;

const DEFAULT_TIMEOUT: u64 = 100;
const FPS: u64 = 15;

/// A controller between the terminal view and game state
pub struct Game<'a> {
    rb: &'a RustBox,
    ui: Ui<'a>,
    board: Board,
}

impl<'a> Game<'a> {

    /// Initializes a new Game struct
    pub fn new(rb: &'a RustBox) -> Self {
        Game {
            rb: rb,
            ui: Ui::new(rb),
            board: Board::new(),
        }
    }

    /// Starts the main game loop
    pub fn run(&mut self) {
        self.setup_ui();

        let mut running = true;
        while running {
            running = self.handle_input();
            self.board.tick();

            // The player has lost; we will just restart the game for now
            if self.board.is_topped_out() {
                self.board = Board::new();
                continue;
            }

            self.render();
            thread::sleep(Duration::from_millis(1000 / FPS));
        }
    }

    /// Renders the game state and board to the terminal
    fn render(&self) {
        self.ui.print_board(&self.board);
        self.ui.print_next(self.board.peek_next());
        self.ui.print_score(self.board.score());
        self.ui.print_level(self.board.level());
        self.ui.print_lines(self.board.cleared());
        self.rb.present();
    }

    /// Renders the initial elements of the user interface
    fn setup_ui(&self) {
        self.ui.setup();
        self.rb.present();
    }

    /// Handles input events from the user, updating the game state if necessary.
    /// Returns false if the user quits; otherwise, true
    fn handle_input(&mut self) -> bool {

        // Peek at events to avoid blocking if there is no input
        match self.rb.peek_event(Duration::from_millis(DEFAULT_TIMEOUT), false) {
            Ok(rustbox::Event::KeyEvent(key)) => {
                match key {
                    Key::Esc => false,

                    Key::Left => {
                        self.board.left();
                        true
                    },

                    Key::Right => {
                        self.board.right();
                        true
                    },

                    Key::Up => {
                        self.board.up();
                        true
                    },

                    Key::Down => {
                        self.board.down();
                        true
                    },

                    Key::Char('z') => {
                        self.board.rotate(Direction::CounterClockwise);
                        true
                    },

                    Key::Char('x') => {
                        self.board.rotate(Direction::Clockwise);
                        true
                    },

                    Key::Char('c') => {
                        self.board.drop();
                        true
                    }

                    _ => true
                }
            },

            Err(e) => panic!("{}", e.description()),

            _ => { true }
        }
    }
}<commit_msg>Add reset key. Move handle_inut() logic into run()<commit_after>extern crate rustbox;

use std::error::Error;
use std::time::Duration;
use std::thread;

use self::rustbox::RustBox;
use self::rustbox::Key;

use super::ui::Ui;
use super::board::Board;
use super::srs::Direction;

const DEFAULT_TIMEOUT: u64 = 100;
const FPS: u64 = 15;

/// A controller between the terminal view and game state
pub struct Game<'a> {
    rb: &'a RustBox,
    ui: Ui<'a>,
    board: Board,
}

impl<'a> Game<'a> {

    /// Initializes a new Game struct
    pub fn new(rb: &'a RustBox) -> Self {
        Game {
            rb: rb,
            ui: Ui::new(rb),
            board: Board::new(),
        }
    }

    /// Starts the main game loop
    pub fn run(&mut self) {
        self.setup_ui();

        let mut running = true;
        while running {

            // Handle the player input. Peek at events to avoid blocking
            match self.rb.peek_event(Duration::from_millis(DEFAULT_TIMEOUT), false) {
                Ok(rustbox::Event::KeyEvent(key)) => {
                    match key {
                        Key::Esc => break,
                        Key::Left => self.board.left(),
                        Key::Right => self.board.right(),
                        Key::Up => self.board.up(),
                        Key::Down => self.board.down(),
                        Key::Char('z') => self.board.rotate(Direction::CounterClockwise),
                        Key::Char('x') => self.board.rotate(Direction::Clockwise),
                        Key::Char('c') => self.board.drop(),
                        Key::Char('r') => self.board = Board::new(),
                        _ => { }
                    }
                },

                Err(e) => panic!("{}", e.description()),

                _ => { }
            }

            self.board.tick();

            // The player has lost; we will just restart the game for now
            if self.board.is_topped_out() {
                self.board = Board::new();
                continue;
            }

            self.render();
            thread::sleep(Duration::from_millis(1000 / FPS));
        }
    }

    /// Renders the game state and board to the terminal
    fn render(&self) {
        self.ui.print_board(&self.board);
        self.ui.print_next(self.board.peek_next());
        self.ui.print_score(self.board.score());
        self.ui.print_level(self.board.level());
        self.ui.print_lines(self.board.cleared());
        self.rb.present();
    }

    /// Renders the initial elements of the user interface
    fn setup_ui(&self) {
        self.ui.setup();
        self.rb.present();
    }
}<|endoftext|>


<commit_before>//! Half-integers for angular momentum quantities.
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
use num::{One, Signed, ToPrimitive, Zero};
use super::utils::{self, RangeInclusive};

/// Type that logically behaves like half-integers, but what is actually
/// stored is twice its logical value.
///
/// For example, `Half(3)` represents the fraction `3/2`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord,
         Serialize, Deserialize)]
pub struct Half<T>(pub T);

impl<T> fmt::Display for Half<T>
    where T: fmt::Display + Div<Output = T> + Rem<Output = T> +
             Zero + One + Clone
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.clone().try_get() {
            Ok(x) => write!(f, "{}", x),
            Err(d) => write!(f, "{}/2", d.0),
        }
    }
}

impl<T: Add<Output = T> + Clone> From<T> for Half<T> {
    #[inline]
    fn from(t: T) -> Self {
        Half(t.clone() + t)
    }
}

impl<T> Half<T> {
    /// Unwrap to twice its logical value.
    #[inline]
    pub fn twice(self) -> T {
        self.0
    }
}

impl<T: Add<Output = T> + Clone> Half<T> {
    #[inline]
    pub fn double(self) -> Self {
        self.clone() + self
    }
}

impl<T: Signed> Half<T> {
    #[inline]
    pub fn abs(self) -> Half<T> {
        Half(self.twice().abs())
    }
}

impl<T: Signed + Ord> Half<T> {
    #[inline]
    pub fn in_multiplet_of(self, j: Half<T>) -> bool {
        self.abs().twice() < j.twice()
    }
}

impl<T: Clone + Div<Output = T> + Rem<Output = T> + Zero + One> Half<T> {
    /// Get the value if it's half-even.  Otherwise, returns `Err(self)`.
    #[inline]
    pub fn try_get(self) -> Result<T, Half<T>> {
        let two = T::one() + T::one();
        if (self.0.clone() % two.clone()).is_zero() {
            Ok(self.0 / two)
        } else {
            Err(self)
        }
    }
}

impl<T> Half<T>
    where T: Clone + fmt::Debug + Div<Output = T> + Rem<Output = T> +
             Zero + One,
{
    /// Equivalent to `try_get().unwrap()`.
    #[inline]
    pub fn unwrap(self) -> T {
        self.try_get().unwrap()
    }
}

impl<T: Ord + Sub> Half<T> {
    #[inline]
    pub fn abs_diff(self, other: Self) -> Half<T::Output> {
        if self.0 >= other.0 {
            self - other
        } else {
            other - self
        }
    }
}

impl<T: Add<Output = T> + Sub<Output = T> + One + Ord + Clone> Half<T> {
    /// Obtain the range of values that satisfy the triangular condition, i.e.
    /// the range from `|self − other|` to `self + other` (inclusive).
    #[inline]
    pub fn tri_range(self, other: Half<T>) -> RangeInclusive<Half<T>> {
        RangeInclusive {
            start: Half::abs_diff(self.clone(), other.clone()),
            end: self + other + Half(One::one()),
        }
    }

    #[inline]
    pub fn tri_range_2(
        (j1, j2): (Half<T>, Half<T>),
        (j3, j4): (Half<T>, Half<T>),
    ) -> RangeInclusive<Half<T>> {
        utils::intersect_range_inclusive(
            Half::tri_range(j1, j2),
            Half::tri_range(j3, j4),
        )
    }
}

impl<T: Neg<Output = T> + Clone> Half<T> {
    #[inline]
    pub fn multiplet(self) -> RangeInclusive<Self> {
        let end = Half(self.twice());
        RangeInclusive {
            start: -end.clone(),
            end,
        }
    }
}

impl<T: Add<U>, U> Add<Half<U>> for Half<T> {
    type Output = Half<T::Output>;
    #[inline]
    fn add(self, other: Half<U>) -> Self::Output {
        Half(self.0 + other.0)
    }
}

impl<T: Sub<U>, U> Sub<Half<U>> for Half<T> {
    type Output = Half<T::Output>;
    #[inline]
    fn sub(self, other: Half<U>) -> Self::Output {
        Half(self.0 - other.0)
    }
}

impl<T: Neg> Neg for Half<T> {
    type Output = Half<T::Output>;
    #[inline]
    fn neg(self) -> Self::Output {
        Half(-self.0)
    }
}

impl<T: Zero> Zero for Half<T> {
    #[inline]
    fn zero() -> Self {
        Half(Zero::zero())
    }
    #[inline]
    fn is_zero(&self) -> bool {
        self.0.is_zero()
    }
}

impl<T> Mul for Half<T>
    where T: Clone + Div<Output = T> + Rem<Output = T> + Zero + One
{
    type Output = Self;
    #[inline]
    fn mul(self, other: Self) -> Self::Output {
        Half(Half(self.0 * other.0).try_get().unwrap_or_else(|_| {
            panic!("cannot multiply two half-odd integers")
        }))
    }
}

impl<T> One for Half<T>
    where T: Clone + Div<Output = T> + Rem<Output = T> + Zero + One
{
    #[inline]
    fn one() -> Self {
        Half(T::one() + T::one())
    }
}

impl<T: ToPrimitive> ToPrimitive for Half<T> {
    #[inline]
    fn to_i64(&self) -> Option<i64> {
        self.0.to_i64().and_then(|x| Half(x).try_get().ok())
    }
    #[inline]
    fn to_u64(&self) -> Option<u64> {
        self.0.to_u64().and_then(|x| Half(x).try_get().ok())
    }
}

impl Half<i32> where {
    /// Returns the phase `(-1)^j`.
    ///
    /// Panics if self is half-odd.
    #[inline]
    pub fn phase(self) -> f64 {
        if self.try_get().expect("phase is not real") % 2 == 0 {
            1.0
        } else {
            -1.0
        }
    }

    /// Returns `(2 j + 1)^(exponent / 2)`.
    #[inline]
    pub fn weight(self, exponent: i32) -> f64 {
        ((self.twice() + 1) as f64).powf(exponent as f64 / 2.0)
    }
}
<commit_msg>half: why is there a "+ 1/2"?<commit_after>//! Half-integers for angular momentum quantities.
use std::fmt;
use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
use num::{One, Signed, ToPrimitive, Zero};
use super::utils::{self, RangeInclusive};

/// Type that logically behaves like half-integers, but what is actually
/// stored is twice its logical value.
///
/// For example, `Half(3)` represents the fraction `3/2`.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord,
         Serialize, Deserialize)]
pub struct Half<T>(pub T);

impl<T> fmt::Display for Half<T>
    where T: fmt::Display + Div<Output = T> + Rem<Output = T> +
             Zero + One + Clone
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.clone().try_get() {
            Ok(x) => write!(f, "{}", x),
            Err(d) => write!(f, "{}/2", d.0),
        }
    }
}

impl<T: Add<Output = T> + Clone> From<T> for Half<T> {
    #[inline]
    fn from(t: T) -> Self {
        Half(t.clone() + t)
    }
}

impl<T> Half<T> {
    /// Unwrap to twice its logical value.
    #[inline]
    pub fn twice(self) -> T {
        self.0
    }
}

impl<T: Add<Output = T> + Clone> Half<T> {
    #[inline]
    pub fn double(self) -> Self {
        self.clone() + self
    }
}

impl<T: Signed> Half<T> {
    #[inline]
    pub fn abs(self) -> Half<T> {
        Half(self.twice().abs())
    }
}

impl<T: Signed + Ord> Half<T> {
    #[inline]
    pub fn in_multiplet_of(self, j: Half<T>) -> bool {
        self.abs().twice() < j.twice()
    }
}

impl<T: Clone + Div<Output = T> + Rem<Output = T> + Zero + One> Half<T> {
    /// Get the value if it's half-even.  Otherwise, returns `Err(self)`.
    #[inline]
    pub fn try_get(self) -> Result<T, Half<T>> {
        let two = T::one() + T::one();
        if (self.0.clone() % two.clone()).is_zero() {
            Ok(self.0 / two)
        } else {
            Err(self)
        }
    }
}

impl<T> Half<T>
    where T: Clone + fmt::Debug + Div<Output = T> + Rem<Output = T> +
             Zero + One,
{
    /// Equivalent to `try_get().unwrap()`.
    #[inline]
    pub fn unwrap(self) -> T {
        self.try_get().unwrap()
    }
}

impl<T: Ord + Sub> Half<T> {
    #[inline]
    pub fn abs_diff(self, other: Self) -> Half<T::Output> {
        if self.0 >= other.0 {
            self - other
        } else {
            other - self
        }
    }
}

impl<T: Add<Output = T> + Sub<Output = T> + One + Ord + Clone> Half<T> {
    /// Obtain the range of values that satisfy the triangular condition, i.e.
    /// the range from `|self − other|` to `self + other` (inclusive).
    #[inline]
    pub fn tri_range(self, other: Half<T>) -> RangeInclusive<Half<T>> {
        RangeInclusive {
            start: Half::abs_diff(self.clone(), other.clone()),
            end: self + other,
        }
    }

    #[inline]
    pub fn tri_range_2(
        (j1, j2): (Half<T>, Half<T>),
        (j3, j4): (Half<T>, Half<T>),
    ) -> RangeInclusive<Half<T>> {
        utils::intersect_range_inclusive(
            Half::tri_range(j1, j2),
            Half::tri_range(j3, j4),
        )
    }
}

impl<T: Neg<Output = T> + Clone> Half<T> {
    #[inline]
    pub fn multiplet(self) -> RangeInclusive<Self> {
        let end = Half(self.twice());
        RangeInclusive {
            start: -end.clone(),
            end,
        }
    }
}

impl<T: Add<U>, U> Add<Half<U>> for Half<T> {
    type Output = Half<T::Output>;
    #[inline]
    fn add(self, other: Half<U>) -> Self::Output {
        Half(self.0 + other.0)
    }
}

impl<T: Sub<U>, U> Sub<Half<U>> for Half<T> {
    type Output = Half<T::Output>;
    #[inline]
    fn sub(self, other: Half<U>) -> Self::Output {
        Half(self.0 - other.0)
    }
}

impl<T: Neg> Neg for Half<T> {
    type Output = Half<T::Output>;
    #[inline]
    fn neg(self) -> Self::Output {
        Half(-self.0)
    }
}

impl<T: Zero> Zero for Half<T> {
    #[inline]
    fn zero() -> Self {
        Half(Zero::zero())
    }
    #[inline]
    fn is_zero(&self) -> bool {
        self.0.is_zero()
    }
}

impl<T> Mul for Half<T>
    where T: Clone + Div<Output = T> + Rem<Output = T> + Zero + One
{
    type Output = Self;
    #[inline]
    fn mul(self, other: Self) -> Self::Output {
        Half(Half(self.0 * other.0).try_get().unwrap_or_else(|_| {
            panic!("cannot multiply two half-odd integers")
        }))
    }
}

impl<T> One for Half<T>
    where T: Clone + Div<Output = T> + Rem<Output = T> + Zero + One
{
    #[inline]
    fn one() -> Self {
        Half(T::one() + T::one())
    }
}

impl<T: ToPrimitive> ToPrimitive for Half<T> {
    #[inline]
    fn to_i64(&self) -> Option<i64> {
        self.0.to_i64().and_then(|x| Half(x).try_get().ok())
    }
    #[inline]
    fn to_u64(&self) -> Option<u64> {
        self.0.to_u64().and_then(|x| Half(x).try_get().ok())
    }
}

impl Half<i32> where {
    /// Returns the phase `(-1)^j`.
    ///
    /// Panics if self is half-odd.
    #[inline]
    pub fn phase(self) -> f64 {
        if self.try_get().expect("phase is not real") % 2 == 0 {
            1.0
        } else {
            -1.0
        }
    }

    /// Returns `(2 j + 1)^(exponent / 2)`.
    #[inline]
    pub fn weight(self, exponent: i32) -> f64 {
        ((self.twice() + 1) as f64).powf(exponent as f64 / 2.0)
    }
}
<|endoftext|>


<commit_before>use super::settings::Settings;
use futures::{self, Future, Stream};
use hyper::{Client, Method, Request, Uri};
use hyper::header::{ContentLength, ContentType};
use std::io::{Error, ErrorKind};
use std::str::{self, FromStr};
use std::time::Duration;
use tokio_core::reactor::{Core, Timeout};

pub struct Response {
    pub status: u16,
    pub body: String,
}

pub fn request(path: &str, request_body: Option<String>) -> Result<Response, Error> {
    let mut request = Request::new(Method::Post, try!(uri(path)));
    match request_body {
        Some(json) => {
            debug!("Request body: {}", json);
            request.headers_mut().set(ContentType::json());
            request.headers_mut().set(ContentLength(json.len() as u64));
            request.set_body(json);
        }
        _ => {
            debug!("Empty request body...");
        }
    }

    let mut status: u16 = 0;
    let mut body = String::new();
    {
        let mut core = Core::new().unwrap();
        let handle = core.handle();
        let client = Client::new(&handle);
        let work = client
            .request(request)
            .and_then(|res| {
                status = res.status().clone().into();
                res.body().for_each(|chunk| {
                    body.push_str(str::from_utf8(&*chunk).unwrap());
                    futures::future::ok(())
                })
            })
            .and_then(|_| {
                let timeout = Timeout::new(Duration::from_secs(1), &handle).unwrap();
                timeout.map_err(|e| e.into())
            })
            .map_err(|err| Error::new(ErrorKind::Other, err));
        try!(core.run(work));
    }

    debug!("Response status: {}", status);
    debug!("Response body: {}", body);
    Ok(Response { status, body })
}

fn uri(path: &str) -> Result<Uri, Error> {
    let mut addr = Settings::base_url();
    addr.push_str(path);
    debug!("Request URL: {}", addr);

    Uri::from_str(&addr).map_err(|err| Error::new(ErrorKind::Other, err))
}

#[cfg(test)]
mod tests {

    use super::{request, Response};
    use rand;
    use std::env;
    use test_server::{self, hyper};
    use test_server::futures::{Future, Stream};

    #[test]
    fn request_with_body_is_content_type_json() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let mut body = String::new();
        for _ in 0..10 {
            body.push(rand::random::<u8>() as char);
        }

        let _r = request("", Some(body));

        let (_method, _uri, _version, headers, _body) = server.request().unwrap().deconstruct();

        assert_eq!(headers.get_raw("content-type").unwrap(), "application/json");
    }

    #[test]
    fn send_request_body_if_given() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let mut body = String::new();
        for _ in 0..10 {
            body.push(rand::random::<u8>() as char);
        }
        let ref_content = body.as_bytes();

        let _r = request("", Some(body.clone()));

        let (_method, _uri, _version, _headers, body) = server.request().unwrap().deconstruct();
        let content = body.concat2().wait().unwrap();

        assert_eq!(ref_content, content.as_ref());
    }

    #[test]
    fn if_no_json_is_given_send_empty_request_body() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let _r = request("", None);

        let (_method, _uri, _version, _headers, body) = server.request().unwrap().deconstruct();

        assert!(body.concat2().wait().unwrap().is_empty());
    }

    #[test]
    fn response_contains_status_and_body() {
        let server = test_server::serve(None);
        server
            .reply()
            .status(hyper::StatusCode::InternalServerError)
            .body("hello world");
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let response: Response = request("", None).unwrap();
        assert_eq!(response.status, 500);
        assert_eq!(response.body, "hello world");
    }
}
<commit_msg>Revert "add explicit connection timeout"<commit_after>use super::settings::Settings;
use futures::{self, Future, Stream};
use hyper::{Client, Method, Request, Uri};
use hyper::header::{ContentLength, ContentType};
use std::io::{Error, ErrorKind};
use std::str::{self, FromStr};
use tokio_core::reactor::Core;

pub struct Response {
    pub status: u16,
    pub body: String,
}

pub fn request(path: &str, request_body: Option<String>) -> Result<Response, Error> {
    let mut request = Request::new(Method::Post, try!(uri(path)));
    match request_body {
        Some(json) => {
            debug!("Request body: {}", json);
            request.headers_mut().set(ContentType::json());
            request.headers_mut().set(ContentLength(json.len() as u64));
            request.set_body(json);
        }
        _ => {
            debug!("Empty request body...");
        }
    }

    let mut status: u16 = 0;
    let mut body = String::new();
    {
        let mut core = Core::new().unwrap();
        let client = Client::new(&core.handle());
        let work = client
            .request(request)
            .and_then(|res| {
                status = res.status().clone().into();
                res.body().for_each(|chunk| {
                    body.push_str(str::from_utf8(&*chunk).unwrap());
                    futures::future::ok(())
                })
            })
            .map_err(|err| Error::new(ErrorKind::Other, err));
        try!(core.run(work));
    }

    debug!("Response status: {}", status);
    debug!("Response body: {}", body);
    Ok(Response { status, body })
}

fn uri(path: &str) -> Result<Uri, Error> {
    let mut addr = Settings::base_url();
    addr.push_str(path);
    debug!("Request URL: {}", addr);

    Uri::from_str(&addr).map_err(|err| Error::new(ErrorKind::Other, err))
}

#[cfg(test)]
mod tests {

    use super::{request, Response};
    use rand;
    use std::env;
    use test_server::{self, hyper};
    use test_server::futures::{Future, Stream};

    #[test]
    fn request_with_body_is_content_type_json() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let mut body = String::new();
        for _ in 0..10 {
            body.push(rand::random::<u8>() as char);
        }

        let _r = request("", Some(body));

        let (_method, _uri, _version, headers, _body) = server.request().unwrap().deconstruct();

        assert_eq!(headers.get_raw("content-type").unwrap(), "application/json");
    }

    #[test]
    fn send_request_body_if_given() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let mut body = String::new();
        for _ in 0..10 {
            body.push(rand::random::<u8>() as char);
        }
        let ref_content = body.as_bytes();

        let _r = request("", Some(body.clone()));

        let (_method, _uri, _version, _headers, body) = server.request().unwrap().deconstruct();
        let content = body.concat2().wait().unwrap();

        assert_eq!(ref_content, content.as_ref());
    }

    #[test]
    fn if_no_json_is_given_send_empty_request_body() {
        let server = test_server::serve(None);
        server.reply().status(hyper::BadRequest);
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let _r = request("", None);

        let (_method, _uri, _version, _headers, body) = server.request().unwrap().deconstruct();

        assert!(body.concat2().wait().unwrap().is_empty());
    }

    #[test]
    fn response_contains_status_and_body() {
        let server = test_server::serve(None);
        server
            .reply()
            .status(hyper::StatusCode::InternalServerError)
            .body("hello world");
        env::set_var("K2_BASE_URL", format!("http://{}", &server.addr()));

        let response: Response = request("", None).unwrap();
        assert_eq!(response.status, 500);
        assert_eq!(response.body, "hello world");
    }
}
<|endoftext|>


<commit_before>//! International domain names
//!
//! https://url.spec.whatwg.org/#idna

use idna_mapping::TABLE;
use punycode;
use std::ascii::AsciiExt;
use unicode_normalization::UnicodeNormalization;
use unicode_normalization::char::canonical_combining_class;
use unicode_bidi::{BidiClass, bidi_class};

#[derive(Debug)]
pub enum Mapping {
    Valid,
    Ignored,
    Mapped(&'static str),
    Deviation(&'static str),
    Disallowed,
    DisallowedStd3Valid,
    DisallowedStd3Mapped(&'static str),
}

pub struct Range {
    pub from: char,
    pub to: char,
    pub mapping: Mapping,
}

fn find_char(codepoint: char) -> &'static Mapping {
    let mut min = 0;
    let mut max = TABLE.len() - 1;
    while max > min {
        let mid = (min + max) >> 1;
        if codepoint > TABLE[mid].to {
           min = mid;
        } else if codepoint < TABLE[mid].from {
            max = mid;
        } else {
            min = mid;
            max = mid;
        }
    }
    &TABLE[min].mapping
}

fn map_char(codepoint: char, flags: Uts46Flags, output: &mut String) -> Result<(), Error> {
    match *find_char(codepoint) {
        Mapping::Valid => output.push(codepoint),
        Mapping::Ignored => {},
        Mapping::Mapped(mapping) => output.push_str(mapping),
        Mapping::Deviation(mapping) => {
            if flags.transitional_processing {
                output.push_str(mapping)
            } else {
                output.push(codepoint)
            }
        }
        Mapping::Disallowed => return Err(Error::DissallowedCharacter),
        Mapping::DisallowedStd3Valid => {
            if flags.use_std3_ascii_rules {
                return Err(Error::DissallowedByStd3AsciiRules);
            } else {
                output.push(codepoint)
            }
        }
        Mapping::DisallowedStd3Mapped(mapping) => {
            if flags.use_std3_ascii_rules {
                return Err(Error::DissallowedMappedInStd3);
            } else {
                output.push_str(mapping)
            }
        }
    }
    Ok(())
}

// XXX: This passes the tests, but isn't correct
//      Should return true if General_Category=Mark
//      We should try to get this info into unicode_normalization
fn is_combining_mark(c: char) -> bool {
    canonical_combining_class(c) != 0
}

// http://tools.ietf.org/html/rfc5893#section-2
fn passes_bidi(label: &str, transitional_processing: bool) -> bool {
    let mut chars = label.chars();
    let class = match chars.next() {
        Some(c) => bidi_class(c),
        None => return true, // empty string
    };

    if class == BidiClass::L
       || (class == BidiClass::ON && transitional_processing) // starts with \u200D
       || (class == BidiClass::ES && transitional_processing) // hack: 1.35.+33.49
       || class == BidiClass::EN // hack: starts with number 0à.\u05D0
    { // LTR
        // Rule 5
        loop {
            match chars.next() {
                Some(c) => {
                    let c = bidi_class(c);
                    if !matches!(c, BidiClass::L | BidiClass::EN |
                                    BidiClass::ES | BidiClass::CS |
                                    BidiClass::ET | BidiClass::ON |
                                    BidiClass::BN | BidiClass::NSM) {
                        return false;
                    }
                },
                None => { break; },
            }
        }

        // Rule 6
        let mut rev_chars = label.chars().rev();
        let mut last = rev_chars.next();
        loop { // must end in L or EN followed by 0 or more NSM
            match last {
                Some(c) if bidi_class(c) == BidiClass::NSM => {
                    last = rev_chars.next();
                    continue;
                }
                _ => { break; },
            }
        }

        // TODO: does not pass for àˇ.\u05D0
        // match last {
        //     Some(c) if bidi_class(c) == BidiClass::L
        //             || bidi_class(c) == BidiClass::EN => {},
        //     Some(c) => { return false; },
        //     _ => {}
        // }

    } else if class == BidiClass::R || class == BidiClass::AL { // RTL
        let mut found_en = false;
        let mut found_an = false;

        // Rule 2
        loop {
            match chars.next() {
                Some(c) => {
                    let char_class = bidi_class(c);

                    if char_class == BidiClass::EN {
                        found_en = true;
                    }
                    if char_class == BidiClass::AN {
                        found_an = true;
                    }

                    if !matches!(char_class, BidiClass::R | BidiClass::AL |
                                             BidiClass::AN | BidiClass::EN |
                                             BidiClass::ES | BidiClass::CS |
                                             BidiClass::ET | BidiClass::ON |
                                             BidiClass::BN | BidiClass::NSM) {
                        return false;
                    }
                },
                None => { break; },
            }
        }
        // Rule 3
        let mut rev_chars = label.chars().rev();
        let mut last = rev_chars.next();
        loop { // must end in L or EN followed by 0 or more NSM
            match last {
                Some(c) if bidi_class(c) == BidiClass::NSM => {
                    last = rev_chars.next();
                    continue;
                }
                _ => { break; },
            }
        }
        match last {
            Some(c) if matches!(bidi_class(c), BidiClass::R | BidiClass::AL |
                                               BidiClass::EN | BidiClass::AN) => {},
            _ => { return false; }
        }

        // Rule 4
        if found_an && found_en {
            return false;
        }
    } else {
        // Rule 2: Should start with L or R/AL
        return false;
    }

    return true;
}

/// http://www.unicode.org/reports/tr46/#Validity_Criteria
fn validate(label: &str, flags: Uts46Flags) -> Result<(), Error> {
    let normalized: String = label.nfc().collect();
    if normalized != label {
        return Err(Error::ValidityCriteria);
    }

    // Can not contain '.' since the input is from .split('.')
    if {
        let mut chars = label.chars().skip(2);
        let third = chars.next();
        let fourth = chars.next();
        (third, fourth) == (Some('-'), Some('-'))
    } || label.starts_with("-")
        || label.ends_with("-")
        || label.chars().next().map_or(false, is_combining_mark)
        || label.chars().any(|c| match *find_char(c) {
            Mapping::Valid => false,
            Mapping::Deviation(_) => flags.transitional_processing,
            Mapping::DisallowedStd3Valid => flags.use_std3_ascii_rules,
            _ => true,
        })
        || !passes_bidi(label, flags.transitional_processing)
    {
        Err(Error::ValidityCriteria)
    } else {
        Ok(())
    }
}

/// http://www.unicode.org/reports/tr46/#Processing
fn uts46_processing(domain: &str, flags: Uts46Flags) -> Result<String, Error> {
    let mut mapped = String::new();
    for c in domain.chars() {
        try!(map_char(c, flags, &mut mapped))
    }
    let normalized: String = mapped.nfc().collect();
    let mut validated = String::new();
    for label in normalized.split('.') {
        if validated.len() > 0 {
            validated.push('.');
        }
        if label.starts_with("xn--") {
            match punycode::decode_to_string(&label["xn--".len()..]) {
                Some(label) => {
                    try!(validate(&label, Uts46Flags {
                        transitional_processing: false,
                        ..flags
                    }));
                    validated.push_str(&label)
                }
                None => return Err(Error::PunycodeError),
            }
        } else {
            try!(validate(label, flags));
            validated.push_str(label)
        }
    }
    Ok(validated)
}

#[derive(Copy, Clone)]
pub struct Uts46Flags {
   pub use_std3_ascii_rules: bool,
   pub transitional_processing: bool,
   pub verify_dns_length: bool,
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum Error {
    PunycodeError,
    ValidityCriteria,
    DissallowedByStd3AsciiRules,
    DissallowedMappedInStd3,
    DissallowedCharacter,
    TooLongForDns,
}

/// http://www.unicode.org/reports/tr46/#ToASCII
pub fn uts46_to_ascii(domain: &str, flags: Uts46Flags) -> Result<String, Error> {
    let mut result = String::new();
    for label in try!(uts46_processing(domain, flags)).split('.') {
        if result.len() > 0 {
            result.push('.');
        }
        if label.is_ascii() {
            result.push_str(label);
        } else {
            match punycode::encode_str(label) {
                Some(x) => {
                    result.push_str("xn--");
                    result.push_str(&x);
                },
                None => return Err(Error::PunycodeError)
            }
        }
    }

    if flags.verify_dns_length {
        let domain = if result.ends_with(".") { &result[..result.len()-1]  } else { &*result };
        if domain.len() < 1 || domain.len() > 253 ||
                domain.split('.').any(|label| label.len() < 1 || label.len() > 63) {
            return Err(Error::TooLongForDns)
        }
    }
    Ok(result)
}

/// https://url.spec.whatwg.org/#concept-domain-to-ascii
pub fn domain_to_ascii(domain: &str) -> Result<String, Error> {
    uts46_to_ascii(domain, Uts46Flags {
        use_std3_ascii_rules: false,
        transitional_processing: true, // XXX: switch when Firefox does
        verify_dns_length: false,
    })
}
<commit_msg>Use Iterator::ne to avoid a string allocation.<commit_after>//! International domain names
//!
//! https://url.spec.whatwg.org/#idna

use idna_mapping::TABLE;
use punycode;
use std::ascii::AsciiExt;
use unicode_normalization::UnicodeNormalization;
use unicode_normalization::char::canonical_combining_class;
use unicode_bidi::{BidiClass, bidi_class};

#[derive(Debug)]
pub enum Mapping {
    Valid,
    Ignored,
    Mapped(&'static str),
    Deviation(&'static str),
    Disallowed,
    DisallowedStd3Valid,
    DisallowedStd3Mapped(&'static str),
}

pub struct Range {
    pub from: char,
    pub to: char,
    pub mapping: Mapping,
}

fn find_char(codepoint: char) -> &'static Mapping {
    let mut min = 0;
    let mut max = TABLE.len() - 1;
    while max > min {
        let mid = (min + max) >> 1;
        if codepoint > TABLE[mid].to {
           min = mid;
        } else if codepoint < TABLE[mid].from {
            max = mid;
        } else {
            min = mid;
            max = mid;
        }
    }
    &TABLE[min].mapping
}

fn map_char(codepoint: char, flags: Uts46Flags, output: &mut String) -> Result<(), Error> {
    match *find_char(codepoint) {
        Mapping::Valid => output.push(codepoint),
        Mapping::Ignored => {},
        Mapping::Mapped(mapping) => output.push_str(mapping),
        Mapping::Deviation(mapping) => {
            if flags.transitional_processing {
                output.push_str(mapping)
            } else {
                output.push(codepoint)
            }
        }
        Mapping::Disallowed => return Err(Error::DissallowedCharacter),
        Mapping::DisallowedStd3Valid => {
            if flags.use_std3_ascii_rules {
                return Err(Error::DissallowedByStd3AsciiRules);
            } else {
                output.push(codepoint)
            }
        }
        Mapping::DisallowedStd3Mapped(mapping) => {
            if flags.use_std3_ascii_rules {
                return Err(Error::DissallowedMappedInStd3);
            } else {
                output.push_str(mapping)
            }
        }
    }
    Ok(())
}

// XXX: This passes the tests, but isn't correct
//      Should return true if General_Category=Mark
//      We should try to get this info into unicode_normalization
fn is_combining_mark(c: char) -> bool {
    canonical_combining_class(c) != 0
}

// http://tools.ietf.org/html/rfc5893#section-2
fn passes_bidi(label: &str, transitional_processing: bool) -> bool {
    let mut chars = label.chars();
    let class = match chars.next() {
        Some(c) => bidi_class(c),
        None => return true, // empty string
    };

    if class == BidiClass::L
       || (class == BidiClass::ON && transitional_processing) // starts with \u200D
       || (class == BidiClass::ES && transitional_processing) // hack: 1.35.+33.49
       || class == BidiClass::EN // hack: starts with number 0à.\u05D0
    { // LTR
        // Rule 5
        loop {
            match chars.next() {
                Some(c) => {
                    let c = bidi_class(c);
                    if !matches!(c, BidiClass::L | BidiClass::EN |
                                    BidiClass::ES | BidiClass::CS |
                                    BidiClass::ET | BidiClass::ON |
                                    BidiClass::BN | BidiClass::NSM) {
                        return false;
                    }
                },
                None => { break; },
            }
        }

        // Rule 6
        let mut rev_chars = label.chars().rev();
        let mut last = rev_chars.next();
        loop { // must end in L or EN followed by 0 or more NSM
            match last {
                Some(c) if bidi_class(c) == BidiClass::NSM => {
                    last = rev_chars.next();
                    continue;
                }
                _ => { break; },
            }
        }

        // TODO: does not pass for àˇ.\u05D0
        // match last {
        //     Some(c) if bidi_class(c) == BidiClass::L
        //             || bidi_class(c) == BidiClass::EN => {},
        //     Some(c) => { return false; },
        //     _ => {}
        // }

    } else if class == BidiClass::R || class == BidiClass::AL { // RTL
        let mut found_en = false;
        let mut found_an = false;

        // Rule 2
        loop {
            match chars.next() {
                Some(c) => {
                    let char_class = bidi_class(c);

                    if char_class == BidiClass::EN {
                        found_en = true;
                    }
                    if char_class == BidiClass::AN {
                        found_an = true;
                    }

                    if !matches!(char_class, BidiClass::R | BidiClass::AL |
                                             BidiClass::AN | BidiClass::EN |
                                             BidiClass::ES | BidiClass::CS |
                                             BidiClass::ET | BidiClass::ON |
                                             BidiClass::BN | BidiClass::NSM) {
                        return false;
                    }
                },
                None => { break; },
            }
        }
        // Rule 3
        let mut rev_chars = label.chars().rev();
        let mut last = rev_chars.next();
        loop { // must end in L or EN followed by 0 or more NSM
            match last {
                Some(c) if bidi_class(c) == BidiClass::NSM => {
                    last = rev_chars.next();
                    continue;
                }
                _ => { break; },
            }
        }
        match last {
            Some(c) if matches!(bidi_class(c), BidiClass::R | BidiClass::AL |
                                               BidiClass::EN | BidiClass::AN) => {},
            _ => { return false; }
        }

        // Rule 4
        if found_an && found_en {
            return false;
        }
    } else {
        // Rule 2: Should start with L or R/AL
        return false;
    }

    return true;
}

/// http://www.unicode.org/reports/tr46/#Validity_Criteria
fn validate(label: &str, flags: Uts46Flags) -> Result<(), Error> {
    if label.nfc().ne(label.chars()) {
        return Err(Error::ValidityCriteria);
    }

    // Can not contain '.' since the input is from .split('.')
    if {
        let mut chars = label.chars().skip(2);
        let third = chars.next();
        let fourth = chars.next();
        (third, fourth) == (Some('-'), Some('-'))
    } || label.starts_with("-")
        || label.ends_with("-")
        || label.chars().next().map_or(false, is_combining_mark)
        || label.chars().any(|c| match *find_char(c) {
            Mapping::Valid => false,
            Mapping::Deviation(_) => flags.transitional_processing,
            Mapping::DisallowedStd3Valid => flags.use_std3_ascii_rules,
            _ => true,
        })
        || !passes_bidi(label, flags.transitional_processing)
    {
        Err(Error::ValidityCriteria)
    } else {
        Ok(())
    }
}

/// http://www.unicode.org/reports/tr46/#Processing
fn uts46_processing(domain: &str, flags: Uts46Flags) -> Result<String, Error> {
    let mut mapped = String::new();
    for c in domain.chars() {
        try!(map_char(c, flags, &mut mapped))
    }
    let normalized: String = mapped.nfc().collect();
    let mut validated = String::new();
    for label in normalized.split('.') {
        if validated.len() > 0 {
            validated.push('.');
        }
        if label.starts_with("xn--") {
            match punycode::decode_to_string(&label["xn--".len()..]) {
                Some(label) => {
                    try!(validate(&label, Uts46Flags {
                        transitional_processing: false,
                        ..flags
                    }));
                    validated.push_str(&label)
                }
                None => return Err(Error::PunycodeError),
            }
        } else {
            try!(validate(label, flags));
            validated.push_str(label)
        }
    }
    Ok(validated)
}

#[derive(Copy, Clone)]
pub struct Uts46Flags {
   pub use_std3_ascii_rules: bool,
   pub transitional_processing: bool,
   pub verify_dns_length: bool,
}

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum Error {
    PunycodeError,
    ValidityCriteria,
    DissallowedByStd3AsciiRules,
    DissallowedMappedInStd3,
    DissallowedCharacter,
    TooLongForDns,
}

/// http://www.unicode.org/reports/tr46/#ToASCII
pub fn uts46_to_ascii(domain: &str, flags: Uts46Flags) -> Result<String, Error> {
    let mut result = String::new();
    for label in try!(uts46_processing(domain, flags)).split('.') {
        if result.len() > 0 {
            result.push('.');
        }
        if label.is_ascii() {
            result.push_str(label);
        } else {
            match punycode::encode_str(label) {
                Some(x) => {
                    result.push_str("xn--");
                    result.push_str(&x);
                },
                None => return Err(Error::PunycodeError)
            }
        }
    }

    if flags.verify_dns_length {
        let domain = if result.ends_with(".") { &result[..result.len()-1]  } else { &*result };
        if domain.len() < 1 || domain.len() > 253 ||
                domain.split('.').any(|label| label.len() < 1 || label.len() > 63) {
            return Err(Error::TooLongForDns)
        }
    }
    Ok(result)
}

/// https://url.spec.whatwg.org/#concept-domain-to-ascii
pub fn domain_to_ascii(domain: &str) -> Result<String, Error> {
    uts46_to_ascii(domain, Uts46Flags {
        use_std3_ascii_rules: false,
        transitional_processing: true, // XXX: switch when Firefox does
        verify_dns_length: false,
    })
}
<|endoftext|>


<commit_before>use std::iter;
use std::fmt::{self, Debug};
use std::cmp::{Eq, PartialEq};
use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point, WlcOutput};
use rustwlc::render::{write_pixels, wlc_pixel_format};
use cairo::{Context, ImageSurface, Format, Operator, Status, SolidPattern};
use cairo::prelude::{SurfaceExt};

use super::super::borders::Borders;
use super::base::{BaseDraw, Drawable, DrawErr};
use super::color::Color;

/// Draws the borders with variable width.
///
/// This can be used to hide certain borders,
/// eg when touching the side of the screen.
pub struct EdgeDraw {
    base: BaseDraw,
    color: Color
}

impl EdgeDraw {
    pub fn new(base: BaseDraw, color: Color) -> Self {
        EdgeDraw {
            base: base,
            color: color
        }
    }

    fn draw_left_border(mut self,
                        mut x: f64,
                        mut y: f64,
                        mut w: f64,
                        mut h: f64,
                        border_geometry: Geometry)
                        -> Result<Self, DrawErr> {
        // TODO This doesn't seem right, wouldn't this break on multi-head output?
        let output_res = WlcOutput::focused().get_resolution()
            .expect("Could not get focused output's resolution");
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32{
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        if w < 0.0 {
            self.base.rectangle(0.0, 0.0, 0.0, 0.0);
            self.base = try!(self.base.check_cairo());
            self.base.fill();
            self.base = try!(self.base.check_cairo());
            return Ok(self)
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }
}

impl Drawable for EdgeDraw {
    fn draw(mut self, view_g: Geometry) -> Result<Borders, DrawErr> {
        let mut border_g = view_g;
        let thickness = self.base.borders().thickness;
        let edge_thickness = thickness / 2;
        // Even though we ignore these origin values,
        // the renderer needs to know where to start drawing the box.
        border_g.origin.x -= edge_thickness as i32;
        border_g.origin.y -= edge_thickness as i32;
        border_g.size.w += thickness;
        border_g.size.h += thickness;
        //warn!("border: {:#?}", border_g);
        //warn!("view_g: {:#?}", view_g);

        //let mut base = self.base;
        self.base.set_source_rgba(0.0,0.0,0.0,0.0);
        self.base.paint();
        self.base.set_color_source(self.color);

        let Size { w, h } = border_g.size;
        let Point { x, y } = border_g.origin;
        let (x, y, w, h) = (x as f64,
                            y as f64,
                            w as f64,
                            h as f64);
        self = try!(self.draw_left_border(x, y, edge_thickness as f64, h, border_g));
        Ok(self.base.finish(border_g))
    }
}
<commit_msg>Added drawing the other borders<commit_after>use std::iter;
use std::fmt::{self, Debug};
use std::cmp::{Eq, PartialEq};
use std::ops::{Deref, DerefMut};
use rustwlc::{Geometry, Size, Point, WlcOutput};
use rustwlc::render::{write_pixels, wlc_pixel_format};
use cairo::{Context, ImageSurface, Format, Operator, Status, SolidPattern};
use cairo::prelude::{SurfaceExt};

use super::super::borders::Borders;
use super::base::{BaseDraw, Drawable, DrawErr};
use super::color::Color;

/// Draws the borders with variable width.
///
/// This can be used to hide certain borders,
/// eg when touching the side of the screen.
pub struct EdgeDraw {
    base: BaseDraw,
    color: Color
}

impl EdgeDraw {
    pub fn new(base: BaseDraw, color: Color) -> Self {
        EdgeDraw {
            base: base,
            color: color
        }
    }

    fn draw_left_border(mut self,
                        mut x: f64,
                        mut y: f64,
                        mut w: f64,
                        mut h: f64,
                        border_geometry: Geometry,
                        output_res: Size)
                        -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32{
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y as u32 + border_geometry.size.h) - output_res.h;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_right_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         mut w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size)
                         -> Result<Self, DrawErr> {
        // yay clamping
        if border_geometry.origin.x < 0 {
            x += border_geometry.origin.x as f64;
        }
        if y < 0.0 {
            h += y;
        }
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y as u32 + border_geometry.size.h) - output_res.h;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_top_border(mut self,
                         mut x: f64,
                         mut y: f64,
                         mut w: f64,
                         mut h: f64,
                         border_geometry: Geometry,
                         output_res: Size)
                         -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if y < 0.0 {
            h += y;
        }
        x = 0.0;
        y = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        if border_geometry.origin.y + border_geometry.size.h as i32 > output_res.h as i32 {
            let offset = (border_geometry.origin.y as u32 + border_geometry.size.h) - output_res.h;
            y += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }

    fn draw_bottom_border(mut self,
                            mut x: f64,
                            mut y: f64,
                            mut w: f64,
                            mut h: f64,
                            border_geometry: Geometry,
                            output_res: Size)
                            -> Result<Self, DrawErr> {
        // yay clamping
        if x < 0.0 {
            w += x;
        }
        if border_geometry.origin.y < 0 {
            y += border_geometry.origin.y as f64;
        }
        x = 0.0;
        if border_geometry.origin.x + border_geometry.size.w as i32 > output_res.w as i32 {
            let offset = (border_geometry.origin.x as u32 + border_geometry.size.w) - output_res.w;
            x += offset as f64;
        }
        self.base.rectangle(x, y, w, h);
        self.base = try!(self.base.check_cairo());
        self.base.fill();
        self.base = try!(self.base.check_cairo());
        Ok(self)
    }
}

impl Drawable for EdgeDraw {
    fn draw(mut self, view_g: Geometry) -> Result<Borders, DrawErr> {
        let mut border_g = view_g;
        let thickness = self.base.borders().thickness;
        let edge_thickness = thickness / 2;
        // TODO This doesn't seem right, wouldn't this break on multi-head output?
        let output_res = WlcOutput::focused().get_resolution()
            .expect("Could not get focused output's resolution");
        // Even though we ignore these origin values,
        // the renderer needs to know where to start drawing the box.
        border_g.origin.x -= edge_thickness as i32;
        border_g.origin.y -= edge_thickness as i32;
        border_g.size.w += thickness;
        border_g.size.h += thickness;

        self.base.set_source_rgba(0.0, 0.0, 0.0, 0.0);
        self.base.paint();
        self.base.set_color_source(self.color);

        let Size { w, h } = border_g.size;
        let Point { x, y } = border_g.origin;
        // basically after everything after this point is floating point arithmetic
        // whee!
        let (x, y, w, h) = (x as f64,
                            y as f64,
                            w as f64,
                            h as f64);
        let edge_thickness = edge_thickness as f64;
        self = self.draw_left_border(x, y, edge_thickness, h, border_g, output_res)?
        .draw_right_border(w - edge_thickness, y, edge_thickness, h, border_g, output_res)?
        .draw_top_border(x, y, w, edge_thickness, border_g, output_res)?
        .draw_bottom_border(x, h, w, -edge_thickness, border_g, output_res)?;

        Ok(self.base.finish(border_g))
    }
}
<|endoftext|>


<commit_before>use std::fmt::Write;

use hir::{
    AdtDef, FieldSource, HasSource,
    db::HirDatabase,
};
use ra_syntax::ast::{self, AstNode};

use crate::{AssistCtx, Assist, AssistId};

fn is_trivial_arm(arm: &ast::MatchArm) -> bool {
    for (i, p) in arm.pats().enumerate() {
        if i > 0 {
            return false;
        }

        match p.kind() {
            ast::PatKind::PlaceholderPat(_) => {}
            _ => {
                return false;
            }
        };
    }
    return true;
}

pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?;

    // We already have some match arms, so we don't provide any assists.
    // Unless if there is only one trivial match arm possibly created
    // by match postfix complete. Trivial match arm is the catch all arm.
    match match_expr.match_arm_list() {
        Some(arm_list) => {
            for (i, a) in arm_list.arms().enumerate() {
                if i > 0 {
                    return None;
                }

                if !is_trivial_arm(a) {
                    return None;
                }
            }
        }
        _ => {}
    }

    let expr = match_expr.expr()?;
    let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, expr.syntax(), None);
    let match_expr_ty = analyzer.type_of(ctx.db, expr)?;
    let enum_def = analyzer.autoderef(ctx.db, match_expr_ty).find_map(|ty| match ty.as_adt() {
        Some((AdtDef::Enum(e), _)) => Some(e),
        _ => None,
    })?;
    let enum_name = enum_def.name(ctx.db)?;
    let db = ctx.db;

    ctx.add_action(AssistId("fill_match_arms"), "fill match arms", |edit| {
        let mut buf = format!("match {} {{\n", expr.syntax().text().to_string());
        let variants = enum_def.variants(db);
        for variant in variants {
            let name = match variant.name(db) {
                Some(it) => it,
                None => continue,
            };
            write!(&mut buf, "    {}::{}", enum_name, name.to_string()).unwrap();

            let pat = variant
                .fields(db)
                .into_iter()
                .map(|field| {
                    let name = field.name(db).to_string();
                    let src = field.source(db);
                    match src.ast {
                        FieldSource::Named(_) => name,
                        FieldSource::Pos(_) => "_".to_string(),
                    }
                })
                .collect::<Vec<_>>();

            match pat.first().map(|s| s.as_str()) {
                Some("_") => write!(&mut buf, "({})", pat.join(", ")).unwrap(),
                Some(_) => write!(&mut buf, "{{{}}}", pat.join(", ")).unwrap(),
                None => (),
            };

            buf.push_str(" => (),\n");
        }
        buf.push_str("}");
        edit.target(match_expr.syntax().range());
        edit.set_cursor(expr.syntax().range().start());
        edit.replace_node_and_indent(match_expr.syntax(), buf);
    });

    ctx.build()
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_target};

    use super::fill_match_arms;

    #[test]
    fn fill_match_arms_empty_body() {
        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn main() {
                let a = A::As;
                match a<|> {}
            }
            "#,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn main() {
                let a = A::As;
                match <|>a {
                    A::As => (),
                    A::Bs => (),
                    A::Cs(_) => (),
                    A::Ds(_, _) => (),
                    A::Es{x, y} => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn test_fill_match_arm_refs() {
        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
            }

            fn foo(a: &A) {
                match a<|> {
                }
            }
            "#,
            r#"
            enum A {
                As,
            }

            fn foo(a: &A) {
                match <|>a {
                    A::As => (),
                }
            }
            "#,
        );

        check_assist(
            fill_match_arms,
            r#"
            enum A {
                Es{x: usize, y: usize}
            }

            fn foo(a: &mut A) {
                match a<|> {
                }
            }
            "#,
            r#"
            enum A {
                Es{x: usize, y: usize}
            }

            fn foo(a: &mut A) {
                match <|>a {
                    A::Es{x, y} => (),
                }
            }
            "#,
        );

        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match &E::X<|>
            }
            "#,
            r#"
            enum E { X, Y}

            fn main() {
                match <|>&E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_match_arms_no_body() {
        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match E::X<|>
            }
            "#,
            r#"
            enum E { X, Y}

            fn main() {
                match <|>E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_match_arms_target() {
        check_assist_target(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match E::X<|> {}
            }
            "#,
            "match E::X {}",
        );
    }

    #[test]
    fn fill_match_arms_trivial_arm() {
        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y }

            fn main() {
                match E::X {
                    <|>_ => {},
                }
            }
            "#,
            r#"
            enum E { X, Y }

            fn main() {
                match <|>E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }
}
<commit_msg>Review 1<commit_after>use std::fmt::Write;
use itertools::Itertools;

use hir::{
    AdtDef, FieldSource, HasSource,
    db::HirDatabase,
};
use ra_syntax::ast::{self, AstNode};

use crate::{AssistCtx, Assist, AssistId};

fn is_trivial_arm(arm: &ast::MatchArm) -> bool {
    fn single_pattern(arm: &ast::MatchArm) -> Option<ast::PatKind> {
        let (pat,) = arm.pats().collect_tuple()?;
        Some(pat.kind())
    }
    match single_pattern(arm) {
        Some(ast::PatKind::PlaceholderPat(..)) => true,
        _ => false,
    }
}

pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
    let match_expr = ctx.node_at_offset::<ast::MatchExpr>()?;

    // We already have some match arms, so we don't provide any assists.
    // Unless if there is only one trivial match arm possibly created
    // by match postfix complete. Trivial match arm is the catch all arm.
    match match_expr.match_arm_list() {
        Some(arm_list) => {
            let mut arm_iter = arm_list.arms();
            let first = arm_iter.next();

            match first {
                // If there arm list is empty or there is only one trivial arm, then proceed.
                Some(arm) if is_trivial_arm(arm) => {
                    if arm_iter.next() != None {
                        return None;
                    }
                }
                None => {}

                _ => {
                    return None;
                }
            }
        }
        _ => {}
    }

    let expr = match_expr.expr()?;
    let analyzer = hir::SourceAnalyzer::new(ctx.db, ctx.frange.file_id, expr.syntax(), None);
    let match_expr_ty = analyzer.type_of(ctx.db, expr)?;
    let enum_def = analyzer.autoderef(ctx.db, match_expr_ty).find_map(|ty| match ty.as_adt() {
        Some((AdtDef::Enum(e), _)) => Some(e),
        _ => None,
    })?;
    let enum_name = enum_def.name(ctx.db)?;
    let db = ctx.db;

    ctx.add_action(AssistId("fill_match_arms"), "fill match arms", |edit| {
        let mut buf = format!("match {} {{\n", expr.syntax().text().to_string());
        let variants = enum_def.variants(db);
        for variant in variants {
            let name = match variant.name(db) {
                Some(it) => it,
                None => continue,
            };
            write!(&mut buf, "    {}::{}", enum_name, name.to_string()).unwrap();

            let pat = variant
                .fields(db)
                .into_iter()
                .map(|field| {
                    let name = field.name(db).to_string();
                    let src = field.source(db);
                    match src.ast {
                        FieldSource::Named(_) => name,
                        FieldSource::Pos(_) => "_".to_string(),
                    }
                })
                .collect::<Vec<_>>();

            match pat.first().map(|s| s.as_str()) {
                Some("_") => write!(&mut buf, "({})", pat.join(", ")).unwrap(),
                Some(_) => write!(&mut buf, "{{{}}}", pat.join(", ")).unwrap(),
                None => (),
            };

            buf.push_str(" => (),\n");
        }
        buf.push_str("}");
        edit.target(match_expr.syntax().range());
        edit.set_cursor(expr.syntax().range().start());
        edit.replace_node_and_indent(match_expr.syntax(), buf);
    });

    ctx.build()
}

#[cfg(test)]
mod tests {
    use crate::helpers::{check_assist, check_assist_target};

    use super::fill_match_arms;

    #[test]
    fn fill_match_arms_empty_body() {
        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn main() {
                let a = A::As;
                match a<|> {}
            }
            "#,
            r#"
            enum A {
                As,
                Bs,
                Cs(String),
                Ds(String, String),
                Es{x: usize, y: usize}
            }

            fn main() {
                let a = A::As;
                match <|>a {
                    A::As => (),
                    A::Bs => (),
                    A::Cs(_) => (),
                    A::Ds(_, _) => (),
                    A::Es{x, y} => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn test_fill_match_arm_refs() {
        check_assist(
            fill_match_arms,
            r#"
            enum A {
                As,
            }

            fn foo(a: &A) {
                match a<|> {
                }
            }
            "#,
            r#"
            enum A {
                As,
            }

            fn foo(a: &A) {
                match <|>a {
                    A::As => (),
                }
            }
            "#,
        );

        check_assist(
            fill_match_arms,
            r#"
            enum A {
                Es{x: usize, y: usize}
            }

            fn foo(a: &mut A) {
                match a<|> {
                }
            }
            "#,
            r#"
            enum A {
                Es{x: usize, y: usize}
            }

            fn foo(a: &mut A) {
                match <|>a {
                    A::Es{x, y} => (),
                }
            }
            "#,
        );

        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match &E::X<|>
            }
            "#,
            r#"
            enum E { X, Y}

            fn main() {
                match <|>&E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_match_arms_no_body() {
        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match E::X<|>
            }
            "#,
            r#"
            enum E { X, Y}

            fn main() {
                match <|>E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }

    #[test]
    fn fill_match_arms_target() {
        check_assist_target(
            fill_match_arms,
            r#"
            enum E { X, Y}

            fn main() {
                match E::X<|> {}
            }
            "#,
            "match E::X {}",
        );
    }

    #[test]
    fn fill_match_arms_trivial_arm() {
        check_assist(
            fill_match_arms,
            r#"
            enum E { X, Y }

            fn main() {
                match E::X {
                    <|>_ => {},
                }
            }
            "#,
            r#"
            enum E { X, Y }

            fn main() {
                match <|>E::X {
                    E::X => (),
                    E::Y => (),
                }
            }
            "#,
        );
    }
}
<|endoftext|>