<commit_before>use traits::structure::{BaseFloat, Cast};
use structs::{Pnt3, Vec3, Mat4};

#[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen};

/// A 3D orthographic projection stored without any matrix.
///
/// This flips the `z` axis and maps a axis-aligned cube to the unit cube with corners varying from
/// `(-1, -1, -1)` to `(1, 1, 1)`. Reading or modifying its individual properties is cheap but
/// applying the transformation is costly.
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct Ortho3<N> {
    left:   N,
    right:  N,
    bottom: N,
    top:    N,
    znear:  N,
    zfar:   N
}

/// A 3D orthographic projection stored as a 4D matrix.
///
/// This flips the `z` axis and maps a axis-aligned cube to the unit cube with corners varying from
/// `(-1, -1, -1)` to `(1, 1, 1)`. Reading or modifying its individual properties is costly but
/// applying the transformation is cheap.
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct OrthoMat3<N> {
    mat: Mat4<N>
}

impl<N: BaseFloat> Ortho3<N> {
    /// Creates a new 3D orthographic projection.
    pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Ortho3<N> {
        assert!(!::is_zero(&(zfar - znear)));
        assert!(!::is_zero(&(left - right)));
        assert!(!::is_zero(&(top - bottom)));

        Ortho3 {
            left:   left,
            right:  right,
            bottom: bottom,
            top:    top,
            znear:  znear,
            zfar:   zfar
        }
    }

    /// Builds a 4D projection matrix (using homogeneous coordinates) for this projection.
    pub fn to_mat(&self) -> Mat4<N> {
        self.to_persp_mat().mat
    }

    /// Build a `OrthoMat3` representing this projection.
    pub fn to_persp_mat(&self) -> OrthoMat3<N> {
        OrthoMat3::new(self.left, self.right, self.bottom, self.top, self.znear, self.zfar)
    }
}

#[cfg(feature="arbitrary")]
impl<N: Arbitrary + BaseFloat> Arbitrary for Ortho3<N> {
    fn arbitrary<G: Gen>(g: &mut G) -> Ortho3<N> {
        let left   = Arbitrary::arbitrary(g);
        let right  = reject(g, |x: &N| *x > left);
        let bottom = Arbitrary::arbitrary(g);
        let top    = reject(g, |x: &N| *x > bottom);
        let znear  = Arbitrary::arbitrary(g);
        let zfar   = reject(g, |x: &N| *x > znear);
        Ortho3::new(width, height, znear, zfar)
    }
}

impl<N: BaseFloat + Clone> Ortho3<N> {
    /// The smallest x-coordinate of the view cuboid.
    #[inline]
    pub fn left(&self) -> N {
        self.left.clone()
    }

    /// The largest x-coordinate of the view cuboid.
    #[inline]
    pub fn right(&self) -> N {
        self.right.clone()
    }

    /// The smallest y-coordinate of the view cuboid.
    #[inline]
    pub fn bottom(&self) -> N {
        self.bottom.clone()
    }

    /// The largest y-coordinate of the view cuboid.
    #[inline]
    pub fn top(&self) -> N {
        self.top.clone()
    }

    /// The near plane offset of the view cuboid.
    #[inline]
    pub fn znear(&self) -> N {
        self.znear.clone()
    }

    /// The far plane offset of the view cuboid.
    #[inline]
    pub fn zfar(&self) -> N {
        self.zfar.clone()
    }

    /// Sets the smallest x-coordinate of the view cuboid.
    #[inline]
    pub fn set_left(&mut self, left: N) {
        assert!(left < self.right, "The left corner must be farther than the right corner.");
        self.left = left
    }

    /// Sets the largest x-coordinate of the view cuboid.
    #[inline]
    pub fn set_right(&mut self, right: N) {
        assert!(right > self.left, "The left corner must be farther than the right corner.");
        self.right = right
    }

    /// Sets the smallest y-coordinate of the view cuboid.
    #[inline]
    pub fn set_bottom(&mut self, bottom: N) {
        assert!(bottom < self.top, "The top corner must be higher than the bottom corner.");
        self.bottom = bottom
    }

    /// Sets the largest y-coordinate of the view cuboid.
    #[inline]
    pub fn set_top(&mut self, top: N) {
        assert!(top > self.bottom, "The top corner must be higher than the left corner.");
        self.top = top
    }

    /// Sets the near plane offset of the view cuboid.
    #[inline]
    pub fn set_znear(&mut self, znear: N) {
        assert!(znear < self.zfar, "The far plane must be farther than the near plane.");
        self.znear = znear
    }

    /// Sets the far plane offset of the view cuboid.
    #[inline]
    pub fn set_zfar(&mut self, zfar: N) {
        assert!(zfar > self.znear, "The far plane must be farther than the near plane.");
        self.zfar = zfar
    }

    /// Projects a point.
    #[inline]
    pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
        // FIXME: optimize that
        self.to_persp_mat().project_pnt(p)
    }

    /// Projects a vector.
    #[inline]
    pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
        // FIXME: optimize that
        self.to_persp_mat().project_vec(p)
    }
}

impl<N: BaseFloat> OrthoMat3<N> {
    /// Creates a new orthographic projection matrix.
    pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> OrthoMat3<N> {
        assert!(left < right, "The left corner must be farther than the right corner.");
        assert!(bottom < top, "The top corner must be higher than the bottom corner.");
        assert!(znear < zfar, "The far plane must be farther than the near plane.");

        let mat: Mat4<N> = ::one();

        let mut res = OrthoMat3 { mat: mat };
        res.set_left_and_right(left, right);
        res.set_bottom_and_top(bottom, top);
        res.set_znear_and_zfar(znear, zfar);

        res
    }

    /// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view.
    pub fn new_with_fov(aspect: N, vfov: N, znear: N, zfar: N) -> OrthoMat3<N> {
        assert!(znear < zfar, "The far plane must be farther than the near plane.");
        assert!(!::is_zero(&aspect));

        let _1: N = ::one();
        let _2 = _1 + _1;
        let width  = zfar * (vfov / _2).tan();
        let height = width / aspect;

        OrthoMat3::new(-width / _2, width / _2, -height / _2, height / _2, znear, zfar)
    }

    /// Creates a new orthographic matrix from a 4D matrix.
    ///
    /// This is unsafe because the input matrix is not checked to be a orthographic projection.
    #[inline]
    pub unsafe fn new_with_mat(mat: Mat4<N>) -> OrthoMat3<N> {
        OrthoMat3 {
            mat: mat
        }
    }

    /// Returns a reference to the 4D matrix (using homogeneous coordinates) of this projection.
    #[inline]
    pub fn as_mat<'a>(&'a self) -> &'a Mat4<N> {
        &self.mat
    }

    /// The smallest x-coordinate of the view cuboid.
    #[inline]
    pub fn left(&self) -> N {
        (-::one::<N>() - self.mat.m14) / self.mat.m11
    }

    /// The largest x-coordinate of the view cuboid.
    #[inline]
    pub fn right(&self) -> N {
        (::one::<N>() - self.mat.m14) / self.mat.m11
    }

    /// The smallest y-coordinate of the view cuboid.
    #[inline]
    pub fn bottom(&self) -> N {
        (-::one::<N>() - self.mat.m24) / self.mat.m22
    }

    /// The largest y-coordinate of the view cuboid.
    #[inline]
    pub fn top(&self) -> N {
        (::one::<N>() - self.mat.m24) / self.mat.m22
    }

    /// The near plane offset of the view cuboid.
    #[inline]
    pub fn znear(&self) -> N {
        (::one::<N>() + self.mat.m34) / self.mat.m33
    }

    /// The far plane offset of the view cuboid.
    #[inline]
    pub fn zfar(&self) -> N {
        (-::one::<N>() + self.mat.m34) / self.mat.m33
    }

    /// Sets the smallest x-coordinate of the view cuboid.
    #[inline]
    pub fn set_left(&mut self, left: N) {
        let right = self.right();
        self.set_left_and_right(left, right);
    }

    /// Sets the largest x-coordinate of the view cuboid.
    #[inline]
    pub fn set_right(&mut self, right: N) {
        let left = self.left();
        self.set_left_and_right(left, right);
    }

    /// Sets the smallest y-coordinate of the view cuboid.
    #[inline]
    pub fn set_bottom(&mut self, bottom: N) {
        let top = self.top();
        self.set_bottom_and_top(bottom, top);
    }

    /// Sets the largest y-coordinate of the view cuboid.
    #[inline]
    pub fn set_top(&mut self, top: N) {
        let bottom = self.bottom();
        self.set_bottom_and_top(bottom, top);
    }

    /// Sets the near plane offset of the view cuboid.
    #[inline]
    pub fn set_znear(&mut self, znear: N) {
        let zfar = self.zfar();
        self.set_znear_and_zfar(znear, zfar);
    }

    /// Sets the far plane offset of the view cuboid.
    #[inline]
    pub fn set_zfar(&mut self, zfar: N) {
        let znear = self.znear();
        self.set_znear_and_zfar(znear, zfar);
    }

    /// Sets the view cuboid coordinates along the `x` axis.
    #[inline]
    pub fn set_left_and_right(&mut self, left: N, right: N) {
        assert!(left < right, "The left corner must be farther than the right corner.");
        self.mat.m11 = <N as Cast<f64>>::from(2.0) / (right - left);
        self.mat.m14 = -(right + left) / (right - left);
    }

    /// Sets the view cuboid coordinates along the `y` axis.
    #[inline]
    pub fn set_bottom_and_top(&mut self, bottom: N, top: N) {
        assert!(bottom < top, "The top corner must be higher than the bottom corner.");
        self.mat.m22 = <N as Cast<f64>>::from(2.0) / (top - bottom);
        self.mat.m24 = -(top + bottom) / (top - bottom);
    }

    /// Sets the near and far plane offsets of the view cuboid.
    #[inline]
    pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) {
        assert!(!::is_zero(&(zfar - znear)));
        self.mat.m33 = -<N as Cast<f64>>::from(2.0) / (zfar - znear);
        self.mat.m34 = -(zfar + znear) / (zfar - znear);
    }

    /// Projects a point.
    #[inline]
    pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
        Pnt3::new(
            self.mat.m11 * p.x + self.mat.m14,
            self.mat.m22 * p.y + self.mat.m24,
            self.mat.m33 * p.z + self.mat.m34
        )
    }

    /// Projects a vector.
    #[inline]
    pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
        Vec3::new(
            self.mat.m11 * p.x,
            self.mat.m22 * p.y,
            self.mat.m33 * p.z
        )
    }
}

