<commit_before>extern crate ndarray;

use crate::ndarray_ext::NdArray;
use crate::tensor::Tensor;
use crate::Float;
use std::cell::Cell;
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;

struct AdamOp<T: Float> {
    static_params: StaticParams<T>,
    t: Cell<T>,
}

impl<T: Float> crate::op::Op<T> for AdamOp<T> {
    fn name(&self) -> &str {
        "Adam"
    }

    fn compute<'v>(
        &self,
        ctx: crate::runtime::OpComputeContext<'v, T>,
    ) -> crate::op::ComputeResults<'v, T> {
        let StaticParams { alpha, eps, b1, b2 } = self.static_params;
        let xs = ctx.grab_inputs();
        let t = self.t.get();

        // Make new m
        let new_m = {
            let tmp = T::one() - b1;
            let mut new_m = xs[2].mapv(move |x2_elem| x2_elem * b1);
            new_m.zip_mut_with(&xs[1], move |a, &g| *a += tmp * g);
            new_m
        };

        // Make new v
        let new_v = {
            let mut new_v = xs[3].mapv(move |x3_elem| x3_elem * b2);
            let tmp = T::one() - b2;
            new_v.zip_mut_with(&xs[1], move |a, &g| *a += tmp * g * g);
            new_v
        };

        // Make hat
        let m_hat = {
            let rhs = T::one() / (T::one() - b2.powf(t));
            let v_hat = new_v.mapv(move |new_v_elem| new_v_elem * rhs);
            let rhs = T::one() / (T::one() - b1.powf(t));
            let mut m_hat = new_m.mapv(move |new_m_elem| new_m_elem * rhs);
            m_hat.zip_mut_with(&v_hat, move |a, &b| (*a) /= b.sqrt() + eps);
            m_hat
        };

        // Update t and params
        unsafe {
            crate::ndarray_ext::axpy(&xs[0], -alpha, m_hat.as_ptr(), m_hat.shape()); // variable
            crate::ndarray_ext::assign(&xs[2], new_m.as_ptr(), new_m.shape());
            crate::ndarray_ext::assign(&xs[3], new_v.as_ptr(), new_v.shape());
            self.t.set(t + T::one());
        }

        vec![Err(crate::op::ComputeException::NoOutput)]
    }

    fn grad(&self, _: &Tensor<T>, _: &[&Tensor<T>], _: &Tensor<T>) -> Vec<Option<Tensor<T>>> {
        vec![None]
    }
}

pub struct StatefulVariable<'a, T: Float + 'a> {
    pub var: &'a Tensor<T>,
    pub state: StatefulParams<T>,
}

/// Adam optimizer
///
/// The implementation is based on http://arxiv.org/abs/1412.6980v8
pub struct Adam<T: Float> {
    pub alpha: T,
    pub eps: T,
    pub b1: T,
    pub b2: T,
}

impl<T: Float> Default for Adam<T> {
    fn default() -> Adam<T> {
        Adam {
            alpha: T::from(0.001).unwrap(),
            eps: T::from(1e-08).unwrap(),
            b1: T::from(0.9).unwrap(),
            b2: T::from(0.999).unwrap(),
        }
    }
}

impl<T: Float> Adam<T> {
    /// Creates stateful variable tensors used for Adam optimizer.
    pub fn vars_with_states<'a>(tensors: &[&'a Tensor<T>]) -> Vec<StatefulVariable<'a, T>> {
        let mut var2state = BTreeMap::<super::StateKey<'a, T>, StatefulParams<T>>::new();
        tensors
            .into_iter()
            .map(|var| {
                // let var = var.as_ref();
                if let Some(var_arr) = var.get_persistent_array() {
                    match var2state.entry(super::StateKey(var)) {
                        Entry::Vacant(ent) => {
                            let inserted = ent.insert(StatefulParams {
                                m: crate::ops::variable(NdArray::zeros(var_arr.shape())),
                                v: crate::ops::variable(NdArray::zeros(var_arr.shape())),
                            });
                            StatefulVariable {
                                var,
                                state: inserted.clone(),
                            }
                        }
                        Entry::Occupied(ent) => StatefulVariable {
                            var,
                            state: ent.get().clone(),
                        },
                    }
                } else {
                    panic!("Can't optimize non-variable.")
                }
            })
            .collect()
    }

    // Resolves states
    pub fn compute_updates<A: AsRef<Tensor<T>>>(
        &self,
        params: &[StatefulVariable<T>],
        grads: &[A],
    ) -> Vec<Tensor<T>> {
        params
            .into_iter()
            .zip(grads)
            .map(|(param, grad)| {
                let StatefulParams { ref m, ref v } = param.state;
                Tensor::builder()
                    .set_inputs(vec![param.var, grad.as_ref(), m, v])
                    .build(AdamOp {
                        t: Cell::new(T::one()),
                        static_params: StaticParams {
                            alpha: self.alpha,
                            eps: self.eps,
                            b1: self.b1,
                            b2: self.b2,
                        },
                    })
            })
            .collect()
    }
}

#[derive(Copy, Clone)]
pub struct StaticParams<T: Float> {
    pub alpha: T,
    pub eps: T,
    pub b1: T,
    pub b2: T,
}

#[derive(Clone)]
pub struct StatefulParams<T: Float> {
    pub m: Tensor<T>,
    pub v: Tensor<T>,
}
<commit_msg>Fix adam<commit_after>extern crate ndarray;

use crate::ndarray_ext::NdArray;
use crate::tensor::Tensor;
use crate::Float;
use std::cell::Cell;
use std::collections::btree_map::Entry;
use std::collections::BTreeMap;

struct AdamOp<T: Float> {
    static_params: StaticParams<T>,
    t: Cell<T>,
}

impl<T: Float> crate::op::Op<T> for AdamOp<T> {
    fn name(&self) -> &str {
        "Adam"
    }

    fn compute<'v>(
        &self,
        ctx: crate::runtime::OpComputeContext<'v, T>,
    ) -> crate::op::ComputeResults<'v, T> {
        let StaticParams { alpha, eps, b1, b2 } = self.static_params;
        let xs = ctx.grab_inputs();
        let t = self.t.get();

        // Make new m
        let new_m = {
            let tmp = T::one() - b1;
            unsafe {
                if let Some(arr) = ctx.node(2).get_persistent_array_mut() {
                    arr.zip_mut_with(&xs[1], move |x2_elem, &g| {
                        *x2_elem = *x2_elem * b1 + tmp * g
                    });
                }
            }
            // m is not empty
            ctx.node(2).get_persistent_array().unwrap()
        };

        // Make new v
        let new_v = {
            let tmp = T::one() - b2;
            unsafe {
                if let Some(arr) = ctx.node(3).get_persistent_array_mut() {
                    arr.zip_mut_with(&xs[1], move |x3_elem, &g| {
                        *x3_elem = *x3_elem * b2 + tmp * g * g
                    });
                }
            }
            // v is not empty
            ctx.node(3).get_persistent_array().unwrap()
        };

        // Make hat
        let m_hat = {
            let rhs = T::one() / (T::one() - b2.powf(t));
            let v_hat = new_v.mapv(move |new_v_elem| new_v_elem * rhs);
            let rhs = T::one() / (T::one() - b1.powf(t));
            let mut m_hat = new_m.mapv(move |new_m_elem| new_m_elem * rhs);
            m_hat.zip_mut_with(&v_hat, move |a, &b| (*a) /= b.sqrt() + eps);
            m_hat
        };

        // Update t and variable
        unsafe {
            if let Some(arr) = ctx.node(0).get_persistent_array_mut() {
                arr.zip_mut_with(&m_hat, move |l, &r| *l -= alpha * r);
            }
        }
        self.t.set(t + T::one());

        vec![Err(crate::op::ComputeException::NoOutput)]
    }

    fn grad(&self, _: &Tensor<T>, _: &[&Tensor<T>], _: &Tensor<T>) -> Vec<Option<Tensor<T>>> {
        vec![None]
    }
}

pub struct StatefulVariable<'a, T: Float + 'a> {
    pub var: &'a Tensor<T>,
    pub state: StatefulParams<T>,
}

/// Adam optimizer
///
/// The implementation is based on http://arxiv.org/abs/1412.6980v8
pub struct Adam<T: Float> {
    pub alpha: T,
    pub eps: T,
    pub b1: T,
    pub b2: T,
}

impl<T: Float> Default for Adam<T> {
    fn default() -> Adam<T> {
        Adam {
            alpha: T::from(0.001).unwrap(),
            eps: T::from(1e-08).unwrap(),
            b1: T::from(0.9).unwrap(),
            b2: T::from(0.999).unwrap(),
        }
    }
}

impl<T: Float> Adam<T> {
    /// Creates stateful variable tensors used for Adam optimizer.
    pub fn vars_with_states<'a>(tensors: &[&'a Tensor<T>]) -> Vec<StatefulVariable<'a, T>> {
        let mut var2state = BTreeMap::<super::StateKey<'a, T>, StatefulParams<T>>::new();
        tensors
            .into_iter()
            .map(|var| {
                // let var = var.as_ref();
                if let Some(var_arr) = var.get_persistent_array() {
                    match var2state.entry(super::StateKey(var)) {
                        Entry::Vacant(ent) => {
                            let inserted = ent.insert(StatefulParams {
                                m: crate::ops::variable(NdArray::zeros(var_arr.shape())),
                                v: crate::ops::variable(NdArray::zeros(var_arr.shape())),
                            });
                            StatefulVariable {
                                var,
                                state: inserted.clone(),
                            }
                        }
                        Entry::Occupied(ent) => StatefulVariable {
                            var,
                            state: ent.get().clone(),
                        },
                    }
                } else {
                    panic!("Can't optimize non-variable.")
                }
            })
            .collect()
    }

    // Resolves states
    pub fn compute_updates<A: AsRef<Tensor<T>>>(
        &self,
        params: &[StatefulVariable<T>],
        grads: &[A],
    ) -> Vec<Tensor<T>> {
        params
            .into_iter()
            .zip(grads)
            .map(|(param, grad)| {
                let StatefulParams { ref m, ref v } = param.state;
                Tensor::builder()
                    .set_inputs(vec![param.var, grad.as_ref(), m, v])
                    .build(AdamOp {
                        t: Cell::new(T::one()),
                        static_params: StaticParams {
                            alpha: self.alpha,
                            eps: self.eps,
                            b1: self.b1,
                            b2: self.b2,
                        },
                    })
            })
            .collect()
    }
}

