<commit_before>use search_algorithms::game_move;
use std::ops;
use std::fmt;
use self::Color::*;
use rand;
use rand::Rng;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Color {
    White,
    Black,
}
impl ops::Not for Color {
    type Output = Color;

    fn not(self) -> Self {
        match self {
            White => Black,
            Black => White,
        }
    }
}

impl fmt::Display for Color {
    fn fmt(&self, fmt : &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let _ = fmt.write_str( match self {
            &White => ("White"),
            &Black => ("Black"),
        });

        Ok(())
    }
}
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum GameResult {
    WhiteWin,
    BlackWin,
    Draw,
}

pub trait EvalBoard : PartialEq + Clone {
    type Move : game_move::Move + Clone;
    type UndoMove : Clone;

    /// Returns whose turn it is
    fn to_move(&self) -> Color;

    fn do_move(&mut self, Self::Move) -> Self::UndoMove;
    fn undo_move(&mut self, Self::UndoMove);

    fn start_board() -> &'static Self;

    fn all_legal_moves(&self) -> Vec<Self::Move>;

    /// Returns the result if the game is decided, otherwise returns None.
    /// This function should return quickly if the game is not decided yet.
    fn game_result(&self) -> Option<GameResult>;

    fn eval_board(&self) -> f32;

    fn do_random_move<R: rand::Rng>(&mut self, rng: &mut R) {
        let moves = self.all_legal_moves();
        self.do_move(moves[rng.gen_range(0, moves.len())].clone());
    }
}
<commit_msg>board::GameResult now implements the not operator<commit_after>use search_algorithms::game_move;
use std::ops;
use std::fmt;
use self::Color::*;
use rand;
use rand::Rng;

#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Color {
    White,
    Black,
}
impl ops::Not for Color {
    type Output = Color;

    fn not(self) -> Self {
        match self {
            White => Black,
            Black => White,
        }
    }
}

impl fmt::Display for Color {
    fn fmt(&self, fmt : &mut fmt::Formatter) -> Result<(), fmt::Error> {
        let _ = fmt.write_str( match self {
            &White => ("White"),
            &Black => ("Black"),
        });

        Ok(())
    }
}
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum GameResult {
    WhiteWin,
    BlackWin,
    Draw,
}

impl ops::Not for GameResult {
    type Output = Self;
    fn not(self) -> Self {
        match self {
            GameResult::WhiteWin => GameResult::BlackWin,
            GameResult::BlackWin => GameResult::WhiteWin,
            GameResult::Draw => GameResult::Draw,
        }
    }
}

pub trait EvalBoard : PartialEq + Clone {
    type Move : game_move::Move + Clone;
    type UndoMove : Clone;

    /// Returns whose turn it is
    fn to_move(&self) -> Color;

    fn do_move(&mut self, Self::Move) -> Self::UndoMove;
    fn undo_move(&mut self, Self::UndoMove);

    fn start_board() -> &'static Self;

    fn all_legal_moves(&self) -> Vec<Self::Move>;

    /// Returns the result if the game is decided, otherwise returns None.
    /// This function should return quickly if the game is not decided yet.
    fn game_result(&self) -> Option<GameResult>;

    fn eval_board(&self) -> f32;

    fn do_random_move<R: rand::Rng>(&mut self, rng: &mut R) {
        let moves = self.all_legal_moves();
        self.do_move(moves[rng.gen_range(0, moves.len())].clone());
    }
}
<|endoftext|>


<commit_before>use std::marker::PhantomData;
use cgmath;
use cgmath::FixedArray;
use gfx;
use grid;
use grid::Grid;
use scene;

#[shader_param]
struct Param<R: gfx::Resources> {
    mvp: [[f32; 4]; 4],
    color: [f32; 4],
    _dummy: PhantomData<R>,
}

#[vertex_format]
#[derive(Clone, Copy)]
struct Vertex {
    position: [f32; 2],
}

impl Vertex {
    pub fn new(x: f32, y: f32) -> Vertex {
        Vertex {
            position: [x, y],
        }
    }
}

#[cfg(not(target_os = "macos"))]
static VERTEX_SRC: &'static [u8] = b"
    #version 120

    uniform mat4 mvp;
    attribute vec2 position;

    void main() {
        gl_Position = mvp * vec4(position, 0.0, 1.0);
        gl_PointSize = 2.0;
    }
";

#[cfg(target_os = "macos")]
static VERTEX_SRC: &'static [u8] = b"
    #version 150

    uniform mat4 mvp;
    in vec2 position;

    void main() {
        gl_Position = mvp * vec4(position, 0.0, 1.0);
        gl_PointSize = 2.0;
    }
";

#[cfg(not(target_os = "macos"))]
static FRAGMENT_SRC: &'static [u8] = b"
    #version 120

    uniform vec4 color;

    void main() {
        gl_FragColor = color;
    }
";

#[cfg(target_os = "macos")]
static FRAGMENT_SRC: &'static [u8] = b"
    #version 150

    uniform vec4 color;
    out vec4 f_color;

    void main() {
        f_color = color;
    }
";

pub use grid::quad::{Coordinate, Direction};

pub struct Field<R: gfx::Resources> {
    pub node: scene::NodeId<f32>,
    pub grid: grid::quad::Grid,
    batch: gfx::batch::OwnedBatch<Param<R>>,
}

impl<R: gfx::Resources> Field<R> {
    pub fn new<F: gfx::Factory<R>>(factory: &mut F,
               node: scene::NodeId<f32>, size: f32, area: f32,
               color: (f32, f32, f32, f32))
               -> Field<R> {
        use gfx::traits::FactoryExt;
        let grid = grid::quad::Grid::new(size);
        let area = [[-area, -area, 0.0], [area, area, 0.0]];
        let vertices = grid.fold_edges_in_area(&area, Vec::new(), |mut u, a, b, _, _| {
            u.push(Vertex::new(a[0], a[1]));
            u.push(Vertex::new(b[0], b[1]));
            u
        });
        let mesh = factory.create_mesh(&vertices);
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, Param {
            mvp: [[0.0; 4]; 4],
            color: [color.0, color.1, color.2, color.3],
            _dummy: PhantomData,
        }).unwrap();
        batch.state = batch.state.depth(gfx::state::Comparison::LessEqual, false);
        batch.slice.prim_type = gfx::PrimitiveType::Line;
        Field {
            node: node,
            grid: grid,
            batch: batch,
        }
    }

    pub fn get_center(&self, coord: Coordinate) -> cgmath::Point3<f32> {
        let fixed = self.grid.get_cell_center(coord);
        cgmath::Point3::new(fixed[0], fixed[1], fixed[2])
    }

    pub fn get_cell(&self, position: &cgmath::Point3<f32>) -> Coordinate {
        self.grid.get_coordinate(position.as_fixed())
    }

    pub fn cast_ray(&self, ray: &cgmath::Ray3<f32>) -> Coordinate {
        use cgmath::{Point, Vector};
        let t = -ray.origin.z / ray.direction.z;
        let p = ray.origin.add_v(&ray.direction.mul_s(t));
        self.get_cell(&p)
    }

    pub fn update_params(&mut self, camera: &scene::Camera<f32>, world: &scene::World<f32>) {
        use cgmath::{Matrix, ToMatrix4, Transform};
        use scene::base::World;
        let mx_proj = camera.projection.to_matrix4();
        let model_view = world.get_transform(&camera.node).invert().unwrap()
                              .concat(&world.get_transform(&self.node));
        self.batch.param.mvp = mx_proj.mul_m(&model_view.to_matrix4()).into_fixed();
    }

    pub fn draw<S: gfx::Stream<R>>(&self, stream: &mut S) {
        stream.draw(&self.batch).unwrap();
    }
}
<commit_msg>Switched field shader to be 150 core<commit_after>use std::marker::PhantomData;
use cgmath;
use cgmath::FixedArray;
use gfx;
use grid;
use grid::Grid;
use scene;

#[shader_param]
struct Param<R: gfx::Resources> {
    mvp: [[f32; 4]; 4],
    color: [f32; 4],
    _dummy: PhantomData<R>,
}

#[vertex_format]
#[derive(Clone, Copy)]
struct Vertex {
    position: [f32; 2],
}

impl Vertex {
    pub fn new(x: f32, y: f32) -> Vertex {
        Vertex {
            position: [x, y],
        }
    }
}

#[cfg(not(target_os = "macos"))]
static VERTEX_SRC: &'static [u8] = b"
    #version 150 core

    uniform mat4 mvp;
    in vec2 position;

    void main() {
        gl_Position = mvp * vec4(position, 0.0, 1.0);
        gl_PointSize = 2.0;
    }
";

#[cfg(target_os = "macos")]
static VERTEX_SRC: &'static [u8] = b"
    #version 150

    uniform mat4 mvp;
    in vec2 position;

    void main() {
        gl_Position = mvp * vec4(position, 0.0, 1.0);
        gl_PointSize = 2.0;
    }
";

#[cfg(not(target_os = "macos"))]
static FRAGMENT_SRC: &'static [u8] = b"
    #version 150 core

    uniform vec4 color;
    out vec4 o_Color;

    void main() {
        o_Color = color;
    }
";

#[cfg(target_os = "macos")]
static FRAGMENT_SRC: &'static [u8] = b"
    #version 150

    uniform vec4 color;
    out vec4 f_color;

    void main() {
        f_color = color;
    }
";

pub use grid::quad::{Coordinate, Direction};

pub struct Field<R: gfx::Resources> {
    pub node: scene::NodeId<f32>,
    pub grid: grid::quad::Grid,
    batch: gfx::batch::OwnedBatch<Param<R>>,
}

impl<R: gfx::Resources> Field<R> {
    pub fn new<F: gfx::Factory<R>>(factory: &mut F,
               node: scene::NodeId<f32>, size: f32, area: f32,
               color: (f32, f32, f32, f32))
               -> Field<R> {
        use gfx::traits::FactoryExt;
        let grid = grid::quad::Grid::new(size);
        let area = [[-area, -area, 0.0], [area, area, 0.0]];
        let vertices = grid.fold_edges_in_area(&area, Vec::new(), |mut u, a, b, _, _| {
            u.push(Vertex::new(a[0], a[1]));
            u.push(Vertex::new(b[0], b[1]));
            u
        });
        let mesh = factory.create_mesh(&vertices);
        let program = factory.link_program(VERTEX_SRC, FRAGMENT_SRC).unwrap();
        let mut batch = gfx::batch::OwnedBatch::new(mesh, program, Param {
            mvp: [[0.0; 4]; 4],
            color: [color.0, color.1, color.2, color.3],
            _dummy: PhantomData,
        }).unwrap();
        batch.state = batch.state.depth(gfx::state::Comparison::LessEqual, false);
        batch.slice.prim_type = gfx::PrimitiveType::Line;
        Field {
            node: node,
            grid: grid,
            batch: batch,
        }
    }

    pub fn get_center(&self, coord: Coordinate) -> cgmath::Point3<f32> {
        let fixed = self.grid.get_cell_center(coord);
        cgmath::Point3::new(fixed[0], fixed[1], fixed[2])
    }

    pub fn get_cell(&self, position: &cgmath::Point3<f32>) -> Coordinate {
        self.grid.get_coordinate(position.as_fixed())
    }

