<commit_before>use cmp::Ord;
use num::{Num, from_int};

use ncast::*;

// TODO: move to a more appropriate module
pub trait ToPtr<T> {
    pure fn to_ptr() -> *T;
}

pub trait ExactEq {
    pure fn exact_eq(other: &self) -> bool;
}

trait MinMax {
    pure fn min(other: &self) -> self;
    pure fn max(other: &self) -> self;
}

#[inline(always)] pure fn min<T:MinMax>(a: &T, b: &T) -> T { a.min(b) }
#[inline(always)] pure fn max<T:MinMax>(a: &T, b: &T) -> T { a.max(b) }

impl u8: MinMax {
    #[inline(always)] pure fn min(other: &u8) -> u8 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &u8) -> u8 { if self > *other { self } else { *other } }
}

impl u16: MinMax {
    #[inline(always)] pure fn min(other: &u16) -> u16 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &u16) -> u16 { if self > *other { self } else { *other } }
}

impl u32: MinMax {
    #[inline(always)] pure fn min(other: &u32) -> u32 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &u32) -> u32 { if self > *other { self } else { *other } }
}

impl u64: MinMax {
    #[inline(always)] pure fn min(other: &u64) -> u64 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &u64) -> u64 { if self > *other { self } else { *other } }
}

impl uint: MinMax {
    #[inline(always)] pure fn min(other: &uint) -> uint { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &uint) -> uint { if self > *other { self } else { *other } }
}

impl i8: MinMax {
    #[inline(always)] pure fn min(other: &i8) -> i8 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &i8) -> i8 { if self > *other { self } else { *other } }
}

impl i16: MinMax {
    #[inline(always)] pure fn min(other: &i16) -> i16 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &i16) -> i16 { if self > *other { self } else { *other } }
}

impl i32: MinMax {
    #[inline(always)] pure fn min(other: &i32) -> i32 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &i32) -> i32 { if self > *other { self } else { *other } }
}

impl i64: MinMax {
    #[inline(always)] pure fn min(other: &i64) -> i64 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &i64) -> i64 { if self > *other { self } else { *other } }
}

impl int: MinMax {
    #[inline(always)] pure fn min(other: &int) -> int { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &int) -> int { if self > *other { self } else { *other } }
}

impl f32: MinMax {
    #[inline(always)] pure fn min(other: &f32) -> f32 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &f32) -> f32 { if self > *other { self } else { *other } }
}

impl f64: MinMax {
    #[inline(always)] pure fn min(other: &f64) -> f64 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &f64) -> f64 { if self > *other { self } else { *other } }
}

impl float: MinMax {
    #[inline(always)] pure fn min(other: &float) -> float { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &float) -> float { if self > *other { self } else { *other } }
}

trait Abs {
    pure fn abs() -> self;
}

#[inline(always)]
pure fn abs<T: Abs>(x: &T) -> T {
    x.abs()
}

impl i8: Abs {
    #[inline(always)]
    pure fn abs() -> i8 {
        if self >= 0 { self }
        else         {-self }
    }
}

impl i16: Abs {
    #[inline(always)]
    pure fn abs() -> i16 {
        if self >= 0 { self }
        else         {-self }
    }
}

impl i32: Abs {
    #[inline(always)]
    pure fn abs() -> i32 {
        if self >= 0 { self }
        else         {-self }
    }
}

impl i64: Abs {
    #[inline(always)]
    pure fn abs() -> i64 {
        if self >= 0 { self }
        else         {-self }
    }
}

impl int: Abs {
    #[inline(always)]
    pure fn abs() -> int {
        if self >= 0 { self }
        else         {-self }
    }
}

impl f32: Abs {
    #[inline(always)]
    pure fn abs() -> f32 {
        if self >= 0f32 { self }
        else            {-self }
    }
}

impl f64: Abs {
    #[inline(always)]
    pure fn abs() -> f64 {
        if self >= 0f64 { self }
        else            {-self }
    }
}

impl float: Abs {
    #[inline(always)]
    pure fn abs() -> float {
        if self >= 0f { self }
        else          {-self }
    }
}

trait Sqrt {
    pure fn sqrt() -> self;
}

#[inline(always)]
pure fn sqrt<T: Sqrt>(x: T) -> T {
    x.sqrt()
}

pub impl<T: NumCast> T: Sqrt {
    #[inline(always)]
    pure fn sqrt() -> T {
        f64::sqrt(self.cast()).cast()
    }
}<commit_msg>Add Todo comments<commit_after>use cmp::Ord;
use num::*;

use ncast::*;

// TODO: move to a more appropriate module
pub trait ToPtr<T> {
    pure fn to_ptr() -> *T;
}

pub trait ExactEq {
    pure fn exact_eq(other: &self) -> bool;
}

/**
 * TODO: This trait will be implemented for <T:Num Ord> when generic trait
 * support is improved. At the moment this would cause a conflict between the
 * implementations in lmath::vector.
 */
trait MinMax {
    pure fn min(other: &self) -> self;
    pure fn max(other: &self) -> self;
}

#[inline(always)] pure fn min<T:MinMax>(a: &T, b: &T) -> T { a.min(b) }
#[inline(always)] pure fn max<T:MinMax>(a: &T, b: &T) -> T { a.max(b) }

impl u8: MinMax {
    #[inline(always)] pure fn min(other: &u8) -> u8 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &u8) -> u8 { if self > *other { self } else { *other } }
}

impl u16: MinMax {
    #[inline(always)] pure fn min(other: &u16) -> u16 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &u16) -> u16 { if self > *other { self } else { *other } }
}

impl u32: MinMax {
    #[inline(always)] pure fn min(other: &u32) -> u32 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &u32) -> u32 { if self > *other { self } else { *other } }
}

impl u64: MinMax {
    #[inline(always)] pure fn min(other: &u64) -> u64 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &u64) -> u64 { if self > *other { self } else { *other } }
}

impl uint: MinMax {
    #[inline(always)] pure fn min(other: &uint) -> uint { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &uint) -> uint { if self > *other { self } else { *other } }
}

impl i8: MinMax {
    #[inline(always)] pure fn min(other: &i8) -> i8 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &i8) -> i8 { if self > *other { self } else { *other } }
}

impl i16: MinMax {
    #[inline(always)] pure fn min(other: &i16) -> i16 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &i16) -> i16 { if self > *other { self } else { *other } }
}

impl i32: MinMax {
    #[inline(always)] pure fn min(other: &i32) -> i32 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &i32) -> i32 { if self > *other { self } else { *other } }
}

impl i64: MinMax {
    #[inline(always)] pure fn min(other: &i64) -> i64 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &i64) -> i64 { if self > *other { self } else { *other } }
}

impl int: MinMax {
    #[inline(always)] pure fn min(other: &int) -> int { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &int) -> int { if self > *other { self } else { *other } }
}

impl f32: MinMax {
    #[inline(always)] pure fn min(other: &f32) -> f32 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &f32) -> f32 { if self > *other { self } else { *other } }
}

impl f64: MinMax {
    #[inline(always)] pure fn min(other: &f64) -> f64 { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &f64) -> f64 { if self > *other { self } else { *other } }
}

impl float: MinMax {
    #[inline(always)] pure fn min(other: &float) -> float { if self < *other { self } else { *other } }
    #[inline(always)] pure fn max(other: &float) -> float { if self > *other { self } else { *other } }
}

/**
 * TODO: This trait will be implemented for <T:NumCast Ord> when generic trait
 * support is improved. At the moment this would cause a conflict between the
 * implementations in lmath::vector.
 */
trait Abs {
    pure fn abs() -> self;
}

#[inline(always)]
pure fn abs<T: Abs>(x: &T) -> T {
    x.abs()
}

impl i8: Abs {
    #[inline(always)]
    pure fn abs() -> i8 {
        if self >= 0 { self }
        else         {-self }
    }
}

impl i16: Abs {
    #[inline(always)]
    pure fn abs() -> i16 {
        if self >= 0 { self }
        else         {-self }
    }
}

impl i32: Abs {
    #[inline(always)]
    pure fn abs() -> i32 {
        if self >= 0 { self }
        else         {-self }
    }
}

impl i64: Abs {
    #[inline(always)]
    pure fn abs() -> i64 {
        if self >= 0 { self }
        else         {-self }
    }
}

impl int: Abs {
    #[inline(always)]
    pure fn abs() -> int {
        if self >= 0 { self }
        else         {-self }
    }
}

impl f32: Abs {
    #[inline(always)]
    pure fn abs() -> f32 {
        if self >= 0f32 { self }
        else            {-self }
    }
}

impl f64: Abs {
    #[inline(always)]
    pure fn abs() -> f64 {
        if self >= 0f64 { self }
        else            {-self }
    }
}

impl float: Abs {
    #[inline(always)]
    pure fn abs() -> float {
        if self >= 0f { self }
        else          {-self }
    }
}

trait Sqrt {
    pure fn sqrt() -> self;
}

#[inline(always)]
pure fn sqrt<T: Sqrt>(x: T) -> T {
    x.sqrt()
}

pub impl<T: NumCast> T: Sqrt {
    #[inline(always)]
    pure fn sqrt() -> T {
        f64::sqrt(self.cast()).cast()
    }
}<|endoftext|>


<commit_before>use common::types::FnType;
use common::types::StructType;
use common::link::*;

use common::entity::FromEntity;
use common::entity::Entity;
use std::cmp::Ordering;

use std::ops::Deref;

#[derive(Debug, Clone)]
pub struct Node {
    id: i32,
    name: String,
    url: String,
    fn_type: FnType,
    link: Vec<Link>,
    nodes: Vec<Node>,
}

impl Node {
    fn set_children(&self, children: &[Entity]) {

    }
}

impl FromEntity for Node {
    fn from_entity(entity: Entity) -> Self {
        Node {
            id: entity.id,
            name: entity.name,
            url: entity.url,
            fn_type: entity.fn_type,
            link: Vec::new(),
            nodes: Vec::new()
        }
    }

    //TODO entity matcher for nodes
    fn from_entities(mut entites: Vec<Entity>) -> Vec<Self> {
        let mut node_vec: Vec<Node> = Vec::new();
        let mut link_vec = Vec::new();

        //let base_length = 2;
        entites.sort_by(|e1, e2| {
            if e1.tree_id.len() < e2.tree_id.len() {
                Ordering::Less
            } else if e1.tree_id.len() > e2.tree_id.len() {
                Ordering::Greater
            } else {
                Ordering::Equal
            }
        });

        println!("{:?}", node_vec);
        node_vec
    }
}
<commit_msg>instance du tableau de lien fixes<commit_after>use common::types::FnType;
use common::types::StructType;
use common::link::*;

use common::entity::FromEntity;
use common::entity::Entity;
use std::cmp::Ordering;

use std::ops::Deref;

#[derive(Debug, Clone)]
pub struct Node {
    id: i32,
    name: String,
    url: String,
    fn_type: FnType,
    link: Vec<Link>,
    nodes: Vec<Node>,
}

impl Node {
    fn set_children(&self, children: &[Entity]) {

    }
}

