<commit_before>// Copyright © 2016 Cormac O'Brien
//
// 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;

pub use std::f32::consts::PI as PI;

/// A 4x4 matrix.
pub struct Mat4(pub [[f32; 4]; 4]);

impl std::ops::Deref for Mat4 {
    type Target = [[f32; 4]; 4];

    fn deref(&self) -> &[[f32; 4]; 4] {
        &self.0
    }
}

impl std::ops::Mul for Mat4 {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
        let mut result = [[0.0; 4]; 4];
        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    result[i][j] += self[k][j] * rhs[i][k];
                }
            }
        }
        Mat4(result)
    }
}

impl Mat4 {
    /// Returns a 4x4 identity matrix.
    pub fn identity() -> Self {
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    /// Performs a rotation about the x-axis.
    pub fn rotation_x(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0,   c,   s, 0.0],
              [0.0,  -s,   c, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    /// Performs a rotation about the y-axis.
    pub fn rotation_y(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[  c, 0.0,   s, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [ -s, 0.0,   c, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    /// Performs a rotation about the z-axis.
    pub fn rotation_z(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[  c,   s, 0.0, 0.0],
              [ -s,   c, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn translation(x: f32, y: f32, z: f32) -> Self {
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [  x,   y,   z, 1.0]])
    }

    pub fn perspective(w: f32, h: f32, fov: f32) -> Self {
        let aspect = w / h;
        let znear = 0.125;
        let zfar = 4096.0;
        let f = 1.0 / (fov / 2.0).tan();

        Mat4([[f / aspect, 0.0,                                   0.0,  0.0],
              [       0.0,   f,                                   0.0,  0.0],
              [       0.0, 0.0,       (zfar + znear) / (zfar - znear), -1.0],
              [       0.0, 0.0, (2.0 * zfar * znear) / (zfar - znear),  0.0]])
    }
}

/// A 3-component vector.
#[derive(Copy, Clone)]
pub struct Vec3([f32; 3]);

impl Vec3 {
    /// Constructs a new Vec3 from its components.
    pub fn new(x: f32, y: f32, z: f32) -> Self {
        Vec3([x, y, z])
    }

    /// Constructs a new Vec3 from an array of components.
    pub fn from_components(components: [f32; 3]) -> Self {
        Vec3(components)
    }

    // Constructs a new Vec3 by rotating `self` about the x-axis by `theta` radians
    pub fn rotate_x(&self, theta: f32) -> Self {
        Vec3([self[0],
              self[1] * theta.cos() - self[2] * theta.sin(),
              self[1] * theta.sin() + self[2] * theta.cos()])
    }

    pub fn rotate_y(&self, theta: f32) -> Self {
        Vec3([self[0] * theta.cos() + self[2] * theta.sin(),
              self[1],
             -self[0] * theta.sin() + self[2] * theta.cos()])
    }

    pub fn rotate_z(&self, theta: f32) -> Self {
        Vec3([self[0] * theta.cos() - self[1] * theta.sin(),
              self[0] * theta.sin() + self[1] * theta.cos(),
              self[2]])
    }

    /// Calculates the dot product of this Vec3 and another.
    pub fn dot(&self, other: Vec3) -> f32 {
        self[0] * other[0] + self[1] * other[1] + self[2] * other[2]
    }
}

impl std::fmt::Display for Vec3 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{{{}, {}, {}}}", self[0], self[1], self[2])
    }
}

// Vec3 Dereferencing

impl std::ops::Deref for Vec3 {
    type Target = [f32; 3];

    fn deref(&self) -> &[f32; 3] {
        &self.0
    }
}

// Vec3 Index Operations

impl std::ops::Index<usize> for Vec3 {
    type Output = f32;

    fn index(&self, i: usize) -> &f32 {
        &self.0[i]
    }
}

impl std::ops::IndexMut<usize> for Vec3 {
    fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut f32 {
        &mut self.0[i]
    }
}

// Vec3 Conversion Traits

impl std::convert::From<[f32; 3]> for Vec3 {
    fn from(__arg_0: [f32; 3]) -> Self {
        Vec3(__arg_0)
    }
}

// Vec3 Arithmetic Operations

impl std::ops::Mul<f32> for Vec3 {
    type Output = Self;

    fn mul(self, scalar: f32) -> Vec3 {
        Vec3([self[0] * scalar, self[1] * scalar, self[2] * scalar])
    }
}

impl<'a> std::ops::Mul<f32> for &'a Vec3 {
    type Output = Vec3;

    fn mul(self, scalar: f32) -> Vec3 {
        Vec3([self[0] * scalar, self[1] * scalar, self[2] * scalar])
    }
}

impl<'a> std::ops::Mul<&'a Vec3> for f32 {
    type Output = Vec3;

    fn mul(self, vec: &'a Vec3) -> Vec3 {
        vec * self
    }
}

impl<'a> std::ops::Add<&'a Vec3> for Vec3 {
    type Output = Vec3;

    fn add(self, other: &'a Vec3) -> Vec3 {
        Vec3([self[0] + other[0], self[1] + other[1], self[2] + other[2]])
    }
}

impl<'a, 'b> std::ops::Add<&'a Vec3> for &'b Vec3 {
    type Output = Vec3;

    fn add(self, other: &'a Vec3) -> Vec3 {
        Vec3([self[0] + other[0], self[1] + other[1], self[2] + other[2]])
    }
}

impl<'a> std::ops::Sub<&'a Vec3> for Vec3 {
    type Output = Vec3;

    fn sub(self, other: &'a Vec3) -> Vec3 {
        Vec3([self[0] - other[0], self[1] - other[1], self[2] - other[2]])
    }
}

impl<'a, 'b> std::ops::Sub<&'a Vec3> for &'b Vec3 {
    type Output = Vec3;

    fn sub(self, other: &'a Vec3) -> Vec3 {
        Vec3([self[0] - other[0], self[1] - other[1], self[2] - other[2]])
    }
}

pub struct Radians(pub f32);

impl std::convert::From<Degrees> for Radians {
    fn from(__arg_0: Degrees) -> Self {
        Radians(__arg_0.0.to_radians())
    }
}

pub struct Degrees(pub f32);

impl std::convert::From<Radians> for Degrees {
    fn from(__arg_0: Radians) -> Self {
        Degrees(__arg_0.0.to_degrees())
    }
}

#[cfg(test)]
mod test {
    use math::{Degrees, PI, Radians};

    #[test]
    fn test_deg2rad() {
        let d = Degrees(180.0);
        match Radians::from(d).0 {
            r if r > PI - 0.1 && r < PI + 0.1 => (),
            r => panic!("Got {}, expected {}", r, PI),
        }
    }

    #[test]
    fn test_rad2deg() {
        let r = Radians(PI);
        match Degrees::from(r).0 {
            d if d > 179.9 && d < 180.1 => (),
            d => panic!("Got {}, expected {}", d, 180.0),
        }
    }
}
<commit_msg>Add Into<[f32; 3]> for Vec3<commit_after>// Copyright © 2016 Cormac O'Brien
//
// 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;

pub use std::f32::consts::PI as PI;

/// A 4x4 matrix.
pub struct Mat4(pub [[f32; 4]; 4]);

impl std::ops::Deref for Mat4 {
    type Target = [[f32; 4]; 4];

    fn deref(&self) -> &[[f32; 4]; 4] {
        &self.0
    }
}

impl std::ops::Mul for Mat4 {
    type Output = Self;

    fn mul(self, rhs: Self) -> Self {
        let mut result = [[0.0; 4]; 4];
        for i in 0..4 {
            for j in 0..4 {
                for k in 0..4 {
                    result[i][j] += self[k][j] * rhs[i][k];
                }
            }
        }
        Mat4(result)
    }
}

impl Mat4 {
    /// Returns a 4x4 identity matrix.
    pub fn identity() -> Self {
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    /// Performs a rotation about the x-axis.
    pub fn rotation_x(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0,   c,   s, 0.0],
              [0.0,  -s,   c, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    /// Performs a rotation about the y-axis.
    pub fn rotation_y(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[  c, 0.0,   s, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [ -s, 0.0,   c, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    /// Performs a rotation about the z-axis.
    pub fn rotation_z(theta: f32) -> Self {
        let s = theta.sin();
        let c = theta.cos();
        Mat4([[  c,   s, 0.0, 0.0],
              [ -s,   c, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [0.0, 0.0, 0.0, 1.0]])
    }

    pub fn translation(x: f32, y: f32, z: f32) -> Self {
        Mat4([[1.0, 0.0, 0.0, 0.0],
              [0.0, 1.0, 0.0, 0.0],
              [0.0, 0.0, 1.0, 0.0],
              [  x,   y,   z, 1.0]])
    }

    pub fn perspective(w: f32, h: f32, fov: f32) -> Self {
        let aspect = w / h;
        let znear = 0.125;
        let zfar = 4096.0;
        let f = 1.0 / (fov / 2.0).tan();

        Mat4([[f / aspect, 0.0,                                   0.0,  0.0],
              [       0.0,   f,                                   0.0,  0.0],
              [       0.0, 0.0,       (zfar + znear) / (zfar - znear), -1.0],
              [       0.0, 0.0, (2.0 * zfar * znear) / (zfar - znear),  0.0]])
    }
}

/// A 3-component vector.
#[derive(Copy, Clone, PartialEq)]
pub struct Vec3([f32; 3]);

impl Vec3 {
    /// Constructs a new Vec3 from its components.
    pub fn new(x: f32, y: f32, z: f32) -> Self {
        Vec3([x, y, z])
    }

    /// Constructs a new Vec3 from an array of components.
    pub fn from_components(components: [f32; 3]) -> Self {
        Vec3(components)
    }

    // Constructs a new Vec3 by rotating `self` about the x-axis by `theta` radians
    pub fn rotate_x(&self, theta: f32) -> Self {
        Vec3([self[0],
              self[1] * theta.cos() - self[2] * theta.sin(),
              self[1] * theta.sin() + self[2] * theta.cos()])
    }

    pub fn rotate_y(&self, theta: f32) -> Self {
        Vec3([self[0] * theta.cos() + self[2] * theta.sin(),
              self[1],
             -self[0] * theta.sin() + self[2] * theta.cos()])
    }

    pub fn rotate_z(&self, theta: f32) -> Self {
        Vec3([self[0] * theta.cos() - self[1] * theta.sin(),
              self[0] * theta.sin() + self[1] * theta.cos(),
              self[2]])
    }

    /// Calculates the dot product of this Vec3 and another.
    pub fn dot(&self, other: Vec3) -> f32 {
        self[0] * other[0] + self[1] * other[1] + self[2] * other[2]
    }
}

impl std::fmt::Display for Vec3 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(f, "{{{}, {}, {}}}", self[0], self[1], self[2])
    }
}

// Vec3 Dereferencing

impl std::ops::Deref for Vec3 {
    type Target = [f32; 3];

    fn deref(&self) -> &[f32; 3] {
        &self.0
    }
}

// Vec3 Index Operations

impl std::ops::Index<usize> for Vec3 {
    type Output = f32;

    fn index(&self, i: usize) -> &f32 {
        &self.0[i]
    }
}

impl std::ops::IndexMut<usize> for Vec3 {
    fn index_mut<'a>(&'a mut self, i: usize) -> &'a mut f32 {
        &mut self.0[i]
    }
}

// Vec3 Conversion Traits

impl std::convert::From<[f32; 3]> for Vec3 {
    fn from(__arg_0: [f32; 3]) -> Self {
        Vec3(__arg_0)
    }
}

impl std::convert::Into<[f32; 3]> for Vec3 {
    fn into(self) -> [f32; 3] {
        self.0
    }
}

// Vec3 Arithmetic Operations
impl std::ops::Mul<f32> for Vec3 {
    type Output = Self;

    fn mul(self, scalar: f32) -> Vec3 {
        Vec3([self[0] * scalar, self[1] * scalar, self[2] * scalar])
    }
}

impl<'a> std::ops::Mul<f32> for &'a Vec3 {
    type Output = Vec3;

    fn mul(self, scalar: f32) -> Vec3 {
        Vec3([self[0] * scalar, self[1] * scalar, self[2] * scalar])
    }
}

impl<'a> std::ops::Mul<&'a Vec3> for f32 {
    type Output = Vec3;

    fn mul(self, vec: &'a Vec3) -> Vec3 {
        vec * self
    }
}

impl std::ops::Add<Vec3> for Vec3 {
    type Output = Vec3;
    fn add(self, other: Vec3) -> Vec3 { &self - &other }
}

impl<'a> std::ops::Add<&'a Vec3> for Vec3 {
    type Output = Vec3;
    fn add(self, other: &'a Vec3) -> Vec3 { &self - other }
}

impl<'a> std::ops::Add<Vec3> for &'a Vec3 {
    type Output = Vec3;
    fn add(self, other: Vec3) -> Vec3 { self - &other }
}

impl<'a, 'b> std::ops::Add<&'a Vec3> for &'b Vec3 {
    type Output = Vec3;

    fn add(self, other: &'a Vec3) -> Vec3 {
        Vec3([self[0] + other[0], self[1] + other[1], self[2] + other[2]])
    }
}

impl std::ops::Sub<Vec3> for Vec3 {
    type Output = Vec3;
    fn sub(self, other: Vec3) -> Vec3 { &self - &other }
}

impl<'a> std::ops::Sub<&'a Vec3> for Vec3 {
    type Output = Vec3;
    fn sub(self, other: &Vec3) -> Vec3 { &self - other }
}

impl<'a> std::ops::Sub<Vec3> for &'a Vec3 {
    type Output = Vec3;
    fn sub(self, other: Vec3) -> Vec3 { self - &other }
}

impl<'a, 'b> std::ops::Sub<&'a Vec3> for &'b Vec3 {
    type Output = Vec3;

    fn sub(self, other: &'a Vec3) -> Vec3 {
        Vec3([self[0] - other[0], self[1] - other[1], self[2] - other[2]])
    }
}

pub struct Radians(pub f32);

impl std::convert::From<Degrees> for Radians {
    fn from(__arg_0: Degrees) -> Self {
        Radians(__arg_0.0.to_radians())
    }
}

pub struct Degrees(pub f32);

impl std::convert::From<Radians> for Degrees {
    fn from(__arg_0: Radians) -> Self {
        Degrees(__arg_0.0.to_degrees())
    }
}

#[cfg(test)]
mod test {
    use math::{Degrees, PI, Radians};

    #[test]
    fn test_deg2rad() {
        let d = Degrees(180.0);
        match Radians::from(d).0 {
            r if r > PI - 0.1 && r < PI + 0.1 => (),
            r => panic!("Got {}, expected {}", r, PI),
        }
    }

    #[test]
    fn test_rad2deg() {
        let r = Radians(PI);
        match Degrees::from(r).0 {
            d if d > 179.9 && d < 180.1 => (),
            d => panic!("Got {}, expected {}", d, 180.0),
        }
    }
}
<|endoftext|>


<commit_before>//! This module contains the machinery necessary to detect infinite loops
//! during const-evaluation by taking snapshots of the state of the interpreter
//! at regular intervals.

// This lives in `interpret` because it needs access to all sots of private state.  However,
// it is not used by the general miri engine, just by CTFE.

use std::hash::{Hash, Hasher};

use rustc::ich::StableHashingContextProvider;
use rustc::mir;
use rustc::mir::interpret::{
    AllocId, Pointer, Scalar,
    Relocations, Allocation, UndefMask,
    EvalResult, EvalErrorKind,
};

use rustc::ty::{self, TyCtxt};
use rustc::ty::layout::Align;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use syntax::ast::Mutability;
use syntax::source_map::Span;

use super::eval_context::{LocalState, StackPopCleanup};
use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef, LocalValue};
use crate::const_eval::CompileTimeInterpreter;

#[derive(Default)]
pub(crate) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir> {
    /// The set of all `EvalSnapshot` *hashes* observed by this detector.
    ///
    /// When a collision occurs in this table, we store the full snapshot in
    /// `snapshots`.
    hashes: FxHashSet<u64>,

    /// The set of all `EvalSnapshot`s observed by this detector.
    ///
    /// An `EvalSnapshot` will only be fully cloned once it has caused a
    /// collision in `hashes`. As a result, the detector must observe at least
    /// *two* full cycles of an infinite loop before it triggers.
    snapshots: FxHashSet<EvalSnapshot<'a, 'mir, 'tcx>>,
}

impl<'a, 'mir, 'tcx> InfiniteLoopDetector<'a, 'mir, 'tcx>
{
    pub fn observe_and_analyze<'b>(
        &mut self,
        tcx: &TyCtxt<'b, 'tcx, 'tcx>,
        span: Span,
        memory: &Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
        stack: &[Frame<'mir, 'tcx>],
    ) -> EvalResult<'tcx, ()> {
        // Compute stack's hash before copying anything
        let mut hcx = tcx.get_stable_hashing_context();
        let mut hasher = StableHasher::<u64>::new();
        stack.hash_stable(&mut hcx, &mut hasher);
        let hash = hasher.finish();

        // Check if we know that hash already
        if self.hashes.is_empty() {
            // FIXME(#49980): make this warning a lint
            tcx.sess.span_warn(span,
                "Constant evaluating a complex constant, this might take some time");
        }
        if self.hashes.insert(hash) {
            // No collision
            return Ok(())
        }

        // We need to make a full copy. NOW things that to get really expensive.
        info!("snapshotting the state of the interpreter");

        if self.snapshots.insert(EvalSnapshot::new(memory, stack)) {
            // Spurious collision or first cycle
            return Ok(())
        }

        // Second cycle
        Err(EvalErrorKind::InfiniteLoop.into())
    }
}

trait SnapshotContext<'a> {
    fn resolve(&'a self, id: &AllocId) -> Option<&'a Allocation>;
}

/// Taking a snapshot of the evaluation context produces a view of
/// the state of the interpreter that is invariant to `AllocId`s.
trait Snapshot<'a, Ctx: SnapshotContext<'a>> {
    type Item;
    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item;
}

macro_rules! __impl_snapshot_field {
    ($field:ident, $ctx:expr) => ($field.snapshot($ctx));
    ($field:ident, $ctx:expr, $delegate:expr) => ($delegate);
}

// This assumes the type has two type parameters, first for the tag (set to `()`),
// then for the id
macro_rules! impl_snapshot_for {
    (enum $enum_name:ident {
        $( $variant:ident $( ( $($field:ident $(-> $delegate:expr)?),* ) )? ),* $(,)?
    }) => {

        impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name
            where Ctx: self::SnapshotContext<'a>,
        {
            type Item = $enum_name<(), AllocIdSnapshot<'a>>;

            #[inline]
            fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
                match *self {
                    $(
                        $enum_name::$variant $( ( $(ref $field),* ) )? =>
                            $enum_name::$variant $(
                                ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* ),
                            )?
                    )*
                }
            }
        }
    };

    (struct $struct_name:ident { $($field:ident $(-> $delegate:expr)?),*  $(,)? }) => {
        impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name
            where Ctx: self::SnapshotContext<'a>,
        {
            type Item = $struct_name<(), AllocIdSnapshot<'a>>;

            #[inline]
            fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
                let $struct_name {
                    $(ref $field),*
                } = *self;

                $struct_name {
                    $( $field: __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),*
                }
            }
        }
    };
}

