<commit_before>//! `GenericArray` iterator implementation.

use super::{ArrayLength, GenericArray};
use core::iter::FusedIterator;
use core::mem::ManuallyDrop;
use core::{cmp, fmt, ptr, mem};

/// An iterator that moves out of a `GenericArray`
pub struct GenericArrayIter<T, N: ArrayLength<T>> {
    // Invariants: index <= index_back <= N
    // Only values in array[index..index_back] are alive at any given time.
    // Values from array[..index] and array[index_back..] are already moved/dropped.
    array: ManuallyDrop<GenericArray<T, N>>,
    index: usize,
    index_back: usize,
}

#[cfg(test)]
mod test {
    use super::*;

    fn send<I: Send>(_iter: I) {}

    #[test]
    fn test_send_iter() {
        send(GenericArray::from([1, 2, 3, 4]).into_iter());
    }
}

impl<T, N> GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    /// Returns the remaining items of this iterator as a slice
    #[inline]
    pub fn as_slice(&self) -> &[T] {
        &self.array.as_slice()[self.index..self.index_back]
    }

    /// Returns the remaining items of this iterator as a mutable slice
    #[inline]
    pub fn as_mut_slice(&mut self) -> &mut [T] {
        &mut self.array.as_mut_slice()[self.index..self.index_back]
    }
}

impl<T, N> IntoIterator for GenericArray<T, N>
where
    N: ArrayLength<T>,
{
    type Item = T;
    type IntoIter = GenericArrayIter<T, N>;

    fn into_iter(self) -> Self::IntoIter {
        GenericArrayIter {
            array: ManuallyDrop::new(self),
            index: 0,
            index_back: N::USIZE,
        }
    }
}

// Based on work in rust-lang/rust#49000
impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("GenericArrayIter")
            .field(&self.as_slice())
            .finish()
    }
}

impl<T, N> Drop for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    #[inline]
    fn drop(&mut self) {
        if mem::needs_drop::<T>() {
            // Drop values that are still alive.
            for p in self.as_mut_slice() {
                unsafe {
                    ptr::drop_in_place(p);
                }
            }
        }
    }
}

// Based on work in rust-lang/rust#49000
impl<T: Clone, N> Clone for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn clone(&self) -> Self {
        // This places all cloned elements at the start of the new array iterator,
        // not at their original indices.
        unsafe {
            let mut array = ptr::read(&self.array);
            let mut index_back = 0;

            for (dst, src) in array.as_mut_slice().into_iter().zip(self.as_slice()) {
                ptr::write(dst, src.clone());
                index_back += 1;
            }

            GenericArrayIter {
                array,
                index: 0,
                index_back
            }
        }
    }
}

impl<T, N> Iterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.index < self.index_back {
            let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };

            self.index += 1;

            p
        } else {
            None
        }
    }

    fn fold<B, F>(mut self, init: B, mut f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        let ret = unsafe {
            let GenericArrayIter {
                ref array,
                ref mut index,
                index_back,
            } = self;

            let remaining = &array[*index..index_back];

            remaining.iter().fold(init, |acc, src| {
                let value = ptr::read(src);

                *index += 1;

                f(acc, value)
            })
        };

        // ensure the drop happens here after iteration
        drop(self);

        ret
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    #[inline]
    fn count(self) -> usize {
        self.len()
    }

    fn nth(&mut self, n: usize) -> Option<T> {
        // First consume values prior to the nth.
        let ndrop = cmp::min(n, self.len());

        for p in &mut self.array[self.index..self.index + ndrop] {
            self.index += 1;

            unsafe {
                ptr::drop_in_place(p);
            }
        }

        self.next()
    }

    #[inline]
    fn last(mut self) -> Option<T> {
        // Note, everything else will correctly drop first as `self` leaves scope.
        self.next_back()
    }
}

impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn next_back(&mut self) -> Option<T> {
        if self.index < self.index_back {
            self.index_back -= 1;

            unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
        } else {
            None
        }
    }

    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        let ret = unsafe {
            let GenericArrayIter {
                ref array,
                index,
                ref mut index_back,
            } = self;

            let remaining = &array[index..*index_back];

            remaining.iter().rfold(init, |acc, src| {
                let value = ptr::read(src);

                *index_back -= 1;

                f(acc, value)
            })
        };

        // ensure the drop happens here after iteration
        drop(self);

        ret
    }
}

impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn len(&self) -> usize {
        self.index_back - self.index
    }
}

impl<T, N> FusedIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
}

// TODO: Implement `TrustedLen` when stabilized
<commit_msg>Shrink unsafe block<commit_after>//! `GenericArray` iterator implementation.

use super::{ArrayLength, GenericArray};
use core::iter::FusedIterator;
use core::mem::ManuallyDrop;
use core::{cmp, fmt, ptr, mem};

/// An iterator that moves out of a `GenericArray`
pub struct GenericArrayIter<T, N: ArrayLength<T>> {
    // Invariants: index <= index_back <= N
    // Only values in array[index..index_back] are alive at any given time.
    // Values from array[..index] and array[index_back..] are already moved/dropped.
    array: ManuallyDrop<GenericArray<T, N>>,
    index: usize,
    index_back: usize,
}

#[cfg(test)]
mod test {
    use super::*;

    fn send<I: Send>(_iter: I) {}

    #[test]
    fn test_send_iter() {
        send(GenericArray::from([1, 2, 3, 4]).into_iter());
    }
}

impl<T, N> GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    /// Returns the remaining items of this iterator as a slice
    #[inline]
    pub fn as_slice(&self) -> &[T] {
        &self.array.as_slice()[self.index..self.index_back]
    }

    /// Returns the remaining items of this iterator as a mutable slice
    #[inline]
    pub fn as_mut_slice(&mut self) -> &mut [T] {
        &mut self.array.as_mut_slice()[self.index..self.index_back]
    }
}

impl<T, N> IntoIterator for GenericArray<T, N>
where
    N: ArrayLength<T>,
{
    type Item = T;
    type IntoIter = GenericArrayIter<T, N>;

    fn into_iter(self) -> Self::IntoIter {
        GenericArrayIter {
            array: ManuallyDrop::new(self),
            index: 0,
            index_back: N::USIZE,
        }
    }
}

// Based on work in rust-lang/rust#49000
impl<T: fmt::Debug, N> fmt::Debug for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_tuple("GenericArrayIter")
            .field(&self.as_slice())
            .finish()
    }
}

impl<T, N> Drop for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    #[inline]
    fn drop(&mut self) {
        if mem::needs_drop::<T>() {
            // Drop values that are still alive.
            for p in self.as_mut_slice() {
                unsafe {
                    ptr::drop_in_place(p);
                }
            }
        }
    }
}

// Based on work in rust-lang/rust#49000
impl<T: Clone, N> Clone for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn clone(&self) -> Self {
        // This places all cloned elements at the start of the new array iterator,
        // not at their original indices.

            let mut array = unsafe {ptr::read(&self.array)};
            let mut index_back = 0;

            for (dst, src) in array.as_mut_slice().into_iter().zip(self.as_slice()) {
                unsafe {ptr::write(dst, src.clone())};
                index_back += 1;
            }

            GenericArrayIter {
                array,
                index: 0,
                index_back
            }

    }
}

impl<T, N> Iterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.index < self.index_back {
            let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) };

            self.index += 1;

            p
        } else {
            None
        }
    }

    fn fold<B, F>(mut self, init: B, mut f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        let ret = unsafe {
            let GenericArrayIter {
                ref array,
                ref mut index,
                index_back,
            } = self;

            let remaining = &array[*index..index_back];

            remaining.iter().fold(init, |acc, src| {
                let value = ptr::read(src);

                *index += 1;

                f(acc, value)
            })
        };

        // ensure the drop happens here after iteration
        drop(self);

        ret
    }

    #[inline]
    fn size_hint(&self) -> (usize, Option<usize>) {
        let len = self.len();
        (len, Some(len))
    }

    #[inline]
    fn count(self) -> usize {
        self.len()
    }

    fn nth(&mut self, n: usize) -> Option<T> {
        // First consume values prior to the nth.
        let ndrop = cmp::min(n, self.len());

        for p in &mut self.array[self.index..self.index + ndrop] {
            self.index += 1;

            unsafe {
                ptr::drop_in_place(p);
            }
        }

        self.next()
    }

    #[inline]
    fn last(mut self) -> Option<T> {
        // Note, everything else will correctly drop first as `self` leaves scope.
        self.next_back()
    }
}

impl<T, N> DoubleEndedIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn next_back(&mut self) -> Option<T> {
        if self.index < self.index_back {
            self.index_back -= 1;

            unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) }
        } else {
            None
        }
    }

    fn rfold<B, F>(mut self, init: B, mut f: F) -> B
    where
        F: FnMut(B, Self::Item) -> B,
    {
        let ret = unsafe {
            let GenericArrayIter {
                ref array,
                index,
                ref mut index_back,
            } = self;

            let remaining = &array[index..*index_back];

            remaining.iter().rfold(init, |acc, src| {
                let value = ptr::read(src);

                *index_back -= 1;

                f(acc, value)
            })
        };

        // ensure the drop happens here after iteration
        drop(self);

        ret
    }
}

impl<T, N> ExactSizeIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
    fn len(&self) -> usize {
        self.index_back - self.index
    }
}

impl<T, N> FusedIterator for GenericArrayIter<T, N>
where
    N: ArrayLength<T>,
{
}

// TODO: Implement `TrustedLen` when stabilized
<|endoftext|>


<commit_before>use std::io::{self, Write};
use std::f32::consts::PI;
use std::f32::INFINITY;

#[derive(Copy, Clone, Debug)]
pub struct Position(f32, f32);

