<commit_before>
use color::Color;
use graphics::{
    AddColor,
    AddLine,
    AddRoundBorder,
    Context,
    Draw,
};
use label;
use label::FontSize;
use mouse_state::{
    MouseState,
    Up,
    Down,
};
use opengl_graphics::Gl;
use piston::input::keyboard::{
    Backspace,
    Left,
    Right,
    Return,
};
use point::Point;
use rectangle;
use std::num::abs;
use time::precise_time_s;
use ui_context::{
    UIID,
    UIContext,
};
use widget::TextBox;

pub type Idx = uint;
pub type CursorX = f64;

/// Represents the state of the text_box widget.
#[deriving(Show, PartialEq, Clone)]
pub struct State(DrawState, Capturing);

/// Represents the next tier of state.
#[deriving(Show, PartialEq, Clone)]
pub enum DrawState {
    Normal,
    Highlighted(Element),
    Clicked(Element),
}

/// Whether the textbox is currently captured or not.
#[deriving(Show, PartialEq, Clone)]
pub enum Capturing {
    Uncaptured,
    Captured(Idx, CursorX),
}

/// Represents an element of the TextBox widget.
#[deriving(Show, PartialEq, Clone)]
pub enum Element {
    Nill,
    Rect,
    Text(Idx, CursorX),
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State(state, capturing) => match capturing {
                Captured(_, _) => rectangle::Normal,
                Uncaptured => match state {
                    Normal => rectangle::Normal,
                    Highlighted(_) => rectangle::Highlighted,
                    Clicked(_) => rectangle::Clicked,
                },
            }
        }
    }
}

widget_fns!(TextBox, State, TextBox(State(Normal, Uncaptured)))

static TEXT_PADDING: f64 = 5f64;

/// Check if cursor is over the pad and if so, which
fn over_elem(uic: &mut UIContext,
             pos: Point<f64>,
             mouse_pos: Point<f64>,
             rect_w: f64,
             rect_h: f64,
             pad_pos: Point<f64>,
             pad_w: f64,
             pad_h: f64,
             text_pos: Point<f64>,
             text_w: f64,
             font_size: FontSize,
             text: &str) -> Element {
    match rectangle::is_over(pos, mouse_pos, rect_w, rect_h) {
        false => Nill,
        true => match rectangle::is_over(pad_pos, mouse_pos, pad_w, pad_h) {
            false => Rect,
            true => {
                let (idx, cursor_x) = closest_idx(uic, mouse_pos, text_pos.x, text_w, font_size, text);
                Text(idx, cursor_x)
            },
        },
    }
}

/// Check which character is closest to the mouse cursor.
fn closest_idx(uic: &mut UIContext,
               mouse_pos: Point<f64>,
               text_x: f64,
               text_w: f64,
               font_size: FontSize,
               text: &str) -> (Idx, f64) {
    if mouse_pos.x <= text_x { return (0u, text_x) }
    let mut x = text_x;
    let mut prev_x = x;
    let mut left_x = text_x;
    for (i, ch) in text.chars().enumerate() {
        let character = uic.get_character(font_size, ch);
        let char_w = (character.glyph.advance().x >> 16) as f64;
        x += char_w;
        let right_x = prev_x + char_w / 2.0;
        if mouse_pos.x > left_x && mouse_pos.x < right_x { return (i, prev_x) }
        prev_x = x;
        left_x = right_x;
    }
    (text.len(), text_x + text_w)
}

/// Check and return the current state of the TextBox.
fn get_new_state(over_elem: Element,
                 prev_box_state: State,
                 mouse: MouseState) -> State {
    match prev_box_state {
        State(prev, Uncaptured) => {
            match (over_elem, prev, mouse.left) {
                (_, Normal, Down) => State(Normal, Uncaptured),
                (Nill, Normal, Up) | (Nill, Highlighted(_), Up) => State(Normal, Uncaptured),
                (_, Normal, Up) | (_, Highlighted(_), Up) => State(Highlighted(over_elem), Uncaptured),
                (_, Highlighted(p_elem), Down) | (_, Clicked(p_elem), Down) =>
                    State(Clicked(p_elem), Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (Nill, _, _) => State(Normal, Uncaptured),
                _ => prev_box_state,
            }
        },
        State(prev, Captured(p_idx, p_x)) => {
            match (over_elem, prev, mouse.left) {
                (Nill, Clicked(Nill), Up) => State(Normal, Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (_, Normal, Up) | (_, Highlighted(_), Up) | (_, Clicked(_), Up)  =>
                    State(Highlighted(over_elem), Captured(p_idx, p_x)),
                (_, Highlighted(p_elem), Down) | (_, Clicked(p_elem), Down) =>
                    State(Clicked(p_elem), Captured(p_idx, p_x)),
                _ => prev_box_state,
            }
        },
    }
}

/// Draw the text cursor.
fn draw_cursor(win_w: f64,
               win_h: f64,
               gl: &mut Gl,
               color: Color,
               cursor_x: f64,
               pad_pos_y: f64,
               pad_h: f64) {
    let context = Context::abs(win_w, win_h);
    let (r, g, b, a) = color.plain_contrast().as_tuple();
    context
        .line(cursor_x, pad_pos_y, cursor_x, pad_pos_y + pad_h)
        .round_border_width(1f64)
        .rgba(r, g, b, abs(a * (precise_time_s() * 2.5).sin() as f32))
        .draw(gl);
}

/// A context on which the builder pattern can be implemented.
pub struct TextBoxContext<'a> {
    uic: &'a mut UIContext,
    ui_id: UIID,
    text: &'a mut String,
    font_size: u32,
    pos: Point<f64>,
    width: f64,
    height: f64,
    maybe_callback: Option<|&mut String|:'a>,
    maybe_color: Option<Color>,
    maybe_frame: Option<(f64, Color)>,
}

impl<'a> TextBoxContext<'a> {
    pub fn font_size(self, font_size: FontSize) -> TextBoxContext<'a> {
        TextBoxContext { font_size: font_size, ..self }
    }
}

pub trait TextBoxBuilder<'a> {
    /// An text box builder method to be implemented by the UIContext.
    fn text_box(&'a mut self, ui_id: UIID, text: &'a mut String) -> TextBoxContext<'a>;
}

impl<'a> TextBoxBuilder<'a> for UIContext {
    /// Initialise a TextBoxContext.
    fn text_box(&'a mut self, ui_id: UIID, text: &'a mut String) -> TextBoxContext<'a> {
        TextBoxContext {
            uic: self,
            ui_id: ui_id,
            text: text,
            font_size: 24u32, // Default font_size.
            pos: Point::new(0.0, 0.0, 0.0),
            width: 192.0,
            height: 48.0,
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
        }
    }
}

impl_callable!(TextBoxContext, |&mut String|:'a)
impl_colorable!(TextBoxContext)
impl_frameable!(TextBoxContext)
impl_positionable!(TextBoxContext)
impl_shapeable!(TextBoxContext)

impl<'a> ::draw::Drawable for TextBoxContext<'a> {
    #[inline]
    fn draw(&mut self, gl: &mut Gl) {
        let mouse = self.uic.get_mouse_state();
        let state = *get_state(self.uic, self.ui_id);

        // Rect.
        let color = self.maybe_color.unwrap_or(::std::default::Default::default());
        let frame_w = match self.maybe_frame { Some((w, _)) => w, None => 0.0 };
        let frame_w2 = frame_w * 2.0;
        let pad_pos = self.pos + Point::new(frame_w, frame_w, 0.0);
        let pad_w = self.width - frame_w2;
        let pad_h = self.height - frame_w2;
        let text_x = pad_pos.x + TEXT_PADDING;
        let text_y = pad_pos.y + (pad_h - self.font_size as f64) / 2.0;
        let text_pos = Point::new(text_x, text_y, 0.0);
        let text_w = label::width(self.uic, self.font_size, self.text.as_slice());
        let over_elem = over_elem(self.uic, self.pos, mouse.pos, self.width, self.height,
                                  pad_pos, pad_w, pad_h, text_pos, text_w,
                                  self.font_size, self.text.as_slice());
        let new_state = get_new_state(over_elem, state, mouse);

        rectangle::draw(self.uic.win_w, self.uic.win_h, gl, new_state.as_rectangle_state(),
                        self.pos, self.width, self.height, self.maybe_frame, color);
        label::draw(gl, self.uic, text_pos, self.font_size,
                    color.plain_contrast(), self.text.as_slice());

        let new_state = match new_state { State(w_state, capturing) => match capturing {
            Uncaptured => new_state,
            Captured(idx, cursor_x) => {
                draw_cursor(self.uic.win_w, self.uic.win_h, gl, color,
                            cursor_x, pad_pos.y, pad_h);
                let mut new_idx = idx;
                let mut new_cursor_x = cursor_x;

                // Check for entered text.
                let entered_text = self.uic.get_entered_text();
                for t in entered_text.iter() {
                    let mut entered_text_width = 0f64;
                    for ch in t.as_slice().chars() {
                        let c = self.uic.get_character(self.font_size, ch);
                        entered_text_width += (c.glyph.advance().x >> 16) as f64;
                    }
                    if new_cursor_x + entered_text_width < pad_pos.x + pad_w - TEXT_PADDING {
                        new_cursor_x += entered_text_width;
                    }
                    else {
                        break;
                    }
                    let new_text = format!("{}{}{}", self.text.as_slice().slice_to(idx),
                                           t, self.text.as_slice().slice_from(idx));
                    *self.text = new_text;
                    new_idx += t.len();
                }

                // Check for control keys.
                let pressed_keys = self.uic.get_pressed_keys();
                for key in pressed_keys.iter() {
                    match *key {
                        Backspace => {
                            if self.text.len() > 0u
                            && self.text.len() >= idx
                            && idx > 0u {
                                let rem_idx = idx - 1u;
                                new_cursor_x -= self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(rem_idx)
                                );
                                let new_text = format!("{}{}",
                                                       self.text.as_slice().slice_to(rem_idx),
                                                       self.text.as_slice().slice_from(idx));
                                *self.text = new_text;
                                new_idx = rem_idx;
                            }
                        },
                        Left => {
                            if idx > 0 {
                                new_cursor_x -= self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(idx - 1u)
                                );
                                new_idx -= 1u;
                            }
                        },
                        Right => {
                            if self.text.len() > idx {
                                new_cursor_x += self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(idx)
                                );
                                new_idx += 1u;
                            }
                        },
                        Return => if self.text.len() > 0u {
                            match self.maybe_callback {
                                Some(ref mut callback) => (*callback)(self.text),
                                None => (),
                            }
                        },
                        _ => (),
                    }
                }

                State(w_state, Captured(new_idx, new_cursor_x))
            },
        }};

        set_state(self.uic, self.ui_id, new_state,
                  self.pos.x, self.pos.y, self.width, self.height);

    }
}