impl<N: BaseFloat + Clone> OrthoMat3<N> {
    /// Returns the 4D matrix (using homogeneous coordinates) of this projection.
    #[inline]
    pub fn to_mat<'a>(&'a self) -> Mat4<N> {
        self.mat.clone()
    }
}

#[cfg(feature="arbitrary")]
impl<N: Arbitrary + BaseFloat> Arbitrary for OrthoMat3<N> {
    fn arbitrary<G: Gen>(g: &mut G) -> OrthoMat3<N> {
        let x: Ortho3<N> = Arbitrary::arbitrary(g);
        x.to_persp_mat()
    }
}

/// Simple helper function for rejection sampling
#[cfg(feature="arbitrary")]
#[inline]
pub fn reject<G: Gen, F: FnMut(&T) -> bool, T: Arbitrary>(g: &mut G, f: F) -> T {
    use std::iter::repeat;
    repeat(()).map(|_| Arbitrary::arbitrary(g)).filter(f).next().unwrap()
}
<commit_msg>Fix Ortho when the feature `arbitrary` is enabled.<commit_after>use traits::structure::{BaseFloat, Cast};
use structs::{Pnt3, Vec3, Mat4};

#[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen};

/// A 3D orthographic projection stored without any matrix.
///
/// This flips the `z` axis and maps a axis-aligned cube to the unit cube with corners varying from
/// `(-1, -1, -1)` to `(1, 1, 1)`. Reading or modifying its individual properties is cheap but
/// applying the transformation is costly.
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct Ortho3<N> {
    left:   N,
    right:  N,
    bottom: N,
    top:    N,
    znear:  N,
    zfar:   N
}

/// A 3D orthographic projection stored as a 4D matrix.
///
/// This flips the `z` axis and maps a axis-aligned cube to the unit cube with corners varying from
/// `(-1, -1, -1)` to `(1, 1, 1)`. Reading or modifying its individual properties is costly but
/// applying the transformation is cheap.
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct OrthoMat3<N> {
    mat: Mat4<N>
}

impl<N: BaseFloat> Ortho3<N> {
    /// Creates a new 3D orthographic projection.
    pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Ortho3<N> {
        assert!(!::is_zero(&(zfar - znear)));
        assert!(!::is_zero(&(left - right)));
        assert!(!::is_zero(&(top - bottom)));

        Ortho3 {
            left:   left,
            right:  right,
            bottom: bottom,
            top:    top,
            znear:  znear,
            zfar:   zfar
        }
    }

    /// Builds a 4D projection matrix (using homogeneous coordinates) for this projection.
    pub fn to_mat(&self) -> Mat4<N> {
        self.to_persp_mat().mat
    }

    /// Build a `OrthoMat3` representing this projection.
    pub fn to_persp_mat(&self) -> OrthoMat3<N> {
        OrthoMat3::new(self.left, self.right, self.bottom, self.top, self.znear, self.zfar)
    }
}

#[cfg(feature="arbitrary")]
impl<N: Arbitrary + BaseFloat> Arbitrary for Ortho3<N> {
    fn arbitrary<G: Gen>(g: &mut G) -> Ortho3<N> {
        let left   = Arbitrary::arbitrary(g);
        let right  = reject(g, |x: &N| *x > left);
        let bottom = Arbitrary::arbitrary(g);
        let top    = reject(g, |x: &N| *x > bottom);
        let znear  = Arbitrary::arbitrary(g);
        let zfar   = reject(g, |x: &N| *x > znear);
        Ortho3::new(left, right, bottom, top, znear, zfar)
    }
}

impl<N: BaseFloat + Clone> Ortho3<N> {
    /// The smallest x-coordinate of the view cuboid.
    #[inline]
    pub fn left(&self) -> N {
        self.left.clone()
    }

    /// The largest x-coordinate of the view cuboid.
    #[inline]
    pub fn right(&self) -> N {
        self.right.clone()
    }

    /// The smallest y-coordinate of the view cuboid.
    #[inline]
    pub fn bottom(&self) -> N {
        self.bottom.clone()
    }

    /// The largest y-coordinate of the view cuboid.
    #[inline]
    pub fn top(&self) -> N {
        self.top.clone()
    }

    /// The near plane offset of the view cuboid.
    #[inline]
    pub fn znear(&self) -> N {
        self.znear.clone()
    }

    /// The far plane offset of the view cuboid.
    #[inline]
    pub fn zfar(&self) -> N {
        self.zfar.clone()
    }

    /// Sets the smallest x-coordinate of the view cuboid.
    #[inline]
    pub fn set_left(&mut self, left: N) {
        assert!(left < self.right, "The left corner must be farther than the right corner.");
        self.left = left
    }

    /// Sets the largest x-coordinate of the view cuboid.
    #[inline]
    pub fn set_right(&mut self, right: N) {
        assert!(right > self.left, "The left corner must be farther than the right corner.");
        self.right = right
    }

    /// Sets the smallest y-coordinate of the view cuboid.
    #[inline]
    pub fn set_bottom(&mut self, bottom: N) {
        assert!(bottom < self.top, "The top corner must be higher than the bottom corner.");
        self.bottom = bottom
    }

    /// Sets the largest y-coordinate of the view cuboid.
    #[inline]
    pub fn set_top(&mut self, top: N) {
        assert!(top > self.bottom, "The top corner must be higher than the left corner.");
        self.top = top
    }

    /// Sets the near plane offset of the view cuboid.
    #[inline]
    pub fn set_znear(&mut self, znear: N) {
        assert!(znear < self.zfar, "The far plane must be farther than the near plane.");
        self.znear = znear
    }

    /// Sets the far plane offset of the view cuboid.
    #[inline]
    pub fn set_zfar(&mut self, zfar: N) {
        assert!(zfar > self.znear, "The far plane must be farther than the near plane.");
        self.zfar = zfar
    }

    /// Projects a point.
    #[inline]
    pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
        // FIXME: optimize that
        self.to_persp_mat().project_pnt(p)
    }

    /// Projects a vector.
    #[inline]
    pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
        // FIXME: optimize that
        self.to_persp_mat().project_vec(p)
    }
}

impl<N: BaseFloat> OrthoMat3<N> {
    /// Creates a new orthographic projection matrix.
    pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> OrthoMat3<N> {
        assert!(left < right, "The left corner must be farther than the right corner.");
        assert!(bottom < top, "The top corner must be higher than the bottom corner.");
        assert!(znear < zfar, "The far plane must be farther than the near plane.");

        let mat: Mat4<N> = ::one();

        let mut res = OrthoMat3 { mat: mat };
        res.set_left_and_right(left, right);
        res.set_bottom_and_top(bottom, top);
        res.set_znear_and_zfar(znear, zfar);

        res
    }

    /// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view.
    pub fn new_with_fov(aspect: N, vfov: N, znear: N, zfar: N) -> OrthoMat3<N> {
        assert!(znear < zfar, "The far plane must be farther than the near plane.");
        assert!(!::is_zero(&aspect));

        let _1: N = ::one();
        let _2 = _1 + _1;
        let width  = zfar * (vfov / _2).tan();
        let height = width / aspect;

        OrthoMat3::new(-width / _2, width / _2, -height / _2, height / _2, znear, zfar)
    }

    /// Creates a new orthographic matrix from a 4D matrix.
    ///
    /// This is unsafe because the input matrix is not checked to be a orthographic projection.
    #[inline]
    pub unsafe fn new_with_mat(mat: Mat4<N>) -> OrthoMat3<N> {
        OrthoMat3 {
            mat: mat
        }
    }