    pub fn cast_ray(&self, ray: &cgmath::Ray3<f32>) -> Coordinate {
        use cgmath::{Point, Vector};
        let t = -ray.origin.z / ray.direction.z;
        let p = ray.origin.add_v(&ray.direction.mul_s(t));
        self.get_cell(&p)
    }

    pub fn update_params(&mut self, camera: &scene::Camera<f32>, world: &scene::World<f32>) {
        use cgmath::{Matrix, ToMatrix4, Transform};
        use scene::base::World;
        let mx_proj = camera.projection.to_matrix4();
        let model_view = world.get_transform(&camera.node).invert().unwrap()
                              .concat(&world.get_transform(&self.node));
        self.batch.param.mvp = mx_proj.mul_m(&model_view.to_matrix4()).into_fixed();
    }

    pub fn draw<S: gfx::Stream<R>>(&self, stream: &mut S) {
        stream.draw(&self.batch).unwrap();
    }
}
<|endoftext|>


<commit_before>//! # generator
//!
//! Rust generator implementation
//!

use std::fmt;
use std::mem;
use std::panic;
use std::thread;
use std::any::Any;
use std::boxed::FnBox;
use std::marker::PhantomData;
use std::intrinsics::type_name;

use scope::Scope;
use yield_::yield_now;
use rt::{Error, Context, ContextStack};
use reg_context::Context as RegContext;

// default stack size, in usize
// windows has a minimal size as 0x4a8!!!!
pub const DEFAULT_STACK_SIZE: usize = 0x800;

/// Generator helper
pub struct Gn<A> {
    dummy: PhantomData<A>,
}

/// the generator type
pub type Generator<'a, A, T> = Box<GeneratorImpl<'a, A, T>>;

impl<A> Gn<A> {
    /// create a scoped generator
    pub fn new_scoped<'a, T, F>(f: F) -> Box<GeneratorImpl<'a, A, T>>
        where F: FnOnce(Scope<A, T>) -> T + 'a,
              T: 'a,
              A: 'a
    {
        let mut g = GeneratorImpl::<A, T>::new(DEFAULT_STACK_SIZE);
        let scope = g.get_scope();
        g.init(move || f(scope));
        g
    }
}

impl<A: Any> Gn<A> {
    /// create a new generator with default stack size
    pub fn new<'a, T: Any, F>(f: F) -> Box<GeneratorImpl<'a, A, T>>
        where F: FnOnce() -> T + 'a
    {
        Self::new_opt(f, DEFAULT_STACK_SIZE)
    }

    /// create a new generator with specified stack size
    pub fn new_opt<'a, T: Any, F>(f: F, size: usize) -> Box<GeneratorImpl<'a, A, T>>
        where F: FnOnce() -> T + 'a
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        g.init_context();
        g.init(f);
        g
    }
}

/// `GeneratorImpl`
pub struct GeneratorImpl<'a, A, T> {
    // run time context
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<Box<FnBox() + 'a>>,
}

impl<'a, A: Any, T: Any> GeneratorImpl<'a, A, T> {
    /// create a new generator with default stack size
    pub fn init_context(&mut self) {
        self.context.para = &mut self.para as &mut Any;
        self.context.ret = &mut self.ret as &mut Any;
    }
}

impl<'a, A, T> GeneratorImpl<'a, A, T> {
    /// create a new generator with specified stack size
    pub fn new(size: usize) -> Box<Self> {
        Box::new(GeneratorImpl {
            para: None,
            ret: None,
            f: None,
            context: Context::new(size),
        })
    }

    /// get the scope object
    pub fn get_scope(&mut self) -> Scope<A, T> {
        Scope::new(&mut self.para, &mut self.ret)
    }

    /// init a heap based generator
    // it's can be used to re-init a 'done' generator before it's get dropped
    pub fn init<F: FnOnce() -> T + 'a>(&mut self, f: F)
        where T: 'a
    {
        // make sure the last one is finished
        if self.f.is_none() && self.context._ref == 0 {
            self.cancel();
        }

        // init the ref to 0 means that it's ready to start
        self.context._ref = 0;
        let ret = &mut self.ret as *mut _;
        // windows box::new is quite slow than unix
        self.f = Some(Box::new(move || unsafe { *ret = Some(f()) }));

        let stk = &self.context.stack;
        let reg = &mut self.context.regs;
        reg.init_with(gen_init, 0, &mut self.f as *mut _ as *mut usize, stk);
    }

    /// resume the generator
    #[inline]
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        // get the current regs
        let cur = &mut env.top().regs;
        // save current generator context on stack
        env.push_context(&mut self.context);
        // switch to new context
        RegContext::swap(cur, &mut self.context.regs);

        // check the panic status
        // this would propagate the panic until root context
        let err = self.context.err;
        if err.is_some() {
            panic!(err.unwrap());
        }
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }

    /// prepare the para that passed into generator before send
    #[inline]
    pub fn set_para(&mut self, para: A) {
        mem::replace(&mut self.para, Some(para));
    }

    /// set the generator local data
    #[inline]
    pub fn set_local_data(&mut self, data: *mut u8) {
        self.context.local_data = data;
    }

    /// resume the generator without touch the para
    /// you should call `set_para` before this method
    #[inline]
    pub fn resume(&mut self) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// `raw_send`
    #[inline]
    pub fn raw_send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        // use the replace is would drop the old value
        mem::replace(&mut self.para, para);

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// send interface
    pub fn send(&mut self, para: A) -> T {
        let ret = self.raw_send(Some(para));
        ret.unwrap()
    }

    /// cancel the generator
    pub fn cancel(&mut self) {
        // consume the fun if it's not started
        if !self.is_started() {
            self.f.take();
            self.context._ref = 1;
        } else {
            // tell the func to panic
            // so that we can stop the inner func
            self.context._ref = 2;
            self.resume_gen();
        }
    }

    /// is finished
    #[inline]
    pub fn is_done(&self) -> bool {
        self.is_started() && self.context._ref != 0
    }

    /// get stack total size and used size in word
    pub fn stack_usage(&self) -> (usize, usize) {
        (self.context.stack.size(), self.context.stack.get_used_size())
    }
}

impl<'a, A, T> Drop for GeneratorImpl<'a, A, T> {
    fn drop(&mut self) {
        // when the thread is already panic, do nothing
        if thread::panicking() {
            return;
        }

        let mut i = 0;
        while !self.is_done() {
            if i > 2 {
                self.cancel();
                break;
            }
            self.raw_send(None);
            i += 1;
        }

        let (total_stack, used_stack) = self.stack_usage();
        if used_stack < total_stack {
            // here we should record the stack in the class
            // next time will just use
            // set_stack_size::<F>(used_stack);
        } else {
            error!("stack overflow detected!");
            panic!(Error::StackErr);
        }
    }
}

impl<'a, A, T> Iterator for GeneratorImpl<'a, A, T> {
    type Item = T;
    // The 'Iterator' trait only requires the 'next' method to be defined. The
    // return type is 'Option<T>', 'None' is returned when the 'Iterator' is
    // over, otherwise the next value is returned wrapped in 'Some'
    fn next(&mut self) -> Option<T> {
        self.resume()
    }
}

impl<'a, A, T> fmt::Debug for GeneratorImpl<'a, A, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            write!(f,
                   "Generator<{}, Output={}> {{ ... }}",
                   type_name::<A>(),
                   type_name::<T>())
        }
    }
}

/// the init function passed to reg_context
fn gen_init(_: usize, f: *mut usize) -> ! {
    let clo = move || {
        // consume self.f
        let f: &mut Option<Box<FnBox()>> = unsafe { &mut *(f as *mut _) };
        let func = f.take().unwrap();
        func();
    };

    // we can't panic inside the generator context
    // need to propagate the panic to the main thread
    // It is currently undefined behavior to unwind from Rust code into foreign code
    if let Err(cause) = panic::catch_unwind(clo) {
        if cause.downcast_ref::<Error>().is_some() {
            match cause.downcast_ref::<Error>().unwrap() {
                &Error::Cancel => {}
                err => {
                    let ctx = ContextStack::current().top();
                    ctx.err = Some(*err);
                }
            }
        } else {
            // we hope all other panic could covert to a string
            // here we forget the panic to avoid shutdown the whole thread
            let e = cause.downcast::<&str>().unwrap_or_else(|_| Box::new("unkown panic"));
            error!("Panicked inside: {:?}", e);
        }
    }

    yield_now();

    unreachable!("Should never comeback");
}
<commit_msg>add get_local_data for generator<commit_after>//! # generator
//!
//! Rust generator implementation
//!

use std::fmt;
use std::mem;
use std::panic;
use std::thread;
use std::any::Any;
use std::boxed::FnBox;
use std::marker::PhantomData;
use std::intrinsics::type_name;

use scope::Scope;
use yield_::yield_now;
use rt::{Error, Context, ContextStack};
use reg_context::Context as RegContext;

// default stack size, in usize
// windows has a minimal size as 0x4a8!!!!
pub const DEFAULT_STACK_SIZE: usize = 0x800;

/// Generator helper
pub struct Gn<A> {
    dummy: PhantomData<A>,
}

/// the generator type
pub type Generator<'a, A, T> = Box<GeneratorImpl<'a, A, T>>;

impl<A> Gn<A> {
    /// create a scoped generator
    pub fn new_scoped<'a, T, F>(f: F) -> Box<GeneratorImpl<'a, A, T>>
        where F: FnOnce(Scope<A, T>) -> T + 'a,
              T: 'a,
              A: 'a
    {
        let mut g = GeneratorImpl::<A, T>::new(DEFAULT_STACK_SIZE);
        let scope = g.get_scope();
        g.init(move || f(scope));
        g
    }
}

impl<A: Any> Gn<A> {
    /// create a new generator with default stack size
    pub fn new<'a, T: Any, F>(f: F) -> Box<GeneratorImpl<'a, A, T>>
        where F: FnOnce() -> T + 'a
    {
        Self::new_opt(DEFAULT_STACK_SIZE, f)
    }

    /// create a new generator with specified stack size
    pub fn new_opt<'a, T: Any, F>(size: usize, f: F) -> Box<GeneratorImpl<'a, A, T>>
        where F: FnOnce() -> T + 'a
    {
        let mut g = GeneratorImpl::<A, T>::new(size);
        g.init_context();
        g.init(f);
        g
    }
}

/// `GeneratorImpl`
pub struct GeneratorImpl<'a, A, T> {
    // run time context
    context: Context,
    // save the input
    para: Option<A>,
    // save the output
    ret: Option<T>,
    // boxed functor
    f: Option<Box<FnBox() + 'a>>,
}

impl<'a, A: Any, T: Any> GeneratorImpl<'a, A, T> {
    /// create a new generator with default stack size
    pub fn init_context(&mut self) {
        self.context.para = &mut self.para as &mut Any;
        self.context.ret = &mut self.ret as &mut Any;
    }
}

impl<'a, A, T> GeneratorImpl<'a, A, T> {
    /// create a new generator with specified stack size
    pub fn new(size: usize) -> Box<Self> {
        Box::new(GeneratorImpl {
            para: None,
            ret: None,
            f: None,
            context: Context::new(size),
        })
    }

