<commit_before>use std::slice;

use libc::c_void;

#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: libc::size_t,
}

/// A simple struct that can be leaked across the FFI boundary in lieu of an actual tuple
#[repr(C)]
pub struct ResultTuple {
    pub e: Array,
    pub n: Array,
}

use super::convert_epsg3857_to_wgs84_threaded_vec;
use super::convert_etrs89_to_ll_threaded_vec;
use super::convert_etrs89_to_osgb36_threaded_vec;
use super::convert_osgb36_to_etrs89_threaded_vec;
use super::convert_osgb36_to_ll_threaded_vec;
use super::convert_to_bng_threaded_vec;
use super::convert_to_etrs89_threaded_vec;
use super::convert_to_lonlat_threaded_vec;
use super::convert_to_osgb36_threaded_vec;

/// Free memory which Rust has allocated across the FFI boundary (f64 values)
///
/// # Examples
///
/// ```
/// # use libc;
/// let lon_vec: Vec<f64> = vec![-2.0183041005533306];
/// let lat_vec: Vec<f64> = vec![54.589097162646141];
/// let lon_arr = Array {
///     data: lon_vec.as_ptr() as *const libc::c_void,
///     len: lon_vec.len() as libc::size_t,
/// };
/// let lat_arr = Array {
///     data: lat_vec.as_ptr() as *const libc::c_void,
///     len: lat_vec.len() as libc::size_t,
/// };
/// let (eastings, northings) = convert_to_bng_threaded(lon_arr, lat_arr);
/// drop_float_array(eastings, northings);
/// ```
/// An example FFI implementation is available at [Convertbng](https://github.com/urschrei/convertbng/blob/master/convertbng/util.py), specifically in the `_void_array_to_list` function.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_float_array(lons: Array, lats: Array) {
    if lons.data.is_null() {
        return;
    }
    if lats.data.is_null() {
        return;
    }
    let _: &mut [f64] = lons.into();
    let _: &mut [f64] = lats.into();
}

// Build an Array from &mut[T], so it can be leaked across the FFI boundary
impl<'a, T> From<&'a mut [T]> for Array {
    fn from(sl: &mut [T]) -> Self {
        Array {
            data: sl.as_ptr() as *const libc::c_void,
            len: sl.len() as libc::size_t,
        }
    }
}

// Build &mut[f64] from an Array, so it can be dropped
impl<'a> From<Array> for &'a mut [f64] {
    fn from(arr: Array) -> Self {
        unsafe { slice::from_raw_parts_mut(arr.data as *mut f64, arr.len) }
    }
}

// Slice tuple to ResultTuple
impl<T> From<(T, T)> for ResultTuple
where
    T: Into<Array>,
{
    fn from(tup: (T, T)) -> Self {
        ResultTuple {
            e: tup.0.into(),
            n: tup.1.into(),
        }
    }
}