    /// Returns a reference to the 4D matrix (using homogeneous coordinates) of this projection.
    #[inline]
    pub fn as_mat<'a>(&'a self) -> &'a Mat4<N> {
        &self.mat
    }

    /// The smallest x-coordinate of the view cuboid.
    #[inline]
    pub fn left(&self) -> N {
        (-::one::<N>() - self.mat.m14) / self.mat.m11
    }

    /// The largest x-coordinate of the view cuboid.
    #[inline]
    pub fn right(&self) -> N {
        (::one::<N>() - self.mat.m14) / self.mat.m11
    }

    /// The smallest y-coordinate of the view cuboid.
    #[inline]
    pub fn bottom(&self) -> N {
        (-::one::<N>() - self.mat.m24) / self.mat.m22
    }

    /// The largest y-coordinate of the view cuboid.
    #[inline]
    pub fn top(&self) -> N {
        (::one::<N>() - self.mat.m24) / self.mat.m22
    }

    /// The near plane offset of the view cuboid.
    #[inline]
    pub fn znear(&self) -> N {
        (::one::<N>() + self.mat.m34) / self.mat.m33
    }

    /// The far plane offset of the view cuboid.
    #[inline]
    pub fn zfar(&self) -> N {
        (-::one::<N>() + self.mat.m34) / self.mat.m33
    }

    /// Sets the smallest x-coordinate of the view cuboid.
    #[inline]
    pub fn set_left(&mut self, left: N) {
        let right = self.right();
        self.set_left_and_right(left, right);
    }

    /// Sets the largest x-coordinate of the view cuboid.
    #[inline]
    pub fn set_right(&mut self, right: N) {
        let left = self.left();
        self.set_left_and_right(left, right);
    }

    /// Sets the smallest y-coordinate of the view cuboid.
    #[inline]
    pub fn set_bottom(&mut self, bottom: N) {
        let top = self.top();
        self.set_bottom_and_top(bottom, top);
    }

    /// Sets the largest y-coordinate of the view cuboid.
    #[inline]
    pub fn set_top(&mut self, top: N) {
        let bottom = self.bottom();
        self.set_bottom_and_top(bottom, top);
    }

    /// Sets the near plane offset of the view cuboid.
    #[inline]
    pub fn set_znear(&mut self, znear: N) {
        let zfar = self.zfar();
        self.set_znear_and_zfar(znear, zfar);
    }

    /// Sets the far plane offset of the view cuboid.
    #[inline]
    pub fn set_zfar(&mut self, zfar: N) {
        let znear = self.znear();
        self.set_znear_and_zfar(znear, zfar);
    }

    /// Sets the view cuboid coordinates along the `x` axis.
    #[inline]
    pub fn set_left_and_right(&mut self, left: N, right: N) {
        assert!(left < right, "The left corner must be farther than the right corner.");
        self.mat.m11 = <N as Cast<f64>>::from(2.0) / (right - left);
        self.mat.m14 = -(right + left) / (right - left);
    }

    /// Sets the view cuboid coordinates along the `y` axis.
    #[inline]
    pub fn set_bottom_and_top(&mut self, bottom: N, top: N) {
        assert!(bottom < top, "The top corner must be higher than the bottom corner.");
        self.mat.m22 = <N as Cast<f64>>::from(2.0) / (top - bottom);
        self.mat.m24 = -(top + bottom) / (top - bottom);
    }

    /// Sets the near and far plane offsets of the view cuboid.
    #[inline]
    pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) {
        assert!(!::is_zero(&(zfar - znear)));
        self.mat.m33 = -<N as Cast<f64>>::from(2.0) / (zfar - znear);
        self.mat.m34 = -(zfar + znear) / (zfar - znear);
    }

    /// Projects a point.
    #[inline]
    pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
        Pnt3::new(
            self.mat.m11 * p.x + self.mat.m14,
            self.mat.m22 * p.y + self.mat.m24,
            self.mat.m33 * p.z + self.mat.m34
        )
    }

    /// Projects a vector.
    #[inline]
    pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
        Vec3::new(
            self.mat.m11 * p.x,
            self.mat.m22 * p.y,
            self.mat.m33 * p.z
        )
    }
}

impl<N: BaseFloat + Clone> OrthoMat3<N> {
    /// Returns the 4D matrix (using homogeneous coordinates) of this projection.
    #[inline]
    pub fn to_mat<'a>(&'a self) -> Mat4<N> {
        self.mat.clone()
    }
}

#[cfg(feature="arbitrary")]
impl<N: Arbitrary + BaseFloat> Arbitrary for OrthoMat3<N> {
    fn arbitrary<G: Gen>(g: &mut G) -> OrthoMat3<N> {
        let x: Ortho3<N> = Arbitrary::arbitrary(g);
        x.to_persp_mat()
    }
}

/// Simple helper function for rejection sampling
#[cfg(feature="arbitrary")]
#[inline]
pub fn reject<G: Gen, F: FnMut(&T) -> bool, T: Arbitrary>(g: &mut G, f: F) -> T {
    use std::iter::repeat;
    repeat(()).map(|_| Arbitrary::arbitrary(g)).filter(f).next().unwrap()
}
<|endoftext|>


<commit_before>use std::io;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, RwLock, Weak};
use std::time::{SystemTime, UNIX_EPOCH};

use byteorder::{BigEndian, ByteOrder};
use bytes::Bytes;
// use futures::sync::mpsc;
// use futures::{Async, Future, IntoFuture, Poll, Stream};
// use tokio::runtime::{current_thread, current_thread::Handle};

// use futures::future::{IntoFuture, Remote};
use futures::{
    channel::mpsc,
    // future::{IntoFuture, Remote},
    Future,
    Stream,
    TryFutureExt,
};
use std::{
    pin::Pin,
    task::{Context, Poll},
};

use tokio::runtime::Handle;

use crate::apresolve::apresolve_or_fallback;
use crate::audio_key::AudioKeyManager;
use crate::authentication::Credentials;
use crate::cache::Cache;
use crate::channel::ChannelManager;
use crate::component::Lazy;
use crate::config::SessionConfig;
use crate::connection;
use crate::mercury::MercuryManager;

struct SessionData {
    country: String,
    time_delta: i64,
    canonical_username: String,
    invalid: bool,
}

struct SessionInternal {
    config: SessionConfig,
    data: RwLock<SessionData>,

    tx_connection: mpsc::UnboundedSender<(u8, Vec<u8>)>,

    audio_key: Lazy<AudioKeyManager>,
    channel: Lazy<ChannelManager>,
    mercury: Lazy<MercuryManager>,
    cache: Option<Arc<Cache>>,

    handle: Mutex<Handle>,
    session_id: usize,
}

static SESSION_COUNTER: AtomicUsize = AtomicUsize::new(0);

#[derive(Clone)]
pub struct Session(Arc<SessionInternal>);

// TODO: Define better errors!
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;

impl Session {
    pub async fn connect(
        config: SessionConfig,
        credentials: Credentials,
        cache: Option<Cache>,
        handle: Handle,
    ) -> Result<Session> {
        unimplemented!()
        // let access_point_addr =
        //     apresolve_or_fallback::<io::Error>(&config.proxy, &config.ap_port).await?;
        //
        // let proxy = config.proxy.clone();
        // info!("Connecting to AP \"{}\"", access_point_addr);
        // let connection = connection::connect(access_point_addr, &proxy);
        //
        // let device_id = config.device_id.clone();
        // let authentication = connection.and_then(move |connection| {
        //     connection::authenticate(connection, credentials, device_id)
        // });
        //
        // let result = authentication.map(move |(transport, reusable_credentials)| {
        //     info!("Authenticated as \"{}\" !", reusable_credentials.username);
        //     if let Some(ref cache) = cache {
        //         cache.save_credentials(&reusable_credentials);
        //     }
        //
        //     let (session, task) = Session::create(
        //         &handle,
        //         transport,
        //         config,
        //         cache,
        //         reusable_credentials.username.clone(),
        //     );
        //
        //     tokio::spawn(task.map_err(|e| {
        //         error!("SessionError: {}", e.to_string());
        //         std::process::exit(0);
        //     }));
        //
        //     session
        // });
        //
        // result
    }

    fn create(
        handle: &Handle,
        transport: connection::Transport,
        config: SessionConfig,
        cache: Option<Cache>,
        username: String,
    ) -> (Session, Box<dyn Future<Output = Result<()>>>) {
        let (sink, stream) = transport.split();

        let (sender_tx, sender_rx) = mpsc::unbounded();
        let session_id = SESSION_COUNTER.fetch_add(1, Ordering::Relaxed);

        debug!("new Session[{}]", session_id);

        let session = Session(Arc::new(SessionInternal {
            config: config,
            data: RwLock::new(SessionData {
                country: String::new(),
                canonical_username: username,
                invalid: false,
                time_delta: 0,
            }),

            tx_connection: sender_tx,

            cache: cache.map(Arc::new),

            audio_key: Lazy::new(),
            channel: Lazy::new(),
            mercury: Lazy::new(),

            handle: Mutex::new(handle.clone()),
            session_id: session_id,
        }));

        let sender_task = sender_rx
            .map_err(|e| -> io::Error { panic!(e) })
            .forward(sink)
            .map(|_| ());
        let receiver_task = DispatchTask(stream, session.weak());

        let task = Box::new(
            (receiver_task, sender_task)
                .into_future()
                .map(|((), ())| ()),
        );

        (session, task)
    }

    pub fn audio_key(&self) -> &AudioKeyManager {
        self.0.audio_key.get(|| AudioKeyManager::new(self.weak()))
    }

    pub fn channel(&self) -> &ChannelManager {
        self.0.channel.get(|| ChannelManager::new(self.weak()))
    }

    pub fn mercury(&self) -> &MercuryManager {
        self.0.mercury.get(|| MercuryManager::new(self.weak()))
    }

    pub fn time_delta(&self) -> i64 {
        self.0.data.read().unwrap().time_delta
    }

    // Spawn a future directly
    pub fn spawn<F>(&self, f: F)
    where
        F: Future<Output = ()> + Send + 'static,
    {
        let handle = self.0.handle.lock().unwrap();
        let spawn_res = handle.spawn(f);
        match spawn_res {
            Ok(_) => (),
            Err(e) => error!("Session SpawnErr {:?}", e),
        }
    }

    // pub fn spawn<F, R>(&self, f: F)
    // where
    //     F: FnOnce() -> R + Send + 'static,
    //     R: Future<Item = (), Error = ()> + Send + 'static,
    // {
    //     // This fails when called from a different thread
    //     // current_thread::spawn(future::lazy(|| f()));
    //
    //     // These fail when the Future doesn't implement Send
    //     let handle = self.0.handle.lock().unwrap();
    //     let spawn_res = handle.spawn(lazy(|| f()));
    //
    //     // let mut te = current_thread::TaskExecutor::current();
    //     // let spawn_res = te.spawn_local(Box::new(future::lazy(|| f())));
    //
    //     match spawn_res {
    //         Ok(_) => (),
    //         Err(e) => error!("Session SpawnErr {:?}", e),
    //     }
    // }