<commit_msg>fix(text_box): handle text_box string mutating on Return press<commit_after>
use color::Color;
use graphics::{
    AddColor,
    AddLine,
    AddRoundBorder,
    Context,
    Draw,
};
use label;
use label::FontSize;
use mouse_state::{
    MouseState,
    Up,
    Down,
};
use opengl_graphics::Gl;
use piston::input::keyboard::{
    Backspace,
    Left,
    Right,
    Return,
};
use point::Point;
use rectangle;
use std::num::abs;
use time::precise_time_s;
use ui_context::{
    UIID,
    UIContext,
};
use widget::TextBox;
use std::cmp;

pub type Idx = uint;
pub type CursorX = f64;

/// Represents the state of the text_box widget.
#[deriving(Show, PartialEq, Clone)]
pub struct State(DrawState, Capturing);

/// Represents the next tier of state.
#[deriving(Show, PartialEq, Clone)]
pub enum DrawState {
    Normal,
    Highlighted(Element),
    Clicked(Element),
}

/// Whether the textbox is currently captured or not.
#[deriving(Show, PartialEq, Clone)]
pub enum Capturing {
    Uncaptured,
    Captured(Idx, CursorX),
}

/// Represents an element of the TextBox widget.
#[deriving(Show, PartialEq, Clone)]
pub enum Element {
    Nill,
    Rect,
    Text(Idx, CursorX),
}

impl State {
    /// Return the associated Rectangle state.
    fn as_rectangle_state(&self) -> rectangle::State {
        match self {
            &State(state, capturing) => match capturing {
                Captured(_, _) => rectangle::Normal,
                Uncaptured => match state {
                    Normal => rectangle::Normal,
                    Highlighted(_) => rectangle::Highlighted,
                    Clicked(_) => rectangle::Clicked,
                },
            }
        }
    }
}

widget_fns!(TextBox, State, TextBox(State(Normal, Uncaptured)))

static TEXT_PADDING: f64 = 5f64;

/// Check if cursor is over the pad and if so, which
fn over_elem(uic: &mut UIContext,
             pos: Point<f64>,
             mouse_pos: Point<f64>,
             rect_w: f64,
             rect_h: f64,
             pad_pos: Point<f64>,
             pad_w: f64,
             pad_h: f64,
             text_pos: Point<f64>,
             text_w: f64,
             font_size: FontSize,
             text: &str) -> Element {
    match rectangle::is_over(pos, mouse_pos, rect_w, rect_h) {
        false => Nill,
        true => match rectangle::is_over(pad_pos, mouse_pos, pad_w, pad_h) {
            false => Rect,
            true => {
                let (idx, cursor_x) = closest_idx(uic, mouse_pos, text_pos.x, text_w, font_size, text);
                Text(idx, cursor_x)
            },
        },
    }
}

/// Check which character is closest to the mouse cursor.
fn closest_idx(uic: &mut UIContext,
               mouse_pos: Point<f64>,
               text_x: f64,
               text_w: f64,
               font_size: FontSize,
               text: &str) -> (Idx, f64) {
    if mouse_pos.x <= text_x { return (0u, text_x) }
    let mut x = text_x;
    let mut prev_x = x;
    let mut left_x = text_x;
    for (i, ch) in text.chars().enumerate() {
        let character = uic.get_character(font_size, ch);
        let char_w = (character.glyph.advance().x >> 16) as f64;
        x += char_w;
        let right_x = prev_x + char_w / 2.0;
        if mouse_pos.x > left_x && mouse_pos.x < right_x { return (i, prev_x) }
        prev_x = x;
        left_x = right_x;
    }
    (text.len(), text_x + text_w)
}

/// Check and return the current state of the TextBox.
fn get_new_state(over_elem: Element,
                 prev_box_state: State,
                 mouse: MouseState) -> State {
    match prev_box_state {
        State(prev, Uncaptured) => {
            match (over_elem, prev, mouse.left) {
                (_, Normal, Down) => State(Normal, Uncaptured),
                (Nill, Normal, Up) | (Nill, Highlighted(_), Up) => State(Normal, Uncaptured),
                (_, Normal, Up) | (_, Highlighted(_), Up) => State(Highlighted(over_elem), Uncaptured),
                (_, Highlighted(p_elem), Down) | (_, Clicked(p_elem), Down) =>
                    State(Clicked(p_elem), Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (Nill, _, _) => State(Normal, Uncaptured),
                _ => prev_box_state,
            }
        },
        State(prev, Captured(p_idx, p_x)) => {
            match (over_elem, prev, mouse.left) {
                (Nill, Clicked(Nill), Up) => State(Normal, Uncaptured),
                (Text(idx, x), Clicked(Text(_, _)), Up) => State(Highlighted(over_elem), Captured(idx, x)),
                (_, Normal, Up) | (_, Highlighted(_), Up) | (_, Clicked(_), Up)  =>
                    State(Highlighted(over_elem), Captured(p_idx, p_x)),
                (_, Highlighted(p_elem), Down) | (_, Clicked(p_elem), Down) =>
                    State(Clicked(p_elem), Captured(p_idx, p_x)),
                _ => prev_box_state,
            }
        },
    }
}

/// Draw the text cursor.
fn draw_cursor(win_w: f64,
               win_h: f64,
               gl: &mut Gl,
               color: Color,
               cursor_x: f64,
               pad_pos_y: f64,
               pad_h: f64) {
    let context = Context::abs(win_w, win_h);
    let (r, g, b, a) = color.plain_contrast().as_tuple();
    context
        .line(cursor_x, pad_pos_y, cursor_x, pad_pos_y + pad_h)
        .round_border_width(1f64)
        .rgba(r, g, b, abs(a * (precise_time_s() * 2.5).sin() as f32))
        .draw(gl);
}

/// A context on which the builder pattern can be implemented.
pub struct TextBoxContext<'a> {
    uic: &'a mut UIContext,
    ui_id: UIID,
    text: &'a mut String,
    font_size: u32,
    pos: Point<f64>,
    width: f64,
    height: f64,
    maybe_callback: Option<|&mut String|:'a>,
    maybe_color: Option<Color>,
    maybe_frame: Option<(f64, Color)>,
}

impl<'a> TextBoxContext<'a> {
    pub fn font_size(self, font_size: FontSize) -> TextBoxContext<'a> {
        TextBoxContext { font_size: font_size, ..self }
    }
}

pub trait TextBoxBuilder<'a> {
    /// An text box builder method to be implemented by the UIContext.
    fn text_box(&'a mut self, ui_id: UIID, text: &'a mut String) -> TextBoxContext<'a>;
}

impl<'a> TextBoxBuilder<'a> for UIContext {
    /// Initialise a TextBoxContext.
    fn text_box(&'a mut self, ui_id: UIID, text: &'a mut String) -> TextBoxContext<'a> {
        TextBoxContext {
            uic: self,
            ui_id: ui_id,
            text: text,
            font_size: 24u32, // Default font_size.
            pos: Point::new(0.0, 0.0, 0.0),
            width: 192.0,
            height: 48.0,
            maybe_callback: None,
            maybe_color: None,
            maybe_frame: None,
        }
    }
}

impl_callable!(TextBoxContext, |&mut String|:'a)
impl_colorable!(TextBoxContext)
impl_frameable!(TextBoxContext)
impl_positionable!(TextBoxContext)
impl_shapeable!(TextBoxContext)

impl<'a> ::draw::Drawable for TextBoxContext<'a> {
    #[inline]
    fn draw(&mut self, gl: &mut Gl) {
        let mouse = self.uic.get_mouse_state();
        let state = *get_state(self.uic, self.ui_id);

        // Rect.
        let color = self.maybe_color.unwrap_or(::std::default::Default::default());
        let frame_w = match self.maybe_frame { Some((w, _)) => w, None => 0.0 };
        let frame_w2 = frame_w * 2.0;
        let pad_pos = self.pos + Point::new(frame_w, frame_w, 0.0);
        let pad_w = self.width - frame_w2;
        let pad_h = self.height - frame_w2;
        let text_x = pad_pos.x + TEXT_PADDING;
        let text_y = pad_pos.y + (pad_h - self.font_size as f64) / 2.0;
        let text_pos = Point::new(text_x, text_y, 0.0);
        let text_w = label::width(self.uic, self.font_size, self.text.as_slice());
        let over_elem = over_elem(self.uic, self.pos, mouse.pos, self.width, self.height,
                                  pad_pos, pad_w, pad_h, text_pos, text_w,
                                  self.font_size, self.text.as_slice());
        let new_state = get_new_state(over_elem, state, mouse);

        rectangle::draw(self.uic.win_w, self.uic.win_h, gl, new_state.as_rectangle_state(),
                        self.pos, self.width, self.height, self.maybe_frame, color);
        label::draw(gl, self.uic, text_pos, self.font_size,
                    color.plain_contrast(), self.text.as_slice());

        let new_state = match new_state { State(w_state, capturing) => match capturing {
            Uncaptured => new_state,
            Captured(idx, cursor_x) => {
                draw_cursor(self.uic.win_w, self.uic.win_h, gl, color,
                            cursor_x, pad_pos.y, pad_h);
                let mut new_idx = idx;
                let mut new_cursor_x = cursor_x;

                // Check for entered text.
                let entered_text = self.uic.get_entered_text();
                for t in entered_text.iter() {
                    let mut entered_text_width = 0f64;
                    for ch in t.as_slice().chars() {
                        let c = self.uic.get_character(self.font_size, ch);
                        entered_text_width += (c.glyph.advance().x >> 16) as f64;
                    }
                    if new_cursor_x + entered_text_width < pad_pos.x + pad_w - TEXT_PADDING {
                        new_cursor_x += entered_text_width;
                    }
                    else {
                        break;
                    }
                    let new_text = format!("{}{}{}", self.text.as_slice().slice_to(idx),
                                           t, self.text.as_slice().slice_from(idx));
                    *self.text = new_text;
                    new_idx += t.len();
                }

                // Check for control keys.
                let pressed_keys = self.uic.get_pressed_keys();
                for key in pressed_keys.iter() {
                    match *key {
                        Backspace => {
                            if self.text.len() > 0u
                            && self.text.len() >= idx
                            && idx > 0u {
                                let rem_idx = idx - 1u;
                                new_cursor_x -= self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(rem_idx)
                                );
                                let new_text = format!("{}{}",
                                                       self.text.as_slice().slice_to(rem_idx),
                                                       self.text.as_slice().slice_from(idx));
                                *self.text = new_text;
                                new_idx = rem_idx;
                            }
                        },
                        Left => {
                            if idx > 0 {
                                new_cursor_x -= self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(idx - 1u)
                                );
                                new_idx -= 1u;
                            }
                        },
                        Right => {
                            if self.text.len() > idx {
                                new_cursor_x += self.uic.get_character_w(
                                    self.font_size, self.text.as_slice().char_at(idx)
                                );
                                new_idx += 1u;
                            }
                        },
                        Return => if self.text.len() > 0u {
                            let TextBoxContext { // borrowck
                                ref mut maybe_callback,
                                ref mut uic,
                                ref font_size,
                                ref mut text,
                                ..
                            } = *self;
                            match *maybe_callback {
                                Some(ref mut callback) => {
                                    (*callback)(*text);

                                    new_idx = cmp::min(new_idx, text.len());
                                    new_cursor_x = text.as_slice()
                                                       .chars()
                                                       // Add text_pos.x for padding
                                                       .fold(text_pos.x, |acc, c| {
                                        acc + uic.get_character_w(*font_size, c)
                                    });
                                },
                                None => (),
                            }
                        },
                        _ => (),
                    }
                }

                State(w_state, Captured(new_idx, new_cursor_x))
            },
        }};

        set_state(self.uic, self.ui_id, new_state,
                  self.pos.x, self.pos.y, self.width, self.height);

    }
}

