<commit_before>use std::iter;
use std::time::{Duration, Instant};

use rand::{self, Rng};
use rand::distributions::IndependentSample;
use rand::distributions::gamma::Gamma;

use board::{Board, LegalMove, GameState};
use player::Player;

// Jeffrey's prior
const PRIOR: f64 = 0.5;

pub struct MCTSPlayer {
    dur: Duration,
}

impl MCTSPlayer {
    pub fn new(dur: Duration) -> Self {
        MCTSPlayer { dur }
    }
}

impl Player for MCTSPlayer {
    fn choose(&self, b: &Board) -> LegalMove {
        let now = Instant::now();
        let mut rng = rand::thread_rng();
        let mut node = Node::Unvisited;
        for i in 0.. {
            node.explore(&mut rng, b.clone());
            if node.is_certain() { break; }
            if now.elapsed() >= self.dur {
                println!("Choosing move after {} play-throughs", i);
                break;
            }
        }
        node.best_move(b)
    }
}

#[derive(Clone, Debug, PartialEq)]
enum Node {
    Unvisited,
    Probabilistic(Probabilistic),
    CertainLoss(Certain),
    CertainWin(Certain),
    CertainDraw(Certain),
}

impl Node {
    pub fn is_certain(&self) -> bool {
        match *self {
            Node::Unvisited => false,
            Node::Probabilistic(..) => false,
            Node::CertainLoss(..) => true,
            Node::CertainWin(..) => true,
            Node::CertainDraw(..) => true,
        }
    }

    pub fn best_move(&self, b: &Board) -> LegalMove {
        match *self {
            Node::Unvisited => panic!("node is unvisited"),
            Node::Probabilistic(ref p) => p.best_move(b),
            Node::CertainLoss(ref c) => {
                println!("Certain loss in {} move(s)", c.depth);
                c.best_move(b)
            },
            Node::CertainWin(ref c) => {
                println!("Certain win in {} move(s)", c.depth);
                c.best_move(b)
            },
            Node::CertainDraw(ref c) => c.best_move(b),
        }
    }

    pub fn explore<R: Rng>(&mut self, rng: &mut R, b: Board) -> f64 {
        let result = match *self {
            Node::Unvisited => self.explore_unvisted(rng, b),
            Node::Probabilistic(ref mut p) => p.explore(rng, b),
            _ => Ok(self.score()),
        };
        match result {
            Ok(score) => score,
            Err(node) => {
                *self = node;
                self.score()
            },
        }
    }

    fn score(&self) -> f64 {
        match *self {
            Node::Unvisited => panic!("node is unvisited"),
            Node::Probabilistic(ref p) => p.score(),
            Node::CertainLoss(..) => 1.0,
            Node::CertainWin(..) => 0.0,
            Node::CertainDraw(..) => 0.5,
        }
    }

    fn explore_unvisted<R: Rng>(&mut self, rng: &mut R, mut b: Board)
                                -> Result<f64, Node> {
        let (n, i, m) = Node::choose_unvisited_first(rng, &b);
        match b.make_legal_move(m) {
            GameState::Won => Err(Node::CertainWin(Certain::new(1, i))),
            GameState::Drawn => Err(Node::CertainDraw(Certain::new(1, i))),
            GameState::Ongoing => {
                let score = Node::choose_unvisited_rest(rng, b);
                Err(Node::Probabilistic(Probabilistic::new(n, score)))
            }
        }
    }

    fn choose_unvisited_first<R: Rng>(rng: &mut R, b: &Board) -> (usize, usize, LegalMove) {
        let mut m = None;
        let mut i = 0;
        let mut n = 0;
        for (i1, m1) in b.legal_moves_iter().enumerate() {
            n += 1;
            if m1.is_winning() { return (n, i1, m1); }
            if rng.gen_range(0, n) == 0 {
                i = i1;
                m = Some(m1);
            }
        }
        (n, i, m.unwrap())
    }

    fn choose_unvisited_rest<R: Rng>(rng: &mut R, mut b: Board) -> f64 {
        let mut score = 1.0;
        loop {
            let m = super::choose_winning_or_random(&b, rng);
            match b.make_legal_move(m) {
                GameState::Won => return score,
                GameState::Drawn => return 0.5,
                GameState::Ongoing => score = 1.0 - score,
            }
        }
    }

    fn p_parent_win(&self) -> f64 {
        match *self {
            Node::Unvisited => 0.5,
            Node::Probabilistic(ref p) => p.p_parent_win(),
            Node::CertainLoss(..) => 1.0,
            Node::CertainWin(..) => 0.0,
            Node::CertainDraw(..) => 0.5,
        }
    }

    fn p_parent_win_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            Node::Unvisited => beta_sample(rng, PRIOR, PRIOR),
            Node::Probabilistic(ref p) => p.p_parent_win_sample(rng),
            _ => self.p_parent_win(),
        }
    }

    fn rank_ordinal(&self) -> usize {
        match *self {
            Node::Unvisited => 2,
            Node::Probabilistic(..) => 2,
            Node::CertainLoss(..) => 3,
            Node::CertainWin(..) => 0,
            Node::CertainDraw(..) => 1,
        }
    }

    fn rank_discriminator(&self) -> isize {
        match *self {
            Node::Unvisited => 0,
            Node::Probabilistic(..) => 0,
            Node::CertainLoss(ref c) => -(c.depth as isize),
            Node::CertainWin(ref c) => c.depth as isize,
            Node::CertainDraw(ref c) => c.depth as isize,
        }
    }

    fn rank_key<R: Rng>(&self, rng: &mut R) -> (usize, f64, isize) {
        let o = self.rank_ordinal();
        let p = self.p_parent_win_sample(rng);
        let d = self.rank_discriminator();
        (o, p, d)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Certain {
    depth: usize,
    index: usize,
}

impl Certain {
    fn new(depth: usize, index: usize) -> Self {
        Certain { depth, index }
    }

    fn parent(&self, index: usize) -> Self {
        Certain::new(self.depth + 1, index)
    }

    fn best_move(&self, b: &Board) -> LegalMove {
        b.legal_moves_iter().nth(self.index).unwrap()
    }
}

#[derive(Clone, Debug, PartialEq)]
struct Probabilistic {
    score: f64,
    nplay: f64,
    children: Box<[Node]>,
}

impl Probabilistic {
    fn new(nchildren: usize, score: f64) -> Self {
        let score = PRIOR + score;
        let nplay = PRIOR + PRIOR + 1.0;
        let children = iter::repeat(Node::Unvisited).
            take(nchildren).collect::<Vec<Node>>().into_boxed_slice();
        Probabilistic { score, nplay, children }
    }

    fn best_move(&self, b: &Board) -> LegalMove {
        self.children.iter().zip(b.legal_moves_iter()).max_by(|&(n1, _), &(n2, _)| {
            n1.p_parent_win().partial_cmp(&n2.p_parent_win()).unwrap()
        }).map(|(_, m)| m).unwrap()
    }

    fn p_parent_win(&self) -> f64 {
        self.score / self.nplay
    }

    fn p_parent_win_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        beta_sample(rng, self.score, self.nplay - self.score)
    }

    fn explore<R: Rng>(&mut self, rng: &mut R, mut b: Board) -> Result<f64, Node> {
        let (_, i, node) = self.children.iter_mut().enumerate().map(|(i, node)| {
            (node.rank_key(rng), i, node)
        }).max_by(|&(k1, _, _), &(k2, _, _)| {
            k1.partial_cmp(&k2).unwrap()
        }).unwrap();
        match *node {
            Node::CertainLoss(ref c) => Err(Node::CertainWin(c.parent(i))),
            Node::CertainWin(ref c) => Err(Node::CertainLoss(c.parent(i))),
            Node::CertainDraw(ref c) => Err(Node::CertainDraw(c.parent(i))),
            _ => {
                let m = b.legal_moves_iter().nth(i).unwrap();
                b.make_legal_move(m);
                let score = 1.0 - node.explore(rng, b);
                self.score += score;
                self.nplay += 1.0;
                Ok(score)
            }
        }
    }

    fn score(&self) -> f64 {
        self.score - PRIOR as f64
    }
}

fn beta_sample<R: Rng>(rng: &mut R, alpha: f64, beta: f64) -> f64 {
    if alpha <= 1.0 && beta <= 1.0 {
        loop {
            let u = rng.next_f64();
            let v = rng.next_f64();
            let x = u.powf(1.0 / alpha);
            let y = v.powf(1.0 / beta);

            if x + y > 1.0 { continue; }
            if x + y > 0.0 { return x / (x + y); }

            let ln_x = u.ln() / alpha;
            let ln_y = v.ln() / beta;
            let ln_m = if ln_x > ln_y { ln_x } else { ln_y };
            let ln_x = ln_x - ln_m;
            let ln_y = ln_y - ln_m;
            return (ln_x - (ln_x.exp() + ln_y.exp()).ln()).exp();
        }
    } else {
        let a = Gamma::new(alpha, 1.0).ind_sample(rng);
        let b = Gamma::new(beta, 1.0).ind_sample(rng);
        a / (a + b)
    }
}
<commit_msg>Refactor exploration findings<commit_after>use std::iter;
use std::time::{Duration, Instant};

use rand::{self, Rng};
use rand::distributions::IndependentSample;
use rand::distributions::gamma::Gamma;

use board::{Board, LegalMove, GameState};
use player::Player;

// Jeffrey's prior
const PRIOR: f64 = 0.5;

pub struct MCTSPlayer {
    dur: Duration,
}

impl MCTSPlayer {
    pub fn new(dur: Duration) -> Self {
        MCTSPlayer { dur }
    }
}

impl Player for MCTSPlayer {
    fn choose(&self, b: &Board) -> LegalMove {
        let now = Instant::now();
        let mut rng = rand::thread_rng();
        let mut node = Node::Unvisited;
        for i in 0.. {
            node.explore(&mut rng, b.clone());
            if node.is_certain() { break; }
            if now.elapsed() >= self.dur {
                println!("Choosing move after {} play-throughs", i);
                break;
            }
        }
        node.best_move(b)
    }
}

#[derive(Clone, Debug)]
enum Finding {
    Score(f64),
    Replace(Node),
    Both(Node, f64),
}

#[derive(Clone, Debug, PartialEq)]
enum Node {
    Unvisited,
    Probabilistic(Probabilistic),
    CertainLoss(Certain),
    CertainWin(Certain),
    CertainDraw(Certain),
}

