<commit_before>use num::rational::Ratio;

use std::f32;
use std::f32::consts::PI;
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::fmt::{Debug, Formatter, Result};

//hack
use sfml::system::{Vector2f, Vector2i};

pub type Coord = f32;
pub type RawAngle = f32;

#[derive(Clone)]
pub struct Vector2 {
    x: Coord,
    y: Coord,
}

impl Vector2 {
    pub fn null() -> Vector2 {
        Vector2 {
            x: 0 as Coord,
            y: 0 as Coord,
        }
    }

    pub fn new(x: Coord, y: Coord) -> Vector2 {
        Vector2 { x: x, y: y }
    }

    pub fn from_sfml_f(v: &Vector2f) -> Vector2 {
        Vector2 { x: v.x, y: v.y }
    }

    /*pub fn from_sfml_i(v: &Vector2i) -> Vector2 {
		Vector2 { x: v.x, y: v.y }
	}*/

    pub fn normalize(&self) -> Vector2 {
        let len = self.len();

        match len {
            0. => Vector2::null(),
            _ => {
                Vector2 {
                    x: self.x / len,
                    y: self.y / len,
                }
            }
        }
    }

    pub fn len_squared(&self) -> f32 {
        self.x * self.x + self.y * self.y
    }

    pub fn len(&self) -> f32 {
        self.len_squared().sqrt()
    }

    pub fn polar(&self) -> Polar {
        Polar::new(Angle::rad(self.y.atan2(self.x)), self.len())
    }

    pub fn to_sfml_f(&self) -> Vector2f {
        Vector2f {
            x: self.x,
            y: self.y,
        }
    }

    /*pub fn to_sfml_i(&self) -> Vector2i {
		Vector2i { self.x as isize, self.y as isize }
	}*/
}