impl<'a, Ctx, T> Snapshot<'a, Ctx> for Option<T>
    where Ctx: SnapshotContext<'a>,
          T: Snapshot<'a, Ctx>
{
    type Item = Option<<T as Snapshot<'a, Ctx>>::Item>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        match self {
            Some(x) => Some(x.snapshot(ctx)),
            None => None,
        }
    }
}

#[derive(Eq, PartialEq)]
struct AllocIdSnapshot<'a>(Option<AllocationSnapshot<'a>>);

impl<'a, Ctx> Snapshot<'a, Ctx> for AllocId
    where Ctx: SnapshotContext<'a>,
{
    type Item = AllocIdSnapshot<'a>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        AllocIdSnapshot(ctx.resolve(self).map(|alloc| alloc.snapshot(ctx)))
    }
}

impl_snapshot_for!(struct Pointer {
    alloc_id,
    offset -> *offset, // just copy offset verbatim
    tag -> *tag, // just copy tag
});

impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar
    where Ctx: SnapshotContext<'a>,
{
    type Item = Scalar<(), AllocIdSnapshot<'a>>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        match self {
            Scalar::Ptr(p) => Scalar::Ptr(p.snapshot(ctx)),
            Scalar::Bits{ size, bits } => Scalar::Bits {
                size: *size,
                bits: *bits,
            },
        }
    }
}

impl_snapshot_for!(enum ScalarMaybeUndef {
    Scalar(s),
    Undef,
});

impl_stable_hash_for!(struct crate::interpret::MemPlace {
    ptr,
    align,
    meta,
});
impl_snapshot_for!(struct MemPlace {
    ptr,
    meta,
    align -> *align, // just copy alignment verbatim
});

impl_stable_hash_for!(enum crate::interpret::Place {
    Ptr(mem_place),
    Local { frame, local },
});
impl<'a, Ctx> Snapshot<'a, Ctx> for Place
    where Ctx: SnapshotContext<'a>,
{
    type Item = Place<(), AllocIdSnapshot<'a>>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        match self {
            Place::Ptr(p) => Place::Ptr(p.snapshot(ctx)),

            Place::Local{ frame, local } => Place::Local{
                frame: *frame,
                local: *local,
            },
        }
    }
}

impl_stable_hash_for!(enum crate::interpret::Immediate {
    Scalar(x),
    ScalarPair(x, y),
});
impl_snapshot_for!(enum Immediate {
    Scalar(s),
    ScalarPair(s, t),
});

impl_stable_hash_for!(enum crate::interpret::Operand {
    Immediate(x),
    Indirect(x),
});
impl_snapshot_for!(enum Operand {
    Immediate(v),
    Indirect(m),
});

impl_stable_hash_for!(enum crate::interpret::LocalValue {
    Dead,
    Live(x),
});
impl_snapshot_for!(enum LocalValue {
    Live(v),
    Dead,
});

impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
    where Ctx: SnapshotContext<'a>,
{
    type Item = Relocations<(), AllocIdSnapshot<'a>>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        Relocations::from_presorted(self.iter()
            .map(|(size, ((), id))| (*size, ((), id.snapshot(ctx))))
            .collect())
    }
}

#[derive(Eq, PartialEq)]
struct AllocationSnapshot<'a> {
    bytes: &'a [u8],
    relocations: Relocations<(), AllocIdSnapshot<'a>>,
    undef_mask: &'a UndefMask,
    align: &'a Align,
    mutability: &'a Mutability,
}

impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation
    where Ctx: SnapshotContext<'a>,
{
    type Item = AllocationSnapshot<'a>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        let Allocation { bytes, relocations, undef_mask, align, mutability, extra: () } = self;

        AllocationSnapshot {
            bytes,
            undef_mask,
            align,
            mutability,
            relocations: relocations.snapshot(ctx),
        }
    }
}

impl_stable_hash_for!(enum crate::interpret::eval_context::StackPopCleanup {
    Goto(block),
    None { cleanup },
});

#[derive(Eq, PartialEq)]
struct FrameSnapshot<'a, 'tcx: 'a> {
    instance: &'a ty::Instance<'tcx>,
    span: &'a Span,
    return_to_block: &'a StackPopCleanup,
    return_place: Option<Place<(), AllocIdSnapshot<'a>>>,
    locals: IndexVec<mir::Local, LocalValue<(), AllocIdSnapshot<'a>>>,
    block: &'a mir::BasicBlock,
    stmt: usize,
}

impl_stable_hash_for!(impl<'mir, 'tcx: 'mir> for struct Frame<'mir, 'tcx> {
    mir,
    instance,
    span,
    return_to_block,
    return_place -> (return_place.as_ref().map(|r| &**r)),
    locals,
    block,
    stmt,
    extra,
});

impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
    where Ctx: SnapshotContext<'a>,
{
    type Item = FrameSnapshot<'a, 'tcx>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        let Frame {
            mir: _,
            instance,
            span,
            return_to_block,
            return_place,
            locals,
            block,
            stmt,
            extra: _,
        } = self;

        FrameSnapshot {
            instance,
            span,
            return_to_block,
            block,
            stmt: *stmt,
            return_place: return_place.map(|r| r.snapshot(ctx)),
            locals: locals.iter().map(|local| local.snapshot(ctx)).collect(),
        }
    }
}

impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx>
    where Ctx: SnapshotContext<'a>,
{
    type Item = LocalValue<(), AllocIdSnapshot<'a>>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        let LocalState { state, layout: _ } = self;
        state.snapshot(ctx)
    }
}

impl_stable_hash_for!(struct LocalState<'tcx> {
    state,
    layout -> _,
});

impl<'a, 'b, 'mir, 'tcx: 'a+'mir> SnapshotContext<'b>
    for Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
{
    fn resolve(&'b self, id: &AllocId) -> Option<&'b Allocation> {
        self.get(*id).ok()
    }
}

/// The virtual machine state during const-evaluation at a given point in time.
/// We assume the `CompileTimeInterpreter` has no interesting extra state that
/// is worth considering here.
struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir> {
    memory: Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
    stack: Vec<Frame<'mir, 'tcx>>,
}

impl<'a, 'mir, 'tcx: 'a + 'mir> EvalSnapshot<'a, 'mir, 'tcx>
{
    fn new(
        memory: &Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
        stack: &[Frame<'mir, 'tcx>]
    ) -> Self {
        EvalSnapshot {
            memory: memory.clone(),
            stack: stack.into(),
        }
    }

    // Used to compare two snapshots
    fn snapshot(&'b self)
        -> Vec<FrameSnapshot<'b, 'tcx>>
    {
        // Start with the stack, iterate and recursively snapshot
        self.stack.iter().map(|frame| frame.snapshot(&self.memory)).collect()
    }

}

impl<'a, 'mir, 'tcx> Hash for EvalSnapshot<'a, 'mir, 'tcx>
{
    fn hash<H: Hasher>(&self, state: &mut H) {
        // Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2)
        let mut hcx = self.memory.tcx.get_stable_hashing_context();
        let mut hasher = StableHasher::<u64>::new();
        self.hash_stable(&mut hcx, &mut hasher);
        hasher.finish().hash(state)
    }
}

impl_stable_hash_for!(impl<'tcx, 'b, 'mir> for struct EvalSnapshot<'b, 'mir, 'tcx> {
    // Not hashing memory: Avoid hashing memory all the time during execution
    memory -> _,
    stack,
});

impl<'a, 'mir, 'tcx> Eq for EvalSnapshot<'a, 'mir, 'tcx>
{}

impl<'a, 'mir, 'tcx> PartialEq for EvalSnapshot<'a, 'mir, 'tcx>
{
    fn eq(&self, other: &Self) -> bool {
        // FIXME: This looks to be a *ridicolously expensive* comparison operation.
        // Doesn't this make tons of copies?  Either `snapshot` is very badly named,
        // or it does!
        self.snapshot() == other.snapshot()
    }
}
<commit_msg>typo fix<commit_after>//! This module contains the machinery necessary to detect infinite loops
//! during const-evaluation by taking snapshots of the state of the interpreter
//! at regular intervals.

// This lives in `interpret` because it needs access to all sots of private state.  However,
// it is not used by the general miri engine, just by CTFE.

use std::hash::{Hash, Hasher};

use rustc::ich::StableHashingContextProvider;
use rustc::mir;
use rustc::mir::interpret::{
    AllocId, Pointer, Scalar,
    Relocations, Allocation, UndefMask,
    EvalResult, EvalErrorKind,
};

use rustc::ty::{self, TyCtxt};
use rustc::ty::layout::Align;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::indexed_vec::IndexVec;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use syntax::ast::Mutability;
use syntax::source_map::Span;

use super::eval_context::{LocalState, StackPopCleanup};
use super::{Frame, Memory, Operand, MemPlace, Place, Immediate, ScalarMaybeUndef, LocalValue};
use crate::const_eval::CompileTimeInterpreter;

#[derive(Default)]
pub(crate) struct InfiniteLoopDetector<'a, 'mir, 'tcx: 'a + 'mir> {
    /// The set of all `EvalSnapshot` *hashes* observed by this detector.
    ///
    /// When a collision occurs in this table, we store the full snapshot in
    /// `snapshots`.
    hashes: FxHashSet<u64>,

    /// The set of all `EvalSnapshot`s observed by this detector.
    ///
    /// An `EvalSnapshot` will only be fully cloned once it has caused a
    /// collision in `hashes`. As a result, the detector must observe at least
    /// *two* full cycles of an infinite loop before it triggers.
    snapshots: FxHashSet<EvalSnapshot<'a, 'mir, 'tcx>>,
}

impl<'a, 'mir, 'tcx> InfiniteLoopDetector<'a, 'mir, 'tcx>
{
    pub fn observe_and_analyze<'b>(
        &mut self,
        tcx: &TyCtxt<'b, 'tcx, 'tcx>,
        span: Span,
        memory: &Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
        stack: &[Frame<'mir, 'tcx>],
    ) -> EvalResult<'tcx, ()> {
        // Compute stack's hash before copying anything
        let mut hcx = tcx.get_stable_hashing_context();
        let mut hasher = StableHasher::<u64>::new();
        stack.hash_stable(&mut hcx, &mut hasher);
        let hash = hasher.finish();

        // Check if we know that hash already
        if self.hashes.is_empty() {
            // FIXME(#49980): make this warning a lint
            tcx.sess.span_warn(span,
                "Constant evaluating a complex constant, this might take some time");
        }
        if self.hashes.insert(hash) {
            // No collision
            return Ok(())
        }

        // We need to make a full copy. NOW things that to get really expensive.
        info!("snapshotting the state of the interpreter");

        if self.snapshots.insert(EvalSnapshot::new(memory, stack)) {
            // Spurious collision or first cycle
            return Ok(())
        }

        // Second cycle
        Err(EvalErrorKind::InfiniteLoop.into())
    }
}

trait SnapshotContext<'a> {
    fn resolve(&'a self, id: &AllocId) -> Option<&'a Allocation>;
}

/// Taking a snapshot of the evaluation context produces a view of
/// the state of the interpreter that is invariant to `AllocId`s.
trait Snapshot<'a, Ctx: SnapshotContext<'a>> {
    type Item;
    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item;
}

macro_rules! __impl_snapshot_field {
    ($field:ident, $ctx:expr) => ($field.snapshot($ctx));
    ($field:ident, $ctx:expr, $delegate:expr) => ($delegate);
}

// This assumes the type has two type parameters, first for the tag (set to `()`),
// then for the id
macro_rules! impl_snapshot_for {
    (enum $enum_name:ident {
        $( $variant:ident $( ( $($field:ident $(-> $delegate:expr)?),* ) )? ),* $(,)?
    }) => {

        impl<'a, Ctx> self::Snapshot<'a, Ctx> for $enum_name
            where Ctx: self::SnapshotContext<'a>,
        {
            type Item = $enum_name<(), AllocIdSnapshot<'a>>;

            #[inline]
            fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
                match *self {
                    $(
                        $enum_name::$variant $( ( $(ref $field),* ) )? =>
                            $enum_name::$variant $(
                                ( $( __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),* ),
                            )?
                    )*
                }
            }
        }
    };

    (struct $struct_name:ident { $($field:ident $(-> $delegate:expr)?),*  $(,)? }) => {
        impl<'a, Ctx> self::Snapshot<'a, Ctx> for $struct_name
            where Ctx: self::SnapshotContext<'a>,
        {
            type Item = $struct_name<(), AllocIdSnapshot<'a>>;

            #[inline]
            fn snapshot(&self, __ctx: &'a Ctx) -> Self::Item {
                let $struct_name {
                    $(ref $field),*
                } = *self;

                $struct_name {
                    $( $field: __impl_snapshot_field!($field, __ctx $(, $delegate)?) ),*
                }
            }
        }
    };
}

impl<'a, Ctx, T> Snapshot<'a, Ctx> for Option<T>
    where Ctx: SnapshotContext<'a>,
          T: Snapshot<'a, Ctx>
{
    type Item = Option<<T as Snapshot<'a, Ctx>>::Item>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        match self {
            Some(x) => Some(x.snapshot(ctx)),
            None => None,
        }
    }
}

#[derive(Eq, PartialEq)]
struct AllocIdSnapshot<'a>(Option<AllocationSnapshot<'a>>);

impl<'a, Ctx> Snapshot<'a, Ctx> for AllocId
    where Ctx: SnapshotContext<'a>,
{
    type Item = AllocIdSnapshot<'a>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        AllocIdSnapshot(ctx.resolve(self).map(|alloc| alloc.snapshot(ctx)))
    }
}

impl_snapshot_for!(struct Pointer {
    alloc_id,
    offset -> *offset, // just copy offset verbatim
    tag -> *tag, // just copy tag
});

impl<'a, Ctx> Snapshot<'a, Ctx> for Scalar
    where Ctx: SnapshotContext<'a>,
{
    type Item = Scalar<(), AllocIdSnapshot<'a>>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        match self {
            Scalar::Ptr(p) => Scalar::Ptr(p.snapshot(ctx)),
            Scalar::Bits{ size, bits } => Scalar::Bits {
                size: *size,
                bits: *bits,
            },
        }
    }
}

impl_snapshot_for!(enum ScalarMaybeUndef {
    Scalar(s),
    Undef,
});

impl_stable_hash_for!(struct crate::interpret::MemPlace {
    ptr,
    align,
    meta,
});
impl_snapshot_for!(struct MemPlace {
    ptr,
    meta,
    align -> *align, // just copy alignment verbatim
});

impl_stable_hash_for!(enum crate::interpret::Place {
    Ptr(mem_place),
    Local { frame, local },
});
impl<'a, Ctx> Snapshot<'a, Ctx> for Place
    where Ctx: SnapshotContext<'a>,
{
    type Item = Place<(), AllocIdSnapshot<'a>>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        match self {
            Place::Ptr(p) => Place::Ptr(p.snapshot(ctx)),

            Place::Local{ frame, local } => Place::Local{
                frame: *frame,
                local: *local,
            },
        }
    }
}

impl_stable_hash_for!(enum crate::interpret::Immediate {
    Scalar(x),
    ScalarPair(x, y),
});
impl_snapshot_for!(enum Immediate {
    Scalar(s),
    ScalarPair(s, t),
});

impl_stable_hash_for!(enum crate::interpret::Operand {
    Immediate(x),
    Indirect(x),
});
impl_snapshot_for!(enum Operand {
    Immediate(v),
    Indirect(m),
});

impl_stable_hash_for!(enum crate::interpret::LocalValue {
    Dead,
    Live(x),
});
impl_snapshot_for!(enum LocalValue {
    Live(v),
    Dead,
});

impl<'a, Ctx> Snapshot<'a, Ctx> for Relocations
    where Ctx: SnapshotContext<'a>,
{
    type Item = Relocations<(), AllocIdSnapshot<'a>>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        Relocations::from_presorted(self.iter()
            .map(|(size, ((), id))| (*size, ((), id.snapshot(ctx))))
            .collect())
    }
}

#[derive(Eq, PartialEq)]
struct AllocationSnapshot<'a> {
    bytes: &'a [u8],
    relocations: Relocations<(), AllocIdSnapshot<'a>>,
    undef_mask: &'a UndefMask,
    align: &'a Align,
    mutability: &'a Mutability,
}

impl<'a, Ctx> Snapshot<'a, Ctx> for &'a Allocation
    where Ctx: SnapshotContext<'a>,
{
    type Item = AllocationSnapshot<'a>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        let Allocation { bytes, relocations, undef_mask, align, mutability, extra: () } = self;

        AllocationSnapshot {
            bytes,
            undef_mask,
            align,
            mutability,
            relocations: relocations.snapshot(ctx),
        }
    }
}