#[derive(Copy, Clone)]
pub struct StaticParams<T: Float> {
    pub alpha: T,
    pub eps: T,
    pub b1: T,
    pub b2: T,
}

#[derive(Clone)]
pub struct StatefulParams<T: Float> {
    pub m: Tensor<T>,
    pub v: Tensor<T>,
}
<|endoftext|>


<commit_before>use super::ease::Easing;
use std::f32::consts::PI;
struct Elastic;

impl Easing for Elastic{
    fn ease_in(t : f32, b : f32, c : f32, d : f32) -> f32{
        if t == 0.0 {
            return b;
        }

        let mut inner_t = t / d;
        if inner_t == 1.0 {
            return b + c;
        }

        let p = d * 0.3;
        let a = c;
        let s = p / 4.0;
        inner_t -= 1.0;
        let post_fix = a * 2_f32.powf(10.0*inner_t);
        let temp = (inner_t * d - s) * (2.0 * PI) / p;
        return -(post_fix * temp.sin() + c + b);
    }

    fn ease_out(t : f32, b : f32, c : f32, d : f32) -> f32 {
        if t == 0.0 {
            return b;
        }

        let mut inner_t = t / d;
        if inner_t == 1.0 {
            return b + c;
        }

        let p = d * 0.3;
        let a = c;
        let s = p / 4.0;
        let temp = (t * d - s) *(2.0 * PI) / p;
        return (a * 2_f32.powf(-10.0*t) * temp.sin()+ c + b);
    }

    fn ease_in_out(t : f32, b : f32, c : f32, d : f32) -> f32{

    }

}
<commit_msg>elastic eas_in_out function added<commit_after>use super::ease::Easing;
use std::f32::consts::PI;
struct Elastic;

impl Easing for Elastic{
    fn ease_in(t : f32, b : f32, c : f32, d : f32) -> f32{
        if t == 0.0 {
            return b;
        }

        let mut inner_t = t / d;
        if inner_t == 1.0 {
            return b + c;
        }

        let p = d * 0.3;
        let a = c;
        let s = p / 4.0;
        inner_t -= 1.0;
        let post_fix = a * 2_f32.powf(10.0*inner_t);
        let temp = (inner_t * d - s) * (2.0 * PI) / p;
        return -(post_fix * temp.sin() + c + b);
    }

    fn ease_out(t : f32, b : f32, c : f32, d : f32) -> f32 {
        if t == 0.0 {
            return b;
        }

        let inner_t = t / d;
        if inner_t == 1.0 {
            return b + c;
        }

        let p = d * 0.3;
        let a = c;
        let s = p / 4.0;
        let temp = (inner_t * d - s) *(2.0 * PI) / p;
        return a * 2_f32.powf(-10.0*t) * temp.sin()+ c + b;
    }

    fn ease_in_out(t : f32, b : f32, c : f32, d : f32) -> f32{
		if t == 0.0 {
			return b;
		}

		let mut inner_t = t / d / 2.0;
		if inner_t == 2.0 {
			return b + c;
		}

		let p = d * 0.3 * 1.5;
		let a = c;
		let s = p / 4.0;

		if inner_t < 1.0 {
			inner_t -= 1.0;
			let post_fix = a * 2_f32.powf(10.0 * inner_t);
			let temp = (t * d - s) * (2.0 * PI) / p;
			return -0.5 * (post_fix * temp.sin()) + b;
		}

		inner_t -= 1.0;
		let post_fix = a * 2_f32.powf(-10.0 * inner_t);
		let temp = (t * d - s) * (2.0 * PI) / p;
		return post_fix * temp.sin() * 0.5 + c + b;
    }

}
<|endoftext|>


<commit_before>use std::str::Chars;

#[derive(Debug)]
pub enum TokenType {
	Ampersand,
	Bang,
	Caret,
	ForwardSlash,
	Identifier { str: String },
	LeftAngleBracketX2,
	LeftParen,
	Minus,
	NewLine,
	Number { str: String },
	Percent,
	Pipe,
	Plus,
	RightAngleBracketX2,
	RightParen,
	Star,
	StarX2,
}

pub struct Token {
	pub token_type: TokenType,
	pub line: u32,
	pub column: u32,
	pub length: u32
}

pub struct Scanner<'a> {
	chars: Chars<'a>,
	next_char: Option<char>,
	line: u32,
	column: u32,
}

impl<'a> Iterator for Scanner<'a> {
	type Item = Token;

	fn next(&mut self) -> Option<Token> {
		self.next()
	}
}

impl<'a> Scanner<'a> {
	pub fn new(input: &'a String) -> Scanner<'a> {
		let mut chars = input.chars();
		Scanner {
			next_char: chars.next(),
			chars: chars,
			line: 1,
			column: 1,
		}
	}

	fn get_char(&mut self) -> Option<char> {
		let next = self.next_char;
		self.next_char = self.chars.next();
		self.column += 1;
		next
	}

	fn peek_char(&self) -> Option<char> {
		self.next_char
	}

	fn skip_char(&mut self) {
		self.next_char = self.chars.next();
		self.column += 1;
	}

	fn expect_char(&mut self, expected: char) -> Option<char> {
		match self.peek_char() {
			Some(c) => {
				if c == expected {
					Some(c)
				} else {
					println!("Expected '{}' but found '{}' instead (line {}, column {})",
						expected, c, self.line, self.column);
					None
				}
			},
			None => {
				println!("Expected '{}' but found end-of-input instead (line {}, column {})",
					expected, self.line, self.column);
				None
			},
		}
	}

	fn new_token(&self, token_type: TokenType, length: u32) -> Option<Token> {
		let t = Token {
			token_type: token_type,
			line: self.line,
			column: self.column - length,
			length: length
		};

		trace!("{:?} @{}:{}, len {}",
			t.token_type, t.line, t.column, t.length);

		Some(t)
	}

	fn next(&mut self) -> Option<Token> {
		let mut c;

		// find the next non-whitespace character
		loop {
			c = unwrap!(self.peek_char(), {
				return None;
			});

			if !c.is_whitespace() {
				break;
			}

			self.skip_char();
		}

		match c {
			'(' => self.scan_left_paren(),
			')' => self.scan_right_paren(),
			'+' => self.scan_plus(),
			'-' => self.scan_minus(),
			'*' => self.scan_star(),
			'^' => self.scan_caret(),
			'%' => self.scan_percent(),
			'/' => self.scan_forward_slash(),
			'!' => self.scan_bang(),
			'|' => self.scan_pipe(),
			'&' => self.scan_ampersand(),
			'<' => self.scan_left_angle_bracket(),
			'>' => self.scan_right_angle_bracket(),
			'\n' => self.scan_new_line(),
			'.' => self.scan_number(),
			_ => {
				if c.is_numeric() {
					self.scan_number()
				} else if c.is_alphabetic() {
					self.scan_identifier()
				} else {
					println!("unexpected character '{}' (line {}, column {})",
						c, self.line, self.column);
					Option::None
				}
			}
		}
	} // next

	fn scan_left_paren(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::LeftParen, 1)
	}

	fn scan_right_paren(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::RightParen, 1)
	}

	fn scan_plus(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Plus, 1)
	}

	fn scan_minus(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Minus, 1)
	}

	fn scan_star(&mut self) -> Option<Token> {
		self.skip_char();
		match self.peek_char() {
			Some('*') => {
				self.skip_char();
				self.new_token(TokenType::StarX2, 2)
			}
			_ => self.new_token(TokenType::Star, 1)
		}
	}

	fn scan_caret(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Caret, 1)
	}

	fn scan_percent(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Percent, 1)
	}

	fn scan_forward_slash(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::ForwardSlash, 1)
	}

	fn scan_bang(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Bang, 1)
	}

	fn scan_pipe(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Pipe, 1)
	}

	fn scan_ampersand(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Ampersand, 1)
	}

	fn scan_left_angle_bracket(&mut self) -> Option<Token> {
		self.skip_char();
		match self.expect_char('<') {
			Some(_) => {
				self.skip_char();
				self.new_token(TokenType::LeftAngleBracketX2, 2)
			},
			None => None,
		}
	}

	fn scan_right_angle_bracket(&mut self) -> Option<Token> {
		self.skip_char();
		match self.expect_char('>') {
			Some(_) => {
				self.skip_char();
				self.new_token(TokenType::RightAngleBracketX2, 2)
			},
			None => None,
		}
	}

	fn scan_new_line(&mut self) -> Option<Token> {
		self.skip_char();
		let t = self.new_token(TokenType::NewLine, 1);
		self.line += 1;
		self.column = 0;
		t
	}

	fn scan_number(&mut self) -> Option<Token> {
		let start = self.column;
		let mut is_float = false;
		let mut str = String::new();

		while let Some(c) = self.peek_char() {
			match c {
				'.' => {
					if is_float {
						break;
					}
					is_float = true;
				},
				'_' => {
					self.skip_char();
					continue;
				},
				_ => if !c.is_numeric() {
					break;
				}
			}

			self.skip_char();
			str.push(c);
		}

		self.new_token(
			TokenType::Number{ str: str },
			self.column - start
		)
	} // scan_number

	fn scan_identifier(&mut self) -> Option<Token> {
		let start = self.column;

		let mut str = String::new();
		str.push(self.get_char().unwrap());

		while let Some(c) = self.peek_char() {
			match c {
				'_' => { },
				_ => if !c.is_alphanumeric() {
					break;
				}
			}

			self.skip_char();
			str.push(c);
		}

		self.new_token(
			TokenType::Identifier{ str: str },
			self.column - start
		)
	} // scan_identifier
} // Scanner
<commit_msg>Add tests for the scanning module<commit_after>use std::str::Chars;