impl Add for Vector2 {
    fn add(&self, rhs: &Vector2) -> Vector2 {
        Vector2 {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl Sub for Vector2 {
    fn sub(&self, rhs: &Vector2) -> Vector2 {
        Vector2 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}

impl Mul for Vector2 {
    fn mul(&self, rhs: &f32) -> Vector2 {
        Vector2 {
            x: self.x * (*rhs),
            y: self.y * (*rhs),
        }
    }
}

impl Div for Vector2 {
    fn div(&self, rhs: &f32) -> Vector2 {
        Vector2 {
            x: self.x / (*rhs),
            y: self.y / (*rhs),
        }
    }
}

impl Neg for Vector2 {
    fn neg(&self) -> Vector2 {
        Vector2 {
            x: -self.x,
            y: -self.y,
        }
    }
}

impl PartialEq for Vector2 {
    fn eq(&self, other: &Vector2) -> bool {
        self.x == other.x && self.y == other.y
    }

    fn ne(&self, other: &Vector2) -> bool {
        self.x != other.x || self.y != other.y
    }
}

impl Debug for Vector2 {
    fn fmt(&self, formatter: &mut Formatter) -> Result {
        let dirStr = angle_to_dir_str(&self.polar().angle);
        write!(formatter.buf,
               "{{ {} | x: {:.2}, y:{:.2} }}",
               dirStr,
               self.x,
               self.y)
    }
}

pub fn dot(v1: Vector2, v2: Vector2) -> f32 {
    v1.x * v2.x + v1.y * v2.y
}

//Angle---
#[derive(Clone)]
pub struct Angle {
    //in radians
    theta: RawAngle,
}

impl Angle {
    //constructors---
    pub fn deg(deg: RawAngle) -> Angle {
        Angle { theta: Angle::clamp(deg.to_radians()) }
    }
    pub fn rad(rad: RawAngle) -> Angle {
        Angle { theta: Angle::clamp(rad) }
    }

    pub fn sin(&self) -> f32 {
        self.theta.sin()
    }

    pub fn cos(&self) -> f32 {
        self.theta.cos()
    }

    pub fn tan(&self) -> f32 {
        self.theta.tan()
    }

    fn clamp(rad: RawAngle) -> RawAngle {
        let tolerance = 2 as RawAngle;
        let limit = (PI as RawAngle) * tolerance;

        if rad > limit || rad < -limit {
            angle_to_principal_domain(rad);
        }
        rad
    }
}

impl Add for Angle {
    fn add(&self, rhs: &Angle) -> Angle {
        Angle { theta: Angle::clamp(self.theta + rhs.theta) }
    }
}

impl Sub for Angle {
    fn sub(&self, rhs: &Angle) -> Angle {
        Angle { theta: Angle::clamp(self.theta - rhs.theta) }
    }
}

impl Mul for Angle {
    fn mul(&self, rhs: &f32) -> Angle {
        Angle { theta: Angle::clamp(self.theta * *rhs) }
    }
}

impl Div for Angle {
    fn div(&self, rhs: &f32) -> Angle {
        //clamp if divided by negative values
        Angle { theta: Angle::clamp(self.theta / *rhs) }
    }
}

impl Neg for Angle {
    fn neg(&self) -> Angle {
        Angle { theta: Angle::clamp(-self.theta) }
    }
}

impl Debug for Angle {
    fn fmt(&self, formatter: &mut Formatter) -> Result {

        let normalizedAngle = angle_to_principal_domain(self.theta);
        let simplificationFactor = 6;
        let simplifiedNumerator = (normalizedAngle / PI * simplificationFactor as f32).round() as
                                  isize;
        let ratio = Ratio::new(simplifiedNumerator, simplificationFactor);

        let n = *ratio.numer();
        let d = *ratio.denom();

        let degrees = self.theta * (180f32 / PI);

        let radStr = match (n, d) {
            (0, _) => "0".to_string(),
            (1, 1) => "π".to_string(),
            (1, _) => format!("π/{}", d),
            (_, 1) => format!("{}π", n),
            _ => format!("{}π/{}", n, d),
        };

        let dirStr = angle_to_dir_str(self);

        write!(formatter.buf,
               "{{ {} | rad: {} | {:.2}° }}",
               dirStr,
               radStr,
               degrees)

    }
}

fn angle_to_dir_str(angle: &Angle) -> String {
    let principal_angle = angle_to_principal_domain(angle.theta);
    let degrees = principal_angle * (180f32 / PI);

    match (degrees / 45.).floor() as isize {
        0 => "→".to_string(),
        1 => "↗".to_string(),
        2 => "↑".to_string(),
        3 => "↖".to_string(),
        4 => "←".to_string(),
        5 => "↙".to_string(),
        6 => "↓".to_string(),
        7 => "↘".to_string(),
        _ => "⟳".to_string(),
    }
}

//polar Coordinates-----------------

#[derive(Debug)]
pub struct Polar {
    angle: Angle,
    len: f32,
}

impl Polar {
    pub fn new(angle: Angle, len: f32) -> Polar {
        Polar {
            angle: angle,
            len: len,
        }
    }

    pub fn unit(angle: Angle) -> Polar {
        Polar {
            angle: angle,
            len: 1.,
        }
    }

    pub fn unit_rad(rad: f32) -> Polar {
        Polar {
            angle: Angle::rad(rad),
            len: 1.,
        }
    }

    pub fn unit_deg(deg: f32) -> Polar {
        Polar {
            angle: Angle::deg(deg),
            len: 1.,
        }
    }

    //member functions-----
    pub fn cartesian(&self) -> Vector2 {
        Vector2::new(self.angle.cos() * self.len, self.angle.sin() * self.len)
    }

    pub fn normalize(&self) -> Polar {
        Polar {
            angle: self.angle,
            len: 1.,
        }
    }
}

//polar by polar multiplication
impl Mul for Polar {
    fn mul(&self, rhs: &Polar) -> Polar {
        Polar {
            angle: self.angle + rhs.angle,
            len: self.len * rhs.len,
        }
    }
}

impl Div for Polar {
    fn div(&self, rhs: &Polar) -> Polar {
        Polar {
            angle: self.angle - rhs.angle,
            len: self.len / rhs.len,
        }
    }
}

impl Neg for Polar {
    fn neg(&self) -> Polar {
        Polar {
            angle: -self.angle,
            len: self.len,
        }
    }
}

//auxiliary helper functions--------------------------------
fn angle_to_principal_domain(rad: RawAngle) -> RawAngle {
    let twoPi = (2. * PI) as RawAngle;

    let mut clamped: RawAngle = rad % twoPi;

    if clamped < 0. {
        clamped += twoPi;
    }

    assert!(clamped >= 0 as RawAngle && clamped < twoPi);
    clamped
}

//tests

#[test]
fn test_vector_cons() {
    let v1 = Vector2::null();
    let v2 = Vector2::new(3.0, 4.0);

    assert!(v1.x == 0. && v1.y == 0.);
    assert!(v2.x == 3. && v2.y == 4.);
}

#[test]
fn test_vector_normalize() {
    let v1 = Vector2::null();
    let v2 = Vector2::new(3.0, 4.0);
    let v3 = Vector2::new(1.0, 0.0);

    assert!(v1.normalize() == v1);
    assert!(v3.normalize() == v3);

    assert!(v2.normalize().x == 3.0 / 5.0 && v2.normalize().y == 4.0 / 5.0)
}

#[test]
fn test_vector_len() {
    let v1 = Vector2::null();
    let v2 = Vector2::new(3.0, 4.0);
    let v3 = Vector2::new(1.0, 0.0);
    let v4 = Vector2::new(1.0, 1.0);

    assert!(v1.len() == 0. && v1.len_squared() == 0.);
    assert!(v2.len() == 5.);
    assert!(v3.len_squared() == 1. && v3.len() == 1.);
    assert!(v4.len_squared() == 2.);
}

#[test]
fn test_vector_operators() {
    let v1 = Vector2::null();
    let v2 = Vector2::new(3.0, 4.0);
    let v3 = Vector2::new(1.0, 0.0);
    let v4 = Vector2::new(1.0, 1.0);
    let v5 = Vector2::new(0.0, 1.0);

    assert!(v1 + v2 == v2);
    assert!(v1 + v1 == v1);
    assert!(v4 + v4 == v4 * 2.);
    assert!(v3 + v4 == Vector2::new(2.0, 1.0));

    assert!(v2 - v1 == v2);
    assert!(v2 - v2 == v1);
    assert!(v4 - v3 == Vector2::new(0.0, 1.0));

    assert!(v2 != v1);
    assert!(v3 != v4 && v5 != v4 && v5 != v3);
}

#[test]
fn test_cartesian_polar() {
    let v1 = Vector2::null();
    let a1 = v1.polar();

    assert!(a1.len == 0.);
    assert!(a1.cartesian() == v1);

    let a1 = Polar::new(Angle::deg(90.), 2.);

    assert!(a1.cartesian().len() == 2.);
    assert!(a1.cartesian().polar() == a1);
    assert!(a1.cartesian().y == 2. && a1.cartesian().x == 0.);

}
<commit_msg>Add Output type to arithmetic impls<commit_after>use num::rational::Ratio;

use std::f32;
use std::f32::consts::PI;
use std::ops::{Add, Sub, Mul, Div, Neg};
use std::fmt::{Debug, Formatter, Result};

//hack
use sfml::system::{Vector2f, Vector2i};

pub type Coord = f32;
pub type RawAngle = f32;

#[derive(Clone)]
pub struct Vector2 {
    x: Coord,
    y: Coord,
}

impl Vector2 {
    pub fn null() -> Vector2 {
        Vector2 {
            x: 0 as Coord,
            y: 0 as Coord,
        }
    }

    pub fn new(x: Coord, y: Coord) -> Vector2 {
        Vector2 { x: x, y: y }
    }

    pub fn from_sfml_f(v: &Vector2f) -> Vector2 {
        Vector2 { x: v.x, y: v.y }
    }

    /*pub fn from_sfml_i(v: &Vector2i) -> Vector2 {
		Vector2 { x: v.x, y: v.y }
	}*/

    pub fn normalize(&self) -> Vector2 {
        let len = self.len();

        match len {
            0. => Vector2::null(),
            _ => {
                Vector2 {
                    x: self.x / len,
                    y: self.y / len,
                }
            }
        }
    }

    pub fn len_squared(&self) -> f32 {
        self.x * self.x + self.y * self.y
    }

    pub fn len(&self) -> f32 {
        self.len_squared().sqrt()
    }

    pub fn polar(&self) -> Polar {
        Polar::new(Angle::rad(self.y.atan2(self.x)), self.len())
    }

    pub fn to_sfml_f(&self) -> Vector2f {
        Vector2f {
            x: self.x,
            y: self.y,
        }
    }

    /*pub fn to_sfml_i(&self) -> Vector2i {
		Vector2i { self.x as isize, self.y as isize }
	}*/
}

impl Add for Vector2 {
    type Output = Vector2;

    fn add(&self, rhs: &Vector2) -> Vector2 {
        Vector2 {
            x: self.x + rhs.x,
            y: self.y + rhs.y,
        }
    }
}

impl Sub for Vector2 {
    type Output = Vector2;

    fn sub(&self, rhs: &Vector2) -> Vector2 {
        Vector2 {
            x: self.x - rhs.x,
            y: self.y - rhs.y,
        }
    }
}

impl Mul for Vector2 {
    type Output = Vector2;

    fn mul(&self, rhs: &f32) -> Vector2 {
        Vector2 {
            x: self.x * (*rhs),
            y: self.y * (*rhs),
        }
    }
}

impl Div for Vector2 {
    type Output = Vector2;

    fn div(&self, rhs: &f32) -> Vector2 {
        Vector2 {
            x: self.x / (*rhs),
            y: self.y / (*rhs),
        }
    }
}

impl Neg for Vector2 {
    type Output = Vector2;

    fn neg(&self) -> Vector2 {
        Vector2 {
            x: -self.x,
            y: -self.y,
        }
    }
}

impl PartialEq for Vector2 {
    fn eq(&self, other: &Vector2) -> bool {
        self.x == other.x && self.y == other.y
    }

    fn ne(&self, other: &Vector2) -> bool {
        self.x != other.x || self.y != other.y
    }
}

impl Debug for Vector2 {
    fn fmt(&self, formatter: &mut Formatter) -> Result {
        let dirStr = angle_to_dir_str(&self.polar().angle);
        write!(formatter.buf,
               "{{ {} | x: {:.2}, y:{:.2} }}",
               dirStr,
               self.x,
               self.y)
    }
}

pub fn dot(v1: Vector2, v2: Vector2) -> f32 {
    v1.x * v2.x + v1.y * v2.y
}

//Angle---
#[derive(Clone)]
pub struct Angle {
    //in radians
    theta: RawAngle,
}

impl Angle {
    //constructors---
    pub fn deg(deg: RawAngle) -> Angle {
        Angle { theta: Angle::clamp(deg.to_radians()) }
    }
    pub fn rad(rad: RawAngle) -> Angle {
        Angle { theta: Angle::clamp(rad) }
    }

    pub fn sin(&self) -> f32 {
        self.theta.sin()
    }

    pub fn cos(&self) -> f32 {
        self.theta.cos()
    }

    pub fn tan(&self) -> f32 {
        self.theta.tan()
    }

    fn clamp(rad: RawAngle) -> RawAngle {
        let tolerance = 2 as RawAngle;
        let limit = (PI as RawAngle) * tolerance;

        if rad > limit || rad < -limit {
            angle_to_principal_domain(rad);
        }
        rad
    }
}

impl Add for Angle {
    type Output = Angle;

    fn add(&self, rhs: &Angle) -> Angle {
        Angle { theta: Angle::clamp(self.theta + rhs.theta) }
    }
}

impl Sub for Angle {
    type Output = Angle;

    fn sub(&self, rhs: &Angle) -> Angle {
        Angle { theta: Angle::clamp(self.theta - rhs.theta) }
    }
}

impl Mul for Angle {
    type Output = Angle;

    fn mul(&self, rhs: &f32) -> Angle {
        Angle { theta: Angle::clamp(self.theta * *rhs) }
    }
}

impl Div for Angle {
    type Output = Angle;

    fn div(&self, rhs: &f32) -> Angle {
        //clamp if divided by negative values
        Angle { theta: Angle::clamp(self.theta / *rhs) }
    }
}

impl Neg for Angle {
    type Output = Angle;

    fn neg(&self) -> Angle {
        Angle { theta: Angle::clamp(-self.theta) }
    }
}

impl Debug for Angle {
    fn fmt(&self, formatter: &mut Formatter) -> Result {

        let normalizedAngle = angle_to_principal_domain(self.theta);
        let simplificationFactor = 6;
        let simplifiedNumerator = (normalizedAngle / PI * simplificationFactor as f32).round() as
                                  isize;
        let ratio = Ratio::new(simplifiedNumerator, simplificationFactor);

        let n = *ratio.numer();
        let d = *ratio.denom();

        let degrees = self.theta * (180f32 / PI);

        let radStr = match (n, d) {
            (0, _) => "0".to_string(),
            (1, 1) => "π".to_string(),
            (1, _) => format!("π/{}", d),
            (_, 1) => format!("{}π", n),
            _ => format!("{}π/{}", n, d),
        };

        let dirStr = angle_to_dir_str(self);

        write!(formatter.buf,
               "{{ {} | rad: {} | {:.2}° }}",
               dirStr,
               radStr,
               degrees)

    }
}

fn angle_to_dir_str(angle: &Angle) -> String {
    let principal_angle = angle_to_principal_domain(angle.theta);
    let degrees = principal_angle * (180f32 / PI);

    match (degrees / 45.).floor() as isize {
        0 => "→".to_string(),
        1 => "↗".to_string(),
        2 => "↑".to_string(),
        3 => "↖".to_string(),
        4 => "←".to_string(),
        5 => "↙".to_string(),
        6 => "↓".to_string(),
        7 => "↘".to_string(),
        _ => "⟳".to_string(),
    }
}

//polar Coordinates-----------------

#[derive(Debug)]
pub struct Polar {
    angle: Angle,
    len: f32,
}

impl Polar {
    pub fn new(angle: Angle, len: f32) -> Polar {
        Polar {
            angle: angle,
            len: len,
        }
    }

    pub fn unit(angle: Angle) -> Polar {
        Polar {
            angle: angle,
            len: 1.,
        }
    }

    pub fn unit_rad(rad: f32) -> Polar {
        Polar {
            angle: Angle::rad(rad),
            len: 1.,
        }
    }

    pub fn unit_deg(deg: f32) -> Polar {
        Polar {
            angle: Angle::deg(deg),
            len: 1.,
        }
    }

    //member functions-----
    pub fn cartesian(&self) -> Vector2 {
        Vector2::new(self.angle.cos() * self.len, self.angle.sin() * self.len)
    }

    pub fn normalize(&self) -> Polar {
        Polar {
            angle: self.angle,
            len: 1.,
        }
    }
}

//polar by polar multiplication
impl Mul for Polar {
    type Output = Polar;

    fn mul(&self, rhs: &Polar) -> Polar {
        Polar {
            angle: self.angle + rhs.angle,
            len: self.len * rhs.len,
        }
    }
}

impl Div for Polar {
    type Output = Polar;

    fn div(&self, rhs: &Polar) -> Polar {
        Polar {
            angle: self.angle - rhs.angle,
            len: self.len / rhs.len,
        }
    }
}

impl Neg for Polar {
    type Output = Polar;

    fn neg(&self) -> Polar {
        Polar {
            angle: -self.angle,
            len: self.len,
        }
    }
}

//auxiliary helper functions--------------------------------
fn angle_to_principal_domain(rad: RawAngle) -> RawAngle {
    let twoPi = (2. * PI) as RawAngle;

    let mut clamped: RawAngle = rad % twoPi;

    if clamped < 0. {
        clamped += twoPi;
    }

    assert!(clamped >= 0 as RawAngle && clamped < twoPi);
    clamped
}

//tests

#[test]
fn test_vector_cons() {
    let v1 = Vector2::null();
    let v2 = Vector2::new(3.0, 4.0);

    assert!(v1.x == 0. && v1.y == 0.);
    assert!(v2.x == 3. && v2.y == 4.);
}

#[test]
fn test_vector_normalize() {
    let v1 = Vector2::null();
    let v2 = Vector2::new(3.0, 4.0);
    let v3 = Vector2::new(1.0, 0.0);

    assert!(v1.normalize() == v1);
    assert!(v3.normalize() == v3);

    assert!(v2.normalize().x == 3.0 / 5.0 && v2.normalize().y == 4.0 / 5.0)
}

#[test]
fn test_vector_len() {
    let v1 = Vector2::null();
    let v2 = Vector2::new(3.0, 4.0);
    let v3 = Vector2::new(1.0, 0.0);
    let v4 = Vector2::new(1.0, 1.0);

    assert!(v1.len() == 0. && v1.len_squared() == 0.);
    assert!(v2.len() == 5.);
    assert!(v3.len_squared() == 1. && v3.len() == 1.);
    assert!(v4.len_squared() == 2.);
}

#[test]
fn test_vector_operators() {
    let v1 = Vector2::null();
    let v2 = Vector2::new(3.0, 4.0);
    let v3 = Vector2::new(1.0, 0.0);
    let v4 = Vector2::new(1.0, 1.0);
    let v5 = Vector2::new(0.0, 1.0);

    assert!(v1 + v2 == v2);
    assert!(v1 + v1 == v1);
    assert!(v4 + v4 == v4 * 2.);
    assert!(v3 + v4 == Vector2::new(2.0, 1.0));

    assert!(v2 - v1 == v2);
    assert!(v2 - v2 == v1);
    assert!(v4 - v3 == Vector2::new(0.0, 1.0));

    assert!(v2 != v1);
    assert!(v3 != v4 && v5 != v4 && v5 != v3);
}

#[test]
fn test_cartesian_polar() {
    let v1 = Vector2::null();
    let a1 = v1.polar();

    assert!(a1.len == 0.);
    assert!(a1.cartesian() == v1);

    let a1 = Polar::new(Angle::deg(90.), 2.);

    assert!(a1.cartesian().len() == 2.);
    assert!(a1.cartesian().polar() == a1);
    assert!(a1.cartesian().y == 2. && a1.cartesian().x == 0.);

}
<|endoftext|>


<commit_before>/// Maximum number of channels supported in the FLAC format.
pub const MAX_CHANNELS: usize = 8;

/// Audio frame that contains one sample for each channel.
pub struct Frame {
  /// Information regarding the current audio frame.
  pub header: Header,
  /// CRC-16 of all frame bytes before this footer.
  pub footer: Footer,
}

/// Channel assignment order.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelAssignment {
  /// Independent channels, from one up to eight.
  Independent,
  /// Left and side stereo.
  LeftSide,
  /// Right and side stereo.
  RightSide,
  /// Middle and side stereo.
  MiddleSide,
}

/// Numbering scheme used from the frame.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberType {
  /// Frame number of first sample in frame.
  Frame(u32),
  /// Sample number of first sample in frame.
  Sample(u64),
}

/// Information regarding the current audio frame.
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
  /// Number of samples per subframe.
  pub block_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels that also represent the number of subframes.
  pub channels: u8,
  pub channel_assignment: ChannelAssignment,
  /// Size, in bits, per sample.
  pub bits_per_sample: usize,
  pub number: NumberType,
  /// CRC-8 of all header bytes before this crc.
  pub crc: u8,
}

/// End of the audio frame.
///
/// Contains a value that represents the CRC-16 of everything inside the
/// frame before the footer.
#[derive(Debug, PartialEq, Eq)]
pub struct Footer(pub u16);
<commit_msg>Add documentation for mem`frame::Header` fields<commit_after>/// Maximum number of channels supported in the FLAC format.
pub const MAX_CHANNELS: usize = 8;

/// Audio frame that contains one sample for each channel.
pub struct Frame {
  /// Information regarding the current audio frame.
  pub header: Header,
  /// CRC-16 of all frame bytes before this footer.
  pub footer: Footer,
}

/// Channel assignment order.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChannelAssignment {
  /// Independent channels, from one up to eight.
  Independent,
  /// Left and side stereo.
  LeftSide,
  /// Right and side stereo.
  RightSide,
  /// Middle and side stereo.
  MiddleSide,
}