    /// get the scope object
    pub fn get_scope(&mut self) -> Scope<A, T> {
        Scope::new(&mut self.para, &mut self.ret)
    }

    /// init a heap based generator
    // it's can be used to re-init a 'done' generator before it's get dropped
    pub fn init<F: FnOnce() -> T + 'a>(&mut self, f: F)
        where T: 'a
    {
        // make sure the last one is finished
        if self.f.is_none() && self.context._ref == 0 {
            self.cancel();
        }

        // init the ref to 0 means that it's ready to start
        self.context._ref = 0;
        let ret = &mut self.ret as *mut _;
        // windows box::new is quite slow than unix
        self.f = Some(Box::new(move || unsafe { *ret = Some(f()) }));

        let stk = &self.context.stack;
        let reg = &mut self.context.regs;
        reg.init_with(gen_init, 0, &mut self.f as *mut _ as *mut usize, stk);
    }

    /// resume the generator
    #[inline]
    fn resume_gen(&mut self) {
        let env = ContextStack::current();
        // get the current regs
        let cur = &mut env.top().regs;
        // save current generator context on stack
        env.push_context(&mut self.context);
        // switch to new context
        RegContext::swap(cur, &mut self.context.regs);

        // check the panic status
        // this would propagate the panic until root context
        let err = self.context.err;
        if err.is_some() {
            panic!(err.unwrap());
        }
    }

    #[inline]
    fn is_started(&self) -> bool {
        // when the f is consumed we think it's running
        self.f.is_none()
    }

    /// prepare the para that passed into generator before send
    #[inline]
    pub fn set_para(&mut self, para: A) {
        mem::replace(&mut self.para, Some(para));
    }

    /// set the generator local data
    #[inline]
    pub fn set_local_data(&mut self, data: *mut u8) {
        self.context.local_data = data;
    }

    /// get the generator local data
    #[inline]
    pub fn get_local_data(&self) -> *mut u8 {
        self.context.local_data
    }

    /// resume the generator without touch the para
    /// you should call `set_para` before this method
    #[inline]
    pub fn resume(&mut self) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// `raw_send`
    #[inline]
    pub fn raw_send(&mut self, para: Option<A>) -> Option<T> {
        if self.is_done() {
            return None;
        }

        // this is the passed in value of the send primitive
        // the yield part would read out this value in the next round
        // use the replace is would drop the old value
        mem::replace(&mut self.para, para);

        // every time we call the function, increase the ref count
        // yiled will decrease it and return will not
        self.context._ref += 1;
        self.resume_gen();

        self.ret.take()
    }

    /// send interface
    pub fn send(&mut self, para: A) -> T {
        let ret = self.raw_send(Some(para));
        ret.unwrap()
    }

    /// cancel the generator
    pub fn cancel(&mut self) {
        // consume the fun if it's not started
        if !self.is_started() {
            self.f.take();
            self.context._ref = 1;
        } else {
            // tell the func to panic
            // so that we can stop the inner func
            self.context._ref = 2;
            self.resume_gen();
        }
    }

    /// is finished
    #[inline]
    pub fn is_done(&self) -> bool {
        self.is_started() && self.context._ref != 0
    }

    /// get stack total size and used size in word
    pub fn stack_usage(&self) -> (usize, usize) {
        (self.context.stack.size(), self.context.stack.get_used_size())
    }
}

impl<'a, A, T> Drop for GeneratorImpl<'a, A, T> {
    fn drop(&mut self) {
        // when the thread is already panic, do nothing
        if thread::panicking() {
            return;
        }

        let mut i = 0;
        while !self.is_done() {
            if i > 2 {
                self.cancel();
                break;
            }
            self.raw_send(None);
            i += 1;
        }

        let (total_stack, used_stack) = self.stack_usage();
        if used_stack < total_stack {
            // here we should record the stack in the class
            // next time will just use
            // set_stack_size::<F>(used_stack);
        } else {
            error!("stack overflow detected!");
            panic!(Error::StackErr);
        }
    }
}

impl<'a, A, T> Iterator for GeneratorImpl<'a, A, T> {
    type Item = T;
    // The 'Iterator' trait only requires the 'next' method to be defined. The
    // return type is 'Option<T>', 'None' is returned when the 'Iterator' is
    // over, otherwise the next value is returned wrapped in 'Some'
    fn next(&mut self) -> Option<T> {
        self.resume()
    }
}

impl<'a, A, T> fmt::Debug for GeneratorImpl<'a, A, T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        unsafe {
            write!(f,
                   "Generator<{}, Output={}> {{ ... }}",
                   type_name::<A>(),
                   type_name::<T>())
        }
    }
}

/// the init function passed to reg_context
fn gen_init(_: usize, f: *mut usize) -> ! {
    let clo = move || {
        // consume self.f
        let f: &mut Option<Box<FnBox()>> = unsafe { &mut *(f as *mut _) };
        let func = f.take().unwrap();
        func();
    };

    // we can't panic inside the generator context
    // need to propagate the panic to the main thread
    // It is currently undefined behavior to unwind from Rust code into foreign code
    // TODO: pass the Err to the main thread
    if let Err(cause) = panic::catch_unwind(clo) {
        if cause.downcast_ref::<Error>().is_some() {
            match cause.downcast_ref::<Error>().unwrap() {
                &Error::Cancel => {}
                err => {
                    let ctx = ContextStack::current().top();
                    ctx.err = Some(*err);
                }
            }
        } else {
            // we hope all other panic could covert to a string
            // here we forget the panic to avoid shutdown the whole thread
            let e = cause.downcast::<&str>().unwrap_or_else(|_| Box::new("unkown panic"));
            error!("Panicked inside: {:?}", e);
        }
    }

    yield_now();

    unreachable!("Should never comeback");
}
<|endoftext|>


<commit_before>use super::*;

/// Represents lifetimes and type parameters attached to a declaration
/// of a function, enum, trait, etc.
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct Generics {
    pub lifetimes: Vec<LifetimeDef>,
    pub ty_params: Vec<TyParam>,
    pub where_clause: WhereClause,
}

impl Generics {
    /// Split a type's generics into the pieces required for impl'ing a trait
    /// for that type.
    ///
    /// ```
    /// # extern crate syn;
    /// # #[macro_use]
    /// # extern crate quote;
    /// # fn main() {
    /// # let generics: syn::Generics = Default::default();
    /// # let name = syn::Ident::new("MyType");
    /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
    /// quote! {
    ///     impl #impl_generics MyTrait for #name #ty_generics #where_clause {
    ///         // ...
    ///     }
    /// }
    /// # ;
    /// # }
    /// ```
    pub fn split_for_impl(&self) -> (Generics, Generics, WhereClause) {
        // Remove where clause and type parameter defaults.
        let impl_generics = Generics {
            lifetimes: self.lifetimes.clone(),
            ty_params: self.ty_params
                .iter()
                .map(|ty_param| {
                    TyParam {
                        ident: ty_param.ident.clone(),
                        bounds: ty_param.bounds.clone(),
                        default: None,
                    }
                })
                .collect(),
            where_clause: WhereClause::none(),
        };

        // Remove where clause, type parameter defaults, and bounds.
        let ty_generics = Generics {
            lifetimes: self.lifetimes
                .iter()
                .map(|lifetime_def| {
                    LifetimeDef {
                        lifetime: lifetime_def.lifetime.clone(),
                        bounds: Vec::new(),
                    }
                })
                .collect(),
            ty_params: self.ty_params
                .iter()
                .map(|ty_param| {
                    TyParam {
                        ident: ty_param.ident.clone(),
                        bounds: Vec::new(),
                        default: None,
                    }
                })
                .collect(),
            where_clause: WhereClause::none(),
        };

        let where_clause = self.where_clause.clone();

        (impl_generics, ty_generics, where_clause)
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Lifetime {
    pub ident: Ident,
}

impl Lifetime {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        Lifetime { ident: Ident::new(t) }
    }
}

/// A lifetime definition, e.g. `'a: 'b+'c+'d`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct LifetimeDef {
    pub lifetime: Lifetime,
    pub bounds: Vec<Lifetime>,
}

impl LifetimeDef {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        LifetimeDef {
            lifetime: Lifetime::new(t),
            bounds: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TyParam {
    pub ident: Ident,
    pub bounds: Vec<TyParamBound>,
    pub default: Option<Ty>,
}

/// The AST represents all type param bounds as types.
/// `typeck::collect::compute_bounds` matches these against
/// the "special" built-in traits (see `middle::lang_items`) and
/// detects Copy, Send and Sync.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TyParamBound {
    Trait(PolyTraitRef, TraitBoundModifier),
    Region(Lifetime),
}

/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. Negative bounds should also be handled here.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TraitBoundModifier {
    None,
    Maybe,
}

/// A `where` clause in a definition
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct WhereClause {
    pub predicates: Vec<WherePredicate>,
}

impl WhereClause {
    pub fn none() -> Self {
        WhereClause { predicates: Vec::new() }
    }
}

/// A single predicate in a `where` clause
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum WherePredicate {
    /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
    BoundPredicate(WhereBoundPredicate),
    /// A lifetime predicate, e.g. `'a: 'b+'c`
    RegionPredicate(WhereRegionPredicate),
}

/// A type bound.
///
/// E.g. `for<'c> Foo: Send+Clone+'c`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct WhereBoundPredicate {
    /// Any lifetimes from a `for` binding
    pub bound_lifetimes: Vec<LifetimeDef>,
    /// The type being bounded
    pub bounded_ty: Ty,
    /// Trait and lifetime bounds (`Clone+Send+'static`)
    pub bounds: Vec<TyParamBound>,
}

