<commit_before>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use python::{Python, PythonObject, ToPythonPointer};
use err::{self, PyResult};
use super::object::PyObject;
use ffi::{self, Py_ssize_t};
use conversion::{ToPyObject, ExtractPyObject};

/// Represents a Python `list`.
pub struct PyList<'p>(PyObject<'p>);

pyobject_newtype!(PyList, PyList_Check, PyList_Type);

impl <'p> PyList<'p> {
    /// Construct a new list with the given elements.
    pub fn new(py: Python<'p>, elements: &[PyObject<'p>]) -> PyList<'p> {
        unsafe {
            let ptr = ffi::PyList_New(elements.len() as Py_ssize_t);
            let t = err::result_from_owned_ptr(py, ptr).unwrap().unchecked_cast_into::<PyList>();
            for (i, e) in elements.iter().enumerate() {
                ffi::PyList_SetItem(ptr, i as Py_ssize_t, e.clone().steal_ptr());
            }
            t
        }
    }

    /// Gets the length of the list.
    #[inline]
    pub fn len(&self) -> usize {
        // non-negative Py_ssize_t should always fit into Rust usize
        unsafe {
            ffi::PyList_Size(self.as_ptr()) as usize
        }
    }

    /// Gets the item at the specified index.
    ///
    /// Panics if the index is out of range.
    pub fn get_item(&self, index: usize) -> PyObject<'p> {
        assert!(index < self.len());
        unsafe {
            PyObject::from_borrowed_ptr(self.python(), ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t))
        }
    }

    /// Sets the item at the specified index.
    ///
    /// Panics if the index is out of range.
    pub fn set_item(&self, index: usize, item: PyObject<'p>) {
        let r = unsafe { ffi::PyList_SetItem(self.as_ptr(), index as Py_ssize_t, item.steal_ptr()) };
        assert!(r == 0);
    }

    /// Inserts an item at the specified index.
    ///
    /// Panics if the index is out of range.
    pub fn insert_item(&self, index: usize, item: PyObject<'p>) {
        let r = unsafe { ffi::PyList_Insert(self.as_ptr(), index as Py_ssize_t, item.as_ptr()) };
        assert!(r == 0);
    }
}

impl <'p> IntoIterator for PyList<'p> {
    type Item = PyObject<'p>;
    type IntoIter = PyListIterator<'p>;

    #[inline]
    fn into_iter(self) -> PyListIterator<'p> {
        PyListIterator { list: self, index: 0 }
    }
}

impl <'a, 'p> IntoIterator for &'a PyList<'p> {
    type Item = PyObject<'p>;
    type IntoIter = PyListIterator<'p>;

    #[inline]
    fn into_iter(self) -> PyListIterator<'p> {
        PyListIterator { list: self.clone(), index: 0 }
    }
}

/// Used by `impl IntoIterator for &PyList`.
pub struct PyListIterator<'p> {
    list: PyList<'p>,
    index: usize
}

impl <'p> Iterator for PyListIterator<'p> {
    type Item = PyObject<'p>;

    #[inline]
    fn next(&mut self) -> Option<PyObject<'p>> {
        if self.index < self.list.len() {
            let item = self.list.get_item(self.index);
            self.index += 1;
            Some(item)
        } else {
            None
        }
    }

    // Note: we cannot implement size_hint because the length of the list
    // might change during the iteration.
}

impl <'p, T> ToPyObject<'p> for [T] where T: ToPyObject<'p> {
    type ObjectType = PyList<'p>;

    fn to_py_object(&self, py: Python<'p>) -> PyList<'p> {
        unsafe {
            let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
            let t = err::cast_from_owned_ptr_or_panic(py, ptr);
            for (i, e) in self.iter().enumerate() {
                let obj = e.to_py_object(py);
                ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj.steal_ptr());
            }
            t
        }
    }
}

impl <'python, 'source, 'prepared, T> ExtractPyObject<'python, 'source, 'prepared>
    for Vec<T>
    where T: for<'s, 'p> ExtractPyObject<'python, 's, 'p>,
          'python : 'source
{

    type Prepared = &'source PyObject<'python>;

    #[inline]
    fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> {
        Ok(obj)
    }

    #[inline]
    fn extract(&obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, Vec<T>> {
        let list = try!(obj.cast_as::<PyList>());
        let mut v = Vec::with_capacity(list.len());
        for i in 0 .. list.len() {
            v.push(try!(list.get_item(i).extract::<T>()));
        }
        Ok(v)
    }
}

<commit_msg>Add tests for list.rs. Still missing tests for extract.<commit_after>// Copyright (c) 2015 Daniel Grunwald
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.

use python::{Python, PythonObject, ToPythonPointer};
use err::{self, PyResult};
use super::object::PyObject;
use ffi::{self, Py_ssize_t};
use conversion::{ToPyObject, ExtractPyObject};

/// Represents a Python `list`.
pub struct PyList<'p>(PyObject<'p>);

pyobject_newtype!(PyList, PyList_Check, PyList_Type);

impl <'p> PyList<'p> {
    /// Construct a new list with the given elements.
    pub fn new(py: Python<'p>, elements: &[PyObject<'p>]) -> PyList<'p> {
        unsafe {
            let ptr = ffi::PyList_New(elements.len() as Py_ssize_t);
            let t = err::result_from_owned_ptr(py, ptr).unwrap().unchecked_cast_into::<PyList>();
            for (i, e) in elements.iter().enumerate() {
                ffi::PyList_SetItem(ptr, i as Py_ssize_t, e.clone().steal_ptr());
            }
            t
        }
    }

    /// Gets the length of the list.
    #[inline]
    pub fn len(&self) -> usize {
        // non-negative Py_ssize_t should always fit into Rust usize
        unsafe {
            ffi::PyList_Size(self.as_ptr()) as usize
        }
    }

    /// Gets the item at the specified index.
    ///
    /// Panics if the index is out of range.
    pub fn get_item(&self, index: usize) -> PyObject<'p> {
        assert!(index < self.len());
        unsafe {
            PyObject::from_borrowed_ptr(self.python(), ffi::PyList_GetItem(self.as_ptr(), index as Py_ssize_t))
        }
    }

    /// Sets the item at the specified index.
    ///
    /// Panics if the index is out of range.
    pub fn set_item(&self, index: usize, item: PyObject<'p>) {
        let r = unsafe { ffi::PyList_SetItem(self.as_ptr(), index as Py_ssize_t, item.steal_ptr()) };
        assert!(r == 0);
    }

    /// Inserts an item at the specified index.
    ///
    /// Panics if the index is out of range.
    pub fn insert_item(&self, index: usize, item: PyObject<'p>) {
        let r = unsafe { ffi::PyList_Insert(self.as_ptr(), index as Py_ssize_t, item.as_ptr()) };
        assert!(r == 0);
    }
}

impl <'p> IntoIterator for PyList<'p> {
    type Item = PyObject<'p>;
    type IntoIter = PyListIterator<'p>;

    #[inline]
    fn into_iter(self) -> PyListIterator<'p> {
        PyListIterator { list: self, index: 0 }
    }
}

impl <'a, 'p> IntoIterator for &'a PyList<'p> {
    type Item = PyObject<'p>;
    type IntoIter = PyListIterator<'p>;

    #[inline]
    fn into_iter(self) -> PyListIterator<'p> {
        PyListIterator { list: self.clone(), index: 0 }
    }
}

/// Used by `impl IntoIterator for &PyList`.
pub struct PyListIterator<'p> {
    list: PyList<'p>,
    index: usize
}

impl <'p> Iterator for PyListIterator<'p> {
    type Item = PyObject<'p>;

    #[inline]
    fn next(&mut self) -> Option<PyObject<'p>> {
        if self.index < self.list.len() {
            let item = self.list.get_item(self.index);
            self.index += 1;
            Some(item)
        } else {
            None
        }
    }

    // Note: we cannot implement size_hint because the length of the list
    // might change during the iteration.
}

impl <'p, T> ToPyObject<'p> for [T] where T: ToPyObject<'p> {
    type ObjectType = PyList<'p>;

    fn to_py_object(&self, py: Python<'p>) -> PyList<'p> {
        unsafe {
            let ptr = ffi::PyList_New(self.len() as Py_ssize_t);
            let t = err::cast_from_owned_ptr_or_panic(py, ptr);
            for (i, e) in self.iter().enumerate() {
                let obj = e.to_py_object(py);
                ffi::PyList_SetItem(ptr, i as Py_ssize_t, obj.steal_ptr());
            }
            t
        }
    }
}

impl <'python, 'source, 'prepared, T> ExtractPyObject<'python, 'source, 'prepared>
    for Vec<T>
    where T: for<'s, 'p> ExtractPyObject<'python, 's, 'p>,
          'python : 'source
{

    type Prepared = &'source PyObject<'python>;

    #[inline]
    fn prepare_extract(obj: &'source PyObject<'python>) -> PyResult<'python, Self::Prepared> {
        Ok(obj)
    }

    #[inline]
    fn extract(&obj: &'prepared &'source PyObject<'python>) -> PyResult<'python, Vec<T>> {
        let list = try!(obj.cast_as::<PyList>());
        let mut v = Vec::with_capacity(list.len());
        for i in 0 .. list.len() {
            v.push(try!(list.get_item(i).extract::<T>()));
        }
        Ok(v)
    }
}

#[cfg(test)]
mod test {
    use std;
    use python::{Python, PythonObject};
    use conversion::ToPyObject;
    use objects::PyList;

    #[test]
    fn test_len() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        let v = vec![1,2,3,4];
        let list = v.to_py_object(py).into_object().cast_into::<PyList>().unwrap();
        assert_eq!(4, list.len());
    }

    #[test]
    fn test_get_item() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        let v = vec![2, 3, 5, 7];
        let list = v.to_py_object(py).into_object().cast_into::<PyList>().unwrap();
        assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
        assert_eq!(3, list.get_item(1).extract::<i32>().unwrap());
        assert_eq!(5, list.get_item(2).extract::<i32>().unwrap());
        assert_eq!(7, list.get_item(3).extract::<i32>().unwrap());
    }

    #[test]
    fn test_set_item() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        let v = vec![2, 3, 5, 7];
        let list = v.to_py_object(py).into_object().cast_into::<PyList>().unwrap();
        let val = 42i32.to_py_object(py).into_object();
        assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
        list.set_item(0, val);
        assert_eq!(42, list.get_item(0).extract::<i32>().unwrap());
    }

    #[test]
    fn test_insert_item() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        let v = vec![2, 3, 5, 7];
        let list = v.to_py_object(py).into_object().cast_into::<PyList>().unwrap();
        let val = 42i32.to_py_object(py).into_object();
        assert_eq!(4, list.len());
        assert_eq!(2, list.get_item(0).extract::<i32>().unwrap());
        list.insert_item(0, val);
        assert_eq!(5, list.len());
        assert_eq!(42, list.get_item(0).extract::<i32>().unwrap());
        assert_eq!(2, list.get_item(1).extract::<i32>().unwrap());
    }

    #[test]
    fn test_iter() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        let v = vec![2, 3, 5, 7];
        let list = v.to_py_object(py).into_object().cast_into::<PyList>().unwrap();
        let mut idx = 0;
        for el in list {
            assert_eq!(v[idx], el.extract::<i32>().unwrap());
            idx += 1;
        }
        assert_eq!(idx, v.len());
    }

    #[test]
    fn test_into_iter() {
        let gil = Python::acquire_gil();
        let py = gil.python();
        let v = vec![2, 3, 5, 7];
        let list = v.to_py_object(py).into_object().cast_into::<PyList>().unwrap();
        let mut idx = 0;
        for el in list.into_iter() {
            assert_eq!(v[idx], el.extract::<i32>().unwrap());
            idx += 1;
        }
        assert_eq!(idx, v.len());
    }
}
<|endoftext|>