/// A threaded, FFI-compatible wrapper for `lonlat_bng::convert_osgb36`
///
/// # Examples
///
/// ```
/// use libc;
/// let lon_vec: Vec<f64> = vec![-2.0183041005533306,
///                              0.95511887434519682,
///                              0.44975855518383501,
///                              -0.096813621191803811,
///                              -0.36807065656416427,
///                              0.63486335458665621];
/// let lat_vec: Vec<f64> = vec![54.589097162646141,
///                              51.560873800587828,
///                              50.431429161121699,
///                              54.535021436247419,
///                              50.839059313135706,
///                              55.412189281234419];
/// let lon_arr = Array {
///     data: lon_vec.as_ptr() as *const libc::c_void,
///     len: lon_vec.len() as libc::size_t,
/// };
/// let lat_arr = Array {
///     data: lat_vec.as_ptr() as *const libc::c_void,
///     len: lat_vec.len() as libc::size_t,
/// };
/// let (eastings, northings) = convert_to_bng_threaded(lon_arr, lat_arr);
/// ```
/// For an FFI implementation, see the code at [Convertbng](https://github.com/urschrei/convertbng/blob/master/convertbng/util.py).
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_to_bng_threaded(longitudes: Array, latitudes: Array) -> ResultTuple {
    convert_to_bng_threaded_vec(longitudes.into(), latitudes.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_osgb36_to_ll`](fn.convert_osgb36_to_ll.html)
///
/// # Examples
///
/// See [`lonlat_bng::convert_to_bng_threaded`](fn.convert_to_bng_threaded.html)
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_to_lonlat_threaded(eastings: Array, northings: Array) -> ResultTuple {
    convert_to_lonlat_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_osgb36`](fn.convert_osgb36.html)
///
/// # Examples
///
/// See [`lonlat_bng::convert_to_bng_threaded`](fn.convert_to_bng_threaded.html) for examples, substituting f64 vectors
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_to_osgb36_threaded(longitudes: Array, latitudes: Array) -> ResultTuple {
    convert_to_osgb36_threaded_vec(longitudes.into(), latitudes.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_etrs89`](fn.convert_etrs89.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples, substituting f64 vectors
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_to_etrs89_threaded(longitudes: Array, latitudes: Array) -> ResultTuple {
    convert_to_etrs89_threaded_vec(longitudes.into(), latitudes.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_etrs89_to_osgb36`](fn.convert_etrs89_to_osgb36.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_etrs89_to_osgb36_threaded(
    eastings: Array,
    northings: Array,
) -> ResultTuple {
    convert_etrs89_to_osgb36_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_etrs89_to_ll`](fn.convert_etrs89_to_ll.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_etrs89_to_ll_threaded(eastings: Array, northings: Array) -> ResultTuple {
    convert_etrs89_to_ll_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_osgb36_to_ll`](fn.convert_osgb36_to_ll.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_osgb36_to_ll_threaded(eastings: Array, northings: Array) -> ResultTuple {
    convert_osgb36_to_ll_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_osgb36_to_etrs89`](fn.convert_osgb36_to_etrs89.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_osgb36_to_etrs89_threaded(
    eastings: Array,
    northings: Array,
) -> ResultTuple {
    convert_osgb36_to_etrs89_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_epsg3857_to_wgs84`](fn.convert_epsg3857_to_wgs84.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_epsg3857_to_wgs84_threaded(x: Array, y: Array) -> ResultTuple {
    convert_epsg3857_to_wgs84_threaded_vec(x.into(), y.into()).into()
}
<commit_msg>Fix up docs<commit_after>use std::slice;

use libc::c_void;

#[repr(C)]
pub struct Array {
    pub data: *const c_void,
    pub len: libc::size_t,
}

/// A simple struct that can be leaked across the FFI boundary in lieu of an actual tuple
#[repr(C)]
pub struct ResultTuple {
    pub e: Array,
    pub n: Array,
}

use super::convert_epsg3857_to_wgs84_threaded_vec;
use super::convert_etrs89_to_ll_threaded_vec;
use super::convert_etrs89_to_osgb36_threaded_vec;
use super::convert_osgb36_to_etrs89_threaded_vec;
use super::convert_osgb36_to_ll_threaded_vec;
use super::convert_to_bng_threaded_vec;
use super::convert_to_etrs89_threaded_vec;
use super::convert_to_lonlat_threaded_vec;
use super::convert_to_osgb36_threaded_vec;

/// Free memory which Rust has allocated across the FFI boundary (f64 values)
///
/// # Examples
///
/// ```
/// # use libc;
/// let lon_vec: Vec<f64> = vec![-2.0183041005533306];
/// let lat_vec: Vec<f64> = vec![54.589097162646141];
/// let lon_arr = Array {
///     data: lon_vec.as_ptr() as *const libc::c_void,
///     len: lon_vec.len() as libc::size_t,
/// };
/// let lat_arr = Array {
///     data: lat_vec.as_ptr() as *const libc::c_void,
///     len: lat_vec.len() as libc::size_t,
/// };
/// let rtp = convert_to_bng_threaded(lon_arr, lat_arr);
/// drop_float_array(rtp.e, rtp.n);
/// ```
/// An example FFI implementation is available at [Convertbng](https://github.com/urschrei/convertbng/blob/master/convertbng/util.py), specifically in the `_void_array_to_list` function.
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn drop_float_array(lons: Array, lats: Array) {
    if lons.data.is_null() {
        return;
    }
    if lats.data.is_null() {
        return;
    }
    let _: &mut [f64] = lons.into();
    let _: &mut [f64] = lats.into();
}

// Build an Array from &mut[T], so it can be leaked across the FFI boundary
impl<'a, T> From<&'a mut [T]> for Array {
    fn from(sl: &mut [T]) -> Self {
        Array {
            data: sl.as_ptr() as *const libc::c_void,
            len: sl.len() as libc::size_t,
        }
    }
}

// Build &mut[f64] from an Array, so it can be dropped
impl<'a> From<Array> for &'a mut [f64] {
    fn from(arr: Array) -> Self {
        unsafe { slice::from_raw_parts_mut(arr.data as *mut f64, arr.len) }
    }
}

// Slice tuple to ResultTuple
impl<T> From<(T, T)> for ResultTuple
where
    T: Into<Array>,
{
    fn from(tup: (T, T)) -> Self {
        ResultTuple {
            e: tup.0.into(),
            n: tup.1.into(),
        }
    }
}

/// A threaded, FFI-compatible wrapper for `lonlat_bng::convert_osgb36`
///
/// # Examples
///
/// ```
/// use libc;
/// let lon_vec: Vec<f64> = vec![-2.0183041005533306,
///                              0.95511887434519682,
///                              0.44975855518383501,
///                              -0.096813621191803811,
///                              -0.36807065656416427,
///                              0.63486335458665621];
/// let lat_vec: Vec<f64> = vec![54.589097162646141,
///                              51.560873800587828,
///                              50.431429161121699,
///                              54.535021436247419,
///                              50.839059313135706,
///                              55.412189281234419];
/// let lon_arr = Array {
///     data: lon_vec.as_ptr() as *const libc::c_void,
///     len: lon_vec.len() as libc::size_t,
/// };
/// let lat_arr = Array {
///     data: lat_vec.as_ptr() as *const libc::c_void,
///     len: lat_vec.len() as libc::size_t,
/// };
/// let rtp = convert_to_bng_threaded(lon_arr, lat_arr);
/// ```
/// For an FFI implementation, see the code at [Convertbng](https://github.com/urschrei/convertbng/blob/master/convertbng/util.py).
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_to_bng_threaded(longitudes: Array, latitudes: Array) -> ResultTuple {
    convert_to_bng_threaded_vec(longitudes.into(), latitudes.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_osgb36_to_ll`](fn.convert_osgb36_to_ll.html)
///
/// # Examples
///
/// See [`lonlat_bng::convert_to_bng_threaded`](fn.convert_to_bng_threaded.html)
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_to_lonlat_threaded(eastings: Array, northings: Array) -> ResultTuple {
    convert_to_lonlat_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_osgb36`](fn.convert_osgb36.html)
///
/// # Examples
///
/// See [`lonlat_bng::convert_to_bng_threaded`](fn.convert_to_bng_threaded.html) for examples, substituting f64 vectors
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_to_osgb36_threaded(longitudes: Array, latitudes: Array) -> ResultTuple {
    convert_to_osgb36_threaded_vec(longitudes.into(), latitudes.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_etrs89`](fn.convert_etrs89.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples, substituting f64 vectors
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_to_etrs89_threaded(longitudes: Array, latitudes: Array) -> ResultTuple {
    convert_to_etrs89_threaded_vec(longitudes.into(), latitudes.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_etrs89_to_osgb36`](fn.convert_etrs89_to_osgb36.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_etrs89_to_osgb36_threaded(
    eastings: Array,
    northings: Array,
) -> ResultTuple {
    convert_etrs89_to_osgb36_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_etrs89_to_ll`](fn.convert_etrs89_to_ll.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_etrs89_to_ll_threaded(eastings: Array, northings: Array) -> ResultTuple {
    convert_etrs89_to_ll_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_osgb36_to_ll`](fn.convert_osgb36_to_ll.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_osgb36_to_ll_threaded(eastings: Array, northings: Array) -> ResultTuple {
    convert_osgb36_to_ll_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_osgb36_to_etrs89`](fn.convert_osgb36_to_etrs89.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_osgb36_to_etrs89_threaded(
    eastings: Array,
    northings: Array,
) -> ResultTuple {
    convert_osgb36_to_etrs89_threaded_vec(eastings.into(), northings.into()).into()
}

/// A threaded, FFI-compatible wrapper for [`lonlat_bng::convert_epsg3857_to_wgs84`](fn.convert_epsg3857_to_wgs84.html)
///
/// # Examples
///
/// See `lonlat_bng::convert_to_bng_threaded` for examples
///
/// # Safety
///
/// This function is unsafe because it accesses a raw pointer which could contain arbitrary data
#[no_mangle]
pub extern "C" fn convert_epsg3857_to_wgs84_threaded(x: Array, y: Array) -> ResultTuple {
    convert_epsg3857_to_wgs84_threaded_vec(x.into(), y.into()).into()
}
<|endoftext|>


<commit_before>use byteorder::{BigEndian, ByteOrder};
use aes;
use ghash;

pub struct GCM {
    cipher: aes::AES,
    hash_key: [u8; 16],
}

impl GCM {
    pub fn new(key: &[u8]) -> Self {
        let cipher = aes::AES::new(key);
        let hash_key = cipher.cipher(&[0; 16]);
        Self {
            cipher: cipher,
            hash_key: hash_key,
        }
    }

    pub fn auth_encrypt(&self, message: &[u8], data: &[u8], nonce: &[u8]) -> (Vec<u8>, [u8; 16]) {
        assert!(1 << 39 >= message.len() + 256);
        let y0 = self.get_y0(nonce);
        let ciphertext = self.encrypt(&message, &y0);
        let tag = self.tag(&ciphertext, data, &y0);
        (ciphertext, tag)
    }

    fn get_y0(&self, nonce: &[u8]) -> [u8; 16] {
        let mut y0;
        if nonce.len() == 12 {
            y0 = [0; 16];
            y0[..12].copy_from_slice(nonce);
            y0[15] = 1;
        } else {
            y0 = ghash::ghash(&self.hash_key, &[], nonce);
        }
        y0
    }

    fn encrypt(&self, message: &[u8], y0: &[u8; 16]) -> Vec<u8> {
        let mut ciphertext = vec![];
        let y = (&y0[..12], BigEndian::read_u32(&y0[12..]));
        for (i, mi) in (1..).zip(message.chunks(16)) {
            let yi = Self::incr(y, i);
            ciphertext.extend(mi.iter().zip(&self.cipher.cipher(&yi)).map(|(x, y)| x ^ y));
        }
        ciphertext.truncate(message.len());
        ciphertext
    }

    fn tag(&self, ciphertext: &[u8], data: &[u8], y0: &[u8; 16]) -> [u8; 16] {
        let mut tag = ghash::ghash(&self.hash_key, data, &ciphertext);
        for (t, &x) in tag.iter_mut().zip(&self.cipher.cipher(y0)) {
            *t ^= x;
        }
        tag
    }

    fn incr((f, w): (&[u8], u32), i: u32) -> [u8; 16] {
        let mut y = [0; 16];
        y[..12].copy_from_slice(f);
        BigEndian::write_u32(&mut y[12..], w.wrapping_add(i));
        y
    }
}

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

    #[test]
    fn test_case_13_14() {
        let key = [0; 32];
        let nonce = [0; 12];
        let tag = [
            0x53,
            0x0f,
            0x8a,
            0xfb,
            0xc7,
            0x45,
            0x36,
            0xb9,
            0xa9,
            0x63,
            0xb4,
            0xf1,
            0xc4,
            0xcb,
            0x73,
            0x8b,
        ];
        let gcm = GCM::new(&key);
        assert_eq!((vec![], tag), gcm.auth_encrypt(&[], &[], &nonce));

        let message = [0; 16];
        let ciphertext = vec![
            0xce,
            0xa7,
            0x40,
            0x3d,
            0x4d,
            0x60,
            0x6b,
            0x6e,
            0x07,
            0x4e,
            0xc5,
            0xd3,
            0xba,
            0xf3,
            0x9d,
            0x18,
        ];
        let tag = [
            0xd0,
            0xd1,
            0xc8,
            0xa7,
            0x99,
            0x99,
            0x6b,
            0xf0,
            0x26,
            0x5b,
            0x98,
            0xb5,
            0xd4,
            0x8a,
            0xb9,
            0x19,
        ];
        assert_eq!((ciphertext, tag), gcm.auth_encrypt(&message, &[], &nonce));
    }

    #[test]
    fn test_case_15_16_17_18() {
        let key = [
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
        ];
        let mut message = vec![
            0xd9,
            0x31,
            0x32,
            0x25,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0xa5,
            0x59,
            0x09,
            0xc5,
            0xaf,
            0xf5,
            0x26,
            0x9a,
            0x86,
            0xa7,
            0xa9,
            0x53,
            0x15,
            0x34,
            0xf7,
            0xda,
            0x2e,
            0x4c,
            0x30,
            0x3d,
            0x8a,
            0x31,
            0x8a,
            0x72,
            0x1c,
            0x3c,
            0x0c,
            0x95,
            0x95,
            0x68,
            0x09,
            0x53,
            0x2f,
            0xcf,
            0x0e,
            0x24,
            0x49,
            0xa6,
            0xb5,
            0x25,
            0xb1,
            0x6a,
            0xed,
            0xf5,
            0xaa,
            0x0d,
            0xe6,
            0x57,
            0xba,
            0x63,
            0x7b,
            0x39,
            0x1a,
            0xaf,
            0xd2,
            0x55,
        ];
        let nonce = [
            0xca,
            0xfe,
            0xba,
            0xbe,
            0xfa,
            0xce,
            0xdb,
            0xad,
            0xde,
            0xca,
            0xf8,
            0x88,
        ];
        let mut ciphertext = vec![
            0x52,
            0x2d,
            0xc1,
            0xf0,
            0x99,
            0x56,
            0x7d,
            0x07,
            0xf4,
            0x7f,
            0x37,
            0xa3,
            0x2a,
            0x84,
            0x42,
            0x7d,
            0x64,
            0x3a,
            0x8c,
            0xdc,
            0xbf,
            0xe5,
            0xc0,
            0xc9,
            0x75,
            0x98,
            0xa2,
            0xbd,
            0x25,
            0x55,
            0xd1,
            0xaa,
            0x8c,
            0xb0,
            0x8e,
            0x48,
            0x59,
            0x0d,
            0xbb,
            0x3d,
            0xa7,
            0xb0,
            0x8b,
            0x10,
            0x56,
            0x82,
            0x88,
            0x38,
            0xc5,
            0xf6,
            0x1e,
            0x63,
            0x93,
            0xba,
            0x7a,
            0x0a,
            0xbc,
            0xc9,
            0xf6,
            0x62,
            0x89,
            0x80,
            0x15,
            0xad,
        ];
        let tag = [
            0xb0,
            0x94,
            0xda,
            0xc5,
            0xd9,
            0x34,
            0x71,
            0xbd,
            0xec,
            0x1a,
            0x50,
            0x22,
            0x70,
            0xe3,
            0xcc,
            0x6c,
        ];
        let gcm = GCM::new(&key);
        assert_eq!(
            (ciphertext.clone(), tag),
            gcm.auth_encrypt(&message, &[], &nonce)
        );

        message.truncate(60);
        ciphertext.truncate(60);
        let data = [
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xab,
            0xad,
            0xda,
            0xd2,
        ];
        let tag = [
            0x76,
            0xfc,
            0x6e,
            0xce,
            0x0f,
            0x4e,
            0x17,
            0x68,
            0xcd,
            0xdf,
            0x88,
            0x53,
            0xbb,
            0x2d,
            0x55,
            0x1b,
        ];
        assert_eq!((ciphertext, tag), gcm.auth_encrypt(&message, &data, &nonce));

        let nonce = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
        let ciphertext = vec![
            0xc3,
            0x76,
            0x2d,
            0xf1,
            0xca,
            0x78,
            0x7d,
            0x32,
            0xae,
            0x47,
            0xc1,
            0x3b,
            0xf1,
            0x98,
            0x44,
            0xcb,
            0xaf,
            0x1a,
            0xe1,
            0x4d,
            0x0b,
            0x97,
            0x6a,
            0xfa,
            0xc5,
            0x2f,
            0xf7,
            0xd7,
            0x9b,
            0xba,
            0x9d,
            0xe0,
            0xfe,
            0xb5,
            0x82,
            0xd3,
            0x39,
            0x34,
            0xa4,
            0xf0,
            0x95,
            0x4c,
            0xc2,
            0x36,
            0x3b,
            0xc7,
            0x3f,
            0x78,
            0x62,
            0xac,
            0x43,
            0x0e,
            0x64,
            0xab,
            0xe4,
            0x99,
            0xf4,
            0x7c,
            0x9b,
            0x1f,
        ];
        let tag = [
            0x3a,
            0x33,
            0x7d,
            0xbf,
            0x46,
            0xa7,
            0x92,
            0xc4,
            0x5e,
            0x45,
            0x49,
            0x13,
            0xfe,
            0x2e,
            0xa8,
            0xf2,
        ];
        assert_eq!((ciphertext, tag), gcm.auth_encrypt(&message, &data, &nonce));

        let nonce = [
            0x93,
            0x13,
            0x22,
            0x5d,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0x55,
            0x90,
            0x9c,
            0x5a,
            0xff,
            0x52,
            0x69,
            0xaa,
            0x6a,
            0x7a,
            0x95,
            0x38,
            0x53,
            0x4f,
            0x7d,
            0xa1,
            0xe4,
            0xc3,
            0x03,
            0xd2,
            0xa3,
            0x18,
            0xa7,
            0x28,
            0xc3,
            0xc0,
            0xc9,
            0x51,
            0x56,
            0x80,
            0x95,
            0x39,
            0xfc,
            0xf0,
            0xe2,
            0x42,
            0x9a,
            0x6b,
            0x52,
            0x54,
            0x16,
            0xae,
            0xdb,
            0xf5,
            0xa0,
            0xde,
            0x6a,
            0x57,
            0xa6,
            0x37,
            0xb3,
            0x9b,
        ];
        let ciphertext = vec![
            0x5a,
            0x8d,
            0xef,
            0x2f,
            0x0c,
            0x9e,
            0x53,
            0xf1,
            0xf7,
            0x5d,
            0x78,
            0x53,
            0x65,
            0x9e,
            0x2a,
            0x20,
            0xee,
            0xb2,
            0xb2,
            0x2a,
            0xaf,
            0xde,
            0x64,
            0x19,
            0xa0,
            0x58,
            0xab,
            0x4f,
            0x6f,
            0x74,
            0x6b,
            0xf4,
            0x0f,
            0xc0,
            0xc3,
            0xb7,
            0x80,
            0xf2,
            0x44,
            0x45,
            0x2d,
            0xa3,
            0xeb,
            0xf1,
            0xc5,
            0xd8,
            0x2c,
            0xde,
            0xa2,
            0x41,
            0x89,
            0x97,
            0x20,
            0x0e,
            0xf8,
            0x2e,
            0x44,
            0xae,
            0x7e,
            0x3f,
        ];
        let tag = [
            0xa4,
            0x4a,
            0x82,
            0x66,
            0xee,
            0x1c,
            0x8e,
            0xb0,
            0xc8,
            0xb5,
            0xd4,
            0xcf,
            0x5a,
            0xe9,
            0xf1,
            0x9a,
        ];
        assert_eq!((ciphertext, tag), gcm.auth_encrypt(&message, &data, &nonce));
    }
}
<commit_msg>gcm: add authenticated decryption<commit_after>use byteorder::{BigEndian, ByteOrder};
use aes;
use ghash;

pub struct GCM {
    cipher: aes::AES,
    hash_key: [u8; 16],
}

impl GCM {
    pub fn new(key: &[u8]) -> Self {
        let cipher = aes::AES::new(key);
        let hash_key = cipher.cipher(&[0; 16]);
        Self {
            cipher: cipher,
            hash_key: hash_key,
        }
    }

    pub fn auth_encrypt(&self, message: &[u8], data: &[u8], nonce: &[u8]) -> (Vec<u8>, [u8; 16]) {
        assert!(1 << 39 >= message.len() + 256);
        let y0 = self.get_y0(nonce);
        let ciphertext = self.encrypt(&message, &y0);
        let tag = self.tag(&ciphertext, data, &y0);
        (ciphertext, tag)
    }

    pub fn auth_decrypt(
        &self,
        ciphertext: &[u8],
        tag: &[u8],
        data: &[u8],
        nonce: &[u8],
    ) -> Result<Vec<u8>, ()> {
        assert_eq!(16, tag.len());
        let y0 = self.get_y0(nonce);
        self.check_tag(ciphertext, data, &y0, tag)?;
        let message = self.encrypt(&ciphertext, &y0);
        Ok(message)
    }

    fn get_y0(&self, nonce: &[u8]) -> [u8; 16] {
        let mut y0;
        if nonce.len() == 12 {
            y0 = [0; 16];
            y0[..12].copy_from_slice(nonce);
            y0[15] = 1;
        } else {
            y0 = ghash::ghash(&self.hash_key, &[], nonce);
        }
        y0
    }

    fn encrypt(&self, message: &[u8], y0: &[u8; 16]) -> Vec<u8> {
        let mut ciphertext = vec![];
        let y = (&y0[..12], BigEndian::read_u32(&y0[12..]));
        for (i, mi) in (1..).zip(message.chunks(16)) {
            let yi = Self::incr(y, i);
            ciphertext.extend(mi.iter().zip(&self.cipher.cipher(&yi)).map(|(x, y)| x ^ y));
        }
        ciphertext.truncate(message.len());
        ciphertext
    }

    fn tag(&self, ciphertext: &[u8], data: &[u8], y0: &[u8; 16]) -> [u8; 16] {
        let mut tag = ghash::ghash(&self.hash_key, data, &ciphertext);
        for (t, &x) in tag.iter_mut().zip(&self.cipher.cipher(y0)) {
            *t ^= x;
        }
        tag
    }

    fn check_tag(
        &self,
        ciphertext: &[u8],
        data: &[u8],
        y0: &[u8; 16],
        tag: &[u8],
    ) -> Result<(), ()> {
        let expected = self.tag(ciphertext, data, y0);
        let valid = expected.iter().zip(tag).fold(
            true,
            |acc, (x, y)| acc && x == y,
        );
        if valid { Ok(()) } else { Err(()) }
    }
    fn incr((f, w): (&[u8], u32), i: u32) -> [u8; 16] {
        let mut y = [0; 16];
        y[..12].copy_from_slice(f);
        BigEndian::write_u32(&mut y[12..], w.wrapping_add(i));
        y
    }
}

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

    #[test]
    fn test_case_13_14() {
        let key = [0; 32];
        let message = vec![];
        let nonce = [0; 12];
        let tag = [
            0x53,
            0x0f,
            0x8a,
            0xfb,
            0xc7,
            0x45,
            0x36,
            0xb9,
            0xa9,
            0x63,
            0xb4,
            0xf1,
            0xc4,
            0xcb,
            0x73,
            0x8b,
        ];
        let gcm = GCM::new(&key);
        assert_eq!((vec![], tag), gcm.auth_encrypt(&message, &[], &nonce));
        assert_eq!(message, gcm.auth_decrypt(&[], &tag, &[], &nonce).unwrap());

        let message = vec![0; 16];
        let ciphertext = vec![
            0xce,
            0xa7,
            0x40,
            0x3d,
            0x4d,
            0x60,
            0x6b,
            0x6e,
            0x07,
            0x4e,
            0xc5,
            0xd3,
            0xba,
            0xf3,
            0x9d,
            0x18,
        ];
        let tag = [
            0xd0,
            0xd1,
            0xc8,
            0xa7,
            0x99,
            0x99,
            0x6b,
            0xf0,
            0x26,
            0x5b,
            0x98,
            0xb5,
            0xd4,
            0x8a,
            0xb9,
            0x19,
        ];
        let actual = gcm.auth_encrypt(&message, &[], &nonce);
        assert_eq!(ciphertext, actual.0);
        assert_eq!(tag, actual.1);
        assert_eq!(
            message,
            gcm.auth_decrypt(&ciphertext, &tag, &[], &nonce).unwrap()
        );
    }

    #[test]
    fn test_case_15_16_17_18() {
        let key = [
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
            0xfe,
            0xff,
            0xe9,
            0x92,
            0x86,
            0x65,
            0x73,
            0x1c,
            0x6d,
            0x6a,
            0x8f,
            0x94,
            0x67,
            0x30,
            0x83,
            0x08,
        ];
        let mut message = vec![
            0xd9,
            0x31,
            0x32,
            0x25,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0xa5,
            0x59,
            0x09,
            0xc5,
            0xaf,
            0xf5,
            0x26,
            0x9a,
            0x86,
            0xa7,
            0xa9,
            0x53,
            0x15,
            0x34,
            0xf7,
            0xda,
            0x2e,
            0x4c,
            0x30,
            0x3d,
            0x8a,
            0x31,
            0x8a,
            0x72,
            0x1c,
            0x3c,
            0x0c,
            0x95,
            0x95,
            0x68,
            0x09,
            0x53,
            0x2f,
            0xcf,
            0x0e,
            0x24,
            0x49,
            0xa6,
            0xb5,
            0x25,
            0xb1,
            0x6a,
            0xed,
            0xf5,
            0xaa,
            0x0d,
            0xe6,
            0x57,
            0xba,
            0x63,
            0x7b,
            0x39,
            0x1a,
            0xaf,
            0xd2,
            0x55,
        ];
        let nonce = [
            0xca,
            0xfe,
            0xba,
            0xbe,
            0xfa,
            0xce,
            0xdb,
            0xad,
            0xde,
            0xca,
            0xf8,
            0x88,
        ];
        let mut ciphertext = vec![
            0x52,
            0x2d,
            0xc1,
            0xf0,
            0x99,
            0x56,
            0x7d,
            0x07,
            0xf4,
            0x7f,
            0x37,
            0xa3,
            0x2a,
            0x84,
            0x42,
            0x7d,
            0x64,
            0x3a,
            0x8c,
            0xdc,
            0xbf,
            0xe5,
            0xc0,
            0xc9,
            0x75,
            0x98,
            0xa2,
            0xbd,
            0x25,
            0x55,
            0xd1,
            0xaa,
            0x8c,
            0xb0,
            0x8e,
            0x48,
            0x59,
            0x0d,
            0xbb,
            0x3d,
            0xa7,
            0xb0,
            0x8b,
            0x10,
            0x56,
            0x82,
            0x88,
            0x38,
            0xc5,
            0xf6,
            0x1e,
            0x63,
            0x93,
            0xba,
            0x7a,
            0x0a,
            0xbc,
            0xc9,
            0xf6,
            0x62,
            0x89,
            0x80,
            0x15,
            0xad,
        ];
        let tag = [
            0xb0,
            0x94,
            0xda,
            0xc5,
            0xd9,
            0x34,
            0x71,
            0xbd,
            0xec,
            0x1a,
            0x50,
            0x22,
            0x70,
            0xe3,
            0xcc,
            0x6c,
        ];
        let gcm = GCM::new(&key);
        let actual = gcm.auth_encrypt(&message, &[], &nonce);
        assert_eq!(ciphertext, actual.0);
        assert_eq!(tag, actual.1);
        assert_eq!(
            message,
            gcm.auth_decrypt(&ciphertext, &tag, &[], &nonce).unwrap()
        );

        message.truncate(60);
        ciphertext.truncate(60);
        let data = [
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xfe,
            0xed,
            0xfa,
            0xce,
            0xde,
            0xad,
            0xbe,
            0xef,
            0xab,
            0xad,
            0xda,
            0xd2,
        ];
        let tag = [
            0x76,
            0xfc,
            0x6e,
            0xce,
            0x0f,
            0x4e,
            0x17,
            0x68,
            0xcd,
            0xdf,
            0x88,
            0x53,
            0xbb,
            0x2d,
            0x55,
            0x1b,
        ];
        let actual = gcm.auth_encrypt(&message, &data, &nonce);
        assert_eq!(ciphertext, actual.0);
        assert_eq!(tag, actual.1);
        assert_eq!(
            message,
            gcm.auth_decrypt(&ciphertext, &tag, &data, &nonce).unwrap()
        );

        let nonce = [0xca, 0xfe, 0xba, 0xbe, 0xfa, 0xce, 0xdb, 0xad];
        let ciphertext = vec![
            0xc3,
            0x76,
            0x2d,
            0xf1,
            0xca,
            0x78,
            0x7d,
            0x32,
            0xae,
            0x47,
            0xc1,
            0x3b,
            0xf1,
            0x98,
            0x44,
            0xcb,
            0xaf,
            0x1a,
            0xe1,
            0x4d,
            0x0b,
            0x97,
            0x6a,
            0xfa,
            0xc5,
            0x2f,
            0xf7,
            0xd7,
            0x9b,
            0xba,
            0x9d,
            0xe0,
            0xfe,
            0xb5,
            0x82,
            0xd3,
            0x39,
            0x34,
            0xa4,
            0xf0,
            0x95,
            0x4c,
            0xc2,
            0x36,
            0x3b,
            0xc7,
            0x3f,
            0x78,
            0x62,
            0xac,
            0x43,
            0x0e,
            0x64,
            0xab,
            0xe4,
            0x99,
            0xf4,
            0x7c,
            0x9b,
            0x1f,
        ];
        let tag = [
            0x3a,
            0x33,
            0x7d,
            0xbf,
            0x46,
            0xa7,
            0x92,
            0xc4,
            0x5e,
            0x45,
            0x49,
            0x13,
            0xfe,
            0x2e,
            0xa8,
            0xf2,
        ];
        let actual = gcm.auth_encrypt(&message, &data, &nonce);
        assert_eq!(ciphertext, actual.0);
        assert_eq!(tag, actual.1);
        assert_eq!(
            message,
            gcm.auth_decrypt(&ciphertext, &tag, &data, &nonce).unwrap()
        );

        let nonce = [
            0x93,
            0x13,
            0x22,
            0x5d,
            0xf8,
            0x84,
            0x06,
            0xe5,
            0x55,
            0x90,
            0x9c,
            0x5a,
            0xff,
            0x52,
            0x69,
            0xaa,
            0x6a,
            0x7a,
            0x95,
            0x38,
            0x53,
            0x4f,
            0x7d,
            0xa1,
            0xe4,
            0xc3,
            0x03,
            0xd2,
            0xa3,
            0x18,
            0xa7,
            0x28,
            0xc3,
            0xc0,
            0xc9,
            0x51,
            0x56,
            0x80,
            0x95,
            0x39,
            0xfc,
            0xf0,
            0xe2,
            0x42,
            0x9a,
            0x6b,
            0x52,
            0x54,
            0x16,
            0xae,
            0xdb,
            0xf5,
            0xa0,
            0xde,
            0x6a,
            0x57,
            0xa6,
            0x37,
            0xb3,
            0x9b,
        ];
        let ciphertext = vec![
            0x5a,
            0x8d,
            0xef,
            0x2f,
            0x0c,
            0x9e,
            0x53,
            0xf1,
            0xf7,
            0x5d,
            0x78,
            0x53,
            0x65,
            0x9e,
            0x2a,
            0x20,
            0xee,
            0xb2,
            0xb2,
            0x2a,
            0xaf,
            0xde,
            0x64,
            0x19,
            0xa0,
            0x58,
            0xab,
            0x4f,
            0x6f,
            0x74,
            0x6b,
            0xf4,
            0x0f,
            0xc0,
            0xc3,
            0xb7,
            0x80,
            0xf2,
            0x44,
            0x45,
            0x2d,
            0xa3,
            0xeb,
            0xf1,
            0xc5,
            0xd8,
            0x2c,
            0xde,
            0xa2,
            0x41,
            0x89,
            0x97,
            0x20,
            0x0e,
            0xf8,
            0x2e,
            0x44,
            0xae,
            0x7e,
            0x3f,
        ];
        let tag = [
            0xa4,
            0x4a,
            0x82,
            0x66,
            0xee,
            0x1c,
            0x8e,
            0xb0,
            0xc8,
            0xb5,
            0xd4,
            0xcf,
            0x5a,
            0xe9,
            0xf1,
            0x9a,
        ];
        let actual = gcm.auth_encrypt(&message, &data, &nonce);
        assert_eq!(ciphertext, actual.0);
        assert_eq!(tag, actual.1);
        assert_eq!(
            message,
            gcm.auth_decrypt(&ciphertext, &tag, &data, &nonce).unwrap()
        );
    }
}
<|endoftext|>


<commit_before>//!  Decoding of GIF Images
//!
//!  GIF (Graphics Interchange Format) is an image format that supports lossless compression.
//!
//!  # Related Links
//!  * <http://www.w3.org/Graphics/GIF/spec-gif89a.txt> - The GIF Specification
//!
//! # Examples
//! ```rust,no_run
//! use image::gif::{Decoder, Encoder};
//! use image::{ImageDecoder, AnimationDecoder};
//! use std::fs::File;
//! # fn main() -> std::io::Result<()> {
//! // Decode a gif into frames
//! let file_in = File::open("foo.gif")?;
//! let mut decoder = Decoder::new(file_in).unwrap();
//! let frames = decoder.into_frames();
//! let frames = frames.collect_frames().expect("error decoding gif");
//!
//! // Encode frames into a gif and save to a file
//! let mut file_out = File::open("out.gif")?;
//! let mut encoder = Encoder::new(file_out);
//! encoder.encode_frames(frames.into_iter());
//! # Ok(())
//! # }
//! ```
#![cfg_attr(feature = "cargo-clippy", allow(while_let_loop))]

extern crate gif;
extern crate num_rational;

use std::clone::Clone;
use std::cmp::min;
use std::io::{self, Cursor, Read, Write};
use std::marker::PhantomData;
use std::mem;

use self::gif::{ColorOutput, SetParameter};
pub use self::gif::{DisposalMethod, Frame};

use animation;
use buffer::{ImageBuffer, Pixel};
use color;
use color::Rgba;
use image::{AnimationDecoder, ImageDecoder, ImageError, ImageResult};
use num_rational::Ratio;

/// GIF decoder
pub struct Decoder<R: Read> {
    reader: gif::Reader<R>,
}

impl<R: Read> Decoder<R> {
    /// Creates a new decoder that decodes the input steam ```r```
    pub fn new(r: R) -> ImageResult<Decoder<R>> {
        let mut decoder = gif::Decoder::new(r);
        decoder.set(ColorOutput::RGBA);

        Ok(Decoder {
            reader: decoder.read_info()?,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for GifReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for Decoder<R> {
    type Reader = GifReader<R>;

    fn dimensions(&self) -> (u64, u64) {
        (self.reader.width() as u64, self.reader.height() as u64)
    }

    fn colortype(&self) -> color::ColorType {
        color::ColorType::RGBA(8)
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(GifReader(Cursor::new(self.read_image()?), PhantomData))
    }

    fn read_image(mut self) -> ImageResult<Vec<u8>> {
        let (f_width, f_height, left, top);

        if let Some(frame) = self.reader.next_frame_info()? {
            left = u32::from(frame.left);
            top = u32::from(frame.top);
            f_width = u32::from(frame.width);
            f_height = u32::from(frame.height);
        } else {
            return Err(ImageError::ImageEnd);
        }

        let mut buf = vec![0; self.reader.buffer_size()];
        self.reader.read_into_buffer(&mut buf)?;

        let image_buffer_raw = ImageBuffer::from_raw(f_width, f_height, buf).unwrap();

        // Recover the full image
        let (width, height) = (self.reader.width() as u32, self.reader.height() as u32);
        let image_buffer = full_image_from_frame(width, height, image_buffer_raw, left, top);

        Ok(image_buffer.into_raw())
    }
}

struct GifFrameIterator<R: Read> {
    reader: gif::Reader<R>,

    width: u32,
    height: u32,

    non_disposed_frame: ImageBuffer<Rgba<u8>, Vec<u8>>,
}

impl<R: Read> GifFrameIterator<R> {
    fn new(decoder: Decoder<R>) -> GifFrameIterator<R> {
        let (width, height) = decoder.dimensions();

        // TODO: Avoid this cast
        let (width, height) = (width as u32, height as u32);

        // intentionally ignore the background color for web compatibility

        // create the first non disposed frame
        let non_disposed_frame = ImageBuffer::from_pixel(width, height, Rgba([0, 0, 0, 0]));

        GifFrameIterator {
            reader: decoder.reader,
            width,
            height,
            non_disposed_frame,
        }
    }
}

impl<R: Read> Iterator for GifFrameIterator<R> {
    type Item = ImageResult<animation::Frame>;

    fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
        // begin looping over each frame
        let (left, top, delay, dispose, f_width, f_height);

        match self.reader.next_frame_info() {
            Ok(frame_info) => {
                if let Some(frame) = frame_info {
                    left = u32::from(frame.left);
                    top = u32::from(frame.top);
                    f_width = u32::from(frame.width);
                    f_height = u32::from(frame.height);

                    // frame.delay is in units of 10ms so frame.delay*10 is in ms
                    delay = Ratio::new(frame.delay * 10, 1);
                    dispose = frame.dispose;
                } else {
                    // no more frames
                    return None;
                }
            },
            Err(err) => return Some(Err(err.into())),
        }

        let mut vec = vec![0; self.reader.buffer_size()];
        if let Err(err) = self.reader.fill_buffer(&mut vec) {
            return Some(Err(err.into()));
        }

        // create the image buffer from the raw frame
        let image_buffer_raw = ImageBuffer::from_raw(f_width, f_height, vec).unwrap();

        // if `image_buffer_raw`'s frame exactly matches the entire image, then
        // use it directly.
        //
        // otherwise, `image_buffer_raw` represents a smaller image.
        // create a new image of the target size and place
        // `image_buffer_raw` within it. the outside region is filled with
        // transparent pixels.
        let mut image_buffer =
            full_image_from_frame(self.width, self.height, image_buffer_raw, left, top);

        // loop over all pixels, checking if any pixels from the non disposed
        // frame need to be used
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let previous_img_buffer = &self.non_disposed_frame;
            let adjusted_pixel: &mut Rgba<u8> = pixel;
            let previous_pixel: &Rgba<u8> = previous_img_buffer.get_pixel(x, y);

            let pixel_alpha = adjusted_pixel.channels()[3];

            // If a pixel is not visible then we show the non disposed frame pixel instead
            if pixel_alpha == 0 {
                adjusted_pixel.blend(previous_pixel);
            }
        }

        let frame = animation::Frame::from_parts(
            image_buffer.clone(), 0, 0, delay
        );

        match dispose {
            DisposalMethod::Any => {
                // do nothing
                // (completely replace this frame with the next)
            }
            DisposalMethod::Keep => {
                // do not dispose
                // (keep pixels from this frame)
                self.non_disposed_frame = image_buffer;
            }
            DisposalMethod::Background => {
                // restore to background color
                // (background shows through transparent pixels in the next frame)
                for y in top..min(top + f_height, self.height) {
                    for x in left..min(left + f_width, self.width) {
                        self.non_disposed_frame.put_pixel(x, y, Rgba([0, 0, 0, 0]));
                    }
                }
            }
            DisposalMethod::Previous => {
                // restore to previous
                // (dispose frames leaving the last none disposal frame)
            }
        };

        Some(Ok(frame))
    }
}

/// Given a frame subimage, construct a full image of size
/// `(screen_width, screen_height)` by placing it at the top-left coordinates
/// `(left, top)`. The remaining portion is filled with transparent pixels.
fn full_image_from_frame(
    screen_width: u32,
    screen_height: u32,
    image: crate::RgbaImage,
    left: u32,
    top: u32,
) -> crate::RgbaImage {
    if (left, top) == (0, 0) && (screen_width, screen_height) == (image.width(), image.height()) {
        image
    } else {
        ImageBuffer::from_fn(screen_width, screen_height, |x, y| {
            let x = x.wrapping_sub(left);
            let y = y.wrapping_sub(top);
            if x < image.width() && y < image.height() {
                *image.get_pixel(x, y)
            } else {
                Rgba([0, 0, 0, 0])
            }
        })
    }
}

impl<'a, R: Read + 'a> AnimationDecoder<'a> for Decoder<R> {
    fn into_frames(self) -> animation::Frames<'a> {
        animation::Frames::new(Box::new(GifFrameIterator::new(self)))
    }
}

/// GIF encoder.
pub struct Encoder<W: Write> {
    w: Option<W>,
    gif_encoder: Option<gif::Encoder<W>>,
}

impl<W: Write> Encoder<W> {
    /// Creates a new GIF encoder.
    pub fn new(w: W) -> Encoder<W> {
        Encoder {
            w: Some(w),
            gif_encoder: None,
        }
    }
    /// Encodes a frame.
    pub fn encode(&mut self, frame: &Frame) -> ImageResult<()> {
        let result;
        if let Some(ref mut encoder) = self.gif_encoder {
            result = encoder.write_frame(frame).map_err(|err| err.into());
        } else {
            let writer = self.w.take().unwrap();
            let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])?;
            result = encoder.write_frame(&frame).map_err(|err| err.into());
            self.gif_encoder = Some(encoder);
        }
        result
    }

    /// Encodes Frames.
    /// Consider using `try_encode_frames` instead to encode an `animation::Frames` like iterator.
    pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = animation::Frame>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame)?;
        }
        Ok(())
    }

    /// Try to encode a collection of `ImageResult<animation::Frame>` objects.
    /// Use this function to encode an `animation::Frames` like iterator.
    /// Whenever an `Err` item is encountered, that value is returned without further actions.
    pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = ImageResult<animation::Frame>>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame?)?;
        }
        Ok(())
    }

    fn encode_single_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
        // get the delay before converting img_frame
        let frame_delay = img_frame.delay().to_integer();
        // convert img_frame into RgbaImage
        let rbga_frame = img_frame.into_buffer();

        // Create the gif::Frame from the animation::Frame
        let mut frame = Frame::from_rgba(rbga_frame.width() as u16, rbga_frame.height() as u16, &mut rbga_frame.into_raw());
        frame.delay = frame_delay;

        // encode the gif::Frame
        self.encode(&frame)
    }
}

impl From<gif::DecodingError> for ImageError {
    fn from(err: gif::DecodingError) -> ImageError {
        use self::gif::DecodingError::*;
        match err {
            Format(desc) | Internal(desc) => ImageError::FormatError(desc.into()),
            Io(io_err) => ImageError::IoError(io_err),
        }
    }
}
<commit_msg>gif: Return an error instead of panicking on buffer size overflow<commit_after>//!  Decoding of GIF Images
//!
//!  GIF (Graphics Interchange Format) is an image format that supports lossless compression.
//!
//!  # Related Links
//!  * <http://www.w3.org/Graphics/GIF/spec-gif89a.txt> - The GIF Specification
//!
//! # Examples
//! ```rust,no_run
//! use image::gif::{Decoder, Encoder};
//! use image::{ImageDecoder, AnimationDecoder};
//! use std::fs::File;
//! # fn main() -> std::io::Result<()> {
//! // Decode a gif into frames
//! let file_in = File::open("foo.gif")?;
//! let mut decoder = Decoder::new(file_in).unwrap();
//! let frames = decoder.into_frames();
//! let frames = frames.collect_frames().expect("error decoding gif");
//!
//! // Encode frames into a gif and save to a file
//! let mut file_out = File::open("out.gif")?;
//! let mut encoder = Encoder::new(file_out);
//! encoder.encode_frames(frames.into_iter());
//! # Ok(())
//! # }
//! ```
#![cfg_attr(feature = "cargo-clippy", allow(while_let_loop))]

extern crate gif;
extern crate num_rational;

use std::clone::Clone;
use std::cmp::min;
use std::io::{self, Cursor, Read, Write};
use std::marker::PhantomData;
use std::mem;

use self::gif::{ColorOutput, SetParameter};
pub use self::gif::{DisposalMethod, Frame};

use animation;
use buffer::{ImageBuffer, Pixel};
use color;
use color::Rgba;
use image::{AnimationDecoder, ImageDecoder, ImageError, ImageResult};
use num_rational::Ratio;

/// GIF decoder
pub struct Decoder<R: Read> {
    reader: gif::Reader<R>,
}

impl<R: Read> Decoder<R> {
    /// Creates a new decoder that decodes the input steam ```r```
    pub fn new(r: R) -> ImageResult<Decoder<R>> {
        let mut decoder = gif::Decoder::new(r);
        decoder.set(ColorOutput::RGBA);

        Ok(Decoder {
            reader: decoder.read_info()?,
        })
    }
}

/// Wrapper struct around a `Cursor<Vec<u8>>`
pub struct GifReader<R>(Cursor<Vec<u8>>, PhantomData<R>);
impl<R> Read for GifReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.0.read(buf)
    }
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        if self.0.position() == 0 && buf.is_empty() {
            mem::swap(buf, self.0.get_mut());
            Ok(buf.len())
        } else {
            self.0.read_to_end(buf)
        }
    }
}