/// A lifetime predicate.
///
/// E.g. `'a: 'b+'c`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct WhereRegionPredicate {
    pub lifetime: Lifetime,
    pub bounds: Vec<Lifetime>,
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use ident::parsing::ident;
    use ty::parsing::{ty, poly_trait_ref};

    named!(pub generics -> Generics, map!(
        alt!(
            do_parse!(
                punct!("<") >>
                lifetimes: separated_list!(punct!(","), lifetime_def) >>
                ty_params: opt_vec!(preceded!(
                    cond!(!lifetimes.is_empty(), punct!(",")),
                    separated_nonempty_list!(punct!(","), ty_param)
                )) >>
                punct!(">") >>
                (lifetimes, ty_params)
            )
            |
            epsilon!() => { |_| (Vec::new(), Vec::new()) }
        ),
        |(lifetimes, ty_params)| Generics {
            lifetimes: lifetimes,
            ty_params: ty_params,
            where_clause: Default::default(),
        }
    ));

    named!(pub lifetime -> Lifetime, preceded!(
        punct!("'"),
        map!(ident, |id| Lifetime {
            ident: format!("'{}", id).into(),
        })
    ));

    named!(pub lifetime_def -> LifetimeDef, do_parse!(
        life: lifetime >>
        bounds: opt_vec!(preceded!(
            punct!(":"),
            separated_nonempty_list!(punct!("+"), lifetime)
        )) >>
        (LifetimeDef {
            lifetime: life,
            bounds: bounds,
        })
    ));

    named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
        keyword!("for") >>
        punct!("<") >>
        lifetimes: separated_list!(punct!(","), lifetime_def) >>
        punct!(">") >>
        (lifetimes)
    )));

    named!(ty_param -> TyParam, do_parse!(
        id: ident >>
        bounds: opt_vec!(preceded!(
            punct!(":"),
            separated_nonempty_list!(punct!("+"), ty_param_bound)
        )) >>
        default: option!(preceded!(
            punct!("="),
            ty
        )) >>
        (TyParam {
            ident: id,
            bounds: bounds,
            default: default,
        })
    ));

    named!(pub ty_param_bound -> TyParamBound, alt!(
        preceded!(punct!("?"), poly_trait_ref) => {
            |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
        }
        |
        lifetime => { TyParamBound::Region }
        |
        poly_trait_ref => {
            |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
        }
    ));

    named!(pub where_clause -> WhereClause, alt!(
        do_parse!(
            keyword!("where") >>
            predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
            option!(punct!(",")) >>
            (WhereClause { predicates: predicates })
        )
        |
        epsilon!() => { |_| Default::default() }
    ));

    named!(where_predicate -> WherePredicate, alt!(
        do_parse!(
            ident: lifetime >>
            punct!(":") >>
            bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
            (WherePredicate::RegionPredicate(WhereRegionPredicate {
                lifetime: ident,
                bounds: bounds,
            }))
        )
        |
        do_parse!(
            bound_lifetimes: bound_lifetimes >>
            bounded_ty: ty >>
            punct!(":") >>
            bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
            (WherePredicate::BoundPredicate(WhereBoundPredicate {
                bound_lifetimes: bound_lifetimes,
                bounded_ty: bounded_ty,
                bounds: bounds,
            }))
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Generics {
        fn to_tokens(&self, tokens: &mut Tokens) {
            let has_lifetimes = !self.lifetimes.is_empty();
            let has_ty_params = !self.ty_params.is_empty();
            if has_lifetimes || has_ty_params {
                tokens.append("<");
                tokens.append_separated(&self.lifetimes, ",");
                if has_lifetimes && has_ty_params {
                    tokens.append(",");
                }
                tokens.append_separated(&self.ty_params, ",");
                tokens.append(">");
            }
        }
    }

    impl ToTokens for Lifetime {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.ident.to_tokens(tokens);
        }
    }

    impl ToTokens for LifetimeDef {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.lifetime.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for TyParam {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.ident.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
            if let Some(ref default) = self.default {
                tokens.append("=");
                default.to_tokens(tokens);
            }
        }
    }

    impl ToTokens for TyParamBound {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
                TyParamBound::Trait(ref trait_ref, modifier) => {
                    match modifier {
                        TraitBoundModifier::None => {}
                        TraitBoundModifier::Maybe => tokens.append("?"),
                    }
                    trait_ref.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for WhereClause {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if !self.predicates.is_empty() {
                tokens.append("where");
                tokens.append_separated(&self.predicates, ",");
            }
        }
    }

    impl ToTokens for WherePredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                WherePredicate::BoundPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
                WherePredicate::RegionPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for WhereBoundPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if !self.bound_lifetimes.is_empty() {
                tokens.append("for");
                tokens.append("<");
                tokens.append_separated(&self.bound_lifetimes, ",");
                tokens.append(">");
            }
            self.bounded_ty.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for WhereRegionPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.lifetime.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }
}
<commit_msg>Panic on programmatic creation of invalid lifetime<commit_after>use super::*;

/// Represents lifetimes and type parameters attached to a declaration
/// of a function, enum, trait, etc.
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct Generics {
    pub lifetimes: Vec<LifetimeDef>,
    pub ty_params: Vec<TyParam>,
    pub where_clause: WhereClause,
}

impl Generics {
    /// Split a type's generics into the pieces required for impl'ing a trait
    /// for that type.
    ///
    /// ```
    /// # extern crate syn;
    /// # #[macro_use]
    /// # extern crate quote;
    /// # fn main() {
    /// # let generics: syn::Generics = Default::default();
    /// # let name = syn::Ident::new("MyType");
    /// let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
    /// quote! {
    ///     impl #impl_generics MyTrait for #name #ty_generics #where_clause {
    ///         // ...
    ///     }
    /// }
    /// # ;
    /// # }
    /// ```
    pub fn split_for_impl(&self) -> (Generics, Generics, WhereClause) {
        // Remove where clause and type parameter defaults.
        let impl_generics = Generics {
            lifetimes: self.lifetimes.clone(),
            ty_params: self.ty_params
                .iter()
                .map(|ty_param| {
                    TyParam {
                        ident: ty_param.ident.clone(),
                        bounds: ty_param.bounds.clone(),
                        default: None,
                    }
                })
                .collect(),
            where_clause: WhereClause::none(),
        };

        // Remove where clause, type parameter defaults, and bounds.
        let ty_generics = Generics {
            lifetimes: self.lifetimes
                .iter()
                .map(|lifetime_def| {
                    LifetimeDef {
                        lifetime: lifetime_def.lifetime.clone(),
                        bounds: Vec::new(),
                    }
                })
                .collect(),
            ty_params: self.ty_params
                .iter()
                .map(|ty_param| {
                    TyParam {
                        ident: ty_param.ident.clone(),
                        bounds: Vec::new(),
                        default: None,
                    }
                })
                .collect(),
            where_clause: WhereClause::none(),
        };

        let where_clause = self.where_clause.clone();

        (impl_generics, ty_generics, where_clause)
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Lifetime {
    pub ident: Ident,
}

impl Lifetime {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        let id = Ident::new(t);
        if !id.as_ref().starts_with('\'') {
            panic!("lifetime name must start with apostrophe as in \"'a\", \
                   got {:?}", id.as_ref());
        }
        Lifetime { ident: id }
    }
}

/// A lifetime definition, e.g. `'a: 'b+'c+'d`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct LifetimeDef {
    pub lifetime: Lifetime,
    pub bounds: Vec<Lifetime>,
}

impl LifetimeDef {
    pub fn new<T: Into<Ident>>(t: T) -> Self {
        LifetimeDef {
            lifetime: Lifetime::new(t),
            bounds: Vec::new(),
        }
    }
}

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct TyParam {
    pub ident: Ident,
    pub bounds: Vec<TyParamBound>,
    pub default: Option<Ty>,
}

/// The AST represents all type param bounds as types.
/// `typeck::collect::compute_bounds` matches these against
/// the "special" built-in traits (see `middle::lang_items`) and
/// detects Copy, Send and Sync.
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum TyParamBound {
    Trait(PolyTraitRef, TraitBoundModifier),
    Region(Lifetime),
}

/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. Negative bounds should also be handled here.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum TraitBoundModifier {
    None,
    Maybe,
}

/// A `where` clause in a definition
#[derive(Debug, Clone, Eq, PartialEq, Default)]
pub struct WhereClause {
    pub predicates: Vec<WherePredicate>,
}

impl WhereClause {
    pub fn none() -> Self {
        WhereClause { predicates: Vec::new() }
    }
}

/// A single predicate in a `where` clause
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum WherePredicate {
    /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
    BoundPredicate(WhereBoundPredicate),
    /// A lifetime predicate, e.g. `'a: 'b+'c`
    RegionPredicate(WhereRegionPredicate),
}

/// A type bound.
///
/// E.g. `for<'c> Foo: Send+Clone+'c`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct WhereBoundPredicate {
    /// Any lifetimes from a `for` binding
    pub bound_lifetimes: Vec<LifetimeDef>,
    /// The type being bounded
    pub bounded_ty: Ty,
    /// Trait and lifetime bounds (`Clone+Send+'static`)
    pub bounds: Vec<TyParamBound>,
}

/// A lifetime predicate.
///
/// E.g. `'a: 'b+'c`
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct WhereRegionPredicate {
    pub lifetime: Lifetime,
    pub bounds: Vec<Lifetime>,
}

#[cfg(feature = "parsing")]
pub mod parsing {
    use super::*;
    use ident::parsing::ident;
    use ty::parsing::{ty, poly_trait_ref};

    named!(pub generics -> Generics, map!(
        alt!(
            do_parse!(
                punct!("<") >>
                lifetimes: separated_list!(punct!(","), lifetime_def) >>
                ty_params: opt_vec!(preceded!(
                    cond!(!lifetimes.is_empty(), punct!(",")),
                    separated_nonempty_list!(punct!(","), ty_param)
                )) >>
                punct!(">") >>
                (lifetimes, ty_params)
            )
            |
            epsilon!() => { |_| (Vec::new(), Vec::new()) }
        ),
        |(lifetimes, ty_params)| Generics {
            lifetimes: lifetimes,
            ty_params: ty_params,
            where_clause: Default::default(),
        }
    ));

    named!(pub lifetime -> Lifetime, preceded!(
        punct!("'"),
        map!(ident, |id| Lifetime {
            ident: format!("'{}", id).into(),
        })
    ));

    named!(pub lifetime_def -> LifetimeDef, do_parse!(
        life: lifetime >>
        bounds: opt_vec!(preceded!(
            punct!(":"),
            separated_nonempty_list!(punct!("+"), lifetime)
        )) >>
        (LifetimeDef {
            lifetime: life,
            bounds: bounds,
        })
    ));

    named!(pub bound_lifetimes -> Vec<LifetimeDef>, opt_vec!(do_parse!(
        keyword!("for") >>
        punct!("<") >>
        lifetimes: separated_list!(punct!(","), lifetime_def) >>
        punct!(">") >>
        (lifetimes)
    )));

    named!(ty_param -> TyParam, do_parse!(
        id: ident >>
        bounds: opt_vec!(preceded!(
            punct!(":"),
            separated_nonempty_list!(punct!("+"), ty_param_bound)
        )) >>
        default: option!(preceded!(
            punct!("="),
            ty
        )) >>
        (TyParam {
            ident: id,
            bounds: bounds,
            default: default,
        })
    ));

    named!(pub ty_param_bound -> TyParamBound, alt!(
        preceded!(punct!("?"), poly_trait_ref) => {
            |poly| TyParamBound::Trait(poly, TraitBoundModifier::Maybe)
        }
        |
        lifetime => { TyParamBound::Region }
        |
        poly_trait_ref => {
            |poly| TyParamBound::Trait(poly, TraitBoundModifier::None)
        }
    ));

    named!(pub where_clause -> WhereClause, alt!(
        do_parse!(
            keyword!("where") >>
            predicates: separated_nonempty_list!(punct!(","), where_predicate) >>
            option!(punct!(",")) >>
            (WhereClause { predicates: predicates })
        )
        |
        epsilon!() => { |_| Default::default() }
    ));

    named!(where_predicate -> WherePredicate, alt!(
        do_parse!(
            ident: lifetime >>
            punct!(":") >>
            bounds: separated_nonempty_list!(punct!("+"), lifetime) >>
            (WherePredicate::RegionPredicate(WhereRegionPredicate {
                lifetime: ident,
                bounds: bounds,
            }))
        )
        |
        do_parse!(
            bound_lifetimes: bound_lifetimes >>
            bounded_ty: ty >>
            punct!(":") >>
            bounds: separated_nonempty_list!(punct!("+"), ty_param_bound) >>
            (WherePredicate::BoundPredicate(WhereBoundPredicate {
                bound_lifetimes: bound_lifetimes,
                bounded_ty: bounded_ty,
                bounds: bounds,
            }))
        )
    ));
}