/// Numbering scheme used from the frame.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum NumberType {
  /// Frame number of first sample in frame.
  Frame(u32),
  /// Sample number of first sample in frame.
  Sample(u64),
}

/// Information regarding the current audio frame.
#[derive(Debug, PartialEq, Eq)]
pub struct Header {
  /// Number of samples per subframe.
  pub block_size: u32,
  /// Sample rate in hertz (Hz).
  pub sample_rate: u32,
  /// Number of channels that also represent the number of subframes.
  pub channels: u8,
  /// Channel assignment order.
  pub channel_assignment: ChannelAssignment,
  /// Size, in bits, per sample.
  pub bits_per_sample: usize,
  /// Numbering scheme used from the frame.
  pub number: NumberType,
  /// CRC-8 of all header bytes before this crc.
  pub crc: u8,
}

/// End of the audio frame.
///
/// Contains a value that represents the CRC-16 of everything inside the
/// frame before the footer.
#[derive(Debug, PartialEq, Eq)]
pub struct Footer(pub u16);
<|endoftext|>


<commit_before>use byteorder::{ByteOrder, LittleEndian};

use gameboy;
use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::frame::{Color, Frame};

const VRAM_SIZE: usize = 0x4000;
const SPRITE_DATA_SIZE: usize = 0xA0;

pub struct GpuStat {
    pub coincidence_interrupt_enabled: bool,
    pub OAM_interrupt_enabled: bool,
    pub VBlank_interrupt_enabled: bool,
    pub HBlank_interrupt_enabled: bool,
}

impl GpuStat {
    pub fn new() -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: false,
            OAM_interrupt_enabled: false,
            VBlank_interrupt_enabled: false,
            HBlank_interrupt_enabled: false,
        }
    }

    pub fn from_u8(b: u8) -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: b & 0x40 == 0x40,
            OAM_interrupt_enabled: b & 0x20 == 0x20,
            VBlank_interrupt_enabled: b & 0x10 == 0x10,
            HBlank_interrupt_enabled: b & 0x08 == 0x08,
        }
    }

    pub fn to_u8(&self, gpu: &Gpu) -> u8 {
        (if self.coincidence_interrupt_enabled {
            0x40
        } else {
            0
        }) | (if self.OAM_interrupt_enabled { 0x20 } else { 0 }) |
        (if self.VBlank_interrupt_enabled {
            0x10
        } else {
            0
        }) |
        (if self.HBlank_interrupt_enabled {
            0x08
        } else {
            0
        }) | (if gpu.ly == gpu.lyc { 0x04 } else { 0 }) | gpu.mode.to_u8()
    }
}

#[derive(Eq, PartialEq, Clone)]
pub enum GpuMode {
    HBlank,
    VBlank,
    SearchingRam,
    TransferringData,
}

impl GpuMode {
    fn to_u8(&self) -> u8 {
        match *self {
            GpuMode::HBlank => 0x00,
            GpuMode::VBlank => 0x01,
            GpuMode::SearchingRam => 0x02,
            GpuMode::TransferringData => 0x03,
        }
    }
}