<|endoftext|>


<commit_before>//! A short tutorial on how to use vikos to solve the problem of supervised machine learning: We
//! want to predict values for a quantity (the target), and we have some data that we can base our
//! inference on (features). We have a data set (a history), that consists of features and
//! corresponding, *true* target values, so that we have a base to learn about how the target
//! relates to the feature data.
//! To do this we choose a function which relates the features to the target (the model). This
//! model depends on coefficients which are determined using a training algorithm and the history.
//! (teacher).
//!
//! # Tutorial
//! Look, a bunch of data! Let us do something with it.
//!
//! ```
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//! ```
//! The first elements of each tuple represent our *feature* vector,
//! the second elements represents the true (observed) *target* value
//! (aka *the truth*). We want to use a [Training](../trait.Training.html) to
//! find the coefficients of a  [Model](../trait.Model.html)
//! which minimizes a [Cost](../trait.Cost.html) function. Let us start with
//! finding the mean value of the truth.
//!
//! ## Estimating the mean target value
//!
//! ```
//! use vikos::{cost, teacher, learn_history};
//! // mean is 9, but of course we do not know that yet
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The mean is just a simple number ...
//! let mut model = 0.0;
//! // ... which minimizes the square error
//! let cost = cost::LeastSquares {};
//! // Use stochastic gradient descent with an annealed learning rate
//! let teacher = teacher::GradientDescentAl { l0: 0.3, t: 4.0 };
//! // Train 100 (admittedly repetitive) events
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().map(|&(x,y)|((),y)).take(100));
//! // Since we know the model's type is `f64`, we can just print it
//! println!("{}", model);
//! ```
//! As far as the mean is concerned, the first element of each tuple, i.e., the feature, is just
//! ignored. We use the map expression to replace it with an empty tuple '()' to show that this
//! model does not use features
//!
//! ## Estimating the median target value
//!
//! If we want to estimate the median instead, we only need to change
//! our cost function, to that of an absolute error:
//!
//! ```
//! use vikos::{cost, teacher, learn_history};
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//! // median is 7, but we don't know that yet of course
//!
//! // The median is just a simple number ...
//! let mut model = 0.0;
//! // ... which minimizes the absolute error
//! let cost = cost::LeastAbsoluteDeviation {};
//! let teacher = teacher::GradientDescentAl { l0: 1.0, t: 9.0 };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().map(|&(x,y)|((),y)).take(100));
//! ```
//! Most notably we changed the cost function to train for the median. We also had to
//! increase our learning rate to be able to converge to `7` more quickly. Maybe we
//! should try a slightly more sophisticated `Teacher` algorithm.
//!
//! ## Estimating median again
//!
//! ```
//! use vikos::{cost, teacher, learn_history};
//! // median is 7, but of course we do not know that yet
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The median is just a simple number ...
//! let mut model = 0.0;
//! // ... which minimizes the absolute error
//! let cost = cost::LeastAbsoluteDeviation {};
//! // Use stochasic gradient descent with an annealed learning rate and momentum
//! let teacher = teacher::Momentum {
//!     l0: 1.0,
//!     t: 3.0,
//!     inertia: 0.9,
//! };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().map(|&(x,y)|((),y)).take(100));
//! println!("{}", model);
//! ```
//! The momentum term allowed us to drop our learning rate way quicker and to retrieve a
//! more precise result in the same number of iterations. The algorithms and their
//! parameters are not the point however — the important thing is we could switch them
//! quite easily and independently of both cost function and model. Speaking of which:
//! it is time to fit a straight line through our data points.
//!
//! ## Line of best fit
//! We now use a linear model
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! // Best described by 2 * m - 3
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! let mut model = model::Linear { m: 0.0, c: 0.0 };
//! let cost = cost::LeastSquares {};
//! let teacher = teacher::Momentum {
//!     l0: 0.0001,
//!     t: 1000.0,
//!     inertia: 0.99,
//! };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().take(500).cloned());
//! for &(input, truth) in history.iter() {
//!     println!("Input: {}, Truth: {}, Prediction: {}",
//!              input,
//!              truth,
//!              model.predict(&input));
//! }
//! println!("slope: {}, intercept: {}", model.m, model.c);
//! ```
//! Note the use of the [Expert](../trait.Expert.html) trait to predict the target based the input.
//!
//! # Summary
//!
//! Using Vikos, we can build a machine-learning model by composing
//! implementations of three aspects:
//!
//!  * the describes how features and target relate to each other using an
//!    [Expert](../trait.Expert.html) algorithm and what kind of estimated parameters/coefficients
//!    mediate among the target and the feature space ([Model](../trait.Model.html)), the model is
//!    fitted by
//!  * the training algorithm, modelled with the [Teacher](../trait.Teacher.html) trait, that
//!    contains the optimization algorithm minimizing the model coefficients.
//!  * the [Cost](../trait.Cost.html) "function" describes the function that should be minimized by
//!    the algorithm.
<commit_msg>fixed dead link in tutorial<commit_after>//! A short tutorial on how to use vikos to solve the problem of supervised machine learning: We
//! want to predict values for a quantity (the target), and we have some data that we can base our
//! inference on (features). We have a data set (a history), that consists of features and
//! corresponding, *true* target values, so that we have a base to learn about how the target
//! relates to the feature data.
//! To do this we choose a function which relates the features to the target (the model). This
//! model depends on coefficients which are determined using a training algorithm and the history.
//! (teacher).
//!
//! # Tutorial
//! Look, a bunch of data! Let us do something with it.
//!
//! ```
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//! ```
//! The first elements of each tuple represent our *feature* vector,
//! the second elements represents the true (observed) *target* value
//! (aka *the truth*). We want to use a [Training](../trait.Training.html) to
//! find the coefficients of a  [Model](../trait.Model.html)
//! which minimizes a [Cost](../trait.Cost.html) function. Let us start with
//! finding the mean value of the truth.
//!
//! ## Estimating the mean target value
//!
//! ```
//! use vikos::{cost, teacher, learn_history};
//! // mean is 9, but of course we do not know that yet
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The mean is just a simple number ...
//! let mut model = 0.0;
//! // ... which minimizes the square error
//! let cost = cost::LeastSquares {};
//! // Use stochastic gradient descent with an annealed learning rate
//! let teacher = teacher::GradientDescentAl { l0: 0.3, t: 4.0 };
//! // Train 100 (admittedly repetitive) events
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().map(|&(x,y)|((),y)).take(100));
//! // Since we know the model's type is `f64`, we can just print it
//! println!("{}", model);
//! ```
//! As far as the mean is concerned, the first element of each tuple, i.e., the feature, is just
//! ignored. We use the map expression to replace it with an empty tuple '()' to show that this
//! model does not use features
//!
//! ## Estimating the median target value
//!
//! If we want to estimate the median instead, we only need to change
//! our cost function, to that of an absolute error:
//!
//! ```
//! use vikos::{cost, teacher, learn_history};
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//! // median is 7, but we don't know that yet of course
//!
//! // The median is just a simple number ...
//! let mut model = 0.0;
//! // ... which minimizes the absolute error
//! let cost = cost::LeastAbsoluteDeviation {};
//! let teacher = teacher::GradientDescentAl { l0: 1.0, t: 9.0 };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().map(|&(x,y)|((),y)).take(100));
//! ```
//! Most notably we changed the cost function to train for the median. We also had to
//! increase our learning rate to be able to converge to `7` more quickly. Maybe we
//! should try a slightly more sophisticated `Teacher` algorithm.
//!
//! ## Estimating median again
//!
//! ```
//! use vikos::{cost, teacher, learn_history};
//! // median is 7, but of course we do not know that yet
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! // The median is just a simple number ...
//! let mut model = 0.0;
//! // ... which minimizes the absolute error
//! let cost = cost::LeastAbsoluteDeviation {};
//! // Use stochasic gradient descent with an annealed learning rate and momentum
//! let teacher = teacher::Momentum {
//!     l0: 1.0,
//!     t: 3.0,
//!     inertia: 0.9,
//! };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().map(|&(x,y)|((),y)).take(100));
//! println!("{}", model);
//! ```
//! The momentum term allowed us to drop our learning rate way quicker and to retrieve a
//! more precise result in the same number of iterations. The algorithms and their
//! parameters are not the point however — the important thing is we could switch them
//! quite easily and independently of both cost function and model. Speaking of which:
//! it is time to fit a straight line through our data points.
//!
//! ## Line of best fit
//! We now use a linear model
//!
//! ```
//! use vikos::{model, cost, teacher, learn_history, Model};
//! // Best described by 2 * m - 3
//! let history = [
//!    (2.0, 1.0), (3.0, 3.0), (3.5, 4.0),
//!    (5.0, 7.0), (5.5, 8.0), (7.0, 11.0),
//!    (16.0, 29.0)
//! ];
//!
//! let mut model = model::Linear { m: 0.0, c: 0.0 };
//! let cost = cost::LeastSquares {};
//! let teacher = teacher::Momentum {
//!     l0: 0.0001,
//!     t: 1000.0,
//!     inertia: 0.99,
//! };
//! learn_history(&teacher,
//!               &cost,
//!               &mut model,
//!               history.iter().cycle().take(500).cloned());
//! for &(input, truth) in history.iter() {
//!     println!("Input: {}, Truth: {}, Prediction: {}",
//!              input,
//!              truth,
//!              model.predict(&input));
//! }
//! println!("slope: {}, intercept: {}", model.m, model.c);
//! ```
//! Note the use of the [Model](../trait.Model.html) trait to predict the target based the input.
//!
//! # Summary
//!
//! Using Vikos, we can build a machine-learning model by composing
//! implementations of three aspects:
//!
//!  * the expert algorithm describes how features and target relate to each other using an
//!    [Model](../trait.Model.html) trait and which also specifies what kind of estimated
//!    parameters/coefficients mediate among the target and the feature space
//!    ([Model](../trait.Model.html)), the model is fitted by
//!  * the training algorithm, modelled with the [Teacher](../trait.Teacher.html) trait, that
//!    contains the optimization algorithm minimizing the model coefficients.
//!  * the [Cost](../trait.Cost.html) "function" describes the function that should be minimized by
//!    the algorithm.
<|endoftext|>


