<commit_before>use traits::operations::{Transpose, ApproxEq};
use traits::structure::{ColSlice, Eye, Indexable, Diag, SquareMat, BaseFloat, Cast};
use traits::geometry::Norm;
use std::cmp::min;
use std::ops::{Mul, Add, Sub};

/// Get the householder matrix corresponding to a reflexion to the hyperplane
/// defined by `vec`. It can be a reflexion contained in a subspace.
///
/// # Arguments
/// * `dim` - the dimension of the space the resulting matrix operates in
/// * `start` - the starting dimension of the subspace of the reflexion
/// * `vec` - the vector defining the reflection.
pub fn householder_matrix<N, V, M>(dim: usize, start: usize, vec: V) -> M
    where N: BaseFloat,
          M: Eye + Indexable<(usize, usize), N>,
          V: Indexable<usize, N> {
    let mut qk : M = Eye::new_identity(dim);
    let subdim = vec.shape();

    let stop = subdim + start;

    assert!(dim >= stop);

    for j in (start .. stop) {
        for i in (start .. stop) {
            unsafe {
                let vv = vec.unsafe_at(i - start) * vec.unsafe_at(j - start);
                let qkij = qk.unsafe_at((i, j));
                qk.unsafe_set((i, j), qkij - vv - vv);
            }
        }
    }
    qk
}

/// QR decomposition using Householder reflections.
///
/// # Arguments
/// * `m` - matrix to decompose
pub fn qr<N, V, M>(m: &M) -> (M, M)
    where N: BaseFloat,
          V: Indexable<usize, N> + Norm<N>,
          M: Copy + Eye + ColSlice<V> + Transpose + Indexable<(usize, usize), N> +
             Mul<M, Output = M> {
    let (rows, cols) = m.shape();
    assert!(rows >= cols);
    let mut q : M = Eye::new_identity(rows);
    let mut r = *m;

    for ite in 0..min(rows - 1, cols) {
        let mut v = r.col_slice(ite, ite, rows);
        let alpha =
            if unsafe { v.unsafe_at(ite) } >= ::zero() {
                -Norm::norm(&v)
            }
            else {
                Norm::norm(&v)
            };
        unsafe {
            let x = v.unsafe_at(0);
            v.unsafe_set(0, x - alpha);
        }
        if !::is_zero(&v.normalize_mut()) {
            let qk: M = householder_matrix(rows, ite, v);
            r = qk * r;
            q = q * Transpose::transpose(&qk);
        }
    }

    (q, r)
}

/// Eigendecomposition of a square symmetric matrix using the qr algorithm
pub fn eigen_qr<N, V, VS, M>(m: &M, eps: &N, niter: usize) -> (M, V)
    where N:  BaseFloat,
          V:  Mul<M, Output = V>,
          VS: Indexable<usize, N> + Norm<N>,
          M:  Indexable<(usize, usize), N> + SquareMat<N, V> + Add<M, Output = M> +
              Sub<M, Output = M> + ColSlice<VS> +
              ApproxEq<N> + Copy {

    let (mut eigenvectors, mut eigenvalues) = hessenberg(m);

    // Allocate arrays for Givens rotation components
    let mut c = Vec::<N>::with_capacity(::dim::<M>()-1);
    let mut s = Vec::<N>::with_capacity(::dim::<M>()-1);

    if ::dim::<M>() == 1 {
        return (eigenvectors, eigenvalues.diag());
    }

    unsafe {
        c.set_len(::dim::<M>()-1);
        s.set_len(::dim::<M>()-1);
    }

    let mut iter = 0;
    let mut curdim = ::dim::<M>()-1;

    for _ in 0..::dim::<M>() {

        let mut stop = false;

        while !stop && iter < niter {

            let lambda;

            unsafe {
                let a = eigenvalues.unsafe_at((curdim-1, curdim-1));
                let b = eigenvalues.unsafe_at((curdim-1, curdim));
                let c = eigenvalues.unsafe_at((curdim, curdim-1));
                let d = eigenvalues.unsafe_at((curdim, curdim));

                let trace = a + d;
                let det = a * d - b * c;

                let constquarter: N = Cast::from(0.25f64);
                let consthalf: N = Cast::from(0.5f64);

                let e = (constquarter * trace * trace - det).sqrt();

                let lambda1 = consthalf * trace + e;
                let lambda2 = consthalf * trace - e;

                if (lambda1 - d).abs() < (lambda2 - d).abs() {
                    lambda = lambda1;
                }
                else {
                    lambda = lambda2;
                }

            }

            // Shift matrix
            for k in 0..curdim+1 {
                unsafe {
                    let a = eigenvalues.unsafe_at((k,k));
                    eigenvalues.unsafe_set((k,k), a - lambda);
                }
            }

            // Givens rotation from left
            for k in 0..curdim {
                let x_i = unsafe { eigenvalues.unsafe_at((k,k)) };
                let x_j = unsafe { eigenvalues.unsafe_at((k+1,k)) };
                let r = (x_i*x_i + x_j*x_j).sqrt();
                let ctmp = x_i / r;
                let stmp = -x_j / r;

                c[k] = ctmp;
                s[k] = stmp;

                for j in k..(curdim+1) {

                    unsafe {
                        let a = eigenvalues.unsafe_at((k,j));
                        let b = eigenvalues.unsafe_at((k+1,j));

                        eigenvalues.unsafe_set((k,j), ctmp * a - stmp * b);
                        eigenvalues.unsafe_set((k+1,j), stmp * a + ctmp * b);
                    }

                }
            }

            // Givens rotation from right applied to eigenvalues
            for k in 0..curdim {
                for i in 0..(k+2) {

                    unsafe {
                        let a = eigenvalues.unsafe_at((i,k));
                        let b = eigenvalues.unsafe_at((i,k+1));

                        eigenvalues.unsafe_set((i,k), c[k] * a - s[k] * b);
                        eigenvalues.unsafe_set((i,k+1), s[k] * a + c[k] * b);
                    }
                }

            }

            // Shift back
            for k in 0..curdim+1 {
                unsafe {
                    let a = eigenvalues.unsafe_at((k,k));
                    eigenvalues.unsafe_set((k,k), a + lambda);
                }
            }

            // Givens rotation from right applied to eigenvectors
            for k in 0..curdim {
                for i in 0..::dim::<M>() {

                    unsafe {
                        let a = eigenvectors.unsafe_at((i,k));
                        let b = eigenvectors.unsafe_at((i,k+1));

                        eigenvectors.unsafe_set((i,k), c[k] * a - s[k] * b);
                        eigenvectors.unsafe_set((i,k+1), s[k] * a + c[k] * b);
                    }
                }
            }

            iter = iter + 1;

            stop = true;

            for j in 0..curdim {

                // Check last row
                if unsafe { eigenvalues.unsafe_at((curdim, j)) }.abs() >= *eps {
                    stop = false;
                    break;
                }

                // Check last column
                if unsafe { eigenvalues.unsafe_at((j, curdim)) }.abs() >= *eps {
                    stop = false;
                    break;
                }
            }
        }

        if stop {

            if curdim > 1 {
                curdim = curdim - 1;
            }
            else {
                break;
            }

        }

    }

    (eigenvectors, eigenvalues.diag())
}

/// Cholesky decomposition G of a square symmetric positive definite matrix A, such that A = G * G^T
///
/// # Arguments
/// * `m` - square symmetric positive definite matrix to decompose
pub fn cholesky<N, V, VS, M>(m: &M) -> Result<M, &'static str>
    where N:  BaseFloat,
          V:  Mul<M, Output = V>,
          VS: Indexable<usize, N> + Norm<N>,
          M:  Indexable<(usize, usize), N> + SquareMat<N, V> + Add<M, Output = M> +
              Sub<M, Output = M> + ColSlice<VS> +
              ApproxEq<N> + Copy {

    let mut out = m.clone().transpose();

    if !ApproxEq::approx_eq(&out, &m) {
        return Err("Cholesky: Input matrix is not symmetric");
    }

    for i in 0 .. out.nrows() {
        for j in 0 .. (i + 1) {

            let mut sum: N = out[(i, j)];

            for k in 0 .. j {
                sum = sum - out[(i, k)] * out[(j, k)];
            }

            if i > j {
                out[(i, j)] = sum / out[(j, j)];
            }
            else if sum > N::zero() {
                out[(i, i)] = sum.sqrt();
            }
            else {
                return Err("Cholesky: Input matrix is not positive definite to machine precision");
            }
        }
    }

    for i in 0 .. out.nrows() {
        for j in i + 1 .. out.ncols() {
            out[(i, j)] = N::zero();
        }
    }

    return Ok(out);
}

/// Hessenberg
/// Returns the matrix m in Hessenberg form and the corresponding similarity transformation
///
/// # Arguments
/// * `m` - matrix to transform
///
/// # Returns
/// * First return value `q` - Similarity matrix p such that q * h * q^T = m
/// * Second return value `h` - Matrix m in Hessenberg form
pub fn hessenberg<N, V, M>(m: &M) -> (M, M)
    where N: BaseFloat,
          V: Indexable<usize, N> + Norm<N>,
          M: Copy + Eye + ColSlice<V> + Transpose + Indexable<(usize, usize), N> +
             Mul<M, Output = M> {

    let mut h = m.clone();
    let (rows, cols) = h.shape();

    let mut q : M = Eye::new_identity(cols);

    if cols <= 2 {
        return (q, h);
    }

    for ite in 0..(cols-2) {
        let mut v = h.col_slice(ite, ite+1, rows);

        let alpha = Norm::norm(&v);

        unsafe {
            let x = v.unsafe_at(0);
            v.unsafe_set(0, x - alpha);
        }

        if !::is_zero(&v.normalize_mut()) {
            let p: M = householder_matrix(rows, ite+1, v);

            q = q * p;
            h = p * h * p;
        }
    }

    return (q, h);
}
<commit_msg>Style fixes.<commit_after>use traits::operations::{Transpose, ApproxEq};
use traits::structure::{ColSlice, Eye, Indexable, Diag, SquareMat, BaseFloat, Cast};
use traits::geometry::Norm;
use std::cmp;
use std::ops::{Mul, Add, Sub};