<commit_before>pub struct Filled {
    filler: String,
    height: usize,
    width: usize,
}

impl Filled {
    pub fn new(width: usize, height: usize, filler: &str) -> Self {
        let filler = filler.to_string();

        Filled {
            filler,
            height,
            width
        }
    }

    pub fn blank(width: usize, height: usize) -> Self {
        Self::new(width, height, " ")
    }

    pub fn render(&self) -> String {
        let mut s = String::new();

        for r in 0..self.height {
            for c in 0..self.width {
                s += &self.filler;

            }
            if r != self.height - 1 {
                s += "\n";
            }
        }

        s
    }
}
<commit_msg>Add `Border` figure<commit_after>use stamp::Stamp;

pub struct Filled {
    filler: String,
    height: usize,
    width: usize,
}

impl Filled {
    pub fn new(width: usize, height: usize, filler: &str) -> Self {
        let filler = filler.to_string();

        Filled {
            filler,
            height,
            width
        }
    }

    pub fn blank(width: usize, height: usize) -> Self {
        Self::new(width, height, " ")
    }

    pub fn render(&self) -> String {
        let mut s = String::new();

        for r in 0..self.height {
            for c in 0..self.width {
                s += &self.filler;

            }
            if r != self.height - 1 {
                s += "\n";
            }
        }

        s
    }
}

pub struct BorderChars {
    left: &'static str,
    bottom_left: &'static str,
    bottom: &'static str,
    bottom_right: &'static str,
    right: &'static str,
    top_left: &'static str,
    top: &'static str,
    top_right: &'static str,
}

pub const ASCII_BORDER: BorderChars = BorderChars {
    left: "|",
    bottom_left: "+",
    bottom: "-",
    bottom_right: "+",
    right: "|",
    top_left: "+",
    top: "-",
    top_right: "+",
};

pub const UNICODE_BORDER: BorderChars = BorderChars {
    left: "│",
    bottom_left: "└",
    bottom: "─",
    bottom_right: "┘",
    right: "│",
    top_left: "┌",
    top: "─",
    top_right: "┐",
};

pub struct Border {
    chars: BorderChars,
    height: usize,
    width: usize,
}

impl Border {
    pub fn new(chars: BorderChars, width: usize, height: usize) -> Self {
        Border {
            chars,
            height,
            width,
        }
    }

    pub fn render(&self) -> String {
        self.render_checked().unwrap()
    }

    fn render_checked(&self) -> Result<String, ()> {
        let filled = Stamp::new(&Filled::blank(self.width, self.height).render())?;

        let bottom_left = Stamp::new(self.chars.bottom_left)?;
        let bottom_right = Stamp::new(self.chars.bottom_right)?;
        let top_left = Stamp::new(self.chars.top_left)?;
        let top_right = Stamp::new(self.chars.top_right)?;

        let bottom = Stamp::new(&self.render_bottom())?;
        let left = Stamp::new(&self.render_left())?;
        let right = Stamp::new(&self.render_right())?;
        let top = Stamp::new(&self.render_top())?;

        let layered = filled
            .layer(&top_left, 0, 0)?
            .layer(&top, 1, 0)?
            .layer(&top_right, self.width - 1, 0)?
            .layer(&right, self.width - 1, 1)?
            .layer(&bottom_right, self.width - 1, self.height - 1)?
            .layer(&bottom, 1, self.height - 1)?
            .layer(&bottom_left, 0, self.height - 1)?
            .layer(&left, 0, 1)?;

        Ok(layered.render())
    }

    fn render_bottom(&self) -> String {
        render_horizontal_line(self.chars.bottom, self.width - 2)
    }

    fn render_left(&self) -> String {
        render_vertical_line(self.chars.left, self.height - 2)
    }

    fn render_right(&self) -> String {
        render_vertical_line(self.chars.right, self.height - 2)
    }

    fn render_top(&self) -> String {
        render_horizontal_line(self.chars.top, self.width - 2)
    }
}

fn render_horizontal_line(c: &str, size: usize) -> String {
    use std::iter::{FromIterator, repeat};

    String::from_iter(repeat(c.to_string()).take(size))
}

fn render_vertical_line(c: &str, size: usize) -> String {
    let mut s = String::new();

    for i in 0..size {
        s += c;

        if i != size - 1 {
            s += "\n";
        }
    }

    s
}
<|endoftext|>


<commit_before>//!Contains traits and methods for the operation of particle physics

pub mod basic_particle;
pub use self::basic_particle::*;

extern crate num;
use self::num::Float;
use super::vector::*;

///An object that has quanta
pub trait Quanta<D> {
    //Retrieve the quanta of a physics particle.
    fn quanta(&self) -> D;
}

///An object that has inertia
pub trait Inertia<D> {
    //Retrieve the inertia of a physics particle.
    fn inertia(&self) -> D;
}

///An object that has location
pub trait Position<V> {
    //Get position of particle.
    fn position(&self) -> V;
}

///An object that has velocity
pub trait Velocity<V> {
    //Get velocity of particle.
    fn velocity(&self) -> V;
}

///An object that has a simple particle motion interface
pub trait Particle<V, D>: Position<V> + Velocity<V> + Inertia<D> {
    ///Apply force to particle, but it isn't moved forward in time until advance is called.
    ///This requires interior mutability and unsafe declarations to fulfil.
    fn impulse(&self, vec: &V);
    ///Advance particle forward in time (update position and velocity from net force).
    fn advance(&mut self, time: D);
}

///Any particle that implements the necessary traits gains access to all of the capabilities of PhysicsParticle.
pub trait PhysicsParticle<V, D>: Particle<V, D> + Quanta<D> + Inertia<D>
    where V: Vector<D>, D: Float
{
    ///Convert a PhysicsParticle into a "basic particle" that implements PhysicsParticle but has the minimum members.
    ///Use this to implement data structures that need to create intermediary particles.
    fn basic_form(&self) -> BasicParticle<V, D> {
        BasicParticle::new(self.quanta(), self.position(), self.velocity(), self.inertia())
    }

    ///Apply drag forces to a particle.
    fn drag(&self, magnitude: D) {
        let force = -self.velocity() * magnitude;
        self.impulse(&force);
    }

    ///Apply proper attraction to a single physics particle towards a location and with a magnitude.
    fn gravitate_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where T: Quanta<D> + Position<V>
    {
        //Create delta vector from the particle to the center of attraction.
        let delta = center.position() - self.position();
        let distance = delta.displacement();
        if distance.is_normal() {
            let force = delta / distance.powi(3) * magnitude * self.quanta() * center.quanta();
            self.impulse(&force);
        }
    }

    ///This works the same as gravitate_radius_squared and gravitate_to.
    fn gravitate_radius_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where T: Quanta<D> + Position<V> + Ball<D>
    {
        //Create delta vector from the particle to the center of attraction.
        let delta = center.position() - self.position();
        let distance_squared = delta.displacement_squared();
        if distance_squared.is_normal() {
            let force = delta * magnitude * self.quanta() * center.quanta() /
                if distance_squared > center.radius().powi(2) {
                    distance_squared.sqrt().powi(3)
                } else {
                    center.radius().powi(2)
                };
            self.impulse(&force);
        }
    }

    ///Apply spring forces between one particle and a virtual particle that is unaffected.
    fn hooke_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where T: Quanta<D> + Position<V>
    {
        let delta = center.position() - self.position();
        let force = delta * magnitude * self.quanta() * center.quanta();
        self.impulse(&force);
    }

    ///Apply spring forces between one particle and a virtual particle that is unaffected.
    fn hooke_equilibrium_to<T: ?Sized>(&self, center: &T, equilibrium: D, magnitude: D)
        where T: Quanta<D> + Position<V>
    {
        let delta = center.position() - self.position();
        let displace = delta.displacement();
        if displace.is_normal() {
            let force = delta / displace * (displace - equilibrium) *
                magnitude * self.quanta() * center.quanta();
            self.impulse(&force);
        }
    }

    ///Apply lorentz force to a particle in a field given by a vector with the magnitude and direction of the field.
    fn lorentz_field(&self, field: &V)
        where V: CrossVector
    {
        let force = V::cross(&self.velocity(), field) * self.quanta() / self.inertia();
        self.impulse(&force);
    }

    ///Apply the lorentz force on a virtual particle that is unaffected.
    fn lorentz_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where V: CrossVector, T: Quanta<D> + Position<V> + Velocity<V>
    {
        let delta = center.position() - self.position();
        let distance_squared = delta.displacement_squared();
        if distance_squared.is_normal() {
            let force = V::cross(&V::cross(&self.velocity(), &delta), &center.velocity()) * magnitude *
                self.quanta() * center.quanta() / distance_squared.sqrt().powi(3);

            self.impulse(&force);
        }
    }

    ///Apply the lorentz force on a virtual particle that is unaffected.
    fn lorentz_radius_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where V: CrossVector, T: Quanta<D> + Position<V> + Velocity<V> + Ball<D>
    {
        let delta = center.position() - self.position();
        let distance_squared = delta.displacement_squared();
        if distance_squared.is_normal() {
            let force = V::cross(&V::cross(&self.velocity(), &delta), &center.velocity()) * magnitude *
                self.quanta() * center.quanta() /
                if distance_squared > center.radius().powi(2) {
                    distance_squared.sqrt().powi(3)
                } else {
                    center.radius().powi(2)
                };

            self.impulse(&force);
        }
    }
}

///Apply proper attraction between two physics particles based on their quanta and position.
pub fn gravitate<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D>, D: Float
{
    //Create delta vector between the two positions.
    let delta = rhs.position() - lhs.position();
    //Find the distance of the delta vector.
    let distance = delta.displacement();
    if distance.is_normal() {
        //Dividing the delta vector by the distance cubed computes attractive force as per the inverse square law.
        //The extra degree normalizes the direction vector to a unit vector.
        let force = delta * magnitude / distance.powi(3) *
        //Multiply by the two quanta of the objects to compute the final force.
        lhs.quanta() * rhs.quanta();

        //Force lhs in the direction of force.
        lhs.impulse(&force);
        //Apply the inverse force to the rhs similarly.
        rhs.impulse(&-force);
    }
}

