<commit_before>extern crate momms;
extern crate core;
extern crate typenum;
extern crate hwloc;
extern crate libc;

use std::time::{Instant};
use typenum::{U1};

pub use momms::matrix::{Scalar, Mat, ColumnPanelMatrix, RowPanelMatrix, Matrix,
                        Subcomputation};
pub use momms::composables::{GemmNode, AlgorithmStep, PartM, PartN, PartK, PackA, PackB,
                             ForceB, TripleLoop};
pub use momms::kern::{Ukernel, KernelNM};
pub use momms::util;
pub use momms::thread_comm::ThreadInfo;
fn test_d_eq_a_b_c<T:Scalar, At: Mat<T>, Bt: Mat<T>,
                   Ct: Mat<T>, Dt: Mat<T>>(a: &mut At, b: &mut Bt, c: &mut Ct, d: &mut Dt) -> T {
    let mut ref_gemm : TripleLoop = TripleLoop{};

    let m = d.height();
    let n = c.width();
    let l = b.width();
    let k = a.width();

    let mut w: Matrix<T> = Matrix::new(n, 1);
    let mut cw: Matrix<T> = Matrix::new(l, 1);
    let mut bcw: Matrix<T> = Matrix::new(k, 1);
    let mut abcw: Matrix<T> = Matrix::new(m, 1);
    let mut dw: Matrix<T> = Matrix::new(m, 1);
    w.fill_rand();
    dw.fill_zero();
    cw.fill_zero();
    bcw.fill_zero();
    abcw.fill_zero();

    //Do cw = Cw, then, bcw = B * (Cw), then abcw = A * (B * (Cw))
    unsafe {
        ref_gemm.run(c, &mut w, &mut cw, &ThreadInfo::single_thread() );
        ref_gemm.run(b, &mut cw, &mut bcw, &ThreadInfo::single_thread() );
        ref_gemm.run(a, &mut bcw, &mut abcw, &ThreadInfo::single_thread() );
    }

    //Do dw = Dw
    unsafe {
        ref_gemm.run(d, &mut w, &mut dw, &ThreadInfo::single_thread() );
    }

    //Dw -= abcw
    dw.axpy(T::zero() - T::one(), &abcw);
    dw.frosqr()
}

fn gflops_ab(m: usize, n: usize, k: usize, l: usize, seconds: f64) -> f64 {
    let nflops = (m * k * l + m * l * n) as f64;
    2.0 * nflops / seconds / 1E9
}

fn gflops_bc(m: usize, n: usize, k: usize, l: usize, seconds: f64) -> f64 {
    let nflops = (k * l * n + m * k * n) as f64;
    2.0 * nflops / seconds / 1E9
}

fn flush_cache(arr: &mut Vec<f64> ) {
    for i in (arr).iter_mut() {
        *i += 1.0;
    }
}

fn test_gemm3() {
    use typenum::{UInt, UTerm, B0, Unsigned};
    type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
    type Nc = U3000;
    type Kc = typenum::U192;
    type Mc = typenum::U120;
    type Mr = typenum::U4;
    type Nr = typenum::U12;

    type Goto<T: Scalar, MTA: Mat<T>, MTB: Mat<T>, MTC: Mat<T>> =
          PartN<T, MTA, MTB, MTC, Nc,
          PartK<T, MTA, MTB, MTC, Kc,
          PackB<T, MTA, MTB, MTC, ColumnPanelMatrix<T, Nr>,
          PartM<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, Mc,
          PackA<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, RowPanelMatrix<T,Mr>,
          KernelNM<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, Mr>>>>>>;

    type GotoPrime = Goto<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
    type GotoChainedSub = Subcomputation<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
    type GotoChained = ForceB<f64, Matrix<f64>,
                              Matrix<f64>, Matrix<f64>, Matrix<f64>,
                              Matrix<f64>, GotoPrime, GotoPrime>;

    type RootS3 = typenum::U768;
    type McL2 = typenum::U120;
    type ColPM<T: Scalar> = ColumnPanelMatrix<T, Nr>;
    type RowPM<T: Scalar> = RowPanelMatrix<T, Mr>;

    type L3CNc = typenum::U624;
    type L3CKc = typenum::U156;
    //Resident C algorithm, inner loops
    type L3Ci<T: Scalar, MTA: Mat<T>, MTB: Mat<T>, MTC: Mat<T>> =
          PartK<T, MTA, MTB, MTC, L3CKc,
          PackB<T, MTA, MTB, MTC, ColPM<T>,
          PartM<T, MTA, ColPM<T>, MTC, L3CKc,
          PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
          KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>;

    type L3CiSub<T> = Subcomputation<T, Matrix<T>, Matrix<T>, ColPM<T>>;

    type L3Bo<T: Scalar, MTA: Mat<T>, MTAi: Mat<T>, MTBi: Mat<T>, MTC: Mat<T>>
        = PartN<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CNc,
          PartK<T, MTA, Subcomputation<T, MTAi, MTBi, ColPM<T>>, MTC, L3CNc, // Also the Mc of that algorithm, and outer k -> inner m
          ForceB<T, MTA, MTAi, MTBi, ColPM<T>, MTC,
                 L3Ci<T, MTAi, MTBi, ColPM<T>>,
          PartM<T, MTA, ColPM<T>, MTC, McL2,
          PartK<T, MTA, ColPM<T>, MTC, Kc,
          PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
          KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>>;

    let mut chained = <L3Bo<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>, Matrix<f64>>>::new();
    let mut goto: GotoChained = GotoChained::new();

    let flusher_len = 32*1024*1024; //256MB
    let mut flusher: Vec<f64> = Vec::with_capacity(flusher_len);
    for _ in 0..flusher_len {
        flusher.push(0.0);
    }

    for index in 1..64 {
        let mut best_time: f64 = 9999999999.0;
        let mut best_time_stock: f64 = 9999999999.0;
        let mut worst_err: f64 = 0.0;
        let size = index * 16;
        let (m, n, k, l) = (size, size, size, size);

        let n_reps = 5;
        for _ in 0..n_reps {
            let mut a: Matrix<f64> = Matrix::new(m, k);
            let mut b: Matrix<f64> = Matrix::new(k, l);
            let mut c: Matrix<f64> = Matrix::new(l, n);
            let mut d: Matrix<f64> = Matrix::new_row_major(m, n);
            a.fill_rand(); b.fill_rand(); c.fill_rand(); d.fill_zero();
            let tmp: ColPM<f64> = ColumnPanelMatrix::new(L3CKc::to_usize(), L3CKc::to_usize());
            let mut submat: L3CiSub<f64> = Subcomputation::new(b, c, tmp);
            submat.set_scalar(0.0);
            flush_cache(&mut flusher);

            let start = Instant::now();
            unsafe {
                chained.run(&mut a, &mut submat, &mut d, &ThreadInfo::single_thread());
            }
            best_time = best_time.min(util::dur_seconds(start));
            let err = test_d_eq_a_b_c(&mut a, &mut submat.a, &mut submat.b, &mut d);
            worst_err = worst_err.max(err);

            let tmp: Matrix<f64> = Matrix::new_row_major(k, n);
            let mut submat: GotoChainedSub = submat.set_c(tmp); // drops old tmp
            submat.set_scalar(0.0);
            flush_cache(&mut flusher);

            let start = Instant::now();
            unsafe {
                goto.run(&mut a, &mut submat, &mut d, &ThreadInfo::single_thread());
            }
            best_time_stock = best_time_stock.min(util::dur_seconds(start));
            ::std::mem::drop(submat);
        }
        println!("{}\t{}\t{}\t{}\t{}\t{}\t{:e}",
                 m, n, k, l,
                 gflops_bc(m,n,k,l,best_time),
                 gflops_bc(m,n,k,l,best_time_stock),
                 worst_err.sqrt());
    }
    let sum: f64 = flusher.iter().sum();
    println!("Flush value {}", sum);
}
fn main() {
    test_gemm3();
}
<commit_msg>Working, but way underperforming, algorithm<commit_after>extern crate momms;
extern crate core;
extern crate typenum;
extern crate hwloc;
extern crate libc;

use std::time::{Instant};
use typenum::{U1};

pub use momms::matrix::{Scalar, Mat, ColumnPanelMatrix, RowPanelMatrix, Matrix,
                        Subcomputation};
pub use momms::composables::{GemmNode, AlgorithmStep, PartM, PartN, PartK, PackA, PackB,
                             ForceB, TripleLoop};
pub use momms::kern::{Ukernel, KernelNM};
pub use momms::util;
pub use momms::thread_comm::ThreadInfo;

use std::cmp::min;

fn test_d_eq_a_b_c<T:Scalar, At: Mat<T>, Bt: Mat<T>,
                   Ct: Mat<T>, Dt: Mat<T>>(a: &mut At, b: &mut Bt, c: &mut Ct, d: &mut Dt) -> T {
    let mut ref_gemm : TripleLoop = TripleLoop{};

    let m = d.height();
    let n = c.width();
    let l = b.width();
    let k = a.width();

    let mut w: Matrix<T> = Matrix::new(n, 1);
    let mut cw: Matrix<T> = Matrix::new(l, 1);
    let mut bcw: Matrix<T> = Matrix::new(k, 1);
    let mut abcw: Matrix<T> = Matrix::new(m, 1);
    let mut dw: Matrix<T> = Matrix::new(m, 1);
    w.fill_rand();
    dw.fill_zero();
    cw.fill_zero();
    bcw.fill_zero();
    abcw.fill_zero();

    //Do cw = Cw, then, bcw = B * (Cw), then abcw = A * (B * (Cw))
    unsafe {
        ref_gemm.run(c, &mut w, &mut cw, &ThreadInfo::single_thread() );
        ref_gemm.run(b, &mut cw, &mut bcw, &ThreadInfo::single_thread() );
        ref_gemm.run(a, &mut bcw, &mut abcw, &ThreadInfo::single_thread() );
    }

    //Do dw = Dw
    unsafe {
        ref_gemm.run(d, &mut w, &mut dw, &ThreadInfo::single_thread() );
    }

    //Dw -= abcw
    dw.axpy(T::zero() - T::one(), &abcw);
    dw.frosqr()
}