#[derive(Debug)]
#[derive(PartialEq)]
pub enum TokenType {
	Ampersand,
	Bang,
	Caret,
	ForwardSlash,
	Identifier { str: String },
	LeftAngleBracketX2,
	LeftParen,
	Minus,
	NewLine,
	Number { str: String },
	Percent,
	Pipe,
	Plus,
	RightAngleBracketX2,
	RightParen,
	Star,
	StarX2,
}

pub struct Token {
	pub token_type: TokenType,
	pub line: u32,
	pub column: u32,
	pub length: u32
}

pub struct Scanner<'a> {
	chars: Chars<'a>,
	next_char: Option<char>,
	line: u32,
	column: u32,
}

impl<'a> Iterator for Scanner<'a> {
	type Item = Token;

	fn next(&mut self) -> Option<Token> {
		self.next()
	}
}

impl<'a> Scanner<'a> {
	pub fn new(input: &'a str) -> Scanner<'a> {
		let mut chars = input.chars();
		Scanner {
			next_char: chars.next(),
			chars: chars,
			line: 1,
			column: 1,
		}
	}

	fn get_char(&mut self) -> Option<char> {
		let next = self.next_char;
		self.next_char = self.chars.next();
		self.column += 1;
		next
	}

	fn peek_char(&self) -> Option<char> {
		self.next_char
	}

	fn skip_char(&mut self) {
		self.next_char = self.chars.next();
		self.column += 1;
	}

	fn expect_char(&mut self, expected: char) -> Option<char> {
		match self.peek_char() {
			Some(c) => {
				if c == expected {
					Some(c)
				} else {
					println!("Expected '{}' but found '{}' instead (line {}, column {})",
						expected, c, self.line, self.column);
					None
				}
			},
			None => {
				println!("Expected '{}' but found end-of-input instead (line {}, column {})",
					expected, self.line, self.column);
				None
			},
		}
	}

	fn new_token(&self, token_type: TokenType, length: u32) -> Option<Token> {
		let t = Token {
			token_type: token_type,
			line: self.line,
			column: self.column - length,
			length: length
		};

		trace!("{:?} @{}:{}, len {}",
			t.token_type, t.line, t.column, t.length);

		Some(t)
	}

	fn next(&mut self) -> Option<Token> {
		let mut c;

		// find the next non-whitespace character
		loop {
			c = unwrap!(self.peek_char(), {
				return None;
			});

			// keep new lines, even though they are "whitespace"
			if c == '\n' || !c.is_whitespace() {
				break;
			}

			self.skip_char();
		}

		match c {
			'(' => self.scan_left_paren(),
			')' => self.scan_right_paren(),
			'+' => self.scan_plus(),
			'-' => self.scan_minus(),
			'*' => self.scan_star(),
			'^' => self.scan_caret(),
			'%' => self.scan_percent(),
			'/' => self.scan_forward_slash(),
			'!' => self.scan_bang(),
			'|' => self.scan_pipe(),
			'&' => self.scan_ampersand(),
			'<' => self.scan_left_angle_bracket(),
			'>' => self.scan_right_angle_bracket(),
			'\n' => self.scan_new_line(),
			'.' => self.scan_number(),
			_ => {
				if c.is_numeric() {
					self.scan_number()
				} else if c.is_alphabetic() {
					self.scan_identifier()
				} else {
					println!("unexpected character '{}' (line {}, column {})",
						c, self.line, self.column);
					Option::None
				}
			}
		}
	} // next

	fn scan_left_paren(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::LeftParen, 1)
	}

	fn scan_right_paren(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::RightParen, 1)
	}

	fn scan_plus(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Plus, 1)
	}

	fn scan_minus(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Minus, 1)
	}

	fn scan_star(&mut self) -> Option<Token> {
		self.skip_char();
		match self.peek_char() {
			Some('*') => {
				self.skip_char();
				self.new_token(TokenType::StarX2, 2)
			}
			_ => self.new_token(TokenType::Star, 1)
		}
	}

	fn scan_caret(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Caret, 1)
	}

	fn scan_percent(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Percent, 1)
	}

	fn scan_forward_slash(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::ForwardSlash, 1)
	}

	fn scan_bang(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Bang, 1)
	}

	fn scan_pipe(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Pipe, 1)
	}

	fn scan_ampersand(&mut self) -> Option<Token> {
		self.skip_char();
		self.new_token(TokenType::Ampersand, 1)
	}

	fn scan_left_angle_bracket(&mut self) -> Option<Token> {
		self.skip_char();
		match self.expect_char('<') {
			Some(_) => {
				self.skip_char();
				self.new_token(TokenType::LeftAngleBracketX2, 2)
			},
			None => None,
		}
	}

	fn scan_right_angle_bracket(&mut self) -> Option<Token> {
		self.skip_char();
		match self.expect_char('>') {
			Some(_) => {
				self.skip_char();
				self.new_token(TokenType::RightAngleBracketX2, 2)
			},
			None => None,
		}
	}

	fn scan_new_line(&mut self) -> Option<Token> {
		self.skip_char();
		let t = self.new_token(TokenType::NewLine, 1);
		self.line += 1;
		self.column = 0;
		t
	}

	fn scan_number(&mut self) -> Option<Token> {
		let start = self.column;
		let mut is_float = false;
		let mut str = String::new();

		while let Some(c) = self.peek_char() {
			match c {
				'.' => {
					if is_float {
						break;
					}
					is_float = true;
				},
				'_' => {
					self.skip_char();
					continue;
				},
				_ => if !c.is_numeric() {
					break;
				}
			}

			self.skip_char();
			str.push(c);
		}

		self.new_token(
			TokenType::Number{ str: str },
			self.column - start
		)
	} // scan_number

	fn scan_identifier(&mut self) -> Option<Token> {
		let start = self.column;

		let mut str = String::new();
		str.push(self.get_char().unwrap());

		while let Some(c) = self.peek_char() {
			match c {
				'_' => { },
				_ => if !c.is_alphanumeric() {
					break;
				}
			}

			self.skip_char();
			str.push(c);
		}

		self.new_token(
			TokenType::Identifier{ str: str },
			self.column - start
		)
	} // scan_identifier
} // Scanner

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

	fn setup(input: &str) -> Scanner {
		Scanner::new(input)
	}

	fn expect(scanner: &mut Scanner, tt: TokenType) {
		let token = unwrap!(scanner.next(), {
			panic!("Expected token but found None");
		});

		assert_eq!(token.token_type, tt);
	}

	#[test]
	fn scan_ampersand() {
		let mut s = setup("&");
		expect(&mut s, TokenType::Ampersand);
	}

	#[test]
	fn scan_bang() {
		let mut s = setup("!");
		expect(&mut s, TokenType::Bang);
	}

	#[test]
	fn scan_caret() {
		let mut s = setup("^");
		expect(&mut s, TokenType::Caret);
	}

	#[test]
	fn scan_forward_slash() {
		let mut s = setup("/");
		expect(&mut s, TokenType::ForwardSlash);
	}

	#[test]
	fn scan_identifier() {
		let mut s = setup("ans");
		expect(&mut s, TokenType::Identifier { str: "ans".to_string() });
	}

	#[test]
	fn scan_left_angle_bracket_x2() {
		let mut s = setup("<<");
		expect(&mut s, TokenType::LeftAngleBracketX2);
	}

	#[test]
	fn scan_left_paren() {
		let mut s = setup("(");
		expect(&mut s, TokenType::LeftParen);
	}

	#[test]
	fn scan_minus() {
		let mut s = setup("-");
		expect(&mut s, TokenType::Minus);
	}

	#[test]
	fn scan_new_line() {
		let mut s = setup("\n");
		expect(&mut s, TokenType::NewLine);
	}

	#[test]
	fn scan_number() {
		let mut s = setup("123");
		expect(&mut s, TokenType::Number { str: "123".to_string() });
	}

	#[test]
	fn scan_percent() {
		let mut s = setup("%");
		expect(&mut s, TokenType::Percent);
	}

	#[test]
	fn scan_pipe() {
		let mut s = setup("|");
		expect(&mut s, TokenType::Pipe);
	}

	#[test]
	fn scan_plus() {
		let mut s = setup("+");
		expect(&mut s, TokenType::Plus);
	}

	#[test]
	fn scan_right_angle_bracket_x2() {
		let mut s = setup(">>");
		expect(&mut s, TokenType::RightAngleBracketX2);
	}

	#[test]
	fn scan_right_paren() {
		let mut s = setup(")");
		expect(&mut s, TokenType::RightParen);
	}

	#[test]
	fn scan_star() {
		let mut s = setup("*");
		expect(&mut s, TokenType::Star);
	}

	#[test]
	fn scan_star_x2() {
		let mut s = setup("**");
		expect(&mut s, TokenType::StarX2);
	}
} // mod tests
<|endoftext|>


<commit_before>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;
use util::Id;

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

use std::hash::{ Hash, Hasher };
use std::collections::{ HashSet, HashMap };

/// A marker for Id.
/// Only useful for writing `Id<ServiceId>`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ServiceId;

/// A marker for Id.
/// Only useful for writing `Id<AdapterId>`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct AdapterId;

// A marker for Id.
/// Only useful for writing `Id<TagId>`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct TagId;

// A helper macro to create a Id<ServiceId> without boilerplate.
#[macro_export]
macro_rules! service_id {
    ($val:expr) => (Id::<ServiceId>::new($val))
}

// A helper macro to create a Id<AdapterId> without boilerplate.
#[macro_export]
macro_rules! adapter_id {
    ($val:expr) => (Id::<AdapterId>::new($val))
}

// A helper macro to create a Id<TagId> without boilerplate.
#[macro_export]
macro_rules! tag_id {
    ($val:expr) => (Id::<TagId>::new($val))
}

/// Metadata on a service. A service is a device or collection of devices
/// that may offer services. The FoxBox itself is a service offering
/// services such as a clock, communicating with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find services and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all services
    /// placed in the entrance of his house, or a tag "blue" to a service
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    pub tags: HashSet<Id<TagId>>,

    /// An id unique to this service.
    pub id: Id<ServiceId>,

    /// Getter channels connected directly to this service.
    pub getters: HashMap<Id<Getter>, Channel<Getter>>,

    /// Setter channels connected directly to this service.
    pub setters: HashMap<Id<Setter>, Channel<Setter>>,

    /// Identifier of the adapter for this service.
    pub adapter: Id<AdapterId>,
}