    fn debug_info(&self) {
        debug!(
            "Session[{}] strong={} weak={}",
            self.0.session_id,
            Arc::strong_count(&self.0),
            Arc::weak_count(&self.0)
        );
    }

    #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
    fn dispatch(&self, cmd: u8, data: Bytes) {
        match cmd {
            0x4 => {
                let server_timestamp = BigEndian::read_u32(data.as_ref()) as i64;
                let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) {
                    Ok(dur) => dur,
                    Err(err) => err.duration(),
                }
                .as_secs() as i64;

                self.0.data.write().unwrap().time_delta = server_timestamp - timestamp;

                self.debug_info();
                self.send_packet(0x49, vec![0, 0, 0, 0]);
            }
            0x4a => (),
            0x1b => {
                let country = String::from_utf8(data.as_ref().to_owned()).unwrap();
                info!("Country: {:?}", country);
                self.0.data.write().unwrap().country = country;
            }

            0x9 | 0xa => self.channel().dispatch(cmd, data),
            0xd | 0xe => self.audio_key().dispatch(cmd, data),
            0xb2..=0xb6 => self.mercury().dispatch(cmd, data),
            _ => trace!("Unknown dispatch cmd :{:?} {:?}", cmd, data),
        }
    }

    pub fn send_packet(&self, cmd: u8, data: Vec<u8>) {
        self.0.tx_connection.unbounded_send((cmd, data)).unwrap();
    }

    pub fn cache(&self) -> Option<&Arc<Cache>> {
        self.0.cache.as_ref()
    }

    fn config(&self) -> &SessionConfig {
        &self.0.config
    }

    pub fn username(&self) -> String {
        self.0.data.read().unwrap().canonical_username.clone()
    }

    pub fn country(&self) -> String {
        self.0.data.read().unwrap().country.clone()
    }

    pub fn device_id(&self) -> &str {
        &self.config().device_id
    }

    fn weak(&self) -> SessionWeak {
        SessionWeak(Arc::downgrade(&self.0))
    }

    pub fn session_id(&self) -> usize {
        self.0.session_id
    }

    pub fn shutdown(&self) {
        debug!("Invalidating session[{}]", self.0.session_id);
        self.0.data.write().unwrap().invalid = true;
        self.mercury().shutdown();
        self.channel().shutdown();
    }

    pub fn is_invalid(&self) -> bool {
        self.0.data.read().unwrap().invalid
    }
}

#[derive(Clone)]
pub struct SessionWeak(Weak<SessionInternal>);

impl SessionWeak {
    fn try_upgrade(&self) -> Option<Session> {
        self.0.upgrade().map(Session)
    }

    pub(crate) fn upgrade(&self) -> Session {
        self.try_upgrade().expect("Session died")
    }
}

impl Drop for SessionInternal {
    fn drop(&mut self) {
        debug!("drop Session[{}]", self.session_id);
    }
}

// type SErr = ::std::fmt::Debug;

struct DispatchTask<S>(S, SessionWeak)
where
    S: Stream<Item = Result<((u8, Bytes), ())>>;

impl<S> Future for DispatchTask<S>
where
    // SErr: ::std::fmt::Debug,
    S: Stream<Item = Result<((u8, Bytes), ())>>,
{
    type Output = Result<((), ())>;

    fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        let session = match self.1.try_upgrade() {
            Some(session) => session,
            None => return Poll::Ready(()),
        };

        loop {
            let (cmd, data) = match self.unwrap().0.poll() {
                Poll::Ready(Ok(Some(t))) => t,
                Poll::Ready(Ok(None)) => {
                    warn!("Connection to server closed.");
                    session.shutdown();
                    return Ok(Poll::Ready(()));
                }
                Poll::Pending => return Poll::Pending,
                Poll::Ready(Err(e)) => {
                    session.shutdown();
                    return Err(From::from(e));
                }
            };

            session.dispatch(cmd, data);
        }
    }
}

impl<S> Drop for DispatchTask<S>
where
    S: Stream<Item = Result<((u8, Bytes), ())>>,
{
    fn drop(&mut self) {
        debug!("drop Dispatch");
    }
}
<commit_msg>[Core] WIP: Sessions<commit_after>use std::io;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, RwLock, Weak};
use std::time::{SystemTime, UNIX_EPOCH};

use byteorder::{BigEndian, ByteOrder};
use bytes::Bytes;
// use futures::sync::mpsc;
// use futures::{Async, Future, IntoFuture, Poll, Stream};
// use tokio::runtime::{current_thread, current_thread::Handle};

// use futures::future::{IntoFuture, Remote};
use futures::{channel::mpsc, future, Future, Stream, StreamExt, TryFutureExt};
use std::{
    pin::Pin,
    task::{Context, Poll},
};

use tokio::runtime::Handle;

use crate::apresolve::apresolve_or_fallback;
// use crate::audio_key::AudioKeyManager;
use crate::authentication::Credentials;
use crate::cache::Cache;
// use crate::channel::ChannelManager;
// use crate::component::Lazy;
use crate::config::SessionConfig;
use crate::connection;
// use crate::mercury::MercuryManager;

struct SessionData {
    country: String,
    time_delta: i64,
    canonical_username: String,
    invalid: bool,
}

struct SessionInternal {
    config: SessionConfig,
    data: RwLock<SessionData>,

    tx_connection: mpsc::UnboundedSender<io::Result<(u8, Vec<u8>)>>,

    // audio_key: Lazy<AudioKeyManager>,
    // channel: Lazy<ChannelManager>,
    // mercury: Lazy<MercuryManager>,
    cache: Option<Arc<Cache>>,
    handle: Mutex<Handle>,
    session_id: usize,
}

static SESSION_COUNTER: AtomicUsize = AtomicUsize::new(0);

#[derive(Clone)]
pub struct Session(Arc<SessionInternal>);

// TODO: Define better errors!
type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;

impl Session {
    pub async fn connect(
        config: SessionConfig,
        credentials: Credentials,
        cache: Option<Cache>,
        handle: Handle,
    ) -> Result<Session> {
        let access_point_addr =
            apresolve_or_fallback::<io::Error>(&config.proxy, &config.ap_port).await?;

        let proxy = config.proxy.clone();
        info!("Connecting to AP \"{}\"", access_point_addr);
        let connection = connection::connect(access_point_addr, &proxy);

        let device_id = config.device_id.clone();
        let authentication = connection.and_then(move |connection| {
            connection::authenticate(connection, credentials, device_id)
        });

        let result = match authentication.await {
            Ok((transport, reusable_credentials)) => {
                info!("Authenticated as \"{}\" !", reusable_credentials.username);
                if let Some(ref cache) = cache {
                    cache.save_credentials(&reusable_credentials);
                }

                let (session, tasks) = Session::create(
                    &handle,
                    transport,
                    config,
                    cache,
                    reusable_credentials.username.clone(),
                );

                tokio::task::spawn_local(async move { tasks });

                Ok(session)
            }
            Err(e) => {
                error!("Unable to Connect");
                Err(e.into())
            }
        };

        result
    }

    fn create(
        handle: &Handle,
        transport: connection::Transport,
        config: SessionConfig,
        cache: Option<Cache>,
        username: String,
    ) -> (Session, Box<dyn Future<Output = (Result<()>, Result<()>)>>) {
        let (sink, stream) = transport.split();

        let (sender_tx, sender_rx) = mpsc::unbounded();
        let session_id = SESSION_COUNTER.fetch_add(1, Ordering::Relaxed);

        debug!("new Session[{}]", session_id);

        let session = Session(Arc::new(SessionInternal {
            config,
            data: RwLock::new(SessionData {
                country: String::new(),
                canonical_username: username,
                invalid: false,
                time_delta: 0,
            }),

            tx_connection: sender_tx,

            cache: cache.map(Arc::new),

            // audio_key: Lazy::new(),
            // channel: Lazy::new(),
            // mercury: Lazy::new(),
            handle: Mutex::new(handle.clone()),
            session_id,
        }));

        let sender_task = sender_rx
            .forward(sink)
            .map_err(|e| -> Box<dyn std::error::Error> { Box::new(e) });

        let receiver_task = DispatchTask(stream, session.weak());

        let task = Box::new(future::join(receiver_task, sender_task));

        (session, task)
    }

    // pub fn audio_key(&self) -> &AudioKeyManager {
    //     self.0.audio_key.get(|| AudioKeyManager::new(self.weak()))
    // }

    // pub fn channel(&self) -> &ChannelManager {
    //     self.0.channel.get(|| ChannelManager::new(self.weak()))
    // }

    // pub fn mercury(&self) -> &MercuryManager {
    //     self.0.mercury.get(|| MercuryManager::new(self.weak()))
    // }

    pub fn time_delta(&self) -> i64 {
        self.0.data.read().unwrap().time_delta
    }

    // Spawn a future directly
    // pub fn spawn<F>(&self, f: F)
    // where
    //     F: Future<Output = ()> + Send + 'static,
    // {
    //     let handle = self.0.handle.lock().unwrap();
    //     let spawn_res = handle.spawn(f);
    //     match spawn_res {
    //         Ok(_) => (),
    //         Err(e) => error!("Session SpawnErr {:?}", e),
    //     }
    // }