impl Position {
    pub fn origin() -> Position {
        Position(0.0, 0.0)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Degree(pub f32);

#[derive(Copy, Clone, Debug)]
pub struct Radiant(pub f32);

impl Into<Degree> for Radiant {
    fn into(self) -> Degree {
        Degree(self.0 * 180.0 / PI)
    }
}

impl Into<Radiant> for Degree {
    fn into(self) -> Radiant {
        Radiant(self.0 * PI / 180.0)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Distance(f32);

impl Into<Distance> for f32 {
    fn into(self) -> Distance {
        Distance(self)
    }
}

pub trait Turtle {
    /// Move turtle forward by specified `distance`.
    fn forward<T: Into<Distance>>(&mut self, distance: T);

    /// Move turtle backward by specified `distance`.
    fn backward<T: Into<Distance>>(&mut self, distance: T);

    /// Turn turtle right by `angle` degree.
    fn right<T: Into<Degree>>(&mut self, angle: T);

    /// Turn turtle left by `angle` degree.
    fn left<T: Into<Degree>>(&mut self, angle: T);

    /// Put the pen down.
    fn pendown(&mut self);

    /// Put the pen up.
    fn penup(&mut self);

    fn goto(&mut self, pos: Position);

    fn home(&mut self) {
        self.goto(Position::origin());
    }

    /// Push current turtle state on stack.
    fn push(&mut self);

    /// Restore previously saved turtle state.
    fn pop(&mut self);
}

#[derive(Clone)]
pub struct TurtleState {
    pos: Position,
    angle: Degree,
    pendown: bool,
}

impl TurtleState {
    fn new() -> TurtleState {
        TurtleState {
            pos: Position::origin(),
            angle: Degree(0.0),
            pendown: true,
        }
    }
}

pub struct TurtleRecorder {
    states: Vec<TurtleState>,
    lines: Vec<(Position, Position)>,
}

impl TurtleRecorder {
    pub fn new() -> TurtleRecorder {
        TurtleRecorder {
            states: vec![TurtleState::new()],
            lines: vec![],
        }
    }

    #[inline]
    fn current_state_mut(&mut self) -> &mut TurtleState {
        self.states.last_mut().unwrap()
    }

    #[inline]
    fn current_state(&self) -> &TurtleState {
        self.states.last().unwrap()
    }

    #[inline]
    fn direction(&self, distance: Distance) -> (f32, f32) {
        let state = self.current_state();
        let rad: Radiant = state.angle.into();
        let dx = rad.0.cos() * distance.0;
        let dy = rad.0.sin() * distance.0;
        (dx, dy)
    }

    fn draw_line(&mut self, src: Position, dst: Position) {
        self.lines.push((src, dst));
    }

    /// Saves the turtle graphic as Scalable Vector Graphic (SVG).
    pub fn save_as_svg<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        // Determine extend of canvas
        let mut min = Position(INFINITY, INFINITY);
        let mut max = Position(-INFINITY, -INFINITY);
        for &(ref src, ref dst) in self.lines.iter() {
            if src.0 < min.0 {
                min.0 = src.0;
            }
            if dst.0 < min.0 {
                min.0 = dst.0;
            }
            if src.0 > max.0 {
                max.0 = src.0;
            }
            if dst.0 > max.0 {
                max.0 = dst.0;
            }

            if src.1 < min.1 {
                min.1 = src.1;
            }
            if dst.1 < min.1 {
                min.1 = dst.1;
            }
            if src.1 > max.1 {
                max.1 = src.1;
            }
            if dst.1 > max.1 {
                max.1 = dst.1;
            }
        }
        let width = (max.0 - min.0).abs();
        let height = (max.1 - min.1).abs();

        let top_left = Position(min.0 - width / 10.0, min.1 - height / 10.0);
        let bottom_right = Position(max.0 + width / 10.0, max.1 + height / 10.0);

        try!(writeln!(wr,
                      r#"<?xml version="1.0" encoding="UTF-8"?>
                <svg xmlns="http://www.w3.org/2000/svg"
                version="1.1" baseProfile="full"
                width="100%" height="100%"
                viewBox="{} {} {} {}">"#,
                      top_left.0,
                      top_left.1,
                      bottom_right.0,
                      bottom_right.1));

        for &(ref src, ref dst) in self.lines.iter() {
            try!(writeln!(wr,
                          r#"<path d="M{} {} L{} {}" stroke="black" stroke-width="1"/>"#,
                          src.0,
                          src.1,
                          dst.0,
                          dst.1));
        }

        writeln!(wr, "</svg>")
    }
}

impl Turtle for TurtleRecorder {
    /// Move turtle forward by specified `distance`.
    fn forward<T: Into<Distance>>(&mut self, distance: T) {
        let (dx, dy) = self.direction(distance.into());
        let pendown = self.current_state().pendown;
        let src: Position = self.current_state().pos;
        let dst = Position(src.0 + dx, src.1 + dy);
        if pendown {
            self.draw_line(src, dst);
        }
        self.current_state_mut().pos = dst;
    }

    /// Move turtle backward by specified `distance`.
    fn backward<T: Into<Distance>>(&mut self, distance: T) {
        let distance: Distance = distance.into();
        self.forward(Distance(-distance.0))
    }

    /// Turn turtle right by `angle` degrees.
    fn right<T: Into<Degree>>(&mut self, angle: T) {
        let angle: Degree = angle.into();
        self.current_state_mut().angle.0 += angle.0;
    }

    /// Turn turtle left by `angle` degrees.
    fn left<T: Into<Degree>>(&mut self, angle: T) {
        let angle: Degree = angle.into();
        self.current_state_mut().angle.0 -= angle.0;
    }

    /// Put the pen down.
    fn pendown(&mut self) {
        self.current_state_mut().pendown = true;
    }

    /// Put the pen up.
    fn penup(&mut self) {
        self.current_state_mut().pendown = false;
    }

    fn goto(&mut self, pos: Position) {
        self.current_state_mut().pos = pos;
    }

    /// Push current turtle state on stack.
    fn push(&mut self) {
        let state = self.current_state_mut().clone();
        self.states.push(state);
    }

    /// Restore previously saved turtle state.
    fn pop(&mut self) {
        self.states.pop();
    }
}

fn main() {
    use std::fs::File;
    let mut t = TurtleRecorder::new();
    t.forward(10.0);
    t.right(Degree(90.0));
    t.forward(10.0);
    t.right(Degree(90.0));
    t.forward(10.0);
    t.right(Degree(90.0));
    t.forward(10.0);
    t.save_as_svg(&mut File::create("test.svg").unwrap());
}
<commit_msg>Start with pen up<commit_after>use std::io::{self, Write};
use std::f32::consts::PI;
use std::f32::INFINITY;

#[derive(Copy, Clone, Debug)]
pub struct Position(f32, f32);

impl Position {
    pub fn origin() -> Position {
        Position(0.0, 0.0)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Degree(pub f32);

#[derive(Copy, Clone, Debug)]
pub struct Radiant(pub f32);

impl Into<Degree> for Radiant {
    fn into(self) -> Degree {
        Degree(self.0 * 180.0 / PI)
    }
}

impl Into<Radiant> for Degree {
    fn into(self) -> Radiant {
        Radiant(self.0 * PI / 180.0)
    }
}

#[derive(Copy, Clone, Debug)]
pub struct Distance(f32);

impl Into<Distance> for f32 {
    fn into(self) -> Distance {
        Distance(self)
    }
}

pub trait Turtle {
    /// Move turtle forward by specified `distance`.
    fn forward<T: Into<Distance>>(&mut self, distance: T);

    /// Move turtle backward by specified `distance`.
    fn backward<T: Into<Distance>>(&mut self, distance: T);

    /// Turn turtle right by `angle` degree.
    fn right<T: Into<Degree>>(&mut self, angle: T);

    /// Turn turtle left by `angle` degree.
    fn left<T: Into<Degree>>(&mut self, angle: T);

    /// Put the pen down.
    fn pendown(&mut self);

    /// Put the pen up.
    fn penup(&mut self);

    fn goto(&mut self, pos: Position);

    fn home(&mut self) {
        self.goto(Position::origin());
    }

    /// Push current turtle state on stack.
    fn push(&mut self);

    /// Restore previously saved turtle state.
    fn pop(&mut self);
}

#[derive(Clone)]
pub struct TurtleState {
    pos: Position,
    angle: Degree,
    pendown: bool,
}

impl TurtleState {
    fn new() -> TurtleState {
        TurtleState {
            pos: Position::origin(),
            angle: Degree(0.0),
            pendown: false,
        }
    }
}

pub struct TurtleRecorder {
    states: Vec<TurtleState>,
    lines: Vec<(Position, Position)>,
}

impl TurtleRecorder {
    pub fn new() -> TurtleRecorder {
        TurtleRecorder {
            states: vec![TurtleState::new()],
            lines: vec![],
        }
    }

    #[inline]
    fn current_state_mut(&mut self) -> &mut TurtleState {
        self.states.last_mut().unwrap()
    }

    #[inline]
    fn current_state(&self) -> &TurtleState {
        self.states.last().unwrap()
    }

    #[inline]
    fn direction(&self, distance: Distance) -> (f32, f32) {
        let state = self.current_state();
        let rad: Radiant = state.angle.into();
        let dx = rad.0.cos() * distance.0;
        let dy = rad.0.sin() * distance.0;
        (dx, dy)
    }

    fn draw_line(&mut self, src: Position, dst: Position) {
        self.lines.push((src, dst));
    }

    /// Saves the turtle graphic as Scalable Vector Graphic (SVG).
    pub fn save_as_svg<W: Write>(&self, wr: &mut W) -> io::Result<()> {
        // Determine extend of canvas
        let mut min = Position(INFINITY, INFINITY);
        let mut max = Position(-INFINITY, -INFINITY);
        for &(ref src, ref dst) in self.lines.iter() {
            if src.0 < min.0 {
                min.0 = src.0;
            }
            if dst.0 < min.0 {
                min.0 = dst.0;
            }
            if src.0 > max.0 {
                max.0 = src.0;
            }
            if dst.0 > max.0 {
                max.0 = dst.0;
            }

            if src.1 < min.1 {
                min.1 = src.1;
            }
            if dst.1 < min.1 {
                min.1 = dst.1;
            }
            if src.1 > max.1 {
                max.1 = src.1;
            }
            if dst.1 > max.1 {
                max.1 = dst.1;
            }
        }
        let width = (max.0 - min.0).abs();
        let height = (max.1 - min.1).abs();

        let top_left = Position(min.0 - width / 10.0, min.1 - height / 10.0);
        let bottom_right = Position(max.0 + width / 10.0, max.1 + height / 10.0);

        try!(writeln!(wr,
                      r#"<?xml version="1.0" encoding="UTF-8"?>
                <svg xmlns="http://www.w3.org/2000/svg"
                version="1.1" baseProfile="full"
                width="100%" height="100%"
                viewBox="{} {} {} {}">"#,
                      top_left.0,
                      top_left.1,
                      bottom_right.0,
                      bottom_right.1));

        for &(ref src, ref dst) in self.lines.iter() {
            try!(writeln!(wr,
                          r#"<path d="M{} {} L{} {}" stroke="black" stroke-width="1"/>"#,
                          src.0,
                          src.1,
                          dst.0,
                          dst.1));
        }

        writeln!(wr, "</svg>")
    }
}

impl Turtle for TurtleRecorder {
    /// Move turtle forward by specified `distance`.
    fn forward<T: Into<Distance>>(&mut self, distance: T) {
        let (dx, dy) = self.direction(distance.into());
        let pendown = self.current_state().pendown;
        let src: Position = self.current_state().pos;
        let dst = Position(src.0 + dx, src.1 + dy);
        if pendown {
            self.draw_line(src, dst);
        }
        self.current_state_mut().pos = dst;
    }

    /// Move turtle backward by specified `distance`.
    fn backward<T: Into<Distance>>(&mut self, distance: T) {
        let distance: Distance = distance.into();
        self.forward(Distance(-distance.0))
    }

    /// Turn turtle right by `angle` degrees.
    fn right<T: Into<Degree>>(&mut self, angle: T) {
        let angle: Degree = angle.into();
        self.current_state_mut().angle.0 += angle.0;
    }

    /// Turn turtle left by `angle` degrees.
    fn left<T: Into<Degree>>(&mut self, angle: T) {
        let angle: Degree = angle.into();
        self.current_state_mut().angle.0 -= angle.0;
    }

    /// Put the pen down.
    fn pendown(&mut self) {
        self.current_state_mut().pendown = true;
    }

    /// Put the pen up.
    fn penup(&mut self) {
        self.current_state_mut().pendown = false;
    }

    fn goto(&mut self, pos: Position) {
        self.current_state_mut().pos = pos;
    }

    /// Push current turtle state on stack.
    fn push(&mut self) {
        let state = self.current_state_mut().clone();
        self.states.push(state);
    }

    /// Restore previously saved turtle state.
    fn pop(&mut self) {
        self.states.pop();
    }
}

fn main() {
    use std::fs::File;
    let mut t = TurtleRecorder::new();
    t.pendown();
    t.forward(10.0);
    t.right(Degree(90.0));
    t.forward(10.0);
    t.right(Degree(90.0));
    t.forward(10.0);
    t.right(Degree(90.0));
    t.forward(10.0);
    t.save_as_svg(&mut File::create("test.svg").unwrap());
}
<|endoftext|>


<commit_before>extern crate docopt;
extern crate rustc_serialize;
extern crate entities;

mod css;
mod html;
mod js;

use docopt::Docopt;

trait CharEncoder: 'static {
    fn encode(&mut Iterator<Item = char>) -> Option<String>;
    fn wrap_in_quotes() -> bool;
}

const USAGE: &'static str = "
how-do-i-escape: Prints escape sequences for unicode graphemes

Usage:
  how-do-i-escape <grapheme>
  how-do-i-escape (--help | --version)

Options:
  -h, --help  Show this screen.
  --version   Show version.

Example:
  $ how-do-i-escape \u{00A7}
  css  = \"\\00A7\"
  html = §
  js   = \"\\u00A7\"
";

#[derive(RustcDecodable)]
struct Args {
    arg_grapheme: String,
}

fn main() {
    let version = format!("v{}", env!("CARGO_PKG_VERSION"));

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.help(true).version(Some(version)).decode())
        .unwrap_or_else(|e| e.exit());

    let grapheme = args.arg_grapheme;

    println!("");
    println!("  {:<10} -- css", escape_grapheme(&grapheme, css::Css));
    println!("");
    println!("  {:<10} -- html", escape_grapheme(&grapheme, html::Html));
    println!("");
    println!("  {:<10} -- javascript", escape_grapheme(&grapheme, js::Js));
}

fn escape_grapheme<T: CharEncoder>(grapheme: &str, _: T) -> String {
    let mut result = String::new();
    let mut iter = grapheme.chars();

    loop {
        match T::encode(&mut iter) {
            Some(s) => result.push_str(&s),
            None => break,
        }
    }

    if T::wrap_in_quotes() {
        format!(r#""{}""#, result)
    } else {
        result
    }
}

#[cfg(test)]
mod tests {
    use super::{CharEncoder, escape_grapheme};

    #[test]
    fn test_escape_grapheme() {
        struct AlwaysHello;

        impl CharEncoder for AlwaysHello {
            fn encode(iter: &mut Iterator<Item = char>) -> Option<String> {
                iter.next().map(|_| "hello".to_string())
            }
        }

        let always_hello = escape_grapheme("a", AlwaysHello);
        assert_eq!(always_hello, "hello");

        struct Simple;

        impl CharEncoder for Simple {
            fn encode(iter: &mut Iterator<Item = char>) -> Option<String> {
                iter.next().map(|i| format!("{}", i as u32))
            }
        }

        let simple = escape_grapheme("a", Simple);
        assert_eq!(simple, "97");
    }
}
<commit_msg>Fix tests<commit_after>extern crate docopt;
extern crate rustc_serialize;
extern crate entities;

mod css;
mod html;
mod js;

use docopt::Docopt;

trait CharEncoder: 'static {
    fn encode(&mut Iterator<Item = char>) -> Option<String>;
    fn wrap_in_quotes() -> bool;
}

const USAGE: &'static str = "
how-do-i-escape: Prints escape sequences for unicode graphemes

Usage:
  how-do-i-escape <grapheme>
  how-do-i-escape (--help | --version)

Options:
  -h, --help  Show this screen.
  --version   Show version.

Example:
  $ how-do-i-escape \u{00A7}
  css  = \"\\00A7\"
  html = §
  js   = \"\\u00A7\"
";

#[derive(RustcDecodable)]
struct Args {
    arg_grapheme: String,
}

fn main() {
    let version = format!("v{}", env!("CARGO_PKG_VERSION"));

    let args: Args = Docopt::new(USAGE)
        .and_then(|d| d.help(true).version(Some(version)).decode())
        .unwrap_or_else(|e| e.exit());

    let grapheme = args.arg_grapheme;

    println!("");
    println!("  {:<10} -- css", escape_grapheme(&grapheme, css::Css));
    println!("");
    println!("  {:<10} -- html", escape_grapheme(&grapheme, html::Html));
    println!("");
    println!("  {:<10} -- javascript", escape_grapheme(&grapheme, js::Js));
}

fn escape_grapheme<T: CharEncoder>(grapheme: &str, _: T) -> String {
    let mut result = String::new();
    let mut iter = grapheme.chars();

    loop {
        match T::encode(&mut iter) {
            Some(s) => result.push_str(&s),
            None => break,
        }
    }

    if T::wrap_in_quotes() {
        format!(r#""{}""#, result)
    } else {
        result
    }
}

#[cfg(test)]
mod tests {
    use super::{CharEncoder, escape_grapheme};

    #[test]
    fn test_escape_grapheme() {
        struct AlwaysHello;

        impl CharEncoder for AlwaysHello {
            fn encode(iter: &mut Iterator<Item = char>) -> Option<String> {
                iter.next().map(|_| "hello".to_string())
            }
            fn wrap_in_quotes() -> bool {
                false
            }
        }

        let always_hello = escape_grapheme("a", AlwaysHello);
        assert_eq!(always_hello, "hello");

        struct Simple;

        impl CharEncoder for Simple {
            fn encode(iter: &mut Iterator<Item = char>) -> Option<String> {
                iter.next().map(|i| format!("{}", i as u32))
            }
            fn wrap_in_quotes() -> bool {
                false
            }
        }

        let simple = escape_grapheme("a", Simple);
        assert_eq!(simple, "97");
    }
}
<|endoftext|>


<commit_before>extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate exonum;
extern crate router;
extern crate bodyparser;
extern crate iron;

use exonum::blockchain::{self, Blockchain, Service, GenesisConfig,
                         ValidatorKeys, Transaction, ApiContext};
use exonum::node::{Node, NodeConfig, NodeApiConfig, TransactionSend,
                   ApiSender, NodeChannel};
use exonum::messages::{RawTransaction, FromRaw, Message};
use exonum::storage::{Fork, MemoryDB, MapIndex};
use exonum::crypto::{PublicKey, Hash};
use exonum::encoding::{self, Field};
use exonum::api::{Api, ApiError};
use iron::prelude::*;
use iron::Handler;
use router::Router;

// // // // // // // // // // CONSTANTS // // // // // // // // // //

const SERVICE_ID: u16 = 1;

const TX_CREATE_WALLET_ID: u16 = 1;

const TX_TRANSFER_ID: u16 = 2;

const INIT_BALANCE: u64 = 100;

// // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

encoding_struct! {
    struct Wallet {
        const SIZE = 48;

        field pub_key:            &PublicKey  [00 => 32]
        field name:               &str        [32 => 40]
        field balance:            u64         [40 => 48]
    }
}

impl Wallet {
    pub fn increase(&mut self, amount: u64) {
        let balance = self.balance() + amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }

    pub fn decrease(&mut self, amount: u64) {
        let balance = self.balance() - amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }
}

// // // // // // // // // // STORAGE DATA LAYOUT // // // // // // // // // //

pub struct CurrencySchema<'a> {
    view: &'a mut Fork,
}

impl<'a> CurrencySchema<'a> {
    pub fn wallets(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
        let prefix = blockchain::gen_prefix(SERVICE_ID, 0, &());
        MapIndex::new(prefix, self.view)
    }

    pub fn wallet(&mut self, pub_key: &PublicKey) -> Option<Wallet> {
        self.wallets().get(pub_key)
    }
}

// // // // // // // // // // TRANSACTIONS // // // // // // // // // //

message! {
    struct TxCreateWallet {
        const TYPE = SERVICE_ID;
        const ID = TX_CREATE_WALLET_ID;
        const SIZE = 40;

        field pub_key:     &PublicKey  [00 => 32]
        field name:        &str        [32 => 40]
    }
}

message! {
    struct TxTransfer {
        const TYPE = SERVICE_ID;
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        field from:        &PublicKey  [00 => 32]
        field to:          &PublicKey  [32 => 64]
        field amount:      u64         [64 => 72]
        field seed:        u64         [72 => 80]
    }
}

// // // // // // // // // // CONTRACTS // // // // // // // // // //

impl Transaction for TxCreateWallet {
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        if let None = schema.wallet(self.pub_key()) {
            let wallet = Wallet::new(self.pub_key(), self.name(), INIT_BALANCE);
            println!("Create the wallet: {:?}", wallet);
            schema.wallets().put(self.pub_key(), wallet)
        }
    }
}

impl Transaction for TxTransfer {
    fn verify(&self) -> bool {
        (*self.from() != *self.to()) && self.verify_signature(self.from())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        let sender = schema.wallet(self.from());
        let receiver = schema.wallet(self.to());
        if let (Some(mut sender), Some(mut receiver)) = (sender, receiver) {
            let amount = self.amount();
            if sender.balance() >= amount {
                sender.decrease(amount);
                receiver.increase(amount);
                println!("Transfer between wallets: {:?} => {:?}", sender, receiver);
                let mut wallets = schema.wallets();
                wallets.put(self.from(), sender);
                wallets.put(self.to(), receiver);
            }
        }
    }
}

// // // // // // // // // // REST API // // // // // // // // // //

#[derive(Clone)]
struct CryptocurrencyApi {
    channel: ApiSender<NodeChannel>,
}

impl Api for CryptocurrencyApi {
    fn wire(&self, router: &mut Router) {

        #[serde(untagged)]
        #[derive(Clone, Serialize, Deserialize)]
        enum TransactionRequest {
            CreateWallet(TxCreateWallet),
            Transfer(TxTransfer),
        }

        impl Into<Box<Transaction>> for TransactionRequest {
            fn into(self) -> Box<Transaction> {
                match self {
                    TransactionRequest::CreateWallet(trans) => Box::new(trans),
                    TransactionRequest::Transfer(trans) => Box::new(trans),
                }
            }
        }

        #[derive(Serialize, Deserialize)]
        struct TransactionResponse {
            tx_hash: Hash,
        }

        let self_ = self.clone();
        let transaction = move |req: &mut Request| -> IronResult<Response> {
            match req.get::<bodyparser::Struct<TransactionRequest>>() {
                Ok(Some(transaction)) => {
                    let transaction: Box<Transaction> = transaction.into();
                    let tx_hash = transaction.hash();
                    self_.channel.send(transaction).map_err(|e| ApiError::Events(e))?;
                    let json = TransactionResponse { tx_hash };
                    self_.ok_response(&serde_json::to_value(&json).unwrap())
                }
                Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
                Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
            }
        };
        let route_post = "/v1/wallets/transaction";
        router.post(&route_post, transaction, "transaction");
    }
}

// // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

struct CurrencyService;

impl Service for CurrencyService {
    fn service_name(&self) -> &'static str { "cryptocurrency" }

    fn service_id(&self) -> u16 { SERVICE_ID }

    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let trans: Box<Transaction> = match raw.message_type() {
            TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
            TX_CREATE_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
            _ => {
                return Err(encoding::Error::IncorrectMessageType { message_type: raw.message_type() });
            },
        };
        Ok(trans)
    }

    fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
        let mut router = Router::new();
        let api = CryptocurrencyApi {
            channel: ctx.node_channel().clone(),
        };
        api.wire(&mut router);
        Some(Box::new(router))
    }
}