#[cfg(feature = "printing")]
mod printing {
    use super::*;
    use quote::{Tokens, ToTokens};

    impl ToTokens for Generics {
        fn to_tokens(&self, tokens: &mut Tokens) {
            let has_lifetimes = !self.lifetimes.is_empty();
            let has_ty_params = !self.ty_params.is_empty();
            if has_lifetimes || has_ty_params {
                tokens.append("<");
                tokens.append_separated(&self.lifetimes, ",");
                if has_lifetimes && has_ty_params {
                    tokens.append(",");
                }
                tokens.append_separated(&self.ty_params, ",");
                tokens.append(">");
            }
        }
    }

    impl ToTokens for Lifetime {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.ident.to_tokens(tokens);
        }
    }

    impl ToTokens for LifetimeDef {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.lifetime.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for TyParam {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.ident.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
            if let Some(ref default) = self.default {
                tokens.append("=");
                default.to_tokens(tokens);
            }
        }
    }

    impl ToTokens for TyParamBound {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                TyParamBound::Region(ref lifetime) => lifetime.to_tokens(tokens),
                TyParamBound::Trait(ref trait_ref, modifier) => {
                    match modifier {
                        TraitBoundModifier::None => {}
                        TraitBoundModifier::Maybe => tokens.append("?"),
                    }
                    trait_ref.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for WhereClause {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if !self.predicates.is_empty() {
                tokens.append("where");
                tokens.append_separated(&self.predicates, ",");
            }
        }
    }

    impl ToTokens for WherePredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            match *self {
                WherePredicate::BoundPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
                WherePredicate::RegionPredicate(ref predicate) => {
                    predicate.to_tokens(tokens);
                }
            }
        }
    }

    impl ToTokens for WhereBoundPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            if !self.bound_lifetimes.is_empty() {
                tokens.append("for");
                tokens.append("<");
                tokens.append_separated(&self.bound_lifetimes, ",");
                tokens.append(">");
            }
            self.bounded_ty.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }

    impl ToTokens for WhereRegionPredicate {
        fn to_tokens(&self, tokens: &mut Tokens) {
            self.lifetime.to_tokens(tokens);
            if !self.bounds.is_empty() {
                tokens.append(":");
                tokens.append_separated(&self.bounds, "+");
            }
        }
    }
}
<|endoftext|>


<commit_before>//! GLTF package loader for gfx-rs

#![crate_name = "gltf"]
#![feature(phase)]

#[phase(plugin, link)]
extern crate log;
extern crate serialize;
extern crate cgmath;
extern crate gfx;
#[phase(plugin)]
extern crate gfx_macros;
extern crate gfx_gl;
extern crate serde;
#[phase(plugin)]
extern crate serde_macros;

use std::cmp;
use std::collections::HashMap;
use std::io::File;
use serde::{de, json};
use gfx_gl::types::GLenum;

mod types;

fn load_map<T: de::Deserializable<json::JsonDeserializer, json::ParserError>, R>(
            json: &json::Json, var: &str, fun: |T| -> R) -> HashMap<String, R> {
    match json.find(&var.to_string()) {
        Some(&json::Object(ref map)) => map.iter().map(|(id, sub)| {
            let v: T = json::from_json(sub.clone()).unwrap();
            (id.clone(), fun(v))
        }).collect(),
        _ => HashMap::new(),
    }
}

fn attrib_to_slice(attrib: &gfx::Attribute)
                   -> Result<gfx::Slice, ()> {
    use gfx::attrib as a;
    match (attrib.format.elem_count, attrib.format.elem_type) {
        (1, a::Int(a::IntRaw, a::U8, a::Unsigned)) => Ok(gfx::IndexSlice8(
            gfx::TriangleList,
            gfx::BufferHandle::from_raw(attrib.buffer),
            0,
            attrib.format.offset >> 0
        )),
        (1, a::Int(a::IntRaw, a::U16, a::Unsigned)) => Ok(gfx::IndexSlice16(
            gfx::TriangleList,
            gfx::BufferHandle::from_raw(attrib.buffer),
            0,
            attrib.format.offset >> 1
        )),
        (1, a::Int(a::IntRaw, a::U32, a::Unsigned)) => Ok(gfx::IndexSlice32(
            gfx::TriangleList,
            gfx::BufferHandle::from_raw(attrib.buffer),
            0,
            attrib.format.offset >> 2
        )),
        _ => Err(())
    }
}

#[deriving(Clone, PartialEq, Show)]
pub enum AccessorCountError {
    AccessorMatrix(u8),
    AccessorUnknown(String),
}

fn parse_accessor_count(ty: &str) -> Result<gfx::attrib::Count, AccessorCountError> {
    use gfx::attrib as a;
    match ty {
        "SCALAR" => Ok(1),
        "VEC2"   => Ok(2),
        "VEC3"   => Ok(3),
        "VEC4"   => Ok(4),
        "MAT2"   => Err(AccessorMatrix(2)),
        "MAT3"   => Err(AccessorMatrix(3)),
        "MAT4"   => Err(AccessorMatrix(4)),
        _        => Err(AccessorUnknown(ty.to_string())),
    }
}

#[deriving(Clone, PartialEq, Show)]
pub enum AccessorTypeError {
    AccessorType(GLenum),
    AccessorRange(f32, f32),
}

fn parse_accessor_type(ty: GLenum, range: f32) -> Result<gfx::attrib::Type, AccessorTypeError> {
    use gfx::attrib as a;
    let sub = if range <= 2.0 {a::IntNormalized} else {a::IntAsFloat};
    Ok(match ty {
        gfx_gl::BYTE => a::Int(sub, a::U8, a::Signed),
        gfx_gl::UNSIGNED_BYTE => a::Int(sub, a::U8, a::Unsigned),
        gfx_gl::SHORT => a::Int(sub, a::U16, a::Signed),
        gfx_gl::UNSIGNED_SHORT => a::Int(sub, a::U32, a::Unsigned),
        gfx_gl::INT => a::Int(sub, a::U16, a::Signed),
        gfx_gl::UNSIGNED_INT => a::Int(sub, a::U32, a::Unsigned),
        gfx_gl::FLOAT => a::Float(a::FloatDefault, a::F32),
        _ => return Err(AccessorType(ty)),
    })
}

#[deriving(Clone, PartialEq, Show)]
pub struct ShaderError(GLenum);

fn parse_shader_type(ty: GLenum) -> Result<gfx::shade::Stage, ShaderError> {
    match ty {
        gfx_gl::VERTEX_SHADER => Ok(gfx::shade::Vertex),
        gfx_gl::GEOMETRY_SHADER => Ok(gfx::shade::Geometry),
        gfx_gl::FRAGMENT_SHADER => Ok(gfx::shade::Fragment),
        _ => Err(ShaderError(ty)),
    }
}

fn parse_state(s: types::States) -> gfx::DrawState {
    let mut d = gfx::DrawState::new();
    for gl in s.enable.iter() {
        match *gl {
            gfx_gl::CULL_FACE => {
                let cull = match s.functions.cull_face {
                    (gfx_gl::FRONT, ) => gfx::state::CullFront,
                    (gfx_gl::BACK, ) => gfx::state::CullBack,
                    _ => {
                        error!("Unknown cull mode: {}", s.functions.cull_face);
                        gfx::state::CullNothing
                    },
                };
                d.primitive.method = gfx::state::Fill(cull);
            },
            gfx_gl::POLYGON_OFFSET_FILL => {
                let (f, u) = s.functions.polygon_offset;
                d.primitive.offset = gfx::state::Offset(f, u);
            },
            gfx_gl::SAMPLE_ALPHA_TO_COVERAGE => {
                //d.multisample.alpha_to_coverage = ;
            },
            gfx_gl::DEPTH_TEST => {
                //d.depth = Some();
            },
            gfx_gl::BLEND => {
                //d.blend = Some();
            },
            gfx_gl::SCISSOR_TEST => {
                let (x, y, w, h) = s.functions.scissor;
                d.scissor = Some(gfx::Rect {
                    x: x, y: y, w: w, h: h,
                });
            },
            _ => error!("Unknown GL state: {}", *gl),
        }
    }
    d
}

pub enum LoadError {
    ErrorString,
    ErrorJson,
}

pub struct SubMesh {
    pub mesh: gfx::Mesh,
    pub slice: gfx::Slice,
    pub material: String,
}

pub struct Package {
    pub buffers:    HashMap<String, gfx::RawBufferHandle>,
    pub attributes: HashMap<String, (gfx::Attribute, gfx::VertexCount)>,
    pub models:     HashMap<String, Vec<SubMesh>>,
    pub shaders:    HashMap<String, gfx::ShaderHandle>,
    pub programs:   HashMap<String, gfx::ProgramHandle>,
}

impl Package {
    pub fn load<C: gfx::CommandBuffer, D: gfx::Device<C>>(input: &str, device: &mut D)
            -> Result<Package, LoadError> {
        let json = match json::from_str(input) {
            Ok(j) => j,
            Err(_e) => return Err(ErrorString),
        };
        let buffers = load_map(&json, "buffers", |b: types::Buffer| {
            let data = File::open(&Path::new(b.uri)).read_to_end().unwrap();
            debug_assert_eq!(data.len(), b.byte_length);
            device.create_buffer_static(&data).raw()
        });
        let attributes = load_map(&json, "accessors", |a: types::Accessor| {
            let range = a.max.val0() - a.min.val0();
            let el_count = parse_accessor_count(a.ty.as_slice()).unwrap();
            let el_type  = parse_accessor_type(a.component_type, range).unwrap();
            (gfx::Attribute {
                name: a.name,
                buffer: *buffers.find(&a.buffer_view).unwrap(),
                format: gfx::attrib::Format {
                    elem_count: el_count,
                    elem_type: el_type,
                    offset: a.byte_offset,
                    stride: a.byte_stride,
                    instance_rate: 0,
                },
            }, a.count)
        });
        let models = load_map(&json, "meshes", |m: types::Mesh| {
            m.primitives.iter().map(|prim| SubMesh {
                mesh: gfx::Mesh {
                    num_vertices: prim.attributes.values().fold(0xFFFFFFFF, |min, id| {
                        let &(_, count) = attributes.find(id).unwrap();
                        cmp::min(min, count)
                    }),
                    attributes: prim.attributes.iter().map(|(name, id)| {
                        let (mut at, _) = attributes.find(id).unwrap().clone();
                        at.name = name.clone();
                        at
                    }).collect(),
                },
                slice: attrib_to_slice(attributes.find(&prim.indices)
                    .unwrap().ref0()).unwrap(),
                material: prim.material.clone(),
            }).collect()
        });
        let shaders = load_map(&json, "shaders", |s: types::Shader| {
            let stage = parse_shader_type(s.ty).unwrap();
            let data = File::open(&Path::new(s.uri)).read_to_end().unwrap();
            let source = gfx::ShaderSource {
                glsl_120: None,
                glsl_150: Some(gfx::OwnedBytes(data)),
            };
            device.create_shader(stage, source).unwrap()
        });
        let programs = load_map(&json, "programs", |p: types::Program| {
            let vs = shaders.find(&p.vertex_shader).unwrap().clone();
            assert_eq!(*vs.get_info(), gfx::shade::Vertex);
            let fs = shaders.find(&p.fragment_shader).unwrap().clone();
            assert_eq!(*fs.get_info(), gfx::shade::Fragment);
            device.create_program([vs, fs].as_slice()).unwrap()
        });
        Ok(Package {
            buffers: buffers,
            attributes: attributes,
            models: models,
            shaders: shaders,
            programs: programs,
        })
    }
}
<commit_msg>gltf - depth test and blend mode parsing<commit_after>//! GLTF package loader for gfx-rs