impl<'a, R: 'a + Read> ImageDecoder<'a> for Decoder<R> {
    type Reader = GifReader<R>;

    fn dimensions(&self) -> (u64, u64) {
        (self.reader.width() as u64, self.reader.height() as u64)
    }

    fn colortype(&self) -> color::ColorType {
        color::ColorType::RGBA(8)
    }

    fn into_reader(self) -> ImageResult<Self::Reader> {
        Ok(GifReader(Cursor::new(self.read_image()?), PhantomData))
    }

    fn read_image(mut self) -> ImageResult<Vec<u8>> {
        let (f_width, f_height, left, top);

        if let Some(frame) = self.reader.next_frame_info()? {
            left = u32::from(frame.left);
            top = u32::from(frame.top);
            f_width = u32::from(frame.width);
            f_height = u32::from(frame.height);
        } else {
            return Err(ImageError::ImageEnd);
        }

        let mut buf = vec![0; self.reader.buffer_size()];
        self.reader.read_into_buffer(&mut buf)?;

        // See the comments inside `<GifFrameIterator as Iterator>::next` about
        // the error handling of `from_raw`.
        let image_buffer_raw = ImageBuffer::from_raw(f_width, f_height, buf).ok_or(
            ImageError::UnsupportedError("Image dimensions are too large".into()),
        )?;

        // Recover the full image
        let (width, height) = (self.reader.width() as u32, self.reader.height() as u32);
        let image_buffer = full_image_from_frame(width, height, image_buffer_raw, left, top);

        Ok(image_buffer.into_raw())
    }
}