impl Node {
    pub fn is_certain(&self) -> bool {
        match *self {
            Node::Unvisited => false,
            Node::Probabilistic(..) => false,
            Node::CertainLoss(..) => true,
            Node::CertainWin(..) => true,
            Node::CertainDraw(..) => true,
        }
    }

    pub fn best_move(&self, b: &Board) -> LegalMove {
        match *self {
            Node::Unvisited => panic!("node is unvisited"),
            Node::Probabilistic(ref p) => p.best_move(b),
            Node::CertainLoss(ref c) => {
                println!("Certain loss in {} move(s)", c.depth);
                c.best_move(b)
            },
            Node::CertainWin(ref c) => {
                println!("Certain win in {} move(s)", c.depth);
                c.best_move(b)
            },
            Node::CertainDraw(ref c) => c.best_move(b),
        }
    }

    pub fn explore<R: Rng>(&mut self, rng: &mut R, b: Board) -> f64 {
        let result = match *self {
            Node::Unvisited => self.explore_unvisted(rng, b),
            Node::Probabilistic(ref mut p) => p.explore(rng, b),
            _ => Finding::Score(self.score()),
        };
        match result {
            Finding::Score(score) => score,
            Finding::Replace(node) => { *self = node; self.score() },
            Finding::Both(node, score) => { *self = node; score }
        }
    }

    fn score(&self) -> f64 {
        match *self {
            Node::Unvisited => panic!("node is unvisited"),
            Node::Probabilistic(..) => panic!("node is probabilistic"),
            Node::CertainLoss(..) => 1.0,
            Node::CertainWin(..) => 0.0,
            Node::CertainDraw(..) => 0.5,
        }
    }

    fn explore_unvisted<R: Rng>(&mut self, rng: &mut R, mut b: Board) -> Finding {
        let (n, i, m) = Node::choose_unvisited_first(rng, &b);
        match b.make_legal_move(m) {
            GameState::Won => Finding::Replace(Node::CertainWin(Certain::new(1, i))),
            GameState::Drawn => Finding::Replace(Node::CertainDraw(Certain::new(1, i))),
            GameState::Ongoing => {
                let score = Node::choose_unvisited_rest(rng, b);
                let node = Node::Probabilistic(Probabilistic::new(n, score));
                Finding::Both(node, score)
            }
        }
    }

    fn choose_unvisited_first<R: Rng>(rng: &mut R, b: &Board) -> (usize, usize, LegalMove) {
        let mut m = None;
        let mut i = 0;
        let mut n = 0;
        for (i1, m1) in b.legal_moves_iter().enumerate() {
            n += 1;
            if m1.is_winning() { return (n, i1, m1); }
            if rng.gen_range(0, n) == 0 {
                i = i1;
                m = Some(m1);
            }
        }
        (n, i, m.unwrap())
    }

    fn choose_unvisited_rest<R: Rng>(rng: &mut R, mut b: Board) -> f64 {
        let mut score = 1.0;
        loop {
            let m = super::choose_winning_or_random(&b, rng);
            match b.make_legal_move(m) {
                GameState::Won => return score,
                GameState::Drawn => return 0.5,
                GameState::Ongoing => score = 1.0 - score,
            }
        }
    }

    fn expected_score(&self) -> f64 {
        match *self {
            Node::Unvisited => 0.5,
            Node::Probabilistic(ref p) => p.expected_score(),
            Node::CertainLoss(..) => 1.0,
            Node::CertainWin(..) => 0.0,
            Node::CertainDraw(..) => 0.5,
        }
    }

    fn expected_score_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        match *self {
            Node::Unvisited => beta_sample(rng, PRIOR, PRIOR),
            Node::Probabilistic(ref p) => p.expected_score_sample(rng),
            _ => self.expected_score(),
        }
    }

    fn rank_ordinal(&self) -> usize {
        match *self {
            Node::Unvisited => 2,
            Node::Probabilistic(..) => 2,
            Node::CertainLoss(..) => 3,
            Node::CertainWin(..) => 0,
            Node::CertainDraw(..) => 1,
        }
    }

    fn rank_discriminator(&self) -> isize {
        match *self {
            Node::Unvisited => 0,
            Node::Probabilistic(..) => 0,
            Node::CertainLoss(ref c) => -(c.depth as isize),
            Node::CertainWin(ref c) => c.depth as isize,
            Node::CertainDraw(ref c) => c.depth as isize,
        }
    }

    fn rank_key<R: Rng>(&self, rng: &mut R) -> (usize, f64, isize) {
        let o = self.rank_ordinal();
        let p = self.expected_score_sample(rng);
        let d = self.rank_discriminator();
        (o, p, d)
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
struct Certain {
    depth: usize,
    index: usize,
}

impl Certain {
    fn new(depth: usize, index: usize) -> Self {
        Certain { depth, index }
    }

    fn parent(&self, index: usize) -> Self {
        Certain::new(self.depth + 1, index)
    }

    fn best_move(&self, b: &Board) -> LegalMove {
        b.legal_moves_iter().nth(self.index).unwrap()
    }
}

#[derive(Clone, Debug, PartialEq)]
struct Probabilistic {
    score: f64,
    nplay: f64,
    children: Box<[Node]>,
}

impl Probabilistic {
    fn new(nchildren: usize, score: f64) -> Self {
        let score = PRIOR + score;
        let nplay = PRIOR + PRIOR + 1.0;
        let children = iter::repeat(Node::Unvisited).
            take(nchildren).collect::<Vec<Node>>().into_boxed_slice();
        Probabilistic { score, nplay, children }
    }

    fn best_move(&self, b: &Board) -> LegalMove {
        self.children.iter().zip(b.legal_moves_iter()).max_by(|&(n1, _), &(n2, _)| {
            n1.expected_score().partial_cmp(&n2.expected_score()).unwrap()
        }).map(|(_, m)| m).unwrap()
    }

    fn expected_score(&self) -> f64 {
        self.score / self.nplay
    }

    fn expected_score_sample<R: Rng>(&self, rng: &mut R) -> f64 {
        beta_sample(rng, self.score, self.nplay - self.score)
    }

    fn explore<R: Rng>(&mut self, rng: &mut R, mut b: Board) -> Finding {
        let (_, i, node) = self.children.iter_mut().enumerate().map(|(i, node)| {
            (node.rank_key(rng), i, node)
        }).max_by(|&(k1, _, _), &(k2, _, _)| {
            k1.partial_cmp(&k2).unwrap()
        }).unwrap();
        match *node {
            Node::CertainLoss(ref c) => Finding::Replace(Node::CertainWin(c.parent(i))),
            Node::CertainWin(ref c) => Finding::Replace(Node::CertainLoss(c.parent(i))),
            Node::CertainDraw(ref c) => Finding::Replace(Node::CertainDraw(c.parent(i))),
            _ => {
                let m = b.legal_moves_iter().nth(i).unwrap();
                b.make_legal_move(m);
                let score = 1.0 - node.explore(rng, b);
                self.score += score;
                self.nplay += 1.0;
                Finding::Score(score)
            }
        }
    }
}

fn beta_sample<R: Rng>(rng: &mut R, alpha: f64, beta: f64) -> f64 {
    if alpha <= 1.0 && beta <= 1.0 {
        loop {
            let u = rng.next_f64();
            let v = rng.next_f64();
            let x = u.powf(1.0 / alpha);
            let y = v.powf(1.0 / beta);

            if x + y > 1.0 { continue; }
            if x + y > 0.0 { return x / (x + y); }

            let ln_x = u.ln() / alpha;
            let ln_y = v.ln() / beta;
            let ln_m = if ln_x > ln_y { ln_x } else { ln_y };
            let ln_x = ln_x - ln_m;
            let ln_y = ln_y - ln_m;
            return (ln_x - (ln_x.exp() + ln_y.exp()).ln()).exp();
        }
    } else {
        let a = Gamma::new(alpha, 1.0).ind_sample(rng);
        let b = Gamma::new(beta, 1.0).ind_sample(rng);
        a / (a + b)
    }
}
<|endoftext|>


<commit_before>use std::fmt;
use std::error::Error;
use std::sync::Mutex;
use CapabilitiesSource;

use gl;
use version::Api;
use version::Version;

pub use self::compute::{ComputeShader, ComputeCommand};
pub use self::program::Program;
pub use self::reflection::{Uniform, UniformBlock, BlockLayout, OutputPrimitives};
pub use self::reflection::{Attribute, TransformFeedbackVarying, TransformFeedbackBuffer, TransformFeedbackMode};

mod compute;
mod program;
mod raw;
mod reflection;
mod shader;
mod uniforms_storage;

/// Returns true if the backend supports geometry shaders.
#[inline]
pub fn is_geometry_shader_supported<C>(ctxt: &C) -> bool where C: CapabilitiesSource {
    shader::check_shader_type_compatibility(ctxt, gl::GEOMETRY_SHADER)
}

/// Returns true if the backend supports tessellation shaders.
#[inline]
pub fn is_tessellation_shader_supported<C>(ctxt: &C) -> bool where C: CapabilitiesSource {
    shader::check_shader_type_compatibility(ctxt, gl::TESS_CONTROL_SHADER)
}

/// Returns true if the backend supports creating and retreiving binary format.
#[inline]
pub fn is_binary_supported<C>(ctxt: &C) -> bool where C: CapabilitiesSource {
    ctxt.get_version() >= &Version(Api::Gl, 4, 1) || ctxt.get_version() >= &Version(Api::GlEs, 2, 0)
        || ctxt.get_extensions().gl_arb_get_programy_binary
}

/// Some shader compilers have race-condition issues, so we lock this mutex
/// in the GL thread every time we compile a shader or link a program.
// TODO: replace by a StaticMutex
lazy_static! {
    static ref COMPILER_GLOBAL_LOCK: Mutex<()> = Mutex::new(());
}

/// Error that can be triggered when creating a `Program`.
#[derive(Clone, Debug)]
pub enum ProgramCreationError {
    /// Error while compiling one of the shaders.
    CompilationError(String),

    /// Error while linking the program.
    LinkingError(String),

    /// One of the requested shader types is not supported by the backend.
    ///
    /// Usually the case for geometry shaders.
    ShaderTypeNotSupported,

    /// The OpenGL implementation doesn't provide a compiler.
    CompilationNotSupported,

    /// You have requested transform feedback varyings, but transform feedback is not supported
    /// by the backend.
    TransformFeedbackNotSupported,

    /// You have requested point size setting from the shader, but it's not
    /// supported by the backend.
    PointSizeNotSupported,
}

impl fmt::Display for ProgramCreationError {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match self {
            &ProgramCreationError::CompilationError(ref s) =>
                formatter.write_fmt(format_args!("Compilation error in one of the shaders: {}", s)),
            &ProgramCreationError::LinkingError(ref s) =>
                formatter.write_fmt(format_args!("Error while linking shaders together: {}", s)),
            &ProgramCreationError::ShaderTypeNotSupported =>
                formatter.write_str("One of the request shader type is \
                                    not supported by the backend"),
            &ProgramCreationError::CompilationNotSupported =>
                formatter.write_str("The backend doesn't support shaders compilation"),
            &ProgramCreationError::TransformFeedbackNotSupported =>
                formatter.write_str("You requested transform feedback, but this feature is not \
                                     supported by the backend"),
            &ProgramCreationError::PointSizeNotSupported =>
                formatter.write_str("You requested point size setting, but it's not \
                                     supported by the backend"),
        }
    }
}