// // // // // // // // // // ENTRY POINT // // // // // // // // // //

fn main() {
    exonum::helpers::init_logger().unwrap();

    println!("Creating in-memory database...");
    let db = MemoryDB::new();
    let services: Vec<Box<Service>> = vec![
        Box::new(CurrencyService),
    ];
    let blockchain = Blockchain::new(Box::new(db), services);

    let (consensus_public_key, consensus_secret_key) = exonum::crypto::gen_keypair();
    let (service_public_key, service_secret_key) = exonum::crypto::gen_keypair();

    let peer_address = "0.0.0.0:2000".parse().unwrap();
    let api_address = "0.0.0.0:8000".parse().unwrap();

    let validator_keys = ValidatorKeys {
        consensus_key: consensus_public_key,
        service_key: service_public_key,
    };
    let genesis = GenesisConfig::new(vec![validator_keys].into_iter());

    let api_cfg = NodeApiConfig {
        public_api_address: Some(api_address),
        ..Default::default()
    };

    let node_cfg = NodeConfig {
        listen_address: peer_address,
        peers: vec![],
        service_public_key,
        service_secret_key,
        consensus_public_key,
        consensus_secret_key,
        genesis,
        external_address: None,
        network: Default::default(),
        whitelist: Default::default(),
        api: api_cfg,
        mempool: Default::default(),
        services_configs: Default::default(),
    };

    println!("Starting a single node...");
    let mut node = Node::new(blockchain, node_cfg);

    println!("Blockchain in ready for transactions!");
    node.run().unwrap();
}
<commit_msg>Add license reference to main.rs<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
#[macro_use] extern crate exonum;
extern crate router;
extern crate bodyparser;
extern crate iron;