#[test]
fn gravitate_test() {
    type P = BasicParticle<Cartesian3<f64>, f64>;
    let mut a = P::default();
    let mut b = P::default();
    gravitate(&a, &b, 1.0);
    a.advance(1.0);
    b.advance(1.0);
}

///If gravitating at a distance greater than the net radius, then gravitational interaction is applied as if the
///particles are point particles. If the distance is less than the radius, then the interaction happens as if the
///gravitational quanta (mass) is evenly distributed and gravitational flux is used instead, which causes the
///interaction to become proportional to the radius, meaning that as the radius approaches zero, so does the force.
pub fn gravitate_radius<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D> + Ball<D>, T2: PhysicsParticle<V, D> + Ball<D>, V: Vector<D>, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance_squared = delta.displacement_squared();
    if distance_squared.is_normal() {
        let radius_squared = (lhs.radius() + rhs.radius()).powi(2);
        //Force is the only thing that changes from normal gravitation.
        let force = delta * magnitude * lhs.quanta() * rhs.quanta() / if distance_squared > radius_squared {
            distance_squared.sqrt().powi(3)
        } else {
            radius_squared
        };
        lhs.impulse(&force);
        rhs.impulse(&-force);
    }
}

///This is the same as the radius function, but the sum of the radii squared is passed separately to avoid overhead.
pub fn gravitate_radius_squared<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, radius_squared: D, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D>, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance_squared = delta.displacement_squared();
    if distance_squared.is_normal() {
        //Force is the only thing that changes from normal gravitation.
        let force = delta * magnitude * lhs.quanta() * rhs.quanta() / if distance_squared > radius_squared {
            distance_squared.sqrt().powi(3)
        } else {
            radius_squared
        };
        lhs.impulse(&force);
        rhs.impulse(&-force);
    }
}

///Apply spring forces between two particles.
pub fn hooke<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D>, D: Float
{
    let delta = rhs.position() - lhs.position();
    let force = delta * magnitude * lhs.quanta() * rhs.quanta();
    lhs.impulse(&force);
    rhs.impulse(&-force);
}

#[test]
fn hooke_test() {
    type P = BasicParticle<Cartesian3<f64>, f64>;
    let mut a = P::default();
    let mut b = P::default();
    hooke(&a, &b, 1.0);
    a.advance(1.0);
    b.advance(1.0);
}

///Apply spring forces between two particles with specified equilibrium distance.
pub fn hooke_equilibrium<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, equilibrium: D, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D>, D: Float
{
    let delta = rhs.position() - lhs.position();
    let displace = delta.displacement();
    if displace.is_normal() {
        let force = delta / displace * magnitude *
            //We scale such that if displacement is greater than equilibrium, the particles attract proportionally.
            //Particles with a displacement smaller than equilibrium repel each other.
            (displace - equilibrium) *
            lhs.quanta() * rhs.quanta();
        lhs.impulse(&force);
        rhs.impulse(&-force);
    }
}

///Apply lorentz forces between two PhysicsParticle objects based on quanta, position, and velocity.
pub fn lorentz<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D> + CrossVector, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance = delta.displacement();
    if distance.is_normal() {
        let force = V::cross(&rhs.velocity(), &V::cross(&lhs.velocity(), &delta)) *
            lhs.quanta() * rhs.quanta() / distance.powi(3) * magnitude;

        lhs.impulse(&-force);
        rhs.impulse(&force);
    }
}

#[test]
fn lorentz_test() {
    type P = BasicParticle<Cartesian3<f64>, f64>;
    let mut a = P::default();
    let mut b = P::default();
    lorentz(&a, &b, 1.0);
    a.advance(1.0);
    b.advance(1.0);
}

///Apply lorentz forces between two PhysicsParticle + Ball objects assuming uniformly distributed quanta.
pub fn lorentz_radius<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D> + Ball<D>, T2: PhysicsParticle<V, D> + Ball<D>, V: Vector<D> + CrossVector, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance_squared = delta.displacement_squared();
    if distance_squared.is_normal() {
        let radius_squared = (lhs.radius() + rhs.radius()).powi(2);
        let force = V::cross(&rhs.velocity(), &V::cross(&lhs.velocity(), &delta)) * magnitude *
            lhs.quanta() * rhs.quanta() /
            if distance_squared > radius_squared {
                distance_squared.sqrt().powi(3)
            } else {
                radius_squared
            };

        lhs.impulse(&-force);
        rhs.impulse(&force);
    }
}

///Apply lorentz forces between two PhysicsParticle objects using a precomputed net radius.
pub fn lorentz_radius_squared<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, radius_squared: D, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D> + CrossVector, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance_squared = delta.displacement_squared();
    if distance_squared.is_normal() {
        let force = V::cross(&rhs.velocity(), &V::cross(&lhs.velocity(), &delta)) * magnitude *
            lhs.quanta() * rhs.quanta() /
            if distance_squared > radius_squared {
                distance_squared.sqrt().powi(3)
            } else {
                radius_squared
            };

        lhs.impulse(&-force);
        rhs.impulse(&force);
    }
}
<commit_msg>fix particle module not being documented<commit_after>///!Contains traits and methods for the operation of particle physics

pub mod basic_particle;
pub use self::basic_particle::*;

extern crate num;
use self::num::Float;
use super::vector::*;

///An object that has quanta
pub trait Quanta<D> {
    //Retrieve the quanta of a physics particle.
    fn quanta(&self) -> D;
}

///An object that has inertia
pub trait Inertia<D> {
    //Retrieve the inertia of a physics particle.
    fn inertia(&self) -> D;
}

///An object that has location
pub trait Position<V> {
    //Get position of particle.
    fn position(&self) -> V;
}

///An object that has velocity
pub trait Velocity<V> {
    //Get velocity of particle.
    fn velocity(&self) -> V;
}

///An object that has a simple particle motion interface
pub trait Particle<V, D>: Position<V> + Velocity<V> + Inertia<D> {
    ///Apply force to particle, but it isn't moved forward in time until advance is called.
    ///This requires interior mutability and unsafe declarations to fulfil.
    fn impulse(&self, vec: &V);
    ///Advance particle forward in time (update position and velocity from net force).
    fn advance(&mut self, time: D);
}

///Any particle that implements the necessary traits gains access to all of the capabilities of PhysicsParticle.
pub trait PhysicsParticle<V, D>: Particle<V, D> + Quanta<D> + Inertia<D>
    where V: Vector<D>, D: Float
{
    ///Convert a PhysicsParticle into a "basic particle" that implements PhysicsParticle but has the minimum members.
    ///Use this to implement data structures that need to create intermediary particles.
    fn basic_form(&self) -> BasicParticle<V, D> {
        BasicParticle::new(self.quanta(), self.position(), self.velocity(), self.inertia())
    }

    ///Apply drag forces to a particle.
    fn drag(&self, magnitude: D) {
        let force = -self.velocity() * magnitude;
        self.impulse(&force);
    }

    ///Apply proper attraction to a single physics particle towards a location and with a magnitude.
    fn gravitate_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where T: Quanta<D> + Position<V>
    {
        //Create delta vector from the particle to the center of attraction.
        let delta = center.position() - self.position();
        let distance = delta.displacement();
        if distance.is_normal() {
            let force = delta / distance.powi(3) * magnitude * self.quanta() * center.quanta();
            self.impulse(&force);
        }
    }

    ///This works the same as gravitate_radius_squared and gravitate_to.
    fn gravitate_radius_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where T: Quanta<D> + Position<V> + Ball<D>
    {
        //Create delta vector from the particle to the center of attraction.
        let delta = center.position() - self.position();
        let distance_squared = delta.displacement_squared();
        if distance_squared.is_normal() {
            let force = delta * magnitude * self.quanta() * center.quanta() /
                if distance_squared > center.radius().powi(2) {
                    distance_squared.sqrt().powi(3)
                } else {
                    center.radius().powi(2)
                };
            self.impulse(&force);
        }
    }

    ///Apply spring forces between one particle and a virtual particle that is unaffected.
    fn hooke_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where T: Quanta<D> + Position<V>
    {
        let delta = center.position() - self.position();
        let force = delta * magnitude * self.quanta() * center.quanta();
        self.impulse(&force);
    }

    ///Apply spring forces between one particle and a virtual particle that is unaffected.
    fn hooke_equilibrium_to<T: ?Sized>(&self, center: &T, equilibrium: D, magnitude: D)
        where T: Quanta<D> + Position<V>
    {
        let delta = center.position() - self.position();
        let displace = delta.displacement();
        if displace.is_normal() {
            let force = delta / displace * (displace - equilibrium) *
                magnitude * self.quanta() * center.quanta();
            self.impulse(&force);
        }
    }

    ///Apply lorentz force to a particle in a field given by a vector with the magnitude and direction of the field.
    fn lorentz_field(&self, field: &V)
        where V: CrossVector
    {
        let force = V::cross(&self.velocity(), field) * self.quanta() / self.inertia();
        self.impulse(&force);
    }

    ///Apply the lorentz force on a virtual particle that is unaffected.
    fn lorentz_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where V: CrossVector, T: Quanta<D> + Position<V> + Velocity<V>
    {
        let delta = center.position() - self.position();
        let distance_squared = delta.displacement_squared();
        if distance_squared.is_normal() {
            let force = V::cross(&V::cross(&self.velocity(), &delta), &center.velocity()) * magnitude *
                self.quanta() * center.quanta() / distance_squared.sqrt().powi(3);

            self.impulse(&force);
        }
    }

    ///Apply the lorentz force on a virtual particle that is unaffected.
    fn lorentz_radius_to<T: ?Sized>(&self, center: &T, magnitude: D)
        where V: CrossVector, T: Quanta<D> + Position<V> + Velocity<V> + Ball<D>
    {
        let delta = center.position() - self.position();
        let distance_squared = delta.displacement_squared();
        if distance_squared.is_normal() {
            let force = V::cross(&V::cross(&self.velocity(), &delta), &center.velocity()) * magnitude *
                self.quanta() * center.quanta() /
                if distance_squared > center.radius().powi(2) {
                    distance_squared.sqrt().powi(3)
                } else {
                    center.radius().powi(2)
                };

            self.impulse(&force);
        }
    }
}

///Apply proper attraction between two physics particles based on their quanta and position.
pub fn gravitate<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D>, D: Float
{
    //Create delta vector between the two positions.
    let delta = rhs.position() - lhs.position();
    //Find the distance of the delta vector.
    let distance = delta.displacement();
    if distance.is_normal() {
        //Dividing the delta vector by the distance cubed computes attractive force as per the inverse square law.
        //The extra degree normalizes the direction vector to a unit vector.
        let force = delta * magnitude / distance.powi(3) *
        //Multiply by the two quanta of the objects to compute the final force.
        lhs.quanta() * rhs.quanta();

        //Force lhs in the direction of force.
        lhs.impulse(&force);
        //Apply the inverse force to the rhs similarly.
        rhs.impulse(&-force);
    }
}

#[test]
fn gravitate_test() {
    type P = BasicParticle<Cartesian3<f64>, f64>;
    let mut a = P::default();
    let mut b = P::default();
    gravitate(&a, &b, 1.0);
    a.advance(1.0);
    b.advance(1.0);
}