impl Error for ProgramCreationError {
    fn description(&self) -> &str {
        match self {
            &ProgramCreationError::CompilationError(_) => "Compilation error in one of the \
                                                           shaders",
            &ProgramCreationError::LinkingError(_) => "Error while linking shaders together",
            &ProgramCreationError::ShaderTypeNotSupported => "One of the request shader type is \
                                                              not supported by the backend",
            &ProgramCreationError::CompilationNotSupported => "The backend doesn't support \
                                                               shaders compilation",
            &ProgramCreationError::TransformFeedbackNotSupported => "Transform feedback is not \
                                                                     supported by the backend.",
            &ProgramCreationError::PointSizeNotSupported => "Point size is not supported by \
                                                             the backend.",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        None
    }
}

/// Error type that is returned by the `program!` macro.
#[derive(Clone, Debug)]
pub enum ProgramChooserCreationError {
    /// No available version has been found.
    NoVersion,

    /// A version has been found but it triggered the given error.
    ProgramCreationError(ProgramCreationError),
}

impl fmt::Display for ProgramChooserCreationError {
    #[inline]
    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(formatter, "{}", self.description())
    }
}

impl Error for ProgramChooserCreationError {
    #[inline]
    fn description(&self) -> &str {
        match self {
            &ProgramChooserCreationError::NoVersion => "No version of the program has been found \
                                                        for the current OpenGL version.",
            &ProgramChooserCreationError::ProgramCreationError(ref err) => err.description(),
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        match self {
            &ProgramChooserCreationError::NoVersion => None,
            &ProgramChooserCreationError::ProgramCreationError(ref err) => Some(err),
        }
    }
}

impl From<ProgramCreationError> for ProgramChooserCreationError {
    fn from(err: ProgramCreationError) -> ProgramChooserCreationError {
        ProgramChooserCreationError::ProgramCreationError(err)
    }
}

/// Error while retreiving the binary representation of a program.
#[derive(Copy, Clone, Debug)]
pub enum GetBinaryError {
    /// The backend doesn't support binary.
    NotSupported,
}

/// Input when creating a program.
pub enum ProgramCreationInput<'a> {
    /// Use GLSL source code.
    SourceCode {
        /// Source code of the vertex shader.
        vertex_shader: &'a str,

        /// Source code of the optional tessellation control shader.
        tessellation_control_shader: Option<&'a str>,

        /// Source code of the optional tessellation evaluation shader.
        tessellation_evaluation_shader: Option<&'a str>,

        /// Source code of the optional geometry shader.
        geometry_shader: Option<&'a str>,

        /// Source code of the fragment shader.
        fragment_shader: &'a str,

        /// The list of variables and mode to use for transform feedback.
        ///
        /// The information specified here will be passed to the OpenGL linker. If you pass
        /// `None`, then you won't be able to use transform feedback.
        transform_feedback_varyings: Option<(Vec<String>, TransformFeedbackMode)>,

        /// Whether the fragment shader outputs colors in `sRGB` or `RGB`. This is false by default,
        /// meaning that the program outputs `RGB`.
        ///
        /// If this is false, then `GL_FRAMEBUFFER_SRGB` will be enabled when this program is used
        /// (if it is supported).
        outputs_srgb: bool,

        /// Whether the shader uses point size.
        uses_point_size: bool,
    },

    /// Use a precompiled binary.
    Binary {
        /// The data.
        data: Binary,

        /// See `SourceCode::outputs_srgb`.
        outputs_srgb: bool,

        /// Whether the shader uses point size.
        uses_point_size: bool,
    }
}

/// Represents the source code of a program.
pub struct SourceCode<'a> {
    /// Source code of the vertex shader.
    pub vertex_shader: &'a str,

    /// Source code of the optional tessellation control shader.
    pub tessellation_control_shader: Option<&'a str>,

    /// Source code of the optional tessellation evaluation shader.
    pub tessellation_evaluation_shader: Option<&'a str>,

    /// Source code of the optional geometry shader.
    pub geometry_shader: Option<&'a str>,

    /// Source code of the fragment shader.
    pub fragment_shader: &'a str,
}

impl<'a> From<SourceCode<'a>> for ProgramCreationInput<'a> {
    #[inline]
    fn from(code: SourceCode<'a>) -> ProgramCreationInput<'a> {
        let SourceCode { vertex_shader, fragment_shader, geometry_shader,
                         tessellation_control_shader, tessellation_evaluation_shader } = code;

        ProgramCreationInput::SourceCode {
            vertex_shader: vertex_shader,
            tessellation_control_shader: tessellation_control_shader,
            tessellation_evaluation_shader: tessellation_evaluation_shader,
            geometry_shader: geometry_shader,
            fragment_shader: fragment_shader,
            transform_feedback_varyings: None,
            outputs_srgb: false,
            uses_point_size: false,
        }
    }
}

/// Represents the compiled binary data of a program.
pub struct Binary {
    /// An implementation-defined format.
    pub format: u32,

    /// The binary data.
    pub content: Vec<u8>,
}

impl<'a> From<Binary> for ProgramCreationInput<'a> {
    #[inline]
    fn from(binary: Binary) -> ProgramCreationInput<'a> {
        ProgramCreationInput::Binary {
            data: binary,
            outputs_srgb: false,
            uses_point_size: false,
        }
    }
}
<commit_msg>fixed error handling in src/program/mod.rs<commit_after>use std::fmt;
use std::error::Error;
use std::sync::Mutex;
use CapabilitiesSource;

use gl;
use version::Api;
use version::Version;

pub use self::compute::{ComputeShader, ComputeCommand};
pub use self::program::Program;
pub use self::reflection::{Uniform, UniformBlock, BlockLayout, OutputPrimitives};
pub use self::reflection::{Attribute, TransformFeedbackVarying, TransformFeedbackBuffer, TransformFeedbackMode};

mod compute;
mod program;
mod raw;
mod reflection;
mod shader;
mod uniforms_storage;

/// Returns true if the backend supports geometry shaders.
#[inline]
pub fn is_geometry_shader_supported<C>(ctxt: &C) -> bool where C: CapabilitiesSource {
    shader::check_shader_type_compatibility(ctxt, gl::GEOMETRY_SHADER)
}

/// Returns true if the backend supports tessellation shaders.
#[inline]
pub fn is_tessellation_shader_supported<C>(ctxt: &C) -> bool where C: CapabilitiesSource {
    shader::check_shader_type_compatibility(ctxt, gl::TESS_CONTROL_SHADER)
}

/// Returns true if the backend supports creating and retreiving binary format.
#[inline]
pub fn is_binary_supported<C>(ctxt: &C) -> bool where C: CapabilitiesSource {
    ctxt.get_version() >= &Version(Api::Gl, 4, 1) || ctxt.get_version() >= &Version(Api::GlEs, 2, 0)
        || ctxt.get_extensions().gl_arb_get_programy_binary
}

/// Some shader compilers have race-condition issues, so we lock this mutex
/// in the GL thread every time we compile a shader or link a program.
// TODO: replace by a StaticMutex
lazy_static! {
    static ref COMPILER_GLOBAL_LOCK: Mutex<()> = Mutex::new(());
}

/// Error that can be triggered when creating a `Program`.
#[derive(Clone, Debug)]
pub enum ProgramCreationError {
    /// Error while compiling one of the shaders.
    CompilationError(String),

    /// Error while linking the program.
    LinkingError(String),

    /// One of the requested shader types is not supported by the backend.
    ///
    /// Usually the case for geometry shaders.
    ShaderTypeNotSupported,

    /// The OpenGL implementation doesn't provide a compiler.
    CompilationNotSupported,

    /// You have requested transform feedback varyings, but transform feedback is not supported
    /// by the backend.
    TransformFeedbackNotSupported,

    /// You have requested point size setting from the shader, but it's not
    /// supported by the backend.
    PointSizeNotSupported,
}

impl fmt::Display for ProgramCreationError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        use self::ProgramCreationError::*;
        match *self {
            CompilationError(ref s) =>
                write!(fmt, "{}: {}", self.description(), s),
            LinkingError(ref s) =>
                write!(fmt, "{}: {}", self.description(), s),
            _ =>
                write!(fmt, "{}", self.description()),
        }
    }
}

impl Error for ProgramCreationError {
    fn description(&self) -> &str {
        use self::ProgramCreationError::*;
        match *self {
            CompilationError(_) =>
                "Compilation error in one of the shaders",
            LinkingError(_) =>
                "Error while linking shaders together",
            ShaderTypeNotSupported =>
                "One of the request shader type is not supported by the backend",
            CompilationNotSupported =>
                "The backend doesn't support shaders compilation",
            TransformFeedbackNotSupported =>
                "Transform feedback is not supported by the backend.",
            PointSizeNotSupported =>
                "Point size is not supported by the backend.",
        }
    }
}

/// Error type that is returned by the `program!` macro.
#[derive(Clone, Debug)]
pub enum ProgramChooserCreationError {
    /// No available version has been found.
    NoVersion,

    /// A version has been found but it triggered the given error.
    ProgramCreationError(ProgramCreationError),
}