impl_stable_hash_for!(enum crate::interpret::eval_context::StackPopCleanup {
    Goto(block),
    None { cleanup },
});

#[derive(Eq, PartialEq)]
struct FrameSnapshot<'a, 'tcx: 'a> {
    instance: &'a ty::Instance<'tcx>,
    span: &'a Span,
    return_to_block: &'a StackPopCleanup,
    return_place: Option<Place<(), AllocIdSnapshot<'a>>>,
    locals: IndexVec<mir::Local, LocalValue<(), AllocIdSnapshot<'a>>>,
    block: &'a mir::BasicBlock,
    stmt: usize,
}

impl_stable_hash_for!(impl<'mir, 'tcx: 'mir> for struct Frame<'mir, 'tcx> {
    mir,
    instance,
    span,
    return_to_block,
    return_place -> (return_place.as_ref().map(|r| &**r)),
    locals,
    block,
    stmt,
    extra,
});

impl<'a, 'mir, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a Frame<'mir, 'tcx>
    where Ctx: SnapshotContext<'a>,
{
    type Item = FrameSnapshot<'a, 'tcx>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        let Frame {
            mir: _,
            instance,
            span,
            return_to_block,
            return_place,
            locals,
            block,
            stmt,
            extra: _,
        } = self;

        FrameSnapshot {
            instance,
            span,
            return_to_block,
            block,
            stmt: *stmt,
            return_place: return_place.map(|r| r.snapshot(ctx)),
            locals: locals.iter().map(|local| local.snapshot(ctx)).collect(),
        }
    }
}

impl<'a, 'tcx, Ctx> Snapshot<'a, Ctx> for &'a LocalState<'tcx>
    where Ctx: SnapshotContext<'a>,
{
    type Item = LocalValue<(), AllocIdSnapshot<'a>>;

    fn snapshot(&self, ctx: &'a Ctx) -> Self::Item {
        let LocalState { state, layout: _ } = self;
        state.snapshot(ctx)
    }
}

impl_stable_hash_for!(struct LocalState<'tcx> {
    state,
    layout -> _,
});