#![crate_name = "gltf"]
#![feature(phase)]

#[phase(plugin, link)]
extern crate log;
extern crate serialize;
extern crate cgmath;
extern crate gfx;
#[phase(plugin)]
extern crate gfx_macros;
extern crate gfx_gl;
extern crate serde;
#[phase(plugin)]
extern crate serde_macros;

use std::cmp;
use std::collections::HashMap;
use std::io::File;
use serde::{de, json};
use gfx_gl::types::GLenum;

mod types;

fn load_map<T: de::Deserializable<json::JsonDeserializer, json::ParserError>, R>(
            json: &json::Json, var: &str, fun: |T| -> R) -> HashMap<String, R> {
    match json.find(&var.to_string()) {
        Some(&json::Object(ref map)) => map.iter().map(|(id, sub)| {
            let v: T = json::from_json(sub.clone()).unwrap();
            (id.clone(), fun(v))
        }).collect(),
        _ => HashMap::new(),
    }
}

fn attrib_to_slice(attrib: &gfx::Attribute)
                   -> Result<gfx::Slice, ()> {
    use gfx::attrib as a;
    match (attrib.format.elem_count, attrib.format.elem_type) {
        (1, a::Int(a::IntRaw, a::U8, a::Unsigned)) => Ok(gfx::IndexSlice8(
            gfx::TriangleList,
            gfx::BufferHandle::from_raw(attrib.buffer),
            0,
            attrib.format.offset >> 0
        )),
        (1, a::Int(a::IntRaw, a::U16, a::Unsigned)) => Ok(gfx::IndexSlice16(
            gfx::TriangleList,
            gfx::BufferHandle::from_raw(attrib.buffer),
            0,
            attrib.format.offset >> 1
        )),
        (1, a::Int(a::IntRaw, a::U32, a::Unsigned)) => Ok(gfx::IndexSlice32(
            gfx::TriangleList,
            gfx::BufferHandle::from_raw(attrib.buffer),
            0,
            attrib.format.offset >> 2
        )),
        _ => Err(())
    }
}

#[deriving(Clone, PartialEq, Show)]
pub enum AccessorCountError {
    AccessorMatrix(u8),
    AccessorUnknown(String),
}

fn parse_accessor_count(ty: &str) -> Result<gfx::attrib::Count, AccessorCountError> {
    use gfx::attrib as a;
    match ty {
        "SCALAR" => Ok(1),
        "VEC2"   => Ok(2),
        "VEC3"   => Ok(3),
        "VEC4"   => Ok(4),
        "MAT2"   => Err(AccessorMatrix(2)),
        "MAT3"   => Err(AccessorMatrix(3)),
        "MAT4"   => Err(AccessorMatrix(4)),
        _        => Err(AccessorUnknown(ty.to_string())),
    }
}

#[deriving(Clone, PartialEq, Show)]
pub enum AccessorTypeError {
    AccessorType(GLenum),
    AccessorRange(f32, f32),
}

fn parse_accessor_type(ty: GLenum, range: f32) -> Result<gfx::attrib::Type, AccessorTypeError> {
    use gfx::attrib as a;
    let sub = if range <= 2.0 {a::IntNormalized} else {a::IntAsFloat};
    Ok(match ty {
        gfx_gl::BYTE => a::Int(sub, a::U8, a::Signed),
        gfx_gl::UNSIGNED_BYTE => a::Int(sub, a::U8, a::Unsigned),
        gfx_gl::SHORT => a::Int(sub, a::U16, a::Signed),
        gfx_gl::UNSIGNED_SHORT => a::Int(sub, a::U32, a::Unsigned),
        gfx_gl::INT => a::Int(sub, a::U16, a::Signed),
        gfx_gl::UNSIGNED_INT => a::Int(sub, a::U32, a::Unsigned),
        gfx_gl::FLOAT => a::Float(a::FloatDefault, a::F32),
        _ => return Err(AccessorType(ty)),
    })
}

#[deriving(Clone, PartialEq, Show)]
pub struct ShaderError(GLenum);

fn parse_shader_type(ty: GLenum) -> Result<gfx::shade::Stage, ShaderError> {
    match ty {
        gfx_gl::VERTEX_SHADER => Ok(gfx::shade::Vertex),
        gfx_gl::GEOMETRY_SHADER => Ok(gfx::shade::Geometry),
        gfx_gl::FRAGMENT_SHADER => Ok(gfx::shade::Fragment),
        _ => Err(ShaderError(ty)),
    }
}

fn parse_comparison(fun: GLenum) -> Result<gfx::state::Comparison, ()> {
    use gfx::state as s;
    Ok(match fun {
        gfx_gl::NEVER    => s::Never,
        gfx_gl::LESS     => s::Less,
        gfx_gl::LEQUAL   => s::LessEqual,
        gfx_gl::EQUAL    => s::Equal,
        gfx_gl::GEQUAL   => s::GreaterEqual,
        gfx_gl::GREATER  => s::Greater,
        gfx_gl::NOTEQUAL => s::NotEqual,
        gfx_gl::ALWAYS   => s::Always,
        _ => return Err(()),
    })
}

fn parse_blend_factor(factor: GLenum) -> Result<gfx::state::Factor, ()> {
    use gfx::state as s;
    Ok(match factor {
        gfx_gl::ZERO => s::Factor(s::Normal, s::Zero),
        gfx_gl::SRC_COLOR => s::Factor(s::Normal, s::SourceColor),
        gfx_gl::SRC_ALPHA => s::Factor(s::Normal, s::SourceAlpha),
        gfx_gl::SRC_ALPHA_SATURATE => s::Factor(s::Normal, s::SourceAlphaSaturated),
        gfx_gl::DST_COLOR => s::Factor(s::Normal, s::DestColor),
        gfx_gl::DST_ALPHA => s::Factor(s::Normal, s::DestAlpha),
        gfx_gl::CONSTANT_COLOR => s::Factor(s::Normal, s::ConstColor),
        gfx_gl::CONSTANT_ALPHA => s::Factor(s::Normal, s::ConstAlpha),
        gfx_gl::ONE => s::Factor(s::Inverse, s::Zero),
        gfx_gl::ONE_MINUS_SRC_COLOR => s::Factor(s::Inverse, s::SourceColor),
        gfx_gl::ONE_MINUS_SRC_ALPHA => s::Factor(s::Inverse, s::SourceAlpha),
        gfx_gl::ONE_MINUS_DST_COLOR => s::Factor(s::Inverse, s::DestColor),
        gfx_gl::ONE_MINUS_DST_ALPHA => s::Factor(s::Inverse, s::DestAlpha),
        gfx_gl::ONE_MINUS_CONSTANT_COLOR => s::Factor(s::Inverse, s::ConstColor),
        gfx_gl::ONE_MINUS_CONSTANT_ALPHA => s::Factor(s::Inverse, s::ConstAlpha),
        _ => return Err(()),
    })
}

#[deriving(Clone, PartialEq, Show)]
pub enum BlendChannelError {
    BlendEquation(GLenum),
    BlendSource(GLenum),
    BlendDestination(GLenum),
}

fn parse_blend_channel(eq: GLenum, src: GLenum, dst: GLenum)
                       -> Result<gfx::state::BlendChannel, BlendChannelError> {
    use gfx::state as s;
    Ok(s::BlendChannel {
        equation: match eq {
            gfx_gl::FUNC_ADD => s::FuncAdd,
            gfx_gl::FUNC_SUBTRACT => s::FuncSub,
            gfx_gl::FUNC_REVERSE_SUBTRACT => s::FuncRevSub,
            gfx_gl::MIN => s::FuncMin,
            gfx_gl::MAX => s::FuncMax,
            _ => return Err(BlendEquation(eq)),
        },
        source: match parse_blend_factor(src) {
            Ok(f) => f,
            Err(_) => return Err(BlendSource(src)),
        },
        destination: match parse_blend_factor(dst) {
            Ok(f) => f,
            Err(_) => return Err(BlendDestination(src)),
        },
    })
}

fn parse_state(s: types::States) -> gfx::DrawState {
    let mut d = gfx::DrawState::new();
    d.primitive.front_face = match s.functions.front_face {
        (gfx_gl::CW, ) => gfx::state::Clockwise,
        (gfx_gl::CCW, ) => gfx::state::CounterClockwise,
        _ => fail!("Unknown front face: {}", s.functions.front_face),
    };
    for gl in s.enable.iter() {
        match *gl {
            gfx_gl::CULL_FACE => {
                let cull = match s.functions.cull_face {
                    (gfx_gl::FRONT, ) => gfx::state::CullFront,
                    (gfx_gl::BACK, ) => gfx::state::CullBack,
                    _ => {
                        error!("Unknown cull mode: {}", s.functions.cull_face);
                        gfx::state::CullNothing
                    },
                };
                d.primitive.method = gfx::state::Fill(cull);
            },
            gfx_gl::POLYGON_OFFSET_FILL => {
                let (f, u) = s.functions.polygon_offset;
                d.primitive.offset = gfx::state::Offset(f, u);
            },
            gfx_gl::SAMPLE_ALPHA_TO_COVERAGE => {
                //TODO
                //d.multisample.alpha_to_coverage = ;
            },
            gfx_gl::STENCIL_TEST => {
                //TODO
            },
            gfx_gl::DEPTH_TEST => {
                let f = &s.functions;
                d.depth = Some(gfx::state::Depth {
                    fun: parse_comparison(f.depth_func.val0()).unwrap(),
                    write: f.depth_mask.val0(),
                });
            },
            gfx_gl::BLEND => {
                let (eq_c, eq_a) = s.functions.blend_equation_separate;
                let (src_c, dst_c, src_a, dst_a) = s.functions.blend_func_separate;
                let (r, g, b, a) = s.functions.blend_color;
                d.blend = Some(gfx::state::Blend {
                    color: parse_blend_channel(eq_c, src_c, dst_c).unwrap(),
                    alpha: parse_blend_channel(eq_a, src_a, dst_a).unwrap(),
                    value: [r, g, b, a],
                });
            },
            gfx_gl::SCISSOR_TEST => {
                let (x, y, w, h) = s.functions.scissor;
                d.scissor = Some(gfx::Rect {
                    x: x, y: y, w: w, h: h,
                });
            },
            _ => error!("Unknown GL state: {}", *gl),
        }
    }
    d
}

pub enum LoadError {
    ErrorString,
    ErrorJson,
}

pub struct SubMesh {
    pub mesh: gfx::Mesh,
    pub slice: gfx::Slice,
    pub material: String,
}