<commit_before>// Copyright 2018 The Grin Developers
//
// 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.

//! Server types

use std::convert::From;
use std::sync::{Arc, RwLock};

use api;
use chain;
use core::global::ChainTypes;
use core::{core, pow};
use p2p;
use pool;
use store;
use util::LOGGER;
use wallet;

/// Error type wrapping underlying module errors.
#[derive(Debug)]
pub enum Error {
	/// Error originating from the core implementation.
	Core(core::block::Error),
	/// Error originating from the db storage.
	Store(store::Error),
	/// Error originating from the blockchain implementation.
	Chain(chain::Error),
	/// Error originating from the peer-to-peer network.
	P2P(p2p::Error),
	/// Error originating from HTTP API calls.
	API(api::Error),
	/// Error originating from wallet API.
	Wallet(wallet::Error),
	/// Error originating from the cuckoo miner
	Cuckoo(pow::cuckoo::Error),
}

impl From<core::block::Error> for Error {
	fn from(e: core::block::Error) -> Error {
		Error::Core(e)
	}
}
impl From<chain::Error> for Error {
	fn from(e: chain::Error) -> Error {
		Error::Chain(e)
	}
}

impl From<p2p::Error> for Error {
	fn from(e: p2p::Error) -> Error {
		Error::P2P(e)
	}
}

impl From<pow::cuckoo::Error> for Error {
	fn from(e: pow::cuckoo::Error) -> Error {
		Error::Cuckoo(e)
	}
}

impl From<store::Error> for Error {
	fn from(e: store::Error) -> Error {
		Error::Store(e)
	}
}

impl From<api::Error> for Error {
	fn from(e: api::Error) -> Error {
		Error::API(e)
	}
}

impl From<wallet::Error> for Error {
	fn from(e: wallet::Error) -> Error {
		Error::Wallet(e)
	}
}

/// Type of seeding the server will use to find other peers on the network.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ChainValidationMode {
	/// Run full chain validation after processing every block.
	EveryBlock,
	/// Do not automatically run chain validation during normal block
	/// processing.
	Disabled,
}

impl Default for ChainValidationMode {
	fn default() -> ChainValidationMode {
		ChainValidationMode::Disabled
	}
}

/// Type of seeding the server will use to find other peers on the network.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Seeding {
	/// No seeding, mostly for tests that programmatically connect
	None,
	/// A list of seed addresses provided to the server
	List,
	/// Automatically download a text file with a list of server addresses
	WebStatic,
	/// Automatically get a list of seeds from multiple DNS
	DNSSeed,
	/// Mostly for tests, where connections are initiated programmatically
	Programmatic,
}

impl Default for Seeding {
	fn default() -> Seeding {
		Seeding::DNSSeed
	}
}

/// Full server configuration, aggregating configurations required for the
/// different components.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ServerConfig {
	/// Directory under which the rocksdb stores will be created
	pub db_root: String,

	/// Network address for the Rest API HTTP server.
	pub api_http_addr: String,

	/// Setup the server for tests, testnet or mainnet
	#[serde(default)]
	pub chain_type: ChainTypes,

	/// Whether this node is a full archival node or a fast-sync, pruned node
	pub archive_mode: Option<bool>,

	/// Automatically run full chain validation during normal block processing?
	#[serde(default)]
	pub chain_validation_mode: ChainValidationMode,

	/// Method used to get the list of seed nodes for initial bootstrap.
	#[serde(default)]
	pub seeding_type: Seeding,

	/// TODO - move this into p2p_config?
	/// The list of seed nodes, if using Seeding as a seed type
	pub seeds: Option<Vec<String>>,

	/// TODO - move this into p2p_config?
	/// Capabilities expose by this node, also conditions which other peers this
	/// node will have an affinity toward when connection.
	pub capabilities: p2p::Capabilities,

	/// Configuration for the peer-to-peer server
	pub p2p_config: p2p::P2PConfig,

	/// Configuration for the mining daemon
	pub stratum_mining_config: Option<StratumServerConfig>,

	/// Transaction pool configuration
	#[serde(default)]
	pub pool_config: pool::PoolConfig,

	/// Dandelion configuration
	#[serde(default)]
	pub dandelion_config: pool::DandelionConfig,

	/// Whether to skip the sync timeout on startup
	/// (To assist testing on solo chains)
	pub skip_sync_wait: Option<bool>,

	/// Whether to run the TUI
	/// if enabled, this will disable logging to stdout
	pub run_tui: Option<bool>,

	/// Whether to run the wallet listener with the server by default
	pub run_wallet_listener: Option<bool>,

	/// Whether to run the web wallet owner listener
	pub run_wallet_owner_api: Option<bool>,

	/// Whether to use the DB wallet backend implementation
	pub use_db_wallet: Option<bool>,

	/// Whether to run the test miner (internal, cuckoo 16)
	pub run_test_miner: Option<bool>,

	/// Test miner wallet URL
	pub test_miner_wallet_url: Option<String>,
}

impl Default for ServerConfig {
	fn default() -> ServerConfig {
		ServerConfig {
			db_root: ".grin".to_string(),
			api_http_addr: "127.0.0.1:13413".to_string(),
			capabilities: p2p::Capabilities::FULL_NODE,
			seeding_type: Seeding::default(),
			seeds: None,
			p2p_config: p2p::P2PConfig::default(),
			dandelion_config: pool::DandelionConfig::default(),
			stratum_mining_config: Some(StratumServerConfig::default()),
			chain_type: ChainTypes::default(),
			archive_mode: None,
			chain_validation_mode: ChainValidationMode::default(),
			pool_config: pool::PoolConfig::default(),
			skip_sync_wait: Some(false),
			run_tui: Some(true),
			run_wallet_listener: Some(true),
			run_wallet_owner_api: Some(true),
			use_db_wallet: None,
			run_test_miner: Some(false),
			test_miner_wallet_url: None,
		}
	}
}

/// Stratum (Mining server) configuration
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct StratumServerConfig {
	/// Run a stratum mining server (the only way to communicate to mine this
	/// node via grin-miner
	pub enable_stratum_server: Option<bool>,

	/// If enabled, the address and port to listen on
	pub stratum_server_addr: Option<String>,

	/// How long to wait before stopping the miner, recollecting transactions
	/// and starting again
	pub attempt_time_per_block: u32,

	/// Minimum difficulty for worker shares
	pub minimum_share_difficulty: u64,

	/// Base address to the HTTP wallet receiver
	pub wallet_listener_url: String,

	/// Attributes the reward to a random private key instead of contacting the
	/// wallet receiver. Mostly used for tests.
	pub burn_reward: bool,
}

impl Default for StratumServerConfig {
	fn default() -> StratumServerConfig {
		StratumServerConfig {
			wallet_listener_url: "http://127.0.0.1:13415".to_string(),
			burn_reward: false,
			attempt_time_per_block: 15,
			minimum_share_difficulty: 1,
			enable_stratum_server: Some(true),
			stratum_server_addr: Some("127.0.0.1:13416".to_string()),
		}
	}
}

/// Various status sync can be in, whether it's fast sync or archival.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum SyncStatus {
	/// Initial State (we do not yet know if we are/should be syncing)
	Initial,
	/// Not syncing
	NoSync,
	/// Downloading block headers
	HeaderSync {
		current_height: u64,
		highest_height: u64,
	},
	/// Downloading the various txhashsets
	TxHashsetDownload,
	/// Setting up before validation
	TxHashsetSetup,
	/// Validating the full state
	TxHashsetValidation {
		kernels: u64,
		kernel_total: u64,
		rproofs: u64,
		rproof_total: u64,
	},
	/// Finalizing the new state
	TxHashsetSave,
	/// Downloading blocks
	BodySync {
		current_height: u64,
		highest_height: u64,
	},
}

/// Current sync state. Encapsulates the current SyncStatus.
pub struct SyncState {
	current: RwLock<SyncStatus>,
	sync_error: Arc<RwLock<Option<Error>>>,
}

impl SyncState {
	/// Return a new SyncState initialize to NoSync
	pub fn new() -> SyncState {
		SyncState {
			current: RwLock::new(SyncStatus::Initial),
			sync_error: Arc::new(RwLock::new(None)),
		}
	}