///If gravitating at a distance greater than the net radius, then gravitational interaction is applied as if the
///particles are point particles. If the distance is less than the radius, then the interaction happens as if the
///gravitational quanta (mass) is evenly distributed and gravitational flux is used instead, which causes the
///interaction to become proportional to the radius, meaning that as the radius approaches zero, so does the force.
pub fn gravitate_radius<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D> + Ball<D>, T2: PhysicsParticle<V, D> + Ball<D>, V: Vector<D>, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance_squared = delta.displacement_squared();
    if distance_squared.is_normal() {
        let radius_squared = (lhs.radius() + rhs.radius()).powi(2);
        //Force is the only thing that changes from normal gravitation.
        let force = delta * magnitude * lhs.quanta() * rhs.quanta() / if distance_squared > radius_squared {
            distance_squared.sqrt().powi(3)
        } else {
            radius_squared
        };
        lhs.impulse(&force);
        rhs.impulse(&-force);
    }
}

///This is the same as the radius function, but the sum of the radii squared is passed separately to avoid overhead.
pub fn gravitate_radius_squared<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, radius_squared: D, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D>, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance_squared = delta.displacement_squared();
    if distance_squared.is_normal() {
        //Force is the only thing that changes from normal gravitation.
        let force = delta * magnitude * lhs.quanta() * rhs.quanta() / if distance_squared > radius_squared {
            distance_squared.sqrt().powi(3)
        } else {
            radius_squared
        };
        lhs.impulse(&force);
        rhs.impulse(&-force);
    }
}

///Apply spring forces between two particles.
pub fn hooke<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D>, D: Float
{
    let delta = rhs.position() - lhs.position();
    let force = delta * magnitude * lhs.quanta() * rhs.quanta();
    lhs.impulse(&force);
    rhs.impulse(&-force);
}

#[test]
fn hooke_test() {
    type P = BasicParticle<Cartesian3<f64>, f64>;
    let mut a = P::default();
    let mut b = P::default();
    hooke(&a, &b, 1.0);
    a.advance(1.0);
    b.advance(1.0);
}

///Apply spring forces between two particles with specified equilibrium distance.
pub fn hooke_equilibrium<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, equilibrium: D, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D>, D: Float
{
    let delta = rhs.position() - lhs.position();
    let displace = delta.displacement();
    if displace.is_normal() {
        let force = delta / displace * magnitude *
            //We scale such that if displacement is greater than equilibrium, the particles attract proportionally.
            //Particles with a displacement smaller than equilibrium repel each other.
            (displace - equilibrium) *
            lhs.quanta() * rhs.quanta();
        lhs.impulse(&force);
        rhs.impulse(&-force);
    }
}

///Apply lorentz forces between two PhysicsParticle objects based on quanta, position, and velocity.
pub fn lorentz<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D> + CrossVector, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance = delta.displacement();
    if distance.is_normal() {
        let force = V::cross(&rhs.velocity(), &V::cross(&lhs.velocity(), &delta)) *
            lhs.quanta() * rhs.quanta() / distance.powi(3) * magnitude;

        lhs.impulse(&-force);
        rhs.impulse(&force);
    }
}

#[test]
fn lorentz_test() {
    type P = BasicParticle<Cartesian3<f64>, f64>;
    let mut a = P::default();
    let mut b = P::default();
    lorentz(&a, &b, 1.0);
    a.advance(1.0);
    b.advance(1.0);
}

///Apply lorentz forces between two PhysicsParticle + Ball objects assuming uniformly distributed quanta.
pub fn lorentz_radius<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, magnitude: D)
    where T1: PhysicsParticle<V, D> + Ball<D>, T2: PhysicsParticle<V, D> + Ball<D>, V: Vector<D> + CrossVector, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance_squared = delta.displacement_squared();
    if distance_squared.is_normal() {
        let radius_squared = (lhs.radius() + rhs.radius()).powi(2);
        let force = V::cross(&rhs.velocity(), &V::cross(&lhs.velocity(), &delta)) * magnitude *
            lhs.quanta() * rhs.quanta() /
            if distance_squared > radius_squared {
                distance_squared.sqrt().powi(3)
            } else {
                radius_squared
            };

        lhs.impulse(&-force);
        rhs.impulse(&force);
    }
}

///Apply lorentz forces between two PhysicsParticle objects using a precomputed net radius.
pub fn lorentz_radius_squared<V, D, T1: ?Sized, T2: ?Sized>(lhs: &T1, rhs: &T2, radius_squared: D, magnitude: D)
    where T1: PhysicsParticle<V, D>, T2: PhysicsParticle<V, D>, V: Vector<D> + CrossVector, D: Float
{
    let delta = rhs.position() - lhs.position();
    let distance_squared = delta.displacement_squared();
    if distance_squared.is_normal() {
        let force = V::cross(&rhs.velocity(), &V::cross(&lhs.velocity(), &delta)) * magnitude *
            lhs.quanta() * rhs.quanta() /
            if distance_squared > radius_squared {
                distance_squared.sqrt().powi(3)
            } else {
                radius_squared
            };

        lhs.impulse(&-force);
        rhs.impulse(&force);
    }
}
<|endoftext|>


<commit_before>use std::error::FromError;
use std::old_io::IoError;
use std::collections::HashMap;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};

use rustc_serialize::json::{self, DecoderError};
use time::{get_time, Timespec};
use url::Url;
use url::form_urlencoded::serialize_owned;
use hyper::client::request::Request;
use hyper::HttpError;
use hyper::method::Method::Get;

use irc::UserId;
use irc::parse::IrcMsg;
use irc::MessageEndpoint::{self, KnownUser};

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator,
    Format,
};

static DEER: &'static str = concat!(
    "\u{0003}01,01@@@@@@@@\u{0003}00,00@\u{0003}01,01@@\u{0003}00,00@\u{0003}01,01@\n",
    "\u{0003}01,01@@@@@@@@\u{0003}00,00@\u{0003}01,01@@\u{0003}00,00@\u{0003}01,01@\n",
    "\u{0003}01,01@@@@@@@@@\u{0003}00,00@@\u{0003}01,01@@\n",
    "\u{0003}01,01@@@@@@@@\u{0003}00,00@@@\u{0003}01,01@@\n",
    "\u{0003}01,01@@@@@@@@@\u{0003}00,00@@\u{0003}01,01@@\n",
    "\u{0003}01,01@@\u{0003}00,00@@@@@@@@@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@@@@@@@@@@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@@@@@@@@@@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@",
    "\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@",
    "\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@",
    "\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@");

static DEERMAN: &'static str = concat!(
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n",
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n",
    "\u{0003}00,00@@@\u{0003}01,01@@\u{0003}00,00@@@\n",
    "\u{0003}00,00@@\u{0003}01,01@@@\u{0003}00,00@@@\n",
    "\u{0003}00,00@@@\u{0003}01,01@@\u{0003}00,00@@@\n",
    "\u{0003}00,00@@\u{0003}01,01@@@@\u{0003}00,00@@\n",
    "\u{0003}01,01@@@@@@@@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\n",
    "\u{0003}00,00@@\u{0003}01,01@@@@\u{0003}00,00@@\n",
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n",
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n",
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n");

static NOT_IMPLEMENTED: &'static str = "Not yet implemented";

static BASE_URL: &'static str = "http://deer.satf.se/deerlist.php";

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct DeerApiResponse {
    irccode: String
}

#[derive(Debug)]
enum DeerApiFailure {
    ResponseDecodeError,
    RequestError(HttpError),
    ResponseReadError(IoError),
    ResponseDeserializeError(DecoderError)
}

impl FromError<HttpError> for DeerApiFailure {
    fn from_error(err: HttpError) -> DeerApiFailure {
        DeerApiFailure::RequestError(err)
    }
}

impl FromError<IoError> for DeerApiFailure {
    fn from_error(err: IoError) -> DeerApiFailure {
        DeerApiFailure::ResponseReadError(err)
    }
}

impl FromError<DecoderError> for DeerApiFailure {
    fn from_error(err: DecoderError) -> DeerApiFailure {
        DeerApiFailure::ResponseDeserializeError(err)
    }
}

fn get_deer_nocache(deer_name: &str) -> Result<DeerApiResponse, DeerApiFailure> {
    let mut url = match Url::parse(BASE_URL) {
        Ok(url) => url,
        Err(_err) => unreachable!()
    };
    url.query = Some(serialize_owned(&[
        (String::from_str("deer"), String::from_str(deer_name)),
    ]));

    let mut resp = try!(try!(try!(Request::new(Get, url)).start()).send());
    let body = match String::from_utf8(try!(resp.read_to_end())) {
        Ok(body) => body,
        Err(_err) => return Err(DeerApiFailure::ResponseDecodeError)
    };

    Ok(try!(json::decode::<DeerApiResponse>(&body[])))
}

fn get_deer(state: &mut DeerInternalState, deer_name: &str) -> Result<DeerApiResponse, DeerApiFailure> {
    let deer_name_alloc = String::from_str(deer_name);

    match state.cache.get(&deer_name_alloc) {
        Some(result) => return Ok(result.clone()),
        None => ()
    }

    match get_deer_nocache(deer_name) {
        Ok(response) => {
            state.cache.insert(
                String::from_str(deer_name),
                response.clone());
            Ok(response)
        },
        Err(err) => Err(err)
    }
}

pub struct DeerPlugin {
    sender: Option<SyncSender<(CommandMapperDispatch, IrcMsg)>>
}

impl DeerPlugin {
    pub fn new() -> DeerPlugin {
        DeerPlugin { sender: None }
    }

    pub fn get_plugin_name() -> &'static str {
        "deer"
    }
}

struct DeerInternalState {
    lines_sent: u64,
    cache: HashMap<String, DeerApiResponse>,
    throttle_map: HashMap<(UserId, MessageEndpoint), Timespec>,
}

impl DeerInternalState {
    fn new() -> DeerInternalState {
        DeerInternalState {
            lines_sent: 0,
            cache: HashMap::new(),
            throttle_map: HashMap::new(),
        }
    }

    fn throttle_ok(&mut self, uid: UserId, endpoint: MessageEndpoint) -> bool {
        match self.throttle_map.get(&(uid, endpoint)) {
            Some(entry) => 60 < (get_time() - *entry).num_seconds(),
            None => true
        }
    }

    fn throttle_bump(&mut self, uid: UserId, endpoint: MessageEndpoint) {
        self.throttle_map.insert((uid, endpoint), get_time());
    }