use exonum::blockchain::{self, Blockchain, Service, GenesisConfig,
                         ValidatorKeys, Transaction, ApiContext};
use exonum::node::{Node, NodeConfig, NodeApiConfig, TransactionSend,
                   ApiSender, NodeChannel};
use exonum::messages::{RawTransaction, FromRaw, Message};
use exonum::storage::{Fork, MemoryDB, MapIndex};
use exonum::crypto::{PublicKey, Hash};
use exonum::encoding::{self, Field};
use exonum::api::{Api, ApiError};
use iron::prelude::*;
use iron::Handler;
use router::Router;

// // // // // // // // // // CONSTANTS // // // // // // // // // //

const SERVICE_ID: u16 = 1;

const TX_CREATE_WALLET_ID: u16 = 1;

const TX_TRANSFER_ID: u16 = 2;

const INIT_BALANCE: u64 = 100;

// // // // // // // // // // PERSISTENT DATA // // // // // // // // // //

encoding_struct! {
    struct Wallet {
        const SIZE = 48;

        field pub_key:            &PublicKey  [00 => 32]
        field name:               &str        [32 => 40]
        field balance:            u64         [40 => 48]
    }
}

impl Wallet {
    pub fn increase(&mut self, amount: u64) {
        let balance = self.balance() + amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }

    pub fn decrease(&mut self, amount: u64) {
        let balance = self.balance() - amount;
        Field::write(&balance, &mut self.raw, 40, 48);
    }
}

// // // // // // // // // // STORAGE DATA LAYOUT // // // // // // // // // //

pub struct CurrencySchema<'a> {
    view: &'a mut Fork,
}

impl<'a> CurrencySchema<'a> {
    pub fn wallets(&mut self) -> MapIndex<&mut Fork, PublicKey, Wallet> {
        let prefix = blockchain::gen_prefix(SERVICE_ID, 0, &());
        MapIndex::new(prefix, self.view)
    }

    pub fn wallet(&mut self, pub_key: &PublicKey) -> Option<Wallet> {
        self.wallets().get(pub_key)
    }
}

// // // // // // // // // // TRANSACTIONS // // // // // // // // // //

message! {
    struct TxCreateWallet {
        const TYPE = SERVICE_ID;
        const ID = TX_CREATE_WALLET_ID;
        const SIZE = 40;

        field pub_key:     &PublicKey  [00 => 32]
        field name:        &str        [32 => 40]
    }
}

message! {
    struct TxTransfer {
        const TYPE = SERVICE_ID;
        const ID = TX_TRANSFER_ID;
        const SIZE = 80;

        field from:        &PublicKey  [00 => 32]
        field to:          &PublicKey  [32 => 64]
        field amount:      u64         [64 => 72]
        field seed:        u64         [72 => 80]
    }
}

// // // // // // // // // // CONTRACTS // // // // // // // // // //

impl Transaction for TxCreateWallet {
    fn verify(&self) -> bool {
        self.verify_signature(self.pub_key())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        if let None = schema.wallet(self.pub_key()) {
            let wallet = Wallet::new(self.pub_key(), self.name(), INIT_BALANCE);
            println!("Create the wallet: {:?}", wallet);
            schema.wallets().put(self.pub_key(), wallet)
        }
    }
}

impl Transaction for TxTransfer {
    fn verify(&self) -> bool {
        (*self.from() != *self.to()) && self.verify_signature(self.from())
    }