pub struct Package {
    pub buffers:    HashMap<String, gfx::RawBufferHandle>,
    pub attributes: HashMap<String, (gfx::Attribute, gfx::VertexCount)>,
    pub models:     HashMap<String, Vec<SubMesh>>,
    pub shaders:    HashMap<String, gfx::ShaderHandle>,
    pub programs:   HashMap<String, gfx::ProgramHandle>,
}

impl Package {
    pub fn load<C: gfx::CommandBuffer, D: gfx::Device<C>>(input: &str, device: &mut D)
            -> Result<Package, LoadError> {
        let json = match json::from_str(input) {
            Ok(j) => j,
            Err(_e) => return Err(ErrorString),
        };
        let buffers = load_map(&json, "buffers", |b: types::Buffer| {
            let data = File::open(&Path::new(b.uri)).read_to_end().unwrap();
            debug_assert_eq!(data.len(), b.byte_length);
            device.create_buffer_static(&data).raw()
        });
        let attributes = load_map(&json, "accessors", |a: types::Accessor| {
            let range = a.max.val0() - a.min.val0();
            let el_count = parse_accessor_count(a.ty.as_slice()).unwrap();
            let el_type  = parse_accessor_type(a.component_type, range).unwrap();
            (gfx::Attribute {
                name: a.name,
                buffer: *buffers.find(&a.buffer_view).unwrap(),
                format: gfx::attrib::Format {
                    elem_count: el_count,
                    elem_type: el_type,
                    offset: a.byte_offset,
                    stride: a.byte_stride,
                    instance_rate: 0,
                },
            }, a.count)
        });
        let models = load_map(&json, "meshes", |m: types::Mesh| {
            m.primitives.iter().map(|prim| SubMesh {
                mesh: gfx::Mesh {
                    num_vertices: prim.attributes.values().fold(0xFFFFFFFF, |min, id| {
                        let &(_, count) = attributes.find(id).unwrap();
                        cmp::min(min, count)
                    }),
                    attributes: prim.attributes.iter().map(|(name, id)| {
                        let (mut at, _) = attributes.find(id).unwrap().clone();
                        at.name = name.clone();
                        at
                    }).collect(),
                },
                slice: attrib_to_slice(attributes.find(&prim.indices)
                    .unwrap().ref0()).unwrap(),
                material: prim.material.clone(),
            }).collect()
        });
        let shaders = load_map(&json, "shaders", |s: types::Shader| {
            let stage = parse_shader_type(s.ty).unwrap();
            let data = File::open(&Path::new(s.uri)).read_to_end().unwrap();
            let source = gfx::ShaderSource {
                glsl_120: None,
                glsl_150: Some(gfx::OwnedBytes(data)),
            };
            device.create_shader(stage, source).unwrap()
        });
        let programs = load_map(&json, "programs", |p: types::Program| {
            let vs = shaders.find(&p.vertex_shader).unwrap().clone();
            assert_eq!(*vs.get_info(), gfx::shade::Vertex);
            let fs = shaders.find(&p.fragment_shader).unwrap().clone();
            assert_eq!(*fs.get_info(), gfx::shade::Fragment);
            device.create_program([vs, fs].as_slice()).unwrap()
        });
        Ok(Package {
            buffers: buffers,
            attributes: attributes,
            models: models,
            shaders: shaders,
            programs: programs,
        })
    }
}
<|endoftext|>


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

use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use crate::gpio::{
    interrupt::{AsyncInterrupt, EventLoop},
    mem::GpioMem,
    Level, Mode,
    PullUpDown::{self, *},
    Result, Trigger,
};

// Maximum GPIO pins on the BCM2835. The actual number of pins
// exposed through the Pi's GPIO header depends on the model.
pub const MAX: usize = 54;

/// Unconfigured GPIO pin.
#[derive(Debug)]
pub struct Pin {
    pub(crate) pin: u8,
    event_loop: Arc<Mutex<EventLoop>>,
    gpio_mem: Arc<GpioMem>,
    gpio_cdev: Arc<File>,
}

impl Pin {
    #[inline]
    pub(crate) fn new(
        pin: u8,
        event_loop: Arc<Mutex<EventLoop>>,
        gpio_mem: Arc<GpioMem>,
        gpio_cdev: Arc<File>,
    ) -> Pin {
        Pin {
            pin,
            event_loop,
            gpio_mem,
            gpio_cdev,
        }
    }

    /// Mutably borrows the pin as an [`InputPin`] and sets its mode to [`Mode::Input`].
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    #[inline]
    pub fn as_input(&mut self) -> InputPin {
        InputPin::new(self, Off)
    }

    /// Additionally to `as_input`, activates the pin's pull-up resistor.
    #[inline]
    pub fn as_input_pullup(&mut self) -> InputPin {
        InputPin::new(self, PullUp)
    }

    /// Additionally to `as_input`, activates the pin's pull-down resistor.
    #[inline]
    pub fn as_input_pulldown(&mut self) -> InputPin {
        InputPin::new(self, PullDown)
    }

    /// Mutably borrows the pin as an [`OutputPin`] and sets its mode to [`Mode::Output`].
    ///
    /// [`OutputPin`]: struct.OutputPin.html
    /// [`Mode::Output`]: enum.Mode.html#variant.Output
    #[inline]
    pub fn as_output(&mut self) -> OutputPin {
        OutputPin::new(self)
    }

    /// Mutably borrows the pin as an [`AltPin`] and sets its mode to the given mode.
    ///
    /// [`AltPin`]: struct.AltPin.html
    /// [`Mode`]: enum.Mode.html
    #[inline]
    pub fn as_alt(&mut self, mode: Mode) -> AltPin {
        AltPin::new(self, mode)
    }

    #[inline]
    pub(crate) fn set_mode(&mut self, mode: Mode) {
        (*self.gpio_mem).set_mode(self.pin, mode);
    }

    /// Returns the current GPIO pin mode.
    #[inline]
    pub fn mode(&self) -> Mode {
        (*self.gpio_mem).mode(self.pin)
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    #[inline]
    pub(crate) fn set_pullupdown(&self, pud: PullUpDown) {
        (*self.gpio_mem).set_pullupdown(self.pin, pud);
    }

    #[inline]
    pub(crate) fn read(&self) -> Level {
        (*self.gpio_mem).level(self.pin)
    }

    #[inline]
    pub(crate) fn set_low(&mut self) {
        (*self.gpio_mem).set_low(self.pin);
    }

    #[inline]
    pub(crate) fn set_high(&mut self) {
        (*self.gpio_mem).set_high(self.pin);
    }

    #[inline]
    pub(crate) fn write(&mut self, level: Level) {
        match level {
            Level::Low => self.set_low(),
            Level::High => self.set_high(),
        };
    }
}

macro_rules! impl_input {
    () => {
        /// Reads the pin's current logic level.
        #[inline]
        pub fn read(&self) -> Level {
            self.pin.read()
        }
    }
}

macro_rules! impl_output {
    () => {
        /// Sets pin's logic level to low.
        #[inline]
        pub fn set_low(&mut self) {
            self.pin.set_low()
        }

        /// Sets pin's logic level to high.
        #[inline]
        pub fn set_high(&mut self) {
            self.pin.set_high()
        }

        /// Sets pin's logic level.
        #[inline]
        pub fn write(&mut self, level: Level) {
            self.pin.write(level)
        }
    }
}

macro_rules! impl_drop {
    ($struct:ident) => {
        impl<'a> $struct<'a> {
            /// Returns the value of `clear_on_drop`.
            pub fn clear_on_drop(&self) -> bool {
                self.clear_on_drop
            }

            /// When enabled, resets pin's mode to its original state when it goes out of scope.
            /// By default, this is set to `true`.
            ///
            /// # Note
            ///
            /// Drop methods aren't called when a program is abnormally terminated, for
            /// instance when a user presses Ctrl + C, and the `SIGINT` signal
            /// isn't caught. You catch those using crates such as [`simple_signal`].
            ///
            /// [`simple_signal`]: https://crates.io/crates/simple-signal
            /// [`cleanup`]: #method.cleanup
            pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
                self.clear_on_drop = clear_on_drop;
            }
        }

        impl<'a> Drop for $struct<'a> {
            /// Resets the pin's mode if `clear_on_drop` is set to `true` (default).
            fn drop(&mut self) {
                if !self.clear_on_drop {
                    return;
                }

                if let Some(prev_mode) = self.prev_mode {
                    self.pin.set_mode(prev_mode)
                }
            }
        }
    };
}

/// GPIO pin configured as input.
#[derive(Debug)]
pub struct InputPin<'a> {
    pub(crate) pin: &'a mut Pin,
    prev_mode: Option<Mode>,
    async_interrupt: Option<AsyncInterrupt>,
    clear_on_drop: bool,
}

impl<'a> InputPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin, pud_mode: PullUpDown) -> InputPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Input {
            None
        } else {
            pin.set_mode(Mode::Input);
            Some(prev_mode)
        };

        pin.set_pullupdown(pud_mode);

        InputPin {
            pin,
            prev_mode,
            async_interrupt: None,
            clear_on_drop: true,
        }
    }

    impl_input!();

    /// Configures a synchronous interrupt trigger.
    ///
    /// After configuring a synchronous interrupt trigger, you can use
    /// [`poll_interrupt`] to wait for a trigger event.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`poll_interrupt`]: #method.poll_interrupt
    pub fn set_interrupt(&mut self, trigger: Trigger) -> Result<()> {
        self.clear_async_interrupt()?;

        // Each pin can only be configured for a single trigger type
        (*self.pin.event_loop.lock().unwrap()).set_interrupt(self.pin.pin, trigger)
    }

    /// Removes a previously configured synchronous interrupt trigger.
    pub fn clear_interrupt(&mut self) -> Result<()> {
        (*self.pin.event_loop.lock().unwrap()).clear_interrupt(self.pin.pin)
    }

    /// Blocks until an interrupt is triggered on the pin, or until a timeout occurs.
    ///
    /// This only works after the pin has been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// If `reset` is set to `false`, returns immediately if an interrupt trigger event was cached in a
    /// previous call to `poll_interrupt`.
    /// If `reset` is set too `true`, clears any cached interrupt trigger events before polling.
    ///
    /// The `timeout` duration indicates how long the call will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    pub fn poll_interrupt(
        &mut self,
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<Level>> {
        let opt = (*self.pin.event_loop.lock().unwrap()).poll(&[self], reset, timeout)?;

        if let Some(trigger) = opt {
            Ok(Some(trigger.1))
        } else {
            Ok(None)
        }
    }

    /// Configures an asynchronous interrupt trigger, which will execute the callback on a
    /// separate thread when the interrupt is triggered.
    ///
    /// The callback closure or function pointer is called with a single [`Level`] argument.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`Level`]: enum.Level.html
    pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        self.clear_interrupt()?;
        self.clear_async_interrupt()?;

        self.async_interrupt = Some(AsyncInterrupt::new(
            (*self.pin.gpio_cdev).as_raw_fd(),
            self.pin.pin,
            trigger,
            callback,
        )?);

        Ok(())
    }

    pub fn clear_async_interrupt(&mut self) -> Result<()> {
        if let Some(mut interrupt) = self.async_interrupt.take() {
            interrupt.stop()?;
        }

        Ok(())
    }
}

impl_drop!(InputPin);