impl Service {
    /// Create an empty service.
    pub fn empty(id: Id<ServiceId>, adapter: Id<AdapterId>) -> Self {
        Service {
            tags: HashSet::new(),
            getters: HashMap::new(),
            setters: HashMap::new(),
            id: id,
            adapter: adapter,
        }
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ChannelKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ChannelKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ChannelKind::*;
        use values::Type;
        match *self {
            Ready => Type::Unit,
            OnOff => Type::OnOff,
            OpenClosed => Type::OpenClosed,
            CurrentTime => Type::TimeStamp,
            CurrentTimeOfDay | RemainingTime => Type::Duration,
            Thermostat | ActualTemperature => Type::Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }
}

/// A getter operation available on a channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Getter {
    /// The kind of value that can be obtained from this channel.
    pub kind: ChannelKind,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    #[serde(default)]
    pub updated: Option<TimeStamp>,
}

impl IOMechanism for Getter {
}

/// An setter operation available on an channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Setter {
    /// The kind of value that can be sent to this channel.
    pub kind: ChannelKind,

    /// Date at which the latest value was sent to the channel.
    #[serde(default)]
    pub updated: Option<TimeStamp>,
}

impl IOMechanism for Setter {
}

/// An channel represents a single place where data can enter or
/// leave a device. Note that channels support either a single kind
/// of getter or a single kind of setter. Devices that support both
/// getters or setters, or several kinds of getters, or several kinds of
/// setters, are represented as services containing several channels.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Channel<IO> where IO: IOMechanism {
    /// Tags describing the channel.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup channels for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    pub tags: HashSet<Id<TagId>>,

    /// An id unique to this channel.
    pub id: Id<IO>,

    /// The service owning this channel.
    pub service: Id<ServiceId>,

    /// The update mechanism for this channel.
    pub mechanism: IO,

    /// Identifier of the adapter for this channel.
    pub adapter: Id<AdapterId>,

    /// The last time the device was seen.
    #[serde(default)]
    pub last_seen: Option<TimeStamp>,
}

impl<IO> Eq for Channel<IO> where IO: IOMechanism {
}

impl<IO> PartialEq for Channel<IO> where IO: IOMechanism {
     fn eq(&self, other: &Self) -> bool {
         self.id.eq(&other.id)
     }
}

impl<IO> Hash for Channel<IO> where IO: IOMechanism {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.id.hash(state)
    }
}

/// The communication mechanism used by the channel.
pub trait IOMechanism: Deserialize + Serialize {
}

<commit_msg>Add a property bag to services<commit_after>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;
use util::Id;

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

use std::hash::{ Hash, Hasher };
use std::collections::{ HashSet, HashMap };

/// A marker for Id.
/// Only useful for writing `Id<ServiceId>`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ServiceId;

/// A marker for Id.
/// Only useful for writing `Id<AdapterId>`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct AdapterId;

// A marker for Id.
/// Only useful for writing `Id<TagId>`.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct TagId;

// A helper macro to create a Id<ServiceId> without boilerplate.
#[macro_export]
macro_rules! service_id {
    ($val:expr) => (Id::<ServiceId>::new($val))
}

// A helper macro to create a Id<AdapterId> without boilerplate.
#[macro_export]
macro_rules! adapter_id {
    ($val:expr) => (Id::<AdapterId>::new($val))
}

// A helper macro to create a Id<TagId> without boilerplate.
#[macro_export]
macro_rules! tag_id {
    ($val:expr) => (Id::<TagId>::new($val))
}

/// Metadata on a service. A service is a device or collection of devices
/// that may offer services. The FoxBox itself is a service offering
/// services such as a clock, communicating with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find services and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all services
    /// placed in the entrance of his house, or a tag "blue" to a service
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    pub tags: HashSet<Id<TagId>>,

    /// An id unique to this service.
    pub id: Id<ServiceId>,

    /// Service properties that are set at creation time.
    /// For instance, these can be device manufacturer, model, etc.
    pub properties: HashMap<String, String>,

    /// Getter channels connected directly to this service.
    pub getters: HashMap<Id<Getter>, Channel<Getter>>,

    /// Setter channels connected directly to this service.
    pub setters: HashMap<Id<Setter>, Channel<Setter>>,

    /// Identifier of the adapter for this service.
    pub adapter: Id<AdapterId>,
}

impl Service {
    /// Create an empty service.
    pub fn empty(id: Id<ServiceId>, adapter: Id<AdapterId>) -> Self {
        Service {
            tags: HashSet::new(),
            getters: HashMap::new(),
            setters: HashMap::new(),
            properties: HashMap::new(),
            id: id,
            adapter: adapter,
        }
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ChannelKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ChannelKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ChannelKind::*;
        use values::Type;
        match *self {
            Ready => Type::Unit,
            OnOff => Type::OnOff,
            OpenClosed => Type::OpenClosed,
            CurrentTime => Type::TimeStamp,
            CurrentTimeOfDay | RemainingTime => Type::Duration,
            Thermostat | ActualTemperature => Type::Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }
}

/// A getter operation available on a channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Getter {
    /// The kind of value that can be obtained from this channel.
    pub kind: ChannelKind,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    #[serde(default)]
    pub updated: Option<TimeStamp>,
}

impl IOMechanism for Getter {
}

/// An setter operation available on an channel.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Setter {
    /// The kind of value that can be sent to this channel.
    pub kind: ChannelKind,

    /// Date at which the latest value was sent to the channel.
    #[serde(default)]
    pub updated: Option<TimeStamp>,
}

impl IOMechanism for Setter {
}

/// An channel represents a single place where data can enter or
/// leave a device. Note that channels support either a single kind
/// of getter or a single kind of setter. Devices that support both
/// getters or setters, or several kinds of getters, or several kinds of
/// setters, are represented as services containing several channels.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Channel<IO> where IO: IOMechanism {
    /// Tags describing the channel.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup channels for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    pub tags: HashSet<Id<TagId>>,

    /// An id unique to this channel.
    pub id: Id<IO>,

    /// The service owning this channel.
    pub service: Id<ServiceId>,

    /// The update mechanism for this channel.
    pub mechanism: IO,

    /// Identifier of the adapter for this channel.
    pub adapter: Id<AdapterId>,

    /// The last time the device was seen.
    #[serde(default)]
    pub last_seen: Option<TimeStamp>,
}

impl<IO> Eq for Channel<IO> where IO: IOMechanism {
}

impl<IO> PartialEq for Channel<IO> where IO: IOMechanism {
     fn eq(&self, other: &Self) -> bool {
         self.id.eq(&other.id)
     }
}

impl<IO> Hash for Channel<IO> where IO: IOMechanism {
    fn hash<H>(&self, state: &mut H) where H: Hasher {
        self.id.hash(state)
    }
}

/// The communication mechanism used by the channel.
pub trait IOMechanism: Deserialize + Serialize {
}

<|endoftext|>


<commit_before>use encoding::EncodingRef;
use encoding::all::UTF_8;
use loirc::{MonitorSettings, ReconnectionSettings};

/// Settings for the dispatcher.
pub struct Settings<'a> {
    /// Address of the irc server.
    pub addr: &'a str,
    /// Preferred nickname.
    pub nickname: &'a str,
    /// Username.
    pub username: &'a str,
    /// Real name.
    pub realname: &'a str,
    /// Reconnection settings. If None, reconnection is disabled.
    pub reconnection: ReconnectionSettings,
    /// Monitor settings. If None, monitoring is disabled.
    pub monitor: Option<MonitorSettings>,
    /// Automatically identify after reconnection.
    pub auto_ident: bool,
    /// Automatically reply to ping requests.
    pub auto_ping: bool,
    /// Encoding used for the connection.
    pub encoding: EncodingRef,
}

impl<'a> Settings<'a> {

    /// Create new settings with sensible defaults.
    pub fn new<'b>(addr: &'b str, nickname: &'b str) -> Settings<'b> {
        Settings {
            addr: addr,
            nickname: nickname,
            username: "hiirc",
            realname: "hiirc",
            reconnection: ReconnectionSettings::DoNotReconnect,
            monitor: None,
            auto_ident: true,
            auto_ping: true,
            encoding: UTF_8,
        }
    }

}
<commit_msg>Document the default values of Settings::new<commit_after>use encoding::EncodingRef;
use encoding::all::UTF_8;
use loirc::{MonitorSettings, ReconnectionSettings};

/// Settings for the dispatcher.
pub struct Settings<'a> {
    /// Address of the irc server.
    pub addr: &'a str,
    /// Preferred nickname.
    pub nickname: &'a str,
    /// Username.
    pub username: &'a str,
    /// Real name.
    pub realname: &'a str,
    /// Reconnection settings. If None, reconnection is disabled.
    pub reconnection: ReconnectionSettings,
    /// Monitor settings. If None, monitoring is disabled.
    pub monitor: Option<MonitorSettings>,
    /// Automatically identify after reconnection.
    pub auto_ident: bool,
    /// Automatically reply to ping requests.
    pub auto_ping: bool,
    /// Encoding used for the connection.
    pub encoding: EncodingRef,
}

impl<'a> Settings<'a> {

    /// Create new settings with sensible default values.
    ///
    /// The default values are:
    ///
    /// ```
    /// username: "hiirc",
    /// realname: "hiirc",
    /// reconnection: ReonnectionSettings::DoNotReconnect,
    /// monitor: None,
    /// auto_ident: true,
    /// auto_ping: true,
    /// encoding: UTF_8,
    /// ```
    pub fn new<'b>(addr: &'b str, nickname: &'b str) -> Settings<'b> {
        Settings {
            addr: addr,
            nickname: nickname,
            username: "hiirc",
            realname: "hiirc",
            reconnection: ReconnectionSettings::DoNotReconnect,
            monitor: None,
            auto_ident: true,
            auto_ping: true,
            encoding: UTF_8,
        }
    }

}
<|endoftext|>