    fn execute(&self, view: &mut Fork) {
        let mut schema = CurrencySchema { view };
        let sender = schema.wallet(self.from());
        let receiver = schema.wallet(self.to());
        if let (Some(mut sender), Some(mut receiver)) = (sender, receiver) {
            let amount = self.amount();
            if sender.balance() >= amount {
                sender.decrease(amount);
                receiver.increase(amount);
                println!("Transfer between wallets: {:?} => {:?}", sender, receiver);
                let mut wallets = schema.wallets();
                wallets.put(self.from(), sender);
                wallets.put(self.to(), receiver);
            }
        }
    }
}

// // // // // // // // // // REST API // // // // // // // // // //

#[derive(Clone)]
struct CryptocurrencyApi {
    channel: ApiSender<NodeChannel>,
}

impl Api for CryptocurrencyApi {
    fn wire(&self, router: &mut Router) {

        #[serde(untagged)]
        #[derive(Clone, Serialize, Deserialize)]
        enum TransactionRequest {
            CreateWallet(TxCreateWallet),
            Transfer(TxTransfer),
        }

        impl Into<Box<Transaction>> for TransactionRequest {
            fn into(self) -> Box<Transaction> {
                match self {
                    TransactionRequest::CreateWallet(trans) => Box::new(trans),
                    TransactionRequest::Transfer(trans) => Box::new(trans),
                }
            }
        }

        #[derive(Serialize, Deserialize)]
        struct TransactionResponse {
            tx_hash: Hash,
        }

        let self_ = self.clone();
        let transaction = move |req: &mut Request| -> IronResult<Response> {
            match req.get::<bodyparser::Struct<TransactionRequest>>() {
                Ok(Some(transaction)) => {
                    let transaction: Box<Transaction> = transaction.into();
                    let tx_hash = transaction.hash();
                    self_.channel.send(transaction).map_err(|e| ApiError::Events(e))?;
                    let json = TransactionResponse { tx_hash };
                    self_.ok_response(&serde_json::to_value(&json).unwrap())
                }
                Ok(None) => Err(ApiError::IncorrectRequest("Empty request body".into()))?,
                Err(e) => Err(ApiError::IncorrectRequest(Box::new(e)))?,
            }
        };
        let route_post = "/v1/wallets/transaction";
        router.post(&route_post, transaction, "transaction");
    }
}

// // // // // // // // // // SERVICE DECLARATION // // // // // // // // // //

struct CurrencyService;

impl Service for CurrencyService {
    fn service_name(&self) -> &'static str { "cryptocurrency" }

    fn service_id(&self) -> u16 { SERVICE_ID }

    fn tx_from_raw(&self, raw: RawTransaction) -> Result<Box<Transaction>, encoding::Error> {
        let trans: Box<Transaction> = match raw.message_type() {
            TX_TRANSFER_ID => Box::new(TxTransfer::from_raw(raw)?),
            TX_CREATE_WALLET_ID => Box::new(TxCreateWallet::from_raw(raw)?),
            _ => {
                return Err(encoding::Error::IncorrectMessageType { message_type: raw.message_type() });
            },
        };
        Ok(trans)
    }

    fn public_api_handler(&self, ctx: &ApiContext) -> Option<Box<Handler>> {
        let mut router = Router::new();
        let api = CryptocurrencyApi {
            channel: ctx.node_channel().clone(),
        };
        api.wire(&mut router);
        Some(Box::new(router))
    }
}

// // // // // // // // // // ENTRY POINT // // // // // // // // // //

fn main() {
    exonum::helpers::init_logger().unwrap();

    println!("Creating in-memory database...");
    let db = MemoryDB::new();
    let services: Vec<Box<Service>> = vec![
        Box::new(CurrencyService),
    ];
    let blockchain = Blockchain::new(Box::new(db), services);

    let (consensus_public_key, consensus_secret_key) = exonum::crypto::gen_keypair();
    let (service_public_key, service_secret_key) = exonum::crypto::gen_keypair();

    let peer_address = "0.0.0.0:2000".parse().unwrap();
    let api_address = "0.0.0.0:8000".parse().unwrap();

    let validator_keys = ValidatorKeys {
        consensus_key: consensus_public_key,
        service_key: service_public_key,
    };
    let genesis = GenesisConfig::new(vec![validator_keys].into_iter());

    let api_cfg = NodeApiConfig {
        public_api_address: Some(api_address),
        ..Default::default()
    };

    let node_cfg = NodeConfig {
        listen_address: peer_address,
        peers: vec![],
        service_public_key,
        service_secret_key,
        consensus_public_key,
        consensus_secret_key,
        genesis,
        external_address: None,
        network: Default::default(),
        whitelist: Default::default(),
        api: api_cfg,
        mempool: Default::default(),
        services_configs: Default::default(),
    };

    println!("Starting a single node...");
    let mut node = Node::new(blockchain, node_cfg);

    println!("Blockchain in ready for transactions!");
    node.run().unwrap();
}
<|endoftext|>


<commit_before>extern crate env_logger;
extern crate mioco;
extern crate trust_dns;
extern crate rand;
#[macro_use] extern crate quick_error;
#[macro_use] extern crate log;

mod future;
mod utils;

use std::net::{SocketAddr, SocketAddrV4, IpAddr};

use mioco::udp::UdpSocket;
use mioco::mio::Ipv4Addr;
use trust_dns::op::{Message, MessageType, ResponseCode, Query, OpCode};

use utils::{Result, CloneExt, MessageExt};
use future::Future;

fn query(q: Query, server: Ipv4Addr) -> Result<Message> {
    let mut msg : Message = Message::new();
    msg.message_type(MessageType::Query);
    msg.id(rand::random());
    msg.op_code(OpCode::Query);
    msg.recursion_desired(true);
    debug!("Q[{}][{}] {} {:?} {:?}",
           server, msg.get_id(), q.get_name(), q.get_query_type(), q.get_query_class());
    msg.add_query(q);
    let msg_data = try!(msg.to_bytes());
    let mut sock = try!(UdpSocket::v4());
    let target = SocketAddr::new(IpAddr::V4(server), 53);
    try!(sock.send(&msg_data, &target));
    loop {
        let (resp, addr) = try!(Message::from_udp(&mut sock));
        if addr != target {
            warn!("Q[{}][{}] Response from unexpected server: {}",
                  server, msg.get_id(), addr);
            continue
        }
        if ! resp.is_resp_for(&msg) {
            warn!("Q[{}][{}] Invalid response: {:?}",
                  server, msg.get_id(), resp);
            continue
        }
        // TODO: Validate response, handle truncated message, retry and timeout
        debug!("A[{}][{}] {} answer(s)",
           server, resp.get_id(), resp.get_answers().len());
        return Ok(resp);
    };
}
fn query_multiple(q: &Query, servers: &[Ipv4Addr]) -> Result<Message> {
    let mut futures = servers.iter()
        .cloned()
        .map(move |server| {
            let qc = q.clone();
            Future::from_fn(move || query(qc, server))
        })
        .collect::<Vec<Future<Result<Message>>>>();
    let result_index = Future::wait_any(&mut futures);
    // TODO: Handle server failure
    futures.remove(result_index).consume()
}

fn handle_request(msg: Message) -> Message {
    let mut ret : Message = msg.new_resp();
    ret.recursion_available(true);
    if msg.get_queries().len() != 1 {
        // For simplicity, only support one question
        ret.response_code(ResponseCode::Refused);
        return ret;
    }
    // TODO: EDNS?
    match query_multiple(&msg.get_queries()[0], &[Ipv4Addr::new(8, 8, 8, 8), Ipv4Addr::new(8, 8, 4, 4)]) {
        Ok(resp) => { ret.copy_resp_from(&resp); },
        Err(_)   => { ret.response_code(ResponseCode::ServFail); },
    };
    ret
}

fn main() {
    env_logger::init().unwrap();
    println!("Hello, world!");

    mioco::start(move || {
        let ip = Ipv4Addr::new(0, 0, 0, 0);
        let port = 5354;
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));

        mioco::spawn(move || -> Result<()> {
            let mut sock : UdpSocket = UdpSocket::v4().unwrap();
            sock.bind(&addr).unwrap();

            loop {
                let (msg, addr) = try!(Message::from_udp(&mut sock));
                let ret = handle_request(msg);
                let resp = try!(ret.to_bytes());
                try!(sock.send(&resp, &addr));
            }
        });
    }).unwrap();
}
<commit_msg>Handle errors when doing multi-server query<commit_after>extern crate env_logger;
extern crate mioco;
extern crate trust_dns;
extern crate rand;
#[macro_use] extern crate quick_error;
#[macro_use] extern crate log;

mod future;
mod utils;

use std::net::{SocketAddr, SocketAddrV4, IpAddr};

use mioco::udp::UdpSocket;
use mioco::mio::Ipv4Addr;
use trust_dns::op::{Message, MessageType, ResponseCode, Query, OpCode};

use utils::{Result, CloneExt, MessageExt};
use future::Future;