    fn handle_command<'a>(&mut self, m: &CommandMapperDispatch, cmd: &'a DeerCommandType) {
        let source = match m.source {
            KnownUser(source) => source,
            _ => return
        };

        if let DeerCommandType::Deer(_) = *cmd {
            if !self.throttle_ok(source, m.target.clone()) {
                m.reply(String::from_str("2deer4plus"));
                return;
            }
        }
        match *cmd {
            DeerCommandType::Deer(ref deer_name) => {
                match get_deer(self, &deer_name[]) {
                    Ok(deer_data) => {
                        for deer_line in deer_data.irccode[].split('\n') {
                            m.reply(String::from_str(deer_line));
                            self.lines_sent += 1;
                        }
                        self.throttle_bump(source, m.target.clone());
                    },
                    Err(err) => {
                        m.reply(format!("error: {:?}", err));
                    }
                }
            },
            DeerCommandType::StaticDeer(data) => {
                for deer_line in data.split('\n') {
                    m.reply(String::from_str(deer_line));
                    self.lines_sent += 1;
                }
                self.throttle_bump(source, m.target.clone());
            },
            DeerCommandType::DeerStats => {
                m.reply(format!("lines sent: {}", self.lines_sent));
            }
        };
    }

    fn start(&mut self, rx: Receiver<(CommandMapperDispatch, IrcMsg)>) {
        for (m, _) in rx.iter() {
            match parse_command(&m) {
                Some(ref command) => self.handle_command(&m, command),
                None => ()
            }
        }
    }
}

enum DeerCommandType {
    Deer(String),
    StaticDeer(&'static str),
    DeerStats
}

fn parse_command<'a>(m: &CommandMapperDispatch) -> Option<DeerCommandType> {
    let command_phrase = m.command();
    match &command_phrase.command[] {
        "deer" => Some(match command_phrase.get("deername") {
            Some(deername) => DeerCommandType::Deer(deername),
            None => DeerCommandType::StaticDeer(DEER)
        }),
        "reed" => Some(DeerCommandType::StaticDeer(NOT_IMPLEMENTED)),
        "deerman" => Some(DeerCommandType::StaticDeer(DEERMAN)),
        "namreed" => Some(DeerCommandType::StaticDeer(NOT_IMPLEMENTED)),
        "deerstats" => Some(DeerCommandType::DeerStats),
        _ => None
    }
}

impl RustBotPlugin for DeerPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map_format(Format::from_str("deer {*deername}").unwrap());
        conf.map_format(Format::from_str("deer").unwrap());
        conf.map_format(Format::from_str("reed").unwrap());
        conf.map_format(Format::from_str("deerman").unwrap());
        conf.map_format(Format::from_str("namreed").unwrap());
        conf.map_format(Format::from_str("deer-stats").unwrap());
    }

    fn start(&mut self) {
        let (tx, rx) = sync_channel(10);
        self.sender = Some(tx);

        ::std::thread::Builder::new().name("plugin-deer".to_string()).spawn(move || {
            let mut deer_internal_state = DeerInternalState::new();
            deer_internal_state.start(rx);
        });
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMsg) {
        match self.sender {
            Some(ref sender) => {
                if let Err(err) = sender.send((m.clone(), message.clone())) {
                    m.reply(format!("Service ``wserver'' unavailable: {:?}", err));
                }
            }
            None => ()
        };
    }
}

<commit_msg>deer: deerstats -> deer-stats<commit_after>use std::error::FromError;
use std::old_io::IoError;
use std::collections::HashMap;
use std::sync::mpsc::{sync_channel, SyncSender, Receiver};

use rustc_serialize::json::{self, DecoderError};
use time::{get_time, Timespec};
use url::Url;
use url::form_urlencoded::serialize_owned;
use hyper::client::request::Request;
use hyper::HttpError;
use hyper::method::Method::Get;

use irc::UserId;
use irc::parse::IrcMsg;
use irc::MessageEndpoint::{self, KnownUser};

use command_mapper::{
    RustBotPlugin,
    CommandMapperDispatch,
    IrcBotConfigurator,
    Format,
};

static DEER: &'static str = concat!(
    "\u{0003}01,01@@@@@@@@\u{0003}00,00@\u{0003}01,01@@\u{0003}00,00@\u{0003}01,01@\n",
    "\u{0003}01,01@@@@@@@@\u{0003}00,00@\u{0003}01,01@@\u{0003}00,00@\u{0003}01,01@\n",
    "\u{0003}01,01@@@@@@@@@\u{0003}00,00@@\u{0003}01,01@@\n",
    "\u{0003}01,01@@@@@@@@\u{0003}00,00@@@\u{0003}01,01@@\n",
    "\u{0003}01,01@@@@@@@@@\u{0003}00,00@@\u{0003}01,01@@\n",
    "\u{0003}01,01@@\u{0003}00,00@@@@@@@@@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@@@@@@@@@@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@@@@@@@@@@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@",
    "\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@",
    "\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@",
    "\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@");

static DEERMAN: &'static str = concat!(
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n",
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n",
    "\u{0003}00,00@@@\u{0003}01,01@@\u{0003}00,00@@@\n",
    "\u{0003}00,00@@\u{0003}01,01@@@\u{0003}00,00@@@\n",
    "\u{0003}00,00@@@\u{0003}01,01@@\u{0003}00,00@@@\n",
    "\u{0003}00,00@@\u{0003}01,01@@@@\u{0003}00,00@@\n",
    "\u{0003}01,01@@@@@@@@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\n",
    "\u{0003}01,01@\u{0003}00,00@\u{0003}01,01@@@@\u{0003}00,00@\u{0003}01,01@\n",
    "\u{0003}00,00@@\u{0003}01,01@@@@\u{0003}00,00@@\n",
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n",
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n",
    "\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\u{0003}01,01@\u{0003}00,00@@\n");

static NOT_IMPLEMENTED: &'static str = "Not yet implemented";

static BASE_URL: &'static str = "http://deer.satf.se/deerlist.php";

#[derive(RustcDecodable, RustcEncodable, Clone)]
struct DeerApiResponse {
    irccode: String
}

#[derive(Debug)]
enum DeerApiFailure {
    ResponseDecodeError,
    RequestError(HttpError),
    ResponseReadError(IoError),
    ResponseDeserializeError(DecoderError)
}

impl FromError<HttpError> for DeerApiFailure {
    fn from_error(err: HttpError) -> DeerApiFailure {
        DeerApiFailure::RequestError(err)
    }
}

impl FromError<IoError> for DeerApiFailure {
    fn from_error(err: IoError) -> DeerApiFailure {
        DeerApiFailure::ResponseReadError(err)
    }
}

impl FromError<DecoderError> for DeerApiFailure {
    fn from_error(err: DecoderError) -> DeerApiFailure {
        DeerApiFailure::ResponseDeserializeError(err)
    }
}

fn get_deer_nocache(deer_name: &str) -> Result<DeerApiResponse, DeerApiFailure> {
    let mut url = match Url::parse(BASE_URL) {
        Ok(url) => url,
        Err(_err) => unreachable!()
    };
    url.query = Some(serialize_owned(&[
        (String::from_str("deer"), String::from_str(deer_name)),
    ]));

    let mut resp = try!(try!(try!(Request::new(Get, url)).start()).send());
    let body = match String::from_utf8(try!(resp.read_to_end())) {
        Ok(body) => body,
        Err(_err) => return Err(DeerApiFailure::ResponseDecodeError)
    };

    Ok(try!(json::decode::<DeerApiResponse>(&body[])))
}

fn get_deer(state: &mut DeerInternalState, deer_name: &str) -> Result<DeerApiResponse, DeerApiFailure> {
    let deer_name_alloc = String::from_str(deer_name);

    match state.cache.get(&deer_name_alloc) {
        Some(result) => return Ok(result.clone()),
        None => ()
    }

    match get_deer_nocache(deer_name) {
        Ok(response) => {
            state.cache.insert(
                String::from_str(deer_name),
                response.clone());
            Ok(response)
        },
        Err(err) => Err(err)
    }
}

pub struct DeerPlugin {
    sender: Option<SyncSender<(CommandMapperDispatch, IrcMsg)>>
}

impl DeerPlugin {
    pub fn new() -> DeerPlugin {
        DeerPlugin { sender: None }
    }

    pub fn get_plugin_name() -> &'static str {
        "deer"
    }
}

struct DeerInternalState {
    lines_sent: u64,
    cache: HashMap<String, DeerApiResponse>,
    throttle_map: HashMap<(UserId, MessageEndpoint), Timespec>,
}

impl DeerInternalState {
    fn new() -> DeerInternalState {
        DeerInternalState {
            lines_sent: 0,
            cache: HashMap::new(),
            throttle_map: HashMap::new(),
        }
    }

    fn throttle_ok(&mut self, uid: UserId, endpoint: MessageEndpoint) -> bool {
        match self.throttle_map.get(&(uid, endpoint)) {
            Some(entry) => 60 < (get_time() - *entry).num_seconds(),
            None => true
        }
    }

    fn throttle_bump(&mut self, uid: UserId, endpoint: MessageEndpoint) {
        self.throttle_map.insert((uid, endpoint), get_time());
    }

    fn handle_command<'a>(&mut self, m: &CommandMapperDispatch, cmd: &'a DeerCommandType) {
        let source = match m.source {
            KnownUser(source) => source,
            _ => return
        };

        if let DeerCommandType::Deer(_) = *cmd {
            if !self.throttle_ok(source, m.target.clone()) {
                m.reply(String::from_str("2deer4plus"));
                return;
            }
        }
        match *cmd {
            DeerCommandType::Deer(ref deer_name) => {
                match get_deer(self, &deer_name[]) {
                    Ok(deer_data) => {
                        for deer_line in deer_data.irccode[].split('\n') {
                            m.reply(String::from_str(deer_line));
                            self.lines_sent += 1;
                        }
                        self.throttle_bump(source, m.target.clone());
                    },
                    Err(err) => {
                        m.reply(format!("error: {:?}", err));
                    }
                }
            },
            DeerCommandType::StaticDeer(data) => {
                for deer_line in data.split('\n') {
                    m.reply(String::from_str(deer_line));
                    self.lines_sent += 1;
                }
                self.throttle_bump(source, m.target.clone());
            },
            DeerCommandType::DeerStats => {
                m.reply(format!("lines sent: {}", self.lines_sent));
            }
        };
    }

    fn start(&mut self, rx: Receiver<(CommandMapperDispatch, IrcMsg)>) {
        for (m, _) in rx.iter() {
            match parse_command(&m) {
                Some(ref command) => self.handle_command(&m, command),
                None => ()
            }
        }
    }
}

enum DeerCommandType {
    Deer(String),
    StaticDeer(&'static str),
    DeerStats
}

fn parse_command<'a>(m: &CommandMapperDispatch) -> Option<DeerCommandType> {
    let command_phrase = m.command();
    match &command_phrase.command[] {
        "deer" => Some(match command_phrase.get("deername") {
            Some(deername) => DeerCommandType::Deer(deername),
            None => DeerCommandType::StaticDeer(DEER)
        }),
        "reed" => Some(DeerCommandType::StaticDeer(NOT_IMPLEMENTED)),
        "deerman" => Some(DeerCommandType::StaticDeer(DEERMAN)),
        "namreed" => Some(DeerCommandType::StaticDeer(NOT_IMPLEMENTED)),
        "deer-stats" => Some(DeerCommandType::DeerStats),
        _ => None
    }
}