<commit_before>//! Force (base unit newton, kg1 · m1 · s-2).

quantity! {
    /// Force (base unit newton, kg1 · m1 · s-2).
    quantity: Force; "force";
    /// Force dimension, kg1 · m1 · s-2.
    dimension: ISQ<
        P1,     // length
        P1,     // mass
        N2,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @yottanewton: prefix!(yotta); "YN", "yottanewton", "yottanewtons";
        @zettanewton: prefix!(zetta); "ZN", "zettanewton", "zettanewtons";
        @exanewton: prefix!(exa); "EN", "exanewton", "exanewtons";
        @petanewton: prefix!(peta); "PN", "petanewton", "petanewtons";
        @teranewton: prefix!(tera); "TN", "teranewton", "teranewtons";
        @giganewton: prefix!(giga); "GN", "giganewton", "giganewtons";
        @meganewton: prefix!(mega); "MN", "meganewton", "meganewtons";
        @kilonewton: prefix!(kilo); "kN", "kilonewton", "kilonewtons";
        @hectonewton: prefix!(hecto); "hN", "hectonewton", "hectonewtons";
        @decanewton: prefix!(deca); "daN", "decanewton", "decanewtons";
        /// Derived unit of force.
        @newton: prefix!(none); "N", "newton", "newtons";
        @decinewton: prefix!(deci); "dN", "decinewton", "decinewtons";
        @centinewton: prefix!(centi); "cN", "centinewton", "centinewtons";
        @millinewton: prefix!(milli); "mN", "millinewton", "millinewtons";
        @micronewton: prefix!(micro); "µN", "micronewton", "micronewtons";
        @nanonewton: prefix!(nano); "nN", "nanonewton", "nanonewtons";
        @piconewton: prefix!(pico); "pN", "piconewton", "piconewtons";
        @femtonewton: prefix!(femto); "fN", "femtonewton", "femtonewtons";
        @attonewton: prefix!(atto); "aN", "attonewton", "attonewtons";
        @zeptonewton: prefix!(zepto); "zN", "zeptonewton", "zeptonewtons";
        @yoctonewton: prefix!(yocto); "yN", "yoctonewton", "yoctonewtons";
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use num::One;
        use si::quantities::*;
        use si::force as f;
        use si::length as l;
        use si::mass as m;
        use si::time as t;
        use tests::Test;

        #[test]
        fn check_dimension() {
            let _: Force<V> = (Mass::new::<m::kilogram>(V::one())
                    * Length::new::<l::meter>(V::one()))
                / (Time::new::<t::second>(V::one()) * Time::new::<t::second>(V::one()));
        }

        #[test]
        fn check_units() {
            test::<m::yottagram, l::meter, t::second, f::zettanewton>();
            test::<m::zettagram, l::meter, t::second, f::exanewton>();
            test::<m::exagram, l::meter, t::second, f::petanewton>();
            test::<m::petagram, l::meter, t::second, f::teranewton>();
            test::<m::teragram, l::meter, t::second, f::giganewton>();
            test::<m::gigagram, l::meter, t::second, f::meganewton>();
            test::<m::megagram, l::meter, t::second, f::kilonewton>();
            test::<m::kilogram, l::meter, t::second, f::newton>();
            test::<m::gram, l::meter, t::second, f::millinewton>();
            test::<m::milligram, l::meter, t::second, f::micronewton>();
            test::<m::microgram, l::meter, t::second, f::nanonewton>();
            test::<m::nanogram, l::meter, t::second, f::piconewton>();
            test::<m::picogram, l::meter, t::second, f::femtonewton>();
            test::<m::femtogram, l::meter, t::second, f::attonewton>();
            test::<m::attogram, l::meter, t::second, f::zeptonewton>();
            test::<m::zeptogram, l::meter, t::second, f::yoctonewton>();

            test::<m::kilogram, l::yottameter, t::second, f::yottanewton>();
            test::<m::kilogram, l::zettameter, t::second, f::zettanewton>();
            test::<m::kilogram, l::exameter, t::second, f::exanewton>();
            test::<m::kilogram, l::petameter, t::second, f::petanewton>();
            test::<m::kilogram, l::terameter, t::second, f::teranewton>();
            test::<m::kilogram, l::gigameter, t::second, f::giganewton>();
            test::<m::kilogram, l::megameter, t::second, f::meganewton>();
            test::<m::kilogram, l::kilometer, t::second, f::kilonewton>();
            test::<m::kilogram, l::hectometer, t::second, f::hectonewton>();
            test::<m::kilogram, l::decameter, t::second, f::decanewton>();
            test::<m::kilogram, l::meter, t::second, f::newton>();
            test::<m::kilogram, l::decimeter, t::second, f::decinewton>();
            test::<m::kilogram, l::centimeter, t::second, f::centinewton>();
            test::<m::kilogram, l::millimeter, t::second, f::millinewton>();
            test::<m::kilogram, l::micrometer, t::second, f::micronewton>();
            test::<m::kilogram, l::nanometer, t::second, f::nanonewton>();
            test::<m::kilogram, l::picometer, t::second, f::piconewton>();
            test::<m::kilogram, l::femtometer, t::second, f::femtonewton>();
            test::<m::kilogram, l::attometer, t::second, f::attonewton>();
            test::<m::kilogram, l::zeptometer, t::second, f::zeptonewton>();
            test::<m::kilogram, l::meter, t::second, f::newton>();

            test::<m::kilogram, l::meter, t::terasecond, f::yoctonewton>();
            test::<m::kilogram, l::meter, t::gigasecond, f::attonewton>();
            test::<m::kilogram, l::meter, t::megasecond, f::piconewton>();
            test::<m::kilogram, l::meter, t::kilosecond, f::micronewton>();
            test::<m::kilogram, l::meter, t::decasecond, f::centinewton>();
            test::<m::kilogram, l::meter, t::decisecond, f::hectonewton>();
            test::<m::kilogram, l::meter, t::millisecond, f::meganewton>();
            test::<m::kilogram, l::meter, t::microsecond, f::teranewton>();
            test::<m::kilogram, l::meter, t::nanosecond, f::exanewton>();
            test::<m::kilogram, l::meter, t::picosecond, f::yottanewton>();

            fn test<
                M: m::Conversion<V>,
                L: l::Conversion<V>,
                T: t::Conversion<V>,
                F: f::Conversion<V>>()
            {
                Test::assert_approx_eq(&Force::new::<F>(V::one()),
                    &((Mass::new::<M>(V::one())
                        * Length::new::<L>(V::one()))
                        / (Time::new::<T>(V::one()) * Time::new::<T>(V::one()))));
            }
        }
    }
}
<commit_msg>Add additional force units.<commit_after>//! Force (base unit newton, kg1 · m1 · s-2).

quantity! {
    /// Force (base unit newton, kg1 · m1 · s-2).
    quantity: Force; "force";
    /// Force dimension, kg1 · m1 · s-2.
    dimension: ISQ<
        P1,     // length
        P1,     // mass
        N2,     // time
        Z0,     // electric current
        Z0,     // thermodynamic temperature
        Z0,     // amount of substance
        Z0>;    // luminous intensity
    units {
        @yottanewton: prefix!(yotta); "YN", "yottanewton", "yottanewtons";
        @zettanewton: prefix!(zetta); "ZN", "zettanewton", "zettanewtons";
        @exanewton: prefix!(exa); "EN", "exanewton", "exanewtons";
        @petanewton: prefix!(peta); "PN", "petanewton", "petanewtons";
        @teranewton: prefix!(tera); "TN", "teranewton", "teranewtons";
        @giganewton: prefix!(giga); "GN", "giganewton", "giganewtons";
        @meganewton: prefix!(mega); "MN", "meganewton", "meganewtons";
        @kilonewton: prefix!(kilo); "kN", "kilonewton", "kilonewtons";
        @hectonewton: prefix!(hecto); "hN", "hectonewton", "hectonewtons";
        @decanewton: prefix!(deca); "daN", "decanewton", "decanewtons";
        /// Derived unit of force.
        @newton: prefix!(none); "N", "newton", "newtons";
        @decinewton: prefix!(deci); "dN", "decinewton", "decinewtons";
        @centinewton: prefix!(centi); "cN", "centinewton", "centinewtons";
        @millinewton: prefix!(milli); "mN", "millinewton", "millinewtons";
        @micronewton: prefix!(micro); "µN", "micronewton", "micronewtons";
        @nanonewton: prefix!(nano); "nN", "nanonewton", "nanonewtons";
        @piconewton: prefix!(pico); "pN", "piconewton", "piconewtons";
        @femtonewton: prefix!(femto); "fN", "femtonewton", "femtonewtons";
        @attonewton: prefix!(atto); "aN", "attonewton", "attonewtons";
        @zeptonewton: prefix!(zepto); "zN", "zeptonewton", "zeptonewtons";
        @yoctonewton: prefix!(yocto); "yN", "yoctonewton", "yoctonewtons";

        @dyne: 1.0_E-5; "dyn", "dyne", "dynes";
        @kilogram_force: 9.806_65_E0; "kgf", "kilogram-force", "kilograms-force"; // kilopond
        @kip: 4.448_222_E3; "kip", "kip", "kips";
        @ounce_force: 2.780_139_E-1; "ozf", "ounce-force", "ounces-force";
        @poundal: 1.382_550_E-1; "pdl", "poundal", "poundals";
        @pound_force: 4.448_222_E0; "lbf", "pound-force", "pounds-force";
        @ton_force: 8.896_443_E3; "2000 lbf", "ton-force", "tons-force"; // Uses the metric ton
    }
}