impl<'a, 'b, 'mir, 'tcx: 'a+'mir> SnapshotContext<'b>
    for Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>
{
    fn resolve(&'b self, id: &AllocId) -> Option<&'b Allocation> {
        self.get(*id).ok()
    }
}

/// The virtual machine state during const-evaluation at a given point in time.
/// We assume the `CompileTimeInterpreter` has no interesting extra state that
/// is worth considering here.
struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir> {
    memory: Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
    stack: Vec<Frame<'mir, 'tcx>>,
}

impl<'a, 'mir, 'tcx: 'a + 'mir> EvalSnapshot<'a, 'mir, 'tcx>
{
    fn new(
        memory: &Memory<'a, 'mir, 'tcx, CompileTimeInterpreter<'a, 'mir, 'tcx>>,
        stack: &[Frame<'mir, 'tcx>]
    ) -> Self {
        EvalSnapshot {
            memory: memory.clone(),
            stack: stack.into(),
        }
    }

    // Used to compare two snapshots
    fn snapshot(&'b self)
        -> Vec<FrameSnapshot<'b, 'tcx>>
    {
        // Start with the stack, iterate and recursively snapshot
        self.stack.iter().map(|frame| frame.snapshot(&self.memory)).collect()
    }

}

impl<'a, 'mir, 'tcx> Hash for EvalSnapshot<'a, 'mir, 'tcx>
{
    fn hash<H: Hasher>(&self, state: &mut H) {
        // Implement in terms of hash stable, so that k1 == k2 -> hash(k1) == hash(k2)
        let mut hcx = self.memory.tcx.get_stable_hashing_context();
        let mut hasher = StableHasher::<u64>::new();
        self.hash_stable(&mut hcx, &mut hasher);
        hasher.finish().hash(state)
    }
}

impl_stable_hash_for!(impl<'tcx, 'b, 'mir> for struct EvalSnapshot<'b, 'mir, 'tcx> {
    // Not hashing memory: Avoid hashing memory all the time during execution
    memory -> _,
    stack,
});

impl<'a, 'mir, 'tcx> Eq for EvalSnapshot<'a, 'mir, 'tcx>
{}

impl<'a, 'mir, 'tcx> PartialEq for EvalSnapshot<'a, 'mir, 'tcx>
{
    fn eq(&self, other: &Self) -> bool {
        // FIXME: This looks to be a *ridiculously expensive* comparison operation.
        // Doesn't this make tons of copies?  Either `snapshot` is very badly named,
        // or it does!
        self.snapshot() == other.snapshot()
    }
}
<|endoftext|>


<commit_before>use std::io::{Result, Write};
use std::path::PathBuf;

use env::Env;
use file_saver::*;
use gobjects::*;
use library::*;
use nameutil::*;

pub fn generate(env: &Env) {
    let root_path = PathBuf::from(&env.config.target_path).join("src/widgets");
    let objs = &env.config.objects;
    for obj in objs.values() {
        if obj.status != GStatus::Generate || obj.gtype != GType::Widget {
            continue;
        }
        let path = root_path.join(file_name(&obj.name));
        println!("Generating file {:?}", path);

        save_to_file(path, &mut |w| inner(w, env, obj));
    }
}

fn inner<W: Write>(w: &mut W, env: &Env, obj: &GObject) -> Result<()>{
    //TODO: do normal generation
    let v = vec![
        "// Copyright 2013-2015, The Rust-GNOME Project Developers.",
        "// See the COPYRIGHT file at the top-level directory of this distribution.",
        "// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>"
    ];
    for s in v {
        try!(writeln!(w, "{}", s));
    }

    println!("{:?}", obj);
    let class_id = env.library.find_type(0, &obj.name).unwrap();
    println!("Class ID: {:?}", class_id);
    let class_info = match env.library.type_(class_id) {
        &Type::Class(ref info) => info,
        _ => panic!("Is not class {}", &obj.name),
    };
    println!("Class name: {:?}", class_info.glib_name);

    Ok(())
}
<commit_msg>Use as_class in the widget generator<commit_after>use std::io::{Result, Write};
use std::path::PathBuf;

use env::Env;
use file_saver::*;
use gobjects::*;
//use library::*;
use nameutil::*;

pub fn generate(env: &Env) {
    let root_path = PathBuf::from(&env.config.target_path).join("src/widgets");
    let objs = &env.config.objects;
    for obj in objs.values() {
        if obj.status != GStatus::Generate || obj.gtype != GType::Widget {
            continue;
        }
        let path = root_path.join(file_name(&obj.name));
        println!("Generating file {:?}", path);

        save_to_file(path, &mut |w| inner(w, env, obj));
    }
}

fn inner<W: Write>(w: &mut W, env: &Env, obj: &GObject) -> Result<()>{
    //TODO: do normal generation
    let v = vec![
        "// Copyright 2013-2015, The Rust-GNOME Project Developers.",
        "// See the COPYRIGHT file at the top-level directory of this distribution.",
        "// Licensed under the MIT license, see the LICENSE file or <http://opensource.org/licenses/MIT>"
    ];
    for s in v {
        try!(writeln!(w, "{}", s));
    }

    println!("{:?}", obj);
    let class_id = env.library.find_type(0, &obj.name)
        .unwrap_or_else(|| panic!("Class {} not found.", obj.name));
    let class_info = env.library.type_(class_id).as_class()
        .unwrap_or_else(|| panic!("{} is not a class.", obj.name));
    println!("Class name: {:?}", class_info.glib_name);

    Ok(())
}
<|endoftext|>


<commit_before>use libc::{c_char, c_int, c_ulong, c_long, c_float, c_double, c_void};
use gmp::mpz::mpz_srcptr;
use gmp::mpq::mpq_srcptr;
use gmp::mpf::mpf_srcptr;
use std::mem::uninitialized;

type mpfr_prec_t = c_int;
type mpfr_sign_t = c_int;
type mpfr_exp_t = c_int;

pub enum mpfr_rnd_t {
	MPFR_RNDN=0,  /* round to nearest, with ties to even */
	MPFR_RNDZ,    /* round toward zero */
	MPFR_RNDU,    /* round toward +Inf */
	MPFR_RNDD,    /* round toward -Inf */
	MPFR_RNDA,    /* round away from zero */
	MPFR_RNDF,    /* faithful rounding (not implemented yet) */
	MPFR_RNDNA=-1 /* round to nearest, with ties away from zero (mpfr_rouund) */
}

#[repr(C)]
pub struct mpfr_struct {
    _mpfr_prec: mpfr_prec_t,
    _mpfr_sign: mpfr_sign_t,
    _mpfr_exp: mpfr_exp_t,
    _mpfr_d: *mut c_void
}

pub type mpfr_srcptr = *const mpfr_struct;
pub type mpfr_ptr = *mut mpfr_struct;

#[link(name = "mpfr")]
extern "C" {
	// Initialization
	fn mpfr_init2(x: mpfr_ptr, prec: mpfr_prec_t);
	fn mpfr_clear(x: mpfr_ptr);
	fn mpfr_set_default_prec(prec: mpfr_prec_t);
	fn mpfr_get_default_prec() -> mpfr_prec_t;
	fn mpfr_set_prec(x: mpfr_ptr, prec: mpfr_prec_t);
	fn mpfr_get_prec(x: mpfr_srcptr) -> mpfr_prec_t;

	// Assignment
	fn mpfr_set(rop: mpfr_ptr, op: mpfr_ptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_ui(rop: mpfr_ptr, op: c_ulong, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_si(rop: mpfr_ptr, op: c_long, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_flt(rop: mpfr_ptr, op: c_float, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_d(rop: mpfr_ptr, op: c_double, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_z(rop: mpfr_ptr, op: mpz_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_q(rop: mpfr_ptr, op: mpq_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_f(rop: mpfr_ptr, op: mpf_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_ui_2exp(rop: mpfr_ptr, op: c_ulong, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_si_2exp(rop: mpfr_ptr, op: c_long, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_z_2exp(rop: mpfr_ptr, op: mpz_srcptr, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_str(rop: mpfr_ptr, s: *const c_char, base: c_int, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_strtofr(rop: mpfr_ptr, nptr: *const c_char, endptr: *mut c_void, base: c_int, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_nan(x: mpfr_ptr);
	fn mpfr_set_inf(x: mpfr_ptr, sign: c_int);
	fn mpfr_set_zero(x: mpfr_ptr, sign: c_int);
	fn mpfr_swap(x: mpfr_ptr, y: mpfr_ptr);
}

pub struct Mpfr {
    pub mpfr: mpfr_struct,
}

unsafe impl Send for Mpfr { }

impl Drop for Mpfr {
    fn drop(&mut self) { unsafe { mpfr_clear(&mut self.mpfr) } }
}

impl Mpfr {
    pub fn new(precision: c_int) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init2(&mut mpfr, precision);
            Mpfr { mpfr: mpfr }
        }
    }
}
<commit_msg>Implemented precision functions (set/get_prec)<commit_after>use libc::{c_char, c_int, c_ulong, c_long, c_float, c_double, c_void};
use gmp::mpz::mpz_srcptr;
use gmp::mpq::mpq_srcptr;
use gmp::mpf::mpf_srcptr;
use std::mem::uninitialized;

type mpfr_prec_t = c_int;
type mpfr_sign_t = c_int;
type mpfr_exp_t = c_int;

#[repr(C)]
pub enum mpfr_rnd_t {
	MPFR_RNDN=0,  /* round to nearest, with ties to even */
	MPFR_RNDZ,    /* round toward zero */
	MPFR_RNDU,    /* round toward +Inf */
	MPFR_RNDD,    /* round toward -Inf */
	MPFR_RNDA,    /* round away from zero */
	MPFR_RNDF,    /* faithful rounding (not implemented yet) */
	MPFR_RNDNA=-1 /* round to nearest, with ties away from zero (mpfr_rouund) */
}

#[repr(C)]
pub struct mpfr_struct {
    _mpfr_prec: mpfr_prec_t,
    _mpfr_sign: mpfr_sign_t,
    _mpfr_exp: mpfr_exp_t,
    _mpfr_d: *mut c_void
}

pub type mpfr_srcptr = *const mpfr_struct;
pub type mpfr_ptr = *mut mpfr_struct;

#[link(name = "mpfr")]
extern "C" {
	// Initialization
	fn mpfr_init2(x: mpfr_ptr, prec: mpfr_prec_t);
	fn mpfr_clear(x: mpfr_ptr);
	fn mpfr_set_default_prec(prec: mpfr_prec_t);
	fn mpfr_get_default_prec() -> mpfr_prec_t;
	fn mpfr_set_prec(x: mpfr_ptr, prec: mpfr_prec_t);
	fn mpfr_get_prec(x: mpfr_srcptr) -> mpfr_prec_t;

	// Assignment
	fn mpfr_set(rop: mpfr_ptr, op: mpfr_ptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_ui(rop: mpfr_ptr, op: c_ulong, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_si(rop: mpfr_ptr, op: c_long, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_flt(rop: mpfr_ptr, op: c_float, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_d(rop: mpfr_ptr, op: c_double, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_z(rop: mpfr_ptr, op: mpz_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_q(rop: mpfr_ptr, op: mpq_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_f(rop: mpfr_ptr, op: mpf_srcptr, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_ui_2exp(rop: mpfr_ptr, op: c_ulong, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_si_2exp(rop: mpfr_ptr, op: c_long, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_z_2exp(rop: mpfr_ptr, op: mpz_srcptr, e: mpfr_exp_t, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_str(rop: mpfr_ptr, s: *const c_char, base: c_int, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_strtofr(rop: mpfr_ptr, nptr: *const c_char, endptr: *mut c_void, base: c_int, rnd: mpfr_rnd_t) -> c_int;
	fn mpfr_set_nan(x: mpfr_ptr);
	fn mpfr_set_inf(x: mpfr_ptr, sign: c_int);
	fn mpfr_set_zero(x: mpfr_ptr, sign: c_int);
	fn mpfr_swap(x: mpfr_ptr, y: mpfr_ptr);

	// Initialization and assignment
	fn mpfr_init_set(rop: mpfr_ptr, op: mpfr_srcptr, rnd: mpfr_rnd_t) -> c_int;
}

pub struct Mpfr {
    pub mpfr: mpfr_struct,
}

unsafe impl Send for Mpfr { }

impl Drop for Mpfr {
    fn drop(&mut self) { unsafe { mpfr_clear(&mut self.mpfr) } }
}

impl Clone for Mpfr {
    fn clone(&self) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init_set(&mut mpfr, &self.mpfr, mpfr_rnd_t::MPFR_RNDN);
            Mpfr { mpfr: mpfr }
        }
    }
}

impl Mpfr {
    pub fn new(precision: c_int) -> Mpfr {
        unsafe {
            let mut mpfr = uninitialized();
            mpfr_init2(&mut mpfr, precision);
            Mpfr { mpfr: mpfr }
        }
    }

    pub fn get_default_prec() -> i64 {
    	unsafe {
    		mpfr_get_default_prec() as i64
    	}
    }

    pub fn set_default_prec(precision: i64) {
    	unsafe {
    		mpfr_set_default_prec(precision as c_int);
    	}
    }

    pub fn get_prec(&self) -> i64 {
    	unsafe {
    		mpfr_get_prec(&self.mpfr) as i64
    	}
    }

    pub fn set_prec(&mut self, precision: i64) {
    	unsafe {
    		mpfr_set_prec(&mut self.mpfr, precision as c_int);
    	}
    }
}
<|endoftext|>


<commit_before>use std::error::Error as StdError;
use std::fmt;

/// An error that occurred while working with a collector.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Error {
    /// No event types were passed to [add_event_type].
    ///
    /// [add_event_type]: crate::collector::EventCollectorBuilder::add_event_type
    NoEventTypes,
    /// The combination of event types and ID filters used with [EventCollectorBuilder] is invalid
    /// and will never match any events.
    ///
    /// For example, the following always errors because GuildCreate never has a related user ID:
    /// ```rust
    /// # use serenity::{prelude::*, collector::{CollectorError, EventCollectorBuilder}, model::prelude::*};
    /// # let (sender, _) = futures::channel::mpsc::unbounded();
    /// # let ctx = serenity::client::bridge::gateway::ShardMessenger::new(sender);
    /// assert!(matches!(
    ///     EventCollectorBuilder::new(&ctx)
    ///         .add_event_type(EventType::GuildCreate)
    ///         .add_user_id(UserId::default())
    ///         .build(),
    ///     Err(SerenityError::Collector(CollectorError::InvalidEventIdFilters)),
    /// ));
    /// ```
    /// [EventCollectorBuilder]: crate::collector::EventCollectorBuilder
    InvalidEventIdFilters,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Error::NoEventTypes => f.write_str("No event types provided"),
            Error::InvalidEventIdFilters => {
                f.write_str("Invalid event type + id filters, would never match any events")
            },
        }
    }
}

impl StdError for Error {}
<commit_msg>Use `Self` in enum matches<commit_after>use std::error::Error as StdError;
use std::fmt;

/// An error that occurred while working with a collector.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Error {
    /// No event types were passed to [add_event_type].
    ///
    /// [add_event_type]: crate::collector::EventCollectorBuilder::add_event_type
    NoEventTypes,
    /// The combination of event types and ID filters used with [EventCollectorBuilder] is invalid
    /// and will never match any events.
    ///
    /// For example, the following always errors because GuildCreate never has a related user ID:
    /// ```rust
    /// # use serenity::{prelude::*, collector::{CollectorError, EventCollectorBuilder}, model::prelude::*};
    /// # let (sender, _) = futures::channel::mpsc::unbounded();
    /// # let ctx = serenity::client::bridge::gateway::ShardMessenger::new(sender);
    /// assert!(matches!(
    ///     EventCollectorBuilder::new(&ctx)
    ///         .add_event_type(EventType::GuildCreate)
    ///         .add_user_id(UserId::default())
    ///         .build(),
    ///     Err(SerenityError::Collector(CollectorError::InvalidEventIdFilters)),
    /// ));
    /// ```
    /// [EventCollectorBuilder]: crate::collector::EventCollectorBuilder
    InvalidEventIdFilters,
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::NoEventTypes => f.write_str("No event types provided"),
            Self::InvalidEventIdFilters => {
                f.write_str("Invalid event type + id filters, would never match any events")
            },
        }
    }
}

impl StdError for Error {}
<|endoftext|>


<commit_before>use std::io::{self, Read, Write};
use std::ops::{Add, AddAssign};
use std::str;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Duration;

use mio;
use mio::tcp::{TcpListener, TcpStream};

use cpu::BreakReason;
use dbgcore;
use hwcore::Message;
use msgs;
use utils;

error_chain! {
    foreign_links {
        Io(io::Error);
        Hex(::std::num::ParseIntError);
    }
    errors {
        Parse {
            description("could not find next element to parse")
        }
        NoResponse {
            description("client should not expect a response")
        }
    }
}

fn parse_next<T, I: Iterator<Item=T>>(it: &mut I) -> Result<T> {
    it.next().ok_or(ErrorKind::Parse.into())
}

fn parse_next_hex<'a, I: Iterator<Item=&'a str>>(it: &mut I) -> Result<u32> {
    Ok(utils::from_hex(parse_next(it)?)?)
}

fn cmd_step(ctx: &mut GdbCtx) -> Result<String> {
    ctx.dbg.hw().step();
    let break_data = BreakData::new(BreakReason::LimitReached, ctx);
    let signal = break_data.to_signal();
    *ctx.last_halt = break_data;
    Ok(signal)
}

fn cmd_continue(ctx: &mut GdbCtx) -> Result<String> {
    ctx.dbg.resume();
    bail!(ErrorKind::NoResponse)
}

struct BreakData {
    reason: BreakReason,
    r15: u32,
    r13: u32
}

impl BreakData {
    fn new(reason: BreakReason, ctx: &mut GdbCtx) -> BreakData {
        let hw = ctx.dbg.hw();
        BreakData {
            reason: reason,
            r15: hw.read_reg(15),
            r13: hw.read_reg(13),
        }
    }

    fn to_signal(&self) -> String {
        let reason_str = match self.reason {
            BreakReason::Breakpoint => format!(";{}:", "swbreak"),
            _ => String::new(),
        };
        format!("T05{:02X}:{:08X};{:02X}:{:08X}{}", 15, self.r15.swap_bytes(),
                                                    13, self.r13.swap_bytes(),
                                                    reason_str)
    }
}

impl Default for BreakData {
    fn default() -> Self {
        BreakData {
            reason: BreakReason::Trapped,
            r15: 0,
            r13: 0,
        }
    }
}

fn handle_gdb_cmd_q(cmd: &str, ctx: &mut GdbCtx) -> Result<String> {
    let mut s = cmd.splitn(2, ':');
    let ty = parse_next(&mut &mut s)?;
    let params = parse_next(&mut &mut s)?;
    let mut out = String::new();
    match ty {
        "Supported" => {
            out += "PacketSize=400;BreakpointCommands+;swbreak+";
        }
        _ => warn!("GDB client tried to run unsupported `q` command {}", ty)
    }
    Ok(out)
}

fn handle_gdb_cmd_v(cmd: &str, ctx: &mut GdbCtx) -> Result<String> {
    let mut s = cmd.splitn(2, |c| c == ',' || c == ':' || c == ';');
    let ty = parse_next(&mut &mut s)?;
    let params = parse_next(&mut &mut s)?;
    let mut out = String::new();
    match ty {
        "Cont" => {
            let threads = params.split(';');
            for thread in threads {
                let mut thread_data = thread.split(':');
                let action = parse_next(&mut &mut thread_data)?;
                let thread_name = thread_data.next();
                if let Some(name) = thread_name {
                    assert!(name == "-1");
                }
                match action {
                    "c" => return cmd_continue(ctx),
                    "s" => return cmd_step(ctx),
                    _ => warn!("GDB client tried to run unsupported `vCont` action {}", action)
                }
            }
        }
        "Cont?" => {
            let supported = ["c", "s"];
            out += "vCont";
            for ty in supported.iter() {
                out += ";";
                out += ty;
            }
        }
        _ => warn!("GDB client tried to run unsupported `v` command {}", ty)
    }
    Ok(out)
}

fn handle_gdb_cmd(cmd: &str, ctx: &mut GdbCtx) -> Result<String> {
    let ty = parse_next(&mut &mut cmd.chars())?;
    let params = &cmd[1..];
    let mut out = String::new();
    ctx.dbg.pause();
    match ty {
        'g' => {
            let hw = ctx.dbg.hw();
            for reg in 0..16 {
                out += &format!("{:08X}", hw.read_reg(reg).swap_bytes());
            }
        }
        'G' => {
            let mut hw = ctx.dbg.hw();
            for reg in 0..16 {
                let param_reg_range = 8*reg..8*(reg+1);
                let reg_data = utils::from_hex(&params[param_reg_range])?;
                hw.write_reg(reg, reg_data.swap_bytes());
            }
            out += "OK";
        }
        'm' => {
            let hw = ctx.dbg.hw();
            let mut params = params.split(',');
            let addr = parse_next_hex(&mut params)?;
            let size = parse_next_hex(&mut params)?;
            let mut buf = [0u8];
            for b in 0..size {
                hw.read_mem(addr+b, &mut buf);
                out += &format!("{:02X}", buf[0]);
            }
        }
        'M' => {
            let mut hw = ctx.dbg.hw();
            let mut params = params.split(|c| c == ',' || c == ':');
            let addr = parse_next_hex(&mut params)?;
            let size = parse_next_hex(&mut params)?;
            let data = parse_next(&mut params)?;
            for b in 0..size {
                let data_byte_range = 2*(b as usize)..2*((b as usize)+1);
                let byte = utils::from_hex(&data[data_byte_range])? as u8;
                hw.write_mem(addr+b, &[byte]);
            }
            out += "OK";
        }
        'q' => {
            return handle_gdb_cmd_q(params, ctx);
        }
        's' => {
            return cmd_step(ctx);
        }
        'c' => {
            return cmd_continue(ctx);
        }
        'v' => {
            return handle_gdb_cmd_v(params, ctx);
        }
        'z' | 'Z' => {
            let mut hw = ctx.dbg.hw();
            let mut params = params.split(',');
            let brk_ty = parse_next(&mut params)?;
            let addr = parse_next_hex(&mut params)?;
            let kind = parse_next(&mut params)?;
            assert!(brk_ty == "0");
            if ty == 'Z' {
                hw.set_breakpoint(addr);
            } else {
                hw.del_breakpoint(addr);
            }
            out += "OK";
        }
        '?' => {
            out += &ctx.last_halt.to_signal();
        }
        x => {
            warn!("GDB client tried to run unsupported command {}", x);
        }
    }
    Ok(out)
}

#[derive(Clone, Copy)]
struct Checksum(pub u32);
impl Add<u8> for Checksum {
    type Output = Checksum;
    fn add(self, b: u8) -> Checksum {
        Checksum((self.0 + (b as u32)) % 256)
    }
}
impl AddAssign<u8> for Checksum {
    fn add_assign(&mut self, b: u8) {
        self.0 = (*self + b).0;
    }
}

enum PacketType {
    Command(String),
    CtrlC,
    Malformed
}

fn load_packet<I: Iterator<Item = u8>>(it: &mut I) -> PacketType {
    let mut it = it.skip_while(|b| *b != 0x03 && *b != b'$');
    match it.next() {
        Some(0x3) => return PacketType::CtrlC,
        Some(b'$') => {}
        _ => return PacketType::Malformed
    }

    let mut string = String::new();
    let mut checksum = Checksum(0);
    for b in it.by_ref().take_while(|b| *b != b'#') {
        string.push(b as char);
        checksum += b;
    }

    if let (Some(top), Some(bot)) = (it.next(), it.next()) {
        let packet_checksum = str::from_utf8(&[top, bot]).ok()
            .and_then(|s| utils::from_hex(s).ok());
        if Some(checksum.0) == packet_checksum {
            return PacketType::Command(string)
        }
    }
    return PacketType::Malformed
}

fn write_gdb_packet(data: &str, stream: &mut TcpStream) -> Result<()> {
    let checksum = data.bytes().fold(Checksum(0), |checksum, b| checksum + b);

    trace!("Replying with GDB packet: ${}#{:02X}", data, checksum.0);
    write!(stream, "${}#{:02X}", data, checksum.0)?;
    stream.flush()?;
    Ok(())
}

fn handle_gdb_packet(data: &[u8], stream: &mut TcpStream, ctx: &mut GdbCtx) -> Result<()> {
    trace!("Recieving GDB packet: {}", str::from_utf8(data).unwrap());
    let mut it = data.iter().cloned();
    loop {
        match load_packet(&mut it) {
            PacketType::Command(cmd) => {
                stream.write(b"+")?;
                stream.flush()?;
                match handle_gdb_cmd(&cmd, ctx) {
                    Ok(out) => write_gdb_packet(&out, stream)?,
                    Err(e) => {
                        if let &ErrorKind::NoResponse = e.kind() {}
                        else { return Err(e) }
                    }
                }
            }
            PacketType::CtrlC => ctx.dbg.pause(),
            PacketType::Malformed => {
                stream.write(b"-")?;
                stream.flush()?;
                return Ok(())
            }
        }
    }
}

struct GdbCtx<'a, 'b: 'a> {
    dbg: &'a mut dbgcore::DbgContext<'b>,
    last_halt: &'a mut BreakData,
}

const TOKEN_LISTENER: mio::Token = mio::Token(1024);
const TOKEN_CLIENT: mio::Token = mio::Token(1025);

pub struct GdbStub {
    debugger: dbgcore::DbgCore,
    gdb_thread: Option<thread::JoinHandle<msgs::Client<Message>>>
}

impl GdbStub {
    pub fn new(msg_client: msgs::Client<Message>, debugger: dbgcore::DbgCore) -> GdbStub {
        let mut stub = GdbStub {
            debugger: debugger,
            gdb_thread: None
        };
        stub.start(msg_client);
        stub
    }

    pub fn start(&mut self, msg_client: msgs::Client<Message>) {
        let mut debugger = self.debugger.clone();
        self.gdb_thread = Some(thread::Builder::new().name("GDBStub".to_owned()).spawn(move || {
            use mio::Events;

            let poll = mio::Poll::new()
                .expect("Could not create mio polling instance!");
            let listener = TcpListener::bind(&"127.0.0.1:4567".parse().unwrap())
                .expect("Could not bind TcpListener to port!");

            poll.register(&listener, TOKEN_LISTENER, mio::Ready::readable(), mio::PollOpt::edge())
                .expect("Could not register TcpListener to mio!");

            let mut connection = Connection {
                listener: &listener,
                poll: poll,
                socket: None,
            };

            let mut events = Events::with_capacity(1024);

            info!("Starting GDB stub on port 4567...");

            let mut last_halt: BreakData = Default::default();
            't: loop {
                connection.poll.poll(&mut events, Some(Duration::from_millis(100)))
                    .expect("Could not poll for network events!");

                let mut ctx = GdbCtx {
                    dbg: &mut debugger.ctx(),
                    last_halt: &mut last_halt
                };

                for event in &events {
                    handle_event(&event, &mut connection, |buf, stream| {
                        handle_gdb_packet(buf, stream, &mut ctx);
                    });
                }

                for msg in msg_client.try_iter() {
                    match msg {
                        Message::Quit => break 't,
                        Message::Arm9Halted(reason) => {
                            if let Some(ref mut stream) = connection.socket {
                                let break_data = BreakData::new(reason, &mut ctx);
                                write_gdb_packet(&break_data.to_signal(), stream);
                            }
                        }
                        _ => {}
                    }
                }
            }
            msg_client
        }).unwrap())
    }

    pub fn wait(&mut self) {
        if let Some(t) = self.gdb_thread.take() {
            t.join().unwrap();
        }
    }
}

struct Connection<'a> {
    listener: &'a TcpListener,
    poll: mio::Poll,
    socket: Option<TcpStream>,
}

fn handle_event<F>(event: &mio::Event, connection: &mut Connection, mut client_responder: F)
        where F: FnMut(&[u8], &mut TcpStream) {

    let mut buf = [0u8; 1024];
    match event.token() {
        TOKEN_LISTENER => {
            match connection.listener.accept() {
                Ok((socket, _)) => {
                    info!("GDB stub accepting connection");
                    connection.poll.register(&socket, TOKEN_CLIENT, mio::Ready::readable(),
                                             mio::PollOpt::edge())
                        .expect("Could not register TCP client to mio!");
                    connection.socket = Some(socket);
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    return; // Socket is not ready anymore, stop accepting
                }
                e => panic!("GDB stub IO error! {:?}", e)
            }
        }
        TOKEN_CLIENT => for i in 0..128 {
            match connection.socket.as_mut().unwrap().read(&mut buf) {
                Ok(0) => {
                    connection.socket = None;
                    break;
                }
                Ok(l) => client_responder(&buf[..l], connection.socket.as_mut().unwrap()),
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    continue; // Socket is not ready anymore, stop reading
                }
                e => panic!("GDB stub IO error! {:?}", e), // Unexpected error
            }
        },
        _ => unimplemented!()
    }
}<commit_msg>GDB fixes: stop reply, missing unhandled command replies, end of packet<commit_after>use std::io::{self, Read, Write};
use std::ops::{Add, AddAssign};
use std::str;
use std::sync::atomic::Ordering;
use std::thread;
use std::time::Duration;

use mio;
use mio::tcp::{TcpListener, TcpStream};

use cpu::BreakReason;
use dbgcore;
use hwcore::Message;
use msgs;
use utils;

error_chain! {
    foreign_links {
        Io(io::Error);
        Hex(::std::num::ParseIntError);
    }
    errors {
        Parse {
            description("could not find next element to parse")
        }
        NoResponse {
            description("client should not expect a response")
        }
    }
}

fn parse_next<T, I: Iterator<Item=T>>(it: &mut I) -> Result<T> {
    it.next().ok_or(ErrorKind::Parse.into())
}

fn parse_next_hex<'a, I: Iterator<Item=&'a str>>(it: &mut I) -> Result<u32> {
    Ok(utils::from_hex(parse_next(it)?)?)
}

fn cmd_step(ctx: &mut GdbCtx) -> Result<String> {
    ctx.dbg.hw().step();
    let break_data = BreakData::new(BreakReason::LimitReached, ctx);
    let signal = break_data.to_signal();
    *ctx.last_halt = break_data;
    Ok(signal)
}

fn cmd_continue(ctx: &mut GdbCtx) -> Result<String> {
    ctx.dbg.resume();
    bail!(ErrorKind::NoResponse)
}

struct BreakData {
    reason: BreakReason,
    r15: u32,
    r13: u32
}

impl BreakData {
    fn new(reason: BreakReason, ctx: &mut GdbCtx) -> BreakData {
        let hw = ctx.dbg.hw();
        BreakData {
            reason: reason,
            r15: hw.read_reg(15),
            r13: hw.read_reg(13),
        }
    }

    fn to_signal(&self) -> String {
        let reason_str = match self.reason {
            BreakReason::Breakpoint => format!(";{}:", "swbreak"),
            _ => String::new(),
        };
        format!("T05{:02X}:{:08X};{:02X}:{:08X}{};", 15, self.r15.swap_bytes(),
                                                     13, self.r13.swap_bytes(),
                                                     reason_str)
    }
}

impl Default for BreakData {
    fn default() -> Self {
        BreakData {
            reason: BreakReason::Trapped,
            r15: 0,
            r13: 0,
        }
    }
}

fn handle_gdb_cmd_q(cmd: &str, ctx: &mut GdbCtx) -> Result<String> {
    let mut s = cmd.splitn(2, ':');
    let ty = parse_next(&mut s)?;
    let mut out = String::new();
    match ty {
        "Supported" => {
            out += "PacketSize=400;BreakpointCommands+;swbreak+";
        }
        _ => warn!("GDB client tried to run unsupported `q` command {}", ty)
    }
    Ok(out)
}

fn handle_gdb_cmd_v(cmd: &str, ctx: &mut GdbCtx) -> Result<String> {
    let mut s = cmd.splitn(2, |c| c == ',' || c == ':' || c == ';');
    let ty = parse_next(&mut s)?;
    let mut out = String::new();
    match ty {
        "Cont" => {
            let params = parse_next(&mut s)?;
            let threads = params.split(';');
            for thread in threads {
                let mut thread_data = thread.split(':');
                let action = parse_next(&mut thread_data)?;
                let thread_name = thread_data.next();
                if let Some(name) = thread_name {
                    assert!(name == "-1");
                }
                match action {
                    "c" => return cmd_continue(ctx),
                    "s" => return cmd_step(ctx),
                    _ => warn!("GDB client tried to run unsupported `vCont` action {}", action)
                }
            }
        }
        "Cont?" => {
            let supported = ["c", "s"];
            out += "vCont";
            for ty in supported.iter() {
                out += ";";
                out += ty;
            }
        }
        _ => warn!("GDB client tried to run unsupported `v` command {}", ty)
    }
    Ok(out)
}

fn handle_gdb_cmd(cmd: &str, ctx: &mut GdbCtx) -> Result<String> {
    let ty = parse_next(&mut cmd.chars())?;
    let params = &cmd[1..];
    let mut out = String::new();
    ctx.dbg.pause();
    match ty {
        'g' => {
            let hw = ctx.dbg.hw();
            for reg in 0..16 {
                out += &format!("{:08X}", hw.read_reg(reg).swap_bytes());
            }
        }
        'G' => {
            let mut hw = ctx.dbg.hw();
            for reg in 0..16 {
                let param_reg_range = 8*reg..8*(reg+1);
                let reg_data = utils::from_hex(&params[param_reg_range])?;
                hw.write_reg(reg, reg_data.swap_bytes());
            }
            out += "OK";
        }
        'm' => {
            let hw = ctx.dbg.hw();
            let mut params = params.split(',');
            let addr = parse_next_hex(&mut params)?;
            let size = parse_next_hex(&mut params)?;
            let mut buf = [0u8];
            for b in 0..size {
                hw.read_mem(addr+b, &mut buf);
                out += &format!("{:02X}", buf[0]);
            }
        }
        'M' => {
            let mut hw = ctx.dbg.hw();
            let mut params = params.split(|c| c == ',' || c == ':');
            let addr = parse_next_hex(&mut params)?;
            let size = parse_next_hex(&mut params)?;
            let data = parse_next(&mut params)?;
            for b in 0..size {
                let data_byte_range = 2*(b as usize)..2*((b as usize)+1);
                let byte = utils::from_hex(&data[data_byte_range])? as u8;
                hw.write_mem(addr+b, &[byte]);
            }
            out += "OK";
        }
        'q' => {
            return handle_gdb_cmd_q(params, ctx);
        }
        's' => {
            return cmd_step(ctx);
        }
        'c' => {
            return cmd_continue(ctx);
        }
        'v' => {
            return handle_gdb_cmd_v(params, ctx);
        }
        'z' | 'Z' => {
            let mut hw = ctx.dbg.hw();
            let mut params = params.split(',');
            let brk_ty = parse_next(&mut params)?;
            let addr = parse_next_hex(&mut params)?;
            let kind = parse_next(&mut params)?;
            assert!(brk_ty == "0");
            if ty == 'Z' {
                hw.set_breakpoint(addr);
            } else {
                hw.del_breakpoint(addr);
            }
            out += "OK";
        }
        '?' => {
            out += &ctx.last_halt.to_signal();
        }
        x => {
            warn!("GDB client tried to run unsupported command {}", x);
        }
    }
    Ok(out)
}

#[derive(Clone, Copy)]
struct Checksum(pub u32);
impl Add<u8> for Checksum {
    type Output = Checksum;
    fn add(self, b: u8) -> Checksum {
        Checksum((self.0 + (b as u32)) % 256)
    }
}
impl AddAssign<u8> for Checksum {
    fn add_assign(&mut self, b: u8) {
        self.0 = (*self + b).0;
    }
}

enum PacketType {
    Command(String),
    CtrlC,
    AckOk,
    AckErr,
    EndOfPacket,
    Malformed,
}

fn load_packet<I: Iterator<Item = u8>>(it: &mut I) -> PacketType {
    let mut it = it.skip_while(|b| *b != 0x03 && *b != b'$' && *b != b'-' && *b != b'+');
    match it.next() {
        Some(0x3) => return PacketType::CtrlC,
        Some(b'$') => {}
        Some(b'+') => return PacketType::AckOk,
        Some(b'-') => return PacketType::AckErr,
        None => return PacketType::EndOfPacket,
        _ => return PacketType::Malformed
    }

    let mut string = String::new();
    let mut checksum = Checksum(0);
    for b in it.by_ref().take_while(|b| *b != b'#') {
        string.push(b as char);
        checksum += b;
    }

    if let (Some(top), Some(bot)) = (it.next(), it.next()) {
        let packet_checksum = str::from_utf8(&[top, bot]).ok()
            .and_then(|s| utils::from_hex(s).ok());
        if Some(checksum.0) == packet_checksum {
            return PacketType::Command(string)
        }
    }
    return PacketType::Malformed
}

fn write_gdb_packet(data: &str, stream: &mut TcpStream) -> Result<()> {
    let checksum = data.bytes().fold(Checksum(0), |checksum, b| checksum + b);

    trace!("Replying with GDB packet: ${}#{:02X}", data, checksum.0);
    write!(stream, "${}#{:02X}", data, checksum.0)?;
    stream.flush()?;
    Ok(())
}

fn handle_gdb_packet(data: &[u8], stream: &mut TcpStream, ctx: &mut GdbCtx) -> Result<()> {
    trace!("Recieving GDB packet: {}", str::from_utf8(data).unwrap());
    let mut it = data.iter().cloned();
    loop {
        match load_packet(&mut it) {
            PacketType::Command(cmd) => {
                stream.write(b"+")?;
                stream.flush()?;
                match handle_gdb_cmd(&cmd, ctx) {
                    Ok(out) => write_gdb_packet(&out, stream)?,
                    Err(e) => {
                        if let &ErrorKind::NoResponse = e.kind() {}
                        else { return Err(e) }
                    }
                }

            }
            PacketType::CtrlC => {
                ctx.dbg.pause();
                trace!("Recieved GDB packet with CTRL-C signal!");
            }
            PacketType::AckOk => {},
            PacketType::AckErr => error!("GDB client replied with error packet!"),
            PacketType::EndOfPacket => {
                return Ok(())
            }
            PacketType::Malformed => {
                trace!("Recieved malformed data {:?}", data);
                stream.write(b"-")?;
                stream.flush()?;
                return Ok(())
            }
        }
    }
}

struct GdbCtx<'a, 'b: 'a> {
    dbg: &'a mut dbgcore::DbgContext<'b>,
    last_halt: &'a mut BreakData,
}

const TOKEN_LISTENER: mio::Token = mio::Token(1024);
const TOKEN_CLIENT: mio::Token = mio::Token(1025);

pub struct GdbStub {
    debugger: dbgcore::DbgCore,
    gdb_thread: Option<thread::JoinHandle<msgs::Client<Message>>>
}

impl GdbStub {
    pub fn new(msg_client: msgs::Client<Message>, debugger: dbgcore::DbgCore) -> GdbStub {
        let mut stub = GdbStub {
            debugger: debugger,
            gdb_thread: None
        };
        stub.start(msg_client);
        stub
    }

    pub fn start(&mut self, msg_client: msgs::Client<Message>) {
        let mut debugger = self.debugger.clone();
        self.gdb_thread = Some(thread::Builder::new().name("GDBStub".to_owned()).spawn(move || {
            use mio::Events;

            let poll = mio::Poll::new()
                .expect("Could not create mio polling instance!");
            let listener = TcpListener::bind(&"127.0.0.1:4567".parse().unwrap())
                .expect("Could not bind TcpListener to port!");

            poll.register(&listener, TOKEN_LISTENER, mio::Ready::readable(), mio::PollOpt::edge())
                .expect("Could not register TcpListener to mio!");

            let mut connection = Connection {
                listener: &listener,
                poll: poll,
                socket: None,
            };

            let mut events = Events::with_capacity(1024);

            info!("Starting GDB stub on port 4567...");

            let mut last_halt: BreakData = Default::default();
            't: loop {
                connection.poll.poll(&mut events, Some(Duration::from_millis(100)))
                    .expect("Could not poll for network events!");

                let mut ctx = GdbCtx {
                    dbg: &mut debugger.ctx(),
                    last_halt: &mut last_halt
                };

                for event in &events {
                    handle_event(&event, &mut connection, |buf, stream| {
                        handle_gdb_packet(buf, stream, &mut ctx).unwrap();
                    });
                }

                for msg in msg_client.try_iter() {
                    match msg {
                        Message::Quit => break 't,
                        Message::Arm9Halted(reason) => {
                            if let Some(ref mut stream) = connection.socket {
                                let break_data = BreakData::new(reason, &mut ctx);
                                write_gdb_packet(&break_data.to_signal(), stream);
                            }
                        }
                        _ => {}
                    }
                }
            }
            msg_client
        }).unwrap())
    }

    pub fn wait(&mut self) {
        if let Some(t) = self.gdb_thread.take() {
            t.join().unwrap();
        }
    }
}

struct Connection<'a> {
    listener: &'a TcpListener,
    poll: mio::Poll,
    socket: Option<TcpStream>,
}

fn handle_event<F>(event: &mio::Event, connection: &mut Connection, mut client_responder: F)
        where F: FnMut(&[u8], &mut TcpStream) {

    let mut buf = [0u8; 1024];
    match event.token() {
        TOKEN_LISTENER => {
            match connection.listener.accept() {
                Ok((socket, _)) => {
                    info!("GDB stub accepting connection");
                    connection.poll.register(&socket, TOKEN_CLIENT, mio::Ready::readable(),
                                             mio::PollOpt::edge())
                        .expect("Could not register TCP client to mio!");
                    connection.socket = Some(socket);
                }
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    return; // Socket is not ready anymore, stop accepting
                }
                e => panic!("GDB stub IO error! {:?}", e)
            }
        }
        TOKEN_CLIENT => for i in 0..128 {
            match connection.socket.as_mut().unwrap().read(&mut buf) {
                Ok(0) => {
                    connection.socket = None;
                    break;
                }
                Ok(l) => client_responder(&buf[..l], connection.socket.as_mut().unwrap()),
                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
                    continue; // Socket is not ready anymore, stop reading
                }
                e => panic!("GDB stub IO error! {:?}", e), // Unexpected error
            }
        },
        _ => unimplemented!()
    }
}<|endoftext|>


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

use rustc::ty::RegionVid;
use rustc_data_structures::graph::scc::Sccs;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use borrow_check::nll::type_check::Locations;

use std::fmt;
use std::ops::Deref;

crate mod graph;

#[derive(Clone, Default)]
crate struct ConstraintSet {
    constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
}

impl ConstraintSet {
    crate fn push(&mut self, constraint: OutlivesConstraint) {
        debug!(
            "ConstraintSet::push({:?}: {:?} @ {:?}",
            constraint.sup, constraint.sub, constraint.locations
        );
        if constraint.sup == constraint.sub {
            // 'a: 'a is pretty uninteresting
            return;
        }
        self.constraints.push(constraint);
    }

    /// Constructs a graph from the constraint set; the graph makes it
    /// easy to find the constraints affecting a particular region
    /// (you should not mutate the set once this graph is
    /// constructed).
    crate fn graph(&self, num_region_vars: usize) -> graph::ConstraintGraph {
        graph::ConstraintGraph::new(self, num_region_vars)
    }

    /// Compute cycles (SCCs) in the graph of regions. In particular,
    /// find all regions R1, R2 such that R1: R2 and R2: R1 and group
    /// them into an SCC, and find the relationships between SCCs.
    crate fn compute_sccs(
        &self,
        constraint_graph: &graph::ConstraintGraph,
    ) -> Sccs<RegionVid, ConstraintSccIndex> {
        let region_graph = &graph::RegionGraph::new(self, constraint_graph);
        Sccs::new(region_graph)
    }
}

impl Deref for ConstraintSet {
    type Target = IndexVec<ConstraintIndex, OutlivesConstraint>;

    fn deref(&self) -> &Self::Target {
        &self.constraints
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OutlivesConstraint {
    // NB. The ordering here is not significant for correctness, but
    // it is for convenience. Before we dump the constraints in the
    // debugging logs, we sort them, and we'd like the "super region"
    // to be first, etc. (In particular, span should remain last.)
    /// The region SUP must outlive SUB...
    pub sup: RegionVid,

    /// Region that must be outlived.
    pub sub: RegionVid,

    /// Where did this constraint arise?
    pub locations: Locations,
}

impl fmt::Debug for OutlivesConstraint {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "({:?}: {:?}) due to {:?}",
            self.sup, self.sub, self.locations
        )
    }
}

newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });

newtype_index!(ConstraintSccIndex { DEBUG_FORMAT = "ConstraintSccIndex({})" });
<commit_msg>update comment to more accurately describe the limitations<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::ty::RegionVid;
use rustc_data_structures::graph::scc::Sccs;
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use borrow_check::nll::type_check::Locations;

use std::fmt;
use std::ops::Deref;

crate mod graph;

#[derive(Clone, Default)]
crate struct ConstraintSet {
    constraints: IndexVec<ConstraintIndex, OutlivesConstraint>,
}

impl ConstraintSet {
    crate fn push(&mut self, constraint: OutlivesConstraint) {
        debug!(
            "ConstraintSet::push({:?}: {:?} @ {:?}",
            constraint.sup, constraint.sub, constraint.locations
        );
        if constraint.sup == constraint.sub {
            // 'a: 'a is pretty uninteresting
            return;
        }
        self.constraints.push(constraint);
    }

    /// Constructs a graph from the constraint set; the graph makes it
    /// easy to find the constraints affecting a particular region.
    ///
    /// NB: This graph contains a "frozen" view of the current
    /// constraints.  any new constraints added to the `ConstraintSet`
    /// after the graph is built will not be present in the graph.
    crate fn graph(&self, num_region_vars: usize) -> graph::ConstraintGraph {
        graph::ConstraintGraph::new(self, num_region_vars)
    }

    /// Compute cycles (SCCs) in the graph of regions. In particular,
    /// find all regions R1, R2 such that R1: R2 and R2: R1 and group
    /// them into an SCC, and find the relationships between SCCs.
    crate fn compute_sccs(
        &self,
        constraint_graph: &graph::ConstraintGraph,
    ) -> Sccs<RegionVid, ConstraintSccIndex> {
        let region_graph = &graph::RegionGraph::new(self, constraint_graph);
        Sccs::new(region_graph)
    }
}

impl Deref for ConstraintSet {
    type Target = IndexVec<ConstraintIndex, OutlivesConstraint>;

    fn deref(&self) -> &Self::Target {
        &self.constraints
    }
}

#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OutlivesConstraint {
    // NB. The ordering here is not significant for correctness, but
    // it is for convenience. Before we dump the constraints in the
    // debugging logs, we sort them, and we'd like the "super region"
    // to be first, etc. (In particular, span should remain last.)
    /// The region SUP must outlive SUB...
    pub sup: RegionVid,

    /// Region that must be outlived.
    pub sub: RegionVid,

    /// Where did this constraint arise?
    pub locations: Locations,
}

impl fmt::Debug for OutlivesConstraint {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        write!(
            formatter,
            "({:?}: {:?}) due to {:?}",
            self.sup, self.sub, self.locations
        )
    }
}

newtype_index!(ConstraintIndex { DEBUG_FORMAT = "ConstraintIndex({})" });

newtype_index!(ConstraintSccIndex { DEBUG_FORMAT = "ConstraintSccIndex({})" });
<|endoftext|>


<commit_before>use std::any::TypeId;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::mem;
use std::ptr;

use ffi;
use libc;

use AsLua;
use AsMutLua;
use Push;
use PushGuard;
use LuaRead;

use LuaTable;

extern fn destructor_wrapper(lua: *mut ffi::lua_State) -> libc::c_int {
    let impl_raw = unsafe { ffi::lua_touserdata(lua, ffi::lua_upvalueindex(1)) };
    let imp: fn(*mut ffi::lua_State)->::libc::c_int = unsafe { mem::transmute(impl_raw) };

    imp(lua)
}

fn destructor_impl<T>(lua: *mut ffi::lua_State) -> libc::c_int {
    let obj = unsafe { ffi::lua_touserdata(lua, -1) };
    let obj: &mut T = unsafe { mem::transmute(obj) };
    mem::replace(obj, unsafe { mem::uninitialized() });

    0
}

/// Pushes an object as a user data.
///
/// In Lua, a user data is anything that is not recognized by Lua. When the script attempts to
///  copy a user data, instead only a reference to the data is copied.
///
/// The way a Lua script can use the user data depends on the content of the **metatable**, which
///  is a Lua table linked to the object.
///
/// [See this link for more infos.](http://www.lua.org/manual/5.2/manual.html#2.4)
///
/// # Arguments
///  * metatable: Function that fills the metatable of the object.
pub fn push_userdata<L, T, F>(data: T, mut lua: L, mut metatable: F) -> PushGuard<L>
                              where F: FnMut(LuaTable<PushGuard<&mut L>>), L: AsMutLua,
                                    T: Send + 'static
{
    let typeid = format!("{:?}", TypeId::of::<T>());

    let lua_data_raw = unsafe { ffi::lua_newuserdata(lua.as_mut_lua().0,
                                                     mem::size_of_val(&data) as libc::size_t) };
    let lua_data: *mut T = unsafe { mem::transmute(lua_data_raw) };
    unsafe { ptr::write(lua_data, data) };

    let lua_raw = lua.as_mut_lua();

    // creating a metatable
    unsafe {
        ffi::lua_newtable(lua.as_mut_lua().0);

        // index "__typeid" corresponds to the hash of the TypeId of T
        "__typeid".push_to_lua(&mut lua).forget();
        typeid.push_to_lua(&mut lua).forget();
        ffi::lua_settable(lua.as_mut_lua().0, -3);

        // index "__gc" call the object's destructor
        {
            "__gc".push_to_lua(&mut lua).forget();

            // pushing destructor_impl as a lightuserdata
            let destructor_impl: fn(*mut ffi::lua_State) -> libc::c_int = destructor_impl::<T>;
            ffi::lua_pushlightuserdata(lua.as_mut_lua().0, mem::transmute(destructor_impl));

            // pushing destructor_wrapper as a closure
            ffi::lua_pushcclosure(lua.as_mut_lua().0, mem::transmute(destructor_wrapper), 1);

            ffi::lua_settable(lua.as_mut_lua().0, -3);
        }

        // calling the metatable closure
        {
            let table = LuaRead::lua_read(PushGuard { lua: &mut lua, size: 1 }).unwrap();
            metatable(table);
        }

        ffi::lua_setmetatable(lua_raw.0, -2);
    }

    PushGuard { lua: lua, size: 1 }
}

pub fn read_userdata<T, L>(mut lua: L, index: i32) -> Option<UserdataOnStack<T, L>>
                           where L: AsMutLua, T: 'static
{
    assert!(index == -1);   // FIXME:

    unsafe {
        let expected_typeid = format!("{:?}", TypeId::of::<T>());

        let data_ptr = ffi::lua_touserdata(lua.as_lua().0, -1);
        if data_ptr.is_null() {
            return None;
        }

        if ffi::lua_getmetatable(lua.as_lua().0, -1) == 0 {
            return None;
        }

        "__typeid".push_to_lua(&mut lua).forget();
        ffi::lua_gettable(lua.as_lua().0, -2);
        if LuaRead::lua_read(&mut lua) != Some(expected_typeid) {
            return None;
        }
        ffi::lua_pop(lua.as_lua().0, -2);

        Some(UserdataOnStack {
            variable: lua,
            marker: PhantomData,
        })
    }
}

pub struct UserdataOnStack<T, L> {
    variable: L,
    marker: PhantomData<T>,
}

impl<T, L> Deref for UserdataOnStack<T, L> where L: AsMutLua, T: 'static {
    type Target = T;

    fn deref(&self) -> &T {
        let me: &mut UserdataOnStack<T, L> = unsafe { mem::transmute(self) };       // FIXME:
        let data = unsafe { ffi::lua_touserdata(me.variable.as_mut_lua().0, -1) };
        let data: &T = unsafe { mem::transmute(data) };
        data
    }
}

impl<T, L> DerefMut for UserdataOnStack<T, L> where L: AsMutLua, T: 'static {
    fn deref_mut(&mut self) -> &mut T {
        let data = unsafe { ffi::lua_touserdata(self.variable.as_mut_lua().0, -1) };
        let data: &mut T = unsafe { mem::transmute(data) };
        data
    }
}
<commit_msg>Fix bug with metatables writing<commit_after>use std::any::TypeId;
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::mem;
use std::ptr;

use ffi;
use libc;

use AsLua;
use AsMutLua;
use Push;
use PushGuard;
use LuaRead;

use LuaTable;

extern fn destructor_wrapper(lua: *mut ffi::lua_State) -> libc::c_int {
    let impl_raw = unsafe { ffi::lua_touserdata(lua, ffi::lua_upvalueindex(1)) };
    let imp: fn(*mut ffi::lua_State)->::libc::c_int = unsafe { mem::transmute(impl_raw) };

    imp(lua)
}

fn destructor_impl<T>(lua: *mut ffi::lua_State) -> libc::c_int {
    let obj = unsafe { ffi::lua_touserdata(lua, -1) };
    let obj: &mut T = unsafe { mem::transmute(obj) };
    mem::replace(obj, unsafe { mem::uninitialized() });

    0
}

/// Pushes an object as a user data.
///
/// In Lua, a user data is anything that is not recognized by Lua. When the script attempts to
///  copy a user data, instead only a reference to the data is copied.
///
/// The way a Lua script can use the user data depends on the content of the **metatable**, which
///  is a Lua table linked to the object.
///
/// [See this link for more infos.](http://www.lua.org/manual/5.2/manual.html#2.4)
///
/// # Arguments
///  * metatable: Function that fills the metatable of the object.
pub fn push_userdata<L, T, F>(data: T, mut lua: L, mut metatable: F) -> PushGuard<L>
                              where F: FnMut(LuaTable<&mut PushGuard<&mut L>>), L: AsMutLua,
                                    T: Send + 'static
{
    let typeid = format!("{:?}", TypeId::of::<T>());

    let lua_data_raw = unsafe { ffi::lua_newuserdata(lua.as_mut_lua().0,
                                                     mem::size_of_val(&data) as libc::size_t) };
    let lua_data: *mut T = unsafe { mem::transmute(lua_data_raw) };
    unsafe { ptr::write(lua_data, data) };

    let lua_raw = lua.as_mut_lua();

    // creating a metatable
    unsafe {
        ffi::lua_newtable(lua.as_mut_lua().0);

        // index "__typeid" corresponds to the hash of the TypeId of T
        "__typeid".push_to_lua(&mut lua).forget();
        typeid.push_to_lua(&mut lua).forget();
        ffi::lua_settable(lua.as_mut_lua().0, -3);

        // index "__gc" call the object's destructor
        {
            "__gc".push_to_lua(&mut lua).forget();

            // pushing destructor_impl as a lightuserdata
            let destructor_impl: fn(*mut ffi::lua_State) -> libc::c_int = destructor_impl::<T>;
            ffi::lua_pushlightuserdata(lua.as_mut_lua().0, mem::transmute(destructor_impl));

            // pushing destructor_wrapper as a closure
            ffi::lua_pushcclosure(lua.as_mut_lua().0, mem::transmute(destructor_wrapper), 1);

            ffi::lua_settable(lua.as_mut_lua().0, -3);
        }

        // calling the metatable closure
        {
            let mut guard = PushGuard { lua: &mut lua, size: 1 };
            metatable(LuaRead::lua_read(&mut guard).unwrap());
            guard.forget();
        }

        ffi::lua_setmetatable(lua_raw.0, -2);
    }

    PushGuard { lua: lua, size: 1 }
}

pub fn read_userdata<T, L>(mut lua: L, index: i32) -> Option<UserdataOnStack<T, L>>
                           where L: AsMutLua, T: 'static
{
    assert!(index == -1);   // FIXME:

    unsafe {
        let expected_typeid = format!("{:?}", TypeId::of::<T>());

        let data_ptr = ffi::lua_touserdata(lua.as_lua().0, -1);
        if data_ptr.is_null() {
            return None;
        }

        if ffi::lua_getmetatable(lua.as_lua().0, -1) == 0 {
            return None;
        }

        "__typeid".push_to_lua(&mut lua).forget();
        ffi::lua_gettable(lua.as_lua().0, -2);
        if LuaRead::lua_read(&mut lua) != Some(expected_typeid) {
            return None;
        }
        ffi::lua_pop(lua.as_lua().0, -2);

        Some(UserdataOnStack {
            variable: lua,
            marker: PhantomData,
        })
    }
}

pub struct UserdataOnStack<T, L> {
    variable: L,
    marker: PhantomData<T>,
}

impl<T, L> Deref for UserdataOnStack<T, L> where L: AsMutLua, T: 'static {
    type Target = T;

    fn deref(&self) -> &T {
        let me: &mut UserdataOnStack<T, L> = unsafe { mem::transmute(self) };       // FIXME:
        let data = unsafe { ffi::lua_touserdata(me.variable.as_mut_lua().0, -1) };
        let data: &T = unsafe { mem::transmute(data) };
        data
    }
}

impl<T, L> DerefMut for UserdataOnStack<T, L> where L: AsMutLua, T: 'static {
    fn deref_mut(&mut self) -> &mut T {
        let data = unsafe { ffi::lua_touserdata(self.variable.as_mut_lua().0, -1) };
        let data: &mut T = unsafe { mem::transmute(data) };
        data
    }
}
<|endoftext|>