impl RustBotPlugin for DeerPlugin {
    fn configure(&mut self, conf: &mut IrcBotConfigurator) {
        conf.map_format(Format::from_str("deer {*deername}").unwrap());
        conf.map_format(Format::from_str("deer").unwrap());
        conf.map_format(Format::from_str("reed").unwrap());
        conf.map_format(Format::from_str("deerman").unwrap());
        conf.map_format(Format::from_str("namreed").unwrap());
        conf.map_format(Format::from_str("deer-stats").unwrap());
    }

    fn start(&mut self) {
        let (tx, rx) = sync_channel(10);
        self.sender = Some(tx);

        ::std::thread::Builder::new().name("plugin-deer".to_string()).spawn(move || {
            let mut deer_internal_state = DeerInternalState::new();
            deer_internal_state.start(rx);
        });
    }

    fn dispatch_cmd(&mut self, m: &CommandMapperDispatch, message: &IrcMsg) {
        match self.sender {
            Some(ref sender) => {
                if let Err(err) = sender.send((m.clone(), message.clone())) {
                    m.reply(format!("Service ``wserver'' unavailable: {:?}", err));
                }
            }
            None => ()
        };
    }
}

<|endoftext|>


<commit_before>//! Implements the Berlekamp-Massey, Chien Search, and Forney algorithms.
//!
//! Most Galois field information as well as the Berlekamp-Massey and Forney
//! implementations are derived from *Coding Theory and Cryptography: The Essentials*,
//! Hankerson, Hoffman, et al, 2000, and the Chien search is derived from
//! [Wikipedia](https://en.wikipedia.org/wiki/Chien_search).

use std;

use coding::galois::{Polynomial, PolynomialCoefs, P25Codeword, P25Field, GaloisField};

/// Implements the iterative part of the Berlekamp-Massey algorithm.
pub struct BerlMasseyDecoder<P: PolynomialCoefs> {
    /// Saved p polynomial: p_{z_i-1}.
    p_saved: Polynomial<P>,
    /// Previous iteration's p polynomial: p_{i-1}.
    p_cur: Polynomial<P>,
    /// Saved q polynomial: q_{z_i-1}.
    q_saved: Polynomial<P>,
    /// Previous iteration's q polynomial: q_{i-1}.
    q_cur: Polynomial<P>,
    /// Degree-related term of saved p polynomial: D_{z_i-1}.
    deg_saved: usize,
    /// Degree-related term of previous p polynomial: D_{i-1}.
    deg_cur: usize,
}

impl<P: PolynomialCoefs> BerlMasseyDecoder<P> {
    /// Construct a new `BerlMasseyDecoder` from the given syndrome polynomial.
    pub fn new(syn: Polynomial<P>) -> BerlMasseyDecoder<P> {
        // 2t zeroes followed by a one.
        let p = Polynomial::new((0..P::syndromes()+1).map(|_| P25Codeword::default())
                                    .chain(std::iter::once(P25Codeword::for_power(0))));

        BerlMasseyDecoder {
            q_saved: syn,
            q_cur: Polynomial::new(syn.iter().skip(1).cloned()),
            p_saved: p,
            p_cur: p.shift(),
            deg_saved: 0,
            deg_cur: 1,
        }
    }

    /// Perform the iterative steps to get the error-location polynomial Λ(x) wih deg(Λ)
    /// <= P::errors().
    pub fn decode(mut self) -> Polynomial<P> {
        for _ in 0..P::syndromes() {
            self.step();
        }

        self.p_cur
    }

    /// Perform one iterative step of the algorithm, updating the state polynomials and
    /// degrees.
    fn step(&mut self) {
        let (save, q, p, d) = if self.q_cur.constant().zero() {
            self.reduce()
        } else {
            self.transform()
        };

        if save {
            self.q_saved = self.q_cur;
            self.p_saved = self.p_cur;
            self.deg_saved = self.deg_cur;
        }

        self.q_cur = q;
        self.p_cur = p;
        self.deg_cur = d;
    }

    /// Simply shift the polynomials since they have no degree-0 term.
    fn reduce(&mut self) -> (bool, Polynomial<P>, Polynomial<P>, usize) {
        (
            false,
            self.q_cur.shift(),
            self.p_cur.shift(),
            2 + self.deg_cur,
        )
    }

    /// Remove the degree-0 terms and shift the polynomials.
    fn transform(&mut self) -> (bool, Polynomial<P>, Polynomial<P>, usize) {
        let mult = self.q_cur.constant() / self.q_saved.constant();

        (
            self.deg_cur >= self.deg_saved,
            (self.q_cur + self.q_saved * mult).shift(),
            (self.p_cur + self.p_saved * mult).shift(),
            2 + std::cmp::min(self.deg_cur, self.deg_saved),
        )
   }
}

/// Uses Chien search to find the roots in GF(2^6) of an error-locator polynomial and
/// produce an iterator of error bit positions. The Forney algorithm is used to find the
/// associated error values.
pub struct Errors<P: PolynomialCoefs> {
    /// Error location polynomial.
    errs: Polynomial<P>,
    /// Derivative of above.
    deriv: Polynomial<P>,
    /// Error value polynomial.
    vals: Polynomial<P>,
    /// Current exponent power of the iteration.
    pow: std::ops::Range<usize>,
}

impl<P: PolynomialCoefs> Errors<P> {
    /// Construct a new `Errors` from the given error and syndrome polynomials.
    pub fn new(errs: Polynomial<P>, syn: Polynomial<P>) -> Errors<P> {
        let deriv = errs.deriv();
        let vals = (errs * syn).truncate(P::syndromes());

        Errors {
            errs: errs,
            deriv: deriv,
            vals: vals,
            pow: 0..P25Field::size(),
        }
    }

    /// Perform the term-updating step of the algorithm: x_{j,i} = x_{j,i-1} * α^j.
    fn update_terms(&mut self) {
        for (pow, term) in self.errs.iter_mut().enumerate() {
            *term = *term * P25Codeword::for_power(pow);
        }
    }

    /// Calculate the sum of the terms: x_{0,i} + x_{1,i} + ... + x_{t,i} -- evaluate the
    /// error-locator polynomial at Λ(α^i).
    fn sum_terms(&self) -> P25Codeword {
        self.errs.iter().fold(P25Codeword::default(), |s, &x| s + x)
    }

    /// Determine the error value for the given error location/root.
    fn value(&self, loc: P25Codeword, root: P25Codeword) -> P25Codeword {
        self.vals.eval(root) / self.deriv.eval(root) * loc
    }
}

impl<P: PolynomialCoefs> Iterator for Errors<P> {
    type Item = (usize, P25Codeword);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let pow = match self.pow.next() {
                Some(pow) => pow,
                None => return None,
            };

            let eval = self.sum_terms();
            self.update_terms();

            if eval.zero() {
                let root = P25Codeword::for_power(pow);
                let loc = root.invert();

                return Some((loc.power().unwrap(), self.value(loc, root)));
            }
        }
    }
}
<commit_msg>Use unit_power in BerlMasseyDecoder<commit_after>//! Implements the Berlekamp-Massey, Chien Search, and Forney algorithms.
//!
//! Most Galois field information as well as the Berlekamp-Massey and Forney
//! implementations are derived from *Coding Theory and Cryptography: The Essentials*,
//! Hankerson, Hoffman, et al, 2000, and the Chien search is derived from
//! [Wikipedia](https://en.wikipedia.org/wiki/Chien_search).

use std;

use coding::galois::{Polynomial, PolynomialCoefs, P25Codeword, P25Field, GaloisField};

/// Implements the iterative part of the Berlekamp-Massey algorithm.
pub struct BerlMasseyDecoder<P: PolynomialCoefs> {
    /// Saved p polynomial: p_{z_i-1}.
    p_saved: Polynomial<P>,
    /// Previous iteration's p polynomial: p_{i-1}.
    p_cur: Polynomial<P>,
    /// Saved q polynomial: q_{z_i-1}.
    q_saved: Polynomial<P>,
    /// Previous iteration's q polynomial: q_{i-1}.
    q_cur: Polynomial<P>,
    /// Degree-related term of saved p polynomial: D_{z_i-1}.
    deg_saved: usize,
    /// Degree-related term of previous p polynomial: D_{i-1}.
    deg_cur: usize,
}

impl<P: PolynomialCoefs> BerlMasseyDecoder<P> {
    /// Construct a new `BerlMasseyDecoder` from the given syndrome polynomial.
    pub fn new(syn: Polynomial<P>) -> BerlMasseyDecoder<P> {
        // 2t zeroes followed by a one.
        let p = Polynomial::unit_power(P::syndromes() + 1);

        BerlMasseyDecoder {
            q_saved: syn,
            q_cur: Polynomial::new(syn.iter().skip(1).cloned()),
            p_saved: p,
            p_cur: p.shift(),
            deg_saved: 0,
            deg_cur: 1,
        }
    }

    /// Perform the iterative steps to get the error-location polynomial Λ(x) wih deg(Λ)
    /// <= P::errors().
    pub fn decode(mut self) -> Polynomial<P> {
        for _ in 0..P::syndromes() {
            self.step();
        }

        self.p_cur
    }

    /// Perform one iterative step of the algorithm, updating the state polynomials and
    /// degrees.
    fn step(&mut self) {
        let (save, q, p, d) = if self.q_cur.constant().zero() {
            self.reduce()
        } else {
            self.transform()
        };

        if save {
            self.q_saved = self.q_cur;
            self.p_saved = self.p_cur;
            self.deg_saved = self.deg_cur;
        }

        self.q_cur = q;
        self.p_cur = p;
        self.deg_cur = d;
    }

    /// Simply shift the polynomials since they have no degree-0 term.
    fn reduce(&mut self) -> (bool, Polynomial<P>, Polynomial<P>, usize) {
        (
            false,
            self.q_cur.shift(),
            self.p_cur.shift(),
            2 + self.deg_cur,
        )
    }

    /// Remove the degree-0 terms and shift the polynomials.
    fn transform(&mut self) -> (bool, Polynomial<P>, Polynomial<P>, usize) {
        let mult = self.q_cur.constant() / self.q_saved.constant();

        (
            self.deg_cur >= self.deg_saved,
            (self.q_cur + self.q_saved * mult).shift(),
            (self.p_cur + self.p_saved * mult).shift(),
            2 + std::cmp::min(self.deg_cur, self.deg_saved),
        )
   }
}

/// Uses Chien search to find the roots in GF(2^6) of an error-locator polynomial and
/// produce an iterator of error bit positions. The Forney algorithm is used to find the
/// associated error values.
pub struct Errors<P: PolynomialCoefs> {
    /// Error location polynomial.
    errs: Polynomial<P>,
    /// Derivative of above.
    deriv: Polynomial<P>,
    /// Error value polynomial.
    vals: Polynomial<P>,
    /// Current exponent power of the iteration.
    pow: std::ops::Range<usize>,
}