fn gflops_ab(m: usize, n: usize, k: usize, l: usize, seconds: f64) -> f64 {
    let nflops = (m * k * l + m * l * n) as f64;
    2.0 * nflops / seconds / 1E9
}

fn gflops_bc(m: usize, n: usize, k: usize, l: usize, seconds: f64) -> f64 {
    let nflops = (k * l * n + m * k * n) as f64;
    2.0 * nflops / seconds / 1E9
}

fn flush_cache(arr: &mut Vec<f64> ) {
    for i in (arr).iter_mut() {
        *i += 1.0;
    }
}

fn test_gemm3() {
    use typenum::{UInt, UTerm, B0, Unsigned};
    type U3000 = UInt<UInt<typenum::U750, B0>, B0>;
    type Nc = U3000;
    type Kc = typenum::U192;
    type Mc = typenum::U120;
    type Mr = typenum::U4;
    type Nr = typenum::U12;

    type Goto<T: Scalar, MTA: Mat<T>, MTB: Mat<T>, MTC: Mat<T>> =
          PartN<T, MTA, MTB, MTC, Nc,
          PartK<T, MTA, MTB, MTC, Kc,
          PackB<T, MTA, MTB, MTC, ColumnPanelMatrix<T, Nr>,
          PartM<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, Mc,
          PackA<T, MTA, ColumnPanelMatrix<T,Nr>, MTC, RowPanelMatrix<T,Mr>,
          KernelNM<T, RowPanelMatrix<T,Mr>, ColumnPanelMatrix<T,Nr>, MTC, Nr, Mr>>>>>>;

    type GotoPrime = Goto<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
    type GotoChainedSub = Subcomputation<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>>;
    type GotoChained = ForceB<f64, Matrix<f64>,
                              Matrix<f64>, Matrix<f64>, Matrix<f64>,
                              Matrix<f64>, GotoPrime, GotoPrime>;

    type RootS3 = typenum::U768;
    type McL2 = typenum::U120;
    type ColPM<T: Scalar> = ColumnPanelMatrix<T, Nr>;
    type RowPM<T: Scalar> = RowPanelMatrix<T, Mr>;

    type L3CNc = typenum::U624;
    type L3CKc = typenum::U156;
    //Resident C algorithm, inner loops
    type L3Ci<T: Scalar, MTA: Mat<T>, MTB: Mat<T>, MTC: Mat<T>> =
          PartK<T, MTA, MTB, MTC, L3CKc,
          PackB<T, MTA, MTB, MTC, ColPM<T>,
          PartM<T, MTA, ColPM<T>, MTC, L3CKc,
          PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
          KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>;

    type L3CiSub<T> = Subcomputation<T, Matrix<T>, Matrix<T>, ColPM<T>>;

    type L3Bo<T: Scalar, MTA: Mat<T>, MTAi: Mat<T>, MTBi: Mat<T>, MTC: Mat<T>>
        = PartN<T, MTA, Subcomputation<T, MTAi, MTBi, Matrix<T>>, MTC, L3CNc,
          PartK<T, MTA, Subcomputation<T, MTAi, MTBi, Matrix<T>>, MTC, L3CNc, // Also the Mc of that algorithm, and outer k -> inner m
          ForceB<T, MTA, MTAi, MTBi, Matrix<T>, MTC,
                    L3Ci<T, MTAi, MTBi, Matrix<T>>,
          PackB<T, MTA, Matrix<T>, MTC, ColPM<T>,
          // ForceB<T, MTA, MTAi, MTBi, ColPM<T>, MTC,
          //        L3Ci<T, MTAi, MTBi, ColPM<T>>,
          PartM<T, MTA, ColPM<T>, MTC, McL2,
          PartK<T, MTA, ColPM<T>, MTC, Kc,
          PackA<T, MTA, ColPM<T>, MTC, RowPM<T>,
          KernelNM<T, RowPM<T>, ColPM<T>, MTC, Nr, Mr>>>>>>>>;

    let mut chained = <L3Bo<f64, Matrix<f64>, Matrix<f64>, Matrix<f64>, Matrix<f64>>>::new();
    let mut goto: GotoChained = GotoChained::new();

    let flusher_len = 32*1024*1024; //256MB
    let mut flusher: Vec<f64> = Vec::with_capacity(flusher_len);
    for _ in 0..flusher_len {
        flusher.push(0.0);
    }

    for index in 1..64 {
        let mut best_time: f64 = 9999999999.0;
        let mut best_time_stock: f64 = 9999999999.0;
        let mut worst_err: f64 = 0.0;
        let size = index * 16;
        let (m, n, k, l) = (size, size, size, size);

        let n_reps = 5;
        for _ in 0..n_reps {
            let mut a: Matrix<f64> = Matrix::new(m, k);
            let mut b: Matrix<f64> = Matrix::new(k, l);
            let mut c: Matrix<f64> = Matrix::new(l, n);
            let mut d: Matrix<f64> = Matrix::new_row_major(m, n);
            a.fill_rand(); b.fill_rand(); c.fill_rand(); d.fill_zero();
            let mut tmp: Matrix<f64> = Matrix::new_row_major(min(k, L3CNc::to_usize()), min(n, L3CNc::to_usize()));
//            let mut tmp: ColPM<f64> = ColumnPanelMatrix::new(L3CNc::to_usize(), L3CNc::to_usize());
            tmp.fill_zero();
            let mut submat = Subcomputation::new(b, c, tmp);
//            let mut submat: L3CiSub<f64> = Subcomputation::new(b, c, tmp);
            submat.set_scalar(0.0);
            flush_cache(&mut flusher);

            let start = Instant::now();
            unsafe {
                chained.run(&mut a, &mut submat, &mut d, &ThreadInfo::single_thread());
            }
            best_time = best_time.min(util::dur_seconds(start));
            let err = test_d_eq_a_b_c(&mut a, &mut submat.a, &mut submat.b, &mut d);
            worst_err = worst_err.max(err);

            let tmp: Matrix<f64> = Matrix::new_row_major(k, n);
            let mut submat: GotoChainedSub = submat.set_c(tmp); // drops old tmp
            submat.set_scalar(0.0);
            flush_cache(&mut flusher);

            let start = Instant::now();
            unsafe {
                goto.run(&mut a, &mut submat, &mut d, &ThreadInfo::single_thread());
            }
            best_time_stock = best_time_stock.min(util::dur_seconds(start));
            ::std::mem::drop(submat);
        }
        println!("{}\t{}\t{}\t{}\t{}\t{}\t{:e}",
                 m, n, k, l,
                 gflops_bc(m,n,k,l,best_time),
                 gflops_bc(m,n,k,l,best_time_stock),
                 worst_err.sqrt());
    }
    let sum: f64 = flusher.iter().sum();
    println!("Flush value {}", sum);
}
fn main() {
    test_gemm3();
}
<|endoftext|>