#[cfg(test)]
mod tests {
    storage_types! {
        use num::One;
        use si::quantities::*;
        use si::force as f;
        use si::length as l;
        use si::mass as m;
        use si::time as t;
        use tests::Test;

        #[test]
        fn check_dimension() {
            let _: Force<V> = (Mass::new::<m::kilogram>(V::one())
                    * Length::new::<l::meter>(V::one()))
                / (Time::new::<t::second>(V::one()) * Time::new::<t::second>(V::one()));
        }

        #[test]
        fn check_units() {
            test::<m::yottagram, l::meter, t::second, f::zettanewton>();
            test::<m::zettagram, l::meter, t::second, f::exanewton>();
            test::<m::exagram, l::meter, t::second, f::petanewton>();
            test::<m::petagram, l::meter, t::second, f::teranewton>();
            test::<m::teragram, l::meter, t::second, f::giganewton>();
            test::<m::gigagram, l::meter, t::second, f::meganewton>();
            test::<m::megagram, l::meter, t::second, f::kilonewton>();
            test::<m::kilogram, l::meter, t::second, f::newton>();
            test::<m::gram, l::meter, t::second, f::millinewton>();
            test::<m::milligram, l::meter, t::second, f::micronewton>();
            test::<m::microgram, l::meter, t::second, f::nanonewton>();
            test::<m::nanogram, l::meter, t::second, f::piconewton>();
            test::<m::picogram, l::meter, t::second, f::femtonewton>();
            test::<m::femtogram, l::meter, t::second, f::attonewton>();
            test::<m::attogram, l::meter, t::second, f::zeptonewton>();
            test::<m::zeptogram, l::meter, t::second, f::yoctonewton>();

            test::<m::kilogram, l::yottameter, t::second, f::yottanewton>();
            test::<m::kilogram, l::zettameter, t::second, f::zettanewton>();
            test::<m::kilogram, l::exameter, t::second, f::exanewton>();
            test::<m::kilogram, l::petameter, t::second, f::petanewton>();
            test::<m::kilogram, l::terameter, t::second, f::teranewton>();
            test::<m::kilogram, l::gigameter, t::second, f::giganewton>();
            test::<m::kilogram, l::megameter, t::second, f::meganewton>();
            test::<m::kilogram, l::kilometer, t::second, f::kilonewton>();
            test::<m::kilogram, l::hectometer, t::second, f::hectonewton>();
            test::<m::kilogram, l::decameter, t::second, f::decanewton>();
            test::<m::kilogram, l::meter, t::second, f::newton>();
            test::<m::kilogram, l::decimeter, t::second, f::decinewton>();
            test::<m::kilogram, l::centimeter, t::second, f::centinewton>();
            test::<m::kilogram, l::millimeter, t::second, f::millinewton>();
            test::<m::kilogram, l::micrometer, t::second, f::micronewton>();
            test::<m::kilogram, l::nanometer, t::second, f::nanonewton>();
            test::<m::kilogram, l::picometer, t::second, f::piconewton>();
            test::<m::kilogram, l::femtometer, t::second, f::femtonewton>();
            test::<m::kilogram, l::attometer, t::second, f::attonewton>();
            test::<m::kilogram, l::zeptometer, t::second, f::zeptonewton>();
            test::<m::kilogram, l::meter, t::second, f::newton>();

            test::<m::kilogram, l::meter, t::terasecond, f::yoctonewton>();
            test::<m::kilogram, l::meter, t::gigasecond, f::attonewton>();
            test::<m::kilogram, l::meter, t::megasecond, f::piconewton>();
            test::<m::kilogram, l::meter, t::kilosecond, f::micronewton>();
            test::<m::kilogram, l::meter, t::decasecond, f::centinewton>();
            test::<m::kilogram, l::meter, t::decisecond, f::hectonewton>();
            test::<m::kilogram, l::meter, t::millisecond, f::meganewton>();
            test::<m::kilogram, l::meter, t::microsecond, f::teranewton>();
            test::<m::kilogram, l::meter, t::nanosecond, f::exanewton>();
            test::<m::kilogram, l::meter, t::picosecond, f::yottanewton>();

            fn test<
                M: m::Conversion<V>,
                L: l::Conversion<V>,
                T: t::Conversion<V>,
                F: f::Conversion<V>>()
            {
                Test::assert_approx_eq(&Force::new::<F>(V::one()),
                    &((Mass::new::<M>(V::one())
                        * Length::new::<L>(V::one()))
                        / (Time::new::<T>(V::one()) * Time::new::<T>(V::one()))));
            }
        }
    }
}
<|endoftext|>


<commit_before>mod fakes;

use crate::web::Server;
use failure::Error;
use once_cell::unsync::OnceCell;
use postgres::Connection;
use reqwest::{Client, Method, RequestBuilder};
use std::sync::{Arc, Mutex, MutexGuard};
use std::panic;

pub(crate) fn wrapper(f: impl FnOnce(&TestEnvironment) -> Result<(), Error>) {
    let env = TestEnvironment::new();
    // if we didn't catch the panic, the server would hang forever
    let maybe_panic = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&env)));
    env.cleanup();
    let result = match maybe_panic {
        Ok(r) => r,
        Err(payload) => panic::resume_unwind(payload),
    };

    if let Err(err) = result {
        eprintln!("the test failed: {}", err);
        for cause in err.iter_causes() {
            eprintln!("  caused by: {}", cause);
        }

        eprintln!("{}", err.backtrace());

        panic!("the test failed");
    }
}

/// Make sure that a URL returns a status code between 200-299
pub(crate) fn assert_success(path: &str, web: &TestFrontend) -> Result<(), Error> {
    let status = web.get(path).send()?.status();
    assert!(status.is_success(), "failed to GET {}: {}", path, status);
    Ok(())
}

/// Make sure that a URL redirects to a specific page
pub(crate) fn assert_redirect(path: &str, expected_target: &str, web: &TestFrontend) -> Result<(), Error> {
    let response = web.get(path).send()?;
    let status = response.status();
    // Reqwest follows redirects
    assert!(status.is_success(), "failed to GET {}: {}", path, status);

    let redirect_target = response.url().path();
    assert!(redirect_target == expected_target,
            "{}: expected redirect to {}, got redirect to {}",
            path, expected_target, redirect_target);
    Ok(())
}

pub(crate) struct TestEnvironment {
    db: OnceCell<TestDatabase>,
    frontend: OnceCell<TestFrontend>,
}

impl TestEnvironment {
    fn new() -> Self {
        Self {
            db: OnceCell::new(),
            frontend: OnceCell::new(),
        }
    }

    fn cleanup(self) {
        if let Some(frontend) = self.frontend.into_inner() {
            frontend.server.leak();
        }
    }

    pub(crate) fn db(&self) -> &TestDatabase {
        self.db
            .get_or_init(|| TestDatabase::new().expect("failed to initialize the db"))
    }

    pub(crate) fn frontend(&self) -> &TestFrontend {
        self.frontend.get_or_init(|| TestFrontend::new(self.db()))
    }
}

pub(crate) struct TestDatabase {
    conn: Arc<Mutex<Connection>>,
}

impl TestDatabase {
    fn new() -> Result<Self, Error> {
        // The temporary migration uses CREATE TEMPORARY TABLE instead of CREATE TABLE, creating
        // fresh temporary copies of the database on top of the real one. The temporary tables are
        // only visible to this connection, and will be deleted when it exits.
        let conn = crate::db::connect_db()?;
        crate::db::migrate_temporary(None, &conn)?;

        Ok(TestDatabase {
            conn: Arc::new(Mutex::new(conn)),
        })
    }

    pub(crate) fn conn(&self) -> MutexGuard<Connection> {
        self.conn.lock().expect("failed to lock the connection")
    }

    pub(crate) fn fake_release(&self) -> fakes::FakeRelease {
        fakes::FakeRelease::new(self)
    }
}

pub(crate) struct TestFrontend {
    server: Server,
    client: Client,
}

impl TestFrontend {
    fn new(db: &TestDatabase) -> Self {
        Self {
            server: Server::start_test(db.conn.clone()),
            client: Client::new(),
        }
    }

    fn build_request(&self, method: Method, url: &str) -> RequestBuilder {
        self.client
            .request(method, &format!("http://{}{}", self.server.addr(), url))
    }

    pub(crate) fn get(&self, url: &str) -> RequestBuilder {
        self.build_request(Method::GET, url)
    }
}
<commit_msg>improve error if web redirects to wrong page<commit_after>mod fakes;

use crate::web::Server;
use failure::Error;
use once_cell::unsync::OnceCell;
use postgres::Connection;
use reqwest::{Client, Method, RequestBuilder};
use std::sync::{Arc, Mutex, MutexGuard};
use std::panic;

pub(crate) fn wrapper(f: impl FnOnce(&TestEnvironment) -> Result<(), Error>) {
    let env = TestEnvironment::new();
    // if we didn't catch the panic, the server would hang forever
    let maybe_panic = panic::catch_unwind(panic::AssertUnwindSafe(|| f(&env)));
    env.cleanup();
    let result = match maybe_panic {
        Ok(r) => r,
        Err(payload) => panic::resume_unwind(payload),
    };

    if let Err(err) = result {
        eprintln!("the test failed: {}", err);
        for cause in err.iter_causes() {
            eprintln!("  caused by: {}", cause);
        }

        eprintln!("{}", err.backtrace());

        panic!("the test failed");
    }
}

/// Make sure that a URL returns a status code between 200-299
pub(crate) fn assert_success(path: &str, web: &TestFrontend) -> Result<(), Error> {
    let status = web.get(path).send()?.status();
    assert!(status.is_success(), "failed to GET {}: {}", path, status);
    Ok(())
}

/// Make sure that a URL redirects to a specific page
pub(crate) fn assert_redirect(path: &str, expected_target: &str, web: &TestFrontend) -> Result<(), Error> {
    let response = web.get(path).send()?;
    let status = response.status();

    // Reqwest follows redirects automatically
    let redirect_target = response.url().path();
    if redirect_target != expected_target {
        if redirect_target != path {
            panic!("{}: expected redirect to {}, got redirect to {}",
                   path, expected_target, redirect_target);
        } else {
            panic!("{}: expected redirect to {}, got {}", path, expected_target, status);
        }
    }
    assert!(status.is_success(), "failed to GET {}: {}", expected_target, status);
    Ok(())
}

pub(crate) struct TestEnvironment {
    db: OnceCell<TestDatabase>,
    frontend: OnceCell<TestFrontend>,
}

impl TestEnvironment {
    fn new() -> Self {
        Self {
            db: OnceCell::new(),
            frontend: OnceCell::new(),
        }
    }