impl<P: PolynomialCoefs> Errors<P> {
    /// Construct a new `Errors` from the given error and syndrome polynomials.
    pub fn new(errs: Polynomial<P>, syn: Polynomial<P>) -> Errors<P> {
        let deriv = errs.deriv();
        let vals = (errs * syn).truncate(P::syndromes());

        Errors {
            errs: errs,
            deriv: deriv,
            vals: vals,
            pow: 0..P25Field::size(),
        }
    }

    /// Perform the term-updating step of the algorithm: x_{j,i} = x_{j,i-1} * α^j.
    fn update_terms(&mut self) {
        for (pow, term) in self.errs.iter_mut().enumerate() {
            *term = *term * P25Codeword::for_power(pow);
        }
    }

    /// Calculate the sum of the terms: x_{0,i} + x_{1,i} + ... + x_{t,i} -- evaluate the
    /// error-locator polynomial at Λ(α^i).
    fn sum_terms(&self) -> P25Codeword {
        self.errs.iter().fold(P25Codeword::default(), |s, &x| s + x)
    }

    /// Determine the error value for the given error location/root.
    fn value(&self, loc: P25Codeword, root: P25Codeword) -> P25Codeword {
        self.vals.eval(root) / self.deriv.eval(root) * loc
    }
}

impl<P: PolynomialCoefs> Iterator for Errors<P> {
    type Item = (usize, P25Codeword);

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let pow = match self.pow.next() {
                Some(pow) => pow,
                None => return None,
            };

            let eval = self.sum_terms();
            self.update_terms();

            if eval.zero() {
                let root = P25Codeword::for_power(pow);
                let loc = root.invert();

                return Some((loc.power().unwrap(), self.value(loc, root)));
            }
        }
    }
}
<|endoftext|>


<commit_before>//! Endpoints for the media repository.

//! [GET /_matrix/media/r0/download/{serverName}/{mediaId}](https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-media-r0-download-servername-mediaid)

use ruma_api::ruma_api;

ruma_api! {
    metadata {
        description: "Retrieve content from the media store.",
        method: GET,
        name: "get_media_content",
        path: "/_matrix/media/r0/download/:server_name/:media_id",
        rate_limited: false,
        requires_authentication: false,
    }

    request {
        /// The media ID from the mxc:// URI (the path component).
        #[ruma_api(path)]
        pub media_id: String,
        /// The server name from the mxc:// URI (the authoritory component).
        #[ruma_api(path)]
        pub server_name: String,
    }

    response {
        /// The content that was previously uploaded.
        #[ruma_api(raw_body)]
        pub file: Vec<u8>,
        /// The content type of the file that was previously uploaded.
        #[ruma_api(header = CONTENT_TYPE)]
        pub content_type: String,
        /// The name of the file that was previously uploaded, if set.
        #[ruma_api(header = CONTENT_DISPOSITION)]
        pub content_disposition: String,
    }
}
<commit_msg>Add allow_remote parameter to content fetching endpoint.<commit_after>//! Endpoints for the media repository.

//! [GET /_matrix/media/r0/download/{serverName}/{mediaId}](https://matrix.org/docs/spec/client_server/r0.4.0.html#get-matrix-media-r0-download-servername-mediaid)

use ruma_api::ruma_api;