<commit_before>macro_rules! struct_events {
  (
    keyboard: { $( $k_alias:ident : $k_sdl:ident ),* },
    else: { $( $e_alias:ident : $e_sdl:pat ),* }
    )
  => {
    use sdl2::EventPump;

    pub struct ImmediateEvents {
      resize: Option<(u32, u32)>,
      $( pub $k_alias : Option<bool> , )*
      $( pub $e_alias : bool ),*
    }

    impl ImmediateEvents {
      pub fn new() -> ImmediateEvents {
        ImmediateEvents {
          resize: None,
          $( $k_alias: None , )*
          $( $e_alias: false ),*
        }
      }
    }

    pub struct Events {
      pump: EventPump,
      pub now: ImmediateEvents,

      $( pub $k_alias: bool ),*
    }

    impl Events {
      pub fn new(pump: EventPump) -> Events {
        Events {
          pump: pump,
          now: ImmediateEvents::new(),

          $( $k_alias: false ),*
        }
      }

      pub fn pump(&mut self, renderer: &mut ::sdl2::render::Renderer) {
        self.now = ImmediateEvents::new();

        for event in self.pump.poll_iter() {
          use sdl2::event::Event::*;
          use sdl2::event::WindowEventId::Resized;
          use sdl2::keyboard::Keycode::*;

          match event {
            Window { win_event_id: Resized, .. } => {
              self.now.resize = Some(renderer.output_size().unwrap());
            },

            MouseButtonDown {x: xCoord, y: yCoord, ..} => {
              println!("Mouse click {} {}", xCoord, yCoord)
            },

            KeyDown { keycode, .. } => match keycode {
              $(
                Some($k_sdl) => {
                  if !self.$k_alias {
                    self.now.$k_alias = Some(true);
                  }

                  self.$k_alias = true;
                }
                ),*
              _ => {}
            },

            KeyUp { keycode, .. } => match keycode {
              $(
                Some($k_sdl) => {
                  self.now.$k_alias = Some(false);
                  self.$k_alias = false;
                }
                ),*
              _ => {}
            },

            $(
              $e_sdl => {
                self.now.$e_alias = true;
              }
              )*,

            _ => {}
          }
        }
      }
    }
  }
}
<commit_msg>Add mouse up event and add mouse events to ImmediateEvents struct<commit_after>macro_rules! struct_events {
  (
    keyboard: { $( $k_alias:ident : $k_sdl:ident ),* },
    else: { $( $e_alias:ident : $e_sdl:pat ),* }
    )
  => {
    use sdl2::EventPump;

    pub struct ImmediateEvents {
      resize: Option<(u32, u32)>,
      mouse1: Option<(i32, i32)>,
      $( pub $k_alias : Option<bool> , )*
      $( pub $e_alias : bool ),*
    }

    impl ImmediateEvents {
      pub fn new() -> ImmediateEvents {
        ImmediateEvents {
          resize: None,
          mouse1: None,
          $( $k_alias: None , )*
          $( $e_alias: false ),*
        }
      }
    }

    pub struct Events {
      pump: EventPump,
      pub now: ImmediateEvents,

      $( pub $k_alias: bool ),*
    }

    impl Events {
      pub fn new(pump: EventPump) -> Events {
        Events {
          pump: pump,
          now: ImmediateEvents::new(),

          $( $k_alias: false ),*
        }
      }

      pub fn pump(&mut self, renderer: &mut ::sdl2::render::Renderer) {
        self.now = ImmediateEvents::new();

        for event in self.pump.poll_iter() {
          use sdl2::event::Event::*;
          use sdl2::event::WindowEventId::Resized;
          use sdl2::keyboard::Keycode::*;

          match event {
            Window { win_event_id: Resized, .. } => {
              self.now.resize = Some(renderer.output_size().unwrap());
            },

            MouseButtonDown {x: xCoord, y: yCoord, ..} => {
              self.now.mouse1 = Some((xCoord, yCoord));
              println!("Mouse DOWN at {} {}", xCoord, yCoord);
            },

            MouseButtonUp {x: xCoord, y: yCoord, ..} => {
              self.now.mouse1 = None;
              println!("Mouse UP at {} {}", xCoord, yCoord);
            },

            KeyDown { keycode, .. } => match keycode {
              $(
                Some($k_sdl) => {
                  if !self.$k_alias {
                    self.now.$k_alias = Some(true);
                  }

                  self.$k_alias = true;
                }
                ),*
              _ => {}
            },

            KeyUp { keycode, .. } => match keycode {
              $(
                Some($k_sdl) => {
                  self.now.$k_alias = Some(false);
                  self.$k_alias = false;
                }
                ),*
              _ => {}
            },

            $(
              $e_sdl => {
                self.now.$e_alias = true;
              }
              )*,

            _ => {}
          }
        }
      }
    }
  }
}
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Texture creation and modification.
//!
//! "Texture" is an overloaded term. In gfx-rs, a texture consists of two
//! separate pieces of information: image storage description (which is
//! immutable for a single texture object), and image data. To actually use a
//! texture, a "sampler" is needed, which provides a way of accessing the
//! texture data.

use std::default::Default;

/// How to [filter](https://en.wikipedia.org/wiki/Texture_filtering) the
/// texture when sampling. They correspond to increasing levels of quality,
/// but also cost. They "layer" on top of each other: it is not possible to
/// have bilinear filtering without mipmapping, for example.
///
/// These names are somewhat poor, in that "bilinear" is really just doing
/// linear filtering on each axis, and it is only bilinear in the case of 2D
/// textures. Similarly for trilinear, it is really Quadralinear(?) for 3D
/// textures. Alas, these names are simple, and match certain intuitions
/// ingrained by many years of public use of inaccurate terminology.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum FilterMethod {
    /// The dumbest filtering possible, nearest-neighbor interpolation.
    Scale,
    /// Add simple mipmapping.
    Mipmap,
    /// Sample multiple texels within a single mipmap level to increase
    /// quality.
    Bilinear,
    /// Sample multiple texels across two mipmap levels to increase quality.
    Trilinear,
    /// Anisotropic filtering with a given "max", must be between 1 and 16,
    /// inclusive.
    Anisotropic(u8)
}

/// Specifies how a given texture may be used. The available texture types are restricted by what
/// Metal exposes, though this could conceivably be extended in the future. Note that a single
/// texture can *only* ever be of one kind. A texture created as `Texture2D` will forever be
/// `Texture2D`.
// TODO: "Texture views" let you get around that limitation.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureKind {
    Texture1D,
    Texture1DArray,
    Texture2D,
    Texture2DArray,
    TextureCube,
    Texture3D
    // TODO: Multisampling?
}

/// Describes the layout of each texel within a texture.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureFormat {
    RGB8,
    RGBA8,
}

/// Describes the storage of a texture.
///
/// # Portability note
///
/// Textures larger than 1024px in any dimension are unlikely to be supported by mobile platforms.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct TextureInfo {
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    /// Mipmap levels outside the range of `[lo, hi]` will never be used for
    /// this texture. Defaults to `(0, -1)`, that is, every mipmap level
    /// available. 0 is the base mipmap level, with the full-sized texture,
    /// and every level after that shrinks each dimension by a factor of 2.
    pub mipmap_range: (u8, u8),
    pub kind: TextureKind,
    pub format: TextureFormat,
}

/// Describes a subvolume of a texture, which image data can be uploaded into.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct ImageInfo {
    pub xoffset: u16,
    pub yoffset: u16,
    pub zoffset: u16,
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    pub format: TextureFormat,
    /// Which mipmap to select.
    pub mipmap: u8,
}

impl Default for ImageInfo {
    fn default() -> ImageInfo {
        ImageInfo {
            xoffset: 0,
            yoffset: 0,
            zoffset: 0,
            width: 0,
            height: 1,
            depth: 1,
            format: RGBA8,
            mipmap: 0
        }
    }
}

impl Default for TextureInfo {
    fn default() -> TextureInfo {
        TextureInfo {
            width: 0,
            height: 1,
            depth: 1,
            mipmap_range: (0, -1),
            kind: Texture2D,
            format: RGBA8,
        }
    }
}

impl TextureInfo { pub fn new() -> TextureInfo { Default::default() } }
impl ImageInfo { pub fn new() -> ImageInfo { Default::default() } }

/// Specifies how texture coordinates outside the range `[0, 1]` are handled.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum WrapMode {
    /// Tile the texture. That is, sample the coordinate modulo `1.0`. This is
    /// the default.
    Tile,
    /// Mirror the texture. Like tile, but uses abs(coord) before the modulo.
    Mirror,
    /// Clamp the texture to the value at `0.0` or `1.0` respectively.
    Clamp,
}

/// Specifies how to sample from a texture.
#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct SamplerInfo {
    pub filtering: FilterMethod,
    /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL
    /// speak)
    pub wrap_mode: (WrapMode, WrapMode, WrapMode),
    /// This bias is added to every computed mipmap level (N + lod_bias). For
    /// example, if it would select mipmap level 2 and lod_bias is 1, it will
    /// use mipmap level 3.
    pub lod_bias: f32,
    /// Mipmap levels outside of `[lo, hi]` will never be sampled. Defaults to
    /// `(0, -1)` (every mipmap available), but will be clamped to the
    /// texture's mipmap_range.
    pub mipmap_range: (u8, u8),
    // TODO: comparison mode
}
<commit_msg>Document texture kinds<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Texture creation and modification.
//!
//! "Texture" is an overloaded term. In gfx-rs, a texture consists of two
//! separate pieces of information: image storage description (which is
//! immutable for a single texture object), and image data. To actually use a
//! texture, a "sampler" is needed, which provides a way of accessing the
//! image data.  Image data consists of an array of "texture elements", or
//! texels.

use std::default::Default;

/// How to [filter](https://en.wikipedia.org/wiki/Texture_filtering) the
/// texture when sampling. They correspond to increasing levels of quality,
/// but also cost. They "layer" on top of each other: it is not possible to
/// have bilinear filtering without mipmapping, for example.
///
/// These names are somewhat poor, in that "bilinear" is really just doing
/// linear filtering on each axis, and it is only bilinear in the case of 2D
/// textures. Similarly for trilinear, it is really Quadralinear(?) for 3D
/// textures. Alas, these names are simple, and match certain intuitions
/// ingrained by many years of public use of inaccurate terminology.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum FilterMethod {
    /// The dumbest filtering possible, nearest-neighbor interpolation.
    Scale,
    /// Add simple mipmapping.
    Mipmap,
    /// Sample multiple texels within a single mipmap level to increase
    /// quality.
    Bilinear,
    /// Sample multiple texels across two mipmap levels to increase quality.
    Trilinear,
    /// Anisotropic filtering with a given "max", must be between 1 and 16,
    /// inclusive.
    Anisotropic(u8)
}

/// Specifies how a given texture may be used. The available texture types are restricted by what
/// Metal exposes, though this could conceivably be extended in the future. Note that a single
/// texture can *only* ever be of one kind. A texture created as `Texture2D` will forever be
/// `Texture2D`.
// TODO: "Texture views" let you get around that limitation.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureKind {
    /// A single row of texels.
    Texture1D,
    /// An array of rows of texels. Equivalent to Texture2D except that texels in a different row
    /// are not sampled.
    Texture1DArray,
    /// A traditional 2D texture, with rows arranged contiguously.
    Texture2D,
    /// An array of 2D textures. Equivalent to Texture3D except that texels in a different depth
    /// level are not sampled.
    Texture2DArray,
    /// A set of 6 2D textures, one for each face of a cube.
    // TODO: implement this, and document it better. cmr doesn't really understand them well enough
    // to explain without rambling.
    TextureCube,
    /// A volume texture, with each 2D layer arranged contiguously.
    Texture3D
    // TODO: Multisampling?
}

/// Describes the layout of each texel within a texture.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
#[repr(u8)]
pub enum TextureFormat {
    RGB8,
    RGBA8,
}