struct GifFrameIterator<R: Read> {
    reader: gif::Reader<R>,

    width: u32,
    height: u32,

    non_disposed_frame: ImageBuffer<Rgba<u8>, Vec<u8>>,
}

impl<R: Read> GifFrameIterator<R> {
    fn new(decoder: Decoder<R>) -> GifFrameIterator<R> {
        let (width, height) = decoder.dimensions();

        // TODO: Avoid this cast
        let (width, height) = (width as u32, height as u32);

        // intentionally ignore the background color for web compatibility

        // create the first non disposed frame
        let non_disposed_frame = ImageBuffer::from_pixel(width, height, Rgba([0, 0, 0, 0]));

        GifFrameIterator {
            reader: decoder.reader,
            width,
            height,
            non_disposed_frame,
        }
    }
}

impl<R: Read> Iterator for GifFrameIterator<R> {
    type Item = ImageResult<animation::Frame>;

    fn next(&mut self) -> Option<ImageResult<animation::Frame>> {
        // begin looping over each frame
        let (left, top, delay, dispose, f_width, f_height);

        match self.reader.next_frame_info() {
            Ok(frame_info) => {
                if let Some(frame) = frame_info {
                    left = u32::from(frame.left);
                    top = u32::from(frame.top);
                    f_width = u32::from(frame.width);
                    f_height = u32::from(frame.height);

                    // frame.delay is in units of 10ms so frame.delay*10 is in ms
                    delay = Ratio::new(frame.delay * 10, 1);
                    dispose = frame.dispose;
                } else {
                    // no more frames
                    return None;
                }
            },
            Err(err) => return Some(Err(err.into())),
        }

        let mut vec = vec![0; self.reader.buffer_size()];
        if let Err(err) = self.reader.fill_buffer(&mut vec) {
            return Some(Err(err.into()));
        }

        // create the image buffer from the raw frame.
        // `buffer_size` uses wrapping arithmetics, thus might not report the
        // correct storage requirement if the result does not fit in `usize`.
        // on the other hand, `ImageBuffer::from_raw` detects overflow and
        // reports by returning `None`.
        let image_buffer_raw = match ImageBuffer::from_raw(f_width, f_height, vec) {
            Some(image_buffer_raw) => image_buffer_raw,
            None => {
                return Some(Err(ImageError::UnsupportedError(
                    "Image dimensions are too large".into(),
                )))
            }
        };

        // if `image_buffer_raw`'s frame exactly matches the entire image, then
        // use it directly.
        //
        // otherwise, `image_buffer_raw` represents a smaller image.
        // create a new image of the target size and place
        // `image_buffer_raw` within it. the outside region is filled with
        // transparent pixels.
        let mut image_buffer =
            full_image_from_frame(self.width, self.height, image_buffer_raw, left, top);

        // loop over all pixels, checking if any pixels from the non disposed
        // frame need to be used
        for (x, y, pixel) in image_buffer.enumerate_pixels_mut() {
            let previous_img_buffer = &self.non_disposed_frame;
            let adjusted_pixel: &mut Rgba<u8> = pixel;
            let previous_pixel: &Rgba<u8> = previous_img_buffer.get_pixel(x, y);

            let pixel_alpha = adjusted_pixel.channels()[3];

            // If a pixel is not visible then we show the non disposed frame pixel instead
            if pixel_alpha == 0 {
                adjusted_pixel.blend(previous_pixel);
            }
        }

        let frame = animation::Frame::from_parts(
            image_buffer.clone(), 0, 0, delay
        );

        match dispose {
            DisposalMethod::Any => {
                // do nothing
                // (completely replace this frame with the next)
            }
            DisposalMethod::Keep => {
                // do not dispose
                // (keep pixels from this frame)
                self.non_disposed_frame = image_buffer;
            }
            DisposalMethod::Background => {
                // restore to background color
                // (background shows through transparent pixels in the next frame)
                for y in top..min(top + f_height, self.height) {
                    for x in left..min(left + f_width, self.width) {
                        self.non_disposed_frame.put_pixel(x, y, Rgba([0, 0, 0, 0]));
                    }
                }
            }
            DisposalMethod::Previous => {
                // restore to previous
                // (dispose frames leaving the last none disposal frame)
            }
        };

        Some(Ok(frame))
    }
}