	/// Whether the current state matches any active syncing operation.
	/// Note: This includes our "initial" state.
	pub fn is_syncing(&self) -> bool {
		*self.current.read().unwrap() != SyncStatus::NoSync
	}

	/// Current syncing status
	pub fn status(&self) -> SyncStatus {
		*self.current.read().unwrap()
	}

	/// Update the syncing status
	pub fn update(&self, new_status: SyncStatus) {
		if self.status() == new_status {
			return;
		}

		let mut status = self.current.write().unwrap();

		debug!(
			LOGGER,
			"sync_state: sync_status: {:?} -> {:?}", *status, new_status,
		);

		*status = new_status;
	}

	/// Communicate sync error
	pub fn set_sync_error(&self, error: Error){
		*self.sync_error.write().unwrap() = Some(error);
	}

	/// Get sync error
	pub fn sync_error(&self) -> Arc<RwLock<Option<Error>>> {
		Arc::clone(&self.sync_error)
	}

	/// Clear sync error
	pub fn clear_sync_error(&self){
		*self.sync_error.write().unwrap() = None;
	}

}

impl chain::TxHashsetWriteStatus for SyncState {
	fn on_setup(&self) {
		self.update(SyncStatus::TxHashsetSetup);
	}

	fn on_validation(&self, vkernels: u64, vkernel_total: u64, vrproofs: u64, vrproof_total: u64) {
		let mut status = self.current.write().unwrap();
		match *status {
			SyncStatus::TxHashsetValidation {
				kernels,
				kernel_total,
				rproofs,
				rproof_total,
			} => {
				let ks = if vkernels > 0 { vkernels } else { kernels };
				let kt = if vkernel_total > 0 {
					vkernel_total
				} else {
					kernel_total
				};
				let rps = if vrproofs > 0 { vrproofs } else { rproofs };
				let rpt = if vrproof_total > 0 {
					vrproof_total
				} else {
					rproof_total
				};
				*status = SyncStatus::TxHashsetValidation {
					kernels: ks,
					kernel_total: kt,
					rproofs: rps,
					rproof_total: rpt,
				};
			}
			_ => {
				*status = SyncStatus::TxHashsetValidation {
					kernels: 0,
					kernel_total: 0,
					rproofs: 0,
					rproof_total: 0,
				}
			}
		}
	}

	fn on_save(&self) {
		self.update(SyncStatus::TxHashsetSave);
	}

	fn on_done(&self) {
		self.update(SyncStatus::BodySync {
			current_height: 0,
			highest_height: 0,
		});
	}
}
<commit_msg>Fix config defaults (#1376)<commit_after>// Copyright 2018 The Grin Developers
//
// 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.

//! Server types

use std::convert::From;
use std::sync::{Arc, RwLock};

use api;
use chain;
use core::global::ChainTypes;
use core::{core, pow};
use p2p;
use pool;
use store;
use util::LOGGER;
use wallet;

/// Error type wrapping underlying module errors.
#[derive(Debug)]
pub enum Error {
	/// Error originating from the core implementation.
	Core(core::block::Error),
	/// Error originating from the db storage.
	Store(store::Error),
	/// Error originating from the blockchain implementation.
	Chain(chain::Error),
	/// Error originating from the peer-to-peer network.
	P2P(p2p::Error),
	/// Error originating from HTTP API calls.
	API(api::Error),
	/// Error originating from wallet API.
	Wallet(wallet::Error),
	/// Error originating from the cuckoo miner
	Cuckoo(pow::cuckoo::Error),
}

impl From<core::block::Error> for Error {
	fn from(e: core::block::Error) -> Error {
		Error::Core(e)
	}
}
impl From<chain::Error> for Error {
	fn from(e: chain::Error) -> Error {
		Error::Chain(e)
	}
}

impl From<p2p::Error> for Error {
	fn from(e: p2p::Error) -> Error {
		Error::P2P(e)
	}
}

impl From<pow::cuckoo::Error> for Error {
	fn from(e: pow::cuckoo::Error) -> Error {
		Error::Cuckoo(e)
	}
}

impl From<store::Error> for Error {
	fn from(e: store::Error) -> Error {
		Error::Store(e)
	}
}

impl From<api::Error> for Error {
	fn from(e: api::Error) -> Error {
		Error::API(e)
	}
}

impl From<wallet::Error> for Error {
	fn from(e: wallet::Error) -> Error {
		Error::Wallet(e)
	}
}

/// Type of seeding the server will use to find other peers on the network.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum ChainValidationMode {
	/// Run full chain validation after processing every block.
	EveryBlock,
	/// Do not automatically run chain validation during normal block
	/// processing.
	Disabled,
}

impl Default for ChainValidationMode {
	fn default() -> ChainValidationMode {
		ChainValidationMode::Disabled
	}
}

/// Type of seeding the server will use to find other peers on the network.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum Seeding {
	/// No seeding, mostly for tests that programmatically connect
	None,
	/// A list of seed addresses provided to the server
	List,
	/// Automatically download a text file with a list of server addresses
	WebStatic,
	/// Automatically get a list of seeds from multiple DNS
	DNSSeed,
	/// Mostly for tests, where connections are initiated programmatically
	Programmatic,
}

impl Default for Seeding {
	fn default() -> Seeding {
		Seeding::DNSSeed
	}
}

/// Full server configuration, aggregating configurations required for the
/// different components.
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct ServerConfig {
	/// Directory under which the rocksdb stores will be created
	pub db_root: String,

	/// Network address for the Rest API HTTP server.
	pub api_http_addr: String,

	/// Setup the server for tests, testnet or mainnet
	#[serde(default)]
	pub chain_type: ChainTypes,

	/// Whether this node is a full archival node or a fast-sync, pruned node
	pub archive_mode: Option<bool>,

	/// Automatically run full chain validation during normal block processing?
	#[serde(default)]
	pub chain_validation_mode: ChainValidationMode,

	/// Method used to get the list of seed nodes for initial bootstrap.
	#[serde(default)]
	pub seeding_type: Seeding,

	/// TODO - move this into p2p_config?
	/// The list of seed nodes, if using Seeding as a seed type
	pub seeds: Option<Vec<String>>,

	/// TODO - move this into p2p_config?
	/// Capabilities expose by this node, also conditions which other peers this
	/// node will have an affinity toward when connection.
	pub capabilities: p2p::Capabilities,

	/// Configuration for the peer-to-peer server
	pub p2p_config: p2p::P2PConfig,

	/// Configuration for the mining daemon
	pub stratum_mining_config: Option<StratumServerConfig>,

	/// Transaction pool configuration
	#[serde(default)]
	pub pool_config: pool::PoolConfig,

	/// Dandelion configuration
	#[serde(default)]
	pub dandelion_config: pool::DandelionConfig,

	/// Whether to skip the sync timeout on startup
	/// (To assist testing on solo chains)
	pub skip_sync_wait: Option<bool>,

	/// Whether to run the TUI
	/// if enabled, this will disable logging to stdout
	pub run_tui: Option<bool>,

	/// Whether to run the wallet listener with the server by default
	pub run_wallet_listener: Option<bool>,

	/// Whether to run the web wallet owner listener
	pub run_wallet_owner_api: Option<bool>,

	/// Whether to use the DB wallet backend implementation
	pub use_db_wallet: Option<bool>,

	/// Whether to run the test miner (internal, cuckoo 16)
	pub run_test_miner: Option<bool>,

	/// Test miner wallet URL
	pub test_miner_wallet_url: Option<String>,
}

impl Default for ServerConfig {
	fn default() -> ServerConfig {
		ServerConfig {
			db_root: ".grin".to_string(),
			api_http_addr: "127.0.0.1:13413".to_string(),
			capabilities: p2p::Capabilities::FULL_NODE,
			seeding_type: Seeding::default(),
			seeds: None,
			p2p_config: p2p::P2PConfig::default(),
			dandelion_config: pool::DandelionConfig::default(),
			stratum_mining_config: Some(StratumServerConfig::default()),
			chain_type: ChainTypes::default(),
			archive_mode: None,
			chain_validation_mode: ChainValidationMode::default(),
			pool_config: pool::PoolConfig::default(),
			skip_sync_wait: Some(false),
			run_tui: Some(true),
			run_wallet_listener: Some(true),
			run_wallet_owner_api: Some(false),
			use_db_wallet: None,
			run_test_miner: Some(false),
			test_miner_wallet_url: None,
		}
	}
}

/// Stratum (Mining server) configuration
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct StratumServerConfig {
	/// Run a stratum mining server (the only way to communicate to mine this
	/// node via grin-miner
	pub enable_stratum_server: Option<bool>,

	/// If enabled, the address and port to listen on
	pub stratum_server_addr: Option<String>,

	/// How long to wait before stopping the miner, recollecting transactions
	/// and starting again
	pub attempt_time_per_block: u32,

	/// Minimum difficulty for worker shares
	pub minimum_share_difficulty: u64,

	/// Base address to the HTTP wallet receiver
	pub wallet_listener_url: String,

	/// Attributes the reward to a random private key instead of contacting the
	/// wallet receiver. Mostly used for tests.
	pub burn_reward: bool,
}

impl Default for StratumServerConfig {
	fn default() -> StratumServerConfig {
		StratumServerConfig {
			wallet_listener_url: "http://127.0.0.1:13415".to_string(),
			burn_reward: false,
			attempt_time_per_block: 15,
			minimum_share_difficulty: 1,
			enable_stratum_server: Some(true),
			stratum_server_addr: Some("127.0.0.1:13416".to_string()),
		}
	}
}

/// Various status sync can be in, whether it's fast sync or archival.
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum SyncStatus {
	/// Initial State (we do not yet know if we are/should be syncing)
	Initial,
	/// Not syncing
	NoSync,
	/// Downloading block headers
	HeaderSync {
		current_height: u64,
		highest_height: u64,
	},
	/// Downloading the various txhashsets
	TxHashsetDownload,
	/// Setting up before validation
	TxHashsetSetup,
	/// Validating the full state
	TxHashsetValidation {
		kernels: u64,
		kernel_total: u64,
		rproofs: u64,
		rproof_total: u64,
	},
	/// Finalizing the new state
	TxHashsetSave,
	/// Downloading blocks
	BodySync {
		current_height: u64,
		highest_height: u64,
	},
}

/// Current sync state. Encapsulates the current SyncStatus.
pub struct SyncState {
	current: RwLock<SyncStatus>,
	sync_error: Arc<RwLock<Option<Error>>>,
}