/// Describes the storage of a texture.
///
/// # Portability note
///
/// Textures larger than 1024px in any dimension are unlikely to be supported by mobile platforms.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct TextureInfo {
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    /// Mipmap levels outside the range of `[lo, hi]` will never be used for
    /// this texture. Defaults to `(0, -1)`, that is, every mipmap level
    /// available. 0 is the base mipmap level, with the full-sized texture,
    /// and every level after that shrinks each dimension by a factor of 2.
    pub mipmap_range: (u8, u8),
    pub kind: TextureKind,
    pub format: TextureFormat,
}

/// Describes a subvolume of a texture, which image data can be uploaded into.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub struct ImageInfo {
    pub xoffset: u16,
    pub yoffset: u16,
    pub zoffset: u16,
    pub width: u16,
    pub height: u16,
    pub depth: u16,
    /// Format of each texel.
    pub format: TextureFormat,
    /// Which mipmap to select.
    pub mipmap: u8,
}

impl Default for ImageInfo {
    fn default() -> ImageInfo {
        ImageInfo {
            xoffset: 0,
            yoffset: 0,
            zoffset: 0,
            width: 0,
            height: 1,
            depth: 1,
            format: RGBA8,
            mipmap: 0
        }
    }
}

impl Default for TextureInfo {
    fn default() -> TextureInfo {
        TextureInfo {
            width: 0,
            height: 1,
            depth: 1,
            mipmap_range: (0, -1),
            kind: Texture2D,
            format: RGBA8,
        }
    }
}

impl TextureInfo { pub fn new() -> TextureInfo { Default::default() } }
impl ImageInfo { pub fn new() -> ImageInfo { Default::default() } }

/// Specifies how texture coordinates outside the range `[0, 1]` are handled.
#[deriving(Eq, Ord, PartialEq, PartialOrd, Hash, Clone, Show)]
pub enum WrapMode {
    /// Tile the texture. That is, sample the coordinate modulo `1.0`. This is
    /// the default.
    Tile,
    /// Mirror the texture. Like tile, but uses abs(coord) before the modulo.
    Mirror,
    /// Clamp the texture to the value at `0.0` or `1.0` respectively.
    Clamp,
}

/// Specifies how to sample from a texture.
// TODO: document the details of sampling.
#[deriving(PartialEq, PartialOrd, Clone, Show)]
pub struct SamplerInfo {
    pub filtering: FilterMethod,
    /// Wrapping mode for each of the U, V, and W axis (S, T, and R in OpenGL
    /// speak)
    pub wrap_mode: (WrapMode, WrapMode, WrapMode),
    /// This bias is added to every computed mipmap level (N + lod_bias). For
    /// example, if it would select mipmap level 2 and lod_bias is 1, it will
    /// use mipmap level 3.
    pub lod_bias: f32,
    /// Mipmap levels outside of `[lo, hi]` will never be sampled. Defaults to
    /// `(0, -1)` (every mipmap available), but will be clamped to the
    /// texture's mipmap_range.
    pub mipmap_range: (u8, u8),
    // TODO: comparison mode
}
<|endoftext|>


<commit_before>// TODO: get num cols of terminal dynamically
// TODO: care about the given print options

use super::{Report, ReportKind, RemarkKind};
use code::{FileMap, LineIdx};
use term_painter::ToStyle;
use term_painter::Color::*;
use std::default::Default;

/// Options for printing on the terminal. By `default()` everything is enabled.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PrintOptions {
    /// Use of unicode allowed?
    pub unicode: bool,
    /// Use of colors allowed?
    pub color: bool,
    /// Is line wrapping allowed?
    pub line_wrap: bool,
}

impl Default for PrintOptions {
    fn default() -> Self {
        PrintOptions {
            unicode: true,
            color: true,
            line_wrap: true,
        }
    }
}

/// Pretty prints a report
///
/// **Note**: right now, the `PrintOptions` are ignored.
pub fn print(rep: &Report, src: &FileMap, _: PrintOptions) {
    trace!("Printing report: {:#?}", rep);
    trace!("Printing with filemap: {:#?}", src);

    // print header
    let title = match rep.kind {
        ReportKind::Error => White.bold().bg(Red).paint("ERROR"),
        ReportKind::Warning => White.bold().bg(Yellow).paint("WARNING"),
    };

    let line = if rep.span.is_dummy() {
        "<dummy-span>".into()
    } else {
        let start = src.get_loc(rep.span.lo);
        let end = src.get_loc(rep.span.hi);
        trace!("Span is from {:?} to {:?}", start, end);

        if start.line != end.line {
            format!("{}-{}", start.line, end.line)
        } else {
            start.line.to_string()
        }
    };

    println!("+---- {} in {} : {} ----+",
        title,
        src.filename(),
        Magenta.bold().paint(line)
    );

    for rem in &rep.remarks {
        trace!("Handling Remark {:?}", rem);

        // print message
        let (title, title_len) = match rem.kind {
            RemarkKind::Error => (Red.paint("error:"), 6),
            RemarkKind::Warning => (Yellow.paint("warning:"), 8),
            RemarkKind::Note => (Green.paint("note:"), 5),
        };

        print!("      =====>  {} ", title);
        // spaces + big arrow + spaces + title + space
        let indent = 6 + 6 + 2 + title_len + 1;
        let block_width = 80 - indent;

        let mut col = 0;
        for word in rem.desc.split_whitespace() {
            let word_len = word.chars().count();
            if col + word_len >= block_width && col != 0 {
                println!("");
                print!("           >  {0:>1$} ", " ", title_len);
                col = 0;
            }
            print!("{} ", White.bold().paint(word));
            col += word_len + 1;
        }
        println!("");

        // print code snippet
        if let Some(span) = rem.span {
            let start = src.get_loc(span.lo);
            let end = src.get_loc(span.hi);
            trace!("Span is from {:?} to {:?}", start, end);

            if span.is_dummy() {
                println!("!!! no snippet due to <dummy-span> !!!");
            } else if start.line == end.line {
                if let Some(line_orig) = src.get_line(start.line) {
                    trace!("Printing single line span. Line: {:?}", line_orig);
                    // replace tabs
                    let line = line_orig.replace("\t", "    ");
                    let num_tabs = line_orig[..start.col.0 as usize]
                        .chars()
                        .filter(|&c| c == '\t')
                        .count();

                    // print line (with marked span section)
                    let startcol = start.col.0 as usize + 3*num_tabs;
                    let endcol = end.col.0 as usize + 3*num_tabs;
                    println!("{:>#4} {} {}{}{}",
                        Magenta.bold().paint(start.line),
                        Magenta.bold().paint("|"),
                        &line[..startcol],
                        Yellow.paint(&line[startcol..endcol]),
                        &line[endcol..],
                    );

                    Yellow.with(|| {
                        println!("       {: <2$}{:-<3$}",
                            " ", "^",
                            startcol,
                            endcol - startcol,
                        );
                    });
                }
            } else {
                for line_idx in start.line.0..end.line.0 + 1 {
                    let line_idx = LineIdx(line_idx);
                    if let Some(line) = src.get_line(line_idx) {
                        println!("{:>#4} {} {}",
                            Magenta.bold().paint(line_idx),
                            Magenta.bold().paint("|"),
                            line
                        );
                    }
                }
            }
            println!("");
        }

    }
    println!("");
}
<commit_msg>Modify underline style when pretty printing reports<commit_after>// TODO: get num cols of terminal dynamically
// TODO: care about the given print options

use super::{Report, ReportKind, RemarkKind};
use code::{FileMap, LineIdx};
use term_painter::ToStyle;
use term_painter::Color::*;
use std::default::Default;

/// Options for printing on the terminal. By `default()` everything is enabled.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PrintOptions {
    /// Use of unicode allowed?
    pub unicode: bool,
    /// Use of colors allowed?
    pub color: bool,
    /// Is line wrapping allowed?
    pub line_wrap: bool,
}

impl Default for PrintOptions {
    fn default() -> Self {
        PrintOptions {
            unicode: true,
            color: true,
            line_wrap: true,
        }
    }
}