    // pub fn spawn<F, R>(&self, f: F)
    // where
    //     F: FnOnce() -> R + Send + 'static,
    //     R: Future<Item = (), Error = ()> + Send + 'static,
    // {
    //     // This fails when called from a different thread
    //     // current_thread::spawn(future::lazy(|| f()));
    //
    //     // These fail when the Future doesn't implement Send
    //     let handle = self.0.handle.lock().unwrap();
    //     let spawn_res = handle.spawn(lazy(|| f()));
    //
    //     // let mut te = current_thread::TaskExecutor::current();
    //     // let spawn_res = te.spawn_local(Box::new(future::lazy(|| f())));
    //
    //     match spawn_res {
    //         Ok(_) => (),
    //         Err(e) => error!("Session SpawnErr {:?}", e),
    //     }
    // }

    fn debug_info(&self) {
        debug!(
            "Session[{}] strong={} weak={}",
            self.0.session_id,
            Arc::strong_count(&self.0),
            Arc::weak_count(&self.0)
        );
    }

    // #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))]
    fn dispatch(&self, cmd: u8, data: Bytes) {
        match cmd {
            0x4 => {
                let server_timestamp = BigEndian::read_u32(data.as_ref()) as i64;
                let timestamp = match SystemTime::now().duration_since(UNIX_EPOCH) {
                    Ok(dur) => dur,
                    Err(err) => err.duration(),
                }
                .as_secs() as i64;

                self.0.data.write().unwrap().time_delta = server_timestamp - timestamp;

                self.debug_info();
                self.send_packet(0x49, vec![0, 0, 0, 0]);
            }
            0x4a => (),
            0x1b => {
                let country = String::from_utf8(data.as_ref().to_owned()).unwrap();
                info!("Country: {:?}", country);
                self.0.data.write().unwrap().country = country;
            }

            // 0x9 | 0xa => self.channel().dispatch(cmd, data),
            // 0xd | 0xe => self.audio_key().dispatch(cmd, data),
            // 0xb2..=0xb6 => self.mercury().dispatch(cmd, data),
            _ => trace!("Unknown dispatch cmd :{:?} {:?}", cmd, data),
        }
    }

    pub fn send_packet(&self, cmd: u8, data: Vec<u8>) {
        self.0
            .tx_connection
            .unbounded_send(Ok((cmd, data)))
            .unwrap();
    }

    pub fn cache(&self) -> Option<&Arc<Cache>> {
        self.0.cache.as_ref()
    }

    fn config(&self) -> &SessionConfig {
        &self.0.config
    }

    pub fn username(&self) -> String {
        self.0.data.read().unwrap().canonical_username.clone()
    }

    pub fn country(&self) -> String {
        self.0.data.read().unwrap().country.clone()
    }

    pub fn device_id(&self) -> &str {
        &self.config().device_id
    }

    fn weak(&self) -> SessionWeak {
        SessionWeak(Arc::downgrade(&self.0))
    }

    pub fn session_id(&self) -> usize {
        self.0.session_id
    }

    pub fn shutdown(&self) {
        debug!("Invalidating session[{}]", self.0.session_id);
        self.0.data.write().unwrap().invalid = true;
        // self.mercury().shutdown();
        // self.channel().shutdown();
    }

    pub fn is_invalid(&self) -> bool {
        self.0.data.read().unwrap().invalid
    }
}

#[derive(Clone)]
pub struct SessionWeak(Weak<SessionInternal>);

impl SessionWeak {
    fn try_upgrade(&self) -> Option<Session> {
        self.0.upgrade().map(Session)
    }

    pub(crate) fn upgrade(&self) -> Session {
        self.try_upgrade().expect("Session died")
    }
}

impl Drop for SessionInternal {
    fn drop(&mut self) {
        debug!("drop Session[{}]", self.session_id);
    }
}

struct DispatchTask<S>(S, SessionWeak)
where
    S: Stream<Item = io::Result<(u8, Bytes)>> + Unpin;

impl<S: Stream<Item = io::Result<(u8, Bytes)>>> Future for DispatchTask<S>
where
    S: Stream<Item = io::Result<(u8, Bytes)>> + Unpin,
{
    type Output = Result<()>;

    fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
        let session = match self.1.try_upgrade() {
            Some(session) => session,
            None => return Poll::Ready(Ok(())),
        };

        loop {
            let (cmd, data) = match Pin::new(&mut self.0).poll_next(cx) {
                Poll::Ready(Some(Ok(t))) => t,
                Poll::Ready(Some(Err(e))) => {
                    warn!("Server Connectioned errored");
                    session.shutdown();
                    return Poll::Ready(Err(Box::new(e)));
                }
                Poll::Ready(None) => {
                    warn!("Connection to server closed.");
                    session.shutdown();
                    return Poll::Ready(Ok(()));
                }
                Poll::Pending => return Poll::Pending,
            };
            session.dispatch(cmd, data);
        }
    }
}

impl<S> Drop for DispatchTask<S>
where
    S: Stream<Item = io::Result<(u8, Bytes)>> + Unpin,
{
    fn drop(&mut self) {
        debug!("drop Dispatch");
    }
}
<|endoftext|>


<commit_before>const n: usize = (16*1024);

struct foo {
    chaMem: *mut [u32; n],
}

impl foo {
    pub fn new() -> foo {
        let mem: *mut [u32; n] = unsafe { ::std::mem::transmute(Box::new([1; n])) };
        foo {chaMem: mem}
    }

    pub fn get_sig_ptr(&mut self, cha_signal: *mut *mut u32) {
        unsafe {
            *cha_signal = self.chaMem as *mut _;
        }
    }

    pub fn get_sig_ptr2(&mut self) -> *mut u32 {
        return self.chaMem as *mut _;
    }

    pub fn get_sig_ptr3(&mut self) -> *mut [u32; n] {
        return self.chaMem;
    }

    pub fn get_sig_ptr4(&mut self) -> &mut [u32; n] {
        unsafe {
            return &mut *(self.chaMem);
        }
    }
}

// This code is editable and runnable!
fn main() {
    let mut f = foo::new();

    let mut cha_signal1: *mut u32 = ::std::ptr::null_mut();
    f.get_sig_ptr(&mut cha_signal1);

    for i in 1..n {
        println!("{}", unsafe { *cha_signal1.offset(i as isize) }); // (*cha_signal)[i]
    }

    let mut cha_signal2: *mut u32 = f.get_sig_ptr2();

    for i in 1..n {
        println!("{}", unsafe { *cha_signal2.offset(i as isize) });
    }

    let mut cha_signal3: *mut [u32; n] = f.get_sig_ptr3();

    for i in 1..n {
        println!("{}", unsafe { (*cha_signal3)[i] });
    }

    let mut cha_signal4: &mut [u32; n] = f.get_sig_ptr4();

    for i in 1..n {
        println!("{}", cha_signal4[i]);
    }
}<commit_msg>added comments<commit_after>const n: usize = (16*1024);

struct foo {
    chaMem: *mut [u32; n],
}

impl foo {
    pub fn new() -> foo {
        let mem: *mut [u32; n] = unsafe { ::std::mem::transmute(Box::new([1; n])) };
        foo {chaMem: mem}
    }

    pub fn get_sig_ptr(&mut self, cha_signal: *mut *mut u32) {
        unsafe {
            *cha_signal = self.chaMem as *mut _;
        }
    }

    pub fn get_sig_ptr2(&mut self) -> *mut u32 {
        return self.chaMem as *mut _;
    }

    pub fn get_sig_ptr3(&mut self) -> *mut [u32; n] {
        return self.chaMem;
    }

    pub fn get_sig_ptr4(&mut self) -> &mut [u32; n] {
        unsafe {
            return &mut *(self.chaMem);
        }
    }
}

// This code is editable and runnable!
fn main() {
    let mut f = foo::new();

    let mut cha_signal1: *mut u32 = ::std::ptr::null_mut();
    f.get_sig_ptr(&mut cha_signal1);

    for i in 1..n {
        println!("{}", unsafe { *cha_signal1.offset(i as isize) }); // (*cha_signal)[i]
    }

    let mut cha_signal2: *mut u32 = f.get_sig_ptr2();

    for i in 1..n {
        println!("{}", unsafe { *cha_signal2.offset(i as isize) });
    }

    let mut cha_signal3: *mut [u32; n] = f.get_sig_ptr3();

    for i in 1..n {
        println!("{}", unsafe { (*cha_signal3)[i] });
    }

    // preferred version
    let mut cha_signal4: &mut [u32; n] = f.get_sig_ptr4();

    for i in 1..n {
        println!("{}", cha_signal4[i]);
    }
}<|endoftext|>


<commit_before>use autograd::{Function, FuncIntf, FuncDelegate, Variable, FIWrap};
use tensor::{TensorKindList, OptTensorKindList, TensorKind};
use ::*;
use nn::backends::backend::*;