impl SyncState {
	/// Return a new SyncState initialize to NoSync
	pub fn new() -> SyncState {
		SyncState {
			current: RwLock::new(SyncStatus::Initial),
			sync_error: Arc::new(RwLock::new(None)),
		}
	}

	/// Whether the current state matches any active syncing operation.
	/// Note: This includes our "initial" state.
	pub fn is_syncing(&self) -> bool {
		*self.current.read().unwrap() != SyncStatus::NoSync
	}

	/// Current syncing status
	pub fn status(&self) -> SyncStatus {
		*self.current.read().unwrap()
	}

	/// Update the syncing status
	pub fn update(&self, new_status: SyncStatus) {
		if self.status() == new_status {
			return;
		}

		let mut status = self.current.write().unwrap();

		debug!(
			LOGGER,
			"sync_state: sync_status: {:?} -> {:?}", *status, new_status,
		);

		*status = new_status;
	}

	/// Communicate sync error
	pub fn set_sync_error(&self, error: Error) {
		*self.sync_error.write().unwrap() = Some(error);
	}

	/// Get sync error
	pub fn sync_error(&self) -> Arc<RwLock<Option<Error>>> {
		Arc::clone(&self.sync_error)
	}

	/// Clear sync error
	pub fn clear_sync_error(&self) {
		*self.sync_error.write().unwrap() = None;
	}
}

impl chain::TxHashsetWriteStatus for SyncState {
	fn on_setup(&self) {
		self.update(SyncStatus::TxHashsetSetup);
	}

	fn on_validation(&self, vkernels: u64, vkernel_total: u64, vrproofs: u64, vrproof_total: u64) {
		let mut status = self.current.write().unwrap();
		match *status {
			SyncStatus::TxHashsetValidation {
				kernels,
				kernel_total,
				rproofs,
				rproof_total,
			} => {
				let ks = if vkernels > 0 { vkernels } else { kernels };
				let kt = if vkernel_total > 0 {
					vkernel_total
				} else {
					kernel_total
				};
				let rps = if vrproofs > 0 { vrproofs } else { rproofs };
				let rpt = if vrproof_total > 0 {
					vrproof_total
				} else {
					rproof_total
				};
				*status = SyncStatus::TxHashsetValidation {
					kernels: ks,
					kernel_total: kt,
					rproofs: rps,
					rproof_total: rpt,
				};
			}
			_ => {
				*status = SyncStatus::TxHashsetValidation {
					kernels: 0,
					kernel_total: 0,
					rproofs: 0,
					rproof_total: 0,
				}
			}
		}
	}

	fn on_save(&self) {
		self.update(SyncStatus::TxHashsetSave);
	}

	fn on_done(&self) {
		self.update(SyncStatus::BodySync {
			current_height: 0,
			highest_height: 0,
		});
	}
}
<|endoftext|>


<commit_before>use buffer;
use buffer::Buffer;
use std::old_io::IoError;

pub struct Workspace {
    path: Path,
    buffers: Vec<Buffer>,
    current_buffer_index: Option<usize>,
}

impl Workspace {
    pub fn add_buffer(&mut self, buf: Buffer) {
        self.buffers.push(buf);
        self.current_buffer_index = Some(self.buffers.len()-1);
    }

    pub fn current_buffer(&mut self) -> Option<&mut Buffer> {
        match self.current_buffer_index {
            Some(index) => Some(&mut self.buffers[index]),
            None => None,
        }
    }

    pub fn close_current_buffer(&mut self) {
        match self.current_buffer_index {
            Some(index) => {
                self.buffers.remove(index);

                if self.buffers.is_empty() {
                    self.current_buffer_index = None;
                } else {
                    self.current_buffer_index = Some(self.buffers.len()-1);
                }
            }
            None => return,
        };
    }
}

pub fn new(path: Path) -> Workspace {
    Workspace{ path: path, buffers: Vec::new(), current_buffer_index: None }
}

#[cfg(test)]
mod tests {
    use super::new;
    use buffer;

    #[test]
    fn add_buffer_adds_and_selects_the_passed_buffer() {
        let mut workspace = new(Path::new("tests/sample"));
        let buf = buffer::from_file(Path::new("tests/sample/file")).unwrap();
        workspace.add_buffer(buf);

        assert_eq!(workspace.buffers.len(), 1);
        assert_eq!(workspace.current_buffer().unwrap().data(), "it works!\n");
    }

    #[test]
    fn current_buffer_returns_none_when_there_are_no_buffers() {
        let mut workspace = new(Path::new("tests/sample"));
        assert!(workspace.current_buffer().is_none());
    }

    #[test]
    fn current_buffer_returns_one_when_there_are_buffers() {
        let mut workspace = new(Path::new("tests/sample"));
        let buf = buffer::from_file(Path::new("tests/sample/file")).unwrap();
        workspace.add_buffer(buf);
        assert!(workspace.current_buffer().is_some());
    }

    #[test]
    fn close_current_buffer_does_nothing_when_none_are_open() {
        let mut workspace = new(Path::new("tests/sample"));
        workspace.close_current_buffer();
        assert!(workspace.current_buffer().is_none());
    }

    #[test]
    fn close_current_buffer_cleans_up_when_only_one_buffer_is_open() {
        let mut workspace = new(Path::new("tests/sample"));
        workspace.add_buffer(buffer::new());
        workspace.close_current_buffer();
        assert!(workspace.current_buffer().is_none());
        assert!(workspace.current_buffer_index.is_none());
    }

    #[test]
    fn close_current_buffer_when_two_are_open_selects_the_other() {
        let mut workspace = new(Path::new("tests/sample"));

        // Create two buffers and add them to the workspace.
        let mut first_buffer = buffer::new();
        let mut second_buffer = buffer::new();
        first_buffer.insert("first buffer");
        second_buffer.insert("second buffer");
        workspace.add_buffer(first_buffer);
        workspace.add_buffer(second_buffer);

        // Ensure that the second buffer is currently selected.
        assert_eq!(workspace.current_buffer().unwrap().data(), "second buffer");

        workspace.close_current_buffer();
        assert_eq!(workspace.current_buffer().unwrap().data(), "first buffer");
    }
}
<commit_msg>Implement previous_buffer method for workspace type.<commit_after>use buffer;
use buffer::Buffer;
use std::old_io::IoError;

pub struct Workspace {
    path: Path,
    buffers: Vec<Buffer>,
    current_buffer_index: Option<usize>,
}

impl Workspace {
    pub fn add_buffer(&mut self, buf: Buffer) {
        self.buffers.push(buf);
        self.current_buffer_index = Some(self.buffers.len()-1);
    }

    pub fn current_buffer(&mut self) -> Option<&mut Buffer> {
        match self.current_buffer_index {
            Some(index) => Some(&mut self.buffers[index]),
            None => None,
        }
    }

    pub fn close_current_buffer(&mut self) {
        match self.current_buffer_index {
            Some(index) => {
                self.buffers.remove(index);

                if self.buffers.is_empty() {
                    self.current_buffer_index = None;
                } else {
                    self.current_buffer_index = Some(self.buffers.len()-1);
                }
            }
            None => return,
        };
    }

    pub fn previous_buffer(&mut self) {
        match self.current_buffer_index {
            Some(index) => {
                if index > 0 {
                    self.current_buffer_index = Some(index-1);
                } else {
                    self.current_buffer_index = Some(self.buffers.len()-1);
                }
            },
            None => return,
        }
    }
}

pub fn new(path: Path) -> Workspace {
    Workspace{ path: path, buffers: Vec::new(), current_buffer_index: None }
}

#[cfg(test)]
mod tests {
    use super::new;
    use buffer;

    #[test]
    fn add_buffer_adds_and_selects_the_passed_buffer() {
        let mut workspace = new(Path::new("tests/sample"));
        let buf = buffer::from_file(Path::new("tests/sample/file")).unwrap();
        workspace.add_buffer(buf);

        assert_eq!(workspace.buffers.len(), 1);
        assert_eq!(workspace.current_buffer().unwrap().data(), "it works!\n");
    }

    #[test]
    fn current_buffer_returns_none_when_there_are_no_buffers() {
        let mut workspace = new(Path::new("tests/sample"));
        assert!(workspace.current_buffer().is_none());
    }

    #[test]
    fn current_buffer_returns_one_when_there_are_buffers() {
        let mut workspace = new(Path::new("tests/sample"));
        let buf = buffer::from_file(Path::new("tests/sample/file")).unwrap();
        workspace.add_buffer(buf);
        assert!(workspace.current_buffer().is_some());
    }

    #[test]
    fn close_current_buffer_does_nothing_when_none_are_open() {
        let mut workspace = new(Path::new("tests/sample"));
        workspace.close_current_buffer();
        assert!(workspace.current_buffer().is_none());
    }

    #[test]
    fn close_current_buffer_cleans_up_when_only_one_buffer_is_open() {
        let mut workspace = new(Path::new("tests/sample"));
        workspace.add_buffer(buffer::new());
        workspace.close_current_buffer();
        assert!(workspace.current_buffer().is_none());
        assert!(workspace.current_buffer_index.is_none());
    }

    #[test]
    fn close_current_buffer_when_two_are_open_selects_the_other() {
        let mut workspace = new(Path::new("tests/sample"));

        // Create two buffers and add them to the workspace.
        let mut first_buffer = buffer::new();
        let mut second_buffer = buffer::new();
        first_buffer.insert("first buffer");
        second_buffer.insert("second buffer");
        workspace.add_buffer(first_buffer);
        workspace.add_buffer(second_buffer);

        // Ensure that the second buffer is currently selected.
        assert_eq!(workspace.current_buffer().unwrap().data(), "second buffer");

        workspace.close_current_buffer();
        assert_eq!(workspace.current_buffer().unwrap().data(), "first buffer");
    }

    #[test]
    fn previous_buffer_does_nothing_when_no_buffers_are_open() {
        let mut workspace = new(Path::new("tests/sample"));
        workspace.previous_buffer();
        assert!(workspace.current_buffer().is_none());
    }