impl fmt::Display for ProgramChooserCreationError {
    #[inline]
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        write!(fmt, "{}", self.description())
    }
}

impl Error for ProgramChooserCreationError {
    #[inline]
    fn description(&self) -> &str {
        use self::ProgramChooserCreationError::*;
        match *self {
            ProgramCreationError(ref err) => err.description(),
            NoVersion => "No version of the program has been found for the current OpenGL version.",
        }
    }

    #[inline]
    fn cause(&self) -> Option<&Error> {
        use self::ProgramChooserCreationError::*;
        match *self {
            ProgramCreationError(ref err) => Some(err),
            _ => None,
        }
    }
}

impl From<ProgramCreationError> for ProgramChooserCreationError {
    fn from(err: ProgramCreationError) -> ProgramChooserCreationError {
        ProgramChooserCreationError::ProgramCreationError(err)
    }
}

/// Error while retreiving the binary representation of a program.
#[derive(Copy, Clone, Debug)]
pub enum GetBinaryError {
    /// The backend doesn't support binary.
    NotSupported,
}

impl fmt::Display for GetBinaryError {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
        write!(fmt, "{}", self.description())
    }
}

impl Error for GetBinaryError {
    fn description(&self) -> &str {
        use self::GetBinaryError::*;
        match *self {
            NotSupported => "The backend doesn't support binary",
        }
    }
}

/// Input when creating a program.
pub enum ProgramCreationInput<'a> {
    /// Use GLSL source code.
    SourceCode {
        /// Source code of the vertex shader.
        vertex_shader: &'a str,

        /// Source code of the optional tessellation control shader.
        tessellation_control_shader: Option<&'a str>,

        /// Source code of the optional tessellation evaluation shader.
        tessellation_evaluation_shader: Option<&'a str>,

        /// Source code of the optional geometry shader.
        geometry_shader: Option<&'a str>,

        /// Source code of the fragment shader.
        fragment_shader: &'a str,

        /// The list of variables and mode to use for transform feedback.
        ///
        /// The information specified here will be passed to the OpenGL linker. If you pass
        /// `None`, then you won't be able to use transform feedback.
        transform_feedback_varyings: Option<(Vec<String>, TransformFeedbackMode)>,

        /// Whether the fragment shader outputs colors in `sRGB` or `RGB`. This is false by default,
        /// meaning that the program outputs `RGB`.
        ///
        /// If this is false, then `GL_FRAMEBUFFER_SRGB` will be enabled when this program is used
        /// (if it is supported).
        outputs_srgb: bool,

        /// Whether the shader uses point size.
        uses_point_size: bool,
    },

    /// Use a precompiled binary.
    Binary {
        /// The data.
        data: Binary,

        /// See `SourceCode::outputs_srgb`.
        outputs_srgb: bool,

        /// Whether the shader uses point size.
        uses_point_size: bool,
    }
}

/// Represents the source code of a program.
pub struct SourceCode<'a> {
    /// Source code of the vertex shader.
    pub vertex_shader: &'a str,

    /// Source code of the optional tessellation control shader.
    pub tessellation_control_shader: Option<&'a str>,

    /// Source code of the optional tessellation evaluation shader.
    pub tessellation_evaluation_shader: Option<&'a str>,

    /// Source code of the optional geometry shader.
    pub geometry_shader: Option<&'a str>,

    /// Source code of the fragment shader.
    pub fragment_shader: &'a str,
}

impl<'a> From<SourceCode<'a>> for ProgramCreationInput<'a> {
    #[inline]
    fn from(code: SourceCode<'a>) -> ProgramCreationInput<'a> {
        let SourceCode { vertex_shader, fragment_shader, geometry_shader,
                         tessellation_control_shader, tessellation_evaluation_shader } = code;

        ProgramCreationInput::SourceCode {
            vertex_shader: vertex_shader,
            tessellation_control_shader: tessellation_control_shader,
            tessellation_evaluation_shader: tessellation_evaluation_shader,
            geometry_shader: geometry_shader,
            fragment_shader: fragment_shader,
            transform_feedback_varyings: None,
            outputs_srgb: false,
            uses_point_size: false,
        }
    }
}

/// Represents the compiled binary data of a program.
pub struct Binary {
    /// An implementation-defined format.
    pub format: u32,

    /// The binary data.
    pub content: Vec<u8>,
}

impl<'a> From<Binary> for ProgramCreationInput<'a> {
    #[inline]
    fn from(binary: Binary) -> ProgramCreationInput<'a> {
        ProgramCreationInput::Binary {
            data: binary,
            outputs_srgb: false,
            uses_point_size: false,
        }
    }
}
<|endoftext|>


<commit_before>//! PowerPC Vectir Scalar eXtensions (VSX) intrinsics.
//!
//! The references are: [POWER ISA v2.07B (for POWER8 & POWER8 with NVIDIA
//! NVlink)] and [POWER ISA v3.0B (for POWER9)].
//!
//! [POWER ISA v2.07B (for POWER8 & POWER8 with NVIDIA NVlink)]: https://ibm.box.com/s/jd5w15gz301s5b5dt375mshpq9c3lh4u
//! [POWER ISA v3.0B (for POWER9)]: https://ibm.box.com/s/1hzcwkwf8rbju5h9iyf44wm94amnlcrv

#![allow(non_camel_case_types)]

use coresimd::powerpc::*;
use coresimd::simd::*;
use coresimd::simd_llvm::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

use mem;

types! {
    // pub struct vector_Float16 = f16x8;
    /// PowerPC-specific 128-bit wide vector of two packed `i64`
    pub struct vector_signed_long(i64, i64);
    /// PowerPC-specific 128-bit wide vector of two packed `u64`
    pub struct vector_unsigned_long(u64, u64);
    /// PowerPC-specific 128-bit wide vector mask of two elements
    pub struct vector_bool_long(i64, i64);
    /// PowerPC-specific 128-bit wide vector of two packed `f64`
    pub struct vector_double(f64, f64);
    // pub struct vector_signed_long_long = vector_signed_long;
    // pub struct vector_unsigned_long_long = vector_unsigned_long;
    // pub struct vector_bool_long_long = vector_bool_long;
    // pub struct vector_signed___int128 = i128x1;
    // pub struct vector_unsigned___int128 = i128x1;
}

impl_from_bits_!(
    vector_signed_long: u64x2,
    i64x2,
    f64x2,
    m64x2,
    u32x4,
    i32x4,
    f32x4,
    m32x4,
    u16x8,
    i16x8,
    m16x8,
    u8x16,
    i8x16,
    m8x16,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);