/// Get the householder matrix corresponding to a reflexion to the hyperplane
/// defined by `vec`. It can be a reflexion contained in a subspace.
///
/// # Arguments
/// * `dim` - the dimension of the space the resulting matrix operates in
/// * `start` - the starting dimension of the subspace of the reflexion
/// * `vec` - the vector defining the reflection.
pub fn householder_matrix<N, V, M>(dim: usize, start: usize, vec: V) -> M
    where N: BaseFloat,
          M: Eye + Indexable<(usize, usize), N>,
          V: Indexable<usize, N> {
    let mut qk : M = Eye::new_identity(dim);
    let subdim = vec.shape();

    let stop = subdim + start;

    assert!(dim >= stop);

    for j in start .. stop {
        for i in start .. stop {
            unsafe {
                let vv = vec.unsafe_at(i - start) * vec.unsafe_at(j - start);
                let qkij = qk.unsafe_at((i, j));
                qk.unsafe_set((i, j), qkij - vv - vv);
            }
        }
    }
    qk
}

/// QR decomposition using Householder reflections.
///
/// # Arguments
/// * `m` - matrix to decompose
pub fn qr<N, V, M>(m: &M) -> (M, M)
    where N: BaseFloat,
          V: Indexable<usize, N> + Norm<N>,
          M: Copy + Eye + ColSlice<V> + Transpose + Indexable<(usize, usize), N> +
             Mul<M, Output = M> {
    let (rows, cols) = m.shape();
    assert!(rows >= cols);
    let mut q : M = Eye::new_identity(rows);
    let mut r = *m;

    for ite in 0 .. cmp::min(rows - 1, cols) {
        let mut v = r.col_slice(ite, ite, rows);
        let alpha =
            if unsafe { v.unsafe_at(ite) } >= ::zero() {
                -Norm::norm(&v)
            }
            else {
                Norm::norm(&v)
            };
        unsafe {
            let x = v.unsafe_at(0);
            v.unsafe_set(0, x - alpha);
        }
        if !::is_zero(&v.normalize_mut()) {
            let qk: M = householder_matrix(rows, ite, v);
            r = qk * r;
            q = q * Transpose::transpose(&qk);
        }
    }

    (q, r)
}

/// Eigendecomposition of a square symmetric matrix using the qr algorithm
pub fn eigen_qr<N, V, VS, M>(m: &M, eps: &N, niter: usize) -> (M, V)
    where N:  BaseFloat,
          V:  Mul<M, Output = V>,
          VS: Indexable<usize, N> + Norm<N>,
          M:  Indexable<(usize, usize), N> + SquareMat<N, V> + Add<M, Output = M> +
              Sub<M, Output = M> + ColSlice<VS> +
              ApproxEq<N> + Copy {

    let (mut eigenvectors, mut eigenvalues) = hessenberg(m);

    // Allocate arrays for Givens rotation components
    let mut c = Vec::<N>::with_capacity(::dim::<M>() - 1);
    let mut s = Vec::<N>::with_capacity(::dim::<M>() - 1);

    if ::dim::<M>() == 1 {
        return (eigenvectors, eigenvalues.diag());
    }

    unsafe {
        c.set_len(::dim::<M>() - 1);
        s.set_len(::dim::<M>() - 1);
    }

    let mut iter = 0;
    let mut curdim = ::dim::<M>() - 1;

    for _ in 0 .. ::dim::<M>() {

        let mut stop = false;

        while !stop && iter < niter {

            let lambda;

            unsafe {
                let a = eigenvalues.unsafe_at((curdim - 1, curdim - 1));
                let b = eigenvalues.unsafe_at((curdim - 1, curdim));
                let c = eigenvalues.unsafe_at((curdim, curdim - 1));
                let d = eigenvalues.unsafe_at((curdim, curdim));

                let trace = a + d;
                let det = a * d - b * c;

                let constquarter: N = Cast::from(0.25f64);
                let consthalf: N = Cast::from(0.5f64);

                let e = (constquarter * trace * trace - det).sqrt();

                let lambda1 = consthalf * trace + e;
                let lambda2 = consthalf * trace - e;

                if (lambda1 - d).abs() < (lambda2 - d).abs() {
                    lambda = lambda1;
                }
                else {
                    lambda = lambda2;
                }

            }

            // Shift matrix
            for k in 0 .. curdim + 1 {
                unsafe {
                    let a = eigenvalues.unsafe_at((k, k));
                    eigenvalues.unsafe_set((k, k), a - lambda);
                }
            }

            // Givens rotation from left
            for k in 0 .. curdim {
                let x_i = unsafe { eigenvalues.unsafe_at((k, k)) };
                let x_j = unsafe { eigenvalues.unsafe_at((k + 1, k)) };
                let r = (x_i * x_i + x_j * x_j).sqrt();
                let ctmp = x_i / r;
                let stmp = -x_j / r;

                c[k] = ctmp;
                s[k] = stmp;

                for j in k .. (curdim + 1) {

                    unsafe {
                        let a = eigenvalues.unsafe_at((k, j));
                        let b = eigenvalues.unsafe_at((k + 1, j));

                        eigenvalues.unsafe_set((k, j), ctmp * a - stmp * b);
                        eigenvalues.unsafe_set((k + 1, j), stmp * a + ctmp * b);
                    }

                }
            }

            // Givens rotation from right applied to eigenvalues
            for k in 0 .. curdim {
                for i in 0 .. (k + 2) {

                    unsafe {
                        let a = eigenvalues.unsafe_at((i, k));
                        let b = eigenvalues.unsafe_at((i, k + 1));

                        eigenvalues.unsafe_set((i, k), c[k] * a - s[k] * b);
                        eigenvalues.unsafe_set((i, k + 1), s[k] * a + c[k] * b);
                    }
                }

            }

            // Shift back
            for k in 0 .. curdim + 1 {
                unsafe {
                    let a = eigenvalues.unsafe_at((k, k));
                    eigenvalues.unsafe_set((k, k), a + lambda);
                }
            }

            // Givens rotation from right applied to eigenvectors
            for k in 0 .. curdim {
                for i in 0 .. ::dim::<M>() {

                    unsafe {
                        let a = eigenvectors.unsafe_at((i, k));
                        let b = eigenvectors.unsafe_at((i, k + 1));

                        eigenvectors.unsafe_set((i, k), c[k] * a - s[k] * b);
                        eigenvectors.unsafe_set((i, k + 1), s[k] * a + c[k] * b);
                    }
                }
            }

            iter = iter + 1;

            stop = true;

            for j in 0 .. curdim {

                // Check last row
                if unsafe { eigenvalues.unsafe_at((curdim, j)) }.abs() >= *eps {
                    stop = false;
                    break;
                }

                // Check last column
                if unsafe { eigenvalues.unsafe_at((j, curdim)) }.abs() >= *eps {
                    stop = false;
                    break;
                }
            }
        }

        if stop {

            if curdim > 1 {
                curdim = curdim - 1;
            }
            else {
                break;
            }

        }

    }

    (eigenvectors, eigenvalues.diag())
}

/// Cholesky decomposition G of a square symmetric positive definite matrix A, such that A = G * G^T
///
/// # Arguments
/// * `m` - square symmetric positive definite matrix to decompose
pub fn cholesky<N, V, VS, M>(m: &M) -> Result<M, &'static str>
    where N:  BaseFloat,
          V:  Mul<M, Output = V>,
          VS: Indexable<usize, N> + Norm<N>,
          M:  Indexable<(usize, usize), N> + SquareMat<N, V> + Add<M, Output = M> +
              Sub<M, Output = M> + ColSlice<VS> +
              ApproxEq<N> + Copy {

    let mut out = m.clone().transpose();

    if !ApproxEq::approx_eq(&out, &m) {
        return Err("Cholesky: Input matrix is not symmetric");
    }

    for i in 0 .. out.nrows() {
        for j in 0 .. (i + 1) {

            let mut sum: N = out[(i, j)];

            for k in 0 .. j {
                sum = sum - out[(i, k)] * out[(j, k)];
            }

            if i > j {
                out[(i, j)] = sum / out[(j, j)];
            }
            else if sum > N::zero() {
                out[(i, i)] = sum.sqrt();
            }
            else {
                return Err("Cholesky: Input matrix is not positive definite to machine precision");
            }
        }
    }

    for i in 0 .. out.nrows() {
        for j in i + 1 .. out.ncols() {
            out[(i, j)] = N::zero();
        }
    }

    return Ok(out);
}

/// Hessenberg
/// Returns the matrix m in Hessenberg form and the corresponding similarity transformation
///
/// # Arguments
/// * `m` - matrix to transform
///
/// # Returns
/// * First return value `q` - Similarity matrix p such that q * h * q^T = m
/// * Second return value `h` - Matrix m in Hessenberg form
pub fn hessenberg<N, V, M>(m: &M) -> (M, M)
    where N: BaseFloat,
          V: Indexable<usize, N> + Norm<N>,
          M: Copy + Eye + ColSlice<V> + Transpose + Indexable<(usize, usize), N> +
             Mul<M, Output = M> {

    let mut h = m.clone();
    let (rows, cols) = h.shape();

    let mut q : M = Eye::new_identity(cols);

    if cols <= 2 {
        return (q, h);
    }

    for ite in 0 .. (cols - 2) {
        let mut v = h.col_slice(ite, ite + 1, rows);

        let alpha = Norm::norm(&v);

        unsafe {
            let x = v.unsafe_at(0);
            v.unsafe_set(0, x - alpha);
        }

        if !::is_zero(&v.normalize_mut()) {
            let p: M = householder_matrix(rows, ite + 1, v);

            q = q * p;
            h = p * h * p;
        }
    }

    return (q, h);
}
<|endoftext|>


<commit_before>use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::fmt;

pub enum ProxyProtocolHeader {
  V1(HeaderV1),
  V2(HeaderV2),
}