    #[test]
    fn previous_buffer_when_two_are_open_selects_the_first_and_cycles_back_to_the_last() {
        let mut workspace = new(Path::new("tests/sample"));

        // Create two buffers and add them to the workspace.
        let mut first_buffer = buffer::new();
        let mut second_buffer = buffer::new();
        first_buffer.insert("first buffer");
        second_buffer.insert("second buffer");
        workspace.add_buffer(first_buffer);
        workspace.add_buffer(second_buffer);

        // Ensure that the second buffer is currently selected.
        assert_eq!(workspace.current_buffer().unwrap().data(), "second buffer");

        // Ensure that the first buffer is returned.
        workspace.previous_buffer();
        assert_eq!(workspace.current_buffer().unwrap().data(), "first buffer");

        // Ensure that the second buffer is returned.
        workspace.previous_buffer();
        assert_eq!(workspace.current_buffer().unwrap().data(), "second buffer");
    }
}
<|endoftext|>


<commit_before>use Thingie as Base;
use nalgebra::{Pnt2, Vec2, Cross, Dot, POrd};
use super::{Intersect, Intersection};

pub struct Circle<S: Base> {
    pub pos: Pnt2<S>,
    pub radius: S
}

///Lines go from a to b
pub struct Line<S: Base> {
    pub a: Pnt2<S>,
    pub b: Pnt2<S>
}

impl<S> Line<S> where S: Base {
    pub fn new(a: Pnt2<S>, b: Pnt2<S>) -> Line<S> {
        Line {
            a: a,
            b: b
        }
    }
}

impl<S> Circle<S> where S: Base {
    pub fn new(pos: Pnt2<S>, radius: S) -> Circle<S> {
        Circle {
            pos: pos,
            radius: radius
        }
    }
}

impl<S> Intersect<Line<S>, S> for Line<S> where S: Base {
    fn intersection(&self, other: &Line<S>) -> Intersection<S> {
        let r = Vec2::new(self.b.x - self.a.x, self.b.y - self.a.y);
        let s = Vec2::new(other.b.x - other.a.x, other.b.y - other.a.y);

        //cross returns a Vec1... wtf?!
        let unum = (other.a - self.a).cross(&r).x;
        let denom = r.cross(&s).x;

        if unum == S::zero() && denom == S::zero() {
            let t0 = (other.a - self.a).dot(&r) / r.dot(&r);
            let t1 = t0 + s.dot(&r) / r.dot(&r);
            //do they overlap
            // s and r go in opposite directions so s dot r < 0 it's t1 -> t0
            if s.dot(&r) < S::zero() && t1 <= S::one() && S::zero() <= t0 {
                return Intersection::Overlap(self.a + (r * t1), self.a + (r * t0))
            } else if t0 <= S::one() && S::zero() <= t1 {
                return Intersection::Overlap(self.a + (r * t0), self.a + (r * t1))
            }

            return Intersection::Outside
        }

        if denom == S::zero() {
            //lines are parallel
            return Intersection::Parallel
        }

        let u = unum / denom;
        let t = (other.a - self.a).cross(&s).x / denom;

        if t >= S::zero() && t <= S::one() && u >= S::zero() && u <= S::one() {
            return Intersection::Intersects(self.a + (r * t), None)
        }

        return Intersection::Outside
    }

    fn intersects(&self, other: &Line<S>) -> bool {
        match self.intersection(other) {
            Intersection::Overlap(_, _) => true,
            Intersection::Intersects(_, _) => true,
            _ => false
        }
    }

    fn contains(&self, other: &Line<S>) -> bool {
        //this function should probably just return false
        match self.intersection(other) {
            Intersection::Overlap(a, b) => {
                a.x >= self.a.x && a.y >= self.a.y && b.x <= self.b.x && b.y <= self.b.y
            },
            _ => false
        }
    }
}

impl<S> Intersect<Line<S>, S> for Circle<S> where S: Base {
    fn intersection(&self, other: &Line<S>) -> Intersection<S> {
        let two = S::from(2.0).unwrap();
        let d = (other.b - other.a);

        if d.x == S::zero() && d.y == S::zero() { //line has zero length
            //I could be an asshole and let it pretend it's a tangent and return NaNs,
            //I guess I'm just that nice
            return self.intersection(&other.a)
        }

        let f = (other.a - self.pos);
        let a = d.dot(&d);
        let b = S::from(2.0).unwrap()*f.dot(&d);
        let c = f.dot(&f) - self.radius.powf(two);

        let mut dis = b.powf(two) - (S::from(4.0).unwrap() * a * c);
        if dis < S::zero() {
            return Intersection::Outside
        }
        else if dis == S::zero() {
            dis = dis.sqrt();

            let t0 = (-b - dis)/(two * a);
            let t1 = (-b + dis)/(two * a);
            println!("zero\t{}, {}", t0, t1);
            return Intersection::Intersects(other.a + (d * t0), None)
        }
        else {
            dis = dis.sqrt();

            let t0 = (-b - dis)/(two * a);
            let t1 = (-b + dis)/(two * a);

            println!(">zero\t{}, {}", t0, t1);
            if t0 < S::zero() && t1 <= S::one() { //A inside circle
                return Intersection::Intersects(other.a + (d * t1), None)
            }
            else if t1 > S::one() && t0 >= S::zero() { //B inside circle
                return Intersection::Intersects(other.a + (d * t0), None)
            }
            else if t1 > S::one() && t0 < S::zero() { //all inside
                return Intersection::Inside
            }
            else if t0 > S::zero() && t0 < S::one() && t1 > S::zero() && t1 < S::one() { //two intersections
                return Intersection::Intersects(other.a + (d * t0), Some(other.a + (d * t1)))
            }
        }
        Intersection::Outside
    }

    fn intersects(&self, other: &Line<S>) -> bool {
        match self.intersection(other) {
            Intersection::Intersects(_, _) => true,
            _ => false
        }
    }

    fn contains(&self, other: &Line<S>) -> bool {
        match self.intersection(other) {
            Intersection::Inside => true,
            _ => false
        }
    }
}

impl<S> Intersect<Pnt2<S>, S> for Circle<S> where S: Base {
    fn intersection(&self, other: &Pnt2<S>) -> Intersection<S> {
        let d = *other - self.pos;

        if d.x.abs() < self.radius && d.y.abs() < self.radius {
            return Intersection::Inside
        }
        else if d.x.abs() > self.radius && d.y.abs() > self.radius {
            return Intersection::Outside
        }
        else {
            return Intersection::Intersects(other.clone(), None)
        }
    }

    fn intersects(&self, other: &Pnt2<S>) -> bool {
        let d = *other - self.pos;
        //should probably add an epsilon-y type check here but eh
        d.x.abs() == self.radius && d.y.abs() == self.radius
    }

    fn contains(&self, other: &Pnt2<S>) -> bool {
        match self.intersection(other) {
            Intersection::Inside => true,
            _ => false
        }
    }
}

#[test]
fn line_intersection() {
    let mut l1 = Line::new(Pnt2::new(-5.0, 5.0), Pnt2::new(-1.0, 5.0));
    let mut l2 = Line::new(Pnt2::new(0.0, -5.0), Pnt2::new(0.0, 5.0));

    // no intersection
    assert_eq!(l1.intersection(&l2), Intersection::Outside);

    l1.b.x = 5.0;
    // intersection
    assert_eq!(l1.intersection(&l2), Intersection::Intersects(Pnt2 {x: 0.0, y: 5.0}, None));

    l1 = Line::new(Pnt2::new(0.0,0.0), Pnt2::new(0.0, 10.0));
    l2 = Line::new(Pnt2::new(2.0, 0.0), Pnt2::new(2.0, 10.0));
    // parallel, vertical
    assert_eq!(l1.intersection(&l2), Intersection::Parallel);

    l1 = Line::new(Pnt2::new(0.0,0.0), Pnt2::new(5.0, 5.0));
    l2 = Line::new(Pnt2::new(2.0, 0.0), Pnt2::new(7.0, 5.0));

    // parallel, diagonal
    assert_eq!(l1.intersection(&l2), Intersection::Parallel);

    l1 = Line::new(Pnt2::new(0.0,0.0), Pnt2::new(5.0, 5.0));
    l2 = Line::new(Pnt2::new(2.0, 2.0), Pnt2::new(7.0, 7.0));

    //collinear, overlap
    assert_eq!(l1.intersection(&l2), Intersection::Overlap(l2.a.clone(), l2.b.clone()));
    l1 = Line::new(Pnt2::new(0.0,0.0), Pnt2::new(5.0, 5.0));
    l2 = Line::new(Pnt2::new(7.0, 7.0), Pnt2::new(10.0, 10.0));

    //collinear, no overlap
    assert_eq!(l1.intersection(&l2), Intersection::Outside);

    l1.b.x = 15.0;
    l1.b.y = 15.0;
    //it is right but there's stupid floating point mess
    assert_eq!(l1.intersection(&l2), Intersection::Overlap(Pnt2 {x: 7.0, y: 7.0 }, Pnt2 {x: 10.000000000000002, y: 10.000000000000002}));
    assert_eq!(l1.contains(&l2), true)
}

#[test]
fn circle_line_intersection() {
    let circle = Circle::new(Pnt2::new(3.0,1.0), 6.0);
    let mut line = Line::new(Pnt2::new(-3.0, -3.0), Pnt2::new(-3.0, 3.0));

    //tangent
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: -3.0, y: 1.0}, None));

    line.a = Pnt2::new(-6.0, 1.0);
    line.b = Pnt2::new(12.0, 1.0);

    //intersection A -> B
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: -3.0, y: 1.0}, Some(Pnt2 {x: 9.0, y: 1.0})));

    let temp = line.a;
    line.a = line.b;
    line.b = temp;

    //intersecion B -> A
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: 9.0, y: 1.0}, Some(Pnt2 {x: -3.0, y: 1.0})));

    line.b = line.a;
    line.a = circle.pos.clone();
    //intersection A inside circle
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: 9.0, y: 1.0}, None));

    line.a = Pnt2::new(-6.0, 1.0);
    line.b = circle.pos;

    //intersection B inside circle
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: -3.0, y: 1.0}, None));

    line.a = circle.pos + (circle.radius/2.0);
    line.b = circle.pos;

    //line completely inside
    assert_eq!(circle.intersection(&line), Intersection::Inside);

    line.a = Pnt2::new(-20.0, 20.0);
    line.b = Pnt2::new(20.0, 20.0);

    //line completely outside
    assert_eq!(circle.intersection(&line), Intersection::Outside);

    line.b = line.a.clone();
    //zero length line outside
    assert_eq!(circle.intersection(&line), Intersection::Outside);

    line.a = circle.pos.clone();
    line.b = line.a.clone();

    //zero length line inside
    assert_eq!(circle.intersection(&line), Intersection::Inside);
}