/// Pretty prints a report
///
/// **Note**: right now, the `PrintOptions` are ignored.
pub fn print(rep: &Report, src: &FileMap, _: PrintOptions) {
    trace!("Printing report: {:#?}", rep);
    trace!("Printing with filemap: {:#?}", src);

    // print header
    let title = match rep.kind {
        ReportKind::Error => White.bold().bg(Red).paint("ERROR"),
        ReportKind::Warning => White.bold().bg(Yellow).paint("WARNING"),
    };

    let line = if rep.span.is_dummy() {
        "<dummy-span>".into()
    } else {
        let start = src.get_loc(rep.span.lo);
        let end = src.get_loc(rep.span.hi);
        trace!("Span is from {:?} to {:?}", start, end);

        if start.line != end.line {
            format!("{}-{}", start.line, end.line)
        } else {
            start.line.to_string()
        }
    };

    println!("+---- {} in {} : {} ----+",
        title,
        src.filename(),
        Magenta.bold().paint(line)
    );

    for rem in &rep.remarks {
        trace!("Handling Remark {:?}", rem);

        // print message
        let (title, title_len) = match rem.kind {
            RemarkKind::Error => (Red.paint("error:"), 6),
            RemarkKind::Warning => (Yellow.paint("warning:"), 8),
            RemarkKind::Note => (Green.paint("note:"), 5),
        };

        print!("      =====>  {} ", title);
        // spaces + big arrow + spaces + title + space
        let indent = 6 + 6 + 2 + title_len + 1;
        let block_width = 80 - indent;

        let mut col = 0;
        for word in rem.desc.split_whitespace() {
            let word_len = word.chars().count();
            if col + word_len >= block_width && col != 0 {
                println!("");
                print!("           >  {0:>1$} ", " ", title_len);
                col = 0;
            }
            print!("{} ", White.bold().paint(word));
            col += word_len + 1;
        }
        println!("");

        // print code snippet
        if let Some(span) = rem.span {
            let start = src.get_loc(span.lo);
            let end = src.get_loc(span.hi);
            trace!("Span is from {:?} to {:?}", start, end);

            if span.is_dummy() {
                println!("!!! no snippet due to <dummy-span> !!!");
            } else if start.line == end.line {
                if let Some(line_orig) = src.get_line(start.line) {
                    trace!("Printing single line span. Line: {:?}", line_orig);
                    // replace tabs
                    let line = line_orig.replace("\t", "    ");
                    let num_tabs = line_orig[..start.col.0 as usize]
                        .chars()
                        .filter(|&c| c == '\t')
                        .count();

                    // print line (with marked span section)
                    let startcol = start.col.0 as usize + 3*num_tabs;
                    let endcol = end.col.0 as usize + 3*num_tabs;
                    println!("{:>#4} {} {}{}{}",
                        Magenta.bold().paint(start.line),
                        Magenta.bold().paint("|"),
                        &line[..startcol],
                        Yellow.paint(&line[startcol..endcol]),
                        &line[endcol..],
                    );

                    Yellow.with(|| {
                        println!("       {: <2$}{:^<3$}",
                            " ", "^",
                            startcol,
                            endcol - startcol,
                        );
                    });
                }
            } else {
                for line_idx in start.line.0..end.line.0 + 1 {
                    let line_idx = LineIdx(line_idx);
                    if let Some(line) = src.get_line(line_idx) {
                        println!("{:>#4} {} {}",
                            Magenta.bold().paint(line_idx),
                            Magenta.bold().paint("|"),
                            line
                        );
                    }
                }
            }
            println!("");
        }

    }
    println!("");
}
<|endoftext|>


<commit_before>// TODO: get num cols of terminal dynamically

use super::{Report, ReportKind, RemarkKind};
use code::{FileMap, LineIdx};
use term_painter::ToStyle;
use term_painter::Color::*;
use std::default::Default;

/// Options for printing
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PrintOptions {
    /// Use of unicode allowed?
    pub unicode: bool,
    /// Use of colors allowed?
    pub color: bool,
    /// Is line wrapping allowed?
    pub line_wrap: bool,
}

impl Default for PrintOptions {
    fn default() -> Self {
        PrintOptions {
            unicode: true,
            color: true,
            line_wrap: true,
        }
    }
}

pub fn print(rep: &Report, src: &FileMap, _: PrintOptions) {
    // print header
    let title = match rep.kind {
        ReportKind::Error => White.bold().bg(Red).paint("ERROR"),
        ReportKind::Warning => White.bold().bg(Yellow).paint("WARNING"),
    };

    let line = if rep.span.is_dummy() {
        "<dummy-span>".into()
    } else {
        let start = src.get_loc(rep.span.lo);
        let end = src.get_loc(rep.span.hi);
        if start.line != end.line {
            format!("{}-{}", start.line, end.line)
        } else {
            start.line.to_string()
        }
    };

    println!("+---- {} in {} : {} ----+",
        title,
        src.filename(),
        Magenta.bold().paint(line)
    );

    for rem in &rep.remarks {
        // print message
        let (title, title_len) = match rem.kind {
            RemarkKind::Error => (Red.paint("error:"), 6),
            RemarkKind::Warning => (Yellow.paint("warning:"), 8),
            RemarkKind::Note => (Green.paint("note:"), 5),
        };

        print!("      =====>  {} ", title);
        // spaces + big arrow + spaces + title + space
        let indent = 6 + 6 + 2 + title_len + 1;
        let block_width = 80 - indent;

        let mut col = 0;
        for word in rem.desc.split_whitespace() {
            let word_len = word.chars().count();
            if col + word_len >= block_width && col != 0 {
                println!("");
                print!("           >  {0:>1$} ", " ", title_len);
                col = 0;
            }
            print!("{} ", White.bold().paint(word));
            col += word_len + 1;
        }
        println!("");

        // print code snippet
        if let Some(span) = rem.span {
            let start = src.get_loc(span.lo);
            let end = src.get_loc(span.hi);

            if span.is_dummy() {
                println!("!!! no snippet due to <dummy-span> !!!");
            } else if start.line == end.line {
                if let Some(line) = src.get_line(start.line) {
                    println!("{:>#4} {} {}",
                        Magenta.bold().paint(start.line),
                        Magenta.bold().paint("|"),
                        line
                    );

                    Yellow.with(|| {
                        println!("       {: <2$}{:-<3$}",
                            " ", "^",
                            start.col.0 as usize,
                            (end.col.0 - start.col.0) as usize
                        );
                    });
                }
            } else {
                for line_idx in start.line.0..end.line.0 + 1 {
                    let line_idx = LineIdx(line_idx);
                    if let Some(line) = src.get_line(line_idx) {
                        println!("{:>#4} {} {}",
                            Magenta.bold().paint(line_idx),
                            Magenta.bold().paint("|"),
                            line
                        );
                    }
                }
            }
            println!("");
        }

    }
    println!("");
}
<commit_msg>Add and improve `print` module documentation<commit_after>// TODO: get num cols of terminal dynamically
// TODO: care about the given print options

use super::{Report, ReportKind, RemarkKind};
use code::{FileMap, LineIdx};
use term_painter::ToStyle;
use term_painter::Color::*;
use std::default::Default;

/// Options for printing on the terminal. By `default()` everything is enabled.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PrintOptions {
    /// Use of unicode allowed?
    pub unicode: bool,
    /// Use of colors allowed?
    pub color: bool,
    /// Is line wrapping allowed?
    pub line_wrap: bool,
}

impl Default for PrintOptions {
    fn default() -> Self {
        PrintOptions {
            unicode: true,
            color: true,
            line_wrap: true,
        }
    }
}

/// Pretty prints a report
///
/// **Note**: right now, the `PrintOptions` are ignored.
pub fn print(rep: &Report, src: &FileMap, _: PrintOptions) {
    // print header
    let title = match rep.kind {
        ReportKind::Error => White.bold().bg(Red).paint("ERROR"),
        ReportKind::Warning => White.bold().bg(Yellow).paint("WARNING"),
    };

    let line = if rep.span.is_dummy() {
        "<dummy-span>".into()
    } else {
        let start = src.get_loc(rep.span.lo);
        let end = src.get_loc(rep.span.hi);
        if start.line != end.line {
            format!("{}-{}", start.line, end.line)
        } else {
            start.line.to_string()
        }
    };

    println!("+---- {} in {} : {} ----+",
        title,
        src.filename(),
        Magenta.bold().paint(line)
    );

    for rem in &rep.remarks {
        // print message
        let (title, title_len) = match rem.kind {
            RemarkKind::Error => (Red.paint("error:"), 6),
            RemarkKind::Warning => (Yellow.paint("warning:"), 8),
            RemarkKind::Note => (Green.paint("note:"), 5),
        };

        print!("      =====>  {} ", title);
        // spaces + big arrow + spaces + title + space
        let indent = 6 + 6 + 2 + title_len + 1;
        let block_width = 80 - indent;

        let mut col = 0;
        for word in rem.desc.split_whitespace() {
            let word_len = word.chars().count();
            if col + word_len >= block_width && col != 0 {
                println!("");
                print!("           >  {0:>1$} ", " ", title_len);
                col = 0;
            }
            print!("{} ", White.bold().paint(word));
            col += word_len + 1;
        }
        println!("");

        // print code snippet
        if let Some(span) = rem.span {
            let start = src.get_loc(span.lo);
            let end = src.get_loc(span.hi);

            if span.is_dummy() {
                println!("!!! no snippet due to <dummy-span> !!!");
            } else if start.line == end.line {
                if let Some(line) = src.get_line(start.line) {
                    println!("{:>#4} {} {}",
                        Magenta.bold().paint(start.line),
                        Magenta.bold().paint("|"),
                        line
                    );

                    Yellow.with(|| {
                        println!("       {: <2$}{:-<3$}",
                            " ", "^",
                            start.col.0 as usize,
                            (end.col.0 - start.col.0) as usize
                        );
                    });
                }
            } else {
                for line_idx in start.line.0..end.line.0 + 1 {
                    let line_idx = LineIdx(line_idx);
                    if let Some(line) = src.get_line(line_idx) {
                        println!("{:>#4} {} {}",
                            Magenta.bold().paint(line_idx),
                            Magenta.bold().paint("|"),
                            line
                        );
                    }
                }
            }
            println!("");
        }

    }
    println!("");
}
<|endoftext|>


<commit_before>use std::collections::VecDeque;

use eew::EEW;

const DEFAULT_MAX_BLOCK_COUNT: usize = 32;

pub struct EEWBuffer {
	buffer: VecDeque<Vec<EEW>>, // each element of buffer must have at least 1 EEW object
	max_block_count: usize
}

impl EEWBuffer {

	pub fn new() -> EEWBuffer
	{
		EEWBuffer { buffer: VecDeque::new(), max_block_count: DEFAULT_MAX_BLOCK_COUNT }
	}

	fn lookup(&self, eew_id: &str) -> Option<usize>
	{
		return self.buffer.iter().position(|ref b|
			b.first().map(|ref e| e.id.as_str()) == Some(eew_id));
	}

	fn extend_block(&mut self, idx: usize, eew: EEW) {

		let ref mut block = self.buffer[idx];

		let is_latest = {
			let last_eew = block.last().expect("a block must have at least 1 element");
			last_eew.number < eew.number
		};

		if is_latest {
			block.push(eew);
		}
	}