impl ProxyProtocolHeader {
  // Use this method to writte the header in the backend socket
  pub fn into_bytes(&self) -> Vec<u8> {
    match *self {
      ProxyProtocolHeader::V1(ref header) => header.into_bytes(),
      ProxyProtocolHeader::V2(_) => unimplemented!(),
    }
  }
}

/// Indicate the proxied INET protocol and family
#[derive(Debug, PartialEq, Eq)]
pub enum ProtocolSupportedV1 {
  TCP4,    // TCP over IPv4
  TCP6,    // TCP over IPv6
  UNKNOWN, // unsupported,or unknown protocols
}

impl fmt::Display for ProtocolSupportedV1 {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      ProtocolSupportedV1::TCP4 => write!(f, "TCP4"),
      ProtocolSupportedV1::TCP6 => write!(f, "TCP6"),
      ProtocolSupportedV1::UNKNOWN => write!(f, "UNKNOWN"),
    }
  }
}

/// Proxy Protocol header for version 1 (text version)
/// Example:
/// - TCP/IPv4: `PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n`
/// - TCP/IPv6: `PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n`
/// - Unknown: `PROXY UNKNOWN\r\n`
#[derive(Debug)]
pub struct HeaderV1 {
  protocol: ProtocolSupportedV1,
  addr_src: SocketAddr,
  addr_dst: SocketAddr,
}

const PROXY_PROTO_IDENTIFIER: &'static str = "PROXY";

impl HeaderV1 {

  pub fn new (addr_src: SocketAddr, addr_dst: SocketAddr) -> Self {
    let protocol = if addr_dst.is_ipv6() {
      ProtocolSupportedV1::TCP6
    } else if addr_dst.is_ipv4() {
      ProtocolSupportedV1::TCP4
    } else {
      ProtocolSupportedV1::UNKNOWN
    };

    HeaderV1 {
      protocol,
      addr_src,
      addr_dst,
    }
  }

  pub fn into_bytes(&self) -> Vec<u8> {
    if self.protocol.eq(&ProtocolSupportedV1::UNKNOWN) {
      format!("{} {}\r\n",
          PROXY_PROTO_IDENTIFIER,
          self.protocol,
      ).into_bytes()
    } else {
      format!("{} {} {} {} {} {}\r\n",
        PROXY_PROTO_IDENTIFIER,
        self.protocol,
        self.addr_src.ip(),
        self.addr_dst.ip(),
        self.addr_src.port(),
        self.addr_dst.port(),
      ).into_bytes()
    }
  }
}

#[cfg(test)]
mod test {

  use super::*;
  use std::net::{IpAddr, Ipv4Addr, SocketAddr, Ipv6Addr};

  #[test]
  fn it_should_return_a_correct_header_with_ipv4() {
    let header = HeaderV1::new(
      SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80),
      SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 17, 40, 59)), 80)
    );

    let header_to_cmp = "PROXY TCP4 127.0.0.1 172.17.40.59 80 80\r\n".as_bytes();

    assert_eq!(header_to_cmp, &header.into_bytes()[..]);
  }

  #[test]
  fn it_should_return_a_correct_header_with_ipv6() {
    let header = HeaderV1::new(
      SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0xffff)), 80),
      SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x9c, 0x76)), 80)
    );

    let header_to_cmp = "PROXY TCP6 ::0.0.255.255 ::0.156.0.118 80 80\r\n".as_bytes();
    assert_eq!(header_to_cmp, &header.into_bytes()[..]);
  }

  // #[test]
  // fn it_should_return_the_an_unknown_header() {
  //   let header = HeaderV1::new(ProtocolSupportedV1::UNKNOWN, None, None);

  //   let header_to_cmp = "PROXY UNKNOWN\r\n".as_bytes();

  //   assert_eq!(header_to_cmp, &header.into_bytes()[..]);
  // }
}

pub struct HeaderV2 {
  signature: [u8; 12], // hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A
  ver_and_cmd: u8,     // protocol version and command
  family: u8,          // protocol family and address
  len: u16,            // number of following bytes part of the header
  addr: AddrV2,
}

impl HeaderV2 {
  fn new(ver_and_cmd: u8, family: u8, addr: AddrV2) -> Self {
    HeaderV2 {
      signature: [0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A],
      ver_and_cmd,
      family,
      len: 0,
      addr,
    }
  }
}

pub enum AddrV2 {
  // len = 12
  TCP_UDP_IPV4 {
    addr_src: SocketAddrV4,
    addr_dst: SocketAddrV4,
  },
  // len = 36
  TCP_UDP_IPV6 {
    addr_src: SocketAddrV6,
    addr_dst: SocketAddrV6,
  },
  // len = 216
  AF_UNIX {
    src_addr: [u8; 108],
    dest_addr: [u8; 108],
  },
  AF_UNSPEC
}
<commit_msg>Add the header of the proxy protocol V2<commit_after>use std::net::{SocketAddr, SocketAddrV4, SocketAddrV6};
use std::fmt;

pub enum ProxyProtocolHeader {
  V1(HeaderV1),
  V2(HeaderV2),
}

impl ProxyProtocolHeader {
  // Use this method to writte the header in the backend socket
  pub fn into_bytes(&self) -> Vec<u8> {
    match *self {
      ProxyProtocolHeader::V1(ref header) => header.into_bytes(),
      ProxyProtocolHeader::V2(ref header) => header.into_bytes(),
    }
  }
}

/// Indicate the proxied INET protocol and family
#[derive(Debug, PartialEq, Eq)]
pub enum ProtocolSupportedV1 {
  TCP4,    // TCP over IPv4
  TCP6,    // TCP over IPv6
  UNKNOWN, // unsupported,or unknown protocols
}

impl fmt::Display for ProtocolSupportedV1 {
  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    match *self {
      ProtocolSupportedV1::TCP4 => write!(f, "TCP4"),
      ProtocolSupportedV1::TCP6 => write!(f, "TCP6"),
      ProtocolSupportedV1::UNKNOWN => write!(f, "UNKNOWN"),
    }
  }
}

/// Proxy Protocol header for version 1 (text version)
/// Example:
/// - TCP/IPv4: `PROXY TCP4 255.255.255.255 255.255.255.255 65535 65535\r\n`
/// - TCP/IPv6: `PROXY TCP6 ffff:f...f:ffff ffff:f...f:ffff 65535 65535\r\n`
/// - Unknown: `PROXY UNKNOWN\r\n`
#[derive(Debug)]
pub struct HeaderV1 {
  protocol: ProtocolSupportedV1,
  addr_src: SocketAddr,
  addr_dst: SocketAddr,
}

const PROXY_PROTO_IDENTIFIER: &'static str = "PROXY";

impl HeaderV1 {

  pub fn new (addr_src: SocketAddr, addr_dst: SocketAddr) -> Self {
    let protocol = if addr_dst.is_ipv6() {
      ProtocolSupportedV1::TCP6
    } else if addr_dst.is_ipv4() {
      ProtocolSupportedV1::TCP4
    } else {
      ProtocolSupportedV1::UNKNOWN
    };

    HeaderV1 {
      protocol,
      addr_src,
      addr_dst,
    }
  }

  pub fn into_bytes(&self) -> Vec<u8> {
    if self.protocol.eq(&ProtocolSupportedV1::UNKNOWN) {
      format!("{} {}\r\n",
          PROXY_PROTO_IDENTIFIER,
          self.protocol,
      ).into_bytes()
    } else {
      format!("{} {} {} {} {} {}\r\n",
        PROXY_PROTO_IDENTIFIER,
        self.protocol,
        self.addr_src.ip(),
        self.addr_dst.ip(),
        self.addr_src.port(),
        self.addr_dst.port(),
      ).into_bytes()
    }
  }
}

#[cfg(test)]
mod test {

  use super::*;
  use std::net::{IpAddr, Ipv4Addr, SocketAddr, Ipv6Addr};

  #[test]
  fn it_should_return_a_correct_header_with_ipv4() {
    let header = HeaderV1::new(
      SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80),
      SocketAddr::new(IpAddr::V4(Ipv4Addr::new(172, 17, 40, 59)), 80)
    );

    let header_to_cmp = "PROXY TCP4 127.0.0.1 172.17.40.59 80 80\r\n".as_bytes();

    assert_eq!(header_to_cmp, &header.into_bytes()[..]);
  }

  #[test]
  fn it_should_return_a_correct_header_with_ipv6() {
    let header = HeaderV1::new(
      SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0xffff)), 80),
      SocketAddr::new(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x9c, 0x76)), 80)
    );

    let header_to_cmp = "PROXY TCP6 ::0.0.255.255 ::0.156.0.118 80 80\r\n".as_bytes();
    assert_eq!(header_to_cmp, &header.into_bytes()[..]);
  }

  // #[test]
  // fn it_should_return_the_an_unknown_header() {
  //   let header = HeaderV1::new(ProtocolSupportedV1::UNKNOWN, None, None);

  //   let header_to_cmp = "PROXY UNKNOWN\r\n".as_bytes();

  //   assert_eq!(header_to_cmp, &header.into_bytes()[..]);
  // }
}

pub struct HeaderV2 {
  signature: [u8; 12], // hex 0D 0A 0D 0A 00 0D 0A 51 55 49 54 0A
  ver_and_cmd: u8,     // protocol version and command
  family: u8,          // protocol family and address
  len: u16,            // number of following bytes part of the header
  addr: ProxyAddr,
}

impl HeaderV2 {
  fn new(addr: ProxyAddr) -> Self {
    HeaderV2 {
      signature: [0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A],
      ver_and_cmd: 0x20,
      family: get_family(&addr),
      len: addr.len(),
      addr,
    }
  }

  pub fn into_bytes(&self) -> Vec<u8> {
    let mut header = Vec::new();
    header.extend_from_slice(&self.signature);
    header.push(self.ver_and_cmd);
    header.push(self.family);
    header.extend_from_slice(&u16_to_array_of_u8(self.len));
    header.extend_from_slice(&self.addr.into_bytes());
    header
  }
}