fn query(q: Query, server: Ipv4Addr) -> Result<Message> {
    let mut msg : Message = Message::new();
    msg.message_type(MessageType::Query);
    msg.id(rand::random());
    msg.op_code(OpCode::Query);
    msg.recursion_desired(true);
    debug!("Q[{}][{}] {} {:?} {:?}",
           server, msg.get_id(), q.get_name(), q.get_query_type(), q.get_query_class());
    msg.add_query(q);
    let msg_data = try!(msg.to_bytes());
    let mut sock = try!(UdpSocket::v4());
    let target = SocketAddr::new(IpAddr::V4(server), 53);
    try!(sock.send(&msg_data, &target));
    loop {
        let (resp, addr) = try!(Message::from_udp(&mut sock));
        if addr != target {
            warn!("Q[{}][{}] Response from unexpected server: {}",
                  server, msg.get_id(), addr);
            continue
        }
        if ! resp.is_resp_for(&msg) {
            warn!("Q[{}][{}] Invalid response: {:?}",
                  server, msg.get_id(), resp);
            continue
        }
        // TODO: Validate response, handle truncated message, retry and timeout
        debug!("A[{}][{}] {:?} {} answer(s)",
           server, resp.get_id(), resp.get_response_code(), resp.get_answers().len());
        return Ok(resp);
    };
}
fn query_multiple(q: &Query, servers: &[Ipv4Addr]) -> Result<Message> {
    let mut futures = servers.iter()
        .cloned()
        .map(move |server| {
            let qc = q.clone();
            Future::from_fn(move || query(qc, server))
        })
        .collect::<Vec<Future<Result<Message>>>>();
    loop {
        let result_index = Future::wait_any(&mut futures);
        let result = futures.remove(result_index).consume();
        let mut should_return = futures.len() == 0;
        match result {
            Ok(ref msg) => {
                match msg.get_response_code() {
                    ResponseCode::ServFail |
                    ResponseCode::NotImp |
                    ResponseCode::Refused => {
                        // Fall below to wait for remaining servers, if any
                    },
                    _ => { should_return = true; },
                }
            },
            Err(ref err) => {
                debug!("Query {:?} returned error {:?}", q, err);
            },
        };
        if should_return {
            return result;
        }
    }
}

fn handle_request(msg: Message) -> Message {
    let mut ret : Message = msg.new_resp();
    ret.recursion_available(true);
    if msg.get_queries().len() != 1 {
        // For simplicity, only support one question
        ret.response_code(ResponseCode::Refused);
        return ret;
    }
    // TODO: EDNS?
    match query_multiple(&msg.get_queries()[0], &[Ipv4Addr::new(8, 8, 8, 8), Ipv4Addr::new(8, 8, 4, 4)]) {
        Ok(resp) => { ret.copy_resp_from(&resp); },
        Err(_)   => { ret.response_code(ResponseCode::ServFail); },
    };
    ret
}

fn main() {
    env_logger::init().unwrap();
    println!("Hello, world!");

    mioco::start(move || {
        let ip = Ipv4Addr::new(0, 0, 0, 0);
        let port = 5354;
        let addr = SocketAddr::V4(SocketAddrV4::new(ip, port));

        mioco::spawn(move || -> Result<()> {
            let mut sock : UdpSocket = UdpSocket::v4().unwrap();
            sock.bind(&addr).unwrap();

            loop {
                let (msg, addr) = try!(Message::from_udp(&mut sock));
                let ret = handle_request(msg);
                let resp = try!(ret.to_bytes());
                try!(sock.send(&resp, &addr));
            }
        });
    }).unwrap();
}
<|endoftext|>


<commit_before>use std::fs::File;
use std::io::Bytes;

enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

struct Stream {
    input: Bytes<File>,
}

impl Stream {
    fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
        }
    }

    fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        return Stream::create_token(buffer);
                    }
                    buffer.push(b);
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        if Stream::is_numeric(&token_str) {
            return Some(Token::ImmConst(token_str.parse::<u16>().unwrap()));
        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0)),
                "v1"   => Some(Token::Reg(Register::V1)),
                "v2"   => Some(Token::Reg(Register::V2)),
                "v3"   => Some(Token::Reg(Register::V3)),
                "v4"   => Some(Token::Reg(Register::V4)),
                "v5"   => Some(Token::Reg(Register::V5)),
                "v6"   => Some(Token::Reg(Register::V6)),
                "v7"   => Some(Token::Reg(Register::V7)),
                "v8"   => Some(Token::Reg(Register::V8)),
                "v9"   => Some(Token::Reg(Register::V9)),
                "va"   => Some(Token::Reg(Register::Va)),
                "vb"   => Some(Token::Reg(Register::Vb)),
                "vc"   => Some(Token::Reg(Register::Vc)),
                "vd"   => Some(Token::Reg(Register::Vd)),
                "ve"   => Some(Token::Reg(Register::Ve)),
                "vf"   => Some(Token::Reg(Register::Vf)),
                "sp"   => Some(Token::Reg(Register::Sp)),
                "st"   => Some(Token::Reg(Register::St)),
                "dt"   => Some(Token::Reg(Register::Dt)),
                "pc"   => Some(Token::Reg(Register::Pc)),
                "i"    => Some(Token::Reg(Register::I)),
                "[i]"  => Some(Token::Reg(Register::IVal)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    fn is_numeric(input: &str) -> bool {
        if input.len() < 1 {
            return false;
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return false;
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return false
                }
                return true
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return false
                }
                return true
            }
        }
        false
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}

fn main() {
}
<commit_msg>Derive debug display implementation for the various structures<commit_after>use std::fs::File;
use std::io::Bytes;

#[derive(Debug)]
enum Mnemonic {
    Add, Call, Cls, Drw,
    Jp, Ld, Or, Ret,
    Rnd, Se, Shl, Shr,
    Sknp, Skp, Sne, Sub,
    Subn, Sys, Xor,
}

#[derive(Debug)]
enum Register {
    V0, V1, V2, V3,
    V4, V5, V6, V7,
    V8, V9, Va, Vb,
    Vc, Vd, Ve, Vf,
    Sp, Pc, I, St, Dt, IVal,
}

#[derive(Debug)]
enum Token {
    Opcode(Mnemonic),
    Reg(Register),
    ImmConst(u16),
}

struct Stream {
    input: Bytes<File>,
}

impl Stream {
    fn new(input: Bytes<File>) -> Stream {
        Stream {
            input: input,
        }
    }

    fn next_token(&mut self) -> Option<Token> {
        let mut buffer: Vec<u8> = vec![];

        loop {
            let bs = self.input.next().map_or(None, |bm| match bm {
                Ok(b) => Some(b),
                _ => None
            });

            match bs {
                Some(b) => {
                    if Stream::is_separator(b) {
                        return Stream::create_token(buffer);
                    }
                    buffer.push(b);
                },
                None => {
                    return Stream::create_token(buffer);
                }
            }
        }
    }

    fn create_token(input: Vec<u8>) -> Option<Token> {
        let token_str: String = String::from_utf8(input).unwrap_or_else(|err| {
            println!("Error: {:?}", err);
            "".to_owned()
        }).to_lowercase();

        if Stream::is_numeric(&token_str) {
            return Some(Token::ImmConst(token_str.parse::<u16>().unwrap()));
        }

        if Stream::is_register(&token_str) {
            return match token_str.as_str() {
                "v0"   => Some(Token::Reg(Register::V0)),
                "v1"   => Some(Token::Reg(Register::V1)),
                "v2"   => Some(Token::Reg(Register::V2)),
                "v3"   => Some(Token::Reg(Register::V3)),
                "v4"   => Some(Token::Reg(Register::V4)),
                "v5"   => Some(Token::Reg(Register::V5)),
                "v6"   => Some(Token::Reg(Register::V6)),
                "v7"   => Some(Token::Reg(Register::V7)),
                "v8"   => Some(Token::Reg(Register::V8)),
                "v9"   => Some(Token::Reg(Register::V9)),
                "va"   => Some(Token::Reg(Register::Va)),
                "vb"   => Some(Token::Reg(Register::Vb)),
                "vc"   => Some(Token::Reg(Register::Vc)),
                "vd"   => Some(Token::Reg(Register::Vd)),
                "ve"   => Some(Token::Reg(Register::Ve)),
                "vf"   => Some(Token::Reg(Register::Vf)),
                "sp"   => Some(Token::Reg(Register::Sp)),
                "st"   => Some(Token::Reg(Register::St)),
                "dt"   => Some(Token::Reg(Register::Dt)),
                "pc"   => Some(Token::Reg(Register::Pc)),
                "i"    => Some(Token::Reg(Register::I)),
                "[i]"  => Some(Token::Reg(Register::IVal)),
                _      => None
            }
        }

        match token_str.as_str() {
            "add"   => Some(Token::Opcode(Mnemonic::Add)),
            "call"  => Some(Token::Opcode(Mnemonic::Call)),
            "cls"   => Some(Token::Opcode(Mnemonic::Cls)),
            "drw"   => Some(Token::Opcode(Mnemonic::Drw)),
            "jp"    => Some(Token::Opcode(Mnemonic::Jp)),
            "ld"    => Some(Token::Opcode(Mnemonic::Ld)),
            "or"    => Some(Token::Opcode(Mnemonic::Or)),
            "ret"   => Some(Token::Opcode(Mnemonic::Ret)),
            "rnd"   => Some(Token::Opcode(Mnemonic::Rnd)),
            "se"    => Some(Token::Opcode(Mnemonic::Se)),
            "shl"   => Some(Token::Opcode(Mnemonic::Shl)),
            "shr"   => Some(Token::Opcode(Mnemonic::Shr)),
            "sknp"  => Some(Token::Opcode(Mnemonic::Sknp)),
            "skp"   => Some(Token::Opcode(Mnemonic::Skp)),
            "sne"   => Some(Token::Opcode(Mnemonic::Sne)),
            "sub"   => Some(Token::Opcode(Mnemonic::Sub)),
            "subn"  => Some(Token::Opcode(Mnemonic::Subn)),
            "sys"   => Some(Token::Opcode(Mnemonic::Sys)),
            "xor"   => Some(Token::Opcode(Mnemonic::Xor)),
            _       => None
        }
    }

    fn is_separator(b: u8) -> bool {
        match b as char {
            ','|' '|'\n' => { true }
            _ => { false }
        }
    }

    fn is_register(input: &str) -> bool {
        input == "v0" || input == "v1" || input == "v2" ||
        input == "v3" || input == "v4" || input == "v5" ||
        input == "v6" || input == "v7" || input == "v8" ||
        input == "v9" || input == "va" || input == "vb" ||
        input == "vc" || input == "vd" || input == "ve" ||
        input == "vf" || input == "sp" || input == "st" ||
        input == "dt" || input == "pc" || input == "i" ||
        input == "[i]"
    }