	fn create_block(&mut self, eew: EEW) {

		let block = vec! { eew };
		self.buffer.push_back(block);

		while self.buffer.len() > self.max_block_count {
			self.buffer.pop_front();
		}
	}

	pub fn append(&mut self, eew: EEW) -> &[EEW]
	{
		match self.lookup(&eew.id) {

			Some(idx) => {
				self.extend_block(idx, eew);
				&self.buffer[idx]
			},
			None => {
				self.create_block(eew);
				&self.buffer.back().expect("a buffer must have at least 1 block")
			}
		}
	}
}
<commit_msg>EEWBuffer: Add with_capacity initializer<commit_after>use std::collections::VecDeque;

use eew::EEW;

const DEFAULT_MAX_BLOCK_COUNT: usize = 32;

pub struct EEWBuffer {
	buffer: VecDeque<Vec<EEW>>, // each element of buffer must have at least 1 EEW object
	max_block_count: usize
}

impl EEWBuffer {

	pub fn new() -> EEWBuffer
	{
		EEWBuffer { buffer: VecDeque::new(), max_block_count: DEFAULT_MAX_BLOCK_COUNT }
	}

	pub fn with_capacity(n: usize) -> EEWBuffer
	{
		assert!(n >= 1);
		EEWBuffer { buffer: VecDeque::new(), max_block_count: n }
	}

	fn lookup(&self, eew_id: &str) -> Option<usize>
	{
		return self.buffer.iter().position(|ref b|
			b.first().map(|ref e| e.id.as_str()) == Some(eew_id));
	}

	fn extend_block(&mut self, idx: usize, eew: EEW) {

		let ref mut block = self.buffer[idx];

		let is_latest = {
			let last_eew = block.last().expect("a block must have at least 1 element");
			last_eew.number < eew.number
		};

		if is_latest {
			block.push(eew);
		}
	}

	fn create_block(&mut self, eew: EEW) {

		let block = vec! { eew };
		self.buffer.push_back(block);

		while self.buffer.len() > self.max_block_count {
			self.buffer.pop_front();
		}
	}

	pub fn append(&mut self, eew: EEW) -> &[EEW]
	{
		match self.lookup(&eew.id) {

			Some(idx) => {
				self.extend_block(idx, eew);
				&self.buffer[idx]
			},
			None => {
				self.create_block(eew);
				&self.buffer.back().expect("a buffer must have at least 1 block")
			}
		}
	}
}
<|endoftext|>


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

mod filter_node;
mod default_filters;

use std::io::Result;
use std::collections::HashMap;
use self::filter_node::FilterNode;
use value::Value;
use context::Context;
pub use self::filter_node::FilterFunction;
pub use self::default_filters::DEFAULT_FILTERS;
pub use self::default_filters::CHRONO_FILTERS;

#[derive(Clone, Debug)]
pub struct FilterExpression {
	var_name: String,
	filters: Vec<FilterNode>,
}

impl FilterExpression {
    pub fn new(expr: &str, storage: &HashMap<String, FilterFunction>) -> Result<FilterExpression> {
    	let mut expr_splitter = expr.trim().split('|');
    	let var_name = expr_splitter.next().unwrap().to_string();
    	let mut filters = Vec::new();
    	for filter_expr in expr_splitter {
    		let filter = try!(FilterNode::from_expression(filter_expr, storage));
    		filters.push(filter);
    	}
        Ok(FilterExpression {
        	var_name: var_name,
        	filters: filters,
    	})
    }

    pub fn apply(&self, context: &Context) -> Option<Box<Value>> {
    	let val = context.get(&self.var_name);
    	let mut cur_val = match val {
    		Some(content) => Some(content.clone_box()),
    		None => None,
    	};
    	for filter in self.filters.iter() {
    		cur_val = filter.apply(cur_val);
    	}
    	println!("Filter final value is {:?}", cur_val);
    	cur_val
    }
}
<commit_msg>Removed debug message<commit_after>// The MIT License (MIT)
//
// Copyright (c) 2015 Vladislav Orlov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

mod filter_node;
mod default_filters;

use std::io::Result;
use std::collections::HashMap;
use self::filter_node::FilterNode;
use value::Value;
use context::Context;
pub use self::filter_node::FilterFunction;
pub use self::default_filters::DEFAULT_FILTERS;
pub use self::default_filters::CHRONO_FILTERS;

#[derive(Clone, Debug)]
pub struct FilterExpression {
	var_name: String,
	filters: Vec<FilterNode>,
}

impl FilterExpression {
    pub fn new(expr: &str, storage: &HashMap<String, FilterFunction>) -> Result<FilterExpression> {
    	let mut expr_splitter = expr.trim().split('|');
    	let var_name = expr_splitter.next().unwrap().to_string();
    	let mut filters = Vec::new();
    	for filter_expr in expr_splitter {
    		let filter = try!(FilterNode::from_expression(filter_expr, storage));
    		filters.push(filter);
    	}
        Ok(FilterExpression {
        	var_name: var_name,
        	filters: filters,
    	})
    }

    pub fn apply(&self, context: &Context) -> Option<Box<Value>> {
    	let val = context.get(&self.var_name);
    	let mut cur_val = match val {
    		Some(content) => Some(content.clone_box()),
    		None => None,
    	};
    	for filter in self.filters.iter() {
    		cur_val = filter.apply(cur_val);
    	}
    	cur_val
    }
}
<|endoftext|>


<commit_before>use std::{
    collections::hash_map::RandomState,
    hash::{BuildHasher, Hash, Hasher},
    sync::Arc,
    time::{Duration, SystemTime},
};

use axum::http::StatusCode;
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 tokio::{
    sync::{
        mpsc::{self, error::SendTimeoutError},
        oneshot,
    },
    task::JoinHandle,
};

use crate::{
    db::Database,
    model::{
        GameInfo, GameInfoPlayer, Mode, Month, PersonalEntry, PersonalKeyBuilder, PersonalStatus,
        UserId, UserName,
    },
    util::NevermindExt as _,
};

mod lila;

use lila::{Game, Lila};

#[derive(Clap, Clone)]
pub struct IndexerOpt {
    #[clap(long = "lila", default_value = "https://lichess.org")]
    lila: String,
    #[clap(long = "bearer")]
    bearer: Option<String>,
    #[clap(long = "indexers", default_value = "16")]
    indexers: usize,
}

#[derive(Clone)]
pub struct IndexerStub {
    random_state: RandomState,
    txs: Vec<mpsc::Sender<IndexerMessage>>,
}

impl IndexerStub {
    pub fn spawn(db: Arc<Database>, opt: IndexerOpt) -> (IndexerStub, Vec<JoinHandle<()>>) {
        let mut txs = Vec::with_capacity(opt.indexers);
        let mut join_handles = Vec::with_capacity(opt.indexers);
        for idx in 0..opt.indexers {
            let (tx, rx) = mpsc::channel(500);
            txs.push(tx);
            join_handles.push(tokio::spawn(
                IndexerActor {
                    idx,
                    rx,
                    db: db.clone(),
                    lila: Lila::new(opt.clone()),
                }
                .run(),
            ));
        }
        let random_state = RandomState::new();
        (IndexerStub { txs, random_state }, join_handles)
    }

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

        let mut responsible_indexer = self.random_state.build_hasher();
        UserId::from(player.clone()).hash(&mut responsible_indexer);

        match self.txs[responsible_indexer.finish() as usize % self.txs.len()]
            .send_timeout(
                IndexerMessage::IndexPlayer {
                    player,
                    callback: req,
                },
                Duration::from_secs(10),
            )
            .await
        {
            Ok(_) => (),
            Err(SendTimeoutError::Timeout(_)) => {
                log::error!("indexer queue full for more than 10 seconds")
            }
            Err(SendTimeoutError::Closed(_)) => panic!("indexer died"),
        };

        res
    }
}