/// Given a frame subimage, construct a full image of size
/// `(screen_width, screen_height)` by placing it at the top-left coordinates
/// `(left, top)`. The remaining portion is filled with transparent pixels.
fn full_image_from_frame(
    screen_width: u32,
    screen_height: u32,
    image: crate::RgbaImage,
    left: u32,
    top: u32,
) -> crate::RgbaImage {
    if (left, top) == (0, 0) && (screen_width, screen_height) == (image.width(), image.height()) {
        image
    } else {
        ImageBuffer::from_fn(screen_width, screen_height, |x, y| {
            let x = x.wrapping_sub(left);
            let y = y.wrapping_sub(top);
            if x < image.width() && y < image.height() {
                *image.get_pixel(x, y)
            } else {
                Rgba([0, 0, 0, 0])
            }
        })
    }
}

impl<'a, R: Read + 'a> AnimationDecoder<'a> for Decoder<R> {
    fn into_frames(self) -> animation::Frames<'a> {
        animation::Frames::new(Box::new(GifFrameIterator::new(self)))
    }
}

/// GIF encoder.
pub struct Encoder<W: Write> {
    w: Option<W>,
    gif_encoder: Option<gif::Encoder<W>>,
}

impl<W: Write> Encoder<W> {
    /// Creates a new GIF encoder.
    pub fn new(w: W) -> Encoder<W> {
        Encoder {
            w: Some(w),
            gif_encoder: None,
        }
    }
    /// Encodes a frame.
    pub fn encode(&mut self, frame: &Frame) -> ImageResult<()> {
        let result;
        if let Some(ref mut encoder) = self.gif_encoder {
            result = encoder.write_frame(frame).map_err(|err| err.into());
        } else {
            let writer = self.w.take().unwrap();
            let mut encoder = gif::Encoder::new(writer, frame.width, frame.height, &[])?;
            result = encoder.write_frame(&frame).map_err(|err| err.into());
            self.gif_encoder = Some(encoder);
        }
        result
    }