pub enum SpriteShape {
    Square,
    Rectangle,
}

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,
    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    pub ly: u8,
    lyc: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: isize,

    pub frame: Frame,
    pub backbuffer: Frame,
    mode: GpuMode,

    counter: u8,
    tile_base: usize,
    background_base: usize,
    sprite_shape: SpriteShape,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(VRAM_SIZE),
            sprite_data: Memory::new(SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            backbuffer: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
            tile_base: 0x00,
            background_base: 0xC00,
            sprite_shape: SpriteShape::Square,
        }
    }

    pub fn reset(&mut self) {
        *self = Gpu::new();
    }

    fn set_status(&mut self, irq: &mut Irq) {
        if !self.enabled {
            self.cycles = 0x1C8;
            self.ly = 0x00;
            self.stat = GpuStat::from_u8(0xFD);
        }

        let current_mode = self.mode.clone();

        if self.ly >= 0x90 {
            self.mode = GpuMode::VBlank;
        } else {
            if self.cycles >= 0x178 {
                self.mode = GpuMode::SearchingRam;
            } else if self.cycles >= 0xCC {
                self.mode = GpuMode::TransferringData;
            } else {
                self.mode = GpuMode::HBlank;
            }
        }

        if self.mode != current_mode {
            irq.request(Interrupt::Lcd);
        }

        self.check_coincidence(irq);
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        self.set_status(irq);

        let cycles = cycles as isize;
        if self.enabled {
            self.cycles -= cycles;
        } else {
            return Ok(());
        }

        if self.cycles <= 0 {
            self.ly += 0x01;

            self.cycles = 0x1C8;

            if self.ly == 0x90 {
                irq.request(Interrupt::Vblank);
            } else if self.ly > 0x99 {
                self.ly = 0x00;
            } else if self.ly < 0x90 {
                self.render_scanline();
            }
        }

        Ok(())
    }

    fn render_scanline(&mut self) {
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        // self.clear_scanline(line);
        self.render_background(line);
        self.render_sprites(line);
        self.frame = self.backbuffer.clone();
    }

    fn clear_scanline(&mut self, line: usize) {
        for i in 0..160 {
            self.backbuffer.pixels[line * 160 + i] = Color::new(0xFF, 0xFF, 0xFF, 0xFF);
        }
    }

    fn render_background(&mut self, line: usize) {
        let bg_base = self.background_base;
        let tile_base = self.tile_base;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..gameboy::SCREEN_WIDTH {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number = self.ram[bg_base + (bg_map_row * 0x20 + bg_map_col)] as usize;

            let line_offset = (line % 0x08) << 0x01;

            let tile_data_start = tile_base +
                                  (if tile_base == 0x00 {
                raw_tile_number
            } else {
                (raw_tile_number as i8 as i16 + 0x80) as usize
            }) * 0x10 + line_offset;

            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.backbuffer.pixels[self.ly as usize * 160 + i as usize] = c;
        }
    }

    fn render_sprites(&mut self, line: usize) {
        for i in 0..40 {
            let sprite_table_entry_base = i * 0x04;
            let s_y = self.sprite_data[sprite_table_entry_base] as i16 - 0x10;
            let s_x = self.sprite_data[sprite_table_entry_base + 0x01] as i16 - 0x08;
            let sprite_height = if let SpriteShape::Rectangle = self.sprite_shape {
                0x10
            } else {
                0x08
            };
            if line < s_y as usize || line > s_y as usize + sprite_height {
                continue;
            }
            let tile_number = self.sprite_data[sprite_table_entry_base + 0x02] as i16;
            let attributes = self.sprite_data[sprite_table_entry_base + 0x03];
            let above_background = attributes & 0x80 == 0x00;

            let sprite_y = (line as i16 - s_y) << 0x01;
            let tile_data_start = (tile_number * 0x10) + sprite_y;
            for x in 0..8 {
                if s_x + x < 0 || s_x + x >= 160 {
                    continue;
                }
                let x_shift = 0x07 - x;
                let tile_data1 = (self.ram[tile_data_start as usize] >> x_shift) & 0x01;
                let tile_data2 = (self.ram[tile_data_start as usize + 0x01] >> x_shift) & 0x01;
                let total_row_data = (tile_data2 << 1) | tile_data1;
                let color_value = total_row_data;
                if color_value == 0x00 {
                    continue;
                }
                let c = self.get_sprite_color_for_byte(color_value as u8,
                                                       ((attributes & 0x10) >> 0x04) as u8);
                self.backbuffer.pixels[line as usize * 160 + (s_x as usize + x as usize)] = c;
            }
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    fn get_sprite_color_for_byte(&self, b: u8, palette_entry: u8) -> Color {
        let palette = if palette_entry == 0x00 {
            self.palette0
        } else {
            self.palette1
        };

        let palette_index = match b {
            0x00 => palette & 0x0003,
            0x01 => (palette & 0x000C) >> 0x02,
            0x02 => (palette & 0x0030) >> 0x04,
            0x03 => (palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => {
                self.control_register = val;
                self.enabled = self.control_register & 0x80 == 0x80;
                self.tile_base = if self.control_register & 0x10 == 0x10 {
                    0x00
                } else {
                    0x800
                };
                self.background_base = if self.control_register & 0x08 == 0x08 {
                    0x1C00
                } else {
                    0x1800
                };
                self.sprite_shape = if self.control_register & 0x04 == 0x04 {
                    SpriteShape::Rectangle
                } else {
                    SpriteShape::Square
                };
            }
            0x41 => self.stat = GpuStat::from_u8(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => (),
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let addr = addr as usize;
        LittleEndian::write_u16(&mut self.ram[addr..], val)
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }
}
<commit_msg>Slight adjustment to scanline sskip check during sprite render<commit_after>use byteorder::{ByteOrder, LittleEndian};

use gameboy;
use gameboy::{Interconnect, Interrupt, Irq, Memory};
use gameboy::frame::{Color, Frame};

const VRAM_SIZE: usize = 0x4000;
const SPRITE_DATA_SIZE: usize = 0xA0;

pub struct GpuStat {
    pub coincidence_interrupt_enabled: bool,
    pub OAM_interrupt_enabled: bool,
    pub VBlank_interrupt_enabled: bool,
    pub HBlank_interrupt_enabled: bool,
}

impl GpuStat {
    pub fn new() -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: false,
            OAM_interrupt_enabled: false,
            VBlank_interrupt_enabled: false,
            HBlank_interrupt_enabled: false,
        }
    }

    pub fn from_u8(b: u8) -> GpuStat {
        GpuStat {
            coincidence_interrupt_enabled: b & 0x40 == 0x40,
            OAM_interrupt_enabled: b & 0x20 == 0x20,
            VBlank_interrupt_enabled: b & 0x10 == 0x10,
            HBlank_interrupt_enabled: b & 0x08 == 0x08,
        }
    }

    pub fn to_u8(&self, gpu: &Gpu) -> u8 {
        (if self.coincidence_interrupt_enabled {
            0x40
        } else {
            0
        }) | (if self.OAM_interrupt_enabled { 0x20 } else { 0 }) |
        (if self.VBlank_interrupt_enabled {
            0x10
        } else {
            0
        }) |
        (if self.HBlank_interrupt_enabled {
            0x08
        } else {
            0
        }) | (if gpu.ly == gpu.lyc { 0x04 } else { 0 }) | gpu.mode.to_u8()
    }
}

#[derive(Eq, PartialEq, Clone)]
pub enum GpuMode {
    HBlank,
    VBlank,
    SearchingRam,
    TransferringData,
}

impl GpuMode {
    fn to_u8(&self) -> u8 {
        match *self {
            GpuMode::HBlank => 0x00,
            GpuMode::VBlank => 0x01,
            GpuMode::SearchingRam => 0x02,
            GpuMode::TransferringData => 0x03,
        }
    }
}

pub enum SpriteShape {
    Square,
    Rectangle,
}

pub struct Gpu {
    pub enabled: bool,
    pub ram: Memory,
    pub sprite_data: Memory,
    control_register: u8,
    stat: GpuStat,
    scroll_y: u8,
    scroll_x: u8,
    window_y: u8,
    window_x: u8,
    pub ly: u8,
    lyc: u8,
    bg_palette: u8,
    palette0: u8,
    palette1: u8,

    cycles: isize,

    pub frame: Frame,
    pub backbuffer: Frame,
    mode: GpuMode,

    counter: u8,
    tile_base: usize,
    background_base: usize,
    sprite_shape: SpriteShape,
}

impl Gpu {
    pub fn new() -> Gpu {
        Gpu {
            enabled: true,
            ram: Memory::new(VRAM_SIZE),
            sprite_data: Memory::new(SPRITE_DATA_SIZE),
            control_register: 0x00,
            stat: GpuStat::new(),
            scroll_y: 0x00,
            scroll_x: 0x00,
            window_y: 0x00,
            window_x: 0x00,
            ly: 0x00,
            lyc: 0x00,
            bg_palette: 0x00,
            palette0: 0x00,
            palette1: 0x00,
            cycles: 0x00,
            frame: Frame::new(),
            backbuffer: Frame::new(),
            mode: GpuMode::HBlank,
            counter: 0,
            tile_base: 0x00,
            background_base: 0xC00,
            sprite_shape: SpriteShape::Square,
        }
    }

    pub fn reset(&mut self) {
        *self = Gpu::new();
    }

    fn set_status(&mut self, irq: &mut Irq) {
        if !self.enabled {
            self.cycles = 0x1C8;
            self.ly = 0x00;
            self.stat = GpuStat::from_u8(0xFD);
        }

        let current_mode = self.mode.clone();

        if self.ly >= 0x90 {
            self.mode = GpuMode::VBlank;
        } else {
            if self.cycles >= 0x178 {
                self.mode = GpuMode::SearchingRam;
            } else if self.cycles >= 0xCC {
                self.mode = GpuMode::TransferringData;
            } else {
                self.mode = GpuMode::HBlank;
            }
        }

        if self.mode != current_mode {
            irq.request(Interrupt::Lcd);
        }

        self.check_coincidence(irq);
    }

    pub fn step(&mut self, irq: &mut Irq, cycles: usize) -> Result<(), String> {
        self.set_status(irq);

        let cycles = cycles as isize;
        if self.enabled {
            self.cycles -= cycles;
        } else {
            return Ok(());
        }

        if self.cycles <= 0 {
            self.ly += 0x01;

            self.cycles = 0x1C8;

            if self.ly == 0x90 {
                irq.request(Interrupt::Vblank);
            } else if self.ly > 0x99 {
                self.ly = 0x00;
            } else if self.ly < 0x90 {
                self.render_scanline();
            }
        }

        Ok(())
    }

    fn render_scanline(&mut self) {
        let line = self.ly.wrapping_add(self.scroll_y) as usize;
        // self.clear_scanline(line);
        self.render_background(line);
        self.render_sprites(line);
        self.frame = self.backbuffer.clone();
    }

    fn clear_scanline(&mut self, line: usize) {
        for i in 0..160 {
            self.backbuffer.pixels[line * 160 + i] = Color::new(0xFF, 0xFF, 0xFF, 0xFF);
        }
    }

    fn render_background(&mut self, line: usize) {
        let bg_base = self.background_base;
        let tile_base = self.tile_base;
        let bg_map_row = (line / 0x08) as usize;
        for i in 0..gameboy::SCREEN_WIDTH {
            let x = (i as u8).wrapping_add(self.scroll_x);
            let bg_map_col = (x / 8) as usize;
            let raw_tile_number = self.ram[bg_base + (bg_map_row * 0x20 + bg_map_col)] as usize;

            let line_offset = (line % 0x08) << 0x01;

            let tile_data_start = tile_base +
                                  (if tile_base == 0x00 {
                raw_tile_number
            } else {
                (raw_tile_number as i8 as i16 + 0x80) as usize
            }) * 0x10 + line_offset;

            let x_shift = (x % 8).wrapping_sub(0x07).wrapping_mul(0xFF);
            let tile_data1 = (self.ram[tile_data_start] >> x_shift) & 0x01;
            let tile_data2 = (self.ram[tile_data_start + 0x01] >> x_shift) & 0x01;
            let total_row_data = (tile_data2 << 1) | tile_data1;
            let color_value = total_row_data;
            let c = self.get_background_color_for_byte(color_value as u8);
            self.backbuffer.pixels[self.ly as usize * 160 + i as usize] = c;
        }
    }

    fn render_sprites(&mut self, line: usize) {
        for i in 0..40 {
            let sprite_table_entry_base = i * 0x04;
            let s_y = self.sprite_data[sprite_table_entry_base] as i16 - 0x10;
            let s_x = self.sprite_data[sprite_table_entry_base + 0x01] as i16 - 0x08;
            let sprite_height = if let SpriteShape::Rectangle = self.sprite_shape {
                0x10
            } else {
                0x08
            };
            if line < s_y as usize || line >= s_y as usize + sprite_height {
                continue;
            }
            let tile_number = self.sprite_data[sprite_table_entry_base + 0x02] as i16;
            let attributes = self.sprite_data[sprite_table_entry_base + 0x03];
            let above_background = attributes & 0x80 == 0x00;

            let sprite_y = (line as i16 - s_y) << 0x01;
            let tile_data_start = (tile_number * 0x10) + sprite_y;
            for x in 0..8 {
                if s_x + x < 0 || s_x + x >= 160 {
                    continue;
                }
                let x_shift = 0x07 - x;
                let tile_data1 = (self.ram[tile_data_start as usize] >> x_shift) & 0x01;
                let tile_data2 = (self.ram[tile_data_start as usize + 0x01] >> x_shift) & 0x01;
                let total_row_data = (tile_data2 << 1) | tile_data1;
                let color_value = total_row_data;
                if color_value == 0x00 {
                    continue;
                }
                let c = self.get_sprite_color_for_byte(color_value as u8,
                                                       ((attributes & 0x10) >> 0x04) as u8);
                self.backbuffer.pixels[line as usize * 160 + (s_x as usize + x as usize)] = c;
            }
        }
    }

    fn get_background_color_for_byte(&self, b: u8) -> Color {
        let palette_index = match b {
            0x00 => self.bg_palette & 0x0003,
            0x01 => (self.bg_palette & 0x000C) >> 0x02,
            0x02 => (self.bg_palette & 0x0030) >> 0x04,
            0x03 => (self.bg_palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    fn get_sprite_color_for_byte(&self, b: u8, palette_entry: u8) -> Color {
        let palette = if palette_entry == 0x00 {
            self.palette0
        } else {
            self.palette1
        };

        let palette_index = match b {
            0x00 => palette & 0x0003,
            0x01 => (palette & 0x000C) >> 0x02,
            0x02 => (palette & 0x0030) >> 0x04,
            0x03 => (palette & 0x00C0) >> 0x06,
            _ => panic!("err: invalid pixel color value found"),
        };

        Color::from_dmg_byte(palette_index as u8)
    }

    pub fn read_u8(&self, addr: u16) -> u8 {
        match addr {
            0x40 => self.control_register,
            0x41 => self.stat.to_u8(self),
            0x42 => self.scroll_y,
            0x43 => self.scroll_x,
            0x4A => self.window_y,
            0x4B => self.window_x,
            0x44 => self.ly,
            0x45 => self.lyc,
            0x47 => self.bg_palette,
            0x48 => self.palette0,
            0x49 => self.palette1,
            _ => panic!("tried to read GPU memory that is not mapped"),
        }
    }

    pub fn write_u8(&mut self, addr: u16, val: u8) {
        match addr {
            0x40 => {
                self.control_register = val;
                self.enabled = self.control_register & 0x80 == 0x80;
                self.tile_base = if self.control_register & 0x10 == 0x10 {
                    0x00
                } else {
                    0x800
                };
                self.background_base = if self.control_register & 0x08 == 0x08 {
                    0x1C00
                } else {
                    0x1800
                };
                self.sprite_shape = if self.control_register & 0x04 == 0x04 {
                    SpriteShape::Rectangle
                } else {
                    SpriteShape::Square
                };
            }
            0x41 => self.stat = GpuStat::from_u8(val),
            0x42 => self.scroll_y = val,
            0x43 => self.scroll_x = val,
            0x44 => (),
            0x45 => {
                self.lyc = val;
            }
            0x47 => self.bg_palette = val,
            0x48 => self.palette0 = val,
            0x49 => self.palette1 = val,
            0x4A => self.window_y = val,
            0x4B => self.window_x = val,
            _ => panic!("tried to write GPU memory that is not mapped: {:04}", addr),
        }
    }

    pub fn write_u16(&mut self, addr: u16, val: u16) {
        let addr = addr as usize;
        LittleEndian::write_u16(&mut self.ram[addr..], val)
    }

    fn check_coincidence(&mut self, irq: &mut Irq) {
        // If LY == LYC then set the coincidence flag
        if self.lyc == self.ly && self.stat.coincidence_interrupt_enabled {
            irq.request(Interrupt::Lcd);
        }
    }
}
<|endoftext|>


<commit_before>use std::marker;
use std::cmp;
use std::collections::HashMap;

use solicit::http::client::RequestStream;
use solicit::http::client::ClientSession;
use solicit::http::session::Client;
use solicit::http::session::SessionState;
use solicit::http::session::DefaultSessionState;
use solicit::http::session::DefaultStream;
use solicit::http::session::StreamState;
use solicit::http::session::StreamDataError;
use solicit::http::session::StreamDataChunk;
use solicit::http::session::Stream as solicit_Stream;
use solicit::http::session::StreamIter;
use solicit::http::connection::HttpConnection;
use solicit::http::connection::SendStatus;
use solicit::http::connection::EndStream;
use solicit::http::connection::DataChunk;
use solicit::http::priority::SimplePrioritizer;
use solicit::http::frame::RawFrame;
use solicit::http::StreamId;
use solicit::http::HttpScheme;
use solicit::http::HttpError;
use solicit::http::Header;
use solicit::http::StaticHeader;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core;
use tokio_core::TcpStream;
use tokio_core::io as tokio_io;
use tokio_core::io::TaskIo;
use tokio_core::io::TaskIoRead;
use tokio_core::io::TaskIoWrite;
use tokio_core::LoopHandle;

use error::*;
use futures_misc::*;

use solicit_async::*;
use solicit_misc::*;

trait ResponseHandler : Send + 'static {
    fn headers(self) -> HttpFuture<Self>;
    fn body_chunk(self) -> HttpFuture<Self>;
    fn end(self) -> HttpFuture<()>;
}

struct GrpcHttp2ClientStream2<H : ResponseHandler> {
    state: StreamState,
    response_handler: H,
}

impl<H : ResponseHandler> solicit_Stream for GrpcHttp2ClientStream2<H> {
    fn new_data_chunk(&mut self, data: &[u8]) {
    }

    fn set_headers<'n, 'v>(&mut self, headers: Vec<Header<'n, 'v>>) {
    }

    fn set_state(&mut self, state: StreamState) {
        self.state = state;
    }

    fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result<StreamDataChunk, StreamDataError> {
        unimplemented!()
    }

    fn state(&self) -> StreamState {
        self.state
    }
}

struct Inner<H : ResponseHandler> {
    host: String,
    conn: HttpConnection,
    streams: HashMap<StreamId, GrpcHttp2ClientStream2<H>>,
    next_stream_id: StreamId,
    call_tx: tokio_core::Sender<ToWriteMessage<H>>,
}

impl<H : ResponseHandler> SessionState for Inner<H> {
    type Stream = GrpcHttp2ClientStream2<H>;

    fn insert_outgoing(&mut self, stream: Self::Stream) -> StreamId {
        let id = self.next_stream_id;
        self.streams.insert(id, stream);
        self.next_stream_id += 2;
        id
    }

    fn insert_incoming(&mut self, stream_id: StreamId, stream: Self::Stream) -> Result<(), ()> {
        // TODO: assert parity
        // TODO: Assert that the stream IDs are monotonically increasing!
        self.streams.insert(stream_id, stream);
        Ok(())
    }

    #[inline]
    fn get_stream_ref(&self, stream_id: StreamId) -> Option<&Self::Stream> {
        self.streams.get(&stream_id)
    }

    #[inline]
    fn get_stream_mut(&mut self, stream_id: StreamId) -> Option<&mut Self::Stream> {
        self.streams.get_mut(&stream_id)
    }

    #[inline]
    fn remove_stream(&mut self, stream_id: StreamId) -> Option<Self::Stream> {
        self.streams.remove(&stream_id)
    }

    #[inline]
    fn iter(&mut self) -> StreamIter<GrpcHttp2ClientStream2<H>> {
        // https://github.com/mlalic/solicit/pull/34
        unimplemented!()
    }

    /// Number of currently active streams
    #[inline]
    fn len(&self) -> usize {
        self.streams.len()
    }
}

struct HttpConnectionAsync<H : ResponseHandler> {
    inner: TaskRcMut<Inner<H>>,
}

struct StartRequestMessage<H : ResponseHandler> {
    headers: Vec<StaticHeader>,
    body: HttpStream<Vec<u8>>,
    response_handler: H,
}

struct BodyChunkMessage {
    stream_id: StreamId,
    chunk: Vec<u8>,
}

struct EndRequestMessage {
    stream_id: StreamId,
}

struct ReadToWriteMessage {
    buf: Vec<u8>,
}

enum ToWriteMessage<H : ResponseHandler> {
    Start(StartRequestMessage<H>),
    BodyChunk(BodyChunkMessage),
    End(EndRequestMessage),
    FromRead(ReadToWriteMessage),
}

struct WriteLoop<H : ResponseHandler> {
    write: TaskIoWrite<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> WriteLoop<H> {
    fn write_all(self, buf: Vec<u8>) -> HttpFuture<Self> {
        let WriteLoop { write, inner } = self;

        tokio_io::write_all(write, buf)
            .map(move |(write, _)| WriteLoop { write: write, inner: inner })
            .map_err(HttpError::from)
            .boxed()
    }

    fn process_from_read(self, message: ReadToWriteMessage) -> HttpFuture<Self> {
        self.write_all(message.buf)
    }

    fn process_start(self, start: StartRequestMessage<H>) -> HttpFuture<Self> {
        let StartRequestMessage { headers, body, response_handler } = start;
        let (buf, stream_id) = self.inner.with(move |inner: &mut Inner<H>| {

            let stream = GrpcHttp2ClientStream2 {
                state: StreamState::Open,
                response_handler: response_handler,
            };
            let stream_id = inner.insert_outgoing(stream);

            let send_buf = {
                let mut send_buf = VecSendFrame(Vec::new());

                inner.conn.sender(&mut send_buf).send_headers(headers, stream_id, EndStream::No).unwrap();

                (send_buf.0, stream_id)
            };

            send_buf
        });

        self.write_all(buf)
            .and_then(move |wl: WriteLoop<H>| {
                body.fold(wl, move |wl: WriteLoop<H>, chunk| {
                    wl.inner.with(|inner: &mut Inner<H>| {
                        inner.call_tx.send(ToWriteMessage::BodyChunk(BodyChunkMessage {
                            stream_id: stream_id,
                            chunk: chunk,
                        }))
                    });
                    futures::finished::<_, HttpError>(wl)
                })
            })
            .and_then(move |wl: WriteLoop<H>| {
                wl.inner.with(|inner: &mut Inner<H>| {
                    inner.call_tx.send(ToWriteMessage::End(EndRequestMessage {
                        stream_id: stream_id,
                    }));
                });
                futures::finished::<_, HttpError>(wl)
            })
            .boxed()
    }

    fn process_body_chunk(self, body_chunk: BodyChunkMessage) -> HttpFuture<Self> {
        let BodyChunkMessage { stream_id, chunk } = body_chunk;

        let buf = self.inner.with(move |inner: &mut Inner<H>| {
            {
                let stream = inner.get_stream_mut(stream_id);
                // TODO: check stream state
            }

            let mut send_buf = VecSendFrame(Vec::new());

            let mut pos = 0;
            const MAX_CHUNK_SIZE: usize = 8 * 1024;
            while pos < chunk.len() {
                let end = cmp::min(chunk.len(), pos + MAX_CHUNK_SIZE);

                let data_chunk = DataChunk::new_borrowed(&chunk[pos..end], stream_id, EndStream::No);

                inner.conn.sender(&mut send_buf).send_data(data_chunk).unwrap();

                pos = end;
            }

            send_buf.0
        });

        self.write_all(buf)
    }

    fn process_end(self, end: EndRequestMessage) -> HttpFuture<Self> {
        let EndRequestMessage { stream_id } = end;

        let buf = self.inner.with(move |inner: &mut Inner<H>| {
            let mut send_buf = VecSendFrame(Vec::new());

            let chunk = Vec::new();
            let data_chunk = DataChunk::new_borrowed(&chunk[..], stream_id, EndStream::Yes);

            inner.conn.sender(&mut send_buf).send_data(data_chunk).unwrap();

            send_buf.0
        });

        futures::finished(self).boxed()
    }

    fn process_message(self, message: ToWriteMessage<H>) -> HttpFuture<Self> {
        match message {
            ToWriteMessage::Start(start) => self.process_start(start),
            ToWriteMessage::BodyChunk(body_chunk) => self.process_body_chunk(body_chunk),
            ToWriteMessage::End(end) => self.process_end(end),
            ToWriteMessage::FromRead(from_read) => self.process_from_read(from_read),
        }
    }

    fn run(self, requests: tokio_core::Receiver<ToWriteMessage<H>>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        requests
            .fold(self, move |wl, message: ToWriteMessage<H>| {
                wl.process_message(message)
            })
            .map(|_| ())
            .boxed()
    }
}

struct ReadLoop<H : ResponseHandler> {
    read: TaskIoRead<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> ReadLoop<H> {
    fn recv_raw_frame(self) -> HttpFuture<(Self, RawFrame<'static>)> {
        let ReadLoop { read, inner } = self;
        recv_raw_frame(read)
            .map(|(read, frame)| (ReadLoop { read: read, inner: inner}, frame))
            .map_err(HttpError::from)
            .boxed()
    }

    fn read_process_frame(self) -> HttpFuture<Self> {
        self.recv_raw_frame()
            .map(|(rl, frame)| rl)
            .boxed()
    }

    fn run(self) -> HttpFuture<()> {
        let stream = stream_repeat(());

        let future = stream.fold(self, |rl, _| {
            rl.read_process_frame()
        });

        future.map(|_| ()).boxed()
    }
}

impl<H : ResponseHandler> HttpConnectionAsync<H> {
    fn new(lh: LoopHandle, conn: TcpStream) -> HttpFuture<(Self, HttpFuture<()>)> {
        let (call_tx, call_rx) = lh.channel();

        let handshake = client_handshake(conn);
        handshake.and_then(move |conn| {
            let (read, write) = TaskIo::new(conn).split();

            let inner = TaskRcMut::new(Inner {
                host: "localhost".to_owned(), // TODO
                conn: HttpConnection::new(HttpScheme::Http),
                next_stream_id: 1,
                streams: HashMap::new(),
                call_tx: call_tx,
            });

            let write_inner = inner.clone();
            let run_write = call_rx.map_err(HttpError::from).and_then(move |call_rx| WriteLoop { write: write, inner: write_inner }.run(call_rx));
            let run_read = ReadLoop { read: read, inner: inner.clone() }.run();

            let c = HttpConnectionAsync {
                inner: inner,
            };
            Ok((c, run_write.join(run_read).map(|_| ()).boxed()))
        }).boxed()
    }

    fn start_request(
        &self,
        headers: Vec<StaticHeader>,
        body: HttpStream<Vec<u8>>,
        response_handler: H)
            -> HttpFuture<()>
    {
        self.inner.with(|inner: &mut Inner<H>| {
            inner.call_tx.send(ToWriteMessage::Start(StartRequestMessage {
                headers: headers,
                body: body,
                response_handler: response_handler,
            }));
        });
        futures::finished(()).boxed()
    }
}
<commit_msg>move http client<commit_after>use std::marker;
use std::cmp;
use std::collections::HashMap;
use std::iter::FromIterator;

use solicit::http::client::RequestStream;
use solicit::http::client::ClientSession;
use solicit::http::session::Client;
use solicit::http::session::SessionState;
use solicit::http::session::DefaultSessionState;
use solicit::http::session::DefaultStream;
use solicit::http::session::StreamState;
use solicit::http::session::StreamDataError;
use solicit::http::session::StreamDataChunk;
use solicit::http::session::Stream as solicit_Stream;
use solicit::http::session::StreamIter;
use solicit::http::connection::HttpConnection;
use solicit::http::connection::SendStatus;
use solicit::http::connection::EndStream;
use solicit::http::connection::DataChunk;
use solicit::http::priority::SimplePrioritizer;
use solicit::http::frame::RawFrame;
use solicit::http::StreamId;
use solicit::http::HttpScheme;
use solicit::http::HttpError;
use solicit::http::Header;
use solicit::http::StaticHeader;

use futures;
use futures::Future;
use futures::stream::Stream;

use tokio_core;
use tokio_core::TcpStream;
use tokio_core::io as tokio_io;
use tokio_core::io::TaskIo;
use tokio_core::io::TaskIoRead;
use tokio_core::io::TaskIoWrite;
use tokio_core::LoopHandle;

use error::*;
use futures_misc::*;

use solicit_async::*;
use solicit_misc::*;

trait ResponseHandler : Send + 'static {
    fn headers(self) -> HttpFuture<Self>;
    fn body_chunk(self) -> HttpFuture<Self>;
    fn end(self) -> HttpFuture<()>;
}

struct GrpcHttp2ClientStream2<H : ResponseHandler> {
    state: StreamState,
    response_handler: H,
}

impl<H : ResponseHandler> solicit_Stream for GrpcHttp2ClientStream2<H> {
    fn new_data_chunk(&mut self, data: &[u8]) {
    }

    fn set_headers<'n, 'v>(&mut self, headers: Vec<Header<'n, 'v>>) {
    }

    fn set_state(&mut self, state: StreamState) {
        self.state = state;
    }

    fn get_data_chunk(&mut self, buf: &mut [u8]) -> Result<StreamDataChunk, StreamDataError> {
        unimplemented!()
    }

    fn state(&self) -> StreamState {
        self.state
    }
}

struct MySessionState<H : ResponseHandler> {
    streams: HashMap<StreamId, GrpcHttp2ClientStream2<H>>,
    next_stream_id: StreamId,
}

impl<H : ResponseHandler> MySessionState<H> {
    fn remove_closed_streams(&mut self) {
        let ids: Vec<StreamId> = self.streams
            .iter()
            .filter_map(|(id, s)| {
                if s.is_closed() {
                    Some(*id)
                } else {
                    None
                }
            })
            .collect();
        Vec::from_iter(ids.into_iter().map(|i| self.remove_stream(i).unwrap()));
    }
}

impl<H : ResponseHandler> SessionState for MySessionState<H> {
    type Stream = GrpcHttp2ClientStream2<H>;

    fn insert_outgoing(&mut self, stream: Self::Stream) -> StreamId {
        let id = self.next_stream_id;
        self.streams.insert(id, stream);
        self.next_stream_id += 2;
        id
    }

    fn insert_incoming(&mut self, stream_id: StreamId, stream: Self::Stream) -> Result<(), ()> {
        // TODO: assert parity
        // TODO: Assert that the stream IDs are monotonically increasing!
        self.streams.insert(stream_id, stream);
        Ok(())
    }

    #[inline]
    fn get_stream_ref(&self, stream_id: StreamId) -> Option<&Self::Stream> {
        self.streams.get(&stream_id)
    }

    #[inline]
    fn get_stream_mut(&mut self, stream_id: StreamId) -> Option<&mut Self::Stream> {
        self.streams.get_mut(&stream_id)
    }

    #[inline]
    fn remove_stream(&mut self, stream_id: StreamId) -> Option<Self::Stream> {
        self.streams.remove(&stream_id)
    }

    #[inline]
    fn iter(&mut self) -> StreamIter<GrpcHttp2ClientStream2<H>> {
        // https://github.com/mlalic/solicit/pull/34
        unimplemented!()
    }

    /// Number of currently active streams
    #[inline]
    fn len(&self) -> usize {
        self.streams.len()
    }
}

struct Inner<H : ResponseHandler> {
    host: String,
    conn: HttpConnection,
    call_tx: tokio_core::Sender<ToWriteMessage<H>>,
    session_state: MySessionState<H>,
}

struct HttpConnectionAsync<H : ResponseHandler> {
    inner: TaskRcMut<Inner<H>>,
}

struct StartRequestMessage<H : ResponseHandler> {
    headers: Vec<StaticHeader>,
    body: HttpStream<Vec<u8>>,
    response_handler: H,
}

struct BodyChunkMessage {
    stream_id: StreamId,
    chunk: Vec<u8>,
}

struct EndRequestMessage {
    stream_id: StreamId,
}

struct ReadToWriteMessage {
    buf: Vec<u8>,
}

enum ToWriteMessage<H : ResponseHandler> {
    Start(StartRequestMessage<H>),
    BodyChunk(BodyChunkMessage),
    End(EndRequestMessage),
    FromRead(ReadToWriteMessage),
}

struct WriteLoop<H : ResponseHandler> {
    write: TaskIoWrite<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> WriteLoop<H> {
    fn write_all(self, buf: Vec<u8>) -> HttpFuture<Self> {
        let WriteLoop { write, inner } = self;

        tokio_io::write_all(write, buf)
            .map(move |(write, _)| WriteLoop { write: write, inner: inner })
            .map_err(HttpError::from)
            .boxed()
    }

    fn process_from_read(self, message: ReadToWriteMessage) -> HttpFuture<Self> {
        self.write_all(message.buf)
    }

    fn process_start(self, start: StartRequestMessage<H>) -> HttpFuture<Self> {
        let StartRequestMessage { headers, body, response_handler } = start;
        let (buf, stream_id) = self.inner.with(move |inner: &mut Inner<H>| {

            let stream = GrpcHttp2ClientStream2 {
                state: StreamState::Open,
                response_handler: response_handler,
            };
            let stream_id = inner.session_state.insert_outgoing(stream);

            let send_buf = {
                let mut send_buf = VecSendFrame(Vec::new());

                inner.conn.sender(&mut send_buf).send_headers(headers, stream_id, EndStream::No).unwrap();

                (send_buf.0, stream_id)
            };

            send_buf
        });

        self.write_all(buf)
            .and_then(move |wl: WriteLoop<H>| {
                body.fold(wl, move |wl: WriteLoop<H>, chunk| {
                    wl.inner.with(|inner: &mut Inner<H>| {
                        inner.call_tx.send(ToWriteMessage::BodyChunk(BodyChunkMessage {
                            stream_id: stream_id,
                            chunk: chunk,
                        }))
                    });
                    futures::finished::<_, HttpError>(wl)
                })
            })
            .and_then(move |wl: WriteLoop<H>| {
                wl.inner.with(|inner: &mut Inner<H>| {
                    inner.call_tx.send(ToWriteMessage::End(EndRequestMessage {
                        stream_id: stream_id,
                    }));
                });
                futures::finished::<_, HttpError>(wl)
            })
            .boxed()
    }

    fn process_body_chunk(self, body_chunk: BodyChunkMessage) -> HttpFuture<Self> {
        let BodyChunkMessage { stream_id, chunk } = body_chunk;

        let buf = self.inner.with(move |inner: &mut Inner<H>| {
            {
                let stream = inner.session_state.get_stream_mut(stream_id);
                // TODO: check stream state
            }

            let mut send_buf = VecSendFrame(Vec::new());

            let mut pos = 0;
            const MAX_CHUNK_SIZE: usize = 8 * 1024;
            while pos < chunk.len() {
                let end = cmp::min(chunk.len(), pos + MAX_CHUNK_SIZE);

                let data_chunk = DataChunk::new_borrowed(&chunk[pos..end], stream_id, EndStream::No);

                inner.conn.sender(&mut send_buf).send_data(data_chunk).unwrap();

                pos = end;
            }

            send_buf.0
        });

        self.write_all(buf)
    }

    fn process_end(self, end: EndRequestMessage) -> HttpFuture<Self> {
        let EndRequestMessage { stream_id } = end;

        let buf = self.inner.with(move |inner: &mut Inner<H>| {
            let mut send_buf = VecSendFrame(Vec::new());

            let chunk = Vec::new();
            let data_chunk = DataChunk::new_borrowed(&chunk[..], stream_id, EndStream::Yes);

            inner.conn.sender(&mut send_buf).send_data(data_chunk).unwrap();

            send_buf.0
        });

        futures::finished(self).boxed()
    }

    fn process_message(self, message: ToWriteMessage<H>) -> HttpFuture<Self> {
        match message {
            ToWriteMessage::Start(start) => self.process_start(start),
            ToWriteMessage::BodyChunk(body_chunk) => self.process_body_chunk(body_chunk),
            ToWriteMessage::End(end) => self.process_end(end),
            ToWriteMessage::FromRead(from_read) => self.process_from_read(from_read),
        }
    }

    fn run(self, requests: tokio_core::Receiver<ToWriteMessage<H>>) -> HttpFuture<()> {
        let requests = requests.map_err(HttpError::from);
        requests
            .fold(self, move |wl, message: ToWriteMessage<H>| {
                wl.process_message(message)
            })
            .map(|_| ())
            .boxed()
    }
}

struct ReadLoop<H : ResponseHandler> {
    read: TaskIoRead<TcpStream>,
    inner: TaskRcMut<Inner<H>>,
}

impl<H : ResponseHandler> ReadLoop<H> {
    fn recv_raw_frame(self) -> HttpFuture<(Self, RawFrame<'static>)> {
        let ReadLoop { read, inner } = self;
        recv_raw_frame(read)
            .map(|(read, frame)| (ReadLoop { read: read, inner: inner}, frame))
            .map_err(HttpError::from)
            .boxed()
    }

    fn process_raw_frame(self, raw_frame: RawFrame) -> HttpFuture<Self> {

        self.inner.with(|inner: &mut Inner<H>| {
            let mut send = VecSendFrame(Vec::new());
            {
                let mut session = ClientSession::new(&mut inner.session_state, &mut send);
                inner.conn.handle_next_frame(&mut OnceReceiveFrame::new(raw_frame), &mut session)
                    .unwrap();
            }

            inner.session_state.remove_closed_streams();

            if !send.0.is_empty() {
                inner.call_tx.send(ToWriteMessage::FromRead(ReadToWriteMessage { buf: send.0 }))
                    .expect("read to write");
            }
        });

        futures::finished(self).boxed()
    }

    fn read_process_frame(self) -> HttpFuture<Self> {
        self.recv_raw_frame()
            .and_then(move |(rl, frame)| rl.process_raw_frame(frame))
            .boxed()
    }

    fn run(self) -> HttpFuture<()> {
        let stream = stream_repeat(());

        let future = stream.fold(self, |rl, _| {
            rl.read_process_frame()
        });

        future.map(|_| ()).boxed()
    }
}

impl<H : ResponseHandler> HttpConnectionAsync<H> {
    fn new(lh: LoopHandle, conn: TcpStream) -> HttpFuture<(Self, HttpFuture<()>)> {
        let (call_tx, call_rx) = lh.channel();

        let handshake = client_handshake(conn);
        handshake.and_then(move |conn| {
            let (read, write) = TaskIo::new(conn).split();

            let inner = TaskRcMut::new(Inner {
                host: "localhost".to_owned(), // TODO
                conn: HttpConnection::new(HttpScheme::Http),
                call_tx: call_tx,
                session_state: MySessionState {
                    next_stream_id: 1,
                    streams: HashMap::new(),
                }
            });

            let write_inner = inner.clone();
            let run_write = call_rx.map_err(HttpError::from).and_then(move |call_rx| WriteLoop { write: write, inner: write_inner }.run(call_rx));
            let run_read = ReadLoop { read: read, inner: inner.clone() }.run();

            let c = HttpConnectionAsync {
                inner: inner,
            };
            Ok((c, run_write.join(run_read).map(|_| ()).boxed()))
        }).boxed()
    }

    fn start_request(
        &self,
        headers: Vec<StaticHeader>,
        body: HttpStream<Vec<u8>>,
        response_handler: H)
            -> HttpFuture<()>
    {
        self.inner.with(|inner: &mut Inner<H>| {
            inner.call_tx.send(ToWriteMessage::Start(StartRequestMessage {
                headers: headers,
                body: body,
                response_handler: response_handler,
            }));
        });
        futures::finished(()).boxed()
    }
}
<|endoftext|>


<commit_before>use parking_lot::Mutex;
use std::{fmt, ops::AddAssign, sync::Arc};

#[derive(Clone)]
pub(crate) struct IdSequence<T>(Arc<Mutex<Inner<T>>>);

impl<T: Default + Copy + AddAssign<T> + PartialEq<T> + PartialOrd<T> + From<u8>> IdSequence<T> {
    pub(crate) fn new(allow_zero: bool) -> Self {
        Self(Arc::new(Mutex::new(Inner::new(allow_zero))))
    }

    pub(crate) fn current(&self) -> T {
        self.0.lock().id
    }

    pub(crate) fn next(&self) -> T {
        self.0.lock().next()
    }

    pub(crate) fn set_max(&self, max: T) {
        self.0.lock().set_max(max)
    }
}

impl<T: fmt::Debug> fmt::Debug for IdSequence<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("IdSequence");
        if let Some(inner) = self.0.try_lock() {
            debug
                .field("allow_zero", &inner.allow_zero)
                .field("max", &inner.max)
                .field("id", &inner.id);
        }
        debug.finish()
    }
}

#[derive(Debug)]
struct Inner<T> {
    allow_zero: bool,
    zero: T,
    one: T,
    max: Option<T>,
    id: T,
}

impl<T: Default + Copy + AddAssign<T> + PartialEq<T> + PartialOrd<T> + From<u8>> Inner<T> {
    fn new(allow_zero: bool) -> Self {
        Self {
            allow_zero,
            zero: 0.into(),
            one: 1.into(),
            max: None,
            id: T::default(),
        }
    }

    fn set_max(&mut self, max: T) {
        self.max = if max == self.zero { None } else { Some(max) };
    }

    fn next(&mut self) -> T {
        if !self.allow_zero && self.id == self.zero {
            self.id += self.one;
        }
        if self.check_max() {
            let id = self.id;
            self.id += self.one;
            id
        } else {
            self.id = self.zero;
            self.next()
        }
    }

    fn check_max(&self) -> bool {
        if let Some(max) = self.max {
            self.id <= max
        } else {
            true
        }
    }
}
<commit_msg>IdSequence: simplify<commit_after>use std::{fmt, ops::AddAssign};

pub(crate) struct IdSequence<T> {
    allow_zero: bool,
    zero: T,
    one: T,
    max: Option<T>,
    id: T,
}

impl<T: Default + Copy + AddAssign<T> + PartialEq<T> + PartialOrd<T> + From<u8>> IdSequence<T> {
    pub(crate) fn new(allow_zero: bool) -> Self {
        Self {
            allow_zero,
            zero: 0.into(),
            one: 1.into(),
            max: None,
            id: T::default(),
        }
    }

    pub(crate) fn current(&self) -> T {
        self.id
    }

    pub(crate) fn set_max(&mut self, max: T) {
        self.max = if max == self.zero { None } else { Some(max) };
    }

    pub(crate) fn next(&mut self) -> T {
        if !self.allow_zero && self.id == self.zero {
            self.id += self.one;
        }
        if self.check_max() {
            let id = self.id;
            self.id += self.one;
            id
        } else {
            self.id = self.zero;
            self.next()
        }
    }

    fn check_max(&self) -> bool {
        if let Some(max) = self.max {
            self.id <= max
        } else {
            true
        }
    }
}

impl<T: fmt::Debug> fmt::Debug for IdSequence<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("IdSequence")
            .field("allow_zero", &self.allow_zero)
            .field("max", &self.max)
            .field("id", &self.id)
            .finish()
    }
}
<|endoftext|>


<commit_before>use parking_lot::Mutex;
use std::{fmt, ops::AddAssign, sync::Arc};

#[derive(Clone)]
pub(crate) struct IdSequence<T> {
    inner: Arc<Mutex<Inner<T>>>,
}

impl<T: Default + Copy + AddAssign<T> + PartialEq<T> + PartialOrd<T> + From<u8>> IdSequence<T> {
    pub(crate) fn new(allow_zero: bool) -> Self {
        Self {
            inner: Arc::new(Mutex::new(Inner::new(allow_zero))),
        }
    }

    pub(crate) fn next(&self) -> T {
        self.inner.lock().next()
    }

    pub(crate) fn set_max(&self, max: T) {
        self.inner.lock().set_max(max)
    }
}

impl<T: fmt::Debug> fmt::Debug for IdSequence<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("IdSequence");
        if let Some(inner) = self.inner.try_lock() {
            debug
                .field("allow_zero", &inner.allow_zero)
                .field("max", &inner.max)
                .field("id", &inner.id);
        }
        debug.finish()
    }
}