impl_from_bits_!(
    i64x2:
    vector_signed_char,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_unsigned_long: u64x2,
    i64x2,
    f64x2,
    m64x2,
    u32x4,
    i32x4,
    f32x4,
    m32x4,
    u16x8,
    i16x8,
    m16x8,
    u8x16,
    i8x16,
    m8x16,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_bool_long,
    vector_double
);
impl_from_bits_!(
    u64x2:
    vector_signed_char,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_double: u64x2,
    i64x2,
    f64x2,
    m64x2,
    u32x4,
    i32x4,
    f32x4,
    m32x4,
    u16x8,
    i16x8,
    m16x8,
    u8x16,
    i8x16,
    m8x16,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_unsigned_long,
    vector_bool_long
);
impl_from_bits_!(
    f64x2:
    vector_signed_char,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(vector_bool_long: m64x2);
impl_from_bits_!(m64x2: vector_bool_long);
impl_from_bits_!(m32x4: vector_bool_long);
impl_from_bits_!(m16x8: vector_bool_long);
impl_from_bits_!(m8x16: vector_bool_long);
impl_from_bits_!(vector_bool_char: vector_bool_long);
impl_from_bits_!(vector_bool_short: vector_bool_long);
impl_from_bits_!(vector_bool_int: vector_bool_long);

impl_from_bits_!(
    vector_signed_char: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_unsigned_char: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_signed_short: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_unsigned_short: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_signed_int: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_unsigned_int: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

mod sealed {

    use super::*;

    pub trait VectorPermDI {
        unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self;
    }

    // xxpermdi has an big-endian bias and extended mnemonics
    #[inline]
    #[target_feature(enable = "vsx")]
    #[cfg_attr(all(test, target_endian="little"), assert_instr(xxmrgld, dm = 0x0))]
    #[cfg_attr(all(test, target_endian="big"), assert_instr(xxspltd, dm = 0x0))]
    unsafe fn xxpermdi(a: i64x2, b: i64x2, dm: u8) -> i64x2 {
        match dm & 0b11 {
            0 => simd_shuffle2(a, b, [0b00, 0b10]),
            1 => simd_shuffle2(a, b, [0b01, 0b10]),
            2 => simd_shuffle2(a, b, [0b00, 0b11]),
            _ => simd_shuffle2(a, b, [0b01, 0b11]),
        }
    }

    macro_rules! vec_xxpermdi {
        {$impl: ident} => {
            impl VectorPermDI for $impl {
                #[inline]
                #[target_feature(enable = "vsx")]
                unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self {
                    mem::transmute(xxpermdi(mem::transmute(self), mem::transmute(b), dm))
                }
            }
        }
    }

    vec_xxpermdi! { vector_unsigned_long }
    vec_xxpermdi! { vector_signed_long }
    vec_xxpermdi! { vector_bool_long }
    vec_xxpermdi! { vector_double }
}

/// Vector permute.
#[inline]
#[target_feature(enable = "vsx")]
#[rustc_args_required_const(2)]
pub unsafe fn vec_xxpermdi<T>(a: T, b: T, dm: u8) -> T
where
    T: sealed::VectorPermDI,
{
    a.vec_xxpermdi(b, dm)
}

#[cfg(test)]
mod tests {
    #[cfg(target_arch = "powerpc")]
    use coresimd::arch::powerpc::*;

    #[cfg(target_arch = "powerpc64")]
    use coresimd::arch::powerpc64::*;

    use simd::*;
    use stdsimd_test::simd_test;

    #[simd_test(enable = "vsx")]
    unsafe fn vec_xxpermdi_u62x2() {
        let a: vector_unsigned_long = u64x2::new(0, 1).into_bits();
        let b = u64x2::new(2, 3).into_bits();

        assert_eq!(u64x2::new(0, 2), vec_xxpermdi(a, b, 0).into_bits());
        assert_eq!(u64x2::new(1, 2), vec_xxpermdi(a, b, 1).into_bits());
        assert_eq!(u64x2::new(0, 3), vec_xxpermdi(a, b, 2).into_bits());
        assert_eq!(u64x2::new(1, 3), vec_xxpermdi(a, b, 3).into_bits());
    }
}
<commit_msg>Extend the xxpermdi coverage<commit_after>//! PowerPC Vectir Scalar eXtensions (VSX) intrinsics.
//!
//! The references are: [POWER ISA v2.07B (for POWER8 & POWER8 with NVIDIA
//! NVlink)] and [POWER ISA v3.0B (for POWER9)].
//!
//! [POWER ISA v2.07B (for POWER8 & POWER8 with NVIDIA NVlink)]: https://ibm.box.com/s/jd5w15gz301s5b5dt375mshpq9c3lh4u
//! [POWER ISA v3.0B (for POWER9)]: https://ibm.box.com/s/1hzcwkwf8rbju5h9iyf44wm94amnlcrv

#![allow(non_camel_case_types)]

use coresimd::powerpc::*;
use coresimd::simd::*;
use coresimd::simd_llvm::*;

#[cfg(test)]
use stdsimd_test::assert_instr;

use mem;

types! {
    // pub struct vector_Float16 = f16x8;
    /// PowerPC-specific 128-bit wide vector of two packed `i64`
    pub struct vector_signed_long(i64, i64);
    /// PowerPC-specific 128-bit wide vector of two packed `u64`
    pub struct vector_unsigned_long(u64, u64);
    /// PowerPC-specific 128-bit wide vector mask of two elements
    pub struct vector_bool_long(i64, i64);
    /// PowerPC-specific 128-bit wide vector of two packed `f64`
    pub struct vector_double(f64, f64);
    // pub struct vector_signed_long_long = vector_signed_long;
    // pub struct vector_unsigned_long_long = vector_unsigned_long;
    // pub struct vector_bool_long_long = vector_bool_long;
    // pub struct vector_signed___int128 = i128x1;
    // pub struct vector_unsigned___int128 = i128x1;
}

impl_from_bits_!(
    vector_signed_long: u64x2,
    i64x2,
    f64x2,
    m64x2,
    u32x4,
    i32x4,
    f32x4,
    m32x4,
    u16x8,
    i16x8,
    m16x8,
    u8x16,
    i8x16,
    m8x16,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);
impl_from_bits_!(
    i64x2:
    vector_signed_char,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_unsigned_long: u64x2,
    i64x2,
    f64x2,
    m64x2,
    u32x4,
    i32x4,
    f32x4,
    m32x4,
    u16x8,
    i16x8,
    m16x8,
    u8x16,
    i8x16,
    m8x16,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_bool_long,
    vector_double
);
impl_from_bits_!(
    u64x2:
    vector_signed_char,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_double: u64x2,
    i64x2,
    f64x2,
    m64x2,
    u32x4,
    i32x4,
    f32x4,
    m32x4,
    u16x8,
    i16x8,
    m16x8,
    u8x16,
    i8x16,
    m8x16,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_unsigned_long,
    vector_bool_long
);
impl_from_bits_!(
    f64x2:
    vector_signed_char,
    vector_unsigned_char,
    vector_bool_char,
    vector_signed_short,
    vector_unsigned_short,
    vector_bool_short,
    vector_signed_int,
    vector_unsigned_int,
    vector_float,
    vector_bool_int,
    vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(vector_bool_long: m64x2);
impl_from_bits_!(m64x2: vector_bool_long);
impl_from_bits_!(m32x4: vector_bool_long);
impl_from_bits_!(m16x8: vector_bool_long);
impl_from_bits_!(m8x16: vector_bool_long);
impl_from_bits_!(vector_bool_char: vector_bool_long);
impl_from_bits_!(vector_bool_short: vector_bool_long);
impl_from_bits_!(vector_bool_int: vector_bool_long);

impl_from_bits_!(
    vector_signed_char: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_unsigned_char: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_signed_short: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_unsigned_short: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_signed_int: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

impl_from_bits_!(
    vector_unsigned_int: vector_signed_long,
    vector_unsigned_long,
    vector_bool_long,
    vector_double
);

mod sealed {

    use super::*;

    pub trait VectorPermDI {
        unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self;
    }

    // xxpermdi has an big-endian bias and extended mnemonics
    #[inline]
    #[target_feature(enable = "vsx")]
    #[cfg_attr(all(test, target_endian="little"), assert_instr(xxmrgld, dm = 0x0))]
    #[cfg_attr(all(test, target_endian="big"), assert_instr(xxspltd, dm = 0x0))]
    unsafe fn xxpermdi(a: i64x2, b: i64x2, dm: u8) -> i64x2 {
        match dm & 0b11 {
            0 => simd_shuffle2(a, b, [0b00, 0b10]),
            1 => simd_shuffle2(a, b, [0b01, 0b10]),
            2 => simd_shuffle2(a, b, [0b00, 0b11]),
            _ => simd_shuffle2(a, b, [0b01, 0b11]),
        }
    }

    macro_rules! vec_xxpermdi {
        {$impl: ident} => {
            impl VectorPermDI for $impl {
                #[inline]
                #[target_feature(enable = "vsx")]
                unsafe fn vec_xxpermdi(self, b: Self, dm: u8) -> Self {
                    mem::transmute(xxpermdi(mem::transmute(self), mem::transmute(b), dm))
                }
            }
        }
    }

    vec_xxpermdi! { vector_unsigned_long }
    vec_xxpermdi! { vector_signed_long }
    vec_xxpermdi! { vector_bool_long }
    vec_xxpermdi! { vector_double }
}

/// Vector permute.
#[inline]
#[target_feature(enable = "vsx")]
#[rustc_args_required_const(2)]
pub unsafe fn vec_xxpermdi<T>(a: T, b: T, dm: u8) -> T
where
    T: sealed::VectorPermDI,
{
    a.vec_xxpermdi(b, dm)
}

#[cfg(test)]
mod tests {
    #[cfg(target_arch = "powerpc")]
    use coresimd::arch::powerpc::*;

    #[cfg(target_arch = "powerpc64")]
    use coresimd::arch::powerpc64::*;

    use simd::*;
    use stdsimd_test::simd_test;

    macro_rules! test_vec_xxpermdi {
        {$name:ident, $shorttype:ident, $longtype:ident, [$($a:expr),+], [$($b:expr),+], [$($c:expr),+], [$($d:expr),+]} => {
            #[simd_test(enable = "vsx")]
            unsafe fn $name() {
                let a: $longtype = $shorttype::new($($a),+, $($b),+).into_bits();
                let b = $shorttype::new($($c),+, $($d),+).into_bits();

                assert_eq!($shorttype::new($($a),+, $($c),+), vec_xxpermdi(a, b, 0).into_bits());
                assert_eq!($shorttype::new($($b),+, $($c),+), vec_xxpermdi(a, b, 1).into_bits());
                assert_eq!($shorttype::new($($a),+, $($d),+), vec_xxpermdi(a, b, 2).into_bits());
                assert_eq!($shorttype::new($($b),+, $($d),+), vec_xxpermdi(a, b, 3).into_bits());
            }
        }
    }

    test_vec_xxpermdi!{test_vec_xxpermdi_u64x2, u64x2, vector_unsigned_long, [0], [1], [2], [3]}
    test_vec_xxpermdi!{test_vec_xxpermdi_i64x2, i64x2, vector_signed_long, [0], [-1], [2], [-3]}
    test_vec_xxpermdi!{test_vec_xxpermdi_m64x2, m64x2, vector_bool_long, [false], [true], [false], [true]}
    test_vec_xxpermdi!{test_vec_xxpermdi_f64x2, f64x2, vector_double, [0.0], [1.0], [2.0], [3.0]}
}
<|endoftext|>


<commit_before>#[doc = "Build indexes as appropriate for the markdown pass"];

export mk_pass;

fn mk_pass(config: config::config) -> pass {
    {
        name: "markdown_index",
        f: fn~(srv: astsrv::srv, doc: doc::doc) -> doc::doc {
            run(srv, doc, config)
        }
    }
}

fn run(
    _srv: astsrv::srv,
    doc: doc::doc,
    config: config::config
) -> doc::doc {
    let fold = fold::fold({
        fold_mod: fold_mod
            with *fold::default_any_fold(config)
    });
    fold.fold_doc(fold, doc)
}

fn fold_mod(
    fold: fold::fold<config::config>,
    doc: doc::moddoc
) -> doc::moddoc {

    let doc = fold::default_any_fold_mod(fold, doc);

    {
        index: some(build_index(doc, fold.ctxt))
        with doc
    }
}

fn build_index(
    doc: doc::moddoc,
    config: config::config
) -> doc::index {
    {
        entries: par::anymap(doc.items) {|item|
            item_to_entry(item, config)
        }
    }
}

fn item_to_entry(
    doc: doc::itemtag,
    config: config::config
) -> doc::index_entry {
    let link = alt doc {
      doc::modtag(_) if config.output_style == config::doc_per_mod {
        markdown_writer::make_filename(config, doc::itempage(doc))
      }
      _ {
        "#" + pandoc_header_id(markdown_pass::header_text(doc))
      }
    };

    {
        kind: markdown_pass::header_kind(doc),
        name: markdown_pass::header_name(doc),
        brief: doc.brief(),
        link: link
    }
}

fn pandoc_header_id(header: str) -> str {

    // http://johnmacfarlane.net/pandoc/README.html#headers

    let header = remove_formatting(header);
    let header = remove_punctuation(header);
    let header = replace_with_hyphens(header);
    let header = convert_to_lowercase(header);
    let header = remove_up_to_first_letter(header);
    let header = maybe_use_section_id(header);
    ret header;

    fn remove_formatting(s: str) -> str {
        str::replace(s, "`", "")
    }
    fn remove_punctuation(s: str) -> str {
        let s = str::replace(s, "<", "");
        let s = str::replace(s, ">", "");
        ret s;
    }
    fn replace_with_hyphens(s: str) -> str {
        str::replace(s, " ", "-")
    }
    fn convert_to_lowercase(s: str) -> str { str::to_lower(s) }
    fn remove_up_to_first_letter(s: str) -> str { s }
    fn maybe_use_section_id(s: str) -> str { s }
}

#[test]
fn should_remove_brackets_from_headers() {
    assert pandoc_header_id("impl foo of bar<A>") == "impl-foo-of-bara";
}

#[test]
fn should_index_mod_contents() {
    let doc = test::mk_doc(
        config::doc_per_crate,
        "mod a { } fn b() { }"
    );
    assert option::get(doc.cratemod().index).entries[0] == {
        kind: "Module",
        name: "a",
        brief: none,
        link: "#module-a"
    };
    assert option::get(doc.cratemod().index).entries[1] == {
        kind: "Function",
        name: "b",
        brief: none,
        link: "#function-b"
    };
}

#[test]
fn should_index_mod_contents_multi_page() {
    let doc = test::mk_doc(
        config::doc_per_mod,
        "mod a { } fn b() { }"
    );
    assert option::get(doc.cratemod().index).entries[0] == {
        kind: "Module",
        name: "a",
        brief: none,
        link: "a.html"
    };
    assert option::get(doc.cratemod().index).entries[1] == {
        kind: "Function",
        name: "b",
        brief: none,
        link: "#function-b"
    };
}

#[test]
fn should_add_brief_desc_to_index() {
    let doc = test::mk_doc(
        config::doc_per_mod,
        "#[doc = \"test\"] mod a { }"
    );
    assert option::get(doc.cratemod().index).entries[0].brief == some("test");
}

#[cfg(test)]
mod test {
    fn mk_doc(output_style: config::output_style, source: str) -> doc::doc {
        astsrv::from_str(source) {|srv|
            let config = {
                output_style: output_style
                with config::default_config("whatever")
            };
            let doc = extract::from_srv(srv, "");
            let doc = attr_pass::mk_pass().f(srv, doc);
            let doc = desc_to_brief_pass::mk_pass().f(srv, doc);
            let doc = path_pass::mk_pass().f(srv, doc);
            run(srv, doc, config)
        }
    }
}
<commit_msg>rustdoc: Fix generation of impl links. Closes #1953<commit_after>#[doc = "Build indexes as appropriate for the markdown pass"];

export mk_pass;

fn mk_pass(config: config::config) -> pass {
    {
        name: "markdown_index",
        f: fn~(srv: astsrv::srv, doc: doc::doc) -> doc::doc {
            run(srv, doc, config)
        }
    }
}

fn run(
    _srv: astsrv::srv,
    doc: doc::doc,
    config: config::config
) -> doc::doc {
    let fold = fold::fold({
        fold_mod: fold_mod
            with *fold::default_any_fold(config)
    });
    fold.fold_doc(fold, doc)
}

fn fold_mod(
    fold: fold::fold<config::config>,
    doc: doc::moddoc
) -> doc::moddoc {

    let doc = fold::default_any_fold_mod(fold, doc);

    {
        index: some(build_index(doc, fold.ctxt))
        with doc
    }
}

fn build_index(
    doc: doc::moddoc,
    config: config::config
) -> doc::index {
    {
        entries: par::anymap(doc.items) {|item|
            item_to_entry(item, config)
        }
    }
}

fn item_to_entry(
    doc: doc::itemtag,
    config: config::config
) -> doc::index_entry {
    let link = alt doc {
      doc::modtag(_) if config.output_style == config::doc_per_mod {
        markdown_writer::make_filename(config, doc::itempage(doc))
      }
      _ {
        "#" + pandoc_header_id(markdown_pass::header_text(doc))
      }
    };

    {
        kind: markdown_pass::header_kind(doc),
        name: markdown_pass::header_name(doc),
        brief: doc.brief(),
        link: link
    }
}

fn pandoc_header_id(header: str) -> str {

    // http://johnmacfarlane.net/pandoc/README.html#headers

    let header = remove_formatting(header);
    let header = remove_punctuation(header);
    let header = replace_with_hyphens(header);
    let header = convert_to_lowercase(header);
    let header = remove_up_to_first_letter(header);
    let header = maybe_use_section_id(header);
    ret header;

    fn remove_formatting(s: str) -> str {
        str::replace(s, "`", "")
    }
    fn remove_punctuation(s: str) -> str {
        let s = str::replace(s, "<", "");
        let s = str::replace(s, ">", "");
        let s = str::replace(s, "[", "");
        let s = str::replace(s, "]", "");
        let s = str::replace(s, "(", "");
        let s = str::replace(s, ")", "");
        let s = str::replace(s, "@", "");
        let s = str::replace(s, "~", "");
        ret s;
    }
    fn replace_with_hyphens(s: str) -> str {
        str::replace(s, " ", "-")
    }
    fn convert_to_lowercase(s: str) -> str { str::to_lower(s) }
    fn remove_up_to_first_letter(s: str) -> str { s }
    fn maybe_use_section_id(s: str) -> str { s }
}

#[test]
fn should_remove_punctuation_from_headers() {
    assert pandoc_header_id("impl foo of bar<A>") == "impl-foo-of-bara";
    assert pandoc_header_id("fn@([~A])") == "fna";
}

#[test]
fn should_index_mod_contents() {
    let doc = test::mk_doc(
        config::doc_per_crate,
        "mod a { } fn b() { }"
    );
    assert option::get(doc.cratemod().index).entries[0] == {
        kind: "Module",
        name: "a",
        brief: none,
        link: "#module-a"
    };
    assert option::get(doc.cratemod().index).entries[1] == {
        kind: "Function",
        name: "b",
        brief: none,
        link: "#function-b"
    };
}

#[test]
fn should_index_mod_contents_multi_page() {
    let doc = test::mk_doc(
        config::doc_per_mod,
        "mod a { } fn b() { }"
    );
    assert option::get(doc.cratemod().index).entries[0] == {
        kind: "Module",
        name: "a",
        brief: none,
        link: "a.html"
    };
    assert option::get(doc.cratemod().index).entries[1] == {
        kind: "Function",
        name: "b",
        brief: none,
        link: "#function-b"
    };
}

#[test]
fn should_add_brief_desc_to_index() {
    let doc = test::mk_doc(
        config::doc_per_mod,
        "#[doc = \"test\"] mod a { }"
    );
    assert option::get(doc.cratemod().index).entries[0].brief == some("test");
}

#[cfg(test)]
mod test {
    fn mk_doc(output_style: config::output_style, source: str) -> doc::doc {
        astsrv::from_str(source) {|srv|
            let config = {
                output_style: output_style
                with config::default_config("whatever")
            };
            let doc = extract::from_srv(srv, "");
            let doc = attr_pass::mk_pass().f(srv, doc);
            let doc = desc_to_brief_pass::mk_pass().f(srv, doc);
            let doc = path_pass::mk_pass().f(srv, doc);
            run(srv, doc, config)
        }
    }
}
<|endoftext|>


<commit_before>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::CHashMap;
use std::collections::{BTreeMap, BTreeSet};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use futures::sync::mpsc::{Sender, Receiver, channel};
use super::*;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
}

struct DataObject {
    server: u64,
    cell: Option<Cell>
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
    await_chan: (Sender<()>, Receiver<()>)
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError>;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError>;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError>;

    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new()
        })
    }
}