    /// Encodes Frames.
    /// Consider using `try_encode_frames` instead to encode an `animation::Frames` like iterator.
    pub fn encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = animation::Frame>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame)?;
        }
        Ok(())
    }

    /// Try to encode a collection of `ImageResult<animation::Frame>` objects.
    /// Use this function to encode an `animation::Frames` like iterator.
    /// Whenever an `Err` item is encountered, that value is returned without further actions.
    pub fn try_encode_frames<F>(&mut self, frames: F) -> ImageResult<()>
    where
        F: IntoIterator<Item = ImageResult<animation::Frame>>
    {
        for img_frame in frames {
            self.encode_single_frame(img_frame?)?;
        }
        Ok(())
    }

    fn encode_single_frame(&mut self, img_frame: animation::Frame) -> ImageResult<()> {
        // get the delay before converting img_frame
        let frame_delay = img_frame.delay().to_integer();
        // convert img_frame into RgbaImage
        let rbga_frame = img_frame.into_buffer();

        // Create the gif::Frame from the animation::Frame
        let mut frame = Frame::from_rgba(rbga_frame.width() as u16, rbga_frame.height() as u16, &mut rbga_frame.into_raw());
        frame.delay = frame_delay;

        // encode the gif::Frame
        self.encode(&frame)
    }
}

impl From<gif::DecodingError> for ImageError {
    fn from(err: gif::DecodingError) -> ImageError {
        use self::gif::DecodingError::*;
        match err {
            Format(desc) | Internal(desc) => ImageError::FormatError(desc.into()),
            Io(io_err) => ImageError::IoError(io_err),
        }
    }
}
<|endoftext|>


<commit_before>extern crate num;

mod thea{

    use std::iter::Iterator;
    use num::Num;
    use num::One;

    /// A Model is defines how to predict a target from an input
    ///
    /// A model usually depends on several coefficents whose values
    /// are derived using a training algorithm
    pub trait Model : Clone{
        /// Input features
        type Input;
        /// Target type
        type Target : Num + One + Copy;

        /// Predicts a target for the inputs based on the internal coefficents
        fn predict(&self, &Self::Input) -> Self::Target;

        /// The number of internal coefficents this model depends on
        fn num_coefficents(&self) -> u32;

        /// Value predict derived by the n-th `coefficent` at `input`
        fn gradient(&self, coefficent : u32, input : &Self::Input) -> Self::Target;

        /// Mutable reference to the n-th `coefficent`
        fn coefficent(& mut self, coefficent : u32) -> & mut Self::Target;
    }

    /// Trains a model
    pub fn stochastic_gradient_descent<M, H>(start : M, history : H, learning_rate : M::Target) -> M
        where M : Model,
        H : Iterator<Item=(M::Input, M::Target)>
    {
        let two = M::Target::one() + M::Target::one();
        let mut last = start;
        let mut next = last.clone();

        for event in history{
            let prediction = next.predict(&event.0);
            let error = prediction - event.1;

            for ci in 0..next.num_coefficents(){
                *next.coefficent(ci) = *last.coefficent(ci) - learning_rate * two * error * last.gradient(ci, &event.0);
            }

            last = next.clone();
        }

        next
    }

    pub mod model{

        use thea::Model;

        /// Constant Model
        ///
        /// This model predicts a number. The cost function used during training decides
        /// wether this number is a mean, median or something else.
        #[derive(Debug, Clone)]
        pub struct Constant{
            /// Any prediction made by this model will have the value of `c`
            pub c : f64
        }

        impl Model for Constant{
            type Input = ();
            type Target = f64;

            fn predict(&self, input: &()) -> f64{
                self.c
            }

            fn num_coefficents(&self) -> u32{
                1
            }