struct IndexerActor {
    idx: usize,
    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 } => {
                    self.index_player(player).await;
                    callback.send(()).nevermind("requester gone away");
                }
            }
        }
    }

    async fn index_player(&self, player: UserName) {
        let player_id = UserId::from(player.clone());
        let mut status = self
            .db
            .queryable()
            .get_player_status(&player_id)
            .expect("get player status")
            .unwrap_or_default();

        let since_created_at = match status
            .maybe_revisit_ongoing()
            .or_else(|| status.maybe_index())
        {
            Some(since) => since,
            None => {
                log::debug!("not reindexing {} so soon", player);
                return;
            }
        };

        log::info!(
            "indexer {} starting {} (created_at >= {})",
            self.idx,
            player,
            since_created_at
        );
        let mut games = match self.lila.user_games(&player, since_created_at).await {
            Ok(games) => games,
            Err(err) if err.status() == Some(StatusCode::NOT_FOUND) => {
                log::warn!("indexer did not find player {}", player);
                return;
            }
            Err(err) => {
                log::error!("indexer {}: request failed: {}", self.idx, err);
                return;
            }
        };

        let hash = ByColor::new_with(|color| PersonalKeyBuilder::with_user_pov(&player_id, color));
        let mut num_games = 0;
        while let Some(game) = games.next().await {
            let game = match game {
                Ok(game) => game,
                Err(err) => {
                    log::error!("{}", err);
                    continue;
                }
            };

            self.index_game(&player, &hash, game, &mut status);

            num_games += 1;
            if num_games % 1024 == 0 {
                log::info!(
                    "indexer {}: indexed {} games for {}",
                    self.idx,
                    num_games,
                    player
                );
            }
        }

        status.indexed_at = SystemTime::now();
        self.db
            .queryable()
            .put_player_status(&player_id, status)
            .expect("put player status");
        log::info!(
            "indexer {}: finished indexing {} games for {}",
            self.idx,
            num_games,
            player
        );
    }

    fn index_game(
        &self,
        player: &UserName,
        hash: &ByColor<PersonalKeyBuilder>,
        game: Game,
        status: &mut PersonalStatus,
    ) {
        status.latest_created_at = game.created_at;

        if game.status.is_ongoing() {
            if status.revisit_ongoing_created_at.is_none() {
                log::debug!("will revisit ongoing game {} eventually", game.id);
                status.revisit_ongoing_created_at = Some(game.created_at);
            }
            return;
        }

        if game.status.is_unindexable() {
            log::debug!("{} with {:?} not indexable", game.id, game.status);
            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 {
            log::error!("{} did not play in {}", player, game.id);
            return;
        };
        let month = Month::from_time_saturating(game.last_move_at);
        let outcome = Outcome::from_winner(game.winner);

        let queryable = self.db.queryable();
        if queryable
            .get_game_info(game.id)
            .expect("get game info")
            .map_or(false, |info| info.indexed.into_color(color))
        {
            log::debug!(
                "{}/{} already indexed",
                game.id,
                color.fold("white", "black")
            );
            return;
        }
        queryable
            .merge_game_info(
                game.id,
                GameInfo {
                    winner: outcome.winner(),
                    speed: game.speed,
                    rated: game.rated,
                    month,
                    players: game.players.map(|p| GameInfoPlayer {
                        name: p.user.map(|p| p.name.to_string()),
                        rating: p.rating,
                    }),
                    indexed: ByColor::new_with(|c| color == c),
                },
            )
            .expect("put game info");

        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::warn!("cutting off {} at ply {}: {}: {}", game.id, ply, err, san);
                    break;
                }
            };

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

            pos.play_unchecked(&m);
        }

        for (zobrist, uci) in table {
            queryable
                .merge_personal(
                    hash.by_color(color)
                        .with_zobrist(variant, zobrist)
                        .with_month(month),
                    PersonalEntry::new_single(
                        uci.clone(),
                        game.speed,
                        Mode::from_rated(game.rated),
                        game.id,
                        outcome,
                    ),
                )
                .expect("merge personal");
        }
    }
}

enum IndexerMessage {
    IndexPlayer {
        player: UserName,
        callback: oneshot::Sender<()>,
    },
}
<commit_msg>tweak a log message<commit_after>use std::{
    collections::hash_map::RandomState,
    hash::{BuildHasher, Hash, Hasher},
    sync::Arc,
    time::{Duration, SystemTime},
};

use axum::http::StatusCode;
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 tokio::{
    sync::{
        mpsc::{self, error::SendTimeoutError},
        oneshot,
    },
    task::JoinHandle,
};

use crate::{
    db::Database,
    model::{
        GameInfo, GameInfoPlayer, Mode, Month, PersonalEntry, PersonalKeyBuilder, PersonalStatus,
        UserId, UserName,
    },
    util::NevermindExt as _,
};

mod lila;

use lila::{Game, Lila};

#[derive(Clap, Clone)]
pub struct IndexerOpt {
    #[clap(long = "lila", default_value = "https://lichess.org")]
    lila: String,
    #[clap(long = "bearer")]
    bearer: Option<String>,
    #[clap(long = "indexers", default_value = "16")]
    indexers: usize,
}

#[derive(Clone)]
pub struct IndexerStub {
    random_state: RandomState,
    txs: Vec<mpsc::Sender<IndexerMessage>>,
}

impl IndexerStub {
    pub fn spawn(db: Arc<Database>, opt: IndexerOpt) -> (IndexerStub, Vec<JoinHandle<()>>) {
        let mut txs = Vec::with_capacity(opt.indexers);
        let mut join_handles = Vec::with_capacity(opt.indexers);
        for idx in 0..opt.indexers {
            let (tx, rx) = mpsc::channel(500);
            txs.push(tx);
            join_handles.push(tokio::spawn(
                IndexerActor {
                    idx,
                    rx,
                    db: db.clone(),
                    lila: Lila::new(opt.clone()),
                }
                .run(),
            ));
        }
        let random_state = RandomState::new();
        (IndexerStub { txs, random_state }, join_handles)
    }

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

        let mut responsible_indexer = self.random_state.build_hasher();
        UserId::from(player.clone()).hash(&mut responsible_indexer);

        match self.txs[responsible_indexer.finish() as usize % self.txs.len()]
            .send_timeout(
                IndexerMessage::IndexPlayer {
                    player,
                    callback: req,
                },
                Duration::from_secs(10),
            )
            .await
        {
            Ok(_) => (),
            Err(SendTimeoutError::Timeout(_)) => {
                log::error!("indexer queue full for more than 10 seconds")
            }
            Err(SendTimeoutError::Closed(_)) => panic!("indexer died"),
        };

        res
    }
}

struct IndexerActor {
    idx: usize,
    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 } => {
                    self.index_player(player).await;
                    callback.send(()).nevermind("requester gone away");
                }
            }
        }
    }

    async fn index_player(&self, player: UserName) {
        let player_id = UserId::from(player.clone());
        let mut status = self
            .db
            .queryable()
            .get_player_status(&player_id)
            .expect("get player status")
            .unwrap_or_default();

        let since_created_at = match status
            .maybe_revisit_ongoing()
            .or_else(|| status.maybe_index())
        {
            Some(since) => since,
            None => {
                log::debug!("not reindexing {} so soon", player);
                return;
            }
        };

        log::info!(
            "indexer {} starting {} (created_at >= {})",
            self.idx,
            player,
            since_created_at
        );
        let mut games = match self.lila.user_games(&player, since_created_at).await {
            Ok(games) => games,
            Err(err) if err.status() == Some(StatusCode::NOT_FOUND) => {
                log::warn!("indexer did not find player {}", player);
                return;
            }
            Err(err) => {
                log::error!("indexer {}: request failed: {}", self.idx, err);
                return;
            }
        };

        let hash = ByColor::new_with(|color| PersonalKeyBuilder::with_user_pov(&player_id, color));
        let mut num_games = 0;
        while let Some(game) = games.next().await {
            let game = match game {
                Ok(game) => game,
                Err(err) => {
                    log::error!("{}", err);
                    continue;
                }
            };

            self.index_game(&player, &hash, game, &mut status);

            num_games += 1;
            if num_games % 1024 == 0 {
                log::info!(
                    "indexer {}: indexed {} games for {}",
                    self.idx,
                    num_games,
                    player
                );
            }
        }

        status.indexed_at = SystemTime::now();
        self.db
            .queryable()
            .put_player_status(&player_id, status)
            .expect("put player status");
        log::info!(
            "indexer {}: finished indexing {} games for {}",
            self.idx,
            num_games,
            player
        );
    }

    fn index_game(
        &self,
        player: &UserName,
        hash: &ByColor<PersonalKeyBuilder>,
        game: Game,
        status: &mut PersonalStatus,
    ) {
        status.latest_created_at = game.created_at;

        if game.status.is_ongoing() {
            if status.revisit_ongoing_created_at.is_none() {
                log::debug!("will revisit ongoing game {} eventually", game.id);
                status.revisit_ongoing_created_at = Some(game.created_at);
            }
            return;
        }

        if game.status.is_unindexable() {
            log::debug!("not indexing {} with status {:?}", game.id, game.status);
            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 {
            log::error!("{} did not play in {}", player, game.id);
            return;
        };
        let month = Month::from_time_saturating(game.last_move_at);
        let outcome = Outcome::from_winner(game.winner);

        let queryable = self.db.queryable();
        if queryable
            .get_game_info(game.id)
            .expect("get game info")
            .map_or(false, |info| info.indexed.into_color(color))
        {
            log::debug!(
                "{}/{} already indexed",
                game.id,
                color.fold("white", "black")
            );
            return;
        }
        queryable
            .merge_game_info(
                game.id,
                GameInfo {
                    winner: outcome.winner(),
                    speed: game.speed,
                    rated: game.rated,
                    month,
                    players: game.players.map(|p| GameInfoPlayer {
                        name: p.user.map(|p| p.name.to_string()),
                        rating: p.rating,
                    }),
                    indexed: ByColor::new_with(|c| color == c),
                },
            )
            .expect("put game info");

        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::warn!("cutting off {} at ply {}: {}: {}", game.id, ply, err, san);
                    break;
                }
            };

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

            pos.play_unchecked(&m);
        }

        for (zobrist, uci) in table {
            queryable
                .merge_personal(
                    hash.by_color(color)
                        .with_zobrist(variant, zobrist)
                        .with_month(month),
                    PersonalEntry::new_single(
                        uci.clone(),
                        game.speed,
                        Mode::from_rated(game.rated),
                        game.id,
                        outcome,
                    ),
                )
                .expect("merge personal");
        }
    }
}

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


<commit_before>use std::collections::hashmap::HashMap;
use std::io::{Writer, IoResult};
use time;
use format_util;
use common::{ LogEntry };

pub struct LogWriter<'a> {
    writer: &'a mut Writer+'a,
    options: LogWriterOptions<'a>
}

pub struct LogWriterOptions<'a> {
    pub repository_link: String,
    pub version: String,
    pub subtitle: String
}

impl<'a> LogWriter<'a> {

    fn commit_link(&self, hash: &String) -> String {
        let short_hash = format_util::get_short_hash(hash.as_slice());
        match self.options.repository_link.as_slice() {
            "" => format!("({})", short_hash),
            link => format!("[{}]({}/commit/{})", short_hash, link, hash)

        }
    }