#[builder(pattern="owned")]
#[derive(Builder, Clone)]
pub struct ConvNdArgs {
    stride: Vec<i32>,
    padding: Vec<i32>,
    dilation: Vec<i32>,
    kernel_size: Vec<i32>,
    #[builder(default="false")]
    transposed: bool,
    output_padding: Vec<i32>,
    groups: u32,
    #[builder(default="false")]
    benchmark: bool,
    #[builder(default="false")]
    cudnn_enabled: bool,
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct Conv1dFArgs {
    #[builder(default="vec![1]")]
    pub kernel_size: Vec<i32>,
    #[builder(default="vec![1]")]
    stride: Vec<i32>,
    #[builder(default="vec![0]")]
    padding: Vec<i32>,
    #[builder(default="vec![1]")]
    dilation: Vec<i32>,
    #[builder(default="1")]
    groups: u32,
}

impl Default for Conv1dFArgs {
    fn default() -> Self {
        Conv1dFArgsBuilder::default().build().unwrap()
    }
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct Conv2dFArgs {
    #[builder(default="1")]
    pub in_features: usize,
    #[builder(default="1")]
    pub out_features: usize,
    #[builder(default="vec![1, 1]")]
    pub kernel_size: Vec<i32>,
    #[builder(default="vec![1, 1]")]
    pub stride: Vec<i32>,
    #[builder(default="vec![0, 0]")]
    pub padding: Vec<i32>,
    #[builder(default="vec![1, 1]")]
    pub dilation: Vec<i32>,
    #[builder(default="1")]
    pub groups: u32,
}

impl Default for Conv2dFArgs {
    fn default() -> Self {
        Conv2dFArgsBuilder::default().build().unwrap()
    }
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct Conv3dFArgs {
    #[builder(default="vec![1, 1, 1]")]
    pub kernel_size: Vec<i32>,
    #[builder(default="vec![1, 1, 1]")]
    stride: Vec<i32>,
    #[builder(default="vec![0, 0, 0]")]
    padding: Vec<i32>,
    #[builder(default="vec![1, 1, 1]")]
    dilation: Vec<i32>,
    #[builder(default="1")]
    groups: u32,
}

impl Default for Conv3dFArgs {
    fn default() -> Self {
        Conv3dFArgsBuilder::default().build().unwrap()
    }
}

impl<'a> From<&'a mut Conv2dFArgs> for ConvNdArgs {
    fn from(input: &'a mut Conv2dFArgs) -> Self {
        ConvNdArgsBuilder::default()
            .kernel_size(input.kernel_size.clone())
            .stride(input.stride.clone())
            .padding(input.padding.clone())
            .dilation(input.dilation.clone())
            .groups(input.groups)
            .output_padding(vec![0, 0])
            .build()
            .unwrap()
    }
}
impl ConvNdArgs {
    fn is_dilated(&self) -> bool {
        self.dilation.iter().any(|v| *v != 1)
    }
}

impl_func_args!(ConvNd, ConvNdArgs);

fn compute_output(input: &mut TensorKind,
                  weight: &mut TensorKind,
                  bias: &mut Option<TensorKind>,
                  columns: &mut TensorKind,
                  ones: &mut TensorKind,
                  args: &ConvNdArgs)
                  -> TensorKind {

    unimplemented!();
    let mut output = input.new(());
    let dim = input.size().len();
    let dilated = args.is_dilated();
    let mut backend = input.backend();

    if dilated {
        if !args.transposed && dim == 4 {
            backend.SpatialDilatedConvolution_updateOutput(input,
                                                           &mut output,
                                                           weight,
                                                           bias,
                                                           columns,
                                                           ones,
                                                           args.kernel_size[1],
                                                           args.kernel_size[0],
                                                           args.stride[1],
                                                           args.stride[0],
                                                           args.padding[1],
                                                           args.padding[0],
                                                           args.dilation[1],
                                                           args.dilation[0])
        } else if !args.transposed && dim == 5 {
            backend.VolumetricDilatedConvolution_updateOutput(input,
                                                              &mut output,
                                                              weight,
                                                              bias,
                                                              columns,
                                                              ones,
                                                              args.kernel_size[0],
                                                              args.kernel_size[2],
                                                              args.kernel_size[1],
                                                              args.stride[0],
                                                              args.stride[2],
                                                              args.stride[1],
                                                              args.padding[0],
                                                              args.padding[2],
                                                              args.padding[1],
                                                              args.dilation[0],
                                                              args.dilation[2],
                                                              args.dilation[1])
        } else {
            panic!("unsupported ConvNd parameters")
        }
    } else {
        if args.transposed {
            /* !dilated && transposed */
            if dim == 4 {
                backend.SpatialFullConvolution_updateOutput(input,
                                                            &mut output,
                                                            weight,
                                                            bias,
                                                            columns,
                                                            ones,
                                                            args.kernel_size[1],
                                                            args.kernel_size[0],
                                                            args.stride[1],
                                                            args.stride[0],
                                                            args.padding[1],
                                                            args.padding[0],
                                                            args.output_padding[1],
                                                            args.output_padding[0]);
            } else if dim == 5 {
                backend.VolumetricFullConvolution_updateOutput(input,
                                                               &mut output,
                                                               weight,
                                                               bias,
                                                               columns,
                                                               ones,
                                                               args.stride[0],
                                                               args.stride[2],
                                                               args.stride[1],
                                                               args.padding[0],
                                                               args.padding[2],
                                                               args.padding[1],
                                                               args.output_padding[0],
                                                               args.output_padding[2],
                                                               args.output_padding[1]);
            } else {
                panic!("unsupported ConvNd parameters")
            }
        } else {
            /* !transposed */

            /* !dilated && !transposed */
            if dim == 4 {
                backend.SpatialConvolutionMM_updateOutput(input,
                                                          &mut output,
                                                          weight,
                                                          bias,
                                                          columns,
                                                          ones,
                                                          args.kernel_size[1],
                                                          args.kernel_size[0],
                                                          args.stride[1],
                                                          args.stride[0],
                                                          args.padding[1],
                                                          args.padding[0]);
            } else if dim == 5 && input.is_cuda() {
                backend.VolumetricConvolution_updateOutput(input,
                                                           &mut output,
                                                           weight,
                                                           bias,
                                                           columns,
                                                           ones,
                                                           args.stride[0],
                                                           args.stride[2],
                                                           args.stride[1],
                                                           args.padding[0],
                                                           args.padding[2],
                                                           args.padding[1]);
            } else if dim == 5 {
                backend.VolumetricConvolutionMM_updateOutput(input,
                                                             &mut output,
                                                             weight,
                                                             bias,
                                                             columns,
                                                             args.kernel_size[0],
                                                             args.kernel_size[2],
                                                             args.kernel_size[1],
                                                             args.stride[0],
                                                             args.stride[2],
                                                             args.stride[1],
                                                             args.padding[0],
                                                             args.padding[2],
                                                             args.padding[1]);
            } else {
                panic!("unsupported ConvNd parameters")
            }
        }
    }
    output
}

fn compute_grad_input(input: &mut TensorKind,
                      grad_output: &mut TensorKind,
                      weight: &mut TensorKind,
                      columns: &mut TensorKind,
                      ones: &mut TensorKind,
                      args: &ConvNdArgs)
                      -> TensorKind {
    let size = input.size();
    let dim = size.len();
    let mut grad_input = input.new(size);
    let dilated = args.is_dilated();
    let mut backend = input.backend();

    if dilated && !args.transposed {
        /* dilated && !transposed */
        if dim == 4 {
            backend.SpatialDilatedConvolution_updateGradInput(input,
                                                              grad_output,
                                                              &mut grad_input,
                                                              weight,
                                                              columns,
                                                              args.kernel_size[1],
                                                              args.kernel_size[0],
                                                              args.stride[1],
                                                              args.stride[0],
                                                              args.padding[1],
                                                              args.padding[0],
                                                              args.dilation[1],
                                                              args.dilation[0]);
        } else if dim == 5 {
            backend.VolumetricDilatedConvolution_updateGradInput(input,
                                                                 grad_output,
                                                                 &mut grad_input,
                                                                 weight,
                                                                 columns,
                                                                 args.kernel_size[0],
                                                                 args.kernel_size[2],
                                                                 args.kernel_size[1],
                                                                 args.stride[0],
                                                                 args.stride[2],
                                                                 args.stride[1],
                                                                 args.padding[0],
                                                                 args.padding[2],
                                                                 args.padding[1],
                                                                 args.dilation[0],
                                                                 args.dilation[2],
                                                                 args.dilation[1]);
        } else {
            panic!("unsupported ConvNdBackward parameters")
        }
    } else if dilated && args.transposed {
        panic!("unsupported ConvNdBackward parameters")
    } else if !dilated && args.transposed {
        /* !dilated && transposed */
        if dim == 4 {
            backend.SpatialFullConvolution_updateGradInput(input,
                                                           grad_output,
                                                           &mut grad_input,
                                                           weight,
                                                           columns,
                                                           args.kernel_size[1],
                                                           args.kernel_size[0],
                                                           args.stride[1],
                                                           args.stride[0],
                                                           args.padding[1],
                                                           args.padding[0],
                                                           args.output_padding[1],
                                                           args.output_padding[0]);
        } else if dim == 5 {
            backend.VolumetricFullConvolution_updateGradInput(input,
                                                              grad_output,
                                                              &mut grad_input,
                                                              weight,
                                                              columns,
                                                              ones,
                                                              args.stride[0],
                                                              args.stride[2],
                                                              args.stride[1],
                                                              args.padding[0],
                                                              args.padding[2],
                                                              args.padding[1],
                                                              args.output_padding[0],
                                                              args.output_padding[2],
                                                              args.output_padding[1]);
        } else {
            panic!("unsupported ConvNdBackward parameters")
        }
    } else
    /* !transposed */
    {
        /* !dilated && !transposed */
        if dim == 4 {
            backend.SpatialConvolutionMM_updateGradInput(input,
                                                         grad_output,
                                                         &mut grad_input,
                                                         weight,
                                                         columns,
                                                         ones,
                                                         args.kernel_size[1],
                                                         args.kernel_size[0],
                                                         args.stride[1],
                                                         args.stride[0],
                                                         args.padding[1],
                                                         args.padding[0]);
        } else if dim == 5 && input.is_cuda() {
            backend.VolumetricConvolution_updateGradInput(input,
                                                          grad_output,
                                                          &mut grad_input,
                                                          weight,
                                                          columns,
                                                          args.stride[0],
                                                          args.stride[2],
                                                          args.stride[1],
                                                          args.padding[0],
                                                          args.padding[2],
                                                          args.padding[1]);
        } else if dim == 5 {
            backend.VolumetricConvolutionMM_updateGradInput(input,
                                                            grad_output,
                                                            &mut grad_input,
                                                            weight,
                                                            columns,
                                                            ones,
                                                            args.kernel_size[0],
                                                            args.kernel_size[2],
                                                            args.kernel_size[1],
                                                            args.stride[0],
                                                            args.stride[2],
                                                            args.stride[1],
                                                            args.padding[0],
                                                            args.padding[2],
                                                            args.padding[1]);
        } else {
            panic!("unsupported ConvNdBackward parameters")
        }
    }

    grad_input
}
impl FuncIntf for ConvNd {
    fn forward(&mut self, mut input: &mut TensorKindList) -> TensorKindList {
        // run native code here
        unimplemented!()
    }
    fn backward(&mut self, mut input: &mut OptTensorKindList) -> OptTensorKindList {
        // run native code here
        unimplemented!()
    }
}
<commit_msg>implement conv forward pass<commit_after>use autograd::{Function, FuncIntf, FuncDelegate, Variable, FIWrap};
use tensor::{TensorKindList, OptTensorKindList, TensorKind};
use ::*;
use nn::backends::backend::*;

#[builder(pattern="owned")]
#[derive(Builder, Clone)]
pub struct ConvNdArgs {
    stride: Vec<i32>,
    padding: Vec<i32>,
    dilation: Vec<i32>,
    kernel_size: Vec<i32>,
    #[builder(default="false")]
    transposed: bool,
    output_padding: Vec<i32>,
    groups: u32,
    #[builder(default="false")]
    benchmark: bool,
    #[builder(default="false")]
    cudnn_enabled: bool,
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct Conv1dFArgs {
    #[builder(default="vec![1]")]
    pub kernel_size: Vec<i32>,
    #[builder(default="vec![1]")]
    stride: Vec<i32>,
    #[builder(default="vec![0]")]
    padding: Vec<i32>,
    #[builder(default="vec![1]")]
    dilation: Vec<i32>,
    #[builder(default="1")]
    groups: u32,
}

impl Default for Conv1dFArgs {
    fn default() -> Self {
        Conv1dFArgsBuilder::default().build().unwrap()
    }
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct Conv2dFArgs {
    #[builder(default="1")]
    pub in_features: usize,
    #[builder(default="1")]
    pub out_features: usize,
    #[builder(default="vec![1, 1]")]
    pub kernel_size: Vec<i32>,
    #[builder(default="vec![1, 1]")]
    pub stride: Vec<i32>,
    #[builder(default="vec![0, 0]")]
    pub padding: Vec<i32>,
    #[builder(default="vec![1, 1]")]
    pub dilation: Vec<i32>,
    #[builder(default="1")]
    pub groups: u32,
}

impl Default for Conv2dFArgs {
    fn default() -> Self {
        Conv2dFArgsBuilder::default().build().unwrap()
    }
}

#[builder(pattern="owned")]
#[derive(Builder)]
pub struct Conv3dFArgs {
    #[builder(default="vec![1, 1, 1]")]
    pub kernel_size: Vec<i32>,
    #[builder(default="vec![1, 1, 1]")]
    stride: Vec<i32>,
    #[builder(default="vec![0, 0, 0]")]
    padding: Vec<i32>,
    #[builder(default="vec![1, 1, 1]")]
    dilation: Vec<i32>,
    #[builder(default="1")]
    groups: u32,
}

impl Default for Conv3dFArgs {
    fn default() -> Self {
        Conv3dFArgsBuilder::default().build().unwrap()
    }
}

impl<'a> From<&'a mut Conv2dFArgs> for ConvNdArgs {
    fn from(input: &'a mut Conv2dFArgs) -> Self {
        ConvNdArgsBuilder::default()
            .kernel_size(input.kernel_size.clone())
            .stride(input.stride.clone())
            .padding(input.padding.clone())
            .dilation(input.dilation.clone())
            .groups(input.groups)
            .output_padding(vec![0, 0])
            .build()
            .unwrap()
    }
}
impl ConvNdArgs {
    fn is_dilated(&self) -> bool {
        self.dilation.iter().any(|v| *v != 1)
    }
}

impl_func_args!(ConvNd, ConvNdArgs);

fn compute_output(input: &mut TensorKind,
                  weight: &mut TensorKind,
                  bias: &mut Option<TensorKind>,
                  columns: &mut TensorKind,
                  ones: &mut TensorKind,
                  args: &ConvNdArgs)
                  -> TensorKind {

    unimplemented!();
    let mut output = input.new(());
    let dim = input.size().len();
    let dilated = args.is_dilated();
    let mut backend = input.backend();

    if dilated {
        if !args.transposed && dim == 4 {
            backend.SpatialDilatedConvolution_updateOutput(input,
                                                           &mut output,
                                                           weight,
                                                           bias,
                                                           columns,
                                                           ones,
                                                           args.kernel_size[1],
                                                           args.kernel_size[0],
                                                           args.stride[1],
                                                           args.stride[0],
                                                           args.padding[1],
                                                           args.padding[0],
                                                           args.dilation[1],
                                                           args.dilation[0])
        } else if !args.transposed && dim == 5 {
            backend.VolumetricDilatedConvolution_updateOutput(input,
                                                              &mut output,
                                                              weight,
                                                              bias,
                                                              columns,
                                                              ones,
                                                              args.kernel_size[0],
                                                              args.kernel_size[2],
                                                              args.kernel_size[1],
                                                              args.stride[0],
                                                              args.stride[2],
                                                              args.stride[1],
                                                              args.padding[0],
                                                              args.padding[2],
                                                              args.padding[1],
                                                              args.dilation[0],
                                                              args.dilation[2],
                                                              args.dilation[1])
        } else {
            panic!("unsupported ConvNd parameters")
        }
    } else {
        if args.transposed {
            /* !dilated && transposed */
            if dim == 4 {
                backend.SpatialFullConvolution_updateOutput(input,
                                                            &mut output,
                                                            weight,
                                                            bias,
                                                            columns,
                                                            ones,
                                                            args.kernel_size[1],
                                                            args.kernel_size[0],
                                                            args.stride[1],
                                                            args.stride[0],
                                                            args.padding[1],
                                                            args.padding[0],
                                                            args.output_padding[1],
                                                            args.output_padding[0]);
            } else if dim == 5 {
                backend.VolumetricFullConvolution_updateOutput(input,
                                                               &mut output,
                                                               weight,
                                                               bias,
                                                               columns,
                                                               ones,
                                                               args.stride[0],
                                                               args.stride[2],
                                                               args.stride[1],
                                                               args.padding[0],
                                                               args.padding[2],
                                                               args.padding[1],
                                                               args.output_padding[0],
                                                               args.output_padding[2],
                                                               args.output_padding[1]);
            } else {
                panic!("unsupported ConvNd parameters")
            }
        } else {
            /* !transposed */

            /* !dilated && !transposed */
            if dim == 4 {
                backend.SpatialConvolutionMM_updateOutput(input,
                                                          &mut output,
                                                          weight,
                                                          bias,
                                                          columns,
                                                          ones,
                                                          args.kernel_size[1],
                                                          args.kernel_size[0],
                                                          args.stride[1],
                                                          args.stride[0],
                                                          args.padding[1],
                                                          args.padding[0]);
            } else if dim == 5 && input.is_cuda() {
                backend.VolumetricConvolution_updateOutput(input,
                                                           &mut output,
                                                           weight,
                                                           bias,
                                                           columns,
                                                           ones,
                                                           args.stride[0],
                                                           args.stride[2],
                                                           args.stride[1],
                                                           args.padding[0],
                                                           args.padding[2],
                                                           args.padding[1]);
            } else if dim == 5 {
                backend.VolumetricConvolutionMM_updateOutput(input,
                                                             &mut output,
                                                             weight,
                                                             bias,
                                                             columns,
                                                             args.kernel_size[0],
                                                             args.kernel_size[2],
                                                             args.kernel_size[1],
                                                             args.stride[0],
                                                             args.stride[2],
                                                             args.stride[1],
                                                             args.padding[0],
                                                             args.padding[2],
                                                             args.padding[1]);
            } else {
                panic!("unsupported ConvNd parameters")
            }
        }
    }
    output
}

fn compute_grad_input(input: &mut TensorKind,
                      grad_output: &mut TensorKind,
                      weight: &mut TensorKind,
                      columns: &mut TensorKind,
                      ones: &mut TensorKind,
                      args: &ConvNdArgs)
                      -> TensorKind {
    let size = input.size();
    let dim = size.len();
    let mut grad_input = input.new(size);
    let dilated = args.is_dilated();
    let mut backend = input.backend();

    if dilated && !args.transposed {
        /* dilated && !transposed */
        if dim == 4 {
            backend.SpatialDilatedConvolution_updateGradInput(input,
                                                              grad_output,
                                                              &mut grad_input,
                                                              weight,
                                                              columns,
                                                              args.kernel_size[1],
                                                              args.kernel_size[0],
                                                              args.stride[1],
                                                              args.stride[0],
                                                              args.padding[1],
                                                              args.padding[0],
                                                              args.dilation[1],
                                                              args.dilation[0]);
        } else if dim == 5 {
            backend.VolumetricDilatedConvolution_updateGradInput(input,
                                                                 grad_output,
                                                                 &mut grad_input,
                                                                 weight,
                                                                 columns,
                                                                 args.kernel_size[0],
                                                                 args.kernel_size[2],
                                                                 args.kernel_size[1],
                                                                 args.stride[0],
                                                                 args.stride[2],
                                                                 args.stride[1],
                                                                 args.padding[0],
                                                                 args.padding[2],
                                                                 args.padding[1],
                                                                 args.dilation[0],
                                                                 args.dilation[2],
                                                                 args.dilation[1]);
        } else {
            panic!("unsupported ConvNdBackward parameters")
        }
    } else if dilated && args.transposed {
        panic!("unsupported ConvNdBackward parameters")
    } else if !dilated && args.transposed {
        /* !dilated && transposed */
        if dim == 4 {
            backend.SpatialFullConvolution_updateGradInput(input,
                                                           grad_output,
                                                           &mut grad_input,
                                                           weight,
                                                           columns,
                                                           args.kernel_size[1],
                                                           args.kernel_size[0],
                                                           args.stride[1],
                                                           args.stride[0],
                                                           args.padding[1],
                                                           args.padding[0],
                                                           args.output_padding[1],
                                                           args.output_padding[0]);
        } else if dim == 5 {
            backend.VolumetricFullConvolution_updateGradInput(input,
                                                              grad_output,
                                                              &mut grad_input,
                                                              weight,
                                                              columns,
                                                              ones,
                                                              args.stride[0],
                                                              args.stride[2],
                                                              args.stride[1],
                                                              args.padding[0],
                                                              args.padding[2],
                                                              args.padding[1],
                                                              args.output_padding[0],
                                                              args.output_padding[2],
                                                              args.output_padding[1]);
        } else {
            panic!("unsupported ConvNdBackward parameters")
        }
    } else
    /* !transposed */
    {
        /* !dilated && !transposed */
        if dim == 4 {
            backend.SpatialConvolutionMM_updateGradInput(input,
                                                         grad_output,
                                                         &mut grad_input,
                                                         weight,
                                                         columns,
                                                         ones,
                                                         args.kernel_size[1],
                                                         args.kernel_size[0],
                                                         args.stride[1],
                                                         args.stride[0],
                                                         args.padding[1],
                                                         args.padding[0]);
        } else if dim == 5 && input.is_cuda() {
            backend.VolumetricConvolution_updateGradInput(input,
                                                          grad_output,
                                                          &mut grad_input,
                                                          weight,
                                                          columns,
                                                          args.stride[0],
                                                          args.stride[2],
                                                          args.stride[1],
                                                          args.padding[0],
                                                          args.padding[2],
                                                          args.padding[1]);
        } else if dim == 5 {
            backend.VolumetricConvolutionMM_updateGradInput(input,
                                                            grad_output,
                                                            &mut grad_input,
                                                            weight,
                                                            columns,
                                                            ones,
                                                            args.kernel_size[0],
                                                            args.kernel_size[2],
                                                            args.kernel_size[1],
                                                            args.stride[0],
                                                            args.stride[2],
                                                            args.stride[1],
                                                            args.padding[0],
                                                            args.padding[2],
                                                            args.padding[1]);
        } else {
            panic!("unsupported ConvNdBackward parameters")
        }
    }

    grad_input
}
fn compute_grad_params(input: &mut TensorKind,
                       grad_output: &mut TensorKind,
                       weight: &mut TensorKind,
                       bias: &mut Option<TensorKind>,
                       columns: &mut TensorKind,
                       ones: &mut TensorKind,
                       args: &ConvNdArgs)
                       -> (TensorKind, Option<TensorKind>) {
    let dim = input.size().len();
    let dilated = args.is_dilated();
    let backend = input.backend();

    let mut grad_weight = weight.new(());
    grad_weight.zero_();
    let mut backend = input.backend();
    let mut grad_bias = None;
    /*
    if let &mut Some(ref bias) = bias {
        if args.should_compute_output(2) {
        	let new_bias = bias.new(());
        	new_bias.zero_();
            grad_bias = Some(new_bias);
        }
    }
*/
    if dim != 4 && dim != 5 {
        panic!("unsupported ConvNdBackward dimension: {}", dim)
    }
    if dilated && args.transposed {
        /* dilated && transposed */
        /* NOT IMPLEMENTED */
        panic!("dilated AND transposed not supported as ConvNdBackward parameters")
    } else if dilated && !args.transposed {
        /* dilated && !transposed */
        if dim == 4 {
            backend.SpatialDilatedConvolution_accGradParameters(input,
                                                                grad_output,
                                                                &mut grad_weight,
                                                                &mut grad_bias,
                                                                columns,
                                                                ones,
                                                                args.kernel_size[1],
                                                                args.kernel_size[0],
                                                                args.stride[1],
                                                                args.stride[0],
                                                                args.padding[1],
                                                                args.padding[0],
                                                                args.dilation[1],
                                                                args.dilation[0],
                                                                1.0);
        } else if dim == 5 {
            backend.VolumetricDilatedConvolution_accGradParameters(input,
                                                                   grad_output,
                                                                   &mut grad_weight,
                                                                   &mut grad_bias,
                                                                   columns,
                                                                   ones,
                                                                   args.kernel_size[0],
                                                                   args.kernel_size[2],
                                                                   args.kernel_size[1],
                                                                   args.stride[0],
                                                                   args.stride[2],
                                                                   args.stride[1],
                                                                   args.padding[0],
                                                                   args.padding[2],
                                                                   args.padding[1],
                                                                   args.dilation[0],
                                                                   args.dilation[2],
                                                                   args.dilation[1],
                                                                   1.0);
        }
    } else if !dilated && args.transposed {
        /* !dilated && transposed */
        if dim == 4 {
            backend.SpatialFullConvolution_accGradParameters(input,
                                                             grad_output,
                                                             &mut grad_weight,
                                                             &mut grad_bias,
                                                             columns,
                                                             ones,
                                                             args.kernel_size[1],
                                                             args.kernel_size[0],
                                                             args.stride[1],
                                                             args.stride[0],
                                                             args.padding[1],
                                                             args.padding[0],
                                                             args.output_padding[1],
                                                             args.output_padding[0],
                                                             1.0);
        } else if dim == 5 {
            backend.VolumetricFullConvolution_accGradParameters(input,
                                                                grad_output,
                                                                &mut grad_weight,
                                                                &mut grad_bias,
                                                                columns,
                                                                ones,
                                                                args.stride[0],
                                                                args.stride[2],
                                                                args.stride[1],
                                                                args.padding[0],
                                                                args.padding[2],
                                                                args.padding[1],
                                                                args.output_padding[0],
                                                                args.output_padding[2],
                                                                args.output_padding[1],
                                                                1.0);
        }
    } else {
        /* !dilated && !transposed */
        if dim == 4 {
            backend.SpatialConvolutionMM_accGradParameters(input,
                                                           grad_output,
                                                           &mut grad_weight,
                                                           &mut grad_bias,
                                                           columns,
                                                           ones,
                                                           args.kernel_size[1],
                                                           args.kernel_size[0],
                                                           args.stride[1],
                                                           args.stride[0],
                                                           args.padding[1],
                                                           args.padding[0],
                                                           1.0);
        } else if dim == 5 && input.is_cuda() {
            backend.VolumetricConvolution_accGradParameters(input,
                                                            grad_output,
                                                            &mut grad_weight,
                                                            &mut grad_bias,
                                                            columns,
                                                            ones,
                                                            args.stride[0],
                                                            args.stride[2],
                                                            args.stride[1],
                                                            args.padding[0],
                                                            args.padding[2],
                                                            args.padding[1],
                                                            1.0);
        } else if dim == 5 {
            backend.VolumetricConvolutionMM_accGradParameters(input,
                                                              grad_output,
                                                              &mut grad_weight,
                                                              &mut grad_bias,
                                                              columns,
                                                              args.kernel_size[0],
                                                              args.kernel_size[2],
                                                              args.kernel_size[1],
                                                              args.stride[0],
                                                              args.stride[2],
                                                              args.stride[1],
                                                              args.padding[0],
                                                              args.padding[2],
                                                              args.padding[1],
                                                              1.0);
        }
    }
    (grad_weight, grad_bias)
}

fn view3d(t: TensorKind) -> TensorKind {
    unimplemented!()
}
fn view4d(t: TensorKind) -> TensorKind {
    unimplemented!()
}

impl ConvNd {
    fn view1d_as_2d(&mut self) {
        unimplemented!()
    }
    fn conv_forward_apply(&mut self, inputs: &mut TensorKindList) -> TensorKindList {

        let mut input = inputs.remove(0);
        let mut weight = inputs.remove(0);
        let (mut ones, mut columns) = (input.new(()), input.new(()));
        let mut save_list = vec![columns.clone(), ones.clone(), input.clone(), weight.clone()];
        let mut bias = if inputs.len() > 2 {
            let b = inputs.remove(0);
            save_list.push(b.clone());
            Some(b)
        } else {
            None
        };
        self.save_for_backward(&save_list);
        let k = input.size().len();
        if k == 3 {
            self.view1d_as_2d();
            input = view4d(input);
            weight = view4d(weight);
        }
        // let weight_size = weight.size(); -- NOT YET
        /* ......... */
        let mut output = compute_output(&mut input,
                                        &mut weight,
                                        &mut bias,
                                        &mut columns,
                                        &mut ones,
                                        &self.args);
        if k == 3 {
            output = view3d(output);
        };
        vec![output]
    }
}

impl FuncIntf for ConvNd {
    fn forward(&mut self, input: &mut TensorKindList) -> TensorKindList {
        // we don't support groups yet
        assert_eq!(self.args.groups, 1);
        self.conv_forward_apply(input)
    }
    fn backward(&mut self, mut input: &mut OptTensorKindList) -> OptTensorKindList {
        // run native code here
        unimplemented!()
    }
}
<|endoftext|>