    fn is_numeric(input: &str) -> bool {
        if input.len() < 1 {
            return false;
        }

        let in_bytes = input.as_bytes();
        if !Stream::is_ascii_numeric(in_bytes[0]) {
            return false;
        }

        // hex
        if input.starts_with("0x") {
            for i in 2..(in_bytes.len()) {
                if !Stream::is_ascii_hex(in_bytes[i]) {
                    return false
                }
                return true
            }
        } else {
            for b in in_bytes {
                if !Stream::is_ascii_numeric(*b) {
                    return false
                }
                return true
            }
        }
        false
    }

    fn is_ascii_numeric(input: u8) -> bool {
        input >= 48 && input <= 57
    }

    fn is_ascii_hex(input: u8) -> bool {
        (input >= 48 && input <= 57) || ((input >= 97 && input <= 102) || (input >= 65 && input <= 70))
    }
}

fn main() {
}
<|endoftext|>


<commit_before>#![feature(plugin, custom_derive)]
#![plugin(maud_macros)]
#![plugin(serde_macros)]

extern crate maud;
extern crate iron;
extern crate router;
extern crate logger;
extern crate git2;
extern crate serde;
extern crate serde_json;
extern crate pulldown_cmark;

use pulldown_cmark::html;
use std::env;
use iron::prelude::*;
use iron::status;
use router::*;
use logger::*;
use iron::mime::Mime;
use git2::{Oid, Repository};

struct Markdown<'a>(&'a str);

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Review {
  timestamp: Option<String>,
  reviewRef: Option<String>,
  targetRef: String,
  requester: Option<String>,
  reviewers: Option<Vec<String>>,
  description: Option<String>,
  v: Option<u8>,
  baseCommit: Option<String>,
}

impl<'a> maud::Render for &'a Markdown<'a> {
  fn render(&self, w: &mut std::fmt::Write) -> std::fmt::Result {
    use std::fmt::Write;
    let mut s = String::with_capacity(self.0.len() * 3 / 2);
    let p = pulldown_cmark::Parser::new(&self.0);
    html::push_html(&mut s, p);
    write!(w, "{}", s)
  }
}

fn main() {
  let path = env::args().nth(1).unwrap();
  let repo = Repository::open(path).unwrap();
  let name = repo.head().unwrap().name().unwrap().to_string();
  let reviews: Vec<(Oid, Review)> = repo
    .notes(Some("refs/notes/devtools/reviews"))
    .unwrap()
    .map(|(_, id)| {
      let note = repo.find_note(Some("refs/notes/devtools/reviews"), id).unwrap();
      let review = serde_json::de::from_str(note.message().unwrap().lines().nth(0).unwrap()).unwrap();
      (id, review)
    })
    .collect();

  let r2 = reviews.clone();

  let mut router = Router::new();
  router.get("/",
    move |_: &mut Request| -> IronResult<Response> {
      let content_type = "text/html".parse::<Mime>().unwrap();
      let mut buffer = String::new();
      html!(buffer, {
        ol {
          #for &(ref id, ref review) in &reviews {
            li {
              a href={ "/" $id } $id
              " -> "
              $(serde_json::ser::to_string_pretty(review).unwrap())
            }
          }
        }
      }).unwrap();
      Ok(Response::with((content_type, status::Ok, buffer)))
    });

  router.get("/:query",
    move |req: &mut Request| -> IronResult<Response> {
      let ref query = req.extensions.get::<Router>().unwrap().find("query").unwrap();
      let content_type = "text/html".parse::<Mime>().unwrap();
      let &(ref id, ref review) = r2.iter().filter(|&&(ref id, _)| *id == Oid::from_str(query).unwrap()).nth(0).unwrap();
      let mut buffer = String::new();
      let description = review.description.as_ref().map(|des| Markdown(des));
      html!(buffer, {
        ul {
          #if let Some(ref requester) = review.requester {
            li { "Requester: " $requester }
          }
          #if let Some(ref timestamp) = review.timestamp {
            li { "Timestamp: " $timestamp }
          }
          #if let Some(ref review_ref) = review.reviewRef {
            li { "Proposed merge: " $review_ref " -> " $review.targetRef }
          }
          #if let Some(ref reviewers) = review.reviewers {
            li { "Reviewers:"
              ul {
                #for reviewer in reviewers {
                  li $reviewer
                }
              }
            }
          }
          #if let Some(ref description) = description {
            li {
              "Description: "
              $description
            }
          }
        }
      }).unwrap();
      Ok(Response::with((content_type, status::Ok, buffer)))
    });

  let (logger_before, logger_after) = Logger::new(None);

  let mut chain = Chain::new(router);

  // Link logger_before as your first before middleware.
  chain.link_before(logger_before);

  // Link logger_after as your *last* after middleware.
  chain.link_after(logger_after);

  Iron::new(chain).http("localhost:3000").unwrap();
}
<commit_msg>Add some basic style<commit_after>#![feature(plugin, custom_derive)]
#![plugin(maud_macros)]
#![plugin(serde_macros)]

extern crate maud;
extern crate iron;
extern crate router;
extern crate logger;
extern crate git2;
extern crate serde;
extern crate serde_json;
extern crate pulldown_cmark;

use maud::PreEscaped;
use pulldown_cmark::html;
use std::env;
use iron::prelude::*;
use iron::status;
use router::*;
use logger::*;
use iron::mime::Mime;
use git2::{Oid, Repository};

struct Markdown<'a>(&'a str);

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Review {
  timestamp: Option<String>,
  reviewRef: Option<String>,
  targetRef: String,
  requester: Option<String>,
  reviewers: Option<Vec<String>>,
  description: Option<String>,
  v: Option<u8>,
  baseCommit: Option<String>,
}

impl<'a> maud::Render for &'a Markdown<'a> {
  fn render(&self, w: &mut std::fmt::Write) -> std::fmt::Result {
    use std::fmt::Write;
    let mut s = String::with_capacity(self.0.len() * 3 / 2);
    let p = pulldown_cmark::Parser::new(&self.0);
    html::push_html(&mut s, p);
    write!(w, "{}", s)
  }
}

fn style() -> String {
  format!("
    html * {{
      color-profile: sRGB;
      rendering-intent: auto;
    }}

    body {{
      background-color: {base03};
      color: {base0};
    }}

    h1, h2, h3, h4, h5, h6 {{
      color: {base1};
      border-color: {base0};
    }}

    body {{
      font-family: \"Raleway\", \"HelveticaNeue\", \"Helvetica Neue\", Helvetica, Arial, sans-serif;
      margin: 20px auto;
      max-width: 650px;
      line-height: 1.4;
      font-size: 18px;
      padding: 0 10px;
    }}

    h1,h2,h3 {{
      font-family: \"Lucida Console\", Monaco, monospace;
      line-height: 1.2;
    }}

    a {{
      color: {blue};
      text-decoration: none;
      cursor: pointer;
    }}

    a:hover {{
      color: {lightblue}
    }}
  ",
    base03 = "#002b36",
    // base02 = "#073642",
    // base01 = "#586e75",
    // base00 = "#657b83",
    base0 = "#839496",
    base1 = "#93a1a1",
    // base2 = "#eee8d5",
    // base3 = "#fdf6e3",
    // yellow = "#b58900",
    // orange = "#cb4b16",
    // red = "#dc322f",
    // magenta = "#d33682",
    // violet = "#6c71c4",
    blue = "#268bd2",
    // cyan = "#2aa198",
    // green = "#859900",
    lightblue = "#3797db"
  )
}

fn main() {
  let path = env::args().nth(1).unwrap();
  let repo = Repository::open(path).unwrap();
  let name = repo.head().unwrap().name().unwrap().to_string();
  let reviews: Vec<(Oid, Review)> = repo
    .notes(Some("refs/notes/devtools/reviews"))
    .unwrap()
    .map(|(_, id)| {
      let note = repo.find_note(Some("refs/notes/devtools/reviews"), id).unwrap();
      let review = serde_json::de::from_str(note.message().unwrap().lines().nth(0).unwrap()).unwrap();
      (id, review)
    })
    .collect();

  let r2 = reviews.clone();

  let mut router = Router::new();
  router.get("/",
    move |_: &mut Request| -> IronResult<Response> {
      let content_type = "text/html".parse::<Mime>().unwrap();
      let mut buffer = String::new();
      html!(buffer, {
        head {
          style type="text/css" {
            $PreEscaped(style())
          }
        }
        body {
          ol {
            #for &(ref id, ref review) in &reviews {
              li {
                a href={ "/" $id } $id
                " -> "
                $(serde_json::ser::to_string_pretty(review).unwrap())
              }
            }
          }
        }
      }).unwrap();
      Ok(Response::with((content_type, status::Ok, buffer)))
    });

  router.get("/:query",
    move |req: &mut Request| -> IronResult<Response> {
      let ref query = req.extensions.get::<Router>().unwrap().find("query").unwrap();
      let content_type = "text/html".parse::<Mime>().unwrap();
      let &(ref id, ref review) = r2.iter().filter(|&&(ref id, _)| *id == Oid::from_str(query).unwrap()).nth(0).unwrap();
      let mut buffer = String::new();
      let description = review.description.as_ref().map(|des| Markdown(des));
      html!(buffer, {
        head {
          style type="text/css" {
            $PreEscaped(style())
          }
        }
        body {
          ul {
            #if let Some(ref requester) = review.requester {
              li { "Requester: " $requester }
            }
            #if let Some(ref timestamp) = review.timestamp {
              li { "Timestamp: " $timestamp }
            }
            #if let Some(ref review_ref) = review.reviewRef {
              li { "Proposed merge: " $review_ref " -> " $review.targetRef }
            }
            #if let Some(ref reviewers) = review.reviewers {
              li { "Reviewers:"
                ul {
                  #for reviewer in reviewers {
                    li $reviewer
                  }
                }
              }
            }
            #if let Some(ref description) = description {
              li {
                "Description: "
                $description
              }
            }
          }
        }
      }).unwrap();
      Ok(Response::with((content_type, status::Ok, buffer)))
    });

  let (logger_before, logger_after) = Logger::new(None);

  let mut chain = Chain::new(router);

  // Link logger_before as your first before middleware.
  chain.link_before(logger_before);

  // Link logger_after as your *last* after middleware.
  chain.link_after(logger_after);

  Iron::new(chain).http("localhost:3000").unwrap();
}
<|endoftext|>