pub enum ProxyAddr {
  Ipv4Addr {
    src_addr: SocketAddrV4,
    dst_addr: SocketAddrV4,
  },
  Ipv6Addr {
    src_addr: SocketAddrV6,
    dst_addr: SocketAddrV6,
  },
  UnixAddr {
    src_addr: [u8; 108],
    dst_addr: [u8; 108],
  },
  AfUnspec,
}

impl ProxyAddr {
  fn len(&self) -> u16 {
    match *self {
      ProxyAddr::Ipv4Addr{ src_addr: _, dst_addr: _ } => 12,
      ProxyAddr::Ipv6Addr{ src_addr: _, dst_addr: _ } => 36,
      ProxyAddr::UnixAddr{ src_addr: _, dst_addr: _ } => 216,
      ProxyAddr::AfUnspec => unimplemented!(),
    }
  }

  fn into_bytes(&self) -> Vec<u8> {
    let mut res = Vec::new();

    match *self {
      ProxyAddr::Ipv4Addr{ src_addr, dst_addr } => {
        res.extend_from_slice(&src_addr.ip().octets());
        res.extend_from_slice(&dst_addr.ip().octets());
        res.extend_from_slice(&u16_to_array_of_u8(src_addr.port()));
        res.extend_from_slice(&u16_to_array_of_u8(dst_addr.port()));
      },
      ProxyAddr::Ipv6Addr{ src_addr, dst_addr } => {
        res.extend_from_slice(&src_addr.ip().octets());
        res.extend_from_slice(&dst_addr.ip().octets());
        res.extend_from_slice(&u16_to_array_of_u8(src_addr.port()));
        res.extend_from_slice(&u16_to_array_of_u8(dst_addr.port()));
      },
      ProxyAddr::UnixAddr{ src_addr, dst_addr } =>{
        res.extend_from_slice(&src_addr);
        res.extend_from_slice(&dst_addr);
      },
      ProxyAddr::AfUnspec => unimplemented!(),
    };

    res
  }
}

fn get_family(addr: &ProxyAddr) -> u8 {
  match addr {
    &ProxyAddr::Ipv4Addr{ src_addr: _, dst_addr: _ } => 0x10 | 0x01, // AF_INET  = 1 + STREAM = 1
    &ProxyAddr::Ipv6Addr{ src_addr: _, dst_addr: _ } => 0x20 | 0x01, // AF_INET6 = 2 + STREAM = 1
    &ProxyAddr::UnixAddr{ src_addr: _, dst_addr: _ } => 0x30 | 0x01, // AF_UNIX  = 3 + STREAM = 1
    &ProxyAddr::AfUnspec => unimplemented!(),
  }
}

fn u16_to_array_of_u8(x: u16) -> [u8; 2] {
    let b1 : u8 = ((x >> 8) & 0xff) as u8;
    let b2 : u8 = (x & 0xff) as u8;
    return [b1, b2]
}

#[cfg(test)]
mod testV2 {

  use super::*;
  use std::net::{Ipv4Addr, Ipv6Addr};

  #[test]
  fn test_u16_to_array_of_u8() {
    let val_u16: u16 = 65534;
    let expected = [0xff, 0xfe];
    assert_eq!(expected, u16_to_array_of_u8(val_u16));
  }

  #[test]
  fn test_deserialize_tcp_ipv4_proxy_protocol_header() {
    let addrs = ProxyAddr::Ipv4Addr {
      src_addr: SocketAddrV4::new(Ipv4Addr::new(125, 25, 10, 1), 8080),
      dst_addr: SocketAddrV4::new(Ipv4Addr::new(10, 4, 5, 8), 4200),
    };

    let header = HeaderV2::new(addrs);
    let expected = &[
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A, // MAGIC header
      0x20,                                                                   // Version 2 and command LOCAL
      0x11,                                                                   // family AF_UNIX with IPv4
      0x00, 0x0C,                                                             // address sizes = 12
      0x7D, 0x19, 0x0A, 0x01,                                                 // source address
      0x0A, 0x04, 0x05, 0x08,                                                 // destination address
      0x1F, 0x90,                                                             // source port
      0x10, 0x68,                                                             // destination port
    ];

    assert_eq!(expected, &header.into_bytes()[..]);
  }

  #[test]
  fn test_deserialize_tcp_ipv6_proxy_protocol_header() {
    let addrs = ProxyAddr::Ipv6Addr {
      src_addr: SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 8080, 0, 0),
      dst_addr: SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1), 4200, 0, 0),
    };

    let header = HeaderV2::new(addrs);
    let expected = vec![
      0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,                         // MAGIC header
      0x20,                                                                                // Version 2 and command LOCAL
      0x21,                                                                                // family AF_UNIX with IPv6
      0x00, 0x24,                                                                                // address sizes = 36
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // source address
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, // destination address
      0x1F, 0x90,                                                                                // source port
      0x10, 0x68,                                                                                // destination port
    ];

    assert_eq!(&expected[..], &header.into_bytes()[..]);
  }
}<|endoftext|>


<commit_before>use env_logger::{Builder, Env};
use log::debug;
use test_harness::BeaconChainHarness;
use types::ChainSpec;

#[test]
fn it_can_build_on_genesis_block() {
    let mut spec = ChainSpec::foundation();
    spec.genesis_slot = spec.epoch_length * 8;

    /*
    spec.shard_count = spec.shard_count / 8;
    spec.target_committee_size = spec.target_committee_size / 8;
    */
    let validator_count = 1000;

    let mut harness = BeaconChainHarness::new(spec, validator_count as usize);

    harness.advance_chain_with_block();
}

#[test]
#[ignore]
fn it_can_produce_past_first_epoch_boundary() {
    Builder::from_env(Env::default().default_filter_or("debug")).init();

    let validator_count = 128 * 1024;

    debug!("Starting harness build...");

    let mut harness = BeaconChainHarness::new(ChainSpec::foundation(), validator_count);

    debug!("Harness built, tests starting..");

    let blocks = harness.spec.epoch_length * 3 + 1;

    for i in 0..blocks {
        harness.advance_chain_with_block();
        debug!("Produced block {}/{}.", i, blocks);
    }
    let dump = harness.chain_dump().expect("Chain dump failed.");

    assert_eq!(dump.len() as u64, blocks + 1); // + 1 for genesis block.

    harness.dump_to_file("/tmp/chaindump.json".to_string(), &dump);
}
<commit_msg>Drop test repetitions down to 100<commit_after>use env_logger::{Builder, Env};
use log::debug;
use test_harness::BeaconChainHarness;
use types::ChainSpec;

#[test]
fn it_can_build_on_genesis_block() {
    let mut spec = ChainSpec::foundation();
    spec.genesis_slot = spec.epoch_length * 8;

    /*
    spec.shard_count = spec.shard_count / 8;
    spec.target_committee_size = spec.target_committee_size / 8;
    */
    let validator_count = 1000;

    let mut harness = BeaconChainHarness::new(spec, validator_count as usize);

    harness.advance_chain_with_block();
}

#[test]
#[ignore]
fn it_can_produce_past_first_epoch_boundary() {
    Builder::from_env(Env::default().default_filter_or("debug")).init();

    let validator_count = 100;

    debug!("Starting harness build...");

    let mut harness = BeaconChainHarness::new(ChainSpec::foundation(), validator_count);

    debug!("Harness built, tests starting..");

    let blocks = harness.spec.epoch_length * 3 + 1;

    for i in 0..blocks {
        harness.advance_chain_with_block();
        debug!("Produced block {}/{}.", i, blocks);
    }
    let dump = harness.chain_dump().expect("Chain dump failed.");

    assert_eq!(dump.len() as u64, blocks + 1); // + 1 for genesis block.

    harness.dump_to_file("/tmp/chaindump.json".to_string(), &dump);
}
<|endoftext|>


<commit_before>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, Field, Ident, Type};

use crate::{
    attrs::{Attrs, Kind, ParserKind},
    utils::{sub_type, subty_if_name, Ty},
};

pub fn gen_for_struct(
    struct_name: &Ident,
    fields: &Punctuated<Field, Comma>,
    parent_attribute: &Attrs,
) -> TokenStream {
    let constructor = gen_constructor(fields, parent_attribute);
    let updater = gen_updater(fields, parent_attribute, true);

    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::FromArgMatches for #struct_name {
            fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
                #struct_name #constructor
            }

            fn update_from_arg_matches(&mut self, matches: &::clap::ArgMatches) {
                #updater
            }
        }
    }
}

pub fn gen_for_enum(name: &Ident) -> TokenStream {
    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::FromArgMatches for #name {
            fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
                <#name as ::clap::Subcommand>::from_subcommand(matches.subcommand()).unwrap()
            }
            fn update_from_arg_matches(&mut self, matches: &::clap::ArgMatches) {
                <#name as ::clap::Subcommand>::update_from_subcommand(self, matches.subcommand());
            }
        }
    }
}

fn gen_arg_enum_parse(ty: &Type, attrs: &Attrs) -> TokenStream {
    let ci = attrs.case_insensitive();

    quote_spanned! { ty.span()=>
        |s| <#ty as ::clap::ArgEnum>::from_str(s, #ci).unwrap()
    }
}

pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
    let fields = fields.iter().map(|field| {
        let attrs = Attrs::from_field(
            field,
            parent_attribute.casing(),
            parent_attribute.env_casing(),
        );
        let field_name = field.ident.as_ref().unwrap();
        let kind = attrs.kind();
        match &*kind {
            Kind::ExternalSubcommand => {
                abort! { kind.span(),
                    "`external_subcommand` can be used only on enum variants"
                }
            }
            Kind::Subcommand(ty) => {
                let subcmd_type = match (**ty, sub_type(&field.ty)) {
                    (Ty::Option, Some(sub_type)) => sub_type,
                    _ => &field.ty,
                };
                let unwrapper = match **ty {
                    Ty::Option => quote!(),
                    _ => quote_spanned!( ty.span()=> .unwrap() ),
                };
                quote_spanned! { kind.span()=>
                    #field_name: {
                        <#subcmd_type as ::clap::Subcommand>::from_subcommand(matches.subcommand())
                        #unwrapper
                    }
                }
            }

            Kind::Flatten => quote_spanned! { kind.span()=>
                #field_name: ::clap::FromArgMatches::from_arg_matches(matches)
            },

            Kind::Skip(val) => match val {
                None => quote_spanned!(kind.span()=> #field_name: Default::default()),
                Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
            },

            Kind::Arg(ty) => {
                use self::ParserKind::*;

                let parser = attrs.parser();
                let func = &parser.func;
                let span = parser.kind.span();
                let (value_of, values_of, mut parse) = match *parser.kind {
                    FromStr => (
                        quote_spanned!(span=> value_of),
                        quote_spanned!(span=> values_of),
                        func.clone(),
                    ),
                    TryFromStr => (
                        quote_spanned!(span=> value_of),
                        quote_spanned!(span=> values_of),
                        quote_spanned!(func.span()=> |s| #func(s).unwrap()),
                    ),
                    FromOsStr => (
                        quote_spanned!(span=> value_of_os),
                        quote_spanned!(span=> values_of_os),
                        func.clone(),
                    ),
                    TryFromOsStr => (
                        quote_spanned!(span=> value_of_os),
                        quote_spanned!(span=> values_of_os),
                        quote_spanned!(func.span()=> |s| #func(s).unwrap()),
                    ),
                    FromOccurrences => (
                        quote_spanned!(span=> occurrences_of),
                        quote!(),
                        func.clone(),
                    ),
                    FromFlag => (quote!(), quote!(), func.clone()),
                };

                let flag = *attrs.parser().kind == ParserKind::FromFlag;
                let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
                let name = attrs.cased_name();

                let field_value = match **ty {
                    Ty::Bool => quote_spanned! { ty.span()=>
                        matches.is_present(#name)
                    },

                    Ty::Option => {
                        if attrs.is_enum() {
                            if let Some(subty) = subty_if_name(&field.ty, "Option") {
                                parse = gen_arg_enum_parse(subty, &attrs);
                            }
                        }

                        quote_spanned! { ty.span()=>
                            matches.#value_of(#name)
                                .map(#parse)
                        }
                    }

                    Ty::OptionOption => quote_spanned! { ty.span()=>
                        if matches.is_present(#name) {
                            Some(matches.#value_of(#name).map(#parse))
                        } else {
                            None
                        }
                    },

                    Ty::OptionVec => quote_spanned! { ty.span()=>
                        if matches.is_present(#name) {
                            Some(matches.#values_of(#name)
                                 .map(|v| v.map(#parse).collect())
                                 .unwrap_or_else(Vec::new))
                        } else {
                            None
                        }
                    },

                    Ty::Vec => {
                        if attrs.is_enum() {
                            if let Some(subty) = subty_if_name(&field.ty, "Vec") {
                                parse = gen_arg_enum_parse(subty, &attrs);
                            }
                        }

                        quote_spanned! { ty.span()=>
                            matches.#values_of(#name)
                                .map(|v| v.map(#parse).collect())
                                .unwrap_or_else(Vec::new)
                        }
                    }

                    Ty::Other if occurrences => quote_spanned! { ty.span()=>
                        #parse(matches.#value_of(#name))
                    },

                    Ty::Other if flag => quote_spanned! { ty.span()=>
                        #parse(matches.is_present(#name))
                    },

                    Ty::Other => {
                        if attrs.is_enum() {
                            parse = gen_arg_enum_parse(&field.ty, &attrs);
                        }

                        quote_spanned! { ty.span()=>
                            matches.#value_of(#name)
                                .map(#parse)
                                .unwrap()
                        }
                    }
                };

                quote_spanned!(field.span()=> #field_name: #field_value )
            }
        }
    });

    quote! {{
        #( #fields ),*
    }}
}

pub fn gen_updater(
    fields: &Punctuated<Field, Comma>,
    parent_attribute: &Attrs,
    use_self: bool,
) -> TokenStream {
    let fields = fields.iter().map(|field| {
        let attrs = Attrs::from_field(
            field,
            parent_attribute.casing(),
            parent_attribute.env_casing(),
        );
        let field_name = field.ident.as_ref().unwrap();
        let kind = attrs.kind();

        let access = if use_self {
            quote! {
                #[allow(non_snake_case)]
                let #field_name = &mut self.#field_name;
            }
        } else {
            quote!()
        };

        match &*kind {
            Kind::ExternalSubcommand => {
                abort! { kind.span(),
                    "`external_subcommand` can be used only on enum variants"
                }
            }
            Kind::Subcommand(ty) => {
                let subcmd_type = match (**ty, sub_type(&field.ty)) {
                    (Ty::Option, Some(sub_type)) => sub_type,
                    _ => &field.ty,
                };

                let updater = quote_spanned!{ ty.span()=>
                    <#subcmd_type as ::clap::Subcommand>::update_from_subcommand(#field_name, subcmd);
                };

                let updater = match **ty {
                    Ty::Option => quote_spanned! { kind.span()=>
                        if let Some(#field_name) = #field_name.as_mut() {
                            #updater
                        } else {
                            *#field_name = <#subcmd_type as ::clap::Subcommand>::from_subcommand(
                                subcmd
                            )
                        }
                    },
                    _ => quote_spanned!{ kind.span()=>
                        #updater
                    }
                };

                quote_spanned! { kind.span()=>
                    {
                        let subcmd = matches.subcommand();
                        #access
                        #updater
                    }
                }
            }

            Kind::Flatten => quote_spanned! { kind.span()=> {
                    #access
                    ::clap::FromArgMatches::update_from_arg_matches(#field_name, matches);
                }
            },

            Kind::Skip(_) => quote!(),

            Kind::Arg(ty) => {
                use self::ParserKind::*;

                let parser = attrs.parser();
                let func = &parser.func;
                let span = parser.kind.span();
                let (value_of, values_of, mut parse) = match *parser.kind {
                    FromStr => (
                        quote_spanned!(span=> value_of),
                        quote_spanned!(span=> values_of),
                        func.clone(),
                    ),
                    TryFromStr => (
                        quote_spanned!(span=> value_of),
                        quote_spanned!(span=> values_of),
                        quote_spanned!(func.span()=> |s| #func(s).unwrap()),
                    ),
                    FromOsStr => (
                        quote_spanned!(span=> value_of_os),
                        quote_spanned!(span=> values_of_os),
                        func.clone(),
                    ),
                    TryFromOsStr => (
                        quote_spanned!(span=> value_of_os),
                        quote_spanned!(span=> values_of_os),
                        quote_spanned!(func.span()=> |s| #func(s).unwrap()),
                    ),
                    FromOccurrences => (
                        quote_spanned!(span=> occurrences_of),
                        quote!(),
                        func.clone(),
                    ),
                    FromFlag => (quote!(), quote!(), func.clone()),
                };

                let flag = *attrs.parser().kind == ParserKind::FromFlag;
                let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
                let name = attrs.cased_name();

                let field_value = match **ty {
                    Ty::Bool => quote_spanned! { ty.span()=>
                        *#field_name || matches.is_present(#name)
                    },

                    Ty::Option => {
                        if attrs.is_enum() {
                            if let Some(subty) = sub_type(&field.ty) {
                                parse = gen_arg_enum_parse(subty, &attrs);
                            }
                        }

                        quote_spanned! { ty.span()=>
                            matches.#value_of(#name)
                                .map(#parse)
                        }
                    }

                    Ty::OptionOption => quote_spanned! { ty.span()=>
                        if matches.is_present(#name) {
                            Some(matches.#value_of(#name).map(#parse))
                        } else {
                            None
                        }
                    },

                    Ty::OptionVec => quote_spanned! { ty.span()=>
                        if matches.is_present(#name) {
                            Some(matches.#values_of(#name)
                                 .map(|v| v.map(#parse).collect())
                                 .unwrap_or_else(Vec::new))
                        } else {
                            None
                        }
                    },

                    Ty::Vec => {
                        if attrs.is_enum() {
                            if let Some(subty) = subty_if_name(&field.ty, "Vec") {
                                parse = gen_arg_enum_parse(subty, &attrs);
                            }
                        }

                        quote_spanned! { ty.span()=>
                            matches.#values_of(#name)
                                .map(|v| v.map(#parse).collect())
                                .unwrap_or_else(Vec::new)
                        }
                    }

                    Ty::Other if occurrences => quote_spanned! { ty.span()=>
                        #parse(matches.#value_of(#name))
                    },

                    Ty::Other if flag => quote_spanned! { ty.span()=>
                        #parse(matches.is_present(#name))
                    },

                    Ty::Other => {
                        if attrs.is_enum() {
                            parse = gen_arg_enum_parse(&field.ty, &attrs);
                        }

                        quote_spanned! { ty.span()=>
                            matches.#value_of(#name)
                                .map(#parse)
                                .unwrap()
                        }
                    }
                };

                quote_spanned! { field.span()=>
                    if matches.is_present(#name) {
                        #access
                        *#field_name = #field_value
                    }
                }
            }
        }
    });

    quote! {
        #( #fields )*
    }
}
<commit_msg>Factor out argument parsing generation<commit_after>// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>,
// Kevin Knapp (@kbknapp) <kbknapp@gmail.com>, and
// Andrew Hobden (@hoverbear) <andrew@hoverbear.org>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//
// This work was derived from Structopt (https://github.com/TeXitoi/structopt)
// commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
// MIT/Apache 2.0 license.
use proc_macro2::TokenStream;
use proc_macro_error::abort;
use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, Field, Ident, Type};

use crate::{
    attrs::{Attrs, Kind, ParserKind},
    utils::{sub_type, subty_if_name, Sp, Ty},
};

pub fn gen_for_struct(
    struct_name: &Ident,
    fields: &Punctuated<Field, Comma>,
    parent_attribute: &Attrs,
) -> TokenStream {
    let constructor = gen_constructor(fields, parent_attribute);
    let updater = gen_updater(fields, parent_attribute, true);

    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::FromArgMatches for #struct_name {
            fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
                #struct_name #constructor
            }

            fn update_from_arg_matches(&mut self, matches: &::clap::ArgMatches) {
                #updater
            }
        }
    }
}

pub fn gen_for_enum(name: &Ident) -> TokenStream {
    quote! {
        #[allow(dead_code, unreachable_code, unused_variables)]
        #[allow(
            clippy::style,
            clippy::complexity,
            clippy::pedantic,
            clippy::restriction,
            clippy::perf,
            clippy::deprecated,
            clippy::nursery,
            clippy::cargo
        )]
        #[deny(clippy::correctness)]
        impl ::clap::FromArgMatches for #name {
            fn from_arg_matches(matches: &::clap::ArgMatches) -> Self {
                <#name as ::clap::Subcommand>::from_subcommand(matches.subcommand()).unwrap()
            }
            fn update_from_arg_matches(&mut self, matches: &::clap::ArgMatches) {
                <#name as ::clap::Subcommand>::update_from_subcommand(self, matches.subcommand());
            }
        }
    }
}

fn gen_arg_enum_parse(ty: &Type, attrs: &Attrs) -> TokenStream {
    let ci = attrs.case_insensitive();

    quote_spanned! { ty.span()=>
        |s| <#ty as ::clap::ArgEnum>::from_str(s, #ci).unwrap()
    }
}

fn gen_parsers(
    attrs: &Attrs,
    ty: &Sp<Ty>,
    field_name: &Ident,
    field: &Field,
    update: Option<&TokenStream>,
) -> TokenStream {
    use self::ParserKind::*;

    let parser = attrs.parser();
    let func = &parser.func;
    let span = parser.kind.span();
    let (value_of, values_of, mut parse) = match *parser.kind {
        FromStr => (
            quote_spanned!(span=> value_of),
            quote_spanned!(span=> values_of),
            func.clone(),
        ),
        TryFromStr => (
            quote_spanned!(span=> value_of),
            quote_spanned!(span=> values_of),
            quote_spanned!(func.span()=> |s| #func(s).unwrap()),
        ),
        FromOsStr => (
            quote_spanned!(span=> value_of_os),
            quote_spanned!(span=> values_of_os),
            func.clone(),
        ),
        TryFromOsStr => (
            quote_spanned!(span=> value_of_os),
            quote_spanned!(span=> values_of_os),
            quote_spanned!(func.span()=> |s| #func(s).unwrap()),
        ),
        FromOccurrences => (
            quote_spanned!(span=> occurrences_of),
            quote!(),
            func.clone(),
        ),
        FromFlag => (quote!(), quote!(), func.clone()),
    };

    let flag = *attrs.parser().kind == ParserKind::FromFlag;
    let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
    let name = attrs.cased_name();

    let field_value = match **ty {
        Ty::Bool => {
            if update.is_some() {
                quote_spanned! { ty.span()=>
                    *#field_name || matches.is_present(#name)
                }
            } else {
                quote_spanned! { ty.span()=>
                    matches.is_present(#name)
                }
            }
        }

        Ty::Option => {
            if attrs.is_enum() {
                if let Some(subty) = subty_if_name(&field.ty, "Option") {
                    parse = gen_arg_enum_parse(subty, &attrs);
                }
            }

            quote_spanned! { ty.span()=>
                matches.#value_of(#name)
                    .map(#parse)
            }
        }

        Ty::OptionOption => quote_spanned! { ty.span()=>
            if matches.is_present(#name) {
                Some(matches.#value_of(#name).map(#parse))
            } else {
                None
            }
        },

        Ty::OptionVec => quote_spanned! { ty.span()=>
            if matches.is_present(#name) {
                Some(matches.#values_of(#name)
                     .map(|v| v.map(#parse).collect())
                     .unwrap_or_else(Vec::new))
            } else {
                None
            }
        },

        Ty::Vec => {
            if attrs.is_enum() {
                if let Some(subty) = subty_if_name(&field.ty, "Vec") {
                    parse = gen_arg_enum_parse(subty, &attrs);
                }
            }

            quote_spanned! { ty.span()=>
                matches.#values_of(#name)
                    .map(|v| v.map(#parse).collect())
                    .unwrap_or_else(Vec::new)
            }
        }

        Ty::Other if occurrences => quote_spanned! { ty.span()=>
            #parse(matches.#value_of(#name))
        },

        Ty::Other if flag => quote_spanned! { ty.span()=>
            #parse(matches.is_present(#name))
        },

        Ty::Other => {
            if attrs.is_enum() {
                parse = gen_arg_enum_parse(&field.ty, &attrs);
            }

            quote_spanned! { ty.span()=>
                matches.#value_of(#name)
                    .map(#parse)
                    .unwrap()
            }
        }
    };

    if let Some(access) = update {
        quote_spanned! { field.span()=>
            if matches.is_present(#name) {
                #access
                *#field_name = #field_value
            }
        }
    } else {
        quote_spanned!(field.span()=> #field_name: #field_value )
    }
}

pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
    let fields = fields.iter().map(|field| {
        let attrs = Attrs::from_field(
            field,
            parent_attribute.casing(),
            parent_attribute.env_casing(),
        );
        let field_name = field.ident.as_ref().unwrap();
        let kind = attrs.kind();
        match &*kind {
            Kind::ExternalSubcommand => {
                abort! { kind.span(),
                    "`external_subcommand` can be used only on enum variants"
                }
            }
            Kind::Subcommand(ty) => {
                let subcmd_type = match (**ty, sub_type(&field.ty)) {
                    (Ty::Option, Some(sub_type)) => sub_type,
                    _ => &field.ty,
                };
                let unwrapper = match **ty {
                    Ty::Option => quote!(),
                    _ => quote_spanned!( ty.span()=> .unwrap() ),
                };
                quote_spanned! { kind.span()=>
                    #field_name: {
                        <#subcmd_type as ::clap::Subcommand>::from_subcommand(matches.subcommand())
                        #unwrapper
                    }
                }
            }

            Kind::Flatten => quote_spanned! { kind.span()=>
                #field_name: ::clap::FromArgMatches::from_arg_matches(matches)
            },

            Kind::Skip(val) => match val {
                None => quote_spanned!(kind.span()=> #field_name: Default::default()),
                Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
            },

            Kind::Arg(ty) => gen_parsers(&attrs, ty, field_name, field, None),
        }
    });

    quote! {{
        #( #fields ),*
    }}
}

pub fn gen_updater(
    fields: &Punctuated<Field, Comma>,
    parent_attribute: &Attrs,
    use_self: bool,
) -> TokenStream {
    let fields = fields.iter().map(|field| {
        let attrs = Attrs::from_field(
            field,
            parent_attribute.casing(),
            parent_attribute.env_casing(),
        );
        let field_name = field.ident.as_ref().unwrap();
        let kind = attrs.kind();

        let access = if use_self {
            quote! {
                #[allow(non_snake_case)]
                let #field_name = &mut self.#field_name;
            }
        } else {
            quote!()
        };

        match &*kind {
            Kind::ExternalSubcommand => {
                abort! { kind.span(),
                    "`external_subcommand` can be used only on enum variants"
                }
            }
            Kind::Subcommand(ty) => {
                let subcmd_type = match (**ty, sub_type(&field.ty)) {
                    (Ty::Option, Some(sub_type)) => sub_type,
                    _ => &field.ty,
                };

                let updater = quote_spanned!{ ty.span()=>
                    <#subcmd_type as ::clap::Subcommand>::update_from_subcommand(#field_name, subcmd);
                };

                let updater = match **ty {
                    Ty::Option => quote_spanned! { kind.span()=>
                        if let Some(#field_name) = #field_name.as_mut() {
                            #updater
                        } else {
                            *#field_name = <#subcmd_type as ::clap::Subcommand>::from_subcommand(
                                subcmd
                            )
                        }
                    },
                    _ => quote_spanned!{ kind.span()=>
                        #updater
                    }
                };

                quote_spanned! { kind.span()=>
                    {
                        let subcmd = matches.subcommand();
                        #access
                        #updater
                    }
                }
            }

            Kind::Flatten => quote_spanned! { kind.span()=> {
                    #access
                    ::clap::FromArgMatches::update_from_arg_matches(#field_name, matches);
                }
            },

            Kind::Skip(_) => quote!(),

            Kind::Arg(ty) => {
                gen_parsers(&attrs, ty, field_name, field, Some(&access))
            }
        }
    });

    quote! {
        #( #fields )*
    }
}
<|endoftext|>


<commit_before>use std::{
    sync::mpsc::{channel, Receiver, Sender},
};

use pathfinder_color::ColorF;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{vec2f, vec2i};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use pathfinder_resources::embedded::EmbeddedResourceLoader;
use surfman::{
    Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion,
};
use surfman::{SurfaceAccess, SurfaceType};
use winit::dpi::LogicalSize;
use winit::{ControlFlow, Event, EventsLoop, WindowBuilder, WindowEvent};

pub use super::native::*;

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {}

/// Concrete implementation of the window shell.
pub struct Shell
where
    A: ShellAdapter,
{
    flip: bool,
    adapter: A,
    update: bool,
    running: bool,
    request_receiver: Receiver<ShellRequest>,
    request_sender: Sender<ShellRequest>,
    render_context_2_d: RenderContext2D,
    window_builder: WindowBuilder,
    mouse_pos: (f64, f64),
}

// unsafe impl HasRawWindowHandle for Shell
// where
//     A: ShellAdapter,
// {
//     fn raw_window_handle(&self) -> RawWindowHandle {
//         // let handle = WebHandle {
//         //     id: 0,
//         //     ..WebHandle::empty()
//         // };

//         // RawWindowHandle::N
//     }
// }

impl Shell
where
    A: ShellAdapter,
{
    /// Gets if the shell is running.
    pub fn running(&self) -> bool {
        self.running
    }

    /// Gets a a new sender to send request to the window shell.
    pub fn request_sender(&self) -> Sender<ShellRequest> {
        self.request_sender.clone()
    }

    /// Sets running.
    pub fn set_running(&mut self, running: bool) {
        self.running = running;
    }

    /// Get if the shell should be updated.
    pub fn update(&self) -> bool {
        self.update
    }

    /// Sets update.
    pub fn set_update(&mut self, update: bool) {
        self.update = update;
    }

    /// Sets the background color of the window.
    pub fn set_background_color(&mut self, red: u8, green: u8, blue: u8) {}

    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render ctx 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    pub fn flip(&mut self) {
        self.flip = false;
    }

    pub fn run(mut self) {
        // Open a window.
        let mut event_loop = EventsLoop::new();
        let size = self
            .window_builder
            .window
            .dimensions
            .unwrap_or(LogicalSize::new(100.0, 100.0));

        let mut render = true;

        let logical_size = LogicalSize::new(size.width as f64, size.height as f64);

        let window = self.window_builder.clone().build(&event_loop).unwrap();
        window.show();

        // Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
        // GPU.
        let connection = Connection::from_winit_window(&window).unwrap();
        let native_widget = connection
            .create_native_widget_from_winit_window(&window)
            .unwrap();
        let adapter = connection.create_low_power_adapter().unwrap();
        let mut device = connection.create_device(&adapter).unwrap();

        // Request an OpenGL 3.x context. Pathfinder requires this.
        let context_attributes = ContextAttributes {
            version: SurfmanGLVersion::new(3, 0),
            flags: ContextAttributeFlags::ALPHA,
        };
        let context_descriptor = device
            .create_context_descriptor(&context_attributes)
            .unwrap();

        // Make the OpenGL context via `surfman`, and load OpenGL functions.
        let surface_type = SurfaceType::Widget { native_widget };
        let mut context = device.create_context(&context_descriptor).unwrap();
        let surface = device
            .create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
            .unwrap();
        device
            .bind_surface_to_context(&mut context, surface)
            .unwrap();
        device.make_context_current(&context).unwrap();
        gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));

        // Get the real size of the window, taking HiDPI into account.
        let hidpi_factor = window.get_current_monitor().get_hidpi_factor();
        let physical_size = logical_size.to_physical(hidpi_factor);
        let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);

        // Create a Pathfinder GL device.
        let default_framebuffer = device
            .context_surface_info(&context)
            .unwrap()
            .unwrap()
            .framebuffer_object;
        let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);

        // Create a Pathfinder renderer.
        let mut renderer = Renderer::new(
            pathfinder_device,
            &EmbeddedResourceLoader::new(),
            DestFramebuffer::full_window(framebuffer_size),
            RendererOptions {
                background_color: Some(ColorF::white()),
                ..RendererOptions::default()
            },
        );

        self.render_context_2_d =
            RenderContext2D::new_ex((size.width as f64, size.height as f64), renderer);

        // Wait for a keypress.
        event_loop.run_forever(|evt| match evt {
            Event::WindowEvent {
                event: WindowEvent::Resized(s),
                ..
            } => {
                self.adapter.resize(s.width, s.height);
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::CloseRequested,
                ..
            } => {
                self.adapter.quit_event();
                ControlFlow::Break
            }
            Event::WindowEvent {
                event: WindowEvent::KeyboardInput { input, .. },
                // todo: implement
                ..
            } => ControlFlow::Continue,
            Event::WindowEvent {
                event: WindowEvent::MouseInput { state, button, .. },
                ..
            } => {
                let button = {
                    match button {
                        winit::MouseButton::Left => MouseButton::Left,
                        winit::MouseButton::Right => MouseButton::Right,
                        winit::MouseButton::Middle => MouseButton::Middle,
                        winit::MouseButton::Other(_) => MouseButton::Left,
                    }
                };

                let state = {
                    match state {
                        winit::ElementState::Pressed => ButtonState::Down,
                        winit::ElementState::Released => ButtonState::Up,
                    }
                };

                let mouse_pos = self.mouse_pos;

                self.adapter.mouse_event(MouseEvent {
                    x: mouse_pos.0,
                    y: mouse_pos.1,
                    button,
                    state,
                });
                render = true;
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::MouseWheel { delta, .. },
                ..
            } => {
                match delta {
                    winit::MouseScrollDelta::LineDelta(_, _) => {}
                    winit::MouseScrollDelta::PixelDelta(p) => {
                        self.adapter.scroll(p.x, p.y);
                    }
                }
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::CursorMoved { position, .. },
                ..
            } => {
                self.mouse_pos = (position.x, position.y);
                self.adapter.mouse(position.x, position.y);
                render = true;
                ControlFlow::Continue
            }
            // | Event::WindowEvent {
            //     event: WindowEvent::KeyboardInput { .. },
            //     ..
            // } => ControlFlow::Break,
            _ => {
                // if let Some(updater) = &mut self.updater {
                //     updater.update();
                // }
                // todo: shell context
                self.adapter.run(&mut self.render_context_2_d);
                self.set_update(true);
                self.flip();
                // self.drain_events();

                if render {
                    // Present the rendered canvas via `surfman`.
                    let mut surface = device
                        .unbind_surface_from_context(&mut context)
                        .unwrap()
                        .unwrap();
                    device.present_surface(&mut context, &mut surface).unwrap();
                    device
                        .bind_surface_to_context(&mut context, surface)
                        .unwrap();
                    render = false;
                }

                ControlFlow::Continue
            }
        });

        // Clean up.
        drop(device.destroy_context(&mut context));
    }
}

/// Constructs the window shell
pub struct ShellBuilder
where
    A: ShellAdapter,
{
    title: String,

    borderless: bool,

    resizeable: bool,

    always_on_top: bool,

    bounds: Rectangle,

    adapter: A,
}

impl ShellBuilder
where
    A: ShellAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        ShellBuilder {
            adapter,
            title: String::default(),
            borderless: false,
            resizeable: false,
            always_on_top: false,
            bounds: Rectangle::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets borderless.
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Does nothing on web.
    pub fn always_on_top(mut self, always_on_top: bool) -> Self {
        self.always_on_top = always_on_top;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rectangle>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(self) -> Shell {
        let (request_sender, request_receiver) = channel();

        // Calculate the right logical size of the window.
        // let event_loop = EventLoop::new();
        let size = (self.bounds.width(), self.bounds.height());

        let logical_size = LogicalSize::new(size.0, size.1);
        // Open a window.
        let window_builder = WindowBuilder::new()
            .with_dimensions(logical_size)
            .with_title(self.title)
            .with_resizable(self.resizeable)
            .with_always_on_top(self.always_on_top)
            .with_decorations(!self.borderless);

        Shell {
            flip: false,
            update: true,
            running: true,
            request_receiver,
            request_sender,
            render_context_2_d: RenderContext2D::new(size.0, size.1),
            adapter: self.adapter,
            window_builder,
            mouse_pos: (0.0, 0.0),
        }
    }
}
<commit_msg>Improve sufrman shell.<commit_after>use std::sync::mpsc::{channel, Receiver, Sender};

use pathfinder_color::ColorF;
use pathfinder_geometry::rect::RectF;
use pathfinder_geometry::vector::{vec2f, vec2i};
use pathfinder_gl::{GLDevice, GLVersion};
use pathfinder_renderer::gpu::options::{DestFramebuffer, RendererOptions};
use pathfinder_renderer::gpu::renderer::Renderer;
use pathfinder_renderer::options::BuildOptions;
use pathfinder_resources::embedded::EmbeddedResourceLoader;
use surfman::{
    Connection, ContextAttributeFlags, ContextAttributes, GLVersion as SurfmanGLVersion,
};
use surfman::{SurfaceAccess, SurfaceType};
use winit::dpi::LogicalSize;
use winit::{ControlFlow, Event, EventsLoop, WindowBuilder, WindowEvent};

pub use super::native::*;

use crate::{prelude::*, render::*, utils::*};

pub fn initialize() {}

/// Concrete implementation of the window shell.
pub struct Shell
where
    A: ShellAdapter,
{
    adapter: A,
    update: bool,
    render: bool,
    running: bool,
    request_receiver: Receiver<ShellRequest>,
    request_sender: Sender<ShellRequest>,
    render_context_2_d: RenderContext2D,
    window_builder: WindowBuilder,
    mouse_pos: (f64, f64),
}

// unsafe impl HasRawWindowHandle for Shell
// where
//     A: ShellAdapter,
// {
//     fn raw_window_handle(&self) -> RawWindowHandle {
//         // let handle = WebHandle {
//         //     id: 0,
//         //     ..WebHandle::empty()
//         // };

//         // RawWindowHandle::N
//     }
// }

impl Shell
where
    A: ShellAdapter,
{
    /// Gets if the shell is running.
    pub fn running(&self) -> bool {
        self.running
    }

    /// Gets a a new sender to send request to the window shell.
    pub fn request_sender(&self) -> Sender<ShellRequest> {
        self.request_sender.clone()
    }

    /// Sets running.
    pub fn set_running(&mut self, running: bool) {
        self.running = running;
    }

    /// Get if the shell should be updated.
    pub fn update(&self) -> bool {
        self.update
    }

    /// Sets update.
    pub fn set_update(&mut self, update: bool) {
        self.update = update;
    }

    /// Sets the background color of the window.
    pub fn set_background_color(&mut self, red: u8, green: u8, blue: u8) {}

    /// Gets the shell adapter.
    pub fn adapter(&mut self) -> &mut A {
        &mut self.adapter
    }

    /// Gets the render ctx 2D.
    pub fn render_context_2_d(&mut self) -> &mut RenderContext2D {
        &mut self.render_context_2_d
    }

    fn drain_events(&mut self, event: Event) -> ControlFlow {
        match event {
            Event::WindowEvent {
                event: WindowEvent::Resized(s),
                ..
            } => {
                self.adapter.resize(s.width, s.height);
                self.update = true;
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::CloseRequested,
                ..
            } => {
                self.adapter.quit_event();
                ControlFlow::Break
            }
            Event::WindowEvent {
                event: WindowEvent::KeyboardInput { input, .. },
                // todo: implement
                ..
            } => ControlFlow::Continue,
            Event::WindowEvent {
                event: WindowEvent::MouseInput { state, button, .. },
                ..
            } => {
                let button = {
                    match button {
                        winit::MouseButton::Left => MouseButton::Left,
                        winit::MouseButton::Right => MouseButton::Right,
                        winit::MouseButton::Middle => MouseButton::Middle,
                        winit::MouseButton::Other(_) => MouseButton::Left,
                    }
                };

                let state = {
                    match state {
                        winit::ElementState::Pressed => ButtonState::Down,
                        winit::ElementState::Released => ButtonState::Up,
                    }
                };

                let mouse_pos = self.mouse_pos;

                self.adapter.mouse_event(MouseEvent {
                    x: mouse_pos.0,
                    y: mouse_pos.1,
                    button,
                    state,
                });
                self.update = true;
                self.render = true;
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::MouseWheel { delta, .. },
                ..
            } => {
                match delta {
                    winit::MouseScrollDelta::LineDelta(_, _) => {}
                    winit::MouseScrollDelta::PixelDelta(p) => {
                        self.adapter.scroll(p.x, p.y);
                    }
                }
                self.render = true;
                self.update = true;
                ControlFlow::Continue
            }
            Event::WindowEvent {
                event: WindowEvent::CursorMoved { position, .. },
                ..
            } => {
                self.mouse_pos = (position.x, position.y);
                self.adapter.mouse(position.x, position.y);
                self.update = true;
                self.render = true;
                ControlFlow::Continue
            }
            _ => ControlFlow::Continue,
        }
    }

    pub fn run(mut self) {
        // Open a window.
        let mut event_loop = EventsLoop::new();
        let size = self
            .window_builder
            .window
            .dimensions
            .unwrap_or(LogicalSize::new(100.0, 100.0));

        let logical_size = LogicalSize::new(size.width as f64, size.height as f64);

        let window = self.window_builder.clone().build(&event_loop).unwrap();
        window.show();

        // Create a `surfman` device. On a multi-GPU system, we'll request the low-power integrated
        // GPU.
        let connection = Connection::from_winit_window(&window).unwrap();
        let native_widget = connection
            .create_native_widget_from_winit_window(&window)
            .unwrap();
        let adapter = connection.create_low_power_adapter().unwrap();
        let mut device = connection.create_device(&adapter).unwrap();

        // Request an OpenGL 3.x context. Pathfinder requires this.
        let context_attributes = ContextAttributes {
            version: SurfmanGLVersion::new(3, 0),
            flags: ContextAttributeFlags::ALPHA,
        };
        let context_descriptor = device
            .create_context_descriptor(&context_attributes)
            .unwrap();

        // Make the OpenGL context via `surfman`, and load OpenGL functions.
        let surface_type = SurfaceType::Widget { native_widget };
        let mut context = device.create_context(&context_descriptor).unwrap();
        let surface = device
            .create_surface(&context, SurfaceAccess::GPUOnly, surface_type)
            .unwrap();
        device
            .bind_surface_to_context(&mut context, surface)
            .unwrap();
        device.make_context_current(&context).unwrap();
        gl::load_with(|symbol_name| device.get_proc_address(&context, symbol_name));

        // Get the real size of the window, taking HiDPI into account.
        let hidpi_factor = window.get_current_monitor().get_hidpi_factor();
        let physical_size = logical_size.to_physical(hidpi_factor);
        let framebuffer_size = vec2i(physical_size.width as i32, physical_size.height as i32);

        // Create a Pathfinder GL device.
        let default_framebuffer = device
            .context_surface_info(&context)
            .unwrap()
            .unwrap()
            .framebuffer_object;
        let pathfinder_device = GLDevice::new(GLVersion::GL3, default_framebuffer);

        // Create a Pathfinder renderer.
        let mut renderer = Renderer::new(
            pathfinder_device,
            &EmbeddedResourceLoader::new(),
            DestFramebuffer::full_window(framebuffer_size),
            RendererOptions {
                background_color: Some(ColorF::white()),
                ..RendererOptions::default()
            },
        );

        self.render_context_2_d =
            RenderContext2D::new_ex((size.width as f64, size.height as f64), renderer);

        // Wait for a keypress.
        event_loop.run_forever(|evt| {
            let control_flow = self.drain_events(evt);

            if self.update {
                self.adapter.run(&mut self.render_context_2_d);
                self.update = false;
            }

            if self.render {
                // Present the rendered canvas via `surfman`.
                let mut surface = device
                    .unbind_surface_from_context(&mut context)
                    .unwrap()
                    .unwrap();
                device.present_surface(&mut context, &mut surface).unwrap();
                device
                    .bind_surface_to_context(&mut context, surface)
                    .unwrap();
                self.render = false;
            }

            control_flow
        });

        // Clean up.
        drop(device.destroy_context(&mut context));
    }
}

/// Constructs the window shell
pub struct ShellBuilder
where
    A: ShellAdapter,
{
    title: String,

    borderless: bool,

    resizeable: bool,

    always_on_top: bool,

    bounds: Rectangle,

    adapter: A,
}

impl ShellBuilder
where
    A: ShellAdapter,
{
    /// Create a new window builder with the given adapter.
    pub fn new(adapter: A) -> Self {
        ShellBuilder {
            adapter,
            title: String::default(),
            borderless: false,
            resizeable: false,
            always_on_top: false,
            bounds: Rectangle::default(),
        }
    }

    /// Sets the title.
    pub fn title(mut self, title: impl Into<String>) -> Self {
        self.title = title.into();
        self
    }

    /// Sets borderless.
    pub fn borderless(mut self, borderless: bool) -> Self {
        self.borderless = borderless;
        self
    }

    /// Sets resizeable.
    pub fn resizeable(mut self, resizeable: bool) -> Self {
        self.resizeable = resizeable;
        self
    }

    /// Does nothing on web.
    pub fn always_on_top(mut self, always_on_top: bool) -> Self {
        self.always_on_top = always_on_top;
        self
    }

    /// Sets the bounds.
    pub fn bounds(mut self, bounds: impl Into<Rectangle>) -> Self {
        self.bounds = bounds.into();
        self
    }

    /// Builds the window shell.
    pub fn build(self) -> Shell {
        let (request_sender, request_receiver) = channel();

        // Calculate the right logical size of the window.
        // let event_loop = EventLoop::new();
        let size = (self.bounds.width(), self.bounds.height());

        let logical_size = LogicalSize::new(size.0, size.1);
        // Open a window.
        let window_builder = WindowBuilder::new()
            .with_dimensions(logical_size)
            .with_title(self.title)
            .with_resizable(self.resizeable)
            .with_always_on_top(self.always_on_top)
            .with_decorations(!self.borderless);

        Shell {
            render: true,
            update: true,
            running: true,
            request_receiver,
            request_sender,
            render_context_2_d: RenderContext2D::new(size.0, size.1),
            adapter: self.adapter,
            window_builder,
            mouse_pos: (0.0, 0.0),
        }
    }
}
<|endoftext|>


<commit_before>extern crate azure_sdk_for_rust;
extern crate env_logger;
extern crate futures;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate log;
extern crate tokio_core;

use azure_sdk_for_rust::prelude::*;
use futures::future::*;
use std::error::Error;
use tokio_core::reactor::Core;

fn main() {
    env_logger::init();
    code().unwrap();
}

// We run a separate method to use the elegant quotation mark operator.
// A series of unwrap(), unwrap() would have achieved the same result.
fn code() -> Result<(), Box<Error>> {
    // First we retrieve the account name and master key from environment variables.
    let account = std::env::var("STORAGE_ACCOUNT").expect("Set env variable STORAGE_ACCOUNT first!");
    let master_key = std::env::var("STORAGE_MASTER_KEY").expect("Set env variable STORAGE_MASTER_KEY first!");

    let container = std::env::args()
        .nth(1)
        .expect("please specify container name as command line parameter");
    let blob = std::env::args().nth(2).expect("please specify blob name as command line parameter");

    let mut core = Core::new()?;

    let client = Client::new(&account, &master_key)?;

    trace!("Requesting blog");

    let future = client
        .get_blob()
        .with_container_name(&container)
        .with_blob_name(&blob)
        .finalize()
        .and_then(move |response| {
            done(String::from_utf8(response.data))
                .map(move |s_content| {
                    println!("blob == {:?}", blob);
                    println!("s_content == {}", s_content);
                }).from_err()
        });
    core.run(future)?;

    Ok(())
}
<commit_msg>Change blog to blob<commit_after>extern crate azure_sdk_for_rust;
extern crate env_logger;
extern crate futures;
extern crate hyper;
extern crate hyper_tls;
#[macro_use]
extern crate log;
extern crate tokio_core;

use azure_sdk_for_rust::prelude::*;
use futures::future::*;
use std::error::Error;
use tokio_core::reactor::Core;

fn main() {
    env_logger::init();
    code().unwrap();
}

// We run a separate method to use the elegant quotation mark operator.
// A series of unwrap(), unwrap() would have achieved the same result.
fn code() -> Result<(), Box<Error>> {
    // First we retrieve the account name and master key from environment variables.
    let account = std::env::var("STORAGE_ACCOUNT").expect("Set env variable STORAGE_ACCOUNT first!");
    let master_key = std::env::var("STORAGE_MASTER_KEY").expect("Set env variable STORAGE_MASTER_KEY first!");

    let container = std::env::args()
        .nth(1)
        .expect("please specify container name as command line parameter");
    let blob = std::env::args().nth(2).expect("please specify blob name as command line parameter");

    let mut core = Core::new()?;

    let client = Client::new(&account, &master_key)?;

    trace!("Requesting blob");

    let future = client
        .get_blob()
        .with_container_name(&container)
        .with_blob_name(&blob)
        .finalize()
        .and_then(move |response| {
            done(String::from_utf8(response.data))
                .map(move |s_content| {
                    println!("blob == {:?}", blob);
                    println!("s_content == {}", s_content);
                }).from_err()
        });
    core.run(future)?;

    Ok(())
}
<|endoftext|>