/// GPIO pin configured as output.
#[derive(Debug)]
pub struct OutputPin<'a> {
    pin: &'a mut Pin,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl<'a> OutputPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin) -> OutputPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Output {
            None
        } else {
            pin.set_mode(Mode::Output);
            Some(prev_mode)
        };

        OutputPin {
            pin,
            prev_mode,
            clear_on_drop: true,
        }
    }

    impl_input!();
    impl_output!();
}

impl_drop!(OutputPin);

/// GPIO pin configured with an alternate function.
#[derive(Debug)]
pub struct AltPin<'a> {
    pin: &'a mut Pin,
    mode: Mode,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl<'a> AltPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin, mode: Mode) -> AltPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == mode {
            None
        } else {
            pin.set_mode(mode);
            Some(prev_mode)
        };

        AltPin {
            pin,
            mode,
            prev_mode,
            clear_on_drop: true,
        }
    }

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

use std::fs::File;
use std::os::unix::io::AsRawFd;
use std::sync::{Arc, Mutex};
use std::time::Duration;

use crate::gpio::{
    interrupt::{AsyncInterrupt, EventLoop},
    mem::GpioMem,
    Level, Mode,
    PullUpDown::{self, *},
    Result, Trigger,
};

// Maximum GPIO pins on the BCM2835. The actual number of pins
// exposed through the Pi's GPIO header depends on the model.
pub const MAX: usize = 54;

/// Unconfigured GPIO pin.
#[derive(Debug)]
pub struct Pin {
    pub(crate) pin: u8,
    event_loop: Arc<Mutex<EventLoop>>,
    gpio_mem: Arc<GpioMem>,
    gpio_cdev: Arc<File>,
}

impl Pin {
    #[inline]
    pub(crate) fn new(
        pin: u8,
        event_loop: Arc<Mutex<EventLoop>>,
        gpio_mem: Arc<GpioMem>,
        gpio_cdev: Arc<File>,
    ) -> Pin {
        Pin {
            pin,
            event_loop,
            gpio_mem,
            gpio_cdev,
        }
    }

    /// Mutably borrows the pin as an [`InputPin`] and sets its mode to [`Mode::Input`].
    ///
    /// [`InputPin`]: struct.InputPin.html
    /// [`Mode::Input`]: enum.Mode.html#variant.Input
    #[inline]
    pub fn as_input(&mut self) -> InputPin {
        InputPin::new(self, Off)
    }

    /// Additionally to `as_input`, activates the pin's pull-up resistor.
    #[inline]
    pub fn as_input_pullup(&mut self) -> InputPin {
        InputPin::new(self, PullUp)
    }

    /// Additionally to `as_input`, activates the pin's pull-down resistor.
    #[inline]
    pub fn as_input_pulldown(&mut self) -> InputPin {
        InputPin::new(self, PullDown)
    }

    /// Mutably borrows the pin as an [`OutputPin`] and sets its mode to [`Mode::Output`].
    ///
    /// [`OutputPin`]: struct.OutputPin.html
    /// [`Mode::Output`]: enum.Mode.html#variant.Output
    #[inline]
    pub fn as_output(&mut self) -> OutputPin {
        OutputPin::new(self)
    }

    /// Mutably borrows the pin as an [`AltPin`] and sets its mode to the given mode.
    ///
    /// [`AltPin`]: struct.AltPin.html
    /// [`Mode`]: enum.Mode.html
    #[inline]
    pub fn as_alt(&mut self, mode: Mode) -> AltPin {
        AltPin::new(self, mode)
    }

    #[inline]
    pub(crate) fn set_mode(&mut self, mode: Mode) {
        (*self.gpio_mem).set_mode(self.pin, mode);
    }

    /// Returns the current GPIO pin mode.
    #[inline]
    pub fn mode(&self) -> Mode {
        (*self.gpio_mem).mode(self.pin)
    }

    /// Configures the built-in GPIO pull-up/pull-down resistors.
    #[inline]
    pub(crate) fn set_pullupdown(&self, pud: PullUpDown) {
        (*self.gpio_mem).set_pullupdown(self.pin, pud);
    }

    /// Reads the pin's current logic level.
    #[inline]
    pub fn read(&self) -> Level {
        (*self.gpio_mem).level(self.pin)
    }

    #[inline]
    pub(crate) fn set_low(&mut self) {
        (*self.gpio_mem).set_low(self.pin);
    }

    #[inline]
    pub(crate) fn set_high(&mut self) {
        (*self.gpio_mem).set_high(self.pin);
    }

    #[inline]
    pub(crate) fn write(&mut self, level: Level) {
        match level {
            Level::Low => self.set_low(),
            Level::High => self.set_high(),
        };
    }
}

macro_rules! impl_input {
    () => {
        /// Reads the pin's current logic level.
        #[inline]
        pub fn read(&self) -> Level {
            self.pin.read()
        }
    }
}

macro_rules! impl_output {
    () => {
        /// Sets pin's logic level to low.
        #[inline]
        pub fn set_low(&mut self) {
            self.pin.set_low()
        }

        /// Sets pin's logic level to high.
        #[inline]
        pub fn set_high(&mut self) {
            self.pin.set_high()
        }

        /// Sets pin's logic level.
        #[inline]
        pub fn write(&mut self, level: Level) {
            self.pin.write(level)
        }
    }
}

macro_rules! impl_drop {
    ($struct:ident) => {
        impl<'a> $struct<'a> {
            /// Returns the value of `clear_on_drop`.
            pub fn clear_on_drop(&self) -> bool {
                self.clear_on_drop
            }

            /// When enabled, resets pin's mode to its original state when it goes out of scope.
            /// By default, this is set to `true`.
            ///
            /// # Note
            ///
            /// Drop methods aren't called when a program is abnormally terminated, for
            /// instance when a user presses Ctrl + C, and the `SIGINT` signal
            /// isn't caught. You catch those using crates such as [`simple_signal`].
            ///
            /// [`simple_signal`]: https://crates.io/crates/simple-signal
            /// [`cleanup`]: #method.cleanup
            pub fn set_clear_on_drop(&mut self, clear_on_drop: bool) {
                self.clear_on_drop = clear_on_drop;
            }
        }

        impl<'a> Drop for $struct<'a> {
            /// Resets the pin's mode if `clear_on_drop` is set to `true` (default).
            fn drop(&mut self) {
                if !self.clear_on_drop {
                    return;
                }

                if let Some(prev_mode) = self.prev_mode {
                    self.pin.set_mode(prev_mode)
                }
            }
        }
    };
}

/// GPIO pin configured as input.
#[derive(Debug)]
pub struct InputPin<'a> {
    pub(crate) pin: &'a mut Pin,
    prev_mode: Option<Mode>,
    async_interrupt: Option<AsyncInterrupt>,
    clear_on_drop: bool,
}

impl<'a> InputPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin, pud_mode: PullUpDown) -> InputPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Input {
            None
        } else {
            pin.set_mode(Mode::Input);
            Some(prev_mode)
        };

        pin.set_pullupdown(pud_mode);

        InputPin {
            pin,
            prev_mode,
            async_interrupt: None,
            clear_on_drop: true,
        }
    }

    impl_input!();

    /// Configures a synchronous interrupt trigger.
    ///
    /// After configuring a synchronous interrupt trigger, you can use
    /// [`poll_interrupt`] to wait for a trigger event.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`poll_interrupt`]: #method.poll_interrupt
    pub fn set_interrupt(&mut self, trigger: Trigger) -> Result<()> {
        self.clear_async_interrupt()?;

        // Each pin can only be configured for a single trigger type
        (*self.pin.event_loop.lock().unwrap()).set_interrupt(self.pin.pin, trigger)
    }

    /// Removes a previously configured synchronous interrupt trigger.
    pub fn clear_interrupt(&mut self) -> Result<()> {
        (*self.pin.event_loop.lock().unwrap()).clear_interrupt(self.pin.pin)
    }

    /// Blocks until an interrupt is triggered on the pin, or until a timeout occurs.
    ///
    /// This only works after the pin has been configured for synchronous interrupts using
    /// [`set_interrupt`]. Asynchronous interrupt triggers are automatically polled on a separate thread.
    ///
    /// If `reset` is set to `false`, returns immediately if an interrupt trigger event was cached in a
    /// previous call to `poll_interrupt`.
    /// If `reset` is set too `true`, clears any cached interrupt trigger events before polling.
    ///
    /// The `timeout` duration indicates how long the call will block while waiting
    /// for interrupt trigger events, after which an `Ok(None))` is returned.
    /// `timeout` can be set to `None` to wait indefinitely.
    ///
    /// [`set_interrupt`]: #method.set_interrupt
    pub fn poll_interrupt(
        &mut self,
        reset: bool,
        timeout: Option<Duration>,
    ) -> Result<Option<Level>> {
        let opt = (*self.pin.event_loop.lock().unwrap()).poll(&[self], reset, timeout)?;

        if let Some(trigger) = opt {
            Ok(Some(trigger.1))
        } else {
            Ok(None)
        }
    }

    /// Configures an asynchronous interrupt trigger, which will execute the callback on a
    /// separate thread when the interrupt is triggered.
    ///
    /// The callback closure or function pointer is called with a single [`Level`] argument.
    ///
    /// Any previously configured (a)synchronous interrupt triggers will be cleared.
    ///
    /// [`Level`]: enum.Level.html
    pub fn set_async_interrupt<C>(&mut self, trigger: Trigger, callback: C) -> Result<()>
    where
        C: FnMut(Level) + Send + 'static,
    {
        self.clear_interrupt()?;
        self.clear_async_interrupt()?;

        self.async_interrupt = Some(AsyncInterrupt::new(
            (*self.pin.gpio_cdev).as_raw_fd(),
            self.pin.pin,
            trigger,
            callback,
        )?);

        Ok(())
    }

    pub fn clear_async_interrupt(&mut self) -> Result<()> {
        if let Some(mut interrupt) = self.async_interrupt.take() {
            interrupt.stop()?;
        }

        Ok(())
    }
}

impl_drop!(InputPin);

/// GPIO pin configured as output.
#[derive(Debug)]
pub struct OutputPin<'a> {
    pin: &'a mut Pin,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl<'a> OutputPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin) -> OutputPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == Mode::Output {
            None
        } else {
            pin.set_mode(Mode::Output);
            Some(prev_mode)
        };

        OutputPin {
            pin,
            prev_mode,
            clear_on_drop: true,
        }
    }

    impl_input!();
    impl_output!();
}

impl_drop!(OutputPin);

/// GPIO pin configured with an alternate function.
#[derive(Debug)]
pub struct AltPin<'a> {
    pin: &'a mut Pin,
    mode: Mode,
    prev_mode: Option<Mode>,
    clear_on_drop: bool,
}

impl<'a> AltPin<'a> {
    pub(crate) fn new(pin: &'a mut Pin, mode: Mode) -> AltPin<'a> {
        let prev_mode = pin.mode();

        let prev_mode = if prev_mode == mode {
            None
        } else {
            pin.set_mode(mode);
            Some(prev_mode)
        };

        AltPin {
            pin,
            mode,
            prev_mode,
            clear_on_drop: true,
        }
    }

    impl_input!();
    impl_output!();
}
impl_drop!(AltPin);
<|endoftext|>