impl FromEntity for Node {
    fn from_entity(entity: Entity) -> Self {
        Node {
            id: entity.id,
            name: entity.name,
            url: entity.url,
            fn_type: entity.fn_type,
            link: Vec::new(),
            nodes: Vec::new()
        }
    }

    //TODO entity matcher for nodes
    fn from_entities(mut entites: Vec<Entity>) -> Vec<Self> {
        let mut node_vec: Vec<Node> = Vec::new();
        let mut link_vec: Vec<Link> = Vec::new();

        //let base_length = 2;
        entites.sort_by(|e1, e2| {
            if e1.tree_id.len() < e2.tree_id.len() {
                Ordering::Less
            } else if e1.tree_id.len() > e2.tree_id.len() {
                Ordering::Greater
            } else {
                Ordering::Equal
            }
        });

        println!("{:?}", node_vec);
        node_vec
    }
}
<|endoftext|>


<commit_before>use luminance::{Depth32F, Dim2, Flat, Framebuffer, Mode, RGBA32F, Tess, Texture, Uniform, Unit};
use luminance::pipeline::{Pipe, Pipeline, RenderCommand, ShadingCommand};
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::{Equation, Factor};

use color::RGBA;
use resource::{Res, ResCache};
use shader::Program;

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(RGBA),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, RGBA, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    rhs.compose_with(self, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<RGBA> for Node<'a> {
  fn from(color: RGBA) -> Self {
    Node::Color(color)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  compose_program: Res<Program>,
  // program used to render textures scaled
  texture_program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);
const TEXTURE_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      compose_program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      texture_program: cache.get("spectra/compositing/texture.glsl", vec![TEXTURE_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];

      let screen = Framebuffer::default((self.w, self.h));

      let black = [0., 0., 0., 1.];
      let compose_program = self.compose_program.borrow();
      let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
      let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&compose_program, render_cmd))];
      let texture_set = &[&*fb.color_slot];

      Pipeline::new(&screen, black, texture_set, &[], shd_cmd).run();
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let black = [0., 0., 0., 1.];
    let texture_program = self.texture_program.borrow();
    let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
    let tess_render = TessRender::from(&self.quad);
    let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
    let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
    let shd_cmd = &[Pipe::new(ShadingCommand::new(&texture_program, render_cmd))];
    let texture_set = &[&**texture];

    Pipeline::new(fb, black, texture_set, &[], shd_cmd).run();

    fb_index
  }

  fn colorize(&mut self, color: RGBA) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[], &[]).run();

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      // compose
      let compose_program = self.compose_program.borrow();
      let uniforms_left = [FORWARD_SOURCE.alter(Unit::new(0))];
      let uniforms_right = [FORWARD_SOURCE.alter(Unit::new(1))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[
        Pipe::empty().uniforms(&uniforms_left).unwrap(tess_render.clone()),
        Pipe::empty().uniforms(&uniforms_right).unwrap(tess_render)
      ];
      let render_cmd = &[Pipe::new(RenderCommand::new((eq, src_fct, dst_fct), false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&compose_program, render_cmd))];
      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[], shd_cmd).run();
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<commit_msg>Fixed Node::Texture() uniforms.<commit_after>use luminance::{Depth32F, Dim2, Flat, Framebuffer, Mode, RGBA32F, Tess, Texture, Uniform, Unit};
use luminance::pipeline::{Pipe, Pipeline, RenderCommand, ShadingCommand};
use luminance::tess::TessRender;
use std::ops::{Add, Mul, Sub};

pub use luminance::{Equation, Factor};

use color::RGBA;
use resource::{Res, ResCache};
use shader::Program;

/// Simple texture that can be embedded into a compositing graph.
pub type TextureLayer<'a> = &'a ColorMap;

pub type ColorMap = Texture<Flat, Dim2, RGBA32F>;
pub type DepthMap = Texture<Flat, Dim2, Depth32F>;

/// Render layer used to host renders.
pub struct RenderLayer<'a> {
  render: Box<Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) + 'a>
}

impl<'a> RenderLayer<'a> {
  pub fn new<F>(render: F) -> Self where F: 'a + Fn(&Framebuffer<Flat, Dim2, ColorMap, DepthMap>) {
    RenderLayer {
      render: Box::new(render)
    }
  }
}

/// Compositing node.
pub enum Node<'a> {
  /// A render node.
  ///
  /// Contains render layer.
  Render(RenderLayer<'a>),
  /// A texture node.
  ///
  /// Contains a single texture.
  Texture(TextureLayer<'a>),
  /// A single color.
  ///
  /// Keep in mind that such a node is great when you want to display a fullscreen colored quad but
  /// you shouldn’t use it for blending purpose. Adding color masking to your post-process is a
  /// better alternative and will avoid fillrate alteration.
  Color(RGBA),
  /// Composite node.
  ///
  /// Composite nodes are used to blend two compositing nodes according to a given `Equation` and
  /// two blending `Factor`s for source and destination, respectively.
  Composite(Box<Node<'a>>, Box<Node<'a>>, RGBA, Equation, Factor, Factor)
}

impl<'a> Node<'a> {
  /// Compose this node with another one.
  pub fn compose_with(self, rhs: Self, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> Self {
    Node::Composite(Box::new(self), Box::new(rhs), clear_color, eq, src_fct, dst_fct)
  }

  /// Compose this node over the other. In effect, the resulting node will replace any pixels covered
  /// by the right node by the ones of the left node unless the alpha value is different than `1`.
  /// In that case, an additive blending based on the alpha value of the left node will be performed.
  ///
  /// If you set the alpha value to `0` at a pixel in the left node, then the resulting pixel will be
  /// the one from the right node.
  pub fn over(self, rhs: Self) -> Self {
    rhs.compose_with(self, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::SrcAlpha, Factor::SrcAlphaComplement)
  }
}

impl<'a> From<RenderLayer<'a>> for Node<'a> {
  fn from(layer: RenderLayer<'a>) -> Self {
    Node::Render(layer)
  }
}

impl<'a> From<TextureLayer<'a>> for Node<'a> {
  fn from(texture: TextureLayer<'a>) -> Self {
    Node::Texture(texture)
  }
}

impl<'a> From<RGBA> for Node<'a> {
  fn from(color: RGBA) -> Self {
    Node::Color(color)
  }
}

impl<'a> Add for Node<'a> {
  type Output = Self;

  fn add(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Additive, Factor::One, Factor::One)
  }
}

impl<'a> Sub for Node<'a> {
  type Output = Self;

  fn sub(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(0., 0., 0., 0.), Equation::Subtract, Factor::One, Factor::One)
  }
}

impl<'a> Mul for Node<'a> {
  type Output = Self;

  fn mul(self, rhs: Self) -> Self {
    self.compose_with(rhs, RGBA::new(1., 1., 1., 1.), Equation::Additive, Factor::Zero, Factor::SrcColor)
  }
}

/// Compositor object; used to consume `Node`s and output to screen.
pub struct Compositor {
  // width
  w: u32,
  // height
  h: u32,
  // allocated framebuffers that might contain nodes’ output
  framebuffers: Vec<Framebuffer<Flat, Dim2, ColorMap, DepthMap>>,
  // free list of available framebuffers
  free_framebuffers: Vec<usize>,
  // program used to compose nodes
  compose_program: Res<Program>,
  // program used to render textures scaled
  texture_program: Res<Program>,
  // attributeless fullscreen quad for compositing
  quad: Tess
}

const FORWARD_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);
const TEXTURE_SOURCE: &'static Uniform<Unit> = &Uniform::new(0);

impl Compositor {
  pub fn new(w: u32, h: u32, cache: &mut ResCache) -> Self {
    Compositor {
      w: w,
      h: h,
      framebuffers: Vec::new(),
      free_framebuffers: Vec::new(),
      compose_program: cache.get("spectra/compositing/forward.glsl", vec![FORWARD_SOURCE.sem("source")]).unwrap(),
      texture_program: cache.get("spectra/compositing/texture.glsl", vec![TEXTURE_SOURCE.sem("source")]).unwrap(),
      quad: Tess::attributeless(Mode::TriangleStrip, 4)
    }
  }

  /// Whenever a node must be composed, we need a framebuffer to render into. This function pulls a
  /// framebuffer to use (via self.framebuffers) by returing an index. It might allocate a new
  /// framebuffer if there isn’t enough framebuffers to be pulled.
  fn pull_framebuffer(&mut self) -> usize {
    self.free_framebuffers.pop().unwrap_or_else(|| {
      let framebuffer_index = self.framebuffers.len();

      let framebuffer = Framebuffer::new((self.w, self.h), 0).unwrap();
      self.framebuffers.push(framebuffer);

      framebuffer_index
    })
  }

  /// Whenever a node has finished being composed, we *might* need to dispose the framebuffer it has
  /// pulled. This funciton does that job.
  ///
  /// It never deallocates memory. It has an important property: once a framebuffer is pulled,
  /// calling that function will make it available for other nodes, improving memory usage for the
  /// next calls.
  #[inline]
  fn dispose_framebuffer(&mut self, framebuffer_index: usize) {
    self.free_framebuffers.push(framebuffer_index);
  }

  /// Consume and display a compositing graph represented by its nodes.
  pub fn display(&mut self, root: Node) {
    let fb_index = self.treat_node(root);

    {
      let fb = &self.framebuffers[fb_index];

      let screen = Framebuffer::default((self.w, self.h));

      let black = [0., 0., 0., 1.];
      let compose_program = self.compose_program.borrow();
      let uniforms_tex = [FORWARD_SOURCE.alter(Unit::new(0))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
      let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&compose_program, render_cmd))];
      let texture_set = &[&*fb.color_slot];