#[derive(Debug)]
struct Inner<T> {
    allow_zero: bool,
    zero: T,
    one: T,
    max: Option<T>,
    id: T,
}

impl<T: Default + Copy + AddAssign<T> + PartialEq<T> + PartialOrd<T> + From<u8>> Inner<T> {
    fn new(allow_zero: bool) -> Self {
        Self {
            allow_zero,
            zero: 0.into(),
            one: 1.into(),
            max: None,
            id: T::default(),
        }
    }

    fn set_max(&mut self, max: T) {
        self.max = if max == self.zero { None } else { Some(max) };
    }

    // FIXME: use Step trait once stable (https://github.com/rust-lang/rust/issues/42168)
    fn next(&mut self) -> T {
        if !self.allow_zero && self.id == self.zero {
            self.id += self.one;
        }
        if self.check_max() {
            let id = self.id;
            self.id += self.one;
            id
        } else {
            self.id = self.zero;
            self.next()
        }
    }

    fn check_max(&self) -> bool {
        if let Some(max) = self.max {
            self.id < max
        } else {
            true
        }
    }
}
<commit_msg>drop old FIXME<commit_after>use parking_lot::Mutex;
use std::{fmt, ops::AddAssign, sync::Arc};

#[derive(Clone)]
pub(crate) struct IdSequence<T> {
    inner: Arc<Mutex<Inner<T>>>,
}