    fn cleanup(self) {
        if let Some(frontend) = self.frontend.into_inner() {
            frontend.server.leak();
        }
    }

    pub(crate) fn db(&self) -> &TestDatabase {
        self.db
            .get_or_init(|| TestDatabase::new().expect("failed to initialize the db"))
    }

    pub(crate) fn frontend(&self) -> &TestFrontend {
        self.frontend.get_or_init(|| TestFrontend::new(self.db()))
    }
}

pub(crate) struct TestDatabase {
    conn: Arc<Mutex<Connection>>,
}

impl TestDatabase {
    fn new() -> Result<Self, Error> {
        // The temporary migration uses CREATE TEMPORARY TABLE instead of CREATE TABLE, creating
        // fresh temporary copies of the database on top of the real one. The temporary tables are
        // only visible to this connection, and will be deleted when it exits.
        let conn = crate::db::connect_db()?;
        crate::db::migrate_temporary(None, &conn)?;

        Ok(TestDatabase {
            conn: Arc::new(Mutex::new(conn)),
        })
    }

    pub(crate) fn conn(&self) -> MutexGuard<Connection> {
        self.conn.lock().expect("failed to lock the connection")
    }

    pub(crate) fn fake_release(&self) -> fakes::FakeRelease {
        fakes::FakeRelease::new(self)
    }
}

pub(crate) struct TestFrontend {
    server: Server,
    client: Client,
}

impl TestFrontend {
    fn new(db: &TestDatabase) -> Self {
        Self {
            server: Server::start_test(db.conn.clone()),
            client: Client::new(),
        }
    }

    fn build_request(&self, method: Method, url: &str) -> RequestBuilder {
        self.client
            .request(method, &format!("http://{}{}", self.server.addr(), url))
    }

    pub(crate) fn get(&self, url: &str) -> RequestBuilder {
        self.build_request(Method::GET, url)
    }
}
<|endoftext|>


<commit_before>extern crate rand;
extern crate itertools;
use self::itertools::Itertools;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::rc::Rc;
use std::cell::RefCell;
use std::sync::mpsc::Receiver;

type WordCell = Rc<RefCell<Word>>;
pub type AuthorCell = Rc<RefCell<Author>>;
pub type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;
type InstanceCell = Rc<RefCell<WordInstance>>;

fn wrap<T>(t: T) -> Rc<RefCell<T>> {
    Rc::new(RefCell::new(t))
}

// const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

#[derive(Default)]
pub struct Lexicon<R: rand::Rng> {
    rng: R,
    words: BTreeMap<String, WordCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
    messages: Vec<MessageCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl<R: rand::Rng> Lexicon<R> {
    pub fn new(rng: R) -> Lexicon<R> {
        Lexicon{
            rng: rng,
            words: Default::default(),
            sources: Default::default(),
            conversations: Default::default(),
            messages: Default::default(),
            active_conversations: Default::default(),
        }
    }

    pub fn source(&mut self, name: String) -> SourceCell {
        match self.sources.entry(name.clone()) {
            Entry::Vacant(v) => v.insert(wrap(Source{
                name: name,
                messages: 0,
                authors: BTreeMap::default(),
            })).clone(),
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    pub fn author(&mut self, source: SourceCell, name: String) -> AuthorCell {
        match source.borrow_mut().authors.entry(name.clone()) {
            Entry::Vacant(v) => {
                let a = wrap(Author{
                    source: source.clone(),
                    name: name.clone(),
                });
                v.insert(a.clone());
                a
            },
            Entry::Occupied(o) => o.get().clone(),
        }
    }
    pub fn tell(&mut self, source: SourceCell, author: AuthorCell, content: String) -> Option<String> {
        let conversation = match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                let c = wrap(Conversation{
                    source: source.clone(),
                    messages: Vec::new(),
                });
                v.insert(c.clone());
                self.conversations.push(c.clone());
                c
            },
            Entry::Occupied(o) => {
                o.get().clone()
            },
        };

        let message = wrap(Message{
            author: author.clone(),
            conversation: conversation.clone(),
            index: conversation.borrow().messages.len(),
            instances: Vec::new(),
        });

        self.messages.push(message.clone());

        for word in content.split(' ').map(|s| {
            let string = s.to_string();
            match self.words.entry(string.clone()) {
                Entry::Vacant(v) => {
                    let w = wrap(Word{
                        name: string,
                        instances: Vec::new(),
                    });
                    v.insert(w.clone());
                    w
                },
                Entry::Occupied(o) => {
                    o.get().clone()
                },
            }
        }) {
            // Create empty category for the word
            let category = wrap(Category::default());
            // Create instance of the word
            let instance = wrap(WordInstance{
                word: word.clone(),
                category: category.clone(),
                message: message.clone(),
                index: message.borrow().instances.len(),
            });
            // Insert word instance into the word, category, and message for future reference
            message.borrow_mut().instances.push(instance.clone());
            category.borrow_mut().instances.push(instance.clone());
            word.borrow_mut().instances.push(instance);
        }

        // Increment the messages by 1 for the source
        source.borrow_mut().messages += 1;

        // TODO: Determine what to say back
        None
    }

    pub fn initiate(&mut self, source: SourceCell) -> Option<String> {
        let conversation = wrap(Conversation{
            source: source.clone(),
            messages: Vec::new(),
        });

        match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                v.insert(conversation.clone());
            },
            Entry::Occupied(mut o) => {
                o.insert(conversation.clone());
            },
        };

        self.conversations.push(conversation.clone());

        let base = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return None,
        };

        let bborrow = base.borrow();

        Some(bborrow.instances.iter()
            .map(|instance| instance.borrow().category.clone())
            // TODO: Allow random choosing from co-category instances as well
            .map(|category| self.rng.choose(&category.borrow().instances[..]).unwrap().clone())
            .map(|instance| {
                let ins = instance.borrow();
                let word = ins.word.borrow();
                word.name.clone()
            })
            .join(" "))
    }

    pub fn think(&mut self, end: Receiver<()>) {
        use std::sync::mpsc::TryRecvError::Empty;
        while end.try_recv() == Err(Empty) {
            // Choose a random message or break if there are none
            let message = match self.rng.choose(&self.messages[..]) {
                Some(m) => m.clone(),
                None => break,
            };

            enum Amount<T> {
                None,
                One(T),
                Multiple,
            }

            // Vector of absolute perfect matches
            let mut vones = Vec::new();

            // Look through each word in the message
            for word in &message.borrow().instances {
                let borrow = word.borrow();
                // Check each instance in that words instances
                for instance in &borrow.word.borrow().instances {
                    // Get the message for each instance
                    let omessage = instance.borrow().message.clone();
                    // Make sure we dont get the same message twice and assure the same length
                    if omessage != message &&
                        omessage.borrow().instances.len() == message.borrow().instances.len() {
                        // Find what kind of matches exist between the messages
                        if let Amount::One(best) = message.borrow().instances.iter()
                            .zip(omessage.borrow().instances.iter())
                            .fold(Amount::None, |acc, ws| {
                                let bs = (ws.0.borrow(), ws.1.borrow());
                                match acc {
                                    Amount::None => {
                                        if bs.0.word.borrow().name !=
                                            bs.1.word.borrow().name {
                                            Amount::One((ws.0.clone(), ws.1.clone()))
                                        } else {
                                            Amount::None
                                        }
                                    },
                                    Amount::One(best) => {
                                        if bs.0.word.borrow().name !=
                                            bs.1.word.borrow().name {
                                            Amount::Multiple
                                        } else {
                                            Amount::One(best)
                                        }
                                    },
                                    Amount::Multiple => Amount::Multiple,
                                }
                            }) {
                            vones.push(best);
                        }
                    }
                }
            }

            // Now that we have perfect matches, merge them into the same Category
            for ms in vones {
                // We only want to combine if they aren't already in the same category
                if ms.0.borrow().category != ms.1.borrow().category {
                    let cats = (ms.0.borrow().category.clone(), ms.1.borrow().category.clone());
                    Category::merge(cats);
                }
            }
        }
    }

    pub fn show_categories(&self) {
        use std::collections::BTreeSet;
        let mut set = BTreeSet::new();
        for message in &self.messages {
            for instance in &message.borrow().instances {
                let ib = instance.borrow();
                set.insert(&*ib.category.borrow() as *const Category);
            }
        }

        for cat in set {
            println!("Category:");
            let catr = unsafe{&*cat};
            for instance in &catr.instances {
                let ib = instance.borrow();
                println!("\t{}", ib.word.borrow().name);
            }
        }
    }
}

macro_rules! pointer_eq {
    ($s:ident) => {
        impl PartialEq for $s {
            fn eq(&self, other: &Self) -> bool {
                self as *const Self == other as *const Self
            }

            fn ne(&self, other: &Self) -> bool {
                self as *const Self != other as *const Self
            }
        }
    };
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

pointer_eq!(Conversation);

pub struct Author {
    source: SourceCell,
    name: String,
}

pointer_eq!(Author);

pub struct Source {
    name: String,
    messages: u64,
    authors: BTreeMap<String, AuthorCell>,
}

pointer_eq!(Source);

struct WordInstance {
    word: WordCell,
    category: CategoryCell,
    message: MessageCell,
    index: usize,
}

pointer_eq!(WordInstance);

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Message);

#[derive(Default)]
struct Category {
    instances: Vec<InstanceCell>,
    cocategories: Vec<CategoryCell>,
}

impl Category {
    fn merge(cs: (CategoryCell, CategoryCell)) -> CategoryCell {
        let cc = wrap(Self::default());
        {
            let clos = |cat: &CategoryCell| {
                for instance in cat.borrow().instances.iter().cloned() {
                    instance.borrow_mut().category = cc.clone();
                }
            };
            clos(&cs.0);
            clos(&cs.1);
            let mut ccm = cc.borrow_mut();
            ccm.instances.append(&mut cs.0.borrow_mut().instances);
            ccm.instances.append(&mut cs.1.borrow_mut().instances);
        }
        cc
    }
}

pointer_eq!(Category);

struct Word {
    name: String,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Word);