    fn issue_link(&self, issue: &String) -> String {
        match self.options.repository_link.as_slice() {
            "" => format!("(#{})", issue),
            link => format!("[#{}]({}/issues/{})", issue, link, issue)
        }
    }

    pub fn write_header(&mut self) -> IoResult<()> {
        let subtitle = match self.options.subtitle.len() {
            0 => self.options.subtitle.clone(),
            _ => format!(" {}", self.options.subtitle)
        };

        let version_text = format!("## {}{}", self.options.version, subtitle);

        let date = time::now_utc().strftime("%Y-%m-%d");

        write!(self.writer, "{} ({})\n\n", version_text, date)
    }

    pub fn write_section(&mut self, title: &str, section: &HashMap<String, Vec<LogEntry>>)
                            -> IoResult<()> {
        if section.len() == 0 { return Ok(()) }

        try!(self.writer.write_line(format!("\n#### {}\n\n", title).as_slice()));

        for (component, entries) in section.iter() {
            let nested = entries.len() > 1;

            //TODO: implement the empty component stuff
            let prefix = if nested {
                try!(write!(self.writer, "* **{}**\n", component));
                "  *".to_string()
            } else {
                format!("* **{}**", component)
            };

            for entry in entries.iter() {
                try!(write!(self.writer, "{} {} ({}",
                                         prefix,
                                         entry.subject,
                                         self.commit_link(&entry.hash)));

                if entry.closes.len() > 0 {
                    let closes_string = entry.closes.iter()
                                                    .map(|s| self.issue_link(s))
                                                    // FIXME: Connect should be
                                                    // used on the Iterator
                                                    .collect::<Vec<String>>()
                                                    .connect(", ");

                    try!(write!(self.writer, ", closes {}", closes_string));
                }

                try!(write!(self.writer, ")\n"));
            }
        }

        Ok(())
    }

    pub fn write(&mut self, content: &str)  -> IoResult<()> {
        try!(write!(self.writer, "\n\n\n"));
        write!(self.writer, "{}", content)
    }

    pub fn new<T:Writer + Send>(writer: &'a mut T, options: LogWriterOptions) -> LogWriter<'a> {
        LogWriter {
            writer: writer,
            options: options
        }
    }
}
<commit_msg>feat(log_writer): include anchor in header<commit_after>use std::collections::hashmap::HashMap;
use std::io::{Writer, IoResult};
use time;
use format_util;
use common::{ LogEntry };

pub struct LogWriter<'a> {
    writer: &'a mut Writer+'a,
    options: LogWriterOptions<'a>
}

pub struct LogWriterOptions<'a> {
    pub repository_link: String,
    pub version: String,
    pub subtitle: String
}

impl<'a> LogWriter<'a> {

    fn commit_link(&self, hash: &String) -> String {
        let short_hash = format_util::get_short_hash(hash.as_slice());
        match self.options.repository_link.as_slice() {
            "" => format!("({})", short_hash),
            link => format!("[{}]({}/commit/{})", short_hash, link, hash)

        }
    }

    fn issue_link(&self, issue: &String) -> String {
        match self.options.repository_link.as_slice() {
            "" => format!("(#{})", issue),
            link => format!("[#{}]({}/issues/{})", issue, link, issue)
        }
    }

    pub fn write_header(&mut self) -> IoResult<()> {
        let subtitle = match self.options.subtitle.len() {
            0 => self.options.subtitle.clone(),
            _ => format!(" {}", self.options.subtitle)
        };

        let version_text = format!("## {}{}", self.options.version, subtitle);

        let date = time::now_utc().strftime("%Y-%m-%d");

        write!(self.writer, "\n{} ({})\n\n", self.options.version, version_text, date)
    }

    pub fn write_section(&mut self, title: &str, section: &HashMap<String, Vec<LogEntry>>)
                            -> IoResult<()> {
        if section.len() == 0 { return Ok(()) }

        try!(self.writer.write_line(format!("\n#### {}\n\n", title).as_slice()));

        for (component, entries) in section.iter() {
            let nested = entries.len() > 1;

            //TODO: implement the empty component stuff
            let prefix = if nested {
                try!(write!(self.writer, "* **{}**\n", component));
                "  *".to_string()
            } else {
                format!("* **{}**", component)
            };

            for entry in entries.iter() {
                try!(write!(self.writer, "{} {} ({}",
                                         prefix,
                                         entry.subject,
                                         self.commit_link(&entry.hash)));

                if entry.closes.len() > 0 {
                    let closes_string = entry.closes.iter()
                                                    .map(|s| self.issue_link(s))
                                                    // FIXME: Connect should be
                                                    // used on the Iterator
                                                    .collect::<Vec<String>>()
                                                    .connect(", ");

                    try!(write!(self.writer, ", closes {}", closes_string));
                }

                try!(write!(self.writer, ")\n"));
            }
        }

        Ok(())
    }

    pub fn write(&mut self, content: &str)  -> IoResult<()> {
        try!(write!(self.writer, "\n\n\n"));
        write!(self.writer, "{}", content)
    }

    pub fn new<T:Writer + Send>(writer: &'a mut T, options: LogWriterOptions) -> LogWriter<'a> {
        LogWriter {
            writer: writer,
            options: options
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Global style data

use context::StyleSystemOptions;
use gecko_bindings::bindings::{Gecko_RegisterProfilerThread, Gecko_UnregisterProfilerThread};
use num_cpus;
use rayon;
use shared_lock::SharedRwLock;
use std::cmp;
use std::env;
use std::ffi::CString;

/// Global style data
pub struct GlobalStyleData {
    /// How many threads parallel styling can use.
    pub num_threads: usize,

    /// The parallel styling thread pool.
    pub style_thread_pool: Option<rayon::ThreadPool>,

    /// Shared RWLock for CSSOM objects
    pub shared_lock: SharedRwLock,

    /// Global style system options determined by env vars.
    pub options: StyleSystemOptions,
}

fn thread_name(index: usize) -> String {
    format!("StyleThread#{}", index)
}

fn thread_startup(index: usize) {
    let name = thread_name(index);
    let name = CString::new(name).unwrap();
    unsafe {
        // Gecko_RegisterProfilerThread copies the passed name here.
        Gecko_RegisterProfilerThread(name.as_ptr());
    }
}

fn thread_shutdown(_: usize) {
    unsafe {
        Gecko_UnregisterProfilerThread();
    }
}

lazy_static! {
    /// Global style data
    pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
        let stylo_threads = env::var("STYLO_THREADS")
            .map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
        let num_threads = match stylo_threads {
            Ok(num) => num,
            _ => cmp::max(num_cpus::get() * 3 / 4, 1),
        };

        let pool = if num_threads <= 1 {
            None
        } else {
            let configuration = rayon::Configuration::new()
                .num_threads(num_threads)
                .thread_name(thread_name)
                .start_handler(thread_startup)
                .exit_handler(thread_shutdown);
            let pool = rayon::ThreadPool::new(configuration).ok();
            pool
        };

        GlobalStyleData {
            num_threads: num_threads,
            style_thread_pool: pool,
            shared_lock: SharedRwLock::new(),
            options: StyleSystemOptions::default(),
        }
    };
}
<commit_msg>Bug 1361258 - Opt-in to thread-local jemalloc arenas for stylo rayon threads. r=bholley<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

//! Global style data

use context::StyleSystemOptions;
use gecko_bindings::bindings::{Gecko_RegisterProfilerThread, Gecko_UnregisterProfilerThread};
use gecko_bindings::bindings::Gecko_SetJemallocThreadLocalArena;
use num_cpus;
use rayon;
use shared_lock::SharedRwLock;
use std::cmp;
use std::env;
use std::ffi::CString;

/// Global style data
pub struct GlobalStyleData {
    /// How many threads parallel styling can use.
    pub num_threads: usize,

    /// The parallel styling thread pool.
    pub style_thread_pool: Option<rayon::ThreadPool>,

    /// Shared RWLock for CSSOM objects
    pub shared_lock: SharedRwLock,

    /// Global style system options determined by env vars.
    pub options: StyleSystemOptions,
}

fn thread_name(index: usize) -> String {
    format!("StyleThread#{}", index)
}

fn thread_startup(index: usize) {
    unsafe {
        Gecko_SetJemallocThreadLocalArena(true);
    }
    let name = thread_name(index);
    let name = CString::new(name).unwrap();
    unsafe {
        // Gecko_RegisterProfilerThread copies the passed name here.
        Gecko_RegisterProfilerThread(name.as_ptr());
    }
}

fn thread_shutdown(_: usize) {
    unsafe {
        Gecko_UnregisterProfilerThread();
        Gecko_SetJemallocThreadLocalArena(false);
    }
}

lazy_static! {
    /// Global style data
    pub static ref GLOBAL_STYLE_DATA: GlobalStyleData = {
        let stylo_threads = env::var("STYLO_THREADS")
            .map(|s| s.parse::<usize>().expect("invalid STYLO_THREADS value"));
        let num_threads = match stylo_threads {
            Ok(num) => num,
            _ => cmp::max(num_cpus::get() * 3 / 4, 1),
        };

        let pool = if num_threads <= 1 {
            None
        } else {
            let configuration = rayon::Configuration::new()
                .num_threads(num_threads)
                .thread_name(thread_name)
                .start_handler(thread_startup)
                .exit_handler(thread_shutdown);
            let pool = rayon::ThreadPool::new(configuration).ok();
            pool
        };

        GlobalStyleData {
            num_threads: num_threads,
            style_thread_pool: pool,
            shared_lock: SharedRwLock::new(),
            options: StyleSystemOptions::default(),
        }
    };
}
<|endoftext|>