impl<T: Default + Copy + AddAssign<T> + PartialEq<T> + PartialOrd<T> + From<u8>> IdSequence<T> {
    pub(crate) fn new(allow_zero: bool) -> Self {
        Self {
            inner: Arc::new(Mutex::new(Inner::new(allow_zero))),
        }
    }

    pub(crate) fn next(&self) -> T {
        self.inner.lock().next()
    }

    pub(crate) fn set_max(&self, max: T) {
        self.inner.lock().set_max(max)
    }
}

impl<T: fmt::Debug> fmt::Debug for IdSequence<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut debug = f.debug_struct("IdSequence");
        if let Some(inner) = self.inner.try_lock() {
            debug
                .field("allow_zero", &inner.allow_zero)
                .field("max", &inner.max)
                .field("id", &inner.id);
        }
        debug.finish()
    }
}

#[derive(Debug)]
struct Inner<T> {
    allow_zero: bool,
    zero: T,
    one: T,
    max: Option<T>,
    id: T,
}

impl<T: Default + Copy + AddAssign<T> + PartialEq<T> + PartialOrd<T> + From<u8>> Inner<T> {
    fn new(allow_zero: bool) -> Self {
        Self {
            allow_zero,
            zero: 0.into(),
            one: 1.into(),
            max: None,
            id: T::default(),
        }
    }