      Pipeline::new(&screen, black, texture_set, &[], shd_cmd).run();
    }

    self.dispose_framebuffer(fb_index);
  }

  /// Treat a node hierarchy and return the index  of the framebuffer that contains the result.
  fn treat_node(&mut self, node: Node) -> usize {
    match node {
      Node::Render(layer) => self.render(layer),
      Node::Texture(texture) => self.texturize(texture),
      Node::Color(color) => self.colorize(color),
      Node::Composite(left, right, clear_color, eq, src_fct, dst_fct) => self.composite(*left, *right, clear_color, eq, src_fct, dst_fct),
    }
  }

  fn render(&mut self, layer: RenderLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    (layer.render)(&fb);

    fb_index
  }

  fn texturize(&mut self, texture: TextureLayer) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let black = [0., 0., 0., 1.];
    let texture_program = self.texture_program.borrow();
    let uniforms_tex = [TEXTURE_SOURCE.alter(Unit::new(0))];
    let tess_render = TessRender::from(&self.quad);
    let tess = &[Pipe::empty().uniforms(&uniforms_tex).unwrap(tess_render.clone())];
    let render_cmd = &[Pipe::new(RenderCommand::new(None, false, tess))];
    let shd_cmd = &[Pipe::new(ShadingCommand::new(&texture_program, render_cmd))];
    let texture_set = &[&**texture];

    Pipeline::new(fb, black, texture_set, &[], shd_cmd).run();

    fb_index
  }

  fn colorize(&mut self, color: RGBA) -> usize {
    let fb_index = self.pull_framebuffer();
    let fb = &self.framebuffers[fb_index];

    let color = *color.as_ref();

    Pipeline::new(fb, color, &[], &[], &[]).run();

    fb_index
  }

  fn composite(&mut self, left: Node, right: Node, clear_color: RGBA, eq: Equation, src_fct: Factor, dst_fct: Factor) -> usize {
    let left_index = self.treat_node(left);
    let right_index = self.treat_node(right);

    assert!(left_index < self.framebuffers.len());
    assert!(right_index < self.framebuffers.len());

    let fb_index = self.pull_framebuffer();

    {
      let fb = &self.framebuffers[fb_index];

      let left_fb = &self.framebuffers[left_index];
      let right_fb = &self.framebuffers[right_index];

      // compose
      let compose_program = self.compose_program.borrow();
      let uniforms_left = [FORWARD_SOURCE.alter(Unit::new(0))];
      let uniforms_right = [FORWARD_SOURCE.alter(Unit::new(1))];
      let tess_render = TessRender::from(&self.quad);
      let tess = &[
        Pipe::empty().uniforms(&uniforms_left).unwrap(tess_render.clone()),
        Pipe::empty().uniforms(&uniforms_right).unwrap(tess_render)
      ];
      let render_cmd = &[Pipe::new(RenderCommand::new((eq, src_fct, dst_fct), false, tess))];
      let shd_cmd = &[Pipe::new(ShadingCommand::new(&compose_program, render_cmd))];
      let texture_set = &[
        &*left_fb.color_slot,
        &*right_fb.color_slot
      ];

      Pipeline::new(fb, *clear_color.as_ref(), texture_set, &[], shd_cmd).run();
    }

    // dispose both left and right framebuffers
    self.dispose_framebuffer(left_index);
    self.dispose_framebuffer(right_index);

    fb_index
  }
}
<|endoftext|>


<commit_before>use std::io::Write;
use std::process::{Command, Stdio};

use indoc::indoc;
use serde::Serialize;

use nmk::NMK_INIT_SCRIPT;

#[derive(Serialize)]
struct Info {
    nmk: Nmk,
    rustup: Rustup,
    toolchain: Toolchain,
}

#[derive(Serialize)]
struct Toolchain {
    rustc: &'static str,
    target: &'static str,
}

#[derive(Serialize)]
struct Rustup {
    get_architecture: String,
}

#[derive(Serialize)]
struct Nmk {
    commit: Option<&'static str>,
}

pub fn print_info() -> crate::Result<()> {
    let info = Info {
        nmk: Nmk {
            commit: option_env!("GIT_SHORT_SHA"),
        },
        rustup: Rustup {
            get_architecture: detect_current_architecture()?,
        },
        toolchain: Toolchain {
            rustc: env!("BUILD_RUSTC_VERSION"),
            target: env!("BUILD_TARGET"),
        },
    };
    println!("{}", toml::to_string_pretty(&info)?);
    Ok(())
}