            fn gradient(&self, coefficent : u32, input : &()) -> f64{
                match coefficent{
                    0 => 1.0,
                    _ => panic!("coefficent index out of range")
                }
            }

            fn coefficent(& mut self, coefficent : u32) -> & mut f64{
                match coefficent{
                    0 => & mut self.c,
                    _ => panic!("coefficent index out of range")
                }
            }
        }

        /// Linear model
        ///
        /// Models the target as `y = m * x + c`
        #[derive(Debug, Clone)]
        pub struct Linear{
            /// Slope
            pub m : f64,
            /// Offset
            pub c : f64
        }

        impl Model for Linear{

            type Input = f64;
            type Target = f64;

            fn predict(&self, input : &f64) -> f64{
                self.m * *input + self.c
            }

            fn num_coefficents(&self) -> u32{
                2
            }

            fn gradient(&self, coefficent : u32, input : &f64) -> f64{
                match coefficent{
                    0 => *input,
                    1 => 1.0,
                    _ => panic!("coefficent index out of range")
                }
            }

            fn coefficent(& mut self, coefficent : u32) -> & mut f64{
                match coefficent{
                    0 => & mut self.m,
                    1 => & mut self.c,
                    _ => panic!("coefficent index out of range")
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn estimate_mean() {

        use thea::model::Constant;
        use thea::Model;

        let history = [((), 3f64), ((), 4.0), ((), 5.0)];

        let mut model = Constant{c : 0.0};

        let learning_rate = 0.05;

        for &event in history.iter().cycle().take(60){
            let prediction = model.predict(&event.0);
            let error = prediction - event.1;

            for ci in 0..model.num_coefficents(){
                * model.coefficent(ci) -= learning_rate * 2. * error * model.gradient(ci, &event.0);
            }

            println!("model: {:?}", model);
        }

        assert!(model.c < 4.1);
        assert!(model.c > 3.9);
    }

    #[test]
    fn linear_stochastic_gradient_descent() {

        use thea::model::Linear;
        use thea::stochastic_gradient_descent;

        let history = [(0f64, 3f64), (1.0, 4.0), (2.0, 5.0)];

        let start = Linear{m : 0.0, c : 0.0};

        let learning_rate = 0.2;

        let model = stochastic_gradient_descent(start, history.iter().cycle().take(20).cloned(), 0.2);

        assert!(model.m < 1.1);
        assert!(model.m > 0.9);
        assert!(model.c < 3.1);
        assert!(model.c > 2.9);
    }

    #[test]
    fn linear_stochastic_gradient_descent_iter() {

        use thea::model::Linear;
        use thea::Model;

        let history = [(0f64, 3f64), (1.0, 4.0), (2.0, 5.0)];

        let mut model = Linear{m : 0.0, c : 0.0};

        let learning_rate = 0.2;

        // for &event in history.iter().cycle().take(20){
        //     let prediction = model.predict(&event.0);
        //     let error = prediction - event.1;

        //     for ci in 0..model.num_coefficents(){
        //         * model.coefficent(ci) -= learning_rate * 2. * error * model.gradient(ci, &event.0);
        //     }

        //     println!("model: {:?}", model);
        // }

        let model_it = history.iter().cycle().take(20).scan(& mut model, |m, &(features, truth)|{
            let prediction = m.predict(&features);
            let error = prediction - truth;

            for ci in 0..m.num_coefficents(){
                * m.coefficent(ci) -= learning_rate * 2. * error * m.gradient(ci, &features);
            }

            Some(m.clone())
        });

        for model in model_it{
            println!("model: {:?}", model);
        }

        // assert!(model.m < 1.1);
        // assert!(model.m > 0.9);
        // assert!(model.c < 3.1);
        // assert!(model.c > 2.9);
    }
}
<commit_msg>added gradient_descent_step<commit_after>extern crate num;

mod thea{

    use std::iter::Iterator;
    use num::Num;
    use num::One;

    /// A Model is defines how to predict a target from an input
    ///
    /// A model usually depends on several coefficents whose values
    /// are derived using a training algorithm
    pub trait Model : Clone{
        /// Input features
        type Input;
        /// Target type
        type Target : Num + One + Copy;

        /// Predicts a target for the inputs based on the internal coefficents
        fn predict(&self, &Self::Input) -> Self::Target;

        /// The number of internal coefficents this model depends on
        fn num_coefficents(&self) -> u32;

        /// Value predict derived by the n-th `coefficent` at `input`
        fn gradient(&self, coefficent : u32, input : &Self::Input) -> Self::Target;

        /// Mutable reference to the n-th `coefficent`
        fn coefficent(& mut self, coefficent : u32) -> & mut Self::Target;
    }

    /// Changes all coefficents of model based on their derivation of the cost function at features
    ///
    /// Can be used to implement stochastic or batch gradient descent
    pub fn gradient_descent_step<M : Model>(model : &mut M, features : &M::Input, truth : M::Target, learning_rate : M::Target)
    {
        let two = M::Target::one() + M::Target::one();
        let prediction = model.predict(&features);
        let error = prediction - truth;

        for ci in 0..model.num_coefficents(){
            *model.coefficent(ci) = *model.coefficent(ci) - learning_rate * two * error * model.gradient(ci, features);
        }
    }

    /// Trains a model
    pub fn stochastic_gradient_descent<M, H>(start : M, history : H, learning_rate : M::Target) -> M
        where M : Model,
        H : Iterator<Item=(M::Input, M::Target)>
    {
        let mut last = start;
        let mut next = last.clone();

        for (features, truth) in history{

            gradient_descent_step(& mut next, &features, truth, learning_rate);
            last = next.clone();
        }

        next
    }

    pub mod model{

        use thea::Model;

        /// Constant Model
        ///
        /// This model predicts a number. The cost function used during training decides
        /// wether this number is a mean, median or something else.
        #[derive(Debug, Clone)]
        pub struct Constant{
            /// Any prediction made by this model will have the value of `c`
            pub c : f64
        }

        impl Model for Constant{
            type Input = ();
            type Target = f64;

            fn predict(&self, input: &()) -> f64{
                self.c
            }

            fn num_coefficents(&self) -> u32{
                1
            }

            fn gradient(&self, coefficent : u32, input : &()) -> f64{
                match coefficent{
                    0 => 1.0,
                    _ => panic!("coefficent index out of range")
                }
            }

            fn coefficent(& mut self, coefficent : u32) -> & mut f64{
                match coefficent{
                    0 => & mut self.c,
                    _ => panic!("coefficent index out of range")
                }
            }
        }

        /// Linear model
        ///
        /// Models the target as `y = m * x + c`
        #[derive(Debug, Clone)]
        pub struct Linear{
            /// Slope
            pub m : f64,
            /// Offset
            pub c : f64
        }

        impl Model for Linear{

            type Input = f64;
            type Target = f64;

            fn predict(&self, input : &f64) -> f64{
                self.m * *input + self.c
            }

            fn num_coefficents(&self) -> u32{
                2
            }

            fn gradient(&self, coefficent : u32, input : &f64) -> f64{
                match coefficent{
                    0 => *input,
                    1 => 1.0,
                    _ => panic!("coefficent index out of range")
                }
            }

            fn coefficent(& mut self, coefficent : u32) -> & mut f64{
                match coefficent{
                    0 => & mut self.m,
                    1 => & mut self.c,
                    _ => panic!("coefficent index out of range")
                }
            }
        }
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn estimate_mean() {

        use thea::model::Constant;
        use thea::gradient_descent_step
;

        let history = [((), 3f64), ((), 4.0), ((), 5.0)];

        let mut model = Constant{c : 0.0};

        let learning_rate = 0.05;

        for &(features, truth) in history.iter().cycle().take(60){

            gradient_descent_step
    (& mut model, &features, truth, learning_rate);
            println!("model: {:?}", model);
        }

        assert!(model.c < 4.1);
        assert!(model.c > 3.9);
    }

    #[test]
    fn linear_stochastic_gradient_descent() {

        use thea::model::Linear;
        use thea::stochastic_gradient_descent;

        let history = [(0f64, 3f64), (1.0, 4.0), (2.0, 5.0)];

        let start = Linear{m : 0.0, c : 0.0};

        let learning_rate = 0.2;

        let model = stochastic_gradient_descent(start, history.iter().cycle().take(20).cloned(), learning_rate);

        assert!(model.m < 1.1);
        assert!(model.m > 0.9);
        assert!(model.c < 3.1);
        assert!(model.c > 2.9);
    }

    #[test]
    fn linear_stochastic_gradient_descent_iter() {

        use thea::model::Linear;
        use thea::gradient_descent_step
;

        let history = [(0f64, 3f64), (1.0, 4.0), (2.0, 5.0)];

        let mut model = Linear{m : 0.0, c : 0.0};

        let learning_rate = 0.2;

        for &(features, truth) in history.iter().cycle().take(20){

            gradient_descent_step
    (& mut model, &features, truth, learning_rate);

            println!("model: {:?}", model);
        }

        assert!(model.m < 1.1);
        assert!(model.m > 0.9);
        assert!(model.c < 3.1);
        assert!(model.c > 2.9);
    }
}
<|endoftext|>


<commit_before>//! Contains various utility types and macros useful for testing hyper clients.
//!
//! # Macros
//! The `mock_connector!` and `mock_connector_in_order!` macros can be used to
//! feed a client with preset data. That way you can control exactly what it will
//! see, confining the test-case to its own sandbox that way.
//!
//! All types they define are public to allow them to be used in other unit-tests.
//! Please note that integration tests cannot share their mock types anyway, as each
//! integration test goes into its own binary.
//!
//! # Usage
//!
//! Set it up for use in tests in `Cargo.toml`
//!
//! ```toml
//! [dev-dependencies]
//! yup-hyper-mock = "*"
//! log = "*"  # log macros are used within yup-hyper-mock
//! ```
//!
//! Link it into your `src/(lib.rs|main.rs)`
//!
//! ```Rust
//! #[cfg(test)] #[macro_use]
//! extern crate "yup-hyper-mock" as hyper_mock
//! ```

extern crate hyper;
extern crate futures;
extern crate tokio_io;
extern crate tokio_core;
extern crate tokio_reactor;
extern crate mio;

#[macro_use]
extern crate log;

use std::sync::Mutex;
use std::collections::HashMap;
use futures::Future;
use hyper::client::connect;

mod streams;
pub use streams::MockPollStream;

/// This macro maps host URLs to a respective reply, which is given in plain-text.
/// It ignores everything that is written to it.
#[macro_export]
macro_rules! mock_connector (
    ($name:ident {
        $($url:expr => $res:expr)*
    }) => (

        pub struct $name($crate::HostToReplyConnector);

        impl Default for $name {
            fn default() -> $name {
                let mut c = $name(Default::default());
                $(c.0.m.insert($url.to_string(), $res.to_string());)*
                c
            }
        }

        impl hyper::client::connect::Connect for $name {
            type Transport = $crate::MockPollStream;
            type Error = std::io::Error;
            type Future = Box<Future<Item=(Self::Transport, hyper::client::connect::Connected), Error=Self::Error> + Send>;

            fn connect(&self, dst: hyper::client::connect::Destination) -> Self::Future {
                let key = format!("{}://{}", dst.scheme(), dst.host());
                // ignore port for now
                match self.0.m.get(&key) {
                    Some(res) => Box::new(futures::future::ok(($crate::MockPollStream::new(res.clone().into_bytes()), hyper::client::connect::Connected::new()))),
                    None => panic!("mock_connector doesn't know url {}", key)
                }
            }
        }
    )
);

/// A `Connect` which provides a single reply stream per host.
///
/// The mapping is done from full host url (e.g. `http://host.name.com`) to the
/// singular reply the host is supposed to make.
#[derive(Default, Clone)]
pub struct HostToReplyConnector {
    pub m: HashMap<String, String>
}

impl connect::Connect for HostToReplyConnector {
    type Transport = MockPollStream;
    type Error = std::io::Error;
    type Future = Box<Future<Item=(Self::Transport, connect::Connected), Error=Self::Error> + Send>;

    fn connect(&self, dst: connect::Destination) -> Self::Future {
        debug!("HostToReplyConnector::connect({:?})", dst);

        let key = format!("{}://{}", dst.scheme(), dst.host());
        // ignore port for now
        match self.m.get(&key) {
            Some(res) => Box::new(futures::future::ok((MockPollStream::new(res.clone().into_bytes()), connect::Connected::new()))),
            None => panic!("HostToReplyConnector doesn't know url {}", key)
        }
    }
}

/// This macro yields all given server replies in the order they are given.
/// The destination host URL doesn't matter at all.
#[macro_export]
macro_rules! mock_connector_in_order (
    ($name:ident {
        $( $res:expr )*
    }) => (
        pub struct $name($crate::SequentialConnector);

        impl Default for $name {
            fn default() -> $name {
                let mut c = $name(Default::default());
                $(c.0.content.push($res.to_string());)*
                c
            }
        }

        impl hyper::client::connect::Connect for $name {
            type Transport = $crate::MockPollStream;
            type Error = std::io::Error;
            type Future = Box<Future<Item=(Self::Transport, hyper::client::connect::Connected), Error=Self::Error> + Send>;

            fn connect(&self, _dst: hyper::client::connect::Destination) -> Self::Future {
                assert!(self.0.content.len() != 0, "Not a single streamer return value specified");

                let data = self.0.content[*self.0.current.lock().unwrap()].clone().into_bytes();
                *self.0.current.lock().unwrap() += 1;
                Box::new(futures::future::ok(($crate::MockPollStream::new(data), hyper::client::connect::Connected::new())))
            }
        }
    )
);

/// A connector which requires you to implement the `Default` trait, allowing you
/// to determine the data it should be initialized with
pub struct SequentialConnector {
    pub content: Vec<String>,
    pub current: Mutex<usize>,
}

impl Default for SequentialConnector {
    fn default() -> Self {
        SequentialConnector {
            content: Vec::new(),
            current: Mutex::new(0)
        }
    }
}

impl connect::Connect for SequentialConnector {
    type Transport = MockPollStream;
    type Error = std::io::Error;
    type Future = Box<Future<Item=(Self::Transport, connect::Connected), Error=Self::Error> + Send>;

    fn connect(&self, dst: connect::Destination) -> Self::Future {
        debug!("SequentialConnector::connect({:?})", dst);

        assert!(self.content.len() != 0, "Not a single streamer return value specified");

        let data = self.content[*self.current.lock().unwrap()].clone().into_bytes();
        *self.current.lock().unwrap() += 1;
        Box::new(futures::future::ok((MockPollStream::new(data), connect::Connected::new())))
    }
}<commit_msg>Add Clone.<commit_after>//! Contains various utility types and macros useful for testing hyper clients.
//!
//! # Macros
//! The `mock_connector!` and `mock_connector_in_order!` macros can be used to
//! feed a client with preset data. That way you can control exactly what it will
//! see, confining the test-case to its own sandbox that way.
//!
//! All types they define are public to allow them to be used in other unit-tests.
//! Please note that integration tests cannot share their mock types anyway, as each
//! integration test goes into its own binary.
//!
//! # Usage
//!
//! Set it up for use in tests in `Cargo.toml`
//!
//! ```toml
//! [dev-dependencies]
//! yup-hyper-mock = "*"
//! log = "*"  # log macros are used within yup-hyper-mock
//! ```
//!
//! Link it into your `src/(lib.rs|main.rs)`
//!
//! ```Rust
//! #[cfg(test)] #[macro_use]
//! extern crate "yup-hyper-mock" as hyper_mock
//! ```

extern crate hyper;
extern crate futures;
extern crate tokio_io;
extern crate tokio_core;
extern crate tokio_reactor;
extern crate mio;

#[macro_use]
extern crate log;

use std::sync::Mutex;
use std::collections::HashMap;
use futures::Future;
use hyper::client::connect;

mod streams;
pub use streams::MockPollStream;

/// This macro maps host URLs to a respective reply, which is given in plain-text.
/// It ignores everything that is written to it.
#[macro_export]
macro_rules! mock_connector (
    ($name:ident {
        $($url:expr => $res:expr)*
    }) => (

        #[derive(Clone)]
        pub struct $name($crate::HostToReplyConnector);

        impl Default for $name {
            fn default() -> $name {
                let mut c = $name(Default::default());
                $(c.0.m.insert($url.to_string(), $res.to_string());)*
                c
            }
        }

        impl hyper::client::connect::Connect for $name {
            type Transport = $crate::MockPollStream;
            type Error = std::io::Error;
            type Future = Box<Future<Item=(Self::Transport, hyper::client::connect::Connected), Error=Self::Error> + Send>;

            fn connect(&self, dst: hyper::client::connect::Destination) -> Self::Future {
                let key = format!("{}://{}", dst.scheme(), dst.host());
                // ignore port for now
                match self.0.m.get(&key) {
                    Some(res) => Box::new(futures::future::ok(($crate::MockPollStream::new(res.clone().into_bytes()), hyper::client::connect::Connected::new()))),
                    None => panic!("mock_connector doesn't know url {}", key)
                }
            }
        }
    )
);

/// A `Connect` which provides a single reply stream per host.
///
/// The mapping is done from full host url (e.g. `http://host.name.com`) to the
/// singular reply the host is supposed to make.
#[derive(Default, Clone)]
pub struct HostToReplyConnector {
    pub m: HashMap<String, String>
}

impl connect::Connect for HostToReplyConnector {
    type Transport = MockPollStream;
    type Error = std::io::Error;
    type Future = Box<Future<Item=(Self::Transport, connect::Connected), Error=Self::Error> + Send>;

    fn connect(&self, dst: connect::Destination) -> Self::Future {
        debug!("HostToReplyConnector::connect({:?})", dst);

        let key = format!("{}://{}", dst.scheme(), dst.host());
        // ignore port for now
        match self.m.get(&key) {
            Some(res) => Box::new(futures::future::ok((MockPollStream::new(res.clone().into_bytes()), connect::Connected::new()))),
            None => panic!("HostToReplyConnector doesn't know url {}", key)
        }
    }
}

/// This macro yields all given server replies in the order they are given.
/// The destination host URL doesn't matter at all.
#[macro_export]
macro_rules! mock_connector_in_order (
    ($name:ident {
        $( $res:expr )*
    }) => (
        pub struct $name($crate::SequentialConnector);

        impl Default for $name {
            fn default() -> $name {
                let mut c = $name(Default::default());
                $(c.0.content.push($res.to_string());)*
                c
            }
        }

        impl hyper::client::connect::Connect for $name {
            type Transport = $crate::MockPollStream;
            type Error = std::io::Error;
            type Future = Box<Future<Item=(Self::Transport, hyper::client::connect::Connected), Error=Self::Error> + Send>;

            fn connect(&self, _dst: hyper::client::connect::Destination) -> Self::Future {
                assert!(self.0.content.len() != 0, "Not a single streamer return value specified");

                let data = self.0.content[*self.0.current.lock().unwrap()].clone().into_bytes();
                *self.0.current.lock().unwrap() += 1;
                Box::new(futures::future::ok(($crate::MockPollStream::new(data), hyper::client::connect::Connected::new())))
            }
        }
    )
);

/// A connector which requires you to implement the `Default` trait, allowing you
/// to determine the data it should be initialized with
pub struct SequentialConnector {
    pub content: Vec<String>,
    pub current: Mutex<usize>,
}

impl Default for SequentialConnector {
    fn default() -> Self {
        SequentialConnector {
            content: Vec::new(),
            current: Mutex::new(0)
        }
    }
}

impl connect::Connect for SequentialConnector {
    type Transport = MockPollStream;
    type Error = std::io::Error;
    type Future = Box<Future<Item=(Self::Transport, connect::Connected), Error=Self::Error> + Send>;

    fn connect(&self, dst: connect::Destination) -> Self::Future {
        debug!("SequentialConnector::connect({:?})", dst);

        assert!(self.content.len() != 0, "Not a single streamer return value specified");

        let data = self.content[*self.current.lock().unwrap()].clone().into_bytes();
        *self.current.lock().unwrap() += 1;
        Box::new(futures::future::ok((MockPollStream::new(data), connect::Connected::new())))
    }
}<|endoftext|>