    fn set_max(&mut self, max: T) {
        self.max = if max == self.zero { None } else { Some(max) };
    }

    fn next(&mut self) -> T {
        if !self.allow_zero && self.id == self.zero {
            self.id += self.one;
        }
        if self.check_max() {
            let id = self.id;
            self.id += self.one;
            id
        } else {
            self.id = self.zero;
            self.next()
        }
    }

    fn check_max(&self) -> bool {
        if let Some(max) = self.max {
            self.id < max
        } else {
            true
        }
    }
}
<|endoftext|>


<commit_before>use crate::{
    api::Error,
    db::Database,
    model::{AnnoLichess, Mode, PersonalEntry, PersonalKeyBuilder, UserName},
    util::NevermindExt as _,
};
use clap::Clap;
use futures_util::StreamExt;
use rustc_hash::FxHashMap;
use shakmaty::{
    uci::Uci, variant::VariantPosition, zobrist::Zobrist, ByColor, CastlingMode, Color, Outcome,
    Position,
};
use std::io::Cursor;
use std::sync::Arc;
use std::time::Duration;
use tokio::{
    sync::{
        mpsc::{self, error::SendTimeoutError},
        oneshot,
    },
    task::JoinHandle,
    time::timeout,
};

mod lila;

use lila::{Game, Lila};

#[derive(Clap)]
pub struct IndexerOpt {
    #[clap(long = "lila", default_value = "https://lichess.org")]
    lila: String,
}

#[derive(Clone)]
pub struct IndexerStub {
    tx: mpsc::Sender<IndexerMessage>,
}

impl IndexerStub {
    pub fn spawn(db: Arc<Database>, opt: IndexerOpt) -> (IndexerStub, JoinHandle<()>) {
        let (tx, rx) = mpsc::channel(2);
        (
            IndexerStub { tx },
            tokio::spawn(
                IndexerActor {
                    rx,
                    db,
                    lila: Lila::new(opt),
                }
                .run(),
            ),
        )
    }

    pub async fn index_player(&self, player: UserName) -> Result<IndexerStatus, Error> {
        let (req, res) = oneshot::channel();

        self.tx
            .send_timeout(
                IndexerMessage::IndexPlayer {
                    player,
                    callback: req,
                },
                Duration::from_secs(2),
            )
            .await
            .map_err(|err| match err {
                SendTimeoutError::Timeout(_) => Error::IndexerQueueFull,
                SendTimeoutError::Closed(_) => panic!("indexer died"),
            })?;

        match timeout(Duration::from_secs(7), res).await {
            Ok(res) => match res.expect("indexer alive") {
                Ok(()) => Ok(IndexerStatus::Completed),
                Err(err) => Err(err),
            },
            Err(_) => return Ok(IndexerStatus::Ongoing),
        }
    }
}

struct IndexerActor {
    rx: mpsc::Receiver<IndexerMessage>,
    db: Arc<Database>,
    lila: Lila,
}