impl TransactionManager {
    fn get_data_site(&self, server_id: u64) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok((self.data_sites .get(&server_id).unwrap().clone(), server_id))
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => self.get_data_site(id),
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.tnx_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.tnx_peer.clock.merge_with(clock)
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.tnx_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new(),
            await_chan: channel(1)
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut tnx = {
            match self.transactions.get_mut(tid) {
                Some(tnx) => tnx,
                _ => {return Err(TMError::TransactionNotFound)}
            }
        };
        if let Some(dataObj) = tnx.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server, server_id)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone())
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None
                                });
                            }
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}
<commit_msg>write in workspace in transaction manager<commit_after>use bifrost::vector_clock::{VectorClock, StandardVectorClock, ServerVectorClock};
use bifrost::utils::time::get_time;
use chashmap::{CHashMap, WriteGuard};
use std::collections::{BTreeMap, BTreeSet};
use ram::types::{Id};
use ram::cell::{Cell, ReadError, WriteError};
use server::NebServer;
use futures::sync::mpsc::{Sender, Receiver, channel};
use super::*;

pub static DEFAULT_SERVICE_ID: u64 = hash_ident!(TNX_MANAGER_RPC_SERVICE) as u64;

#[derive(Debug, Serialize, Deserialize)]
pub enum TMError {
    TransactionNotFound,
    CannotLocateCellServer,
    NoResponseFromCellServer,
}

struct DataObject {
    server: u64,
    cell: Option<Cell>
}

struct Transaction {
    start_time: i64, // use for timeout detecting
    id: TransactionId,
    data: BTreeMap<Id, DataObject>,
    writes: BTreeSet<Id>,
    await_chan: (Sender<()>, Receiver<()>)
}

service! {
    rpc begin() -> TransactionId;
    rpc read(tid: TransactionId, id: Id) -> TransactionExecResult<Cell, ReadError> | TMError;
    rpc write(tid: TransactionId, id: Id, cell: Cell) -> TransactionExecResult<(), WriteError> | TMError;
    rpc update(tid: TransactionId, cell: Cell) -> TransactionExecResult<(), WriteError>;
    rpc remove(tid: TransactionId, id: Id) -> TransactionExecResult<(), WriteError>;

    rpc commit(tid: TransactionId);
    rpc abort(tid: TransactionId);

    rpc go_ahead(tid: BTreeSet<TransactionId>); // invoked by data site to continue on it's transaction in case of waiting
}

pub struct TransactionManager {
    server: Arc<NebServer>,
    transactions: CHashMap<TransactionId, Transaction>,
    data_sites: CHashMap<u64, Arc<data_site::AsyncServiceClient>>,
}
dispatch_rpc_service_functions!(TransactionManager);

impl TransactionManager {
    pub fn new(server: &Arc<NebServer>) -> Arc<TransactionManager> {
        Arc::new(TransactionManager {
            server: server.clone(),
            transactions: CHashMap::new(),
            data_sites: CHashMap::new()
        })
    }
}