<commit_msg>What debug statements?<commit_after>use Thingie as Base;
use nalgebra::{Pnt2, Vec2, Cross, Dot, POrd};
use super::{Intersect, Intersection};

pub struct Circle<S: Base> {
    pub pos: Pnt2<S>,
    pub radius: S
}

///Lines go from a to b
pub struct Line<S: Base> {
    pub a: Pnt2<S>,
    pub b: Pnt2<S>
}

impl<S> Line<S> where S: Base {
    pub fn new(a: Pnt2<S>, b: Pnt2<S>) -> Line<S> {
        Line {
            a: a,
            b: b
        }
    }
}

impl<S> Circle<S> where S: Base {
    pub fn new(pos: Pnt2<S>, radius: S) -> Circle<S> {
        Circle {
            pos: pos,
            radius: radius
        }
    }
}

impl<S> Intersect<Line<S>, S> for Line<S> where S: Base {
    fn intersection(&self, other: &Line<S>) -> Intersection<S> {
        let r = Vec2::new(self.b.x - self.a.x, self.b.y - self.a.y);
        let s = Vec2::new(other.b.x - other.a.x, other.b.y - other.a.y);

        //cross returns a Vec1... wtf?!
        let unum = (other.a - self.a).cross(&r).x;
        let denom = r.cross(&s).x;

        if unum == S::zero() && denom == S::zero() {
            let t0 = (other.a - self.a).dot(&r) / r.dot(&r);
            let t1 = t0 + s.dot(&r) / r.dot(&r);
            //do they overlap
            // s and r go in opposite directions so s dot r < 0 it's t1 -> t0
            if s.dot(&r) < S::zero() && t1 <= S::one() && S::zero() <= t0 {
                return Intersection::Overlap(self.a + (r * t1), self.a + (r * t0))
            } else if t0 <= S::one() && S::zero() <= t1 {
                return Intersection::Overlap(self.a + (r * t0), self.a + (r * t1))
            }

            return Intersection::Outside
        }

        if denom == S::zero() {
            //lines are parallel
            return Intersection::Parallel
        }

        let u = unum / denom;
        let t = (other.a - self.a).cross(&s).x / denom;

        if t >= S::zero() && t <= S::one() && u >= S::zero() && u <= S::one() {
            return Intersection::Intersects(self.a + (r * t), None)
        }

        return Intersection::Outside
    }

    fn intersects(&self, other: &Line<S>) -> bool {
        match self.intersection(other) {
            Intersection::Overlap(_, _) => true,
            Intersection::Intersects(_, _) => true,
            _ => false
        }
    }

    fn contains(&self, other: &Line<S>) -> bool {
        //this function should probably just return false
        match self.intersection(other) {
            Intersection::Overlap(a, b) => {
                a.x >= self.a.x && a.y >= self.a.y && b.x <= self.b.x && b.y <= self.b.y
            },
            _ => false
        }
    }
}

impl<S> Intersect<Line<S>, S> for Circle<S> where S: Base {
    fn intersection(&self, other: &Line<S>) -> Intersection<S> {
        let two = S::from(2.0).unwrap();
        let d = (other.b - other.a);

        if d.x == S::zero() && d.y == S::zero() { //line has zero length
            //I could be an asshole and let it pretend it's a tangent and return NaNs,
            //I guess I'm just that nice
            return self.intersection(&other.a)
        }

        let f = (other.a - self.pos);
        let a = d.dot(&d);
        let b = S::from(2.0).unwrap()*f.dot(&d);
        let c = f.dot(&f) - self.radius.powf(two);

        let mut dis = b.powf(two) - (S::from(4.0).unwrap() * a * c);
        if dis < S::zero() {
            return Intersection::Outside
        }
        else if dis == S::zero() {
            dis = dis.sqrt();

            let t0 = (-b - dis)/(two * a);
            let t1 = (-b + dis)/(two * a);
            return Intersection::Intersects(other.a + (d * t0), None)
        }
        else {
            dis = dis.sqrt();

            let t0 = (-b - dis)/(two * a);
            let t1 = (-b + dis)/(two * a);

            if t0 < S::zero() && t1 <= S::one() { //A inside circle
                return Intersection::Intersects(other.a + (d * t1), None)
            }
            else if t1 > S::one() && t0 >= S::zero() { //B inside circle
                return Intersection::Intersects(other.a + (d * t0), None)
            }
            else if t1 > S::one() && t0 < S::zero() { //all inside
                return Intersection::Inside
            }
            else if t0 > S::zero() && t0 < S::one() && t1 > S::zero() && t1 < S::one() { //two intersections
                return Intersection::Intersects(other.a + (d * t0), Some(other.a + (d * t1)))
            }
        }
        Intersection::Outside
    }

    fn intersects(&self, other: &Line<S>) -> bool {
        match self.intersection(other) {
            Intersection::Intersects(_, _) => true,
            _ => false
        }
    }

    fn contains(&self, other: &Line<S>) -> bool {
        match self.intersection(other) {
            Intersection::Inside => true,
            _ => false
        }
    }
}

impl<S> Intersect<Pnt2<S>, S> for Circle<S> where S: Base {
    fn intersection(&self, other: &Pnt2<S>) -> Intersection<S> {
        let d = *other - self.pos;

        if d.x.abs() < self.radius && d.y.abs() < self.radius {
            return Intersection::Inside
        }
        else if d.x.abs() > self.radius && d.y.abs() > self.radius {
            return Intersection::Outside
        }
        else {
            return Intersection::Intersects(other.clone(), None)
        }
    }

    fn intersects(&self, other: &Pnt2<S>) -> bool {
        let d = *other - self.pos;
        //should probably add an epsilon-y type check here but eh
        d.x.abs() == self.radius && d.y.abs() == self.radius
    }

    fn contains(&self, other: &Pnt2<S>) -> bool {
        match self.intersection(other) {
            Intersection::Inside => true,
            _ => false
        }
    }
}

#[test]
fn line_intersection() {
    let mut l1 = Line::new(Pnt2::new(-5.0, 5.0), Pnt2::new(-1.0, 5.0));
    let mut l2 = Line::new(Pnt2::new(0.0, -5.0), Pnt2::new(0.0, 5.0));

    // no intersection
    assert_eq!(l1.intersection(&l2), Intersection::Outside);

    l1.b.x = 5.0;
    // intersection
    assert_eq!(l1.intersection(&l2), Intersection::Intersects(Pnt2 {x: 0.0, y: 5.0}, None));

    l1 = Line::new(Pnt2::new(0.0,0.0), Pnt2::new(0.0, 10.0));
    l2 = Line::new(Pnt2::new(2.0, 0.0), Pnt2::new(2.0, 10.0));
    // parallel, vertical
    assert_eq!(l1.intersection(&l2), Intersection::Parallel);

    l1 = Line::new(Pnt2::new(0.0,0.0), Pnt2::new(5.0, 5.0));
    l2 = Line::new(Pnt2::new(2.0, 0.0), Pnt2::new(7.0, 5.0));

    // parallel, diagonal
    assert_eq!(l1.intersection(&l2), Intersection::Parallel);

    l1 = Line::new(Pnt2::new(0.0,0.0), Pnt2::new(5.0, 5.0));
    l2 = Line::new(Pnt2::new(2.0, 2.0), Pnt2::new(7.0, 7.0));

    //collinear, overlap
    assert_eq!(l1.intersection(&l2), Intersection::Overlap(l2.a.clone(), l2.b.clone()));
    l1 = Line::new(Pnt2::new(0.0,0.0), Pnt2::new(5.0, 5.0));
    l2 = Line::new(Pnt2::new(7.0, 7.0), Pnt2::new(10.0, 10.0));

    //collinear, no overlap
    assert_eq!(l1.intersection(&l2), Intersection::Outside);

    l1.b.x = 15.0;
    l1.b.y = 15.0;
    //it is right but there's stupid floating point mess
    assert_eq!(l1.intersection(&l2), Intersection::Overlap(Pnt2 {x: 7.0, y: 7.0 }, Pnt2 {x: 10.000000000000002, y: 10.000000000000002}));
    assert_eq!(l1.contains(&l2), true)
}

#[test]
fn circle_line_intersection() {
    let circle = Circle::new(Pnt2::new(3.0,1.0), 6.0);
    let mut line = Line::new(Pnt2::new(-3.0, -3.0), Pnt2::new(-3.0, 3.0));

    //tangent
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: -3.0, y: 1.0}, None));

    line.a = Pnt2::new(-6.0, 1.0);
    line.b = Pnt2::new(12.0, 1.0);

    //intersection A -> B
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: -3.0, y: 1.0}, Some(Pnt2 {x: 9.0, y: 1.0})));

    let temp = line.a;
    line.a = line.b;
    line.b = temp;

    //intersecion B -> A
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: 9.0, y: 1.0}, Some(Pnt2 {x: -3.0, y: 1.0})));

    line.b = line.a;
    line.a = circle.pos.clone();
    //intersection A inside circle
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: 9.0, y: 1.0}, None));

    line.a = Pnt2::new(-6.0, 1.0);
    line.b = circle.pos;

    //intersection B inside circle
    assert_eq!(circle.intersection(&line), Intersection::Intersects(Pnt2 {x: -3.0, y: 1.0}, None));

    line.a = circle.pos + (circle.radius/2.0);
    line.b = circle.pos;

    //line completely inside
    assert_eq!(circle.intersection(&line), Intersection::Inside);

    line.a = Pnt2::new(-20.0, 20.0);
    line.b = Pnt2::new(20.0, 20.0);

    //line completely outside
    assert_eq!(circle.intersection(&line), Intersection::Outside);

    line.b = line.a.clone();
    //zero length line outside
    assert_eq!(circle.intersection(&line), Intersection::Outside);

    line.a = circle.pos.clone();
    line.b = line.a.clone();

    //zero length line inside
    assert_eq!(circle.intersection(&line), Intersection::Inside);
}

<|endoftext|>