<commit_msg>allow category-based learning<commit_after>extern crate rand;
extern crate itertools;
use self::itertools::Itertools;

use std::collections::BTreeMap;
use std::collections::btree_map::Entry;
use std::rc::Rc;
use std::cell::RefCell;
use std::cell::Ref;
use std::sync::mpsc::Receiver;

type WordCell = Rc<RefCell<Word>>;
pub type AuthorCell = Rc<RefCell<Author>>;
pub type SourceCell = Rc<RefCell<Source>>;
type MessageCell = Rc<RefCell<Message>>;
type CategoryCell = Rc<RefCell<Category>>;
type ConversationCell = Rc<RefCell<Conversation>>;
type InstanceCell = Rc<RefCell<WordInstance>>;

enum Mismatch<T> {
    // Incompatible for matching or no mismatch (exactly the same)
    None,
    // Exactly one mismatch
    One(T),
    // Multiple mismatches
    Multiple,
}

fn wrap<T>(t: T) -> Rc<RefCell<T>> {
    Rc::new(RefCell::new(t))
}

// const RATIO_CONTAINED_BEFORE_COMBINATION: f64 = 0.8;

#[derive(Default)]
pub struct Lexicon<R: rand::Rng> {
    rng: R,
    words: BTreeMap<String, WordCell>,
    sources: BTreeMap<String, SourceCell>,
    conversations: Vec<ConversationCell>,
    messages: Vec<MessageCell>,

    active_conversations: BTreeMap<*const Source, ConversationCell>,
}

impl<R: rand::Rng> Lexicon<R> {
    pub fn new(rng: R) -> Lexicon<R> {
        Lexicon{
            rng: rng,
            words: Default::default(),
            sources: Default::default(),
            conversations: Default::default(),
            messages: Default::default(),
            active_conversations: Default::default(),
        }
    }

    pub fn source(&mut self, name: String) -> SourceCell {
        match self.sources.entry(name.clone()) {
            Entry::Vacant(v) => v.insert(wrap(Source{
                name: name,
                messages: 0,
                authors: BTreeMap::default(),
            })).clone(),
            Entry::Occupied(o) => o.get().clone(),
        }
    }

    pub fn author(&mut self, source: SourceCell, name: String) -> AuthorCell {
        match source.borrow_mut().authors.entry(name.clone()) {
            Entry::Vacant(v) => {
                let a = wrap(Author{
                    source: source.clone(),
                    name: name.clone(),
                });
                v.insert(a.clone());
                a
            },
            Entry::Occupied(o) => o.get().clone(),
        }
    }
    pub fn tell(&mut self, source: SourceCell, author: AuthorCell, content: String) -> Option<String> {
        let conversation = match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                let c = wrap(Conversation{
                    source: source.clone(),
                    messages: Vec::new(),
                });
                v.insert(c.clone());
                self.conversations.push(c.clone());
                c
            },
            Entry::Occupied(o) => {
                o.get().clone()
            },
        };

        let message = wrap(Message{
            author: author.clone(),
            conversation: conversation.clone(),
            index: conversation.borrow().messages.len(),
            instances: Vec::new(),
        });

        self.messages.push(message.clone());

        for word in content.split(' ').map(|s| {
            let string = s.to_string();
            match self.words.entry(string.clone()) {
                Entry::Vacant(v) => {
                    let w = wrap(Word{
                        name: string,
                        instances: Vec::new(),
                    });
                    v.insert(w.clone());
                    w
                },
                Entry::Occupied(o) => {
                    o.get().clone()
                },
            }
        }) {
            // Create empty category for the word
            let category = wrap(Category::default());
            // Create instance of the word
            let instance = wrap(WordInstance{
                word: word.clone(),
                category: category.clone(),
                message: message.clone(),
                index: message.borrow().instances.len(),
            });
            // Insert word instance into the word, category, and message for future reference
            message.borrow_mut().instances.push(instance.clone());
            category.borrow_mut().instances.push(instance.clone());
            word.borrow_mut().instances.push(instance);
        }

        // Increment the messages by 1 for the source
        source.borrow_mut().messages += 1;

        // TODO: Determine what to say back
        None
    }

    pub fn initiate(&mut self, source: SourceCell) -> Option<String> {
        let conversation = wrap(Conversation{
            source: source.clone(),
            messages: Vec::new(),
        });

        match self.active_conversations.entry(&*source.borrow() as *const Source) {
            Entry::Vacant(v) => {
                v.insert(conversation.clone());
            },
            Entry::Occupied(mut o) => {
                o.insert(conversation.clone());
            },
        };

        self.conversations.push(conversation.clone());

        let base = match self.rng.choose(&self.messages[..]) {
            Some(m) => m.clone(),
            None => return None,
        };

        let bborrow = base.borrow();

        Some(bborrow.instances.iter()
            .map(|instance| instance.borrow().category.clone())
            // TODO: Allow random choosing from co-category instances as well
            .map(|category| self.rng.choose(&category.borrow().instances[..]).unwrap().clone())
            .map(|instance| {
                let ins = instance.borrow();
                let word = ins.word.borrow();
                word.name.clone()
            })
            .join(" "))
    }

    pub fn think(&mut self, end: Receiver<()>) {
        use std::sync::mpsc::TryRecvError::Empty;
        while end.try_recv() == Err(Empty) {
            // Choose a random message or break if there are none
            let message = match self.rng.choose(&self.messages[..]) {
                Some(m) => m.clone(),
                None => break,
            };

            // Vector of absolute perfect matches
            let mut vones = Vec::new();

            // Look through each word in the message
            for word in &message.borrow().instances {
                let borrow = word.borrow();
                // Check each instance in that words instances
                for instance in &borrow.word.borrow().instances {
                    // Get the message for each instance
                    let omessage = instance.borrow().message.clone();
                    // Find what kind of matches exist between the messages
                    if let Mismatch::One(best) =
                        Message::category_and_word_mismatch((message.clone(), omessage.clone())) {
                        vones.push(best);
                    }
                }
            }

            // Now that we have perfect matches, merge them into the same Category
            for ms in vones {
                // We only want to combine if they aren't already in the same category
                if ms.0.borrow().category != ms.1.borrow().category {
                    let cats = (ms.0.borrow().category.clone(), ms.1.borrow().category.clone());
                    Category::merge(cats);
                }
            }
        }
    }

    pub fn show_categories(&self) {
        use std::collections::BTreeSet;
        let mut set = BTreeSet::new();
        for message in &self.messages {
            for instance in &message.borrow().instances {
                let ib = instance.borrow();
                set.insert(&*ib.category.borrow() as *const Category);
            }
        }

        for cat in set {
            println!("Category:");
            let catr = unsafe{&*cat};
            for instance in &catr.instances {
                let ib = instance.borrow();
                println!("\t{}", ib.word.borrow().name);
            }
        }
    }
}

macro_rules! pointer_eq {
    ($s:ident) => {
        impl PartialEq for $s {
            fn eq(&self, other: &Self) -> bool {
                self as *const Self == other as *const Self
            }

            fn ne(&self, other: &Self) -> bool {
                self as *const Self != other as *const Self
            }
        }
    };
}

struct Conversation {
    source: SourceCell,
    messages: Vec<MessageCell>,
}

pointer_eq!(Conversation);

pub struct Author {
    source: SourceCell,
    name: String,
}

pointer_eq!(Author);

pub struct Source {
    name: String,
    messages: u64,
    authors: BTreeMap<String, AuthorCell>,
}

pointer_eq!(Source);

struct WordInstance {
    word: WordCell,
    category: CategoryCell,
    message: MessageCell,
    index: usize,
}

pointer_eq!(WordInstance);

struct Message {
    author: AuthorCell,
    conversation: ConversationCell,
    index: usize,
    instances: Vec<InstanceCell>,
}

impl Message {
    fn mismatch<F>(messages: (MessageCell, MessageCell), diff: F) -> Mismatch<(InstanceCell, InstanceCell)>
        where F: Fn((&WordInstance, &WordInstance)) -> bool
    {
        if messages.0 == messages.1 ||
            messages.0.borrow().instances.len() != messages.1.borrow().instances.len() {
            return Mismatch::None;
        }
        messages.0.borrow().instances.iter()
            .zip(messages.1.borrow().instances.iter())
            .fold(Mismatch::None, |acc, ws| {
                let bs = (ws.0.borrow(), ws.1.borrow());
                match acc {
                    Mismatch::None => {
                        if diff((&*bs.0, &*bs.1)) {
                            Mismatch::One((ws.0.clone(), ws.1.clone()))
                        } else {
                            Mismatch::None
                        }
                    },
                    Mismatch::One(best) => {
                        if diff((&*bs.0, &*bs.1)) {
                            Mismatch::Multiple
                        } else {
                            Mismatch::One(best)
                        }
                    },
                    Mismatch::Multiple => Mismatch::Multiple,
                }
            })
    }
    /*fn category_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.category != ins.1.category)
    }

    fn word_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.word != ins.1.word)
    }*/

    fn category_and_word_mismatch(messages: (MessageCell, MessageCell)) ->
        Mismatch<(InstanceCell, InstanceCell)> {
        Self::mismatch(messages, |ins| ins.0.word != ins.1.word && ins.0.category != ins.1.category)
    }
}

pointer_eq!(Message);

#[derive(Default)]
struct Category {
    instances: Vec<InstanceCell>,
    cocategories: Vec<CategoryCell>,
}

impl Category {
    fn merge(cs: (CategoryCell, CategoryCell)) -> CategoryCell {
        let cc = wrap(Self::default());
        {
            let clos = |cat: &CategoryCell| {
                for instance in cat.borrow().instances.iter().cloned() {
                    instance.borrow_mut().category = cc.clone();
                }
            };
            clos(&cs.0);
            clos(&cs.1);
            let mut ccm = cc.borrow_mut();
            ccm.instances.append(&mut cs.0.borrow_mut().instances);
            ccm.instances.append(&mut cs.1.borrow_mut().instances);
        }
        cc
    }
}

pointer_eq!(Category);

struct Word {
    name: String,
    instances: Vec<InstanceCell>,
}

pointer_eq!(Word);
<|endoftext|>