ruma_api! {
    metadata {
        description: "Retrieve content from the media store.",
        method: GET,
        name: "get_media_content",
        path: "/_matrix/media/r0/download/:server_name/:media_id",
        rate_limited: false,
        requires_authentication: false,
    }

    request {
        /// The media ID from the mxc:// URI (the path component).
        #[ruma_api(path)]
        pub media_id: String,
        /// The server name from the mxc:// URI (the authoritory component).
        #[ruma_api(path)]
        pub server_name: String,
        /// Whether to fetch media deemed remote.
        /// Used to prevent routing loops. Defaults to `true`.
        #[ruma_api(query)]
        pub allow_remote: Option<bool>,
    }

    response {
        /// The content that was previously uploaded.
        #[ruma_api(raw_body)]
        pub file: Vec<u8>,
        /// The content type of the file that was previously uploaded.
        #[ruma_api(header = CONTENT_TYPE)]
        pub content_type: String,
        /// The name of the file that was previously uploaded, if set.
        #[ruma_api(header = CONTENT_DISPOSITION)]
        pub content_disposition: String,
    }
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2014 Y. T. CHUNG <zonyitoo@gmail.com>

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// SOCKS5 UDP Request
// +----+------+------+----------+----------+----------+
// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
// +----+------+------+----------+----------+----------+
// | 2  |  1   |  1   | Variable |    2     | Variable |
// +----+------+------+----------+----------+----------+

// SOCKS5 UDP Response
// +----+------+------+----------+----------+----------+
// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
// +----+------+------+----------+----------+----------+
// | 2  |  1   |  1   | Variable |    2     | Variable |
// +----+------+------+----------+----------+----------+

// shadowsocks UDP Request (before encrypted)
// +------+----------+----------+----------+
// | ATYP | DST.ADDR | DST.PORT |   DATA   |
// +------+----------+----------+----------+
// |  1   | Variable |    2     | Variable |
// +------+----------+----------+----------+

// shadowsocks UDP Response (before encrypted)
// +------+----------+----------+----------+
// | ATYP | DST.ADDR | DST.PORT |   DATA   |
// +------+----------+----------+----------+
// |  1   | Variable |    2     | Variable |
// +------+----------+----------+----------+

// shadowsocks UDP Request and Response (after encrypted)
// +-------+--------------+
// |   IV  |    PAYLOAD   |
// +-------+--------------+
// | Fixed |   Variable   |
// +-------+--------------+

use std::sync::{Arc, Mutex};
use std::net::{SocketAddr, lookup_host};
use std::collections::HashMap;
use std::io::{BufReader, self};

use coio::Builder;
use coio::net::UdpSocket;

use lru_cache::LruCache;

use crypto::{cipher, CryptoMode};
use crypto::cipher::Cipher;
use config::{Config, ServerConfig};
use relay::{socks5, COROUTINE_STACK_SIZE};
use relay::loadbalancing::server::{LoadBalancer, RoundRobin};
use relay::udprelay::UDP_RELAY_LOCAL_LRU_CACHE_CAPACITY;

#[derive(Clone)]
pub struct UdpRelayLocal {
    config: Config,
}

impl UdpRelayLocal {
    pub fn new(config: Config) -> UdpRelayLocal {
        UdpRelayLocal {
            config: config,
        }
    }
}

impl UdpRelayLocal {
    pub fn run(&self) {
        let addr = match self.config.local {
            Some(addr) => addr,
            None => {
                error!("Local configuration should not be None");
                return;
            }
        };

        let mut server_load_balancer = RoundRobin::new(self.config.server.clone());

        let (server_set, server_addr) = {
            let mut server_set = HashMap::new();
            let mut server_addr = HashMap::new();
            for s in self.config.server.iter() {
                let mut addrs = match lookup_host(&s.addr[..]) {
                    Ok(addr) => addr,
                    Err(..) => continue,
                };

                match addrs.next() {
                    Some(Ok(addr)) => {
                        server_set.insert(addr, s.clone());
                        server_addr.insert(s.addr.clone(), addr);
                    },
                    _ => {}
                }
            }
            (server_set, server_addr)
        };

        let client_map_arc = Arc::new(Mutex::new(
                    LruCache::<socks5::Address, SocketAddr>::new(UDP_RELAY_LOCAL_LRU_CACHE_CAPACITY)));

        let socket = match UdpSocket::bind(&addr) {
            Ok(sk) => sk,
            Err(err) => {
                error!("Failed to bind udp socket: {:?}", err);
                return;
            }
        };

        let mut buf = [0u8; 0xffff];
        loop {
            match socket.recv_from(&mut buf) {
                Ok((len, source_addr)) => {
                    if len < 4 {
                        error!("UDP request is too short");
                        continue;
                    }

                    let request_message = buf[..len].to_vec();
                    let move_socket = socket.try_clone().unwrap();
                    let client_map = client_map_arc.clone();

                    match server_set.get(&source_addr) {
                        Some(sref) => {
                            let s = sref.clone();
                            Builder::new().stack_size(COROUTINE_STACK_SIZE).spawn(move ||
                                handle_response(move_socket,
                                               &request_message[..],
                                               source_addr,
                                               &s,
                                               client_map));
                        }
                        None => {
                            let s = server_load_balancer.pick_server().clone();
                            debug!("UDP associate picked a server: {:?}", s);

                            match server_addr.get(&s.addr) {
                                Some(saddr) => {
                                    let saddr = saddr.clone();
                                    Builder::new().stack_size(COROUTINE_STACK_SIZE).spawn(move ||
                                        handle_request(move_socket,
                                                      &request_message[..],
                                                      source_addr,
                                                      saddr,
                                                      &s,
                                                      client_map));
                                },
                                None => {}
                            }
                        }
                    }
                },
                Err(err) => {
                    error!("Failed in UDP recv_from: {}", err);
                    break
                }
            }
        }
    }
}

fn handle_request(socket: UdpSocket,
                  request_message: &[u8],
                  from_addr: SocketAddr,
                  server_addr: SocketAddr,
                  config: &ServerConfig,
                  client_map: Arc<Mutex<LruCache<socks5::Address, SocketAddr>>>) {
    // According to RFC 1928
    //
    // Implementation of fragmentation is optional; an implementation that
    // does not support fragmentation MUST drop any datagram whose FRAG
    // field is other than X'00'.
    if request_message[2] != 0x00u8 {
        // Drop it
        warn!("Does not support fragmentation");
        return;
    }

    let mut bufr = BufReader::new(request_message);
    let request = match socks5::UdpAssociateHeader::read_from(&mut bufr) {
        Ok(r) => r,
        Err(err) => {
            error!("Error occurs while reading UdpAssociateHeader: {:?}", err);
            return;
        }
    };

    let addr = request.address.clone();

    info!("UDP ASSOCIATE {}", addr);
    debug!("UDP associate {} <-> {}", addr, from_addr);

    client_map.lock().unwrap().insert(addr, from_addr);

    let key = config.method.bytes_to_key(config.password.as_bytes());
    let mut iv = config.method.gen_init_vec();
    let mut encryptor = cipher::with_type(config.method,
                                          &key[..],
                                          &iv[..],
                                          CryptoMode::Encrypt);

    let mut wbuf = Vec::new();
    if let Err(err) = request.write_to(&mut wbuf) {
        error!("Error occurs while writing request: {:?}", err);
        return;
    }

    if let Err(err) = io::copy(&mut bufr, &mut wbuf) {
        error!("Error occurs while copying from bufr to wbuf: {:?}", err);
        return;
    }

    if let Err(err) = encryptor.update(&wbuf[..], &mut iv) {
        error!("Error occurs while encrypting: {:?}", err);
        return;
    }

    if let Err(err) = encryptor.finalize(&mut iv) {
        error!("Error occurs while finalizing: {:?}", err);
        return;
    }

    if let Err(err) = socket.send_to(&iv[..], &server_addr) {
        error!("Error occurs while sending to remote: {:?}", err);
    }
}

fn handle_response(socket: UdpSocket,
                   response_message: &[u8],
                   from_addr: SocketAddr,
                   config: &ServerConfig,
                   client_map: Arc<Mutex<LruCache<socks5::Address, SocketAddr>>>) {
    let key = config.method.bytes_to_key(config.password.as_bytes());

    let mut decryptor = cipher::with_type(config.method,
                                          &key[..],
                                          &response_message[0..config.method.block_size()],
                                          CryptoMode::Decrypt);
    let mut decrypted_data = Vec::new();
    if let Err(err) = decryptor.update(&response_message[config.method.block_size()..], &mut decrypted_data) {
        error!("Error occurs while decrypting data: {:?}", err);
        return;
    }

    if let Err(err) = decryptor.finalize(&mut decrypted_data) {
        error!("Error occurs while finalizing decrypt: {:?}", err);
        return;
    }

    let mut bufr = BufReader::new(&decrypted_data[..]);

    let addr = match socks5::Address::read_from(&mut bufr) {
        Ok(addr) => addr,
        Err(err) => {
            error!("Error occurs while reading address: {:?}", err);
            return;
        }
    };

    let client_addr = {
        let mut cmap = client_map.lock().unwrap();
        match cmap.get(&addr) {
            Some(a) => a.clone(),
            None => return
        }
    };

    debug!("UDP response {} -> {}", from_addr, client_addr);

    let mut bufw = Vec::new();
    if let Err(err) = socks5::UdpAssociateHeader::new(0, addr).write_to(&mut bufw) {
        error!("Error occurs while writing UdpAssociateHeader: {:?}", err);
        return;
    }

    if let Err(err) = io::copy(&mut bufr, &mut bufw) {
        error!("Error occurs while copying from bufr to bufw: {:?}", err);
        return;
    }

    if let Err(err) = socket.send_to(&bufw[..], &client_addr) {
        error!("Error occurs while sending to local: {:?}", err);
    }
}
<commit_msg>fixed udp client<commit_after>// The MIT License (MIT)

// Copyright (c) 2014 Y. T. CHUNG <zonyitoo@gmail.com>

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

// SOCKS5 UDP Request
// +----+------+------+----------+----------+----------+
// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
// +----+------+------+----------+----------+----------+
// | 2  |  1   |  1   | Variable |    2     | Variable |
// +----+------+------+----------+----------+----------+

// SOCKS5 UDP Response
// +----+------+------+----------+----------+----------+
// |RSV | FRAG | ATYP | DST.ADDR | DST.PORT |   DATA   |
// +----+------+------+----------+----------+----------+
// | 2  |  1   |  1   | Variable |    2     | Variable |
// +----+------+------+----------+----------+----------+

// shadowsocks UDP Request (before encrypted)
// +------+----------+----------+----------+
// | ATYP | DST.ADDR | DST.PORT |   DATA   |
// +------+----------+----------+----------+
// |  1   | Variable |    2     | Variable |
// +------+----------+----------+----------+

// shadowsocks UDP Response (before encrypted)
// +------+----------+----------+----------+
// | ATYP | DST.ADDR | DST.PORT |   DATA   |
// +------+----------+----------+----------+
// |  1   | Variable |    2     | Variable |
// +------+----------+----------+----------+

// shadowsocks UDP Request and Response (after encrypted)
// +-------+--------------+
// |   IV  |    PAYLOAD   |
// +-------+--------------+
// | Fixed |   Variable   |
// +-------+--------------+

use std::sync::{Arc, Mutex};
use std::net::{SocketAddr, lookup_host};
use std::collections::HashMap;
use std::io::{BufReader, self};

use coio::Builder;
use coio::net::UdpSocket;

use lru_cache::LruCache;

use crypto::{cipher, CryptoMode};
use crypto::cipher::Cipher;
use config::{Config, ServerConfig};
use relay::{socks5, COROUTINE_STACK_SIZE};
use relay::loadbalancing::server::{LoadBalancer, RoundRobin};
use relay::udprelay::UDP_RELAY_LOCAL_LRU_CACHE_CAPACITY;

#[derive(Clone)]
pub struct UdpRelayLocal {
    config: Config,
}

impl UdpRelayLocal {
    pub fn new(config: Config) -> UdpRelayLocal {
        UdpRelayLocal {
            config: config,
        }
    }
}

impl UdpRelayLocal {
    pub fn run(&self) {
        let addr = match self.config.local {
            Some(addr) => addr,
            None => {
                error!("Local configuration should not be None");
                return;
            }
        };

        let mut server_load_balancer = RoundRobin::new(self.config.server.clone());

        let (server_set, server_addr) = {
            let mut server_set = HashMap::new();
            let mut server_addr = HashMap::new();
            for s in self.config.server.iter() {
                let mut addrs = match lookup_host(&s.addr[..]) {
                    Ok(addr) => addr,
                    Err(..) => continue,
                };

                match addrs.next() {
                    Some(Ok(addr)) => {
                        let addr = SocketAddr::new(addr.ip(), s.port);
                        server_set.insert(addr.clone(), s.clone());
                        server_addr.insert(s.addr.clone(), addr);
                    },
                    _ => {}
                }
            }
            (server_set, server_addr)
        };

        let client_map_arc = Arc::new(Mutex::new(
                    LruCache::<socks5::Address, SocketAddr>::new(UDP_RELAY_LOCAL_LRU_CACHE_CAPACITY)));

        let socket = match UdpSocket::bind(&addr) {
            Ok(sk) => sk,
            Err(err) => {
                error!("Failed to bind udp socket: {:?}", err);
                return;
            }
        };

        let mut buf = [0u8; 0xffff];
        loop {
            match socket.recv_from(&mut buf) {
                Ok((len, source_addr)) => {
                    if len < 4 {
                        error!("UDP request is too short");
                        continue;
                    }

                    let request_message = buf[..len].to_vec();
                    let move_socket = socket.try_clone().unwrap();
                    let client_map = client_map_arc.clone();

                    debug!("Received UDP packet, source {:?}", source_addr);
                    match server_set.get(&source_addr) {
                        Some(sref) => {
                            let s = sref.clone();
                            Builder::new().stack_size(COROUTINE_STACK_SIZE).spawn(move ||
                                handle_response(move_socket,
                                               &request_message[..],
                                               source_addr,
                                               &s,
                                               client_map));
                        }
                        None => {
                            let s = server_load_balancer.pick_server().clone();
                            debug!("UDP associate picked a server: {:?}", s);

                            match server_addr.get(&s.addr) {
                                Some(saddr) => {
                                    let saddr = saddr.clone();
                                    Builder::new().stack_size(COROUTINE_STACK_SIZE).spawn(move ||
                                        handle_request(move_socket,
                                                      &request_message[..],
                                                      source_addr,
                                                      saddr,
                                                      &s,
                                                      client_map));
                                },
                                None => {}
                            }
                        }
                    }
                },
                Err(err) => {
                    error!("Failed in UDP recv_from: {}", err);
                    break
                }
            }
        }
    }
}

fn handle_request(socket: UdpSocket,
                  request_message: &[u8],
                  from_addr: SocketAddr,
                  server_addr: SocketAddr,
                  config: &ServerConfig,
                  client_map: Arc<Mutex<LruCache<socks5::Address, SocketAddr>>>) {
    // According to RFC 1928
    //
    // Implementation of fragmentation is optional; an implementation that
    // does not support fragmentation MUST drop any datagram whose FRAG
    // field is other than X'00'.
    if request_message[2] != 0x00u8 {
        // Drop it
        warn!("Does not support fragmentation");
        return;
    }

    let mut bufr = BufReader::new(request_message);
    let request = match socks5::UdpAssociateHeader::read_from(&mut bufr) {
        Ok(r) => r,
        Err(err) => {
            error!("Error occurs while reading UdpAssociateHeader: {:?}", err);
            return;
        }
    };

    let addr = request.address.clone();

    info!("UDP ASSOCIATE {}", addr);
    debug!("UDP associate {} <-> {}", addr, from_addr);

    client_map.lock().unwrap().insert(addr, from_addr);

    let key = config.method.bytes_to_key(config.password.as_bytes());
    let mut iv = config.method.gen_init_vec();
    let mut encryptor = cipher::with_type(config.method,
                                          &key[..],
                                          &iv[..],
                                          CryptoMode::Encrypt);

    let mut wbuf = Vec::new();
    if let Err(err) = request.write_to(&mut wbuf) {
        error!("Error occurs while writing request: {:?}", err);
        return;
    }

    if let Err(err) = io::copy(&mut bufr, &mut wbuf) {
        error!("Error occurs while copying from bufr to wbuf: {:?}", err);
        return;
    }

    if let Err(err) = encryptor.update(&wbuf[..], &mut iv) {
        error!("Error occurs while encrypting: {:?}", err);
        return;
    }

    if let Err(err) = encryptor.finalize(&mut iv) {
        error!("Error occurs while finalizing: {:?}", err);
        return;
    }

    if let Err(err) = socket.send_to(&iv[..], &server_addr) {
        error!("Error occurs while sending to remote: {:?}", err);
    }

    debug!("Sent packet:{:?} to {:?}", iv, server_addr);
}

fn handle_response(socket: UdpSocket,
                   response_message: &[u8],
                   from_addr: SocketAddr,
                   config: &ServerConfig,
                   client_map: Arc<Mutex<LruCache<socks5::Address, SocketAddr>>>) {
    let key = config.method.bytes_to_key(config.password.as_bytes());

    let mut decryptor = cipher::with_type(config.method,
                                          &key[..],
                                          &response_message[0..config.method.block_size()],
                                          CryptoMode::Decrypt);
    let mut decrypted_data = Vec::new();
    if let Err(err) = decryptor.update(&response_message[config.method.block_size()..], &mut decrypted_data) {
        error!("Error occurs while decrypting data: {:?}", err);
        return;
    }

    if let Err(err) = decryptor.finalize(&mut decrypted_data) {
        error!("Error occurs while finalizing decrypt: {:?}", err);
        return;
    }

    let mut bufr = BufReader::new(&decrypted_data[..]);

    let addr = match socks5::Address::read_from(&mut bufr) {
        Ok(addr) => addr,
        Err(err) => {
            error!("Error occurs while reading address: {:?}", err);
            return;
        }
    };

    let client_addr = {
        let mut cmap = client_map.lock().unwrap();
        match cmap.get(&addr) {
            Some(a) => a.clone(),
            None => return
        }
    };

    debug!("UDP response {} -> {}", from_addr, client_addr);

    let mut bufw = Vec::new();
    if let Err(err) = socks5::UdpAssociateHeader::new(0, addr).write_to(&mut bufw) {
        error!("Error occurs while writing UdpAssociateHeader: {:?}", err);
        return;
    }

    if let Err(err) = io::copy(&mut bufr, &mut bufw) {
        error!("Error occurs while copying from bufr to bufw: {:?}", err);
        return;
    }

    if let Err(err) = socket.send_to(&bufw[..], &client_addr) {
        error!("Error occurs while sending to local: {:?}", err);
    }
}
<|endoftext|>