impl TransactionManager {
    fn get_data_site(&self, server_id: u64) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        if !self.data_sites.contains_key(&server_id) {
            let client = self.server.get_member_by_server_id(server_id)?;
            self.data_sites.upsert(server_id, || {
                data_site::AsyncServiceClient::new(DEFAULT_SERVICE_ID, &client)
            }, |_| {});
        }
        Ok((self.data_sites .get(&server_id).unwrap().clone(), server_id))
    }
    fn get_data_site_by_id(&self, id: &Id) -> io::Result<(Arc<data_site::AsyncServiceClient>, u64)> {
        match self.server.get_server_id_by_id(id) {
            Some(id) => self.get_data_site(id),
            _ => Err(io::Error::new(io::ErrorKind::NotFound, "cannot find data site for this id"))
        }
    }
    fn get_clock(&self) -> StandardVectorClock {
        self.server.tnx_peer.clock.to_clock()
    }
    fn merge_clock(&self, clock: &StandardVectorClock) {
        self.server.tnx_peer.clock.merge_with(clock)
    }
    fn get_transaction(&self, tid: &TransactionId) -> Result<WriteGuard<TransactionId, Transaction>, TMError> {
        match self.transactions.get_mut(tid) {
            Some(tnx) => Ok(tnx),
            _ => {Err(TMError::TransactionNotFound)}
        }
    }
}

impl Service for TransactionManager {
    fn begin(&self) -> Result<TransactionId, ()> {
        let id = self.server.tnx_peer.clock.inc();
        self.transactions.insert(id.clone(), Transaction {
            start_time: get_time(),
            id: id.clone(),
            data: BTreeMap::new(),
            writes: BTreeSet::new(),
            await_chan: channel(1)
        });
        Ok(id)
    }
    fn read(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<Cell, ReadError>, TMError> {
        let mut tnx = self.get_transaction(tid)?;
        if let Some(dataObj) = tnx.data.get(id) {
            match dataObj.cell {
                Some(ref cell) => {
                    return Ok(TransactionExecResult::Accepted(cell.clone())) // read from cache
                },
                None => {
                   return Ok(TransactionExecResult::Error(ReadError::CellDoesNotExisted))
                }
            }
        }
        let server = self.get_data_site_by_id(&id);
        match server {
            Ok((server, server_id)) => {
                let self_server_id = self.server.server_id;
                let read_response = server.read(
                    &self_server_id,
                    &self.get_clock(),
                    tid, id
                ).wait();
                match read_response {
                    Ok(dsr) => {
                        let dsr = dsr.unwrap();
                        self.merge_clock(&dsr.clock);
                        match dsr.payload {
                            TransactionExecResult::Accepted(ref cell) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: Some(cell.clone())
                                });
                            },
                            TransactionExecResult::Error(ReadError::CellDoesNotExisted) => {
                                tnx.data.insert(*id, DataObject {
                                    server: server_id,
                                    cell: None
                                });
                            }
                            _ => {}
                        }
                        Ok(dsr.payload)
                    },
                    Err(e) => {
                        error!("{:?}", e);
                        Err(TMError::NoResponseFromCellServer)
                    }
                }
            },
            Err(e) => {
                error!("{:?}", e);
                Err(TMError::CannotLocateCellServer)
            }
        }
    }
    fn write(&self, tid: &TransactionId, id: &Id, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, TMError> {
        let mut tnx = self.get_transaction(tid)?;
        match self.server.get_server_id_by_id(id) {
            Some(server_id) => {
                tnx.data.insert(*id, DataObject {
                    server: server_id,
                    cell: Some(cell.clone())
                });
                Ok(TransactionExecResult::Accepted(()))
            },
            None => Err(TMError::CannotLocateCellServer)
        }
    }
    fn update(&self, tid: &TransactionId, cell: &Cell) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn remove(&self, tid: &TransactionId, id: &Id) -> Result<TransactionExecResult<(), WriteError>, ()> {
        Err(())
    }
    fn commit(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn abort(&self, tid: &TransactionId) -> Result<(), ()> {
        Err(())
    }
    fn go_ahead(&self, tid: &BTreeSet<TransactionId>) -> Result<(), ()> {
        Err(())
    }
}
<|endoftext|>


<commit_before>/*
The first test case using pipes. The idea is to break this into
several stages for prototyping. Here's the plan:

1. Write an already-compiled protocol using existing ports and chans.

2. Take the already-compiled version and add the low-level
synchronization code instead.

3. Write a syntax extension to compile the protocols.

At some point, we'll need to add support for select.

This file does horrible things to pretend we have self-move.

*/

// Hopefully someday we'll move this into core.
mod pipes {
    import unsafe::{forget, reinterpret_cast};

    enum state {
        empty,
        full,
        blocked,
        terminated
    }

    type packet<T: send> = {
        mut state: state,
        mut blocked_task: option<task::task>,
        mut payload: option<T>
    };

    fn packet<T: send>() -> *packet<T> unsafe {
        let p: *packet<T> = unsafe::transmute(~{
            mut state: empty,
            mut blocked_task: none::<task::task>,
            mut payload: none::<T>
        });
        p
    }

    #[abi = "rust-intrinsic"]
    native mod rusti {
        fn atomic_xchng(&dst: int, src: int) -> int;
        fn atomic_xchng_acq(&dst: int, src: int) -> int;
        fn atomic_xchng_rel(&dst: int, src: int) -> int;
    }

    // We should consider moving this to core::unsafe, although I
    // suspect graydon would want us to use void pointers instead.
    unsafe fn uniquify<T>(x: *T) -> ~T {
        unsafe { unsafe::reinterpret_cast(x) }
    }

    fn swap_state_acq(&dst: state, src: state) -> state {
        unsafe {
            reinterpret_cast(rusti::atomic_xchng_acq(
                *(ptr::mut_addr_of(dst) as *mut int),
                src as int))
        }
    }

    fn swap_state_rel(&dst: state, src: state) -> state {
        unsafe {
            reinterpret_cast(rusti::atomic_xchng_rel(
                *(ptr::mut_addr_of(dst) as *mut int),
                src as int))
        }
    }

    fn send<T: send>(-p: send_packet<T>, -payload: T) {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        assert (*p).payload == none;
        (*p).payload <- some(payload);
        let old_state = swap_state_rel((*p).state, full);
        alt old_state {
          empty {
            // Yay, fastpath.

            // The receiver will eventually clean this up.
            unsafe { forget(p); }
          }
          full { fail "duplicate send" }
          blocked {
            // FIXME: once the target will actually block, tell the
            // scheduler to wake it up.

            // The receiver will eventually clean this up.
            unsafe { forget(p); }
          }
          terminated {
            // The receiver will never receive this. Rely on drop_glue
            // to clean everything up.
          }
        }
    }

    fn recv<T: send>(-p: recv_packet<T>) -> option<T> {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        loop {
            let old_state = swap_state_acq((*p).state,
                                           blocked);
            alt old_state {
              empty | blocked { task::yield(); }
              full {
                let mut payload = none;
                payload <-> (*p).payload;
                ret some(option::unwrap(payload))
              }
              terminated {
                assert old_state == terminated;
                ret none;
              }
            }
        }
    }

    fn sender_terminate<T: send>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        alt swap_state_rel((*p).state, terminated) {
          empty | blocked {
            // The receiver will eventually clean up.
            unsafe { forget(p) }
          }
          full {
            // This is impossible
            fail "you dun goofed"
          }
          terminated {
            // I have to clean up, use drop_glue
          }
        }
    }

    fn receiver_terminate<T: send>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        alt swap_state_rel((*p).state, terminated) {
          empty {
            // the sender will clean up
            unsafe { forget(p) }
          }
          blocked {
            // this shouldn't happen.
            fail "terminating a blocked packet"
          }
          terminated | full {
            // I have to clean up, use drop_glue
          }
        }
    }

    class send_packet<T: send> {
        let mut p: option<*packet<T>>;
        new(p: *packet<T>) { self.p = some(p); }
        drop {
            if self.p != none {
                let mut p = none;
                p <-> self.p;
                sender_terminate(option::unwrap(p))
            }
        }
        fn unwrap() -> *packet<T> {
            let mut p = none;
            p <-> self.p;
            option::unwrap(p)
        }
    }

    class recv_packet<T: send> {
        let mut p: option<*packet<T>>;
        new(p: *packet<T>) { self.p = some(p); }
        drop {
            if self.p != none {
                let mut p = none;
                p <-> self.p;
                receiver_terminate(option::unwrap(p))
            }
        }
        fn unwrap() -> *packet<T> {
            let mut p = none;
            p <-> self.p;
            option::unwrap(p)
        }
    }

    fn entangle<T: send>() -> (send_packet<T>, recv_packet<T>) {
        let p = packet();
        (send_packet(p), recv_packet(p))
    }
}

mod pingpong {
    enum ping { ping, }
    enum ping_message = *pipes::packet<pong_message>;
    enum pong { pong, }
    enum pong_message = *pipes::packet<ping_message>;

    fn init() -> (client::ping, server::ping) {
        pipes::entangle()
    }

    mod client {
        type ping = pipes::send_packet<pingpong::ping_message>;
        type pong = pipes::recv_packet<pingpong::pong_message>;
    }

    impl abominable for client::ping {
        fn send() -> fn@(-client::ping, ping) -> client::pong {
            {|pipe, data|
                let p = pipes::packet();
                pipes::send(pipe, pingpong::ping_message(p));
                pipes::recv_packet(p)
            }
        }
    }

    impl abominable for client::pong {
        fn recv() -> fn@(-client::pong) -> (client::ping, pong) {
            {|pipe|
                let packet = pipes::recv(pipe);
                if packet == none {
                    fail "sender closed the connection"
                }
                let p : pong_message = option::unwrap(packet);
                (pipes::send_packet(*p), pong)
            }
        }
    }

    mod server {
        type ping = pipes::recv_packet<pingpong::ping_message>;
        type pong = pipes::send_packet<pingpong::pong_message>;
    }

    impl abominable for server::ping {
        fn recv() -> fn@(-server::ping) -> (server::pong, ping) {
            {|pipe|
                let packet = pipes::recv(pipe);
                if packet == none {
                    fail "sender closed the connection"
                }
                let p : ping_message = option::unwrap(packet);
                (pipes::send_packet(*p), ping)
            }
        }
    }

    impl abominable for server::pong {
        fn send() -> fn@(-server::pong, pong) -> server::ping {
            {|pipe, data|
                let p = pipes::packet();
                pipes::send(pipe, pingpong::pong_message(p));
                pipes::recv_packet(p)
            }
        }
    }
}

mod test {
    import pingpong::{ping, pong, abominable};