const GET_ARCHITECTURE: &str = indoc! {r##"
    get_architecture || return 1
    echo $RETVAL
"##};

fn detect_current_architecture() -> crate::Result<String> {
    // capacity should be bigger than final script size to avoid reallocation
    let capacity = NMK_INIT_SCRIPT.len() + GET_ARCHITECTURE.len();
    let mut detect_arch_script = NMK_INIT_SCRIPT
        .lines()
        .take_while(|line| !line.starts_with(r##"main "$@""##))
        .fold(String::with_capacity(capacity), |mut acc, line| {
            acc.push_str(line);
            acc.push('\n');
            acc
        });
    detect_arch_script.push_str(GET_ARCHITECTURE);
    let mut shell = Command::new("sh")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::null())
        .spawn()?;
    let stdin = shell.stdin.as_mut().expect("Shell must have stdin");
    write!(stdin, "{}", detect_arch_script)?;
    let output = shell.wait_with_output()?;
    let arch = std::str::from_utf8(&output.stdout)?.trim().to_string();
    Ok(arch)
}
<commit_msg>Simplify get architecture by use join<commit_after>use std::io::Write;
use std::iter;
use std::process::{Command, Stdio};

use indoc::indoc;
use serde::Serialize;

use nmk::NMK_INIT_SCRIPT;

#[derive(Serialize)]
struct Info {
    nmk: Nmk,
    rustup: Rustup,
    toolchain: Toolchain,
}

#[derive(Serialize)]
struct Toolchain {
    rustc: &'static str,
    target: &'static str,
}

#[derive(Serialize)]
struct Rustup {
    get_architecture: String,
}

#[derive(Serialize)]
struct Nmk {
    commit: Option<&'static str>,
}

pub fn print_info() -> crate::Result<()> {
    let info = Info {
        nmk: Nmk {
            commit: option_env!("GIT_SHORT_SHA"),
        },
        rustup: Rustup {
            get_architecture: detect_current_architecture()?,
        },
        toolchain: Toolchain {
            rustc: env!("BUILD_RUSTC_VERSION"),
            target: env!("BUILD_TARGET"),
        },
    };
    println!("{}", toml::to_string_pretty(&info)?);
    Ok(())
}

const GET_ARCHITECTURE: &str = indoc! {r##"
    get_architecture || return 1
    echo $RETVAL
"##};

fn detect_current_architecture() -> crate::Result<String> {
    let detect_arch_script = NMK_INIT_SCRIPT
        .lines()
        .take_while(|line| !line.starts_with(r##"main "$@""##))
        .chain(iter::once(GET_ARCHITECTURE))
        .collect::<Vec<_>>()
        .join("\n");
    let mut shell = Command::new("sh")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .stderr(Stdio::null())
        .spawn()?;
    let stdin = shell.stdin.as_mut().expect("Shell must have stdin");
    write!(stdin, "{}", detect_arch_script)?;
    let output = shell.wait_with_output()?;
    let arch = std::str::from_utf8(&output.stdout)?.trim().to_string();
    Ok(arch)
}
<|endoftext|>


<commit_before>// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::rc::Rc;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::EntropyRng;
use prng::hc128::Hc128Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// Cloning this handle just produces a new reference to the same thread-local
/// generator.
///
/// [`thread_rng`]: ../fn.thread_rng.html
#[derive(Clone, Debug)]
pub struct ThreadRng {
    rng: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>>,
}

thread_local!(
    static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>> = {
        let mut entropy_source = EntropyRng::new();
        let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    entropy_source);
        Rc::new(UnsafeCell::new(rng))
    }
);

/// Retrieve the lazily-initialized thread-local random number
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `thread_rng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// [`ReseedingRng`]: rngs/adapter/struct.ReseedingRng.html
/// [`StdRng`]: rngs/struct.StdRng.html
/// [`EntropyRng`]: rngs/struct.EntropyRng.html
/// [HC-128]: prng/hc128/struct.Hc128Rng.html
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng.get()).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng.get()).next_u64() }
    }

    fn fill_bytes(&mut self, bytes: &mut [u8]) {
        unsafe { (*self.rng.get()).fill_bytes(bytes) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng.get()).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    #[cfg(not(feature="stdweb"))]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        let mut v = [1, 1, 1];
        r.shuffle(&mut v);
        let b: &[_] = &[1, 1, 1];
        assert_eq!(v, b);
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<commit_msg>Move around ThreadRng documentation<commit_after>// Copyright 2017-2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// https://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Thread-local random number generator

use std::cell::UnsafeCell;
use std::rc::Rc;

use {RngCore, CryptoRng, SeedableRng, Error};
use rngs::adapter::ReseedingRng;
use rngs::EntropyRng;
use prng::hc128::Hc128Core;

// Rationale for using `UnsafeCell` in `ThreadRng`:
//
// Previously we used a `RefCell`, with an overhead of ~15%. There will only
// ever be one mutable reference to the interior of the `UnsafeCell`, because
// we only have such a reference inside `next_u32`, `next_u64`, etc. Within a
// single thread (which is the definition of `ThreadRng`), there will only ever
// be one of these methods active at a time.
//
// A possible scenario where there could be multiple mutable references is if
// `ThreadRng` is used inside `next_u32` and co. But the implementation is
// completely under our control. We just have to ensure none of them use
// `ThreadRng` internally, which is nonsensical anyway. We should also never run
// `ThreadRng` in destructors of its implementation, which is also nonsensical.
//
// The additional `Rc` is not strictly neccesary, and could be removed. For now
// it ensures `ThreadRng` stays `!Send` and `!Sync`, and implements `Clone`.

// Number of generated bytes after which to reseed `TreadRng`.
//
// The time it takes to reseed HC-128 is roughly equivalent to generating 7 KiB.
// We pick a treshold here that is large enough to not reduce the average
// performance too much, but also small enough to not make reseeding something
// that basically never happens.
const THREAD_RNG_RESEED_THRESHOLD: u64 = 32*1024*1024; // 32 MiB

/// The type returned by [`thread_rng`], essentially just a reference to the
/// PRNG in thread-local memory.
///
/// `ThreadRng` uses [`ReseedingRng`] wrapping the same PRNG as [`StdRng`],
/// which is reseeded after generating 32 MiB of random data. A single instance
/// is cached per thread and the returned `ThreadRng` is a reference to this
/// instance — hence `ThreadRng` is neither `Send` nor `Sync` but is safe to use
/// within a single thread. This RNG is seeded and reseeded via [`EntropyRng`]
/// as required.
///
/// Note that the reseeding is done as an extra precaution against entropy
/// leaks and is in theory unnecessary — to predict `ThreadRng`'s output, an
/// attacker would have to either determine most of the RNG's seed or internal
/// state, or crack the algorithm used.
///
/// Like [`StdRng`], `ThreadRng` is a cryptographically secure PRNG. The current
/// algorithm used is [HC-128], which is an array-based PRNG that trades memory
/// usage for better performance. This makes it similar to ISAAC, the algorithm
/// used in `ThreadRng` before rand 0.5.
///
/// Cloning this handle just produces a new reference to the same thread-local
/// generator.
///
/// [`thread_rng`]: ../fn.thread_rng.html
/// [`ReseedingRng`]: adapter/struct.ReseedingRng.html
/// [`StdRng`]: struct.StdRng.html
/// [`EntropyRng`]: struct.EntropyRng.html
/// [HC-128]: ../prng/hc128/struct.Hc128Rng.html
#[derive(Clone, Debug)]
pub struct ThreadRng {
    rng: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>>,
}

thread_local!(
    static THREAD_RNG_KEY: Rc<UnsafeCell<ReseedingRng<Hc128Core, EntropyRng>>> = {
        let mut entropy_source = EntropyRng::new();
        let r = Hc128Core::from_rng(&mut entropy_source).unwrap_or_else(|err|
                panic!("could not initialize thread_rng: {}", err));
        let rng = ReseedingRng::new(r,
                                    THREAD_RNG_RESEED_THRESHOLD,
                                    entropy_source);
        Rc::new(UnsafeCell::new(rng))
    }
);

/// Retrieve the lazily-initialized thread-local random number
/// generator, seeded by the system. Intended to be used in method
/// chaining style, e.g. `thread_rng().gen::<i32>()`, or cached locally, e.g.
/// `let mut rng = thread_rng();`.
///
/// For more information see [`ThreadRng`].
///
/// [`ThreadRng`]: rngs/struct.ThreadRng.html
pub fn thread_rng() -> ThreadRng {
    ThreadRng { rng: THREAD_RNG_KEY.with(|t| t.clone()) }
}

impl RngCore for ThreadRng {
    #[inline(always)]
    fn next_u32(&mut self) -> u32 {
        unsafe { (*self.rng.get()).next_u32() }
    }

    #[inline(always)]
    fn next_u64(&mut self) -> u64 {
        unsafe { (*self.rng.get()).next_u64() }
    }

    fn fill_bytes(&mut self, bytes: &mut [u8]) {
        unsafe { (*self.rng.get()).fill_bytes(bytes) }
    }

    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
        unsafe { (*self.rng.get()).try_fill_bytes(dest) }
    }
}

impl CryptoRng for ThreadRng {}

#[cfg(test)]
mod test {
    #[test]
    #[cfg(not(feature="stdweb"))]
    fn test_thread_rng() {
        use Rng;
        let mut r = ::thread_rng();
        r.gen::<i32>();
        let mut v = [1, 1, 1];
        r.shuffle(&mut v);
        let b: &[_] = &[1, 1, 1];
        assert_eq!(v, b);
        assert_eq!(r.gen_range(0, 1), 0);
    }
}
<|endoftext|>


<commit_before>use result::NSSResult;
use ffi::{pk11, sec};
use std::{ptr, mem};
use libc::{c_uint, c_int, c_void};

#[allow(non_camel_case_types)]
pub enum RSAPadding
{
    PKCS1v15,
    OAEP_MGF1_SHA1,
    OAEP_MGF1_SHA224,
    OAEP_MGF1_SHA256,
    OAEP_MGF1_SHA384,
    OAEP_MGF1_SHA512,
}

enum RSAPaddingParam
{
    NullParam,
    OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS),
}

impl RSAPaddingParam
{
    unsafe fn to_secitem(&self) -> sec::SECItem
    {
        match *self
        {
            NullParam => sec::SECItem::from_struct(&()),
            OAEPParam(ref param) => sec::SECItem::from_struct(param),
        }
    }
}

impl RSAPadding
{
    fn to_ckm(&self) -> pk11::CK_MECHANISM_TYPE
    {
        match *self
        {
            PKCS1v15 => pk11::CKM_RSA_PKCS,
            OAEP_MGF1_SHA1
            | OAEP_MGF1_SHA224
            | OAEP_MGF1_SHA256
            | OAEP_MGF1_SHA384
            | OAEP_MGF1_SHA512 => pk11::CKM_RSA_PKCS_OAEP,
        }
    }

    fn get_param(&self) -> RSAPaddingParam
    {
        match *self
        {
            PKCS1v15 => NullParam,
            OAEP_MGF1_SHA1 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_1)),
            OAEP_MGF1_SHA224 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_224)),
            OAEP_MGF1_SHA256 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_256)),
            OAEP_MGF1_SHA384 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_384)),
            OAEP_MGF1_SHA512 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_512)),
        }
    }
}

pub struct RSAPrivateKey
{
    key: *mut pk11::SECKEYPrivateKey,
}

impl RSAPrivateKey
{
    pub fn load(data: &[u8]) -> NSSResult<RSAPrivateKey>
    {
        try!(::nss::init());
        unsafe
        {
            let mut der = sec::SECItem::new(data);
            let slot = try!(pk11::SlotInfo::get_internal());
            let mut key = ptr::null_mut();

            try!(pk11::PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.ptr(), &mut der, ptr::null_mut(), ptr::null_mut(), false, false, pk11::KU_ALL, &mut key, ptr::null_mut()).to_result());

            Ok(RSAPrivateKey { key: key })
        }
    }

    pub fn gen(key_size_bits: uint) -> NSSResult<RSAPrivateKey>
    {
        try!(::nss::init());
        unsafe
        {
            let slot = try!(pk11::SlotInfo::get_internal());
            let mut param = pk11::PK11RSAGenParams { key_size_bits: key_size_bits as c_int, pe: 65537, };
            let param_ptr = mem::transmute::<_, *mut c_void>(&mut param);
            let mut pubkey = ptr::null_mut();
            let privkey = try_ptr!(pk11::PK11_GenerateKeyPair(slot.ptr(), pk11::CKM_RSA_PKCS_KEY_PAIR_GEN, param_ptr, &mut pubkey, false, false, ptr::null_mut()));

            pk11::SECKEY_DestroyPublicKey(pubkey);

            Ok(RSAPrivateKey { key: privkey })
        }
    }

    pub fn save(&self) -> NSSResult<Vec<u8>>
    {
        unsafe
        {
            let secitem = try_ptr!(pk11::PK11_ExportDERPrivateKeyInfo(self.key, ptr::null_mut()));
            let result = (&*secitem).copy_buf();
            sec::SECItem::free(secitem);
            Ok(result)
        }
    }

    pub fn key_len(&self) -> uint
    {
        match self.get_public()
        {
            Err(..) => 0,
            Ok(public) => public.key_len(),
        }
    }

    pub fn encrypt(&self, padding: RSAPadding, data: &[u8]) -> NSSResult<Vec<u8>>
    {
        let public = try!(self.get_public());
        public.encrypt(padding, data)
    }

    pub fn decrypt(&self, padding: RSAPadding, data: &[u8]) -> NSSResult<Vec<u8>>
    {
        unsafe
        {
            let mut out = Vec::with_capacity(self.key_len());
            let mut outlen = 0;

            let params = padding.get_param();
            let mut secitem = params.to_secitem();

            try!(pk11::PK11_PrivDecrypt(self.key, padding.to_ckm(), &mut secitem, out.as_mut_ptr(),
                                        &mut outlen, out.capacity() as c_uint, data.as_ptr(), data.len() as c_uint).to_result());
            out.set_len(outlen as uint);
            Ok(out)
        }
    }

    pub fn get_public(&self) -> NSSResult<RSAPublicKey>
    {
        unsafe
        {
            let mypub = try_ptr!(pk11::SECKEY_ConvertToPublicKey(self.key));
            Ok(RSAPublicKey { key: mypub })
        }
    }
}

impl Drop for RSAPrivateKey
{
    fn drop(&mut self)
    {
        unsafe
        {
            pk11::SECKEY_DestroyPrivateKey(self.key);
        }
    }
}

pub struct RSAPublicKey
{
    key: *mut pk11::SECKEYPublicKey,
}

impl RSAPublicKey
{
    pub fn load(data: &[u8]) -> NSSResult<RSAPublicKey>
    {
        try!(::nss::init());
        unsafe
        {
            let der = sec::SECItem::new(data);
            let spki = try_ptr!(pk11::SECKEY_DecodeDERSubjectPublicKeyInfo(&der));
            let key = try_ptr!(pk11::SECKEY_ExtractPublicKey(spki as *const pk11::CERTSubjectPublicKeyInfo));

            pk11::SECKEY_DestroySubjectPublicKeyInfo(spki);
            Ok(RSAPublicKey { key: key })
        }
    }

    pub fn save(&self) -> NSSResult<Vec<u8>>
    {
        unsafe
        {
            let secitem = try_ptr!(pk11::SECKEY_EncodeDERSubjectPublicKeyInfo(self.key as *const _));
            let result = (&*secitem).copy_buf();
            sec::SECItem::free(secitem);
            Ok(result)
        }
    }

    pub fn key_len(&self) -> uint
    {
        unsafe
        {
            pk11::SECKEY_PublicKeyStrength(self.key as *const pk11::SECKEYPublicKey) as uint
        }
    }

    pub fn encrypt(&self, padding: RSAPadding, data: &[u8]) -> NSSResult<Vec<u8>>
    {
        unsafe
        {
            let mut out = Vec::with_capacity(self.key_len());
            let mut outlen = 0;

            let params = padding.get_param();
            let mut secitem = params.to_secitem();

            try!(pk11::PK11_PubEncrypt(self.key, padding.to_ckm(), &mut secitem, out.as_mut_ptr(),
                                       &mut outlen, out.capacity() as c_uint, data.as_ptr(), data.len() as c_uint,
                                       ptr::null_mut()).to_result());
            out.set_len(outlen as uint);
            Ok(out)
        }
    }
}

impl Drop for RSAPublicKey
{
    fn drop(&mut self)
    {
        unsafe
        {
            pk11::SECKEY_DestroyPublicKey(self.key);
        }
    }
}
<commit_msg>Add tests to pkey<commit_after>use result::NSSResult;
use ffi::{pk11, sec};
use std::{ptr, mem};
use libc::{c_uint, c_int, c_void};

#[allow(non_camel_case_types)]
pub enum RSAPadding
{
    PKCS1v15,
    OAEP_MGF1_SHA1,
    OAEP_MGF1_SHA224,
    OAEP_MGF1_SHA256,
    OAEP_MGF1_SHA384,
    OAEP_MGF1_SHA512,
}

enum RSAPaddingParam
{
    NullParam,
    OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS),
}

impl RSAPaddingParam
{
    unsafe fn to_secitem(&self) -> sec::SECItem
    {
        match *self
        {
            NullParam => sec::SECItem::from_struct(&()),
            OAEPParam(ref param) => sec::SECItem::from_struct(param),
        }
    }
}

impl RSAPadding
{
    fn to_ckm(&self) -> pk11::CK_MECHANISM_TYPE
    {
        match *self
        {
            PKCS1v15 => pk11::CKM_RSA_PKCS,
            OAEP_MGF1_SHA1
            | OAEP_MGF1_SHA224
            | OAEP_MGF1_SHA256
            | OAEP_MGF1_SHA384
            | OAEP_MGF1_SHA512 => pk11::CKM_RSA_PKCS_OAEP,
        }
    }

    fn get_param(&self) -> RSAPaddingParam
    {
        match *self
        {
            PKCS1v15 => NullParam,
            OAEP_MGF1_SHA1 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_1)),
            OAEP_MGF1_SHA224 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_224)),
            OAEP_MGF1_SHA256 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_256)),
            OAEP_MGF1_SHA384 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_384)),
            OAEP_MGF1_SHA512 => OAEPParam(pk11::CK_RSA_PKCS_OAEP_PARAMS::from_algorithm(pk11::CKM_SHA_512)),
        }
    }
}

pub struct RSAPrivateKey
{
    key: *mut pk11::SECKEYPrivateKey,
}

impl RSAPrivateKey
{
    pub fn load(data: &[u8]) -> NSSResult<RSAPrivateKey>
    {
        try!(::nss::init());
        unsafe
        {
            let mut der = sec::SECItem::new(data);
            let slot = try!(pk11::SlotInfo::get_internal());
            let mut key = ptr::null_mut();

            try!(pk11::PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.ptr(), &mut der, ptr::null_mut(), ptr::null_mut(), false, false, pk11::KU_ALL, &mut key, ptr::null_mut()).to_result());

            Ok(RSAPrivateKey { key: key })
        }
    }

    pub fn gen(key_size_bits: uint) -> NSSResult<RSAPrivateKey>
    {
        try!(::nss::init());
        unsafe
        {
            let slot = try!(pk11::SlotInfo::get_internal());
            let mut param = pk11::PK11RSAGenParams { key_size_bits: key_size_bits as c_int, pe: 65537, };
            let param_ptr = mem::transmute::<_, *mut c_void>(&mut param);
            let mut pubkey = ptr::null_mut();
            let privkey = try_ptr!(pk11::PK11_GenerateKeyPair(slot.ptr(), pk11::CKM_RSA_PKCS_KEY_PAIR_GEN, param_ptr, &mut pubkey, false, false, ptr::null_mut()));

            pk11::SECKEY_DestroyPublicKey(pubkey);

            Ok(RSAPrivateKey { key: privkey })
        }
    }

    pub fn save(&self) -> NSSResult<Vec<u8>>
    {
        unsafe
        {
            let secitem = try_ptr!(pk11::PK11_ExportDERPrivateKeyInfo(self.key, ptr::null_mut()));
            let result = (&*secitem).copy_buf();
            sec::SECItem::free(secitem);
            Ok(result)
        }
    }

    pub fn key_len(&self) -> uint
    {
        match self.get_public()
        {
            Err(..) => 0,
            Ok(public) => public.key_len(),
        }
    }

    pub fn encrypt(&self, padding: RSAPadding, data: &[u8]) -> NSSResult<Vec<u8>>
    {
        let public = try!(self.get_public());
        public.encrypt(padding, data)
    }

    pub fn decrypt(&self, padding: RSAPadding, data: &[u8]) -> NSSResult<Vec<u8>>
    {
        unsafe
        {
            let mut out = Vec::with_capacity(self.key_len());
            let mut outlen = 0;

            let params = padding.get_param();
            let mut secitem = params.to_secitem();

            try!(pk11::PK11_PrivDecrypt(self.key, padding.to_ckm(), &mut secitem, out.as_mut_ptr(),
                                        &mut outlen, out.capacity() as c_uint, data.as_ptr(), data.len() as c_uint).to_result());
            out.set_len(outlen as uint);
            Ok(out)
        }
    }

    pub fn get_public(&self) -> NSSResult<RSAPublicKey>
    {
        unsafe
        {
            let mypub = try_ptr!(pk11::SECKEY_ConvertToPublicKey(self.key));
            Ok(RSAPublicKey { key: mypub })
        }
    }
}

impl Drop for RSAPrivateKey
{
    fn drop(&mut self)
    {
        unsafe
        {
            pk11::SECKEY_DestroyPrivateKey(self.key);
        }
    }
}

pub struct RSAPublicKey
{
    key: *mut pk11::SECKEYPublicKey,
}

impl RSAPublicKey
{
    pub fn load(data: &[u8]) -> NSSResult<RSAPublicKey>
    {
        try!(::nss::init());
        unsafe
        {
            let der = sec::SECItem::new(data);
            let spki = try_ptr!(pk11::SECKEY_DecodeDERSubjectPublicKeyInfo(&der));
            let key = try_ptr!(pk11::SECKEY_ExtractPublicKey(spki as *const pk11::CERTSubjectPublicKeyInfo));

            pk11::SECKEY_DestroySubjectPublicKeyInfo(spki);
            Ok(RSAPublicKey { key: key })
        }
    }

    pub fn save(&self) -> NSSResult<Vec<u8>>
    {
        unsafe
        {
            let secitem = try_ptr!(pk11::SECKEY_EncodeDERSubjectPublicKeyInfo(self.key as *const _));
            let result = (&*secitem).copy_buf();
            sec::SECItem::free(secitem);
            Ok(result)
        }
    }

    pub fn key_len(&self) -> uint
    {
        unsafe
        {
            pk11::SECKEY_PublicKeyStrength(self.key as *const pk11::SECKEYPublicKey) as uint
        }
    }

    pub fn encrypt(&self, padding: RSAPadding, data: &[u8]) -> NSSResult<Vec<u8>>
    {
        unsafe
        {
            let mut out = Vec::with_capacity(self.key_len());
            let mut outlen = 0;

            let params = padding.get_param();
            let mut secitem = params.to_secitem();

            try!(pk11::PK11_PubEncrypt(self.key, padding.to_ckm(), &mut secitem, out.as_mut_ptr(),
                                       &mut outlen, out.capacity() as c_uint, data.as_ptr(), data.len() as c_uint,
                                       ptr::null_mut()).to_result());
            out.set_len(outlen as uint);
            Ok(out)
        }
    }
}

impl Drop for RSAPublicKey
{
    fn drop(&mut self)
    {
        unsafe
        {
            pk11::SECKEY_DestroyPublicKey(self.key);
        }
    }
}

#[cfg(test)]
mod test
{
    extern crate serialize;
    use self::serialize::base64::FromBase64;

    static PUB_BASE64 : &'static [u8] = b"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL3F6TIc3JEYsugo+a2fPU3W+Epv/FeIX21DC86WYnpFtW4srFtz2oNUzyLUzDHZdb+k//8dcT3IAOzUUi3R2eMCAwEAAQ==";
    static PRIV_BASE64 : &'static [u8] = b"MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAvcXpMhzckRiy6Cj5rZ89Tdb4Sm/8V4hfbUMLzpZiekW1biysW3Pag1TPItTMMdl1v6T//x1xPcgA7NRSLdHZ4wIDAQABAkEAjh8+4qncwcmGivnM6ytbpQT+k/jEOeXG2bQhjojvnXN3FazGCEFXvpuIBcJVfaIJS9YBCMOzzrAtO0+k2hWnOQIhAOC4NVbo8FQhZS4yXM1M86kMl47FA9ui//OUfbhlAdw1AiEA2DBmIXnsboKB+OHver69p0gNeWlvcJc9bjDVfdLVsLcCIQCPtV3vGYJv2vdwxqZQaHC+YB4gIGAqOqBCbmjD3lyFLQIgA+VTYdUNoqwtZWvE4gRf7IzK2V5CCNhg3gR5RGwxN58CIGCcafoRrUKsM66ISg0ITI04G9V/w+wMx91wjEEB+QBz";

    #[test]
    fn decrypt()
    {
        static ENC_MESSAGE : &'static [u8] = b"C3fHQjn390troPLazlU5eW0A+p/wlJXv6nwPvEeDh3tCvJ8VWKdnpQbSYGEIuhiNZ8SqNepluES/izTHbXaSWA==";
        let encrypted = ENC_MESSAGE.from_base64().unwrap();

        let priv_der = PRIV_BASE64.from_base64().unwrap();
        let privkey = super::RSAPrivateKey::load(priv_der.as_slice()).unwrap();

        let message = privkey.decrypt(super::OAEP_MGF1_SHA1, encrypted.as_slice()).unwrap();
        assert_eq!(b"Encrypt Me!", message.as_slice());
    }

    #[test]
    fn priv_pub()
    {
        let priv_der = PRIV_BASE64.from_base64().unwrap();
        let pub_der = PUB_BASE64.from_base64().unwrap();

        let privkey = super::RSAPrivateKey::load(priv_der.as_slice()).unwrap();
        let pubkey = privkey.get_public().unwrap();

        let derivedpub_der = pubkey.save().unwrap();
        assert_eq!(pub_der, derivedpub_der);
    }
}
<|endoftext|>


<commit_before>#[doc = "Generate markdown from a document tree"];

import std::io;
import std::io::writer_util;

export mk_pass;

fn mk_pass(
    writer: fn~() -> io::writer
) -> pass {
    ret fn~(
        _srv: astsrv::srv,
        doc: doc::cratedoc
    ) -> doc::cratedoc {
        write_markdown(doc, writer());
        doc
    };
}

type ctxt = {
    w: io::writer,
    mutable depth: uint
};

fn write_markdown(
    doc: doc::cratedoc,
    writer: io::writer
) {
    let ctxt = {
        w: writer,
        mutable depth: 1u
    };

    write_crate(ctxt, doc);
}

fn write_header(ctxt: ctxt, title: str) {
    let hashes = str::from_chars(vec::init_elt('#', ctxt.depth));
    ctxt.w.write_line(#fmt("%s %s", hashes, title));
    ctxt.w.write_line("");
}

fn subsection(ctxt: ctxt, f: fn&()) {
    ctxt.depth += 1u;
    f();
    ctxt.depth -= 1u;
}

fn write_crate(
    ctxt: ctxt,
    doc: doc::cratedoc
) {
    write_header(ctxt, #fmt("Crate %s", doc.topmod.name));
    write_top_module(ctxt, doc.topmod);
}

fn write_top_module(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    write_mod_contents(ctxt, moddoc);
}

fn write_mod(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    write_header(ctxt, #fmt("Module `%s`", moddoc.name));
    write_mod_contents(ctxt, moddoc);
}

fn write_mod_contents(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    for fndoc in *moddoc.fns {
        subsection(ctxt) {||
            write_fn(ctxt, fndoc);
        }
    }

    for moddoc in *moddoc.mods {
        subsection(ctxt) {||
            write_mod(ctxt, moddoc);
        }
    }
}

fn write_fn(
    ctxt: ctxt,
    doc: doc::fndoc
) {
    write_header(ctxt, #fmt("Function `%s`", doc.name));
    alt doc.brief {
      some(brief) {
        ctxt.w.write_line(brief);
        ctxt.w.write_line("");
      }
      none. { }
    }
    alt doc.desc {
        some(_d) {
            ctxt.w.write_line("");
            ctxt.w.write_line(_d);
            ctxt.w.write_line("");
        }
        none. { }
    }
    for (arg, desc) in doc.args {
        ctxt.w.write_str("### Argument `" + arg + "`: ");
        ctxt.w.write_str(desc)
    }
    alt doc.return {
      some(doc) {
        alt doc.ty {
          some(ty) {
            ctxt.w.write_line("### Returns `" + ty + "`");
            alt doc.desc {
              some(d) {
                ctxt.w.write_line(d);
              }
              none. { }
            }
          }
          none. { fail "unimplemented"; }
        }
      }
      none. { }
    }
}

#[cfg(test)]
mod tests {
    fn render(source: str) -> str {
        let srv = astsrv::mk_srv_from_str(source);
        let doc = extract::from_srv(srv, "");
        let doc = attr_pass::mk_pass()(srv, doc);
        write_markdown_str(doc)
    }

    fn write_markdown_str(
        doc: doc::cratedoc
    ) -> str {
        let buffer = io::mk_mem_buffer();
        let writer = io::mem_buffer_writer(buffer);
        write_markdown(doc, writer);
        ret io::mem_buffer_str(buffer);
    }

    #[test]
    fn write_markdown_should_write_crate_header() {
        let srv = astsrv::mk_srv_from_str("");
        let doc = extract::from_srv(srv, "belch");
        let doc = attr_pass::mk_pass()(srv, doc);
        let markdown = write_markdown_str(doc);
        assert str::contains(markdown, "# Crate belch");
    }

    #[test]
    fn write_markdown_should_write_function_header() {
        let markdown = render("fn func() { }");
        assert str::contains(markdown, "## Function `func`");
    }

    #[test]
    fn write_markdown_should_write_mod_headers() {
        let markdown = render("mod moo { }");
        assert str::contains(markdown, "## Module `moo`");
    }

    #[test]
    fn should_leave_blank_line_after_header() {
        let markdown = render("mod morp { }");
        assert str::contains(markdown, "Module `morp`\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_fn_header_and_brief() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "Function `a`\n\nbrief");
    }

    #[test]
    fn should_leve_blank_line_after_brief() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "brief\n\n");
    }
}<commit_msg>rustdoc: Extract various gen functions<commit_after>#[doc = "Generate markdown from a document tree"];

import std::io;
import std::io::writer_util;

export mk_pass;

fn mk_pass(
    writer: fn~() -> io::writer
) -> pass {
    ret fn~(
        _srv: astsrv::srv,
        doc: doc::cratedoc
    ) -> doc::cratedoc {
        write_markdown(doc, writer());
        doc
    };
}

type ctxt = {
    w: io::writer,
    mutable depth: uint
};

fn write_markdown(
    doc: doc::cratedoc,
    writer: io::writer
) {
    let ctxt = {
        w: writer,
        mutable depth: 1u
    };

    write_crate(ctxt, doc);
}

fn write_header(ctxt: ctxt, title: str) {
    let hashes = str::from_chars(vec::init_elt('#', ctxt.depth));
    ctxt.w.write_line(#fmt("%s %s", hashes, title));
    ctxt.w.write_line("");
}

fn subsection(ctxt: ctxt, f: fn&()) {
    ctxt.depth += 1u;
    f();
    ctxt.depth -= 1u;
}

fn write_crate(
    ctxt: ctxt,
    doc: doc::cratedoc
) {
    write_header(ctxt, #fmt("Crate %s", doc.topmod.name));
    write_top_module(ctxt, doc.topmod);
}

fn write_top_module(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    write_mod_contents(ctxt, moddoc);
}

fn write_mod(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    write_header(ctxt, #fmt("Module `%s`", moddoc.name));
    write_mod_contents(ctxt, moddoc);
}

fn write_mod_contents(
    ctxt: ctxt,
    moddoc: doc::moddoc
) {
    for fndoc in *moddoc.fns {
        subsection(ctxt) {||
            write_fn(ctxt, fndoc);
        }
    }

    for moddoc in *moddoc.mods {
        subsection(ctxt) {||
            write_mod(ctxt, moddoc);
        }
    }
}

fn write_fn(
    ctxt: ctxt,
    doc: doc::fndoc
) {
    write_header(ctxt, #fmt("Function `%s`", doc.name));
    write_brief(ctxt, doc.brief);
    write_desc(ctxt, doc.desc);
    write_args(ctxt, doc.args);
    write_return(ctxt, doc.return);
}

fn write_brief(
    ctxt: ctxt,
    brief: option<str>
) {
    alt brief {
      some(brief) {
        ctxt.w.write_line(brief);
        ctxt.w.write_line("");
      }
      none. { }
    }
}

fn write_desc(
    ctxt: ctxt,
    desc: option<str>
) {
    alt desc {
        some(_d) {
            ctxt.w.write_line("");
            ctxt.w.write_line(_d);
            ctxt.w.write_line("");
        }
        none. { }
    }
}

fn write_args(
    ctxt: ctxt,
    args: [(str, str)]
) {
    for (arg, desc) in args {
        ctxt.w.write_str("### Argument `" + arg + "`: ");
        ctxt.w.write_str(desc)
    }
}

fn write_return(
    ctxt: ctxt,
    return: option<doc::retdoc>
) {
    alt return {
      some(doc) {
        alt doc.ty {
          some(ty) {
            ctxt.w.write_line("### Returns `" + ty + "`");
            alt doc.desc {
              some(d) {
                ctxt.w.write_line(d);
              }
              none. { }
            }
          }
          none. { fail "unimplemented"; }
        }
      }
      none. { }
    }
}

#[cfg(test)]
mod tests {
    fn render(source: str) -> str {
        let srv = astsrv::mk_srv_from_str(source);
        let doc = extract::from_srv(srv, "");
        let doc = attr_pass::mk_pass()(srv, doc);
        write_markdown_str(doc)
    }

    fn write_markdown_str(
        doc: doc::cratedoc
    ) -> str {
        let buffer = io::mk_mem_buffer();
        let writer = io::mem_buffer_writer(buffer);
        write_markdown(doc, writer);
        ret io::mem_buffer_str(buffer);
    }

    #[test]
    fn write_markdown_should_write_crate_header() {
        let srv = astsrv::mk_srv_from_str("");
        let doc = extract::from_srv(srv, "belch");
        let doc = attr_pass::mk_pass()(srv, doc);
        let markdown = write_markdown_str(doc);
        assert str::contains(markdown, "# Crate belch");
    }

    #[test]
    fn write_markdown_should_write_function_header() {
        let markdown = render("fn func() { }");
        assert str::contains(markdown, "## Function `func`");
    }

    #[test]
    fn write_markdown_should_write_mod_headers() {
        let markdown = render("mod moo { }");
        assert str::contains(markdown, "## Module `moo`");
    }

    #[test]
    fn should_leave_blank_line_after_header() {
        let markdown = render("mod morp { }");
        assert str::contains(markdown, "Module `morp`\n\n");
    }

    #[test]
    fn should_leave_blank_line_between_fn_header_and_brief() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "Function `a`\n\nbrief");
    }

    #[test]
    fn should_leve_blank_line_after_brief() {
        let markdown = render("#[doc(brief = \"brief\")] fn a() { }");
        assert str::contains(markdown, "brief\n\n");
    }
}<|endoftext|>


<commit_before>use gfx;
use std::ops::Add;

gfx_defines! {
  constant TileMapData {
    data: [f32; 4] = "data",
  }

  constant TilemapSettings {
    world_size: [f32; 2] = "u_WorldSize",
    tilesheet_size: [f32; 2] = "u_TilesheetSize",
  }

  vertex VertexData {
    pos: [f32; 2] = "a_Pos",
    buf_pos: [f32; 2] = "a_BufPos",
  }

  constant CharacterSheet {
    x_div: f32 = "x_div",
    y_div: f32 = "y_div",
    row_idx: u32 = "a_row",
    index: f32 = "a_index",
  }

  constant Position {
    position: [f32; 2] = "a_position",
  }

  pipeline bullet_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    projection_cb: gfx::ConstantBuffer<Projection> = "b_VsLocals",
    position_cb: gfx::ConstantBuffer<Position> = "b_BulletPosition",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  pipeline critter_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    projection_cb: gfx::ConstantBuffer<Projection> = "b_VsLocals",
    position_cb: gfx::ConstantBuffer<Position> = "b_CharacterPosition",
    character_sprite_cb: gfx::ConstantBuffer<CharacterSheet> = "b_CharacterSprite",
    charactersheet: gfx::TextureSampler<[f32; 4]> = "t_CharacterSheet",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  pipeline tilemap_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    position_cb: gfx::ConstantBuffer<Position> = "b_TileMapPosition",
    projection_cb: gfx::ConstantBuffer<Projection> = "b_VsLocals",
    tilemap: gfx::ConstantBuffer<TileMapData> = "b_TileMap",
    tilemap_cb: gfx::ConstantBuffer<TilemapSettings> = "b_PsLocals",
    tilesheet: gfx::TextureSampler<[f32; 4]> = "t_TileSheet",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  pipeline static_element_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    position_cb: gfx::ConstantBuffer<Position> = "b_StaticElementPosition",
    projection_cb: gfx::ConstantBuffer<Projection> = "b_VsLocals",
    static_element_sheet: gfx::TextureSampler<[f32; 4]> = "t_StaticElementSheet",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  pipeline text_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    position_cb: gfx::ConstantBuffer<Position> = "b_TextPosition",
    text_sheet: gfx::TextureSampler<[f32; 4]> = "t_TextSheet",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  constant Projection {
    model: [[f32; 4]; 4] = "u_Model",
    view: [[f32; 4]; 4] = "u_View",
    proj: [[f32; 4]; 4] = "u_Proj",
  }
}

impl VertexData {
  pub fn new(pos: [f32; 2], buf_pos: [f32; 2]) -> VertexData {
    VertexData {
      pos,
      buf_pos,
    }
  }
}

impl TileMapData {
  pub fn new_empty() -> TileMapData {
    TileMapData { data: [32.0, 32.0, 0.0, 0.0] }
  }

  pub fn new(data: [f32; 4]) -> TileMapData {
    TileMapData { data }
  }
}

impl Position {
  pub fn new(position: [f32; 2]) -> Position { Position { position } }
}

impl Add for Position {
  type Output = Position;

  fn add(self, other: Position) -> Position {
    Position::new([self.position[0] + other.position[0], self.position[1] + other.position[1]])
  }
}
<commit_msg>Implement Display trait for Position type<commit_after>use gfx;
use std::{fmt::{Display, Formatter, Result}, ops::Add};

gfx_defines! {
  constant TileMapData {
    data: [f32; 4] = "data",
  }

  constant TilemapSettings {
    world_size: [f32; 2] = "u_WorldSize",
    tilesheet_size: [f32; 2] = "u_TilesheetSize",
  }

  vertex VertexData {
    pos: [f32; 2] = "a_Pos",
    buf_pos: [f32; 2] = "a_BufPos",
  }

  constant CharacterSheet {
    x_div: f32 = "x_div",
    y_div: f32 = "y_div",
    row_idx: u32 = "a_row",
    index: f32 = "a_index",
  }

  constant Position {
    position: [f32; 2] = "a_position",
  }

  pipeline bullet_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    projection_cb: gfx::ConstantBuffer<Projection> = "b_VsLocals",
    position_cb: gfx::ConstantBuffer<Position> = "b_BulletPosition",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  pipeline critter_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    projection_cb: gfx::ConstantBuffer<Projection> = "b_VsLocals",
    position_cb: gfx::ConstantBuffer<Position> = "b_CharacterPosition",
    character_sprite_cb: gfx::ConstantBuffer<CharacterSheet> = "b_CharacterSprite",
    charactersheet: gfx::TextureSampler<[f32; 4]> = "t_CharacterSheet",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  pipeline tilemap_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    position_cb: gfx::ConstantBuffer<Position> = "b_TileMapPosition",
    projection_cb: gfx::ConstantBuffer<Projection> = "b_VsLocals",
    tilemap: gfx::ConstantBuffer<TileMapData> = "b_TileMap",
    tilemap_cb: gfx::ConstantBuffer<TilemapSettings> = "b_PsLocals",
    tilesheet: gfx::TextureSampler<[f32; 4]> = "t_TileSheet",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  pipeline static_element_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    position_cb: gfx::ConstantBuffer<Position> = "b_StaticElementPosition",
    projection_cb: gfx::ConstantBuffer<Projection> = "b_VsLocals",
    static_element_sheet: gfx::TextureSampler<[f32; 4]> = "t_StaticElementSheet",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  pipeline text_pipeline {
    vbuf: gfx::VertexBuffer<VertexData> = (),
    position_cb: gfx::ConstantBuffer<Position> = "b_TextPosition",
    text_sheet: gfx::TextureSampler<[f32; 4]> = "t_TextSheet",
    out_color: gfx::RenderTarget<gfx::format::Rgba8> = "Target0",
    out_depth: gfx::DepthTarget<gfx::format::DepthStencil> = gfx::preset::depth::LESS_EQUAL_WRITE,
  }

  constant Projection {
    model: [[f32; 4]; 4] = "u_Model",
    view: [[f32; 4]; 4] = "u_View",
    proj: [[f32; 4]; 4] = "u_Proj",
  }
}

impl VertexData {
  pub fn new(pos: [f32; 2], buf_pos: [f32; 2]) -> VertexData {
    VertexData {
      pos,
      buf_pos,
    }
  }
}

impl TileMapData {
  pub fn new_empty() -> TileMapData {
    TileMapData { data: [32.0, 32.0, 0.0, 0.0] }
  }

  pub fn new(data: [f32; 4]) -> TileMapData {
    TileMapData { data }
  }
}

impl Position {
  pub fn new(position: [f32; 2]) -> Position { Position { position } }
}

impl Add for Position {
  type Output = Position;

  fn add(self, other: Position) -> Position {
    Position::new([self.position[0] + other.position[0], self.position[1] + other.position[1]])
  }
}

impl Display for Position {
  fn fmt(&self, f: &mut Formatter) -> Result {
    write!(f, "{}, {}", self.position[0], self.position[1])
  }
}
<|endoftext|>


<commit_before>extern crate test;
extern crate time;

use std::os::args;
use test::black_box;
use time::precise_time_ns;

#[deriving(Eq,FromPrimitive)]
enum Day {
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
}

impl Day {
    fn advance(&self, days: uint) -> Day {
        FromPrimitive::from_uint((*self as uint + days) % 7).unwrap()
    }
}

enum Month {
    January, February, March, April, May, June, July, August, September,
    October, November, December,
}

static MONTHS: [Month, ..12] = [January, February, March, April, May, June,
                                July, August, September, October, November,
                                December];

impl Month {
    fn days(&self, year: Year) -> uint {
        match *self {
            January | March | May | July | August | October | December => 31,
            April | June | September | November => 30,
            February => if year.is_leap() { 29 } else { 28 },
        }
    }
}

type Year = uint;

trait Leap {
    fn is_leap(&self) -> bool;
}

impl Leap for Year {
    fn is_leap(&self) -> bool {
        if *self % 400 == 0 {
            true
        } else if *self % 100 == 0 {
            false
        } else if *self % 4 == 0 {
            true
        } else {
            false
        }
    }
}

#[inline]
fn f() -> u64 {
    let mut count = 0;
    let mut today = Monday;

    for year in range(1900 as Year, 2001) {
        for month in MONTHS.iter() {
            today = today.advance(month.days(year));

            if year != 1900 && today == Sunday {
                count += 1;
            }
        }
    }

    count
}

fn main() {
    match args().as_slice() {
        [_] => {
            println!("{}", f());
        },
        [_, ref iters] => {
            let iters: u64 = from_str(iters.as_slice()).unwrap();

            let start = precise_time_ns();
            for _ in range(0, iters) {
                black_box(f());
            }
            let end = precise_time_ns();

            println!("{}", end - start);
        },
        _ => unreachable!(),
    }
}
<commit_msg>019.rs: temporarily use TotalEq instead of Eq<commit_after>extern crate test;
extern crate time;

use std::os::args;
use test::black_box;
use time::precise_time_ns;

#[deriving(FromPrimitive,PartialEq,TotalEq)]
enum Day {
    Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday,
}

impl Day {
    fn advance(&self, days: uint) -> Day {
        FromPrimitive::from_uint((*self as uint + days) % 7).unwrap()
    }
}

enum Month {
    January, February, March, April, May, June, July, August, September,
    October, November, December,
}

static MONTHS: [Month, ..12] = [January, February, March, April, May, June,
                                July, August, September, October, November,
                                December];

impl Month {
    fn days(&self, year: Year) -> uint {
        match *self {
            January | March | May | July | August | October | December => 31,
            April | June | September | November => 30,
            February => if year.is_leap() { 29 } else { 28 },
        }
    }
}

type Year = uint;

trait Leap {
    fn is_leap(&self) -> bool;
}

impl Leap for Year {
    fn is_leap(&self) -> bool {
        if *self % 400 == 0 {
            true
        } else if *self % 100 == 0 {
            false
        } else if *self % 4 == 0 {
            true
        } else {
            false
        }
    }
}

#[inline]
fn f() -> u64 {
    let mut count = 0;
    let mut today = Monday;

    for year in range(1900 as Year, 2001) {
        for month in MONTHS.iter() {
            today = today.advance(month.days(year));

            if year != 1900 && today == Sunday {
                count += 1;
            }
        }
    }

    count
}

fn main() {
    match args().as_slice() {
        [_] => {
            println!("{}", f());
        },
        [_, ref iters] => {
            let iters: u64 = from_str(iters.as_slice()).unwrap();

            let start = precise_time_ns();
            for _ in range(0, iters) {
                black_box(f());
            }
            let end = precise_time_ns();

            println!("{}", end - start);
        },
        _ => unreachable!(),
    }
}
<|endoftext|>


<commit_before>use SearchInfo;

use bitboard::Board;
use bitboard::Move;
use bitboard::Turn;
use bitboard::empty_movelist;

use heuristic::Heuristic;

use std::i32;
use std::time::Instant;

use rand::Rng;

const DEPTH : u8 = 3;

pub fn pvs<H: Heuristic>(info : &mut SearchInfo, hr: &mut H, bb : Board, mut alpha : i32, mut beta : i32, depth : u8, msleft : u64) -> (Move, i32) {
    if depth <= DEPTH {
        info.check_timeout(msleft);
        if info.to {
            return (Move::null(), 0);
        } else {
            return (Move::null(), pvs_no_tt(info, hr, bb, alpha, beta, depth));
        }
    }

    info.sr += 1;

    {//transposition table code
        let (l,h) = info.tt.fetch(bb);

        if l >= beta  { return (Move::null(), l); }
        alpha = if l > alpha {l} else {alpha};

        if h <= alpha { return (Move::null(), h); }
        beta = if h < beta {h} else {beta};
    }

    if bb.is_done() {
        return (Move::null(), hr.evaluate(bb, Turn::BLACK));
    } else if depth == 0 {
        return (Move::null(), hr.evaluate(bb, Turn::BLACK));
    }

    let mut mvs = empty_movelist();
    let n = bb.get_moves(&mut mvs) as usize;

    //order moves (random for now TODO: make history heuristic, etc)
    info.rn.shuffle(&mut mvs[0..n]);

    //search
    let mut g = i32::MIN;
    let mut m = Move::null();
    {
        let mut bc = bb.copy();
        bc.f_do_move(mvs[0]);
        let score = -pvs(info, hr, bc, -beta, -alpha, depth-1, msleft).1;

        if info.to {
            return (Move::null(), 0);
        }

        g = if g < score {m = mvs[0]; score} else {g};
        alpha = if alpha < score {score} else {alpha};
    }

    for i in 1..n {
        let mut bc = bb.copy();
        bc.f_do_move(mvs[i]);

        let mut score = -pvs(info, hr, bc, -alpha-1, -alpha, depth-1, msleft).1;
        if alpha < score && score < beta {
            score = -pvs(info, hr, bc, -beta, -alpha, depth-1, msleft).1;
        }

        g = if g < score {m = mvs[i]; score} else {g};
        alpha = if alpha < score {score} else {alpha};
        if alpha >= beta {break;}
    }

    let mut low = i32::MIN;
    let mut high = i32::MAX;

    if g <= alpha               { high = g; }
    if g > alpha && g < beta    { high = g; low = g; }
    if g >= beta                { low = g; }

    info.tt.update(bb, low, high);

    (m, g)
}

fn pvs_no_tt<H: Heuristic>(info : &mut SearchInfo, hr: &mut H, bb : Board, mut alpha : i32, beta : i32, depth : u8) -> i32 {

    info.sr += 1;

    if bb.is_done() {
        return hr.evaluate(bb, Turn::BLACK);
    } else if depth == 0 {
        return hr.evaluate(bb, Turn::BLACK);
    }

    let mut mvs = empty_movelist();
    let n = bb.get_moves(&mut mvs) as usize;

    //order moves (random for now TODO: make history heuristic, etc)
    info.rn.shuffle(&mut mvs[0..n]);

    //search
    let mut g = i32::MIN;
    let mut m = Move::null();
    {
        let mut bc = bb.copy();
        bc.f_do_move(mvs[0]);
        let score = -pvs_no_tt(info, hr, bc, -beta, -alpha, depth-1);

        g = if g < score {score} else {g};
        alpha = if alpha < score {score} else {alpha};
    }

    for i in 1..n {
        let mut bc = bb.copy();
        bc.f_do_move(mvs[i]);

        let mut score = -pvs_no_tt(info, hr, bc, -alpha-1, -alpha, depth-1);
        if alpha < score && score < beta {
            score = -pvs_no_tt(info, hr, bc, -beta, -alpha, depth-1);
        }

        g = if g < score {score} else {g};
        alpha = if alpha < score {score} else {alpha};
        if alpha >= beta {break;}
    }

    g
}

pub fn pvs_id<H: Heuristic>(bb : Board, hr : &mut [H], hz : &mut H, max_depth : u8, msleft : u64) -> Move {
    use search::SearchInfo;

    let mut d = 5;
    let mut info = SearchInfo::new();
    let mut best_move = Move::null();
    let empty = bb.get_empty();

    eprintln!("Starting ID PVS...");
    eprintln!("[COIN]: | {: <5} | {: <9} | {: <13} | {: <14} | {: <14} | {: <12} |",
            "Depth", "Best Move", "Minimax Value", "Transpositions", "Nodes Searched", "Time Elapsed");
    eprintln!("[COIN]: |{0:-<7}|{0:-<11}|{0:-<15}|{0:-<16}|{0:-<16}|{0:-<14}|", "");
    while d < max_depth && d <= empty + 2 {

        info.tt.clear();

        //select heuristic
        let hi = empty as i32 - d as i32;

        let (m, s) = if hi <= 0 {
            pvs(&mut info, hz, bb.copy(), i32::MIN+1, i32::MAX-1, d, msleft);
        } else {
            pvs(&mut info, hr[(i/3) as usize], bb.copy(), i32::MIN+1, i32::MAX-1, d, msleft);
        }

        if info.to {
            return best_move;
        }

        best_move = m;

        let elapsed = {
            let d = info.st.elapsed();
            (d.as_secs() as f32) + (d.subsec_nanos() as f32)/1_000_000_000f32
        };

        eprintln!("[COIN]: | {: >5} | {: >9} | {: >13} | {: >14} | {: >14} | {: >12.2} |",
                d, format!("{}",best_move), s, info.tt.size(), info.sr, elapsed);

        d += 2;
    }

    best_move
}<commit_msg>added a history heuristic among other improvements to the PVS algorithm<commit_after>use SearchInfo;

use bitboard::Board;
use bitboard::Move;
use bitboard::Turn;
use bitboard::empty_movelist;
use bitboard::empty_moveorder;

use heuristic::Heuristic;

use std::i32;
use std::time::Instant;

use rand::Rng;

const DEPTH : u8 = 3;

pub fn pvs<H: Heuristic>(info : &mut SearchInfo, hr: &mut H, bb : Board, mut alpha : i32, mut beta : i32, depth : u8, color : u8, msleft : u64) -> (Move, i32) {
    if depth <= DEPTH {
        info.check_timeout(msleft);
        if info.to {
            return (Move::null(), 0);
        } else {
            return (Move::null(), pvs_no_tt(info, hr, bb, alpha, beta, depth));
        }
    }

    info.sr += 1;

    {//transposition table code
        let (l,h) = info.tt.fetch(bb);

        if l >= beta  { return (Move::null(), l); }
        alpha = if l > alpha {l} else {alpha};

        if h <= alpha { return (Move::null(), h); }
        beta = if h < beta {h} else {beta};
    }

    if bb.is_done() {
        let p = bb.count_pieces();
        return (Move::null(), (p.0 as i32 - p.1 as i32) * 10_000);
    } else if depth == 0 {
        return (Move::null(), hr.evaluate(bb, Turn::BLACK));
    }

    let mut mvs = empty_movelist();
    let n = bb.get_moves(&mut mvs) as usize;

    //order moves (random for now TODO: make history heuristic, etc)
    let mut order = empty_moveorder();
    for i in 0..n {
        order[i] = (info.hs[color as usize][mvs[i].offset() as usize], i);
    }

    order[0..n].sort();
    order[0..n].reverse();

    // info.rn.shuffle(&mut mvs[0..n]);

    //search
    let mut g = i32::MIN;
    let mut m = Move::null();
    {
        let mut bc = bb.copy();
        bc.f_do_move(mvs[order[0].1]);
        let score = -pvs(info, hr, bc, -beta, -alpha, depth-1, color^1, msleft).1;

        if info.to {
            return (Move::null(), 0);
        }

        g = if g < score {m = mvs[order[0].1]; score} else {g};
        alpha = if alpha < score {score} else {alpha};
    }

    for i in 1..n {
        if alpha >= beta {
            info.hs[color as usize][m.offset() as usize] += (depth * depth) as i32;
            break;
        }

        let mut bc = bb.copy();
        let mv = mvs[order[i].1];
        bc.f_do_move(mv);

        let mut score = -pvs(info, hr, bc, -alpha-1, -alpha, depth-1, color^1, msleft).1;
        if alpha < score && score < beta {
            score = -pvs(info, hr, bc, -beta, -alpha, depth-1, color^1, msleft).1;
        }

        g = if g < score {m = mv; score} else {g};
        alpha = if alpha < score {score} else {alpha};
    }

    let mut low = i32::MIN;
    let mut high = i32::MAX;

    if g <= alpha               { high = g; }
    if g > alpha && g < beta    { high = g; low = g; }
    if g >= beta                { low = g; }

    info.tt.update(bb, low, high);

    (m, g)
}

fn pvs_no_tt<H: Heuristic>(info : &mut SearchInfo, hr: &mut H, bb : Board, mut alpha : i32, beta : i32, depth : u8) -> i32 {

    info.sr += 1;

    if bb.is_done() {
        let p = bb.count_pieces();
        return (p.0 as i32 - p.1 as i32) * 10_000;
    } else if depth == 0 {
        return hr.evaluate(bb, Turn::BLACK);
    }

    let mut mvs = empty_movelist();
    let n = bb.get_moves(&mut mvs) as usize;

    //order moves (random for now TODO: make history heuristic, etc)
    // info.rn.shuffle(&mut mvs[0..n]);

    //search
    let mut g = i32::MIN;
    let mut m = Move::null();
    {
        let mut bc = bb.copy();
        bc.f_do_move(mvs[0]);
        let score = -pvs_no_tt(info, hr, bc, -beta, -alpha, depth-1);

        g = if g < score {score} else {g};
        alpha = if alpha < score {score} else {alpha};
    }

    for i in 1..n {
        if alpha >= beta {break;}

        let mut bc = bb.copy();
        bc.f_do_move(mvs[i]);

        let mut score = -pvs_no_tt(info, hr, bc, -alpha-1, -alpha, depth-1);
        if alpha < score && score < beta {
            score = -pvs_no_tt(info, hr, bc, -beta, -alpha, depth-1);
        }

        g = if g < score {score} else {g};
        alpha = if alpha < score {score} else {alpha};
    }

    g
}

pub fn pvs_id<Hf: Heuristic + Clone, Hz: Heuristic + Clone>(bb : Board, hr : &mut [Box<Hf>], hz : &mut Hz, max_depth : u8, msleft : u64) -> Move {
    use search::SearchInfo;

    let mut d = 5;
    if max_depth < d {d = max_depth};
    let mut info = SearchInfo::new();
    let mut best_move = Move::null();
    let empty = bb.total_empty();

    eprintln!("Starting ID PVS...");
    eprintln!("[COIN]: |{0:-<7}|{0:-<11}|{0:-<15}|{0:-<16}|{0:-<16}|{0:-<14}|", "");
    eprintln!("[COIN]: | {: <5} | {: <9} | {: <13} | {: <14} | {: <14} | {: <12} |",
            "Depth", "Best Move", "Minimax Value", "Transpositions", "Nodes Searched", "Time Elapsed");
    eprintln!("[COIN]: |{0:-<7}|{0:-<11}|{0:-<15}|{0:-<16}|{0:-<16}|{0:-<14}|", "");

    while d <= max_depth && d <= empty + 2 {

        info.tt.clear();
        info.reset_history();

        //select heuristic
        let hi = empty as i32 - d as i32;

        let (m, s) = if hi <= 0 {
            pvs(&mut info, hz, bb.copy(), i32::MIN+1, i32::MAX-1, d, 0, msleft)
        } else {
            pvs(&mut info, &mut (*hr[(hi/3) as usize].clone()), bb.copy(), i32::MIN+1, i32::MAX-1, d, 0, msleft)
        };

        if info.to {
            eprintln!("[COIN]: |{0:-<7}|{0:-<11}|{0:-<15}|{0:-<16}|{0:-<16}|{0:-<14}|", "");
            eprintln!("[COIN]: TIMEOUT");
            return best_move;
        }

        best_move = m;

        let elapsed = {
            let d = info.st.elapsed();
            (d.as_secs() as f32) + (d.subsec_nanos() as f32)/1_000_000_000f32
        };

        eprintln!("[COIN]: | {: >5} | {: >9} | {: >13} | {: >14} | {: >14} | {: >12.2} |",
                d, format!("{}",best_move), s, info.tt.size(), info.sr, elapsed);

        d += 2;
    }
    eprintln!("[COIN]: |{0:-<7}|{0:-<11}|{0:-<15}|{0:-<16}|{0:-<16}|{0:-<14}|", "");

    best_move
}<|endoftext|>


<commit_before>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

use super::Term;

pub fn handle(term: &mut Term, ch: char) {
    match ch {
        '\x1b' => { // Escape key
            term.cursor.save_pos();
            if term.cursor.pos.x > 0 {
                term.cursor.pos.x -= 1;
            }

            term.editor.switch_mode();
        }
        '\x7f' => { // Backspace key
            let line = term.current_line() + term.cursor.pos.y;
            term.cursor.save_pos();

            if term.cursor.pos.x == 0 {
                let mut rem = term.editor.contents[line].clone();
                let pos = term.editor.contents[line - 1].len() - 1;

                term.editor.contents[line - 1].remove(pos);
                term.editor.contents[line - 1].append(&mut rem);
                term.editor.contents.remove(line);

                if term.cursor.pos.y != 0 {
                    term.cursor.pos.y -= 1;
                }

                term.cursor.pos.x = pos;
                term.redraw_file();
            } else {
                term.cursor.pos.x -= 1;
                let pos = term.cursor.pos.x;

                term.editor.contents[line].remove(pos);
                term.redraw_file();
            }
        }
        '\r' => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            let mut rem = term.editor.contents[line].split_off(pos);
            rem.push(b'\n');
            term.editor.contents.insert(line + 1, rem);

            term.cursor.save_pos();
            term.cursor.pos.x = 0;
            term.cursor.pos.y += 1;

            term.redraw_file();
        }
        '\t' => {
            for i in 0..4 {
                let x = term.cursor.pos.x + i;
                term.term[(x, term.cursor.pos.y)].set_ch(' ');
            }

            term.cursor.save_pos();
            term.cursor.pos.x += 4;
        }
        c @ _ => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            term.editor.contents[line].insert(pos, c as u8);

            term.cursor.save_pos();
            term.cursor.pos.x += 1;
            term.redraw_file();
        }
    }
}
<commit_msg>Implement TAB<commit_after>/* Copyright (C)  2016 nokaa <nokaa@cock.li>
 * This software is licensed under the terms of the
 * GNU Affero General Public License. You should have
 * received a copy of this license with this software.
 * The license may also be found at https://gnu.org/licenses/agpl.txt
 */

use super::Term;

pub fn handle(term: &mut Term, ch: char) {
    match ch {
        '\x1b' => { // Escape key
            term.cursor.save_pos();
            if term.cursor.pos.x > 0 {
                term.cursor.pos.x -= 1;
            }

            term.editor.switch_mode();
        }
        '\x7f' => { // Backspace key
            let line = term.current_line() + term.cursor.pos.y;
            term.cursor.save_pos();

            if term.cursor.pos.x == 0 {
                let mut rem = term.editor.contents[line].clone();
                let pos = term.editor.contents[line - 1].len() - 1;

                term.editor.contents[line - 1].remove(pos);
                term.editor.contents[line - 1].append(&mut rem);
                term.editor.contents.remove(line);

                if term.cursor.pos.y != 0 {
                    term.cursor.pos.y -= 1;
                }

                term.cursor.pos.x = pos;
                term.redraw_file();
            } else {
                term.cursor.pos.x -= 1;
                let pos = term.cursor.pos.x;

                term.editor.contents[line].remove(pos);
                term.redraw_file();
            }
        }
        '\r' => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            let mut rem = term.editor.contents[line].split_off(pos);
            rem.push(b'\n');
            term.editor.contents.insert(line + 1, rem);

            term.cursor.save_pos();
            term.cursor.pos.x = 0;
            term.cursor.pos.y += 1;

            term.redraw_file();
        }
        '\t' => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            for i in 0..4 {
                term.editor.contents[line].insert(pos, b' ');
            }

            term.cursor.save_pos();
            term.cursor.pos.x += 4;
            term.redraw_file();
        }
        c @ _ => {
            let line = term.current_line() + term.cursor.pos.y;
            let pos = term.cursor.pos.x;

            term.editor.contents[line].insert(pos, c as u8);

            term.cursor.save_pos();
            term.cursor.pos.x += 1;
            term.redraw_file();
        }
    }
}
<|endoftext|>