<commit_before>extern crate toml;

use std::{env, process};
use std::io::prelude::*;
use std::io::{BufReader, ErrorKind};
use std::collections::BTreeMap;
use std::fs::File;

static OVERRIDES_PATH : &'static str = ".multirust/overrides";
static SETTINGS_PATH : &'static str = ".rustup/settings.toml";
static OLD_SETTINGS_PATH : &'static str = ".multirust/settings.toml";

enum OverridesDatabase {
    Plain(BTreeMap<String, String>),
    Toml(BTreeMap<String, toml::Value>),
}

impl OverridesDatabase {
    pub fn get(&self, key: &str) -> Option<&str> {
        use OverridesDatabase::*;

        match *self {
            Plain(ref db) => db.get(key).map(|s| &s[..]),
            Toml(ref db) => {
                db.get(key).map(|v| v.as_str().expect("Expected value is not a string."))
            }
        }
    }
}

fn with_date<'a>(short: &'a str, toolchain: &'a str) -> Option<&'a str> {
    let date_start = short.len() + 1;
    let date_end   = short.len() + 3 + 4 + 2 + 2;
    let char_range = toolchain.chars()
        .skip(date_start)
        .take(4)
        .all(char::is_numeric);

    if toolchain.len() > date_start && char_range {
        Some(&toolchain[0..date_end])
    } else {
        None
    }
}

fn clean_toolchain_name(toolchain: &str) -> &str {
    static SHORTNAMES : &'static [&'static str] = &["stable", "nightly", "beta"];

    for short in SHORTNAMES {
        if toolchain.starts_with(short) {
            return match with_date(short, toolchain) {
                Some(s) => s,
                None => short
            }
        }
    }

    toolchain
}

fn plain_overrides_file(f: File) {
    let overrides = BufReader::new(f);

    let mut overrides_map = BTreeMap::new();

    for line in overrides.lines() {
        let line = line.expect("No valid line found");
        let mut s = line.split(';');
        let path = s.next().expect("No path in line");
        let toolchain = s.next().expect("No toolchain in line");

        overrides_map.insert(path.into(), toolchain.into());
    }

    let database = OverridesDatabase::Plain(overrides_map);
    toolchain(database);
}

fn settings_toml(mut settings: File) -> Result<(), ()> {
    let mut content = String::new();
    settings.read_to_string(&mut content).expect("Can't read settings file");

    let database = try!(toml::Parser::new(&content).parse()
        .and_then(|toml| toml.get("overrides").cloned())
        .and_then(|overrides| overrides.as_table().cloned())
        .and_then(|database| Some(OverridesDatabase::Toml(database)))
        .ok_or(()));

    toolchain(database);
    Ok(())
}

fn toolchain(database: OverridesDatabase) {
    let mut cwd = env::current_dir().expect("No valid working directory");

    loop {
        let path = format!("{}", cwd.display());

        if let Some(toolchain) =  database.get(&path) {
            println!("{}", clean_toolchain_name(toolchain));
            return;
        }

        if !cwd.pop() {
            break;
        }
    }
    println!("default");
}

fn main() {
    let home = env::home_dir().expect("Impossible to get your home dir!");

    let mut overrides_path = home.clone();
    overrides_path.push(OVERRIDES_PATH);

    match File::open(&overrides_path) {
        Ok(f) => {
            plain_overrides_file(f);
            process::exit(0);
        },
        Err(ref e) if e.kind() == ErrorKind::NotFound => { /* ignored */ },
        Err(_) => {
            println!("default");
            process::exit(0);
        }
    }

    let mut settings_path = home.clone();
    settings_path.push(SETTINGS_PATH);

    if let Ok(f) = File::open(&settings_path) {
        settings_toml(f).unwrap_or_else(|_| println!("default"));
        process::exit(0);
    }

    let mut settings_path = home.clone();
    settings_path.push(OLD_SETTINGS_PATH);
    println!("Fall through");

    if let Ok(f) = File::open(&settings_path) {
        settings_toml(f).unwrap_or_else(|_| println!("default"));
        process::exit(0);
    }

    println!("default");
}

#[cfg(test)]
mod test {
    use super::clean_toolchain_name;

    #[test]
    fn simple_name() {
        assert_eq!("nightly", clean_toolchain_name("nightly-x86_64-unknown-linux-gnu"));
        assert_eq!("nightly", clean_toolchain_name("nightly"));
    }

    #[test]
    fn name_with_date() {
        assert_eq!("nightly-2016-06-05", clean_toolchain_name("nightly-2016-06-05-x86_64-unknown-linux-gnu"));
    }
}
<commit_msg>feat: Don't print anything if there if the cwd is non-existent<commit_after>extern crate toml;

use std::{env, process};
use std::io::prelude::*;
use std::io::{BufReader, ErrorKind};
use std::collections::BTreeMap;
use std::fs::File;

static OVERRIDES_PATH : &'static str = ".multirust/overrides";
static SETTINGS_PATH : &'static str = ".rustup/settings.toml";
static OLD_SETTINGS_PATH : &'static str = ".multirust/settings.toml";

enum OverridesDatabase {
    Plain(BTreeMap<String, String>),
    Toml(BTreeMap<String, toml::Value>),
}

impl OverridesDatabase {
    pub fn get(&self, key: &str) -> Option<&str> {
        use OverridesDatabase::*;

        match *self {
            Plain(ref db) => db.get(key).map(|s| &s[..]),
            Toml(ref db) => {
                db.get(key).map(|v| v.as_str().expect("Expected value is not a string."))
            }
        }
    }
}

fn with_date<'a>(short: &'a str, toolchain: &'a str) -> Option<&'a str> {
    let date_start = short.len() + 1;
    let date_end   = short.len() + 3 + 4 + 2 + 2;
    let char_range = toolchain.chars()
        .skip(date_start)
        .take(4)
        .all(char::is_numeric);

    if toolchain.len() > date_start && char_range {
        Some(&toolchain[0..date_end])
    } else {
        None
    }
}

fn clean_toolchain_name(toolchain: &str) -> &str {
    static SHORTNAMES : &'static [&'static str] = &["stable", "nightly", "beta"];

    for short in SHORTNAMES {
        if toolchain.starts_with(short) {
            return match with_date(short, toolchain) {
                Some(s) => s,
                None => short
            }
        }
    }

    toolchain
}

fn plain_overrides_file(f: File) {
    let overrides = BufReader::new(f);

    let mut overrides_map = BTreeMap::new();

    for line in overrides.lines() {
        let line = line.expect("No valid line found");
        let mut s = line.split(';');
        let path = s.next().expect("No path in line");
        let toolchain = s.next().expect("No toolchain in line");

        overrides_map.insert(path.into(), toolchain.into());
    }

    let database = OverridesDatabase::Plain(overrides_map);
    toolchain(database);
}

fn settings_toml(mut settings: File) -> Result<(), ()> {
    let mut content = String::new();
    settings.read_to_string(&mut content).expect("Can't read settings file");

    let database = try!(toml::Parser::new(&content).parse()
        .and_then(|toml| toml.get("overrides").cloned())
        .and_then(|overrides| overrides.as_table().cloned())
        .and_then(|database| Some(OverridesDatabase::Toml(database)))
        .ok_or(()));

    toolchain(database);
    Ok(())
}

fn toolchain(database: OverridesDatabase) {
    let mut cwd = match env::current_dir() {
        Ok(cwd) => cwd,
        Err(_) => return,
    };

    loop {
        let path = format!("{}", cwd.display());

        if let Some(toolchain) =  database.get(&path) {
            println!("{}", clean_toolchain_name(toolchain));
            return;
        }

        if !cwd.pop() {
            break;
        }
    }
    println!("default");
}

fn main() {
    let home = env::home_dir().expect("Impossible to get your home dir!");

    let mut overrides_path = home.clone();
    overrides_path.push(OVERRIDES_PATH);

    match File::open(&overrides_path) {
        Ok(f) => {
            plain_overrides_file(f);
            process::exit(0);
        },
        Err(ref e) if e.kind() == ErrorKind::NotFound => { /* ignored */ },
        Err(_) => {
            println!("default");
            process::exit(0);
        }
    }

    let mut settings_path = home.clone();
    settings_path.push(SETTINGS_PATH);

    if let Ok(f) = File::open(&settings_path) {
        settings_toml(f).unwrap_or_else(|_| println!("default"));
        process::exit(0);
    }

    let mut settings_path = home.clone();
    settings_path.push(OLD_SETTINGS_PATH);
    println!("Fall through");

    if let Ok(f) = File::open(&settings_path) {
        settings_toml(f).unwrap_or_else(|_| println!("default"));
        process::exit(0);
    }

    println!("default");
}

#[cfg(test)]
mod test {
    use super::clean_toolchain_name;

    #[test]
    fn simple_name() {
        assert_eq!("nightly", clean_toolchain_name("nightly-x86_64-unknown-linux-gnu"));
        assert_eq!("nightly", clean_toolchain_name("nightly"));
    }

    #[test]
    fn name_with_date() {
        assert_eq!("nightly-2016-06-05", clean_toolchain_name("nightly-2016-06-05-x86_64-unknown-linux-gnu"));
    }
}
<|endoftext|>