    fn macros() {
        #macro[
            [#send[chan, data, ...],
             chan.send()(chan, data, ...)]
        ];
        #macro[
            [#recv[chan],
             chan.recv()(chan)]
        ];
    }

    fn client(-chan: pingpong::client::ping) {
        let chan = #send(chan, ping);
        log(error, "Sent ping");
        let (chan, _data) = #recv(chan);
        log(error, "Received pong");
    }

    fn server(-chan: pingpong::server::ping) {
        let (chan, _data) = #recv(chan);
        log(error, "Received ping");
        let chan = #send(chan, pong);
        log(error, "Sent pong");
    }
}

fn main() {
    let (client_, server_) = pingpong::init();
    let client_ = ~mut some(client_);
    let server_ = ~mut some(server_);

    task::spawn {|move client_|
        let mut client__ = none;
        *client_ <-> client__;
        test::client(option::unwrap(client__));
    };
    task::spawn {|move server_|
        let mut server_ˊ = none;
        *server_ <-> server_ˊ;
        test::server(option::unwrap(server_ˊ));
    };
}
<commit_msg>send only takes one data argument.<commit_after>/*
The first test case using pipes. The idea is to break this into
several stages for prototyping. Here's the plan:

1. Write an already-compiled protocol using existing ports and chans.

2. Take the already-compiled version and add the low-level
synchronization code instead.

3. Write a syntax extension to compile the protocols.

At some point, we'll need to add support for select.

This file does horrible things to pretend we have self-move.

*/

// Hopefully someday we'll move this into core.
mod pipes {
    import unsafe::{forget, reinterpret_cast};

    enum state {
        empty,
        full,
        blocked,
        terminated
    }

    type packet<T: send> = {
        mut state: state,
        mut blocked_task: option<task::task>,
        mut payload: option<T>
    };

    fn packet<T: send>() -> *packet<T> unsafe {
        let p: *packet<T> = unsafe::transmute(~{
            mut state: empty,
            mut blocked_task: none::<task::task>,
            mut payload: none::<T>
        });
        p
    }

    #[abi = "rust-intrinsic"]
    native mod rusti {
        fn atomic_xchng(&dst: int, src: int) -> int;
        fn atomic_xchng_acq(&dst: int, src: int) -> int;
        fn atomic_xchng_rel(&dst: int, src: int) -> int;
    }

    // We should consider moving this to core::unsafe, although I
    // suspect graydon would want us to use void pointers instead.
    unsafe fn uniquify<T>(x: *T) -> ~T {
        unsafe { unsafe::reinterpret_cast(x) }
    }

    fn swap_state_acq(&dst: state, src: state) -> state {
        unsafe {
            reinterpret_cast(rusti::atomic_xchng_acq(
                *(ptr::mut_addr_of(dst) as *mut int),
                src as int))
        }
    }

    fn swap_state_rel(&dst: state, src: state) -> state {
        unsafe {
            reinterpret_cast(rusti::atomic_xchng_rel(
                *(ptr::mut_addr_of(dst) as *mut int),
                src as int))
        }
    }

    fn send<T: send>(-p: send_packet<T>, -payload: T) {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        assert (*p).payload == none;
        (*p).payload <- some(payload);
        let old_state = swap_state_rel((*p).state, full);
        alt old_state {
          empty {
            // Yay, fastpath.

            // The receiver will eventually clean this up.
            unsafe { forget(p); }
          }
          full { fail "duplicate send" }
          blocked {
            // FIXME: once the target will actually block, tell the
            // scheduler to wake it up.

            // The receiver will eventually clean this up.
            unsafe { forget(p); }
          }
          terminated {
            // The receiver will never receive this. Rely on drop_glue
            // to clean everything up.
          }
        }
    }

    fn recv<T: send>(-p: recv_packet<T>) -> option<T> {
        let p = p.unwrap();
        let p = unsafe { uniquify(p) };
        loop {
            let old_state = swap_state_acq((*p).state,
                                           blocked);
            alt old_state {
              empty | blocked { task::yield(); }
              full {
                let mut payload = none;
                payload <-> (*p).payload;
                ret some(option::unwrap(payload))
              }
              terminated {
                assert old_state == terminated;
                ret none;
              }
            }
        }
    }

    fn sender_terminate<T: send>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        alt swap_state_rel((*p).state, terminated) {
          empty | blocked {
            // The receiver will eventually clean up.
            unsafe { forget(p) }
          }
          full {
            // This is impossible
            fail "you dun goofed"
          }
          terminated {
            // I have to clean up, use drop_glue
          }
        }
    }

    fn receiver_terminate<T: send>(p: *packet<T>) {
        let p = unsafe { uniquify(p) };
        alt swap_state_rel((*p).state, terminated) {
          empty {
            // the sender will clean up
            unsafe { forget(p) }
          }
          blocked {
            // this shouldn't happen.
            fail "terminating a blocked packet"
          }
          terminated | full {
            // I have to clean up, use drop_glue
          }
        }
    }

    class send_packet<T: send> {
        let mut p: option<*packet<T>>;
        new(p: *packet<T>) { self.p = some(p); }
        drop {
            if self.p != none {
                let mut p = none;
                p <-> self.p;
                sender_terminate(option::unwrap(p))
            }
        }
        fn unwrap() -> *packet<T> {
            let mut p = none;
            p <-> self.p;
            option::unwrap(p)
        }
    }

    class recv_packet<T: send> {
        let mut p: option<*packet<T>>;
        new(p: *packet<T>) { self.p = some(p); }
        drop {
            if self.p != none {
                let mut p = none;
                p <-> self.p;
                receiver_terminate(option::unwrap(p))
            }
        }
        fn unwrap() -> *packet<T> {
            let mut p = none;
            p <-> self.p;
            option::unwrap(p)
        }
    }

    fn entangle<T: send>() -> (send_packet<T>, recv_packet<T>) {
        let p = packet();
        (send_packet(p), recv_packet(p))
    }
}

mod pingpong {
    enum ping { ping, }
    enum ping_message = *pipes::packet<pong_message>;
    enum pong { pong, }
    enum pong_message = *pipes::packet<ping_message>;

    fn init() -> (client::ping, server::ping) {
        pipes::entangle()
    }

    mod client {
        type ping = pipes::send_packet<pingpong::ping_message>;
        type pong = pipes::recv_packet<pingpong::pong_message>;
    }

    impl abominable for client::ping {
        fn send() -> fn@(-client::ping, ping) -> client::pong {
            {|pipe, data|
                let p = pipes::packet();
                pipes::send(pipe, pingpong::ping_message(p));
                pipes::recv_packet(p)
            }
        }
    }

    impl abominable for client::pong {
        fn recv() -> fn@(-client::pong) -> (client::ping, pong) {
            {|pipe|
                let packet = pipes::recv(pipe);
                if packet == none {
                    fail "sender closed the connection"
                }
                let p : pong_message = option::unwrap(packet);
                (pipes::send_packet(*p), pong)
            }
        }
    }

    mod server {
        type ping = pipes::recv_packet<pingpong::ping_message>;
        type pong = pipes::send_packet<pingpong::pong_message>;
    }

    impl abominable for server::ping {
        fn recv() -> fn@(-server::ping) -> (server::pong, ping) {
            {|pipe|
                let packet = pipes::recv(pipe);
                if packet == none {
                    fail "sender closed the connection"
                }
                let p : ping_message = option::unwrap(packet);
                (pipes::send_packet(*p), ping)
            }
        }
    }

    impl abominable for server::pong {
        fn send() -> fn@(-server::pong, pong) -> server::ping {
            {|pipe, data|
                let p = pipes::packet();
                pipes::send(pipe, pingpong::pong_message(p));
                pipes::recv_packet(p)
            }
        }
    }
}

mod test {
    import pingpong::{ping, pong, abominable};

    fn macros() {
        #macro[
            [#send[chan, data],
             chan.send()(chan, data)]
        ];
        #macro[
            [#recv[chan],
             chan.recv()(chan)]
        ];
    }

    fn client(-chan: pingpong::client::ping) {
        let chan = #send(chan, ping);
        log(error, "Sent ping");
        let (chan, _data) = #recv(chan);
        log(error, "Received pong");
    }

    fn server(-chan: pingpong::server::ping) {
        let (chan, _data) = #recv(chan);
        log(error, "Received ping");
        let chan = #send(chan, pong);
        log(error, "Sent pong");
    }
}

fn main() {
    let (client_, server_) = pingpong::init();
    let client_ = ~mut some(client_);
    let server_ = ~mut some(server_);

    task::spawn {|move client_|
        let mut client__ = none;
        *client_ <-> client__;
        test::client(option::unwrap(client__));
    };
    task::spawn {|move server_|
        let mut server_ˊ = none;
        *server_ <-> server_ˊ;
        test::server(option::unwrap(server_ˊ));
    };
}
<|endoftext|>


<commit_before>// test the behavior of the --no-run flag

// check-pass
// compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"

/// ```
/// let a = true;
/// ```
/// ```should_panic
/// panic!()
/// ```
/// ```ignore
/// fn foo() {
/// ```
/// ```no_run
/// loop {
///     println!("Hello, world");
/// }
/// ```
/// fails to compile
/// ```compile_fail
/// let x = 5;
/// x += 2; // shouldn't compile!
/// ```
/// Ok the test does not run
/// ```
/// panic!()
/// ```
/// Ok the test does not run
/// ```should_panic
/// loop {
///     println!("Hello, world");
/// panic!()
/// }
/// ```
pub fn f() {}
<commit_msg>fix failing tidy check<commit_after>// test the behavior of the --no-run flag

// check-pass
// compile-flags:-Z unstable-options --test --no-run --test-args=--test-threads=1
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME"

/// ```
/// let a = true;
/// ```
/// ```should_panic
/// panic!()
/// ```
/// ```ignore (incomplete-code)
/// fn foo() {
/// ```
/// ```no_run
/// loop {
///     println!("Hello, world");
/// }
/// ```
/// fails to compile
/// ```compile_fail
/// let x = 5;
/// x += 2; // shouldn't compile!
/// ```
/// Ok the test does not run
/// ```
/// panic!()
/// ```
/// Ok the test does not run
/// ```should_panic
/// loop {
///     println!("Hello, world");
/// panic!()
/// }
/// ```
pub fn f() {}
<|endoftext|>