impl IndexerActor {
    async fn run(mut self) {
        while let Some(msg) = self.rx.recv().await {
            match msg {
                IndexerMessage::IndexPlayer { callback, player } => {
                    callback
                        .send(self.index_player(player).await)
                        .nevermind("requester gone away");
                }
            }
        }
    }

    async fn index_player(&self, player: UserName) -> Result<(), Error> {
        log::info!("starting to index {}", player);

        let hash = ByColor::new_with(|color| {
            PersonalKeyBuilder::with_user_pov(&player.to_owned().into(), color)
        });

        let mut num_games = 0;
        let mut games = self.lila.user_games(&player).await?;
        while let Some(game) = games.next().await {
            let game = game?;
            num_games += 1;
            self.index_game(&player, &hash, game);
        }

        log::info!("indexed {} games for {}", num_games, player);
        Ok(())
    }

    fn index_game(&self, player: &UserName, hash: &ByColor<PersonalKeyBuilder>, game: Game) {
        if game.status.is_unindexable() || game.status.is_ongoing() {
            return;
        }

        let color = if Some(player) == game.user_name(Color::White) {
            Color::White
        } else if Some(player) == game.user_name(Color::Black) {
            Color::Black
        } else {
            return;
        };

        let year = AnnoLichess::from_time(game.last_move_at);
        let outcome = Outcome::from_winner(game.winner);
        let variant = game.variant.into();
        let pos = match game.initial_fen {
            Some(fen) => VariantPosition::from_setup(variant, &fen, CastlingMode::Chess960),
            None => Ok(VariantPosition::new(variant)),
        };

        let mut pos: Zobrist<_, u128> = match pos {
            Ok(pos) => Zobrist::new(pos),
            Err(err) => {
                log::error!("indexing {}: {}", game.id, err);
                return;
            }
        };

        // Build an intermediate table to remove loops (due to repetitions).
        let mut table: FxHashMap<u128, Uci> =
            FxHashMap::with_capacity_and_hasher(game.moves.len(), Default::default());

        for (ply, san) in game.moves.into_iter().enumerate() {
            let m = match san.to_move(&pos) {
                Ok(m) => m,
                Err(err) => {
                    log::error!("indexing {}: {} ({} at ply {})", game.id, err, san, ply);
                    return;
                }
            };

            let uci = m.to_uci(CastlingMode::Chess960);
            table.insert(pos.zobrist_hash(), uci);

            pos.play_unchecked(&m);
        }

        let queryable = self.db.queryable();

        for (zobrist, uci) in table {
            let entry = PersonalEntry::new_single(
                uci.clone(),
                game.speed,
                Mode::from_rated(game.rated),
                game.id,
                outcome,
            );

            let mut buf = Cursor::new(Vec::new());
            entry.write(&mut buf).expect("serialize personal entry");

            queryable
                .db
                .put_cf(
                    queryable.cf_personal,
                    hash.by_color(color)
                        .with_zobrist(variant, zobrist)
                        .with_year(year),
                    buf.into_inner(),
                )
                .expect("merge cf personal");
        }
    }
}

enum IndexerMessage {
    IndexPlayer {
        player: UserName,
        callback: oneshot::Sender<Result<(), Error>>,
    },
}

pub enum IndexerStatus {
    Ongoing,
    Completed,
    Failed,
}
<commit_msg>downgrade illegal starting positions to warning<commit_after>use crate::{
    api::Error,
    db::Database,
    model::{AnnoLichess, Mode, PersonalEntry, PersonalKeyBuilder, UserName},
    util::NevermindExt as _,
};
use clap::Clap;
use futures_util::StreamExt;
use rustc_hash::FxHashMap;
use shakmaty::{
    uci::Uci, variant::VariantPosition, zobrist::Zobrist, ByColor, CastlingMode, Color, Outcome,
    Position,
};
use std::io::Cursor;
use std::sync::Arc;
use std::time::Duration;
use tokio::{
    sync::{
        mpsc::{self, error::SendTimeoutError},
        oneshot,
    },
    task::JoinHandle,
    time::timeout,
};

mod lila;

use lila::{Game, Lila};

#[derive(Clap)]
pub struct IndexerOpt {
    #[clap(long = "lila", default_value = "https://lichess.org")]
    lila: String,
}

#[derive(Clone)]
pub struct IndexerStub {
    tx: mpsc::Sender<IndexerMessage>,
}

impl IndexerStub {
    pub fn spawn(db: Arc<Database>, opt: IndexerOpt) -> (IndexerStub, JoinHandle<()>) {
        let (tx, rx) = mpsc::channel(2);
        (
            IndexerStub { tx },
            tokio::spawn(
                IndexerActor {
                    rx,
                    db,
                    lila: Lila::new(opt),
                }
                .run(),
            ),
        )
    }

    pub async fn index_player(&self, player: UserName) -> Result<IndexerStatus, Error> {
        let (req, res) = oneshot::channel();

        self.tx
            .send_timeout(
                IndexerMessage::IndexPlayer {
                    player,
                    callback: req,
                },
                Duration::from_secs(2),
            )
            .await
            .map_err(|err| match err {
                SendTimeoutError::Timeout(_) => Error::IndexerQueueFull,
                SendTimeoutError::Closed(_) => panic!("indexer died"),
            })?;

        match timeout(Duration::from_secs(7), res).await {
            Ok(res) => match res.expect("indexer alive") {
                Ok(()) => Ok(IndexerStatus::Completed),
                Err(err) => Err(err),
            },
            Err(_) => return Ok(IndexerStatus::Ongoing),
        }
    }
}

struct IndexerActor {
    rx: mpsc::Receiver<IndexerMessage>,
    db: Arc<Database>,
    lila: Lila,
}

impl IndexerActor {
    async fn run(mut self) {
        while let Some(msg) = self.rx.recv().await {
            match msg {
                IndexerMessage::IndexPlayer { callback, player } => {
                    callback
                        .send(self.index_player(player).await)
                        .nevermind("requester gone away");
                }
            }
        }
    }

    async fn index_player(&self, player: UserName) -> Result<(), Error> {
        log::info!("starting to index {}", player);

        let hash = ByColor::new_with(|color| {
            PersonalKeyBuilder::with_user_pov(&player.to_owned().into(), color)
        });

        let mut num_games = 0;
        let mut games = self.lila.user_games(&player).await?;
        while let Some(game) = games.next().await {
            let game = game?;
            num_games += 1;
            self.index_game(&player, &hash, game);
        }

        log::info!("indexed {} games for {}", num_games, player);
        Ok(())
    }

    fn index_game(&self, player: &UserName, hash: &ByColor<PersonalKeyBuilder>, game: Game) {
        if game.status.is_unindexable() || game.status.is_ongoing() {
            return;
        }

        let color = if Some(player) == game.user_name(Color::White) {
            Color::White
        } else if Some(player) == game.user_name(Color::Black) {
            Color::Black
        } else {
            return;
        };

        let year = AnnoLichess::from_time(game.last_move_at);
        let outcome = Outcome::from_winner(game.winner);
        let variant = game.variant.into();
        let pos = match game.initial_fen {
            Some(fen) => VariantPosition::from_setup(variant, &fen, CastlingMode::Chess960),
            None => Ok(VariantPosition::new(variant)),
        };

        let mut pos: Zobrist<_, u128> = match pos {
            Ok(pos) => Zobrist::new(pos),
            Err(err) => {
                log::warn!("not indexing {}: {}", game.id, err);
                return;
            }
        };

        // Build an intermediate table to remove loops (due to repetitions).
        let mut table: FxHashMap<u128, Uci> =
            FxHashMap::with_capacity_and_hasher(game.moves.len(), Default::default());

        for (ply, san) in game.moves.into_iter().enumerate() {
            let m = match san.to_move(&pos) {
                Ok(m) => m,
                Err(err) => {
                    log::error!("not indexing {}: {} ({} at ply {})", game.id, err, san, ply);
                    return;
                }
            };

            let uci = m.to_uci(CastlingMode::Chess960);
            table.insert(pos.zobrist_hash(), uci);

            pos.play_unchecked(&m);
        }

        let queryable = self.db.queryable();

        for (zobrist, uci) in table {
            let entry = PersonalEntry::new_single(
                uci.clone(),
                game.speed,
                Mode::from_rated(game.rated),
                game.id,
                outcome,
            );

            let mut buf = Cursor::new(Vec::new());
            entry.write(&mut buf).expect("serialize personal entry");

            queryable
                .db
                .put_cf(
                    queryable.cf_personal,
                    hash.by_color(color)
                        .with_zobrist(variant, zobrist)
                        .with_year(year),
                    buf.into_inner(),
                )
                .expect("merge cf personal");
        }
    }
}

enum IndexerMessage {
    IndexPlayer {
        player: UserName,
        callback: oneshot::Sender<Result<(), Error>>,
    },
}

pub enum IndexerStatus {
    Ongoing,
    Completed,
    Failed,
}
<|endoftext|>


<commit_before>//! An interpreter implementation.

/// Instructions.
#[derive(PartialEq)]
pub enum Op {
    /// Treats the next instruction as a function call.
    Call,
    /// Treats the next instruction as argument path.
    Path,
    /// Treats the next instruction as function path.
    FnPath,
    /// A function reference.
    FnRef(usize),
    /// A return reference.
    RetRef(usize),
}

/// Evaluates a program.
pub fn eval(fns: &[Op], rets: &[Op], ops: &[Op], st: &mut Vec<Op>) {

}
<commit_msg>Prepare `not` unit test for interpreter<commit_after>//! An interpreter implementation.

/// Instructions.
#[derive(PartialEq, Debug)]
pub enum Op {
    /// Treats the next instruction as a function call.
    Call,
    /// Treats the next instruction as argument path.
    Path,
    /// Treats the next instruction as function path.
    FnPath,
    /// A function reference.
    FnRef(usize),
    /// An instruction reference.
    OpRef(usize),
    /// End of instructions.
    End,
}

/// Evaluates a program.
pub fn eval(fns: &[Op], ops: &[Op], st: &mut Vec<Op>, calls: &mut Vec<usize>) {

}

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

    #[test]
    fn not() {
        let fns = vec![
            // bool,
            FnRef(0),                   // 0: bool
            End,
            // false,
            FnRef(2),                   // 2: false
            End,
            // true,
            FnRef(4),                   // 4: true
            End,
            // not(bool) -> bool
            FnRef(6),                   // 6: not
            FnRef(0),                   // 7: bool,
            OpRef(1),                   // 8: -> bool
            // not([true] true) -> [false] false
            FnRef(6),                   // 9: not
            Path,
            FnRef(4),                   // 11: true
            FnRef(4),                   // 12: true
            OpRef(5),                   // 13: -> [false] false,
        ];

        let ops = vec![
            // bool
            End,
            FnRef(0),                   // 1: bool
            // [false] false
            End,
            Path,
            FnRef(2),                   // 4: false
            FnRef(2),                   // 5: false
            // call not([true] true)
            End,
            Call,
            FnRef(6),                   // 8: not
            Path,
            FnRef(4),                   // 10: true
            FnRef(4),                   // 11: true
        ];

        let mut stack = vec![];
        let mut calls = vec![];

        eval(&fns, &ops, &mut stack, &mut calls);

        assert_eq!(&stack, &[
        ]);
    